fix(core): update

This commit is contained in:
Philipp Kunz 2021-11-12 16:23:26 +01:00
parent 9b3892c1e8
commit 551916fe5c
4 changed files with 155 additions and 38 deletions

View File

@ -200,14 +200,19 @@ class Truck extends smartdata.SmartDataDbDoc<Car, Car> {
tap.test('should store a new Truck', async () => { tap.test('should store a new Truck', async () => {
const truck = new Truck('blue', 'MAN'); const truck = new Truck('blue', 'MAN');
await truck.save(); await truck.save();
const myTruck = await Truck.getInstance({ color: 'blue' });
myTruck.id = 'foo';
await myTruck.save();
const myTruck2 = await Truck.getInstance({ color: 'blue' }); const myTruck2 = await Truck.getInstance({ color: 'blue' });
console.log(myTruck2); myTruck2.color = 'red';
await myTruck2.save();
const myTruck3 = await Truck.getInstance({ color: 'blue' });
console.log(myTruck3);
}); });
tap.test('should ', async () => {}); tap.test('should use a cursor', async () => {
const cursor = await Truck.getCursor({});
cursor.forEach(async truckArg => {
console.log(truckArg.id);
});
});
// ======================================= // =======================================
// close the database connection // close the database connection

View File

@ -1,5 +1,6 @@
import * as plugins from './smartdata.plugins'; import * as plugins from './smartdata.plugins';
import { SmartdataDb } from './smartdata.classes.db'; import { SmartdataDb } from './smartdata.classes.db';
import { SmartdataDbCursor } from './smartdata.classes.cursor';
import { SmartDataDbDoc } from './smartdata.classes.doc'; import { SmartDataDbDoc } from './smartdata.classes.doc';
import { CollectionFactory } from './smartdata.classes.collectionfactory'; import { CollectionFactory } from './smartdata.classes.collectionfactory';
@ -170,9 +171,28 @@ export class SmartdataCollection<T> {
/** /**
* finds an object in the DbCollection * finds an object in the DbCollection
*/ */
public async find(filterObject: any): Promise<any> { public async findOne(filterObject: any): Promise<any> {
await this.init(); await this.init();
const result = await this.mongoDbCollection.find(filterObject).toArray(); const cursor = this.mongoDbCollection.find(filterObject);
const result = await cursor.next();
cursor.close();
return result;
}
public async getCursor(filterObject: any): Promise<SmartdataDbCursor<any>> {
await this.init();
const cursor = this.mongoDbCollection.find(filterObject);
return new SmartdataDbCursor(cursor);
}
/**
* finds an object in the DbCollection
*/
public async findAll(filterObject: any): Promise<any[]> {
await this.init();
const cursor = this.mongoDbCollection.find(filterObject);
const result = await cursor.toArray();
cursor.close();
return result; return result;
} }

View File

@ -0,0 +1,39 @@
import * as plugins from './smartdata.plugins';
/**
* a wrapper for the native mongodb cursor. Exposes better
*/
export class SmartdataDbCursor<T = any> {
// STATIC
// INSTANCE
public mongodbCursor: plugins.mongodb.Cursor<T>;
constructor(cursorArg: plugins.mongodb.Cursor<T>) {
this.mongodbCursor = cursorArg
};
public async next(closeAtEnd = true) {
const result = await this.mongodbCursor.next();
if (!result && closeAtEnd) {
await this.close();
};
return result;
};
public async forEach(forEachFuncArg: (itemArg: T) => Promise<any>, closeCursorAtEnd = true) {
let currentValue: T;
do {
currentValue = await this.mongodbCursor.next();
if (currentValue) {
await forEachFuncArg(currentValue);
}
} while (currentValue);
if (closeCursorAtEnd) {
await this.close();
}
}
public async close() {
await this.mongodbCursor.close();
}
}

View File

@ -3,6 +3,7 @@ import * as plugins from './smartdata.plugins';
import { ObjectMap } from '@pushrocks/lik'; import { ObjectMap } from '@pushrocks/lik';
import { SmartdataDb } from './smartdata.classes.db'; import { SmartdataDb } from './smartdata.classes.db';
import { SmartdataDbCursor } from './smartdata.classes.cursor';
import { IManager, SmartdataCollection } from './smartdata.classes.collection'; import { IManager, SmartdataCollection } from './smartdata.classes.collection';
export type TDocCreation = 'db' | 'new' | 'mixed'; export type TDocCreation = 'db' | 'new' | 'mixed';
@ -41,6 +42,31 @@ export function unI() {
}; };
} }
export const convertFilterForMongoDb = (filterArg: { [key: string]: any }) => {
const convertedFilter: { [key: string]: any } = {};
const convertFilterArgument = (keyPathArg2: string, filterArg2: any) => {
if (typeof filterArg2 === 'object') {
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<T extends TImplements, TImplements, TManager extends IManager = any> { export class SmartDataDbDoc<T extends TImplements, TImplements, TManager extends IManager = any> {
/** /**
* the collection object an Doc belongs to * the collection object an Doc belongs to
@ -81,54 +107,81 @@ export class SmartDataDbDoc<T extends TImplements, TImplements, TManager extends
*/ */
constructor() {} constructor() {}
public static createInstanceFromMongoDbNativeDoc<T>(
this: plugins.tsclass.typeFest.Class<T>,
mongoDbNativeDocArg: any
): T {
const newInstance = new this();
(newInstance as any).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
*/
public static async getInstances<T>( public static async getInstances<T>(
this: plugins.tsclass.typeFest.Class<T>, this: plugins.tsclass.typeFest.Class<T>,
filterArg: plugins.tsclass.typeFest.PartialDeep<T> filterArg: plugins.tsclass.typeFest.PartialDeep<T>
): Promise<T[]> { ): Promise<T[]> {
const convertedFilter: any = {}; const foundDocs = await (this as any).collection.findAll(convertFilterForMongoDb(filterArg));
const convertFilterArgument = (keyPathArg: string, filterArg2: any) => {
if (typeof filterArg2 === 'object') {
for (const key of Object.keys(filterArg2)) {
if (key.startsWith('$')) {
convertedFilter[keyPathArg] = filterArg2;
return;
} else if (key.includes('.')) {
throw new Error('keys cannot contain dots');
}
}
for (const key of Object.keys(filterArg2)) {
convertFilterArgument(`${keyPathArg}.${key}`, filterArg2[key]);
}
} else {
convertedFilter[keyPathArg] = filterArg2;
}
};
for (const key of Object.keys(filterArg)) {
convertFilterArgument(key, filterArg[key]);
}
const foundDocs = await (this as any).collection.find(convertedFilter);
const returnArray = []; const returnArray = [];
for (const item of foundDocs) { for (const foundDoc of foundDocs) {
const newInstance = new this(); const newInstance: T = (this as any).createInstanceFromMongoDbNativeDoc(foundDoc);
(newInstance as any).creationStatus = 'db';
for (const key of Object.keys(item)) {
newInstance[key] = item[key];
}
returnArray.push(newInstance); returnArray.push(newInstance);
} }
return returnArray; return returnArray;
} }
/**
* gets the first matching instance
* @param this
* @param filterArg
* @returns
*/
public static async getInstance<T>( public static async getInstance<T>(
this: plugins.tsclass.typeFest.Class<T>, this: plugins.tsclass.typeFest.Class<T>,
filterArg: plugins.tsclass.typeFest.PartialDeep<T> filterArg: plugins.tsclass.typeFest.PartialDeep<T>
): Promise<T> { ): Promise<T> {
const result = await (this as any).getInstances(filterArg); const foundDoc = await (this as any).collection.findOne(convertFilterForMongoDb(filterArg));
if (result && result.length > 0) { if (foundDoc) {
return result[0]; const newInstance: T = (this as any).createInstanceFromMongoDbNativeDoc(foundDoc);
return newInstance;
} else {
return null;
} }
} }
/**
* get cursor
* @returns
*/
public static async getCursor<T>(
this: plugins.tsclass.typeFest.Class<T>,
filterArg: plugins.tsclass.typeFest.PartialDeep<T>
) {
const cursor: SmartdataDbCursor<T> = await (this as any).collection.getCursor(convertFilterForMongoDb(filterArg));
return cursor;
}
/**
* run a function for all instances
* @returns
*/
public static async forEach<T>(
this: plugins.tsclass.typeFest.Class<T>,
filterArg: plugins.tsclass.typeFest.PartialDeep<T>,
forEachFunction: (itemArg: T) => Promise<any>
) {
const cursor: SmartdataDbCursor<T> = await (this as any).getCursor(filterArg);
await cursor.forEach(forEachFunction)
}
/** /**
* 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