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.

549 lines 46.1 kB
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; var __metadata = (this && this.__metadata) || function (k, v) { if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v); }; import * as plugins from './plugins.js'; import { SmartdataDb } from './classes.db.js'; import { SmartdataDbCursor } from './classes.cursor.js'; import { SmartdataCollection } from './classes.collection.js'; import { SmartdataDbWatcher } from './classes.watcher.js'; import { SmartdataLuceneAdapter } from './classes.lucene.adapter.js'; export function globalSvDb() { return (target, key) => { console.log(`called svDb() on >${target.constructor.name}.${key}<`); if (!target.globalSaveableProperties) { target.globalSaveableProperties = []; } target.globalSaveableProperties.push(key); }; } /** * saveable - saveable decorator to be used on class properties */ export function svDb(options) { return (target, key) => { console.log(`called svDb() on >${target.constructor.name}.${key}<`); if (!target.saveableProperties) { target.saveableProperties = []; } target.saveableProperties.push(key); // attach custom serializer/deserializer options to the class constructor const ctor = target.constructor; if (!ctor._svDbOptions) { ctor._svDbOptions = {}; } if (options) { ctor._svDbOptions[key] = options; } }; } /** * searchable - marks a property as searchable with Lucene query syntax */ export function searchable() { return (target, key) => { // Attach to class constructor for direct access const ctor = target.constructor; if (!Array.isArray(ctor.searchableFields)) { ctor.searchableFields = []; } ctor.searchableFields.push(key); }; } // Escape user input for safe use in MongoDB regular expressions function escapeForRegex(input) { return input.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); } /** * unique index - decorator to mark a unique index */ export function unI() { return (target, key) => { console.log(`called unI on >>${target.constructor.name}.${key}<<`); // mark the index as unique if (!target.uniqueIndexes) { target.uniqueIndexes = []; } target.uniqueIndexes.push(key); // and also save it if (!target.saveableProperties) { target.saveableProperties = []; } target.saveableProperties.push(key); }; } /** * index - decorator to mark a field for regular indexing */ export function index(options) { return (target, key) => { console.log(`called index() on >${target.constructor.name}.${key}<`); // Initialize regular indexes array if it doesn't exist if (!target.regularIndexes) { target.regularIndexes = []; } // Add this field to regularIndexes with its options target.regularIndexes.push({ field: key, options: options || {} }); // Also ensure it's marked as saveable if (!target.saveableProperties) { target.saveableProperties = []; } if (!target.saveableProperties.includes(key)) { target.saveableProperties.push(key); } }; } export const convertFilterForMongoDb = (filterArg) => { // Special case: detect MongoDB operators and pass them through directly const topLevelOperators = ['$and', '$or', '$nor', '$not', '$text', '$where', '$regex']; for (const key of Object.keys(filterArg)) { if (topLevelOperators.includes(key)) { return filterArg; // Return the filter as-is for MongoDB operators } } // Original conversion logic for non-MongoDB query objects const convertedFilter = {}; const convertFilterArgument = (keyPathArg2, filterArg2) => { if (Array.isArray(filterArg2)) { // Directly assign arrays (they might be using operators like $in or $all) convertFilterArgument(keyPathArg2, filterArg2[0]); } else if (typeof filterArg2 === 'object' && filterArg2 !== null) { for (const key of Object.keys(filterArg2)) { if (key.startsWith('$')) { convertedFilter[keyPathArg2] = filterArg2; return; } else if (key.includes('.')) { throw new Error('keys cannot contain dots'); } } for (const key of Object.keys(filterArg2)) { convertFilterArgument(`${keyPathArg2}.${key}`, filterArg2[key]); } } else { convertedFilter[keyPathArg2] = filterArg2; } }; for (const key of Object.keys(filterArg)) { convertFilterArgument(key, filterArg[key]); } return convertedFilter; }; export class SmartDataDbDoc { // STATIC static createInstanceFromMongoDbNativeDoc(mongoDbNativeDocArg) { const newInstance = new this(); newInstance.creationStatus = 'db'; for (const key of Object.keys(mongoDbNativeDocArg)) { const rawValue = mongoDbNativeDocArg[key]; const optionsMap = this._svDbOptions || {}; const opts = optionsMap[key]; newInstance[key] = opts && typeof opts.deserialize === 'function' ? opts.deserialize(rawValue) : rawValue; } return newInstance; } /** * gets all instances as array * @param this * @param filterArg * @returns */ static async getInstances(filterArg, opts) { // Pass session through to findAll for transactional queries const foundDocs = await this.collection.findAll(convertFilterForMongoDb(filterArg), { session: opts?.session }); const returnArray = []; for (const foundDoc of foundDocs) { const newInstance = this.createInstanceFromMongoDbNativeDoc(foundDoc); returnArray.push(newInstance); } return returnArray; } /** * gets the first matching instance * @param this * @param filterArg * @returns */ static async getInstance(filterArg, opts) { // Retrieve one document, with optional session for transactions const foundDoc = await this.collection.findOne(convertFilterForMongoDb(filterArg), { session: opts?.session }); if (foundDoc) { const newInstance = this.createInstanceFromMongoDbNativeDoc(foundDoc); return newInstance; } else { return null; } } /** * get a unique id prefixed with the class name */ static async getNewId(lengthArg = 20) { return `${this.className}:${plugins.smartunique.shortId(lengthArg)}`; } /** * Get a cursor for streaming results, with optional session and native cursor modifiers. * @param filterArg Partial filter to apply * @param opts Optional session and modifier for the raw MongoDB cursor */ static async getCursor(filterArg, opts) { const collection = this.collection; const { session, modifier } = opts || {}; await collection.init(); let rawCursor = collection.mongoDbCollection.find(convertFilterForMongoDb(filterArg), { session }); if (modifier) { rawCursor = modifier(rawCursor); } return new SmartdataDbCursor(rawCursor, this); } /** * watch the collection * @param this * @param filterArg * @param forEachFunction */ static async watch(filterArg) { const collection = this.collection; const watcher = await collection.watch(convertFilterForMongoDb(filterArg), this); return watcher; } /** * run a function for all instances * @returns */ static async forEach(filterArg, forEachFunction) { const cursor = await this.getCursor(filterArg); await cursor.forEach(forEachFunction); } /** * returns a count of the documents in the collection */ static async getCount(filterArg = {}) { const collection = this.collection; return await collection.getCount(filterArg); } /** * Create a MongoDB filter from a Lucene query string * @param luceneQuery Lucene query string * @returns MongoDB query object */ static createSearchFilter(luceneQuery) { const searchableFields = this.getSearchableFields(); if (searchableFields.length === 0) { throw new Error(`No searchable fields defined for class ${this.name}`); } const adapter = new SmartdataLuceneAdapter(searchableFields); return adapter.convert(luceneQuery); } /** * List all searchable fields defined on this class */ static getSearchableFields() { const ctor = this; return Array.isArray(ctor.searchableFields) ? ctor.searchableFields : []; } /** * Execute a query with optional hard filter and post-fetch validation */ static async execQuery(baseFilter, opts) { let mongoFilter = baseFilter || {}; if (opts?.filter) { mongoFilter = { $and: [mongoFilter, opts.filter] }; } // Fetch with optional session for transactions // Fetch within optional session let docs = await this.getInstances(mongoFilter, { session: opts?.session }); if (opts?.validate) { const out = []; for (const d of docs) { if (await opts.validate(d)) out.push(d); } docs = out; } return docs; } /** * Search documents by text or field:value syntax, with safe regex fallback * Supports additional filtering and post-fetch validation via opts * @param query A search term or field:value expression * @param opts Optional filter and validate hooks * @returns Array of matching documents */ static async search(query, opts) { const searchableFields = this.getSearchableFields(); if (searchableFields.length === 0) { throw new Error(`No searchable fields defined for class ${this.name}`); } // empty query -> return all const q = query.trim(); if (!q) { // empty query: fetch all, apply opts return await this.execQuery({}, opts); } // simple exact field:value (no spaces, no wildcards, no quotes) // simple exact field:value (no spaces, wildcards, quotes) const simpleExact = q.match(/^(\w+):([^"'\*\?\s]+)$/); if (simpleExact) { const field = simpleExact[1]; const value = simpleExact[2]; if (!searchableFields.includes(field)) { throw new Error(`Field '${field}' is not searchable for class ${this.name}`); } // simple field:value search return await this.execQuery({ [field]: value }, opts); } // quoted phrase across all searchable fields: exact match of phrase const quoted = q.match(/^"(.+)"$|^'(.+)'$/); if (quoted) { const phrase = quoted[1] || quoted[2] || ''; const parts = phrase.split(/\s+/).map((t) => escapeForRegex(t)); const pattern = parts.join('\\s+'); const orConds = searchableFields.map((f) => ({ [f]: { $regex: pattern, $options: 'i' } })); return await this.execQuery({ $or: orConds }, opts); } // wildcard field:value (supports * and ?) -> direct regex on that field const wildcardField = q.match(/^(\w+):(.+[*?].*)$/); if (wildcardField) { const field = wildcardField[1]; // Support quoted wildcard patterns: strip surrounding quotes let pattern = wildcardField[2]; if ((pattern.startsWith('"') && pattern.endsWith('"')) || (pattern.startsWith("'") && pattern.endsWith("'"))) { pattern = pattern.slice(1, -1); } if (!searchableFields.includes(field)) { throw new Error(`Field '${field}' is not searchable for class ${this.name}`); } // escape regex special chars except * and ?, then convert wildcards const escaped = pattern.replace(/([.+^${}()|[\\]\\])/g, '\\$1'); const regexPattern = escaped.replace(/\*/g, '.*').replace(/\?/g, '.'); return await this.execQuery({ [field]: { $regex: regexPattern, $options: 'i' } }, opts); } // wildcard plain term across all fields (supports * and ?) if (!q.includes(':') && (q.includes('*') || q.includes('?'))) { // build wildcard regex pattern: escape all except * and ? then convert const escaped = q.replace(/([.+^${}()|[\\]\\])/g, '\\$1'); const pattern = escaped.replace(/\*/g, '.*').replace(/\?/g, '.'); const orConds = searchableFields.map((f) => ({ [f]: { $regex: pattern, $options: 'i' } })); return await this.execQuery({ $or: orConds }, opts); } // implicit AND for multiple tokens: free terms, quoted phrases, and field:values { // Split query into tokens, preserving quoted substrings const rawTokens = q.match(/(?:[^\s"']+|"[^"]*"|'[^']*')+/g) || []; // Only apply when more than one token and no boolean operators or grouping if (rawTokens.length > 1 && !/(\bAND\b|\bOR\b|\bNOT\b|\(|\))/i.test(q) && !/\[|\]/.test(q)) { const andConds = []; for (let token of rawTokens) { // field:value token const fv = token.match(/^(\w+):(.+)$/); if (fv) { const field = fv[1]; let value = fv[2]; if (!searchableFields.includes(field)) { throw new Error(`Field '${field}' is not searchable for class ${this.name}`); } // Strip surrounding quotes if present if ((value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'"))) { value = value.slice(1, -1); } // Wildcard search? if (value.includes('*') || value.includes('?')) { const escaped = value.replace(/([.+^${}()|[\\]\\])/g, '\\$1'); const pattern = escaped.replace(/\*/g, '.*').replace(/\?/g, '.'); andConds.push({ [field]: { $regex: pattern, $options: 'i' } }); } else { andConds.push({ [field]: value }); } } else if ((token.startsWith('"') && token.endsWith('"')) || (token.startsWith("'") && token.endsWith("'"))) { // Quoted free phrase across all fields const phrase = token.slice(1, -1); const parts = phrase.split(/\s+/).map((t) => escapeForRegex(t)); const pattern = parts.join('\\s+'); andConds.push({ $or: searchableFields.map((f) => ({ [f]: { $regex: pattern, $options: 'i' } })) }); } else { // Free term across all fields const esc = escapeForRegex(token); andConds.push({ $or: searchableFields.map((f) => ({ [f]: { $regex: esc, $options: 'i' } })) }); } } return await this.execQuery({ $and: andConds }, opts); } } // detect advanced Lucene syntax: field:value, wildcards, boolean, grouping const luceneSyntax = /(\w+:[^\s]+)|\*|\?|\bAND\b|\bOR\b|\bNOT\b|\(|\)/; if (luceneSyntax.test(q)) { const filter = this.createSearchFilter(q); return await this.execQuery(filter, opts); } // multi-term unquoted -> AND of regex across fields for each term const terms = q.split(/\s+/); if (terms.length > 1) { const andConds = terms.map((term) => { const esc = escapeForRegex(term); const ors = searchableFields.map((f) => ({ [f]: { $regex: esc, $options: 'i' } })); return { $or: ors }; }); return await this.execQuery({ $and: andConds }, opts); } // single term -> regex across all searchable fields const esc = escapeForRegex(q); const orConds = searchableFields.map((f) => ({ [f]: { $regex: esc, $options: 'i' } })); return await this.execQuery({ $or: orConds }, opts); } /** * class constructor */ constructor() { // INSTANCE // INSTANCE /** * how the Doc in memory was created, may prove useful later. */ this.creationStatus = 'new'; /** * updated from db in any case where doc comes from db */ this._createdAt = new Date().toISOString(); /** * will be updated everytime the doc is saved */ this._updatedAt = new Date().toISOString(); /** * regular indexes with their options */ this.regularIndexes = []; } /** * saves this instance (optionally within a transaction) */ async save(opts) { // allow hook before saving if (typeof this.beforeSave === 'function') { await this.beforeSave(); } // tslint:disable-next-line: no-this-assignment const self = this; let dbResult; // update timestamp this._updatedAt = new Date().toISOString(); // perform insert or update switch (this.creationStatus) { case 'db': dbResult = await this.collection.update(self, { session: opts?.session }); break; case 'new': dbResult = await this.collection.insert(self, { session: opts?.session }); this.creationStatus = 'db'; break; default: console.error('neither new nor in db?'); } // allow hook after saving if (typeof this.afterSave === 'function') { await this.afterSave(); } return dbResult; } /** * deletes a document from the database (optionally within a transaction) */ async delete(opts) { // allow hook before deleting if (typeof this.beforeDelete === 'function') { await this.beforeDelete(); } // perform deletion const result = await this.collection.delete(this, { session: opts?.session }); // allow hook after delete if (typeof this.afterDelete === 'function') { await this.afterDelete(); } return result; } /** * also store any referenced objects to DB * better for data consistency */ saveDeep(savedMapArg = null) { if (!savedMapArg) { savedMapArg = new plugins.lik.ObjectMap(); } savedMapArg.add(this); this.save(); for (const propertyKey of Object.keys(this)) { const property = this[propertyKey]; if (property instanceof SmartDataDbDoc && !savedMapArg.checkForObject(property)) { property.saveDeep(savedMapArg); } } } /** * updates an object from db */ async updateFromDb() { const mongoDbNativeDoc = await this.collection.findOne(await this.createIdentifiableObject()); for (const key of Object.keys(mongoDbNativeDoc)) { const rawValue = mongoDbNativeDoc[key]; const optionsMap = this.constructor._svDbOptions || {}; const opts = optionsMap[key]; this[key] = opts && typeof opts.deserialize === 'function' ? opts.deserialize(rawValue) : rawValue; } } /** * creates a saveable object so the instance can be persisted as json in the database */ async createSavableObject() { const saveableObject = {}; // is not exposed to outside, so any is ok here const saveableProperties = [...this.globalSaveableProperties, ...this.saveableProperties]; // apply custom serialization if configured const optionsMap = this.constructor._svDbOptions || {}; for (const propertyNameString of saveableProperties) { const rawValue = this[propertyNameString]; const opts = optionsMap[propertyNameString]; saveableObject[propertyNameString] = opts && typeof opts.serialize === 'function' ? opts.serialize(rawValue) : rawValue; } return saveableObject; } /** * creates an identifiable object for operations that require filtering */ async createIdentifiableObject() { const identifiableObject = {}; // is not exposed to outside, so any is ok here for (const propertyNameString of this.uniqueIndexes) { identifiableObject[propertyNameString] = this[propertyNameString]; } return identifiableObject; } } __decorate([ globalSvDb(), __metadata("design:type", String) ], SmartDataDbDoc.prototype, "_createdAt", void 0); __decorate([ globalSvDb(), __metadata("design:type", String) ], SmartDataDbDoc.prototype, "_updatedAt", void 0); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5kb2MuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9jbGFzc2VzLmRvYy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7QUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGNBQWMsQ0FBQztBQUV4QyxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDOUMsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDeEQsT0FBTyxFQUFpQixtQkFBbUIsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQzdFLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQzFELE9BQU8sRUFBRSxzQkFBc0IsRUFBRSxNQUFNLDZCQUE2QixDQUFDO0FBeUJyRSxNQUFNLFVBQVUsVUFBVTtJQUN4QixPQUFPLENBQUMsTUFBd0MsRUFBRSxHQUFXLEVBQUUsRUFBRTtRQUMvRCxPQUFPLENBQUMsR0FBRyxDQUFDLHFCQUFxQixNQUFNLENBQUMsV0FBVyxDQUFDLElBQUksSUFBSSxHQUFHLEdBQUcsQ0FBQyxDQUFDO1FBQ3BFLElBQUksQ0FBQyxNQUFNLENBQUMsd0JBQXdCLEVBQUUsQ0FBQztZQUNyQyxNQUFNLENBQUMsd0JBQXdCLEdBQUcsRUFBRSxDQUFDO1FBQ3ZDLENBQUM7UUFDRCxNQUFNLENBQUMsd0JBQXdCLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQzVDLENBQUMsQ0FBQztBQUNKLENBQUM7QUFZRDs7R0FFRztBQUNILE1BQU0sVUFBVSxJQUFJLENBQUMsT0FBcUI7SUFDeEMsT0FBTyxDQUFDLE1BQXdDLEVBQUUsR0FBVyxFQUFFLEVBQUU7UUFDL0QsT0FBTyxDQUFDLEdBQUcsQ0FBQyxxQkFBcUIsTUFBTSxDQUFDLFdBQVcsQ0FBQyxJQUFJLElBQUksR0FBRyxHQUFHLENBQUMsQ0FBQztRQUNwRSxJQUFJLENBQUMsTUFBTSxDQUFDLGtCQUFrQixFQUFF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