@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
JavaScript
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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