@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.
252 lines • 17.8 kB
JavaScript
import * as plugins from './smartdata.plugins.js';
import { SmartdataDb } from './smartdata.classes.db.js';
import { SmartdataDbCursor } from './smartdata.classes.cursor.js';
import { SmartDataDbDoc } from './smartdata.classes.doc.js';
import { SmartdataDbWatcher } from './smartdata.classes.watcher.js';
import { CollectionFactory } from './smartdata.classes.collectionfactory.js';
const collectionFactory = new CollectionFactory();
/**
* This is a decorator that will tell the decorated class what dbTable to use
* @param dbArg
*/
export function Collection(dbArg) {
return function classDecorator(constructor) {
const decoratedClass = class extends constructor {
static { this.className = constructor.name; }
static get collection() {
if (!(dbArg instanceof SmartdataDb)) {
dbArg = dbArg();
}
return collectionFactory.getCollection(constructor.name, dbArg);
}
get collection() {
if (!(dbArg instanceof SmartdataDb)) {
dbArg = dbArg();
}
return collectionFactory.getCollection(constructor.name, dbArg);
}
};
return decoratedClass;
};
}
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(constructor) {
const decoratedClass = class extends constructor {
static { this.className = constructor.name; }
static get collection() {
let dbArg;
if (!managerArg) {
dbArg = this.prototype.defaultManager.db;
}
else if (managerArg['db']) {
dbArg = managerArg.db;
}
else {
dbArg = managerArg().db;
}
return collectionFactory.getCollection(constructor.name, dbArg);
}
get collection() {
let dbArg;
if (!managerArg) {
//console.log(this.defaultManager.db);
//process.exit(0)
dbArg = this.defaultManager.db;
}
else if (managerArg['db']) {
dbArg = managerArg.db;
}
else {
dbArg = managerArg().db;
}
return collectionFactory.getCollection(constructor.name, dbArg);
}
static get manager() {
let manager;
if (!managerArg) {
manager = this.prototype.defaultManager;
}
else if (managerArg['db']) {
manager = managerArg;
}
else {
manager = managerArg();
}
return manager;
}
get manager() {
let manager;
if (!managerArg) {
manager = this.defaultManager;
}
else if (managerArg['db']) {
manager = managerArg;
}
else {
manager = managerArg();
}
return manager;
}
};
return decoratedClass;
};
}
/**
* @dpecrecated use @managed instead
*/
export const Manager = managed;
export class SmartdataCollection {
constructor(classNameArg, smartDataDbArg) {
this.objectValidation = null;
this.uniqueIndexes = [];
// 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);
console.log(`Successfully initiated Collection ${this.collectionName}`);
}
this.mongoDbCollection = this.smartdataDb.mongoDb.collection(this.collectionName);
}
}
/**
* mark unique index
*/
markUniqueIndexes(keyArrayArg = []) {
for (const key of keyArrayArg) {
if (!this.uniqueIndexes.includes(key)) {
this.mongoDbCollection.createIndex(key, {
unique: true,
});
// make sure we only call this once and not for every doc we create
this.uniqueIndexes.push(key);
}
}
}
/**
* 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) {
await this.init();
const cursor = this.mongoDbCollection.find(filterObject);
const result = await cursor.next();
cursor.close();
return result;
}
async getCursor(filterObjectArg, dbDocArg) {
await this.init();
const cursor = this.mongoDbCollection.find(filterObjectArg);
return new SmartdataDbCursor(cursor, dbDocArg);
}
/**
* finds an object in the DbCollection
*/
async findAll(filterObject) {
await this.init();
const cursor = this.mongoDbCollection.find(filterObject);
const result = await cursor.toArray();
cursor.close();
return result;
}
/**
* watches the collection while applying a filter
*/
async watch(filterObject, smartdataDbDocArg) {
await this.init();
const changeStream = this.mongoDbCollection.watch([
{
$match: filterObject,
},
], {
fullDocument: 'updateLookup',
});
const smartdataWatcher = new SmartdataDbWatcher(changeStream, smartdataDbDocArg);
await smartdataWatcher.readyDeferred.promise;
return smartdataWatcher;
}
/**
* create an object in the database
*/
async insert(dbDocArg) {
await this.init();
await this.checkDoc(dbDocArg);
this.markUniqueIndexes(dbDocArg.uniqueIndexes);
const saveableObject = await dbDocArg.createSavableObject();
const result = await this.mongoDbCollection.insertOne(saveableObject);
return result;
}
/**
* inserts object into the DbCollection
*/
async update(dbDocArg) {
await this.init();
await this.checkDoc(dbDocArg);
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 });
return result;
}
async delete(dbDocArg) {
await this.init();
await this.checkDoc(dbDocArg);
const identifiableObject = await dbDocArg.createIdentifiableObject();
await this.mongoDbCollection.deleteOne(identifiableObject);
}
async getCount(filterObject) {
await this.init();
return this.mongoDbCollection.countDocuments(filterObject);
}
/**
* 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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnRkYXRhLmNsYXNzZXMuY29sbGVjdGlvbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL3NtYXJ0ZGF0YS5jbGFzc2VzLmNvbGxlY3Rpb24udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSx3QkFBd0IsQ0FBQztBQUNsRCxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sMkJBQTJCLENBQUM7QUFDeEQsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sK0JBQStCLENBQUM7QUFDbEUsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBQzVELE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLGdDQUFnQyxDQUFDO0FBQ3BFLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLDBDQUEwQyxDQUFDO0FBZTdFLE1BQU0saUJBQWlCLEdBQUcsSUFBSSxpQkFBaUIsRUFBRSxDQUFDO0FBRWxEOzs7R0FHRztBQUNILE1BQU0sVUFBVSxVQUFVLENBQUMsS0FBMEM7SUFDbkUsT0FBTyxTQUFTLGNBQWMsQ0FBeUMsV0FBYztRQUNuRixNQUFNLGNBQWMsR0FBRyxLQUFNLFNBQVEsV0FBVztxQkFDaEMsY0FBUyxHQUFHLFdBQVcsQ0FBQyxJQUFJLENBQUM7WUFDcEMsTUFBTSxLQUFLLFVBQVU7Z0JBQzFCLElBQUksQ0FBQyxDQUFDLEtBQUssWUFBWSxXQUFXLENBQUMsRUFBRTtvQkFDbkMsS0FBSyxHQUFHLEtBQUssRUFBRSxDQUFDO2lCQUNqQjtnQkFDRCxPQUFPLGlCQUFpQixDQUFDLGFBQWEsQ0FBQyxXQUFXLENBQUMsSUFBSSxFQUFFLEtBQUssQ0FBQyxDQUFDO1lBQ2xFLENBQUM7WUFDRCxJQUFXLFVBQVU7Z0JBQ25CLElBQUksQ0FBQyxDQUFDLEtBQUssWUFBWSxXQUFXLENBQUMsRUFBRTtvQkFDbkMsS0FBSyxHQUFHLEtBQUssRUFBRSxDQUFDO2lCQUNqQjtnQkFDRCxPQUFPLGlCQUFp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