UNPKG

@push.rocks/smartdata

Version:

An advanced library for NoSQL data organization and manipulation using TypeScript with support for MongoDB, data validation, collections, and custom data types.

529 lines 47.4 kB
import * as plugins from './plugins.js'; import { SmartdataDb } from './classes.db.js'; import { SmartdataDbCursor } from './classes.cursor.js'; import { SmartDataDbDoc } from './classes.doc.js'; import { SmartdataDbWatcher } from './classes.watcher.js'; import { CollectionFactory } from './classes.collectionfactory.js'; import { logger } from './logging.js'; const collectionFactory = new CollectionFactory(); const getOwnMetadataValue = (metadata, key) => { if (!metadata || !Object.prototype.hasOwnProperty.call(metadata, key)) { return undefined; } return metadata[key]; }; const mergeStringArrays = (...arrays) => { const merged = []; for (const array of arrays) { if (!array) { continue; } for (const item of array) { if (!merged.includes(item)) { merged.push(item); } } } return merged; }; const mergeRegularIndexes = (...indexArrays) => { const mergedMap = new Map(); for (const indexArray of indexArrays) { if (!indexArray) { continue; } for (const indexDef of indexArray) { mergedMap.set(indexDef.field, { field: indexDef.field, options: { ...indexDef.options }, }); } } return [...mergedMap.values()]; }; const mergeDecoratorMetadata = (...metadataArgs) => { const merged = {}; merged.globalSaveableProperties = mergeStringArrays(...metadataArgs.map((metadataArg) => getOwnMetadataValue(metadataArg, 'globalSaveableProperties'))); merged.saveableProperties = mergeStringArrays(...metadataArgs.map((metadataArg) => getOwnMetadataValue(metadataArg, 'saveableProperties'))); merged.uniqueIndexes = mergeStringArrays(...metadataArgs.map((metadataArg) => getOwnMetadataValue(metadataArg, 'uniqueIndexes'))); merged.searchableFields = mergeStringArrays(...metadataArgs.map((metadataArg) => getOwnMetadataValue(metadataArg, 'searchableFields'))); merged.regularIndexes = mergeRegularIndexes(...metadataArgs.map((metadataArg) => getOwnMetadataValue(metadataArg, 'regularIndexes'))); const svDbOptions = {}; for (const metadataArg of metadataArgs) { const options = getOwnMetadataValue(metadataArg, '_svDbOptions'); if (options) { Object.assign(svDbOptions, options); } } if (Object.keys(svDbOptions).length > 0) { merged._svDbOptions = svDbOptions; } return merged; }; const collectInheritedDecoratorMetadata = (constructor) => { const metadataChain = []; let proto = Object.getPrototypeOf(constructor.prototype); while (proto && proto !== Object.prototype) { const metadata = proto.constructor?.[Symbol.metadata]; if (metadata) { metadataChain.unshift(metadata); } proto = Object.getPrototypeOf(proto); } return mergeDecoratorMetadata(...metadataChain); }; /** * Initialize prototype and constructor properties from TC39 decorator metadata. * Shared by both Collection and managed decorators. */ function initializeDecoratorMetadata(constructor, metadata) { const mergedMetadata = mergeDecoratorMetadata(collectInheritedDecoratorMetadata(constructor), metadata); const proto = constructor.prototype; const ctor = constructor; // Prototype properties (instance-level) if (mergedMetadata.globalSaveableProperties?.length) { proto.globalSaveableProperties = [...mergedMetadata.globalSaveableProperties]; } if (mergedMetadata.saveableProperties?.length) { proto.saveableProperties = [...mergedMetadata.saveableProperties]; } if (mergedMetadata.uniqueIndexes?.length) { proto.uniqueIndexes = [...mergedMetadata.uniqueIndexes]; } if (mergedMetadata.regularIndexes?.length) { proto.regularIndexes = [...mergedMetadata.regularIndexes]; } // Constructor properties (static-level) if (mergedMetadata.searchableFields?.length) { ctor.searchableFields = [...mergedMetadata.searchableFields]; } if (mergedMetadata._svDbOptions) { ctor._svDbOptions = { ...mergedMetadata._svDbOptions }; } } /** * This is a decorator that will tell the decorated class what dbTable to use * @param dbArg */ export function Collection(dbArg) { return function classDecorator(value, context) { if (context.kind !== 'class') { throw new Error('Collection can only decorate classes'); } const constructor = value; const getCollection = () => { if (!(dbArg instanceof SmartdataDb)) { dbArg = dbArg(); } const coll = collectionFactory.getCollection(constructor.name, dbArg); // Attach document constructor for searchableFields lookup if (coll && !coll.docCtor) { coll.docCtor = constructor; } return coll; }; // Add static className property directly on the constructor constructor.className = constructor.name; // Define collection getter on constructor (static access) Object.defineProperty(constructor, 'collection', { get: getCollection, enumerable: false, configurable: true }); // Define collection getter on prototype (instance access) Object.defineProperty(constructor.prototype, 'collection', { get: getCollection, enumerable: false, configurable: true }); initializeDecoratorMetadata(constructor, context.metadata); return constructor; }; } export const setDefaultManagerForDoc = (managerArg, dbDocArg) => { dbDocArg.prototype.defaultManager = managerArg; return dbDocArg; }; /** * This is a decorator that will tell the decorated class what dbTable to use * @param dbArg */ export function managed(managerArg) { return function classDecorator(value, context) { if (context.kind !== 'class') { throw new Error('managed can only decorate classes'); } const constructor = value; constructor.className = constructor.name; // Resolution helpers (capture managerArg via closure) const getManager = (defaultManagerFn) => { if (!managerArg) return defaultManagerFn(); if (managerArg['db']) return managerArg; return managerArg(); }; const getDb = (defaultManagerFn) => { return getManager(defaultManagerFn).db; }; // Static getters Object.defineProperty(constructor, 'collection', { get() { return collectionFactory.getCollection(constructor.name, getDb(() => this.prototype.defaultManager)); }, enumerable: false, configurable: true }); Object.defineProperty(constructor, 'manager', { get() { return getManager(() => this.prototype.defaultManager); }, enumerable: false, configurable: true }); // Instance getters Object.defineProperty(constructor.prototype, 'collection', { get() { return collectionFactory.getCollection(constructor.name, getDb(() => this.defaultManager)); }, enumerable: false, configurable: true }); Object.defineProperty(constructor.prototype, 'manager', { get() { return getManager(() => this.defaultManager); }, enumerable: false, configurable: true }); initializeDecoratorMetadata(constructor, context.metadata); return constructor; }; } /** * @dpecrecated use @managed instead */ export const Manager = managed; export class SmartdataCollection { /** * the collection that is used */ mongoDbCollection; objectValidation = null; collectionName; smartdataDb; uniqueIndexes = []; regularIndexes = []; // flag to ensure text index is created only once textIndexCreated = false; constructor(classNameArg, smartDataDbArg) { // tell the collection where it belongs this.collectionName = classNameArg; this.smartdataDb = smartDataDbArg; // tell the db class about it (important since Db uses different systems under the hood) this.smartdataDb.addCollection(this); } /** * makes sure a collection exists within MongoDb that maps to the SmartdataCollection */ async init() { if (!this.mongoDbCollection) { // connect this instance to a MongoDB collection const availableMongoDbCollections = await this.smartdataDb.mongoDb.collections(); const wantedCollection = availableMongoDbCollections.find((collection) => { return collection.collectionName === this.collectionName; }); if (!wantedCollection) { await this.smartdataDb.mongoDb.createCollection(this.collectionName); logger.log('info', `Successfully initiated Collection ${this.collectionName}`); } this.mongoDbCollection = this.smartdataDb.mongoDb.collection(this.collectionName); // Auto-create a compound text index on all searchable fields // Use document constructor's searchableFields registered via decorator const docCtor = this.docCtor; const searchableFields = docCtor?.searchableFields || []; if (searchableFields.length > 0 && !this.textIndexCreated) { // Build a compound text index spec const indexSpec = {}; searchableFields.forEach(f => { indexSpec[f] = 'text'; }); // Cast to any to satisfy TypeScript IndexSpecification typing try { await this.mongoDbCollection.createIndex(indexSpec, { name: 'smartdata_text_index' }); this.textIndexCreated = true; } catch (err) { logger.log('warn', `Failed to create text index on fields [${searchableFields.join(', ')}] in collection "${this.collectionName}": ${err?.message || String(err)}`); } } } } /** * mark unique index */ async markUniqueIndexes(keyArrayArg = []) { for (const key of keyArrayArg) { if (!this.uniqueIndexes.includes(key)) { // Claim the slot immediately to prevent concurrent inserts from retrying this.uniqueIndexes.push(key); try { await this.mongoDbCollection.createIndex({ [key]: 1 }, { unique: true, }); } catch (err) { const errorCode = err?.code || err?.codeName || 'unknown'; const errorMessage = err?.message || String(err); logger.log('error', `Failed to create unique index on field "${key}" in collection "${this.collectionName}". ` + `MongoDB error [${errorCode}]: ${errorMessage}. ` + `Uniqueness constraint on "${key}" is NOT enforced.`); if (errorCode === 11000 || errorCode === 'DuplicateKey' || String(errorMessage).includes('E11000')) { await this.logDuplicatesForField(key); } } } } } /** * creates regular indexes for the collection */ async createRegularIndexes(indexesArg = []) { for (const indexDef of indexesArg) { // Check if we've already created this index const indexKey = indexDef.field; if (!this.regularIndexes.some(i => i.field === indexKey)) { // Claim the slot immediately to prevent concurrent retries this.regularIndexes.push(indexDef); try { await this.mongoDbCollection.createIndex({ [indexDef.field]: 1 }, // Simple single-field index indexDef.options); } catch (err) { const errorCode = err?.code || err?.codeName || 'unknown'; const errorMessage = err?.message || String(err); logger.log('warn', `Failed to create index on field "${indexKey}" in collection "${this.collectionName}". ` + `MongoDB error [${errorCode}]: ${errorMessage}.`); if (indexDef.options?.unique && (errorCode === 11000 || errorCode === 'DuplicateKey' || String(errorMessage).includes('E11000'))) { await this.logDuplicatesForField(indexKey); } } } } } /** * Logs duplicate values for a field to help diagnose unique index creation failures. */ async logDuplicatesForField(field) { try { const pipeline = [ { $group: { _id: `$${field}`, count: { $sum: 1 }, ids: { $push: '$_id' } } }, { $match: { count: { $gt: 1 } } }, { $limit: 5 }, ]; const duplicates = await this.mongoDbCollection.aggregate(pipeline).toArray(); if (duplicates.length > 0) { for (const dup of duplicates) { logger.log('warn', `Duplicate values for "${field}" in "${this.collectionName}": ` + `value=${JSON.stringify(dup._id)} appears ${dup.count} times ` + `(document _ids: ${JSON.stringify(dup.ids.slice(0, 5))})`); } logger.log('warn', `Unique index on "${field}" in "${this.collectionName}" was NOT created. ` + `Resolve duplicates and restart to enforce uniqueness.`); } } catch (aggErr) { logger.log('warn', `Could not identify duplicate documents for field "${field}" in "${this.collectionName}": ${aggErr?.message || String(aggErr)}`); } } /** * adds a validation function that all newly inserted and updated objects have to pass */ addDocValidation(funcArg) { this.objectValidation = funcArg; } /** * finds an object in the DbCollection */ async findOne(filterObject, opts) { await this.init(); // Use MongoDB driver's findOne with optional session return this.mongoDbCollection.findOne(filterObject, { session: opts?.session }); } async getCursor(filterObjectArg, dbDocArg, opts) { await this.init(); const cursor = this.mongoDbCollection.find(filterObjectArg, { session: opts?.session }); return new SmartdataDbCursor(cursor, dbDocArg); } /** * finds an object in the DbCollection */ async findAll(filterObject, opts) { await this.init(); const cursor = this.mongoDbCollection.find(filterObject, { session: opts?.session }); const result = await cursor.toArray(); cursor.close(); // In-memory check for duplicate _id values (should never happen) if (result.length > 0) { const idSet = new Set(); const duplicateIds = []; for (const doc of result) { const idStr = String(doc._id); if (idSet.has(idStr)) { duplicateIds.push(idStr); } else { idSet.add(idStr); } } if (duplicateIds.length > 0) { logger.log('error', `Integrity issue in "${this.collectionName}": found ${duplicateIds.length} duplicate _id values ` + `in findAll results: [${duplicateIds.slice(0, 5).join(', ')}]. This should never happen.`); } } return result; } /** * Watches the collection, returning a SmartdataDbWatcher with RxJS and EventEmitter support. * @param filterObject match filter for change stream * @param opts optional MongoDB ChangeStreamOptions & { bufferTimeMs } to buffer events * @param smartdataDbDocArg document class for instance creation */ async watch(filterObject, opts = {}, smartdataDbDocArg) { await this.init(); // Extract bufferTimeMs from options const { bufferTimeMs, fullDocument, ...otherOptions } = opts || {}; // Determine fullDocument behavior: default to 'updateLookup' const changeStreamOptions = { ...otherOptions, fullDocument: fullDocument === undefined ? 'updateLookup' : fullDocument === true ? 'updateLookup' : fullDocument, }; // Build pipeline with match if provided const pipeline = filterObject ? [{ $match: filterObject }] : []; const changeStream = this.mongoDbCollection.watch(pipeline, changeStreamOptions); const smartdataWatcher = new SmartdataDbWatcher(changeStream, smartdataDbDocArg, { bufferTimeMs }); await smartdataWatcher.readyDeferred.promise; return smartdataWatcher; } /** * create an object in the database */ async insert(dbDocArg, opts) { await this.init(); await this.checkDoc(dbDocArg); await this.markUniqueIndexes(dbDocArg.uniqueIndexes); // Create regular indexes if available if (dbDocArg.regularIndexes && dbDocArg.regularIndexes.length > 0) { await this.createRegularIndexes(dbDocArg.regularIndexes); } const saveableObject = await dbDocArg.createSavableObject(); try { const result = await this.mongoDbCollection.insertOne(saveableObject, { session: opts?.session }); return result; } catch (err) { const isDuplicateKey = err?.code === 11000 || err?.codeName === 'DuplicateKey'; if (isDuplicateKey && dbDocArg.uniqueIndexes && dbDocArg.uniqueIndexes.length > 0) { const identifiableObject = await dbDocArg.createIdentifiableObject(); logger.log('error', `Duplicate key conflict in "${this.collectionName}" on insert. ` + `A document with ${JSON.stringify(identifiableObject)} already exists. ` + `Use getInstance() to retrieve the existing document, or update it via save() on a db-retrieved instance.`); } throw err; } } /** * inserts object into the DbCollection */ async update(dbDocArg, opts) { await this.init(); await this.checkDoc(dbDocArg); await this.markUniqueIndexes(dbDocArg.uniqueIndexes); if (dbDocArg.regularIndexes && dbDocArg.regularIndexes.length > 0) { await this.createRegularIndexes(dbDocArg.regularIndexes); } const identifiableObject = await dbDocArg.createIdentifiableObject(); const saveableObject = await dbDocArg.createSavableObject(); const updateableObject = {}; for (const key of Object.keys(saveableObject)) { if (identifiableObject[key]) { continue; } updateableObject[key] = saveableObject[key]; } const result = await this.mongoDbCollection.updateOne(identifiableObject, { $set: updateableObject }, { upsert: true, session: opts?.session }); return result; } async delete(dbDocArg, opts) { await this.init(); await this.checkDoc(dbDocArg); const identifiableObject = await dbDocArg.createIdentifiableObject(); await this.mongoDbCollection.deleteOne(identifiableObject, { session: opts?.session }); } async getCount(filterObject, opts) { await this.init(); return this.mongoDbCollection.countDocuments(filterObject, { session: opts?.session }); } /** * Runs an integrity check on the collection. * Compares estimated vs actual document count and checks for duplicates on unique index fields. */ async checkCollectionIntegrity() { await this.init(); const result = { ok: true, estimatedCount: 0, actualCount: 0, duplicateFields: [], }; try { result.estimatedCount = await this.mongoDbCollection.estimatedDocumentCount(); result.actualCount = await this.mongoDbCollection.countDocuments({}); if (result.estimatedCount !== result.actualCount) { result.ok = false; logger.log('warn', `Integrity check on "${this.collectionName}": estimatedDocumentCount=${result.estimatedCount} ` + `but countDocuments=${result.actualCount}. Possible data inconsistency.`); } // Check for duplicates on each tracked unique index field for (const field of this.uniqueIndexes) { try { const pipeline = [ { $group: { _id: `$${field}`, count: { $sum: 1 } } }, { $match: { count: { $gt: 1 } } }, { $count: 'total' }, ]; const countResult = await this.mongoDbCollection.aggregate(pipeline).toArray(); const dupCount = countResult[0]?.total || 0; if (dupCount > 0) { result.ok = false; result.duplicateFields.push({ field, duplicateValues: dupCount }); logger.log('warn', `Integrity check on "${this.collectionName}": field "${field}" has ${dupCount} values with duplicates ` + `despite being marked as unique.`); } } catch (fieldErr) { logger.log('warn', `Integrity check: could not verify uniqueness of "${field}" in "${this.collectionName}": ${fieldErr?.message || String(fieldErr)}`); } } } catch (err) { result.ok = false; logger.log('error', `Integrity check failed for "${this.collectionName}": ${err?.message || String(err)}`); } return result; } /** * checks a Doc for constraints * if this.objectValidation is not set it passes. */ checkDoc(docArg) { const done = plugins.smartpromise.defer(); let validationResult = true; if (this.objectValidation) { validationResult = this.objectValidation(docArg); } if (validationResult) { done.resolve(); } else { done.reject('validation of object did not pass'); } return done.promise; } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5jb2xsZWN0aW9uLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvY2xhc3Nlcy5jb2xsZWN0aW9uLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sY0FBYyxDQUFDO0FBQ3hDLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUM5QyxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUN4RCxPQUFPLEVBQUUsY0FBYyxFQUFzQixNQUFNLGtCQUFrQixDQUFDO0FBQ3RFLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQzFELE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLGdDQUFnQyxDQUFDO0FBQ25FLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxjQUFjLENBQUM7QUFldEMsTUFBTSxpQkFBaUIsR0FBRyxJQUFJLGlCQUFpQixFQUFFLENBQUM7QUFXbEQsTUFBTSxtQkFBbUIsR0FBRyxDQUFJLFFBQWEsRUFBRSxHQUFzQyxFQUFpQixFQUFFO0lBQ3RHLElBQUksQ0FBQyxRQUFRLElBQUksQ0FBQyxNQUFNLENBQUMsU0FBUyxDQUFDLGNBQWMsQ0FBQyxJQUFJLENBQUMsUUFBUSxFQUFFLEdBQUcsQ0FBQyxFQUFFLENBQUM7UUFDdEUsT0FBTyxTQUFTLENBQUM7SUFDbkIsQ0FBQztJQUNELE9BQU8sUUFBUSxDQUFDLEdBQUcsQ0FBTSxDQUFDO0FBQzVCLENBQUMsQ0FBQztBQUVGLE1BQU0saUJBQWlCLEdBQUcsQ0FBQyxHQUFHLE1BQW1DLEVBQVksRUFBRTtJQUM3RSxNQUFNLE1BQU0sR0FBYSxFQUFFLENBQUM7SUFDNUIsS0FBSyxNQUFNLEtBQUssSUFBSSxNQUFNLEVBQUUsQ0FBQztRQUMzQixJQUFJLENBQUMsS0FBSyxFQUFFLENBQUM7WUFDWCxTQUFTO1FBQ1gsQ0FBQztRQUNELEtBQUssTUFBTSxJQUFJLElB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