import Datastore from 'nedb'; import * as path from 'path'; import { Bookmark, AppSettings } from '../shared/types'; import { DEFAULT_SETTINGS } from '../shared/constants'; import { v4 as uuidv4 } from 'uuid'; export class DatabaseManager { private bookmarksDb: Datastore; private settingsDb: Datastore; constructor(userDataPath: string) { this.bookmarksDb = new Datastore({ filename: path.join(userDataPath, 'bookmarks.db'), autoload: false, }); this.settingsDb = new Datastore({ filename: path.join(userDataPath, 'settings.db'), autoload: false, }); } async init(): Promise { return new Promise((resolve, reject) => { this.bookmarksDb.loadDatabase((err) => { if (err) { reject(err); return; } this.settingsDb.loadDatabase((err) => { if (err) { reject(err); return; } // Create indexes this.bookmarksDb.ensureIndex({ fieldName: 'id', unique: true }); this.bookmarksDb.ensureIndex({ fieldName: 'siteId' }); console.log('Database initialized'); resolve(); }); }); }); } // Bookmarks methods async getBookmarks(): Promise { return new Promise((resolve, reject) => { this.bookmarksDb .find({}) .sort({ createdAt: -1 }) .exec((err, docs) => { if (err) { reject(err); } else { resolve(docs as Bookmark[]); } }); }); } async addBookmark(bookmark: Omit): Promise { const newBookmark: Bookmark = { ...bookmark, id: uuidv4(), createdAt: new Date().toISOString(), }; return new Promise((resolve, reject) => { this.bookmarksDb.insert(newBookmark, (err, doc) => { if (err) { reject(err); } else { resolve(doc as Bookmark); } }); }); } async removeBookmark(id: string): Promise { return new Promise((resolve, reject) => { this.bookmarksDb.remove({ id }, {}, (err, numRemoved) => { if (err) { reject(err); } else { resolve(numRemoved > 0); } }); }); } async getBookmarksBySite(siteId: string): Promise { return new Promise((resolve, reject) => { this.bookmarksDb .find({ siteId }) .sort({ createdAt: -1 }) .exec((err, docs) => { if (err) { reject(err); } else { resolve(docs as Bookmark[]); } }); }); } // Settings methods async getSettings(): Promise { return new Promise((resolve, reject) => { this.settingsDb.findOne({ type: 'app-settings' }, (err, doc) => { if (err) { reject(err); } else if (doc) { resolve(doc as AppSettings); } else { // Return default settings if not found resolve(DEFAULT_SETTINGS); } }); }); } async saveSettings(settings: AppSettings): Promise { return new Promise((resolve, reject) => { this.settingsDb.update( { type: 'app-settings' }, { ...settings, type: 'app-settings' }, { upsert: true }, (err) => { if (err) { reject(err); } else { resolve(); } } ); }); } close(): void { // NeDB doesn't require explicit closing, but we can compact databases this.bookmarksDb.persistence.compactDatafile(); this.settingsDb.persistence.compactDatafile(); } }