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