2018-07-08 21:48:14 +00:00
|
|
|
import * as plugins from './smartdata.plugins';
|
|
|
|
import { SmartdataDb } from './smartdata.classes.db';
|
2018-07-09 22:02:04 +00:00
|
|
|
import { SmartDataDbDoc } from './smartdata.classes.doc';
|
2018-01-14 16:32:04 +00:00
|
|
|
|
|
|
|
export interface IFindOptions {
|
|
|
|
limit?: number;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
export interface IDocValidationFunc<T> {
|
|
|
|
(doc: T): boolean;
|
|
|
|
}
|
|
|
|
|
2019-01-08 13:37:17 +00:00
|
|
|
export type TDelayedDbCreation = () => SmartdataDb;
|
|
|
|
|
2018-01-14 16:32:04 +00:00
|
|
|
/**
|
|
|
|
* This is a decorator that will tell the decorated class what dbTable to use
|
2019-01-08 13:37:17 +00:00
|
|
|
* @param dbArg
|
2018-01-14 16:32:04 +00:00
|
|
|
*/
|
2019-01-08 13:37:17 +00:00
|
|
|
export function Collection(dbArg: SmartdataDb | TDelayedDbCreation) {
|
2018-01-14 16:32:04 +00:00
|
|
|
return function(constructor) {
|
2019-01-08 13:37:17 +00:00
|
|
|
if (dbArg instanceof SmartdataDb) {
|
|
|
|
// tslint:disable-next-line: no-string-literal
|
|
|
|
constructor['smartdataCollection'] = new SmartdataCollection(constructor, dbArg);
|
|
|
|
} else {
|
|
|
|
constructor['smartdataDelayedDatabase'] = () => {
|
|
|
|
return new SmartdataCollection(constructor, dbArg());
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2018-01-14 16:32:04 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2018-07-08 21:48:14 +00:00
|
|
|
export class SmartdataCollection<T> {
|
2018-01-14 16:32:04 +00:00
|
|
|
/**
|
|
|
|
* the collection that is used
|
|
|
|
*/
|
2018-07-08 21:48:14 +00:00
|
|
|
mongoDbCollection: plugins.mongodb.Collection;
|
2018-01-14 16:32:04 +00:00
|
|
|
objectValidation: IDocValidationFunc<T> = null;
|
2018-07-08 21:48:14 +00:00
|
|
|
collectionName: string;
|
|
|
|
smartdataDb: SmartdataDb;
|
2018-07-10 19:27:16 +00:00
|
|
|
uniqueIndexes: string[] = [];
|
2018-01-14 16:32:04 +00:00
|
|
|
|
2018-07-09 22:02:04 +00:00
|
|
|
constructor(collectedClassArg: T & SmartDataDbDoc<T>, smartDataDbArg: SmartdataDb) {
|
2018-01-14 16:32:04 +00:00
|
|
|
// tell the collection where it belongs
|
2018-07-08 21:48:14 +00:00
|
|
|
this.collectionName = collectedClassArg.name;
|
|
|
|
this.smartdataDb = smartDataDbArg;
|
2018-01-14 16:32:04 +00:00
|
|
|
|
|
|
|
// tell the db class about it (important since Db uses different systems under the hood)
|
2018-07-08 21:48:14 +00:00
|
|
|
this.smartdataDb.addTable(this);
|
2018-01-14 16:32:04 +00:00
|
|
|
}
|
|
|
|
|
2018-07-08 21:48:14 +00:00
|
|
|
/**
|
|
|
|
* makes sure a collection exists within MongoDb that maps to the SmartdataCollection
|
|
|
|
*/
|
2018-01-14 16:32:04 +00:00
|
|
|
async init() {
|
2018-07-08 21:48:14 +00:00
|
|
|
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);
|
2018-01-14 16:32:04 +00:00
|
|
|
}
|
2018-07-08 21:48:14 +00:00
|
|
|
this.mongoDbCollection = await this.smartdataDb.mongoDb.collection(this.collectionName);
|
2019-01-07 01:41:38 +00:00
|
|
|
console.log(`Successfully initiated Collection ${this.collectionName}`);
|
2018-01-14 16:32:04 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-10 19:27:16 +00:00
|
|
|
/**
|
|
|
|
* mark unique index
|
|
|
|
*/
|
|
|
|
markUniqueIndexes(keyArrayArg: string[] = []) {
|
2019-01-07 01:41:38 +00:00
|
|
|
for (let key of keyArrayArg) {
|
|
|
|
if (!this.uniqueIndexes.includes(key)) {
|
2018-07-10 19:27:16 +00:00
|
|
|
this.mongoDbCollection.createIndex(key, {
|
|
|
|
unique: true
|
|
|
|
});
|
|
|
|
// make sure we only call this once and not for every doc we create
|
|
|
|
this.uniqueIndexes.push(key);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-01-14 16:32:04 +00:00
|
|
|
/**
|
|
|
|
* adds a validation function that all newly inserted and updated objects have to pass
|
|
|
|
*/
|
|
|
|
addDocValidation(funcArg: IDocValidationFunc<T>) {
|
|
|
|
this.objectValidation = funcArg;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* finds an object in the DbCollection
|
|
|
|
*/
|
|
|
|
async find(filterObject: any): Promise<any> {
|
|
|
|
await this.init();
|
2018-07-09 22:02:04 +00:00
|
|
|
const result = await this.mongoDbCollection.find(filterObject).toArray();
|
|
|
|
return result;
|
2018-01-14 16:32:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* create an object in the database
|
|
|
|
*/
|
2018-07-09 22:02:04 +00:00
|
|
|
async insert(dbDocArg: T & SmartDataDbDoc<T>): Promise<any> {
|
2018-01-14 16:32:04 +00:00
|
|
|
await this.init();
|
|
|
|
await this.checkDoc(dbDocArg);
|
2018-07-10 19:27:16 +00:00
|
|
|
this.markUniqueIndexes(dbDocArg.uniqueIndexes);
|
2018-07-08 21:48:14 +00:00
|
|
|
const saveableObject = await dbDocArg.createSavableObject();
|
2018-07-09 22:02:04 +00:00
|
|
|
console.log(saveableObject);
|
2018-07-08 21:48:14 +00:00
|
|
|
const result = await this.mongoDbCollection.insertOne(saveableObject);
|
|
|
|
return result;
|
2018-01-14 16:32:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* inserts object into the DbCollection
|
|
|
|
*/
|
2018-07-09 22:02:04 +00:00
|
|
|
async update(dbDocArg: T & SmartDataDbDoc<T>): Promise<any> {
|
2018-01-14 16:32:04 +00:00
|
|
|
await this.init();
|
|
|
|
await this.checkDoc(dbDocArg);
|
2018-07-08 21:48:14 +00:00
|
|
|
const saveableObject = await dbDocArg.createSavableObject();
|
|
|
|
this.mongoDbCollection.updateOne(saveableObject.dbDocUniqueId, saveableObject);
|
2018-01-14 16:32:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* checks a Doc for constraints
|
|
|
|
* if this.objectValidation is not set it passes.
|
|
|
|
*/
|
|
|
|
private checkDoc(docArg: T): Promise<void> {
|
|
|
|
let done = plugins.smartq.defer<void>();
|
|
|
|
let validationResult = true;
|
|
|
|
if (this.objectValidation) {
|
|
|
|
validationResult = this.objectValidation(docArg);
|
|
|
|
}
|
|
|
|
if (validationResult) {
|
|
|
|
done.resolve();
|
|
|
|
} else {
|
2018-07-08 21:48:14 +00:00
|
|
|
done.reject('validation of object did not pass');
|
2018-01-14 16:32:04 +00:00
|
|
|
}
|
|
|
|
return done.promise;
|
|
|
|
}
|
|
|
|
}
|