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.

271 lines 18 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 './smartdata.plugins.js'; import { SmartdataDb } from './smartdata.classes.db.js'; import { SmartdataDbCursor } from './smartdata.classes.cursor.js'; import { SmartdataCollection } from './smartdata.classes.collection.js'; import { SmartdataDbWatcher } from './smartdata.classes.watcher.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() { return (target, key) => { console.log(`called svDb() on >${target.constructor.name}.${key}<`); if (!target.saveableProperties) { target.saveableProperties = []; } target.saveableProperties.push(key); }; } /** * 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); }; } export const convertFilterForMongoDb = (filterArg) => { 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)) { newInstance[key] = mongoDbNativeDocArg[key]; } return newInstance; } /** * gets all instances as array * @param this * @param filterArg * @returns */ static async getInstances(filterArg) { const foundDocs = await this.collection.findAll(convertFilterForMongoDb(filterArg)); 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) { const foundDoc = await this.collection.findOne(convertFilterForMongoDb(filterArg)); 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 cursor * @returns */ static async getCursor(filterArg) { const collection = this.collection; const cursor = await collection.getCursor(convertFilterForMongoDb(filterArg), this); return cursor; } /** * 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); } /** * class constructor */ constructor() { // 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(); } /** * saves this instance but not any connected items * may lead to data inconsistencies, but is faster */ async save() { // tslint:disable-next-line: no-this-assignment const self = this; let dbResult; this._updatedAt = (new Date()).toISOString(); switch (this.creationStatus) { case 'db': dbResult = await this.collection.update(self); break; case 'new': dbResult = await this.collection.insert(self); this.creationStatus = 'db'; break; default: console.error('neither new nor in db?'); } return dbResult; } /** * deletes a document from the database */ async delete() { await this.collection.delete(this); } /** * 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)) { this[key] = mongoDbNativeDoc[key]; } } /** * 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 ]; for (const propertyNameString of saveableProperties) { saveableObject[propertyNameString] = this[propertyNameString]; } 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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnRkYXRhLmNsYXNzZXMuZG9jLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvc21hcnRkYXRhLmNsYXNzZXMuZG9jLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7OztBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sd0JBQXdCLENBQUM7QUFFbEQsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBQ3hELE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLCtCQUErQixDQUFDO0FBQ2xFLE9BQU8sRUFBaUIsbUJBQW1CLEVBQUUsTUFBTSxtQ0FBbUMsQ0FBQztBQUN2RixPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSxnQ0FBZ0MsQ0FBQztBQUlwRSxNQUFNLFVBQVUsVUFBVTtJQUN4QixPQUFPLENBQUMsTUFBd0MsRUFBRSxHQUFXLEVBQUUsRUFBRTtRQUMvRCxPQUFPLENBQUMsR0FBRyxDQUFDLHFCQUFxQixNQUFNLENBQUMsV0FBVyxDQUFDLElBQUksSUFBSSxHQUFHLEdBQUcsQ0FBQyxDQUFDO1FBQ3BFLElBQUksQ0FBQyxNQUFNLENBQUMsd0JBQXdCLEVBQUU7WUFDcEMsTUFBTSxDQUFDLHdCQUF3QixHQUFHLEVBQUUsQ0FBQztTQUN0QztRQUNELE1BQU0sQ0FBQyx3QkFBd0IsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDNUMsQ0FBQyxDQUFDO0FBQ0osQ0FBQztBQUVEOztHQUVHO0FBQ0gsTUFBTSxVQUFVLElBQUk7SUFDbEIsT0FBTyxDQUFDLE1BQXdDLEVBQUUsR0FBVyxFQUFFLEVBQUU7UUFDL0QsT0FBTyxDQUFDLEdBQUcsQ0FBQyxxQkFBcUIsTUFBTSxDQUFDLFdBQVcsQ0FBQyxJQUFJLElBQUksR0FBRyxHQUFHLENBQUMsQ0FBQztRQUNwRSxJQUFJLENBQUMsTUFBTSxDQUFDLGtCQUFrQixFQUFFO1lBQzlCLE1BQU0sQ0FBQyxrQkFBa0IsR0FBRyxFQUFFLENBQUM7U0FDaEM7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