fix(core): update

This commit is contained in:
Philipp Kunz 2019-09-02 16:42:29 +02:00
parent c6cbff1308
commit 25803330de
7 changed files with 954 additions and 551 deletions

1281
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -21,26 +21,27 @@
}, },
"homepage": "https://gitlab.com/pushrocks/smartdata#README", "homepage": "https://gitlab.com/pushrocks/smartdata#README",
"dependencies": { "dependencies": {
"@pushrocks/lik": "^3.0.4", "@pushrocks/lik": "^3.0.11",
"@pushrocks/smartlog": "^2.0.9", "@pushrocks/smartlog": "^2.0.19",
"@pushrocks/smartpromise": "^2.0.5", "@pushrocks/smartpromise": "^3.0.2",
"@pushrocks/smartstring": "^3.0.5", "@pushrocks/smartstring": "^3.0.10",
"@types/lodash": "^4.14.119", "@pushrocks/smartunique": "^3.0.1",
"@types/mongodb": "^3.1.18", "@types/lodash": "^4.14.138",
"lodash": "^4.17.11", "@types/mongodb": "^3.3.1",
"mongodb": "^3.1.10", "lodash": "^4.17.15",
"mongodb": "^3.3.2",
"runtime-type-checks": "0.0.4" "runtime-type-checks": "0.0.4"
}, },
"devDependencies": { "devDependencies": {
"@gitzone/tsbuild": "^2.1.4", "@gitzone/tsbuild": "^2.1.17",
"@gitzone/tstest": "^1.0.18", "@gitzone/tstest": "^1.0.24",
"@pushrocks/qenv": "^3.0.2", "@pushrocks/qenv": "^4.0.4",
"@pushrocks/tapbundle": "^3.0.7", "@pushrocks/tapbundle": "^3.0.13",
"@types/node": "^10.12.18", "@types/mongodb-memory-server": "^1.8.0",
"@types/node": "^12.7.3",
"@types/shortid": "0.0.29", "@types/shortid": "0.0.29",
"mongodb-memory-server": "^2.9.1", "mongodb-memory-server": "^5.2.0",
"shortid": "^2.2.14", "tslint": "^5.19.0",
"tslint": "^5.12.0", "tslint-config-prettier": "^1.18.0"
"tslint-config-prettier": "^1.17.0"
} }
} }

View File

@ -1,22 +1,39 @@
import { tap, expect } from '@pushrocks/tapbundle'; import { tap, expect } from '@pushrocks/tapbundle';
import * as smartpromise from '@pushrocks/smartpromise';
import { Qenv } from '@pushrocks/qenv'; import { Qenv } from '@pushrocks/qenv';
let testQenv = new Qenv(process.cwd(), process.cwd() + '/.nogit/'); const testQenv = new Qenv(process.cwd(), process.cwd() + '/.nogit/');
// the tested module // the tested module
import * as smartdata from '../ts/index'; import * as smartdata from '../ts/index';
import { smartstring } from '../ts/smartdata.plugins'; import { smartstring } from '../ts/smartdata.plugins';
import * as shortid from 'shortid'; import * as smartunique from '@pushrocks/smartunique';
import * as mongoPlugin from 'mongodb-memory-server';
// ======================================= // =======================================
// Connecting to the database server // Connecting to the database server
// ======================================= // =======================================
let testDb = new smartdata.SmartdataDb({ let testDb: smartdata.SmartdataDb;
mongoDbName: process.env.MONGO_DBNAME, let smartdataOptions: smartdata.ISmartdataOptions;
mongoDbUrl: process.env.MONGO_URL, let mongod: mongoPlugin.MongoMemoryServer;
mongoDbPass: process.env.MONGO_PASS
tap.test('should create a testinstance as database', async () => {
mongod = new mongoPlugin.MongoMemoryServer();
smartdataOptions = {
mongoDbName: await mongod.getDbName(),
mongoDbPass: '',
mongoDbUrl: await mongod.getConnectionString()
};
console.log(smartdataOptions);
});
tap.test('should create a smartdb', async () => {
testDb = new smartdata.SmartdataDb({
mongoDbName: testQenv.getEnvVarOnDemand('MONGO_DBNAME'),
mongoDbUrl: testQenv.getEnvVarOnDemand('MONGO_URL'),
mongoDbPass: testQenv.getEnvVarOnDemand('MONGO_PASS')
});
}); });
tap.test('should establish a connection to the rethink Db cluster', async () => { tap.test('should establish a connection to the rethink Db cluster', async () => {
@ -31,11 +48,19 @@ tap.test('should establish a connection to the rethink Db cluster', async () =>
// Collections // Collections
// ------ // ------
@smartdata.Collection(testDb) @smartdata.Collection(() => {
return testDb;
})
class Car extends smartdata.SmartDataDbDoc<Car> { class Car extends smartdata.SmartDataDbDoc<Car> {
@smartdata.unI() index: string = shortid(); @smartdata.unI()
@smartdata.svDb() color: string; public index: string = smartunique.shortId();
@smartdata.svDb() brand: string;
@smartdata.svDb()
public color: string;
@smartdata.svDb()
public brand: string;
constructor(colorArg: string, brandArg: string) { constructor(colorArg: string, brandArg: string) {
super(); super();
this.color = colorArg; this.color = colorArg;
@ -46,20 +71,38 @@ class Car extends smartdata.SmartDataDbDoc<Car> {
tap.test('should save the car to the db', async () => { tap.test('should save the car to the db', async () => {
const myCar = new Car('red', 'Volvo'); const myCar = new Car('red', 'Volvo');
await myCar.save(); await myCar.save();
const myCar2 = new Car('red', 'Renault');
await myCar2.save();
}); });
tap.test('expect to get instance of Car', async () => { tap.test('expect to get instance of Car', async () => {
let myCars = await Car.getInstances<Car>({ const myCars = await Car.getInstances<Car>({
brand: 'Volvo' brand: 'Volvo'
}); });
expect(myCars[0].color).to.equal('red'); expect(myCars[0].color).to.equal('red');
}); });
tap.test('expect to get instance of Car and update it', async () => {
const myCar = await Car.getInstance<Car>({
brand: 'Volvo'
});
expect(myCar.color).to.equal('red');
myCar.color = 'blue';
await myCar.save();
});
tap.test('should be able to update an instance of car', async () => {});
tap.test('should be able to delete an instance of car', async () => {});
// ======================================= // =======================================
// close the database connection // close the database connection
// ======================================= // =======================================
tap.test('should close the database connection', async tools => { tap.test('should close the database connection', async tools => {
await testDb.close(); await testDb.close();
await mongod.stop();
}); });
tap.start({ throwOnError: true }); tap.start({ throwOnError: true });

View File

@ -36,11 +36,11 @@ export class SmartdataCollection<T> {
/** /**
* the collection that is used * the collection that is used
*/ */
mongoDbCollection: plugins.mongodb.Collection; public mongoDbCollection: plugins.mongodb.Collection;
objectValidation: IDocValidationFunc<T> = null; public objectValidation: IDocValidationFunc<T> = null;
collectionName: string; public collectionName: string;
smartdataDb: SmartdataDb; public smartdataDb: SmartdataDb;
uniqueIndexes: string[] = []; public uniqueIndexes: string[] = [];
constructor(collectedClassArg: T & SmartDataDbDoc<T>, smartDataDbArg: SmartdataDb) { constructor(collectedClassArg: T & SmartDataDbDoc<T>, smartDataDbArg: SmartdataDb) {
// tell the collection where it belongs // tell the collection where it belongs
@ -54,7 +54,7 @@ export class SmartdataCollection<T> {
/** /**
* makes sure a collection exists within MongoDb that maps to the SmartdataCollection * makes sure a collection exists within MongoDb that maps to the SmartdataCollection
*/ */
async init() { public async init() {
if (!this.mongoDbCollection) { if (!this.mongoDbCollection) {
// connect this instance to a MongoDB collection // connect this instance to a MongoDB collection
const availableMongoDbCollections = await this.smartdataDb.mongoDb.collections(); const availableMongoDbCollections = await this.smartdataDb.mongoDb.collections();
@ -65,15 +65,15 @@ export class SmartdataCollection<T> {
await this.smartdataDb.mongoDb.createCollection(this.collectionName); await this.smartdataDb.mongoDb.createCollection(this.collectionName);
} }
this.mongoDbCollection = await this.smartdataDb.mongoDb.collection(this.collectionName); this.mongoDbCollection = await this.smartdataDb.mongoDb.collection(this.collectionName);
console.log(`Successfully initiated Collection ${this.collectionName}`); // console.log(`Successfully initiated Collection ${this.collectionName}`);
} }
} }
/** /**
* mark unique index * mark unique index
*/ */
markUniqueIndexes(keyArrayArg: string[] = []) { public markUniqueIndexes(keyArrayArg: string[] = []) {
for (let key of keyArrayArg) { for (const key of keyArrayArg) {
if (!this.uniqueIndexes.includes(key)) { if (!this.uniqueIndexes.includes(key)) {
this.mongoDbCollection.createIndex(key, { this.mongoDbCollection.createIndex(key, {
unique: true unique: true
@ -87,14 +87,14 @@ export class SmartdataCollection<T> {
/** /**
* adds a validation function that all newly inserted and updated objects have to pass * adds a validation function that all newly inserted and updated objects have to pass
*/ */
addDocValidation(funcArg: IDocValidationFunc<T>) { public addDocValidation(funcArg: IDocValidationFunc<T>) {
this.objectValidation = funcArg; this.objectValidation = funcArg;
} }
/** /**
* finds an object in the DbCollection * finds an object in the DbCollection
*/ */
async find(filterObject: any): Promise<any> { public async find(filterObject: any): Promise<any> {
await this.init(); await this.init();
const result = await this.mongoDbCollection.find(filterObject).toArray(); const result = await this.mongoDbCollection.find(filterObject).toArray();
return result; return result;
@ -103,7 +103,7 @@ export class SmartdataCollection<T> {
/** /**
* create an object in the database * create an object in the database
*/ */
async insert(dbDocArg: T & SmartDataDbDoc<T>): Promise<any> { public async insert(dbDocArg: T & SmartDataDbDoc<T>): Promise<any> {
await this.init(); await this.init();
await this.checkDoc(dbDocArg); await this.checkDoc(dbDocArg);
this.markUniqueIndexes(dbDocArg.uniqueIndexes); this.markUniqueIndexes(dbDocArg.uniqueIndexes);
@ -120,7 +120,17 @@ export class SmartdataCollection<T> {
await this.checkDoc(dbDocArg); await this.checkDoc(dbDocArg);
const identifiableObject = await dbDocArg.createIdentifiableObject(); const identifiableObject = await dbDocArg.createIdentifiableObject();
const saveableObject = await dbDocArg.createSavableObject(); const saveableObject = await dbDocArg.createSavableObject();
this.mongoDbCollection.updateOne(identifiableObject, saveableObject); console.log(identifiableObject);
console.log(saveableObject);
const updateableObject: any = {};
for (const key of Object.keys(saveableObject)) {
if (identifiableObject[key]) {
continue;
}
updateableObject[key] = saveableObject[key];
}
console.log(updateableObject);
this.mongoDbCollection.updateOne(identifiableObject, { $set: updateableObject }, {upsert: true});
} }
public async delete(dbDocArg: T & SmartDataDbDoc<T>): Promise<any> { public async delete(dbDocArg: T & SmartDataDbDoc<T>): Promise<any> {

View File

@ -44,7 +44,7 @@ export class SmartdataDb {
/** /**
* connects to the database that was specified during instance creation * connects to the database that was specified during instance creation
*/ */
async init(): Promise<any> { public async init(): Promise<any> {
let finalConnectionUrl = this.smartdataOptions.mongoDbUrl; let finalConnectionUrl = this.smartdataOptions.mongoDbUrl;
if (this.smartdataOptions.mongoDbPass) { if (this.smartdataOptions.mongoDbPass) {
finalConnectionUrl = mongoHelpers.addPassword( finalConnectionUrl = mongoHelpers.addPassword(
@ -52,7 +52,7 @@ export class SmartdataDb {
this.smartdataOptions.mongoDbPass this.smartdataOptions.mongoDbPass
); );
} }
console.log(finalConnectionUrl); console.log(`connection Url: ${finalConnectionUrl}`);
this.mongoDbClient = await plugins.mongodb.MongoClient.connect(finalConnectionUrl, { this.mongoDbClient = await plugins.mongodb.MongoClient.connect(finalConnectionUrl, {
useNewUrlParser: true useNewUrlParser: true
}); });
@ -64,7 +64,7 @@ export class SmartdataDb {
/** /**
* closes the connection to the databse * closes the connection to the databse
*/ */
async close(): Promise<any> { public async close(): Promise<any> {
await this.mongoDbClient.close(); await this.mongoDbClient.close();
this.status = 'disconnected'; this.status = 'disconnected';
plugins.smartlog.defaultLogger.log( plugins.smartlog.defaultLogger.log(
@ -75,7 +75,7 @@ export class SmartdataDb {
// handle table to class distribution // handle table to class distribution
addTable(SmartdataCollectionArg: SmartdataCollection<any>) { public addTable(SmartdataCollectionArg: SmartdataCollection<any>) {
this.smartdataCollectionMap.add(SmartdataCollectionArg); this.smartdataCollectionMap.add(SmartdataCollectionArg);
} }
@ -84,8 +84,8 @@ export class SmartdataDb {
* @param nameArg * @param nameArg
* @returns DbTable * @returns DbTable
*/ */
async getSmartdataCollectionByName<T>(nameArg: string): Promise<SmartdataCollection<T>> { public async getSmartdataCollectionByName<T>(nameArg: string): Promise<SmartdataCollection<T>> {
let resultCollection = this.smartdataCollectionMap.find(dbTableArg => { const resultCollection = this.smartdataCollectionMap.find(dbTableArg => {
return dbTableArg.collectionName === nameArg; return dbTableArg.collectionName === nameArg;
}); });
return resultCollection; return resultCollection;

View File

@ -45,32 +45,32 @@ export class SmartDataDbDoc<T> {
/** /**
* the collection object an Doc belongs to * the collection object an Doc belongs to
*/ */
collection: SmartdataCollection<T>; public collection: SmartdataCollection<T>;
/** /**
* how the Doc in memory was created, may prove useful later. * how the Doc in memory was created, may prove useful later.
*/ */
creationStatus: TDocCreation = 'new'; public creationStatus: TDocCreation = 'new';
/** /**
* unique indexes * unique indexes
*/ */
uniqueIndexes: string[]; public uniqueIndexes: string[];
/** /**
* an array of saveable properties of a doc * an array of saveable properties of a doc
*/ */
saveableProperties: string[]; public saveableProperties: string[];
/** /**
* name * name
*/ */
name: string; public name: string;
/** /**
* primary id in the database * primary id in the database
*/ */
dbDocUniqueId: string; public dbDocUniqueId: string;
/** /**
* class constructor * class constructor
@ -89,8 +89,8 @@ export class SmartDataDbDoc<T> {
} }
} }
static async getInstances<T>(filterArg): Promise<T[]> { public static async getInstances<T>(filterArg): Promise<T[]> {
let self: any = this; // fool typesystem const self: any = this; // fool typesystem
let referenceMongoDBCollection: SmartdataCollection<T>; let referenceMongoDBCollection: SmartdataCollection<T>;
if (self.smartdataCollection) { if (self.smartdataCollection) {
@ -100,9 +100,10 @@ export class SmartDataDbDoc<T> {
} }
const foundDocs = await referenceMongoDBCollection.find(filterArg); const foundDocs = await referenceMongoDBCollection.find(filterArg);
const returnArray = []; const returnArray = [];
for (let item of foundDocs) { for (const item of foundDocs) {
let newInstance = new this(); const newInstance = new this();
for (let key in item) { newInstance.creationStatus = 'db';
for (const key in item) {
if (key !== 'id') { if (key !== 'id') {
newInstance[key] = item[key]; newInstance[key] = item[key];
} }
@ -113,7 +114,7 @@ export class SmartDataDbDoc<T> {
} }
static async getInstance<T>(filterArg): Promise<T> { static async getInstance<T>(filterArg): Promise<T> {
let result = await this.getInstances<T>(filterArg); const result = await this.getInstances<T>(filterArg);
if (result && result.length > 0) { if (result && result.length > 0) {
return result[0]; return result[0];
} }
@ -123,15 +124,15 @@ export class SmartDataDbDoc<T> {
* saves this instance but not any connected items * saves this instance but not any connected items
* may lead to data inconsistencies, but is faster * may lead to data inconsistencies, but is faster
*/ */
async save() { public async save() {
// tslint:disable-next-line: no-this-assignment // tslint:disable-next-line: no-this-assignment
let self: any = this; const self: any = this;
switch (this.creationStatus) { switch (this.creationStatus) {
case 'db': case 'db':
await this.collection.update(self); await this.collection.update(self);
break; break;
case 'new': case 'new':
let writeResult = await this.collection.insert(self); const writeResult = await this.collection.insert(self);
this.creationStatus = 'db'; this.creationStatus = 'db';
break; break;
default: default:
@ -142,20 +143,20 @@ export class SmartDataDbDoc<T> {
/** /**
* deletes a document from the database * deletes a document from the database
*/ */
async delete() {} public async delete() {}
/** /**
* also store any referenced objects to DB * also store any referenced objects to DB
* better for data consistency * better for data consistency
*/ */
saveDeep(savedMapArg: Objectmap<SmartDataDbDoc<any>> = null) { public saveDeep(savedMapArg: Objectmap<SmartDataDbDoc<any>> = null) {
if (!savedMapArg) { if (!savedMapArg) {
savedMapArg = new Objectmap<SmartDataDbDoc<any>>(); savedMapArg = new Objectmap<SmartDataDbDoc<any>>();
} }
savedMapArg.add(this); savedMapArg.add(this);
this.save(); this.save();
for (let propertyKey in this) { for (const propertyKey of Object.keys(this)) {
let property: any = this[propertyKey]; const property: any = this[propertyKey];
if (property instanceof SmartDataDbDoc && !savedMapArg.checkForObject(property)) { if (property instanceof SmartDataDbDoc && !savedMapArg.checkForObject(property)) {
property.saveDeep(savedMapArg); property.saveDeep(savedMapArg);
} }

View File

@ -4,5 +4,6 @@ import * as lodash from 'lodash';
import * as mongodb from 'mongodb'; import * as mongodb from 'mongodb';
import * as smartq from '@pushrocks/smartpromise'; import * as smartq from '@pushrocks/smartpromise';
import * as smartstring from '@pushrocks/smartstring'; import * as smartstring from '@pushrocks/smartstring';
import * as smartunique from '@pushrocks/smartunique';
export { assert, smartlog, lodash, smartq, mongodb, smartstring }; export { assert, smartlog, lodash, smartq, mongodb, smartstring, smartunique };