UNPKG

bolt-browser-db

Version:

A Fast NoSQL Database for Browser that stores data clientside , Supports Schema .

194 lines (159 loc) 6.99 kB
// Bolt: IndexedDB Library with MongoDB-like Features and Database-Based Store Management class Bolt { constructor(storeName) { this.dbName = storeName; this.storeName = storeName; this.db = null; // Automatically initialize the database this.init().catch((err) => { console.error(`Failed to initialize database '${this.dbName}':`, err); }); } async init() { return new Promise((resolve, reject) => { const request = indexedDB.open(this.dbName); request.onupgradeneeded = (event) => { const db = event.target.result; db.createObjectStore(this.storeName, { keyPath: '_id', autoIncrement: true }); console.log(`Database '${this.dbName}' and store '${this.storeName}' created.`); }; request.onsuccess = (event) => { this.db = event.target.result; console.log(`Database '${this.dbName}' initialized successfully.`); resolve(this); }; request.onerror = (event) => reject(event.target.error); }); } async _ensureDatabaseExists() { if (!this.db) { console.warn('Database is not initialized. Reinitializing.'); await this.init(); } } async _getTransaction(storeMode = 'readonly') { await this._ensureDatabaseExists(); return this.db.transaction(this.storeName, storeMode).objectStore(this.storeName); } async insertOne(doc) { const store = await this._getTransaction('readwrite'); return new Promise((resolve, reject) => { const request = store.add(doc); request.onsuccess = () => resolve(request.result); request.onerror = () => reject(request.error); }); } async insertMany(docs) { return Promise.all(docs.map(doc => this.insertOne(doc))); } async findOne(query = {}) { const store = await this._getTransaction('readonly'); return new Promise((resolve, reject) => { const request = store.getAll(); request.onsuccess = () => { const result = request.result.find(doc => Object.keys(query).every(key => doc[key] === query[key]) ); resolve(result || null); }; request.onerror = () => reject(request.error); }); } async find(query = {}) { const store = await this._getTransaction('readonly'); return new Promise((resolve, reject) => { const request = store.getAll(); request.onsuccess = () => { const result = request.result.filter(doc => Object.keys(query).every(key => doc[key] === query[key]) ); resolve(result); }; request.onerror = () => reject(request.error); }); } async update(filter, update) { // Open a readwrite transaction const store = await this._getTransaction('readwrite'); // Find the documents that match the filter const docs = await this.find(filter); // Iterate over the documents and update each one return Promise.all( docs.map(doc => { // Merge the update fields into the existing document const updatedDoc = { ...doc, ...update }; return new Promise((resolve, reject) => { // Perform the 'put' operation on the object store const request = store.put(updatedDoc); // Handle successful update request.onsuccess = () => resolve(updatedDoc); // Handle any errors during the update request.onerror = (error) => reject(error.target.error); }); }) ).then(results => { // Return all updated documents return results; }).catch((error) => { console.error('Error updating documents:', error); throw error; // Propagate error if the update fails }); } async delete(query) { const store = await this._getTransaction('readwrite'); const docs = await this.find(query); return Promise.all( docs.map(doc => { return new Promise((resolve, reject) => { const request = store.delete(doc._id); request.onsuccess = () => resolve(doc._id); request.onerror = () => reject(request.error); }); }) ).then(results => results.length); } async sum(field, condition = {}) { const store = await this._getTransaction('readonly'); return new Promise((resolve, reject) => { const request = store.getAll(); request.onsuccess = () => { const result = request.result .filter(doc => Object.keys(condition).every(key => doc[key] === condition[key])) .reduce((acc, doc) => acc + (doc[field] || 0), 0); resolve(result); }; request.onerror = () => reject(request.error); }); } async aggregate(pipeline) { const store = await this._getTransaction('readonly'); return new Promise((resolve, reject) => { const request = store.getAll(); request.onsuccess = () => { let result = request.result; pipeline.forEach((stage) => { if (stage.$match) { result = result.filter(doc => Object.keys(stage.$match).every(key => doc[key] === stage.$match[key]) ); } else if (stage.$group) { const grouped = {}; result.forEach(doc => { const key = doc[stage.$group._id]; if (!grouped[key]) grouped[key] = { _id: key, ...stage.$group.initial }; Object.keys(stage.$group).forEach(field => { if (field !== '_id' && field !== 'initial') { grouped[key][field] = (grouped[key][field] || 0) + doc[field]; } }); }); result = Object.values(grouped); } }); resolve(result); }; request.onerror = () => reject(request.error); }); } } export default Bolt;