UNPKG

@codai/cbd

Version:

Codai Better Database - High-Performance Vector Memory System with HPKV-inspired architecture and MCP server

283 lines 10.5 kB
/** * Document Storage Engine - MongoDB-compatible document database * Part of CBD Universal Database Phase 2 & 3 */ import { EventEmitter } from 'events'; export class DocumentStorageEngine extends EventEmitter { collections = new Map(); indexes = new Map(); constructor() { super(); } async initialize() { // Initialize the document storage engine this.emit('initialized'); } /** * Insert a single document */ async insertDocument(collection, document) { const coll = this.getOrCreateCollection(collection); const id = document._id || this.generateId(); document._id = id; coll.set(id, { ...document }); this.emit('document:inserted', { collection, document }); return id; } /** * Insert a single document (MongoDB-compatible alias) */ async insertOne(collection, document) { return await this.insertDocument(collection, document); } /** * Insert multiple documents */ async insertMany(collection, documents) { const insertedIds = []; for (const doc of documents) { const id = await this.insertDocument(collection, doc); insertedIds.push(id); } return insertedIds; } /** * Find documents matching query */ async findDocuments(collection, query = {}, options = {}) { const coll = this.collections.get(collection); if (!coll) return []; let results = Array.from(coll.values()); // Apply query filter if (Object.keys(query).length > 0) { results = results.filter(doc => this.matchesQuery(doc, query)); } // Apply sorting if (options.sort) { results.sort((a, b) => { for (const [field, direction] of Object.entries(options.sort)) { const aVal = a[field]; const bVal = b[field]; const comparison = aVal < bVal ? -1 : aVal > bVal ? 1 : 0; if (comparison !== 0) { return comparison * direction; } } return 0; }); } // Apply skip and limit if (options.skip) { results = results.slice(options.skip); } if (options.limit) { results = results.slice(0, options.limit); } return results; } /** * Find documents (MongoDB-compatible alias) */ async find(collection, query = {}, options = {}) { return await this.findDocuments(collection, query, options); } /** * Find a single document */ async findOne(collection, query = {}, options = {}) { const results = await this.findDocuments(collection, query, { ...options, limit: 1 }); return results.length > 0 ? results[0] : null; } /** * Update a single document */ async updateDocument(collection, filter, update) { const docs = await this.findDocuments(collection, filter, { limit: 1 }); if (docs.length === 0) { return { matchedCount: 0, modifiedCount: 0 }; } const doc = docs[0]; const updatedDoc = this.applyUpdate(doc, update); const coll = this.getOrCreateCollection(collection); coll.set(doc._id, updatedDoc); this.emit('document:updated', { collection, filter, update, document: updatedDoc }); return { matchedCount: 1, modifiedCount: 1 }; } /** * Update a single document (MongoDB-compatible alias) */ async updateOne(collection, filter, update) { return await this.updateDocument(collection, filter, update); } /** * Delete documents matching filter */ async deleteDocuments(collection, filter) { const docsToDelete = await this.findDocuments(collection, filter); const coll = this.collections.get(collection); if (!coll || docsToDelete.length === 0) { return 0; } for (const doc of docsToDelete) { coll.delete(doc._id); } this.emit('document:deleted', { collection, filter, count: docsToDelete.length }); return docsToDelete.length; } /** * Delete a single document */ async deleteOne(collection, filter) { const docs = await this.findDocuments(collection, filter, { limit: 1 }); if (docs.length === 0) { return 0; } const coll = this.collections.get(collection); if (coll) { coll.delete(docs[0]._id); this.emit('document:deleted', { collection, filter, count: 1 }); return 1; } return 0; } /** * Get collection statistics */ async getCollectionStats(collection) { if (collection) { const coll = this.collections.get(collection); if (!coll) return null; const docs = Array.from(coll.values()); const totalSize = docs.reduce((size, doc) => size + JSON.stringify(doc).length, 0); return { name: collection, count: docs.length, size: totalSize, avgObjSize: docs.length > 0 ? totalSize / docs.length : 0, storageSize: totalSize * 1.2, // Estimated with overhead indexCount: this.indexes.get(collection)?.size || 0 }; } // Return stats for all collections when no collection specified const allStats = {}; for (const [collName, coll] of this.collections) { const docs = Array.from(coll.values()); const totalSize = docs.reduce((size, doc) => size + JSON.stringify(doc).length, 0); allStats[collName] = { name: collName, count: docs.length, size: totalSize, avgObjSize: docs.length > 0 ? totalSize / docs.length : 0, storageSize: totalSize * 1.2, indexCount: this.indexes.get(collName)?.size || 0 }; } return allStats; } getOrCreateCollection(collection) { if (!this.collections.has(collection)) { this.collections.set(collection, new Map()); } return this.collections.get(collection); } generateId() { return `doc_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`; } matchesQuery(document, query) { for (const [key, value] of Object.entries(query)) { if (key.startsWith('$')) { // Handle logical operators if (key === '$and' && Array.isArray(value)) { return value.every(subQuery => this.matchesQuery(document, subQuery)); } if (key === '$or' && Array.isArray(value)) { return value.some(subQuery => this.matchesQuery(document, subQuery)); } if (key === '$not') { return !this.matchesQuery(document, value); } } else { // Handle field queries if (!this.matchesFieldQuery(document[key], value)) { return false; } } } return true; } matchesFieldQuery(fieldValue, queryValue) { if (typeof queryValue === 'object' && queryValue !== null && !Array.isArray(queryValue)) { for (const [operator, operatorValue] of Object.entries(queryValue)) { switch (operator) { case '$eq': return fieldValue === operatorValue; case '$ne': return fieldValue !== operatorValue; case '$gt': return typeof fieldValue === 'number' && typeof operatorValue === 'number' ? fieldValue > operatorValue : false; case '$gte': return typeof fieldValue === 'number' && typeof operatorValue === 'number' ? fieldValue >= operatorValue : false; case '$lt': return typeof fieldValue === 'number' && typeof operatorValue === 'number' ? fieldValue < operatorValue : false; case '$lte': return typeof fieldValue === 'number' && typeof operatorValue === 'number' ? fieldValue <= operatorValue : false; case '$in': return Array.isArray(operatorValue) && operatorValue.includes(fieldValue); case '$nin': return Array.isArray(operatorValue) && !operatorValue.includes(fieldValue); case '$exists': return operatorValue ? fieldValue !== undefined : fieldValue === undefined; case '$regex': return typeof fieldValue === 'string' && typeof operatorValue === 'string' ? new RegExp(operatorValue).test(fieldValue) : false; default: return false; } } return true; } else { return fieldValue === queryValue; } } applyUpdate(document, update) { const updatedDoc = { ...document }; if (update.$set) { Object.assign(updatedDoc, update.$set); } if (update.$unset) { for (const field of Object.keys(update.$unset)) { delete updatedDoc[field]; } } if (update.$inc) { for (const [field, increment] of Object.entries(update.$inc)) { updatedDoc[field] = (updatedDoc[field] || 0) + Number(increment); } } return updatedDoc; } /** * Alias for insertDocument - Cloud service compatibility */ async insert(collection, document) { return this.insertDocument(collection, document); } /** * Find document by ID - Cloud service compatibility */ async findById(collection, id) { const coll = this.collections.get(collection); if (!coll) return null; return coll.get(id) || null; } } //# sourceMappingURL=DocumentStorageEngine.js.map