Compare commits
66 Commits
Author | SHA1 | Date | |
---|---|---|---|
8b2beb3485 | |||
144a620f43 | |||
c241247845 | |||
81e39d09e4 | |||
8e51b518b1 | |||
8308d8d03b | |||
97365ddf29 | |||
55d96fa68d | |||
54ec6accdf | |||
fc5d092b25 | |||
dfba057562 | |||
1ad05943b5 | |||
302e51a77f | |||
1330d03af2 | |||
a298e9d190 | |||
e571ef347b | |||
39a4c7ef3f | |||
0d3518d990 | |||
fbdde2268c | |||
8b6c26f45a | |||
97e82ed75a | |||
03baffd9fd | |||
f29ae67580 | |||
e550a8dbd6 | |||
cf6ef25a8d | |||
29c512b0cc | |||
105f69d1c9 | |||
4c375f8465 | |||
9466af6a4a | |||
c5aa747f42 | |||
b5f2474f65 | |||
85f0d99934 | |||
3b2d3d9072 | |||
3ff5c36fdf | |||
a5acc2fe4e | |||
9c81257101 | |||
f7342962f4 | |||
bcd10205d3 | |||
6cab20f32d | |||
5aaa6ad2d6 | |||
635256f2f6 | |||
f799d3efa5 | |||
f74020ba96 | |||
f6d6545ff5 | |||
85a196c8c1 | |||
adb198af01 | |||
6dce9f3ff8 | |||
2f6a4ce3e5 | |||
0984a1ade4 | |||
804701c96a | |||
a3759fa484 | |||
ef38df62be | |||
c17789e92e | |||
0bf2ba554d | |||
5cbf1a222a | |||
f075530838 | |||
efb83853fb | |||
73300ca4d3 | |||
1e946cdceb | |||
608ff93a41 | |||
6211953f14 | |||
99e520b776 | |||
eda8297356 | |||
ffa52a5883 | |||
1e83f0a0ef | |||
0203eabdfd |
@ -19,23 +19,35 @@ mirror:
|
|||||||
stage: security
|
stage: security
|
||||||
script:
|
script:
|
||||||
- npmci git mirror
|
- npmci git mirror
|
||||||
|
only:
|
||||||
|
- tags
|
||||||
tags:
|
tags:
|
||||||
- lossless
|
- lossless
|
||||||
- docker
|
- docker
|
||||||
- notpriv
|
- notpriv
|
||||||
|
|
||||||
audit:
|
auditProductionDependencies:
|
||||||
|
image: registry.gitlab.com/hosttoday/ht-docker-node:npmci
|
||||||
|
stage: security
|
||||||
|
script:
|
||||||
|
- npmci npm prepare
|
||||||
|
- npmci command npm install --production --ignore-scripts
|
||||||
|
- npmci command npm config set registry https://registry.npmjs.org
|
||||||
|
- npmci command npm audit --audit-level=high --only=prod --production
|
||||||
|
tags:
|
||||||
|
- docker
|
||||||
|
|
||||||
|
auditDevDependencies:
|
||||||
image: registry.gitlab.com/hosttoday/ht-docker-node:npmci
|
image: registry.gitlab.com/hosttoday/ht-docker-node:npmci
|
||||||
stage: security
|
stage: security
|
||||||
script:
|
script:
|
||||||
- npmci npm prepare
|
- npmci npm prepare
|
||||||
- npmci command npm install --ignore-scripts
|
- npmci command npm install --ignore-scripts
|
||||||
- npmci command npm config set registry https://registry.npmjs.org
|
- npmci command npm config set registry https://registry.npmjs.org
|
||||||
- npmci command npm audit --audit-level=high
|
- npmci command npm audit --audit-level=high --only=dev
|
||||||
tags:
|
tags:
|
||||||
- lossless
|
|
||||||
- docker
|
- docker
|
||||||
- notpriv
|
allow_failure: true
|
||||||
|
|
||||||
# ====================
|
# ====================
|
||||||
# test stage
|
# test stage
|
||||||
@ -50,9 +62,7 @@ testStable:
|
|||||||
- npmci npm test
|
- npmci npm test
|
||||||
coverage: /\d+.?\d+?\%\s*coverage/
|
coverage: /\d+.?\d+?\%\s*coverage/
|
||||||
tags:
|
tags:
|
||||||
- lossless
|
|
||||||
- docker
|
- docker
|
||||||
- priv
|
|
||||||
|
|
||||||
testBuild:
|
testBuild:
|
||||||
stage: test
|
stage: test
|
||||||
@ -63,9 +73,7 @@ testBuild:
|
|||||||
- npmci command npm run build
|
- npmci command npm run build
|
||||||
coverage: /\d+.?\d+?\%\s*coverage/
|
coverage: /\d+.?\d+?\%\s*coverage/
|
||||||
tags:
|
tags:
|
||||||
- lossless
|
|
||||||
- docker
|
- docker
|
||||||
- notpriv
|
|
||||||
|
|
||||||
release:
|
release:
|
||||||
stage: release
|
stage: release
|
||||||
@ -85,6 +93,8 @@ release:
|
|||||||
codequality:
|
codequality:
|
||||||
stage: metadata
|
stage: metadata
|
||||||
allow_failure: true
|
allow_failure: true
|
||||||
|
only:
|
||||||
|
- tags
|
||||||
script:
|
script:
|
||||||
- npmci command npm install -g tslint typescript
|
- npmci command npm install -g tslint typescript
|
||||||
- npmci npm prepare
|
- npmci npm prepare
|
||||||
|
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
@ -15,7 +15,7 @@
|
|||||||
"properties": {
|
"properties": {
|
||||||
"projectType": {
|
"projectType": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["website", "element", "service", "npm"]
|
"enum": ["website", "element", "service", "npm", "wcc"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
25390
package-lock.json
generated
25390
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
36
package.json
36
package.json
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@pushrocks/smartdata",
|
"name": "@pushrocks/smartdata",
|
||||||
"version": "3.1.29",
|
"version": "4.0.6",
|
||||||
"private": false,
|
"private": false,
|
||||||
"description": "do more with data",
|
"description": "do more with data",
|
||||||
"main": "dist_ts/index.js",
|
"main": "dist_ts/index.js",
|
||||||
@ -21,27 +21,28 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://gitlab.com/pushrocks/smartdata#README",
|
"homepage": "https://gitlab.com/pushrocks/smartdata#README",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@pushrocks/lik": "^4.0.13",
|
"@pushrocks/lik": "^4.0.20",
|
||||||
"@pushrocks/smartlog": "^2.0.35",
|
"@pushrocks/smartlog": "^2.0.39",
|
||||||
"@pushrocks/smartpromise": "^3.0.6",
|
"@pushrocks/smartpromise": "^3.1.5",
|
||||||
"@pushrocks/smartstring": "^3.0.18",
|
"@pushrocks/smartstring": "^3.0.24",
|
||||||
"@pushrocks/smartunique": "^3.0.3",
|
"@tsclass/tsclass": "^3.0.33",
|
||||||
"@types/lodash": "^4.14.155",
|
"@types/lodash": "^4.14.169",
|
||||||
"@types/mongodb": "^3.5.20",
|
"@types/mongodb": "^3.6.12",
|
||||||
"lodash": "^4.17.15",
|
"lodash": "^4.17.21",
|
||||||
"mongodb": "^3.5.8",
|
"mongodb": "^3.6.6",
|
||||||
"runtime-type-checks": "0.0.4"
|
"runtime-type-checks": "0.0.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@gitzone/tsbuild": "^2.1.24",
|
"@gitzone/tsbuild": "^2.1.25",
|
||||||
"@gitzone/tstest": "^1.0.33",
|
"@gitzone/tstest": "^1.0.54",
|
||||||
"@pushrocks/qenv": "^4.0.10",
|
"@pushrocks/qenv": "^4.0.10",
|
||||||
"@pushrocks/tapbundle": "^3.2.1",
|
"@pushrocks/smartunique": "^3.0.3",
|
||||||
|
"@pushrocks/tapbundle": "^3.2.14",
|
||||||
"@types/mongodb-memory-server": "^2.3.0",
|
"@types/mongodb-memory-server": "^2.3.0",
|
||||||
"@types/node": "^14.0.13",
|
"@types/node": "^15.3.0",
|
||||||
"@types/shortid": "0.0.29",
|
"@types/shortid": "0.0.29",
|
||||||
"mongodb-memory-server": "^6.6.1",
|
"mongodb-memory-server": "^6.9.6",
|
||||||
"tslint": "^6.1.2",
|
"tslint": "^6.1.3",
|
||||||
"tslint-config-prettier": "^1.18.0"
|
"tslint-config-prettier": "^1.18.0"
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
@ -55,5 +56,8 @@
|
|||||||
"cli.js",
|
"cli.js",
|
||||||
"npmextra.json",
|
"npmextra.json",
|
||||||
"readme.md"
|
"readme.md"
|
||||||
|
],
|
||||||
|
"browserslist": [
|
||||||
|
"last 1 chrome versions"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
25
readme.md
25
readme.md
@ -49,15 +49,16 @@ How RethinkDB's terms map to the ones of smartdata:
|
|||||||
represents a Database. Naturally it has .connect() etc. methods on it.
|
represents a Database. Naturally it has .connect() etc. methods on it.
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
|
// Assuming toplevel await
|
||||||
import * as smartdata from 'smartdata';
|
import * as smartdata from 'smartdata';
|
||||||
|
|
||||||
const smartdataDb = new smartdata.SmartdataDb({
|
const smartdataDb = new smartdata.SmartdataDb({
|
||||||
mongoDbUrl: '//someurl',
|
mongoDbUrl: '//someurl',
|
||||||
mongoDbName: 'myDatabase',
|
mongoDbName: 'myDatabase',
|
||||||
mongoDbPass: 'mypassword'
|
mongoDbPass: 'mypassword',
|
||||||
});
|
});
|
||||||
|
|
||||||
smartdataDb.connect();
|
await smartdataDb.connect();
|
||||||
```
|
```
|
||||||
|
|
||||||
### class DbCollection
|
### class DbCollection
|
||||||
@ -68,10 +69,11 @@ A collection is defined by the object class (that is extending smartdata.dbdoc)
|
|||||||
So to get to get access to a specific collection you document
|
So to get to get access to a specific collection you document
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
|
// Assuming toplevel await
|
||||||
// continues from the block before...
|
// continues from the block before...
|
||||||
|
|
||||||
@smartdata.Collection(smartdataDb)
|
@smartdata.Collection(smartdataDb)
|
||||||
class MyObject extends smartdata.DbDoc<MyObject> {
|
class MyObject extends smartdata.DbDoc<MyObject /* ,[an optional interface to implement] */> {
|
||||||
// read the next block about DbDoc
|
// read the next block about DbDoc
|
||||||
@smartdata.svDb()
|
@smartdata.svDb()
|
||||||
property1: string; // @smartdata.svDb() marks the property for db save
|
property1: string; // @smartdata.svDb() marks the property for db save
|
||||||
@ -87,14 +89,22 @@ class MyObject extends smartdata.DbDoc<MyObject> {
|
|||||||
|
|
||||||
const localObject = new MyObject({
|
const localObject = new MyObject({
|
||||||
property1: 'hi',
|
property1: 'hi',
|
||||||
property2: 2
|
property2: {
|
||||||
|
deep: 3
|
||||||
|
},
|
||||||
});
|
});
|
||||||
localObject.save(); // saves the object to the database
|
await localObject.save(); // saves the object to the database
|
||||||
|
|
||||||
// start retrieving instances
|
// start retrieving instances
|
||||||
|
|
||||||
MyObject.getInstance<MyObject>({
|
// .getInstance is staticly inheritied, yet fully typed static function to get instances with fully typed filters
|
||||||
property: 'hi'
|
const myInstance = await MyObject.getInstance({
|
||||||
|
property1: 'hi',
|
||||||
|
property2: {
|
||||||
|
deep: {
|
||||||
|
$gt: 2
|
||||||
|
} as any
|
||||||
|
}
|
||||||
}); // outputs a new instance of MyObject with the values from db assigned
|
}); // outputs a new instance of MyObject with the values from db assigned
|
||||||
```
|
```
|
||||||
|
|
||||||
@ -134,7 +144,6 @@ Since you define your classes in TypeScript and types flow through smartdata in
|
|||||||
you should get all the Intellisense and type checking you love when using smartdata.
|
you should get all the Intellisense and type checking you love when using smartdata.
|
||||||
smartdata itself also bundles typings. You don't need to install any additional types for smartdata.
|
smartdata itself also bundles typings. You don't need to install any additional types for smartdata.
|
||||||
|
|
||||||
|
|
||||||
## Contribution
|
## Contribution
|
||||||
|
|
||||||
We are always happy for code contributions. If you are not the code contributing type that is ok. Still, maintaining Open Source repositories takes considerable time and thought. If you like the quality of what we do and our modules are useful to you we would appreciate a little monthly contribution: You can [contribute one time](https://lossless.link/contribute-onetime) or [contribute monthly](https://lossless.link/contribute). :)
|
We are always happy for code contributions. If you are not the code contributing type that is ok. Still, maintaining Open Source repositories takes considerable time and thought. If you like the quality of what we do and our modules are useful to you we would appreciate a little monthly contribution: You can [contribute one time](https://lossless.link/contribute-onetime) or [contribute monthly](https://lossless.link/contribute). :)
|
||||||
|
128
test/test.ts
128
test/test.ts
@ -3,33 +3,49 @@ import { Qenv } from '@pushrocks/qenv';
|
|||||||
|
|
||||||
const testQenv = new Qenv(process.cwd(), process.cwd() + '/.nogit/');
|
const testQenv = new Qenv(process.cwd(), process.cwd() + '/.nogit/');
|
||||||
|
|
||||||
|
console.log(process.memoryUsage());
|
||||||
|
|
||||||
// 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 * as smartunique from '@pushrocks/smartunique';
|
|
||||||
|
|
||||||
import * as mongoPlugin from 'mongodb-memory-server';
|
import * as mongoPlugin from 'mongodb-memory-server';
|
||||||
|
import { smartunique } from '../ts/smartdata.plugins';
|
||||||
|
|
||||||
// =======================================
|
// =======================================
|
||||||
// Connecting to the database server
|
// Connecting to the database server
|
||||||
// =======================================
|
// =======================================
|
||||||
|
|
||||||
let testDb: smartdata.SmartdataDb;
|
let testDb: smartdata.SmartdataDb;
|
||||||
let smartdataOptions: smartdata.ISmartdataOptions;
|
let smartdataOptions: smartdata.IMongoDescriptor;
|
||||||
let mongod: mongoPlugin.MongoMemoryServer;
|
let mongod: mongoPlugin.MongoMemoryServer;
|
||||||
|
|
||||||
tap.test('should create a testinstance as database', async () => {
|
const totalCars = 2000;
|
||||||
mongod = new mongoPlugin.MongoMemoryServer();
|
|
||||||
|
tap.skip.test('should create a testinstance as database', async () => {
|
||||||
|
mongod = new mongoPlugin.MongoMemoryServer({});
|
||||||
|
console.log('created mongod instance');
|
||||||
|
await mongod._startUpInstance().catch((err) => {
|
||||||
|
console.log(err);
|
||||||
|
});
|
||||||
|
console.log('mongod started');
|
||||||
smartdataOptions = {
|
smartdataOptions = {
|
||||||
mongoDbName: await mongod.getDbName(),
|
mongoDbName: await mongod.getDbName(),
|
||||||
mongoDbPass: '',
|
mongoDbPass: '',
|
||||||
mongoDbUrl: await mongod.getConnectionString()
|
mongoDbUrl: await mongod.getUri(),
|
||||||
};
|
};
|
||||||
console.log(smartdataOptions);
|
console.log(smartdataOptions);
|
||||||
testDb = new smartdata.SmartdataDb(smartdataOptions);
|
testDb = new smartdata.SmartdataDb(smartdataOptions);
|
||||||
});
|
});
|
||||||
|
|
||||||
tap.test('should establish a connection to the rethink Db cluster', async () => {
|
tap.test('should connect to atlas', async (tools) => {
|
||||||
|
const databaseName = `test-smartdata-${smartunique.shortId()}`;
|
||||||
|
testDb = new smartdata.SmartdataDb({
|
||||||
|
mongoDbUrl: testQenv.getEnvVarOnDemand('MONGO_URL'),
|
||||||
|
mongoDbName: databaseName,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
tap.test('should establish a connection to mongod', async () => {
|
||||||
await testDb.init();
|
await testDb.init();
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -54,6 +70,11 @@ class Car extends smartdata.SmartDataDbDoc<Car, Car> {
|
|||||||
@smartdata.svDb()
|
@smartdata.svDb()
|
||||||
public brand: string;
|
public brand: string;
|
||||||
|
|
||||||
|
@smartdata.svDb()
|
||||||
|
deepData = {
|
||||||
|
sodeep: 'yes',
|
||||||
|
};
|
||||||
|
|
||||||
constructor(colorArg: string, brandArg: string) {
|
constructor(colorArg: string, brandArg: string) {
|
||||||
super();
|
super();
|
||||||
this.color = colorArg;
|
this.color = colorArg;
|
||||||
@ -68,20 +89,70 @@ tap.test('should save the car to the db', async () => {
|
|||||||
const myCar2 = new Car('red', 'Volvo');
|
const myCar2 = new Car('red', 'Volvo');
|
||||||
await myCar2.save();
|
await myCar2.save();
|
||||||
|
|
||||||
const myCar3 = new Car('red', 'Renault');
|
let counter = 0;
|
||||||
await myCar3.save();
|
process.memoryUsage();
|
||||||
|
do {
|
||||||
|
const myCar3 = new Car('red', 'Renault');
|
||||||
|
await myCar3.save();
|
||||||
|
counter++;
|
||||||
|
if (counter % 100 === 0) {
|
||||||
|
console.log(
|
||||||
|
`Filled database with ${counter} of ${totalCars} Cars and memory usage ${
|
||||||
|
process.memoryUsage().rss / 1e6
|
||||||
|
} MB`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} while (counter < totalCars);
|
||||||
|
console.log(process.memoryUsage());
|
||||||
});
|
});
|
||||||
|
|
||||||
tap.test('expect to get instance of Car', async () => {
|
tap.test('expect to get instance of Car with shallow match', async () => {
|
||||||
const myCars = await Car.getInstances<Car>({
|
const totalQueryCycles = totalCars / 4;
|
||||||
brand: 'Volvo'
|
let counter = 0;
|
||||||
});
|
do {
|
||||||
expect(myCars[0].color).to.equal('red');
|
const timeStart = Date.now();
|
||||||
|
const myCars = await Car.getInstances({
|
||||||
|
brand: 'Renault',
|
||||||
|
});
|
||||||
|
if (counter % 10 === 0) {
|
||||||
|
console.log(
|
||||||
|
`performed ${counter} of ${totalQueryCycles} total query cycles: took ${
|
||||||
|
Date.now() - timeStart
|
||||||
|
}ms to query a set of 2000 with memory footprint ${process.memoryUsage().rss / 1e6} MB`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
expect(myCars[0].deepData.sodeep).to.equal('yes');
|
||||||
|
expect(myCars[0].brand).to.equal('Renault');
|
||||||
|
counter++;
|
||||||
|
} while (counter < totalQueryCycles);
|
||||||
|
});
|
||||||
|
|
||||||
|
tap.test('expect to get instance of Car with deep match', async () => {
|
||||||
|
const totalQueryCycles = totalCars / 4;
|
||||||
|
let counter = 0;
|
||||||
|
do {
|
||||||
|
const timeStart = Date.now();
|
||||||
|
const myCars2 = await Car.getInstances({
|
||||||
|
deepData: {
|
||||||
|
sodeep: 'yes'
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (counter % 10 === 0) {
|
||||||
|
console.log(
|
||||||
|
`performed ${counter} of ${totalQueryCycles} total query cycles: took ${
|
||||||
|
Date.now() - timeStart
|
||||||
|
}ms to deep query a set of 2000 with memory footprint ${process.memoryUsage().rss / 1e6} MB`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
expect(myCars2[0].deepData.sodeep).to.equal('yes');
|
||||||
|
expect(myCars2[0].brand).to.equal('Volvo');
|
||||||
|
counter++;
|
||||||
|
} while (counter < totalQueryCycles);
|
||||||
});
|
});
|
||||||
|
|
||||||
tap.test('expect to get instance of Car and update it', async () => {
|
tap.test('expect to get instance of Car and update it', async () => {
|
||||||
const myCar = await Car.getInstance<Car>({
|
const myCar = await Car.getInstance<Car>({
|
||||||
brand: 'Volvo'
|
brand: 'Volvo',
|
||||||
});
|
});
|
||||||
expect(myCar.color).to.equal('red');
|
expect(myCar.color).to.equal('red');
|
||||||
myCar.color = 'blue';
|
myCar.color = 'blue';
|
||||||
@ -89,14 +160,18 @@ tap.test('expect to get instance of Car and update it', async () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
tap.test('should be able to delete an instance of car', async () => {
|
tap.test('should be able to delete an instance of car', async () => {
|
||||||
const myCar = await Car.getInstance<Car>({
|
const myCars = await Car.getInstances({
|
||||||
brand: 'Volvo'
|
brand: 'Volvo',
|
||||||
|
color: 'blue',
|
||||||
});
|
});
|
||||||
expect(myCar.color).to.equal('blue');
|
console.log(myCars);
|
||||||
await myCar.delete();
|
expect(myCars[0].color).to.equal('blue');
|
||||||
|
for (const myCar of myCars) {
|
||||||
|
await myCar.delete();
|
||||||
|
}
|
||||||
|
|
||||||
const myCar2 = await Car.getInstance<Car>({
|
const myCar2 = await Car.getInstance<Car>({
|
||||||
brand: 'Volvo'
|
brand: 'Volvo',
|
||||||
});
|
});
|
||||||
expect(myCar2.color).to.equal('red');
|
expect(myCar2.color).to.equal('red');
|
||||||
});
|
});
|
||||||
@ -125,19 +200,24 @@ 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<Truck>({ color: 'blue' });
|
const myTruck = await Truck.getInstance({ color: 'blue' });
|
||||||
myTruck.id = 'foo';
|
myTruck.id = 'foo';
|
||||||
await myTruck.save();
|
await myTruck.save();
|
||||||
const myTruck2 = await Truck.getInstance<Truck>({ color: 'blue' });
|
const myTruck2 = await Truck.getInstance({ color: 'blue' });
|
||||||
console.log(myTruck2);
|
console.log(myTruck2);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
tap.test('should ', 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.mongoDb.dropDatabase();
|
||||||
await testDb.close();
|
await testDb.close();
|
||||||
await mongod.stop();
|
try {
|
||||||
|
await mongod.stop();
|
||||||
|
} catch (e) {}
|
||||||
});
|
});
|
||||||
|
|
||||||
tap.start({ throwOnError: true });
|
tap.start({ throwOnError: true });
|
||||||
|
@ -1,5 +1,22 @@
|
|||||||
export interface IMongoDescriptor {
|
export interface IMongoDescriptor {
|
||||||
mongoDbName: string;
|
/**
|
||||||
|
* the URL to connect to
|
||||||
|
*/
|
||||||
mongoDbUrl: string;
|
mongoDbUrl: string;
|
||||||
mongoDbPass: string;
|
|
||||||
|
/**
|
||||||
|
* the db to use for the project
|
||||||
|
*/
|
||||||
|
mongoDbName?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* a username to use to connect to the database
|
||||||
|
*/
|
||||||
|
|
||||||
|
mongoDbUser?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* an optional password that will be replace <PASSWORD> in the connection string
|
||||||
|
*/
|
||||||
|
mongoDbPass?: string;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
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 { SmartDataDbDoc } from './smartdata.classes.doc';
|
import { SmartDataDbDoc } from './smartdata.classes.doc';
|
||||||
|
import { CollectionFactory } from './smartdata.classes.collectionfactory';
|
||||||
|
|
||||||
export interface IFindOptions {
|
export interface IFindOptions {
|
||||||
limit?: number;
|
limit?: number;
|
||||||
@ -13,25 +14,85 @@ export interface IDocValidationFunc<T> {
|
|||||||
(doc: T): boolean;
|
(doc: T): boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type TDelayedDbCreation = () => SmartdataDb;
|
export type TDelayed<TDelayedArg> = () => TDelayedArg;
|
||||||
|
|
||||||
|
const collectionFactory = new CollectionFactory();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is a decorator that will tell the decorated class what dbTable to use
|
* This is a decorator that will tell the decorated class what dbTable to use
|
||||||
* @param dbArg
|
* @param dbArg
|
||||||
*/
|
*/
|
||||||
export function Collection(dbArg: SmartdataDb | TDelayedDbCreation) {
|
export function Collection(dbArg: SmartdataDb | TDelayed<SmartdataDb>) {
|
||||||
return function(constructor) {
|
return function classDecorator<T extends { new (...args: any[]): {} }>(constructor: T) {
|
||||||
if (dbArg instanceof SmartdataDb) {
|
return class extends constructor {
|
||||||
// tslint:disable-next-line: no-string-literal
|
public static get collection() {
|
||||||
constructor['smartdataCollection'] = new SmartdataCollection(constructor, dbArg);
|
if (!(dbArg instanceof SmartdataDb)) {
|
||||||
} else {
|
dbArg = dbArg();
|
||||||
constructor['smartdataDelayedCollection'] = () => {
|
}
|
||||||
return new SmartdataCollection(constructor, dbArg());
|
return collectionFactory.getCollection(constructor.name, dbArg);
|
||||||
};
|
}
|
||||||
}
|
public get collection() {
|
||||||
|
if (!(dbArg instanceof SmartdataDb)) {
|
||||||
|
dbArg = dbArg();
|
||||||
|
}
|
||||||
|
return collectionFactory.getCollection(constructor.name, dbArg);
|
||||||
|
}
|
||||||
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface IManager {
|
||||||
|
db: SmartdataDb
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a decorator that will tell the decorated class what dbTable to use
|
||||||
|
* @param dbArg
|
||||||
|
*/
|
||||||
|
export function Manager<TManager extends IManager>(managerArg?: TManager | TDelayed<TManager>) {
|
||||||
|
return function classDecorator<T extends { new (...args: any[]): {} }>(constructor: T) {
|
||||||
|
return class extends constructor {
|
||||||
|
public static get collection() {
|
||||||
|
let dbArg: SmartdataDb;
|
||||||
|
if (managerArg['db']) {
|
||||||
|
dbArg = (managerArg as TManager).db
|
||||||
|
} else {
|
||||||
|
dbArg = (managerArg as TDelayed<TManager>)().db;
|
||||||
|
}
|
||||||
|
return collectionFactory.getCollection(constructor.name, dbArg);
|
||||||
|
}
|
||||||
|
public get collection() {
|
||||||
|
let dbArg: SmartdataDb;
|
||||||
|
if (managerArg['db']) {
|
||||||
|
dbArg = (managerArg as TManager).db
|
||||||
|
} else {
|
||||||
|
dbArg = (managerArg as TDelayed<TManager>)().db;
|
||||||
|
}
|
||||||
|
return collectionFactory.getCollection(constructor.name, dbArg);
|
||||||
|
}
|
||||||
|
public static get manager() {
|
||||||
|
let manager: TManager;
|
||||||
|
if (managerArg['db']) {
|
||||||
|
manager = (managerArg as TManager);
|
||||||
|
} else {
|
||||||
|
manager = (managerArg as TDelayed<TManager>)();
|
||||||
|
}
|
||||||
|
return manager;
|
||||||
|
}
|
||||||
|
public get manager() {
|
||||||
|
let manager: TManager;
|
||||||
|
if (managerArg['db']) {
|
||||||
|
manager = (managerArg as TManager);
|
||||||
|
} else {
|
||||||
|
manager = (managerArg as TDelayed<TManager>)();
|
||||||
|
}
|
||||||
|
return manager;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// tslint:disable-next-line: max-classes-per-file
|
||||||
export class SmartdataCollection<T> {
|
export class SmartdataCollection<T> {
|
||||||
/**
|
/**
|
||||||
* the collection that is used
|
* the collection that is used
|
||||||
@ -42,13 +103,13 @@ export class SmartdataCollection<T> {
|
|||||||
public smartdataDb: SmartdataDb;
|
public smartdataDb: SmartdataDb;
|
||||||
public uniqueIndexes: string[] = [];
|
public uniqueIndexes: string[] = [];
|
||||||
|
|
||||||
constructor(collectedClassArg: T & SmartDataDbDoc<T, unknown>, smartDataDbArg: SmartdataDb) {
|
constructor(classNameArg: string, smartDataDbArg: SmartdataDb) {
|
||||||
// tell the collection where it belongs
|
// tell the collection where it belongs
|
||||||
this.collectionName = collectedClassArg.name;
|
this.collectionName = classNameArg;
|
||||||
this.smartdataDb = smartDataDbArg;
|
this.smartdataDb = smartDataDbArg;
|
||||||
|
|
||||||
// tell the db class about it (important since Db uses different systems under the hood)
|
// tell the db class about it (important since Db uses different systems under the hood)
|
||||||
this.smartdataDb.addTable(this);
|
this.smartdataDb.addCollection(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -58,14 +119,14 @@ export class SmartdataCollection<T> {
|
|||||||
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();
|
||||||
const wantedCollection = availableMongoDbCollections.find(collection => {
|
const wantedCollection = availableMongoDbCollections.find((collection) => {
|
||||||
return collection.collectionName === this.collectionName;
|
return collection.collectionName === this.collectionName;
|
||||||
});
|
});
|
||||||
if (!wantedCollection) {
|
if (!wantedCollection) {
|
||||||
await this.smartdataDb.mongoDb.createCollection(this.collectionName);
|
await this.smartdataDb.mongoDb.createCollection(this.collectionName);
|
||||||
|
console.log(`Successfully initiated Collection ${this.collectionName}`);
|
||||||
}
|
}
|
||||||
this.mongoDbCollection = await this.smartdataDb.mongoDb.collection(this.collectionName);
|
this.mongoDbCollection = this.smartdataDb.mongoDb.collection(this.collectionName);
|
||||||
// console.log(`Successfully initiated Collection ${this.collectionName}`);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,7 +137,7 @@ export class SmartdataCollection<T> {
|
|||||||
for (const 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,
|
||||||
});
|
});
|
||||||
// make sure we only call this once and not for every doc we create
|
// make sure we only call this once and not for every doc we create
|
||||||
this.uniqueIndexes.push(key);
|
this.uniqueIndexes.push(key);
|
||||||
@ -127,11 +188,12 @@ export class SmartdataCollection<T> {
|
|||||||
}
|
}
|
||||||
updateableObject[key] = saveableObject[key];
|
updateableObject[key] = saveableObject[key];
|
||||||
}
|
}
|
||||||
this.mongoDbCollection.updateOne(
|
const result = await this.mongoDbCollection.updateOne(
|
||||||
identifiableObject,
|
identifiableObject,
|
||||||
{ $set: updateableObject },
|
{ $set: updateableObject },
|
||||||
{ upsert: true }
|
{ upsert: true }
|
||||||
);
|
);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async delete(dbDocArg: T & SmartDataDbDoc<T, unknown>): Promise<any> {
|
public async delete(dbDocArg: T & SmartDataDbDoc<T, unknown>): Promise<any> {
|
||||||
@ -139,7 +201,7 @@ export class SmartdataCollection<T> {
|
|||||||
await this.checkDoc(dbDocArg);
|
await this.checkDoc(dbDocArg);
|
||||||
const identifiableObject = await dbDocArg.createIdentifiableObject();
|
const identifiableObject = await dbDocArg.createIdentifiableObject();
|
||||||
await this.mongoDbCollection.deleteOne(identifiableObject, {
|
await this.mongoDbCollection.deleteOne(identifiableObject, {
|
||||||
w: 1
|
w: 1,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
22
ts/smartdata.classes.collectionfactory.ts
Normal file
22
ts/smartdata.classes.collectionfactory.ts
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import * as plugins from './smartdata.plugins';
|
||||||
|
import { SmartdataCollection } from './smartdata.classes.collection';
|
||||||
|
import { SmartdataDb } from './smartdata.classes.db';
|
||||||
|
|
||||||
|
export class CollectionFactory {
|
||||||
|
public collections: { [key: string]: SmartdataCollection<any> } = {};
|
||||||
|
|
||||||
|
public getCollection = (
|
||||||
|
nameArg: string,
|
||||||
|
dbArg: SmartdataDb
|
||||||
|
): SmartdataCollection<any> => {
|
||||||
|
if (!this.collections[nameArg]) {
|
||||||
|
this.collections[nameArg] = (() => {
|
||||||
|
if (dbArg instanceof SmartdataDb) {
|
||||||
|
// tslint:disable-next-line: no-string-literal
|
||||||
|
return new SmartdataCollection(nameArg, dbArg);
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
return this.collections[nameArg];
|
||||||
|
};
|
||||||
|
}
|
@ -3,39 +3,22 @@ import { ObjectMap } from '@pushrocks/lik';
|
|||||||
|
|
||||||
import { SmartdataCollection } from './smartdata.classes.collection';
|
import { SmartdataCollection } from './smartdata.classes.collection';
|
||||||
|
|
||||||
import * as mongoHelpers from './smartdata.mongohelpers';
|
|
||||||
import { logger } from './smartdata.logging';
|
import { logger } from './smartdata.logging';
|
||||||
|
import { IMongoDescriptor } from './interfaces';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* interface - indicates the connection status of the db
|
* interface - indicates the connection status of the db
|
||||||
*/
|
*/
|
||||||
export type TConnectionStatus = 'initial' | 'disconnected' | 'connected' | 'failed';
|
export type TConnectionStatus = 'initial' | 'disconnected' | 'connected' | 'failed';
|
||||||
|
|
||||||
export interface ISmartdataOptions {
|
|
||||||
/**
|
|
||||||
* the URL to connect to
|
|
||||||
*/
|
|
||||||
mongoDbUrl: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* the db to use for the project
|
|
||||||
*/
|
|
||||||
mongoDbName: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* an optional password that will be replace <PASSWORD> in the connection string
|
|
||||||
*/
|
|
||||||
mongoDbPass?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class SmartdataDb {
|
export class SmartdataDb {
|
||||||
smartdataOptions: ISmartdataOptions;
|
smartdataOptions: IMongoDescriptor;
|
||||||
mongoDbClient: plugins.mongodb.MongoClient;
|
mongoDbClient: plugins.mongodb.MongoClient;
|
||||||
mongoDb: plugins.mongodb.Db;
|
mongoDb: plugins.mongodb.Db;
|
||||||
status: TConnectionStatus;
|
status: TConnectionStatus;
|
||||||
smartdataCollectionMap = new ObjectMap<SmartdataCollection<any>>();
|
smartdataCollectionMap = new ObjectMap<SmartdataCollection<any>>();
|
||||||
|
|
||||||
constructor(smartdataOptions: ISmartdataOptions) {
|
constructor(smartdataOptions: IMongoDescriptor) {
|
||||||
this.smartdataOptions = smartdataOptions;
|
this.smartdataOptions = smartdataOptions;
|
||||||
this.status = 'initial';
|
this.status = 'initial';
|
||||||
}
|
}
|
||||||
@ -46,17 +29,21 @@ export class SmartdataDb {
|
|||||||
* connects to the database that was specified during instance creation
|
* connects to the database that was specified during instance creation
|
||||||
*/
|
*/
|
||||||
public async init(): Promise<any> {
|
public async init(): Promise<any> {
|
||||||
let finalConnectionUrl = this.smartdataOptions.mongoDbUrl;
|
const finalConnectionUrl = this.smartdataOptions.mongoDbUrl
|
||||||
if (this.smartdataOptions.mongoDbPass) {
|
.replace('<USERNAME>', this.smartdataOptions.mongoDbUser)
|
||||||
finalConnectionUrl = mongoHelpers.addPassword(
|
.replace('<username>', this.smartdataOptions.mongoDbUser)
|
||||||
this.smartdataOptions.mongoDbUrl,
|
.replace('<USER>', this.smartdataOptions.mongoDbUser)
|
||||||
this.smartdataOptions.mongoDbPass
|
.replace('<user>', this.smartdataOptions.mongoDbUser)
|
||||||
);
|
.replace('<PASSWORD>', this.smartdataOptions.mongoDbPass)
|
||||||
}
|
.replace('<password>', this.smartdataOptions.mongoDbPass)
|
||||||
console.log(`connection Url: ${finalConnectionUrl}`);
|
.replace('<DBNAME>', this.smartdataOptions.mongoDbName)
|
||||||
|
.replace('<dbname>', this.smartdataOptions.mongoDbName);
|
||||||
|
|
||||||
this.mongoDbClient = await plugins.mongodb.MongoClient.connect(finalConnectionUrl, {
|
this.mongoDbClient = await plugins.mongodb.MongoClient.connect(finalConnectionUrl, {
|
||||||
useNewUrlParser: true,
|
useNewUrlParser: true,
|
||||||
useUnifiedTopology: true
|
useUnifiedTopology: true,
|
||||||
|
maxPoolSize: 100,
|
||||||
|
maxIdleTimeMS: 10,
|
||||||
});
|
});
|
||||||
this.mongoDb = this.mongoDbClient.db(this.smartdataOptions.mongoDbName);
|
this.mongoDb = this.mongoDbClient.db(this.smartdataOptions.mongoDbName);
|
||||||
this.status = 'connected';
|
this.status = 'connected';
|
||||||
@ -74,7 +61,7 @@ export class SmartdataDb {
|
|||||||
|
|
||||||
// handle table to class distribution
|
// handle table to class distribution
|
||||||
|
|
||||||
public addTable(SmartdataCollectionArg: SmartdataCollection<any>) {
|
public addCollection(SmartdataCollectionArg: SmartdataCollection<any>) {
|
||||||
this.smartdataCollectionMap.add(SmartdataCollectionArg);
|
this.smartdataCollectionMap.add(SmartdataCollectionArg);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,7 +71,7 @@ export class SmartdataDb {
|
|||||||
* @returns DbTable
|
* @returns DbTable
|
||||||
*/
|
*/
|
||||||
public async getSmartdataCollectionByName<T>(nameArg: string): Promise<SmartdataCollection<T>> {
|
public async getSmartdataCollectionByName<T>(nameArg: string): Promise<SmartdataCollection<T>> {
|
||||||
const resultCollection = this.smartdataCollectionMap.find(dbTableArg => {
|
const resultCollection = this.smartdataCollectionMap.find((dbTableArg) => {
|
||||||
return dbTableArg.collectionName === nameArg;
|
return dbTableArg.collectionName === nameArg;
|
||||||
});
|
});
|
||||||
return resultCollection;
|
return resultCollection;
|
||||||
|
@ -3,7 +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 { SmartdataCollection } from './smartdata.classes.collection';
|
import { IManager, SmartdataCollection } from './smartdata.classes.collection';
|
||||||
|
|
||||||
export type TDocCreation = 'db' | 'new' | 'mixed';
|
export type TDocCreation = 'db' | 'new' | 'mixed';
|
||||||
|
|
||||||
@ -12,7 +12,7 @@ export type TDocCreation = 'db' | 'new' | 'mixed';
|
|||||||
*/
|
*/
|
||||||
export function svDb() {
|
export function svDb() {
|
||||||
return (target: SmartDataDbDoc<unknown, unknown>, key: string) => {
|
return (target: SmartDataDbDoc<unknown, unknown>, key: string) => {
|
||||||
console.log(`called svDb() on ${key}`);
|
console.log(`called svDb() on >${target.constructor.name}.${key}<`);
|
||||||
if (!target.saveableProperties) {
|
if (!target.saveableProperties) {
|
||||||
target.saveableProperties = [];
|
target.saveableProperties = [];
|
||||||
}
|
}
|
||||||
@ -25,7 +25,7 @@ export function svDb() {
|
|||||||
*/
|
*/
|
||||||
export function unI() {
|
export function unI() {
|
||||||
return (target: SmartDataDbDoc<unknown, unknown>, key: string) => {
|
return (target: SmartDataDbDoc<unknown, unknown>, key: string) => {
|
||||||
console.log('called unI');
|
console.log(`called unI on >>${target.constructor.name}.${key}<<`);
|
||||||
|
|
||||||
// mark the index as unique
|
// mark the index as unique
|
||||||
if (!target.uniqueIndexes) {
|
if (!target.uniqueIndexes) {
|
||||||
@ -41,11 +41,14 @@ export function unI() {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export class SmartDataDbDoc<T, TImplements> {
|
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
|
||||||
*/
|
*/
|
||||||
public collection: SmartdataCollection<T>;
|
public static collection: SmartdataCollection<any>;
|
||||||
|
public collection: SmartdataCollection<any>;
|
||||||
|
public static manager: TManager;
|
||||||
|
public manager: TManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* how the Doc in memory was created, may prove useful later.
|
* how the Doc in memory was created, may prove useful later.
|
||||||
@ -75,34 +78,38 @@ export class SmartDataDbDoc<T, TImplements> {
|
|||||||
/**
|
/**
|
||||||
* class constructor
|
* class constructor
|
||||||
*/
|
*/
|
||||||
constructor() {
|
constructor() {}
|
||||||
this.name = this.constructor['name'];
|
|
||||||
if (this.constructor['smartdataCollection']) {
|
|
||||||
// tslint:disable-next-line: no-string-literal
|
|
||||||
this.collection = this.constructor['smartdataCollection'];
|
|
||||||
// tslint:disable-next-line: no-string-literal
|
|
||||||
} else if (typeof this.constructor['smartdataDelayedCollection'] === 'function') {
|
|
||||||
// tslint:disable-next-line: no-string-literal
|
|
||||||
this.collection = this.constructor['smartdataDelayedCollection']();
|
|
||||||
} else {
|
|
||||||
console.error('Could not determine collection for DbDoc');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async getInstances<T>(filterArg): Promise<T[]> {
|
public static async getInstances<T>(
|
||||||
const self: any = this; // fool typesystem
|
this: plugins.tsclass.typeFest.Class<T>,
|
||||||
let referenceMongoDBCollection: SmartdataCollection<T>;
|
filterArg: plugins.tsclass.typeFest.PartialDeep<T>
|
||||||
|
): Promise<T[]> {
|
||||||
if (self.smartdataCollection) {
|
const convertedFilter: any = {};
|
||||||
referenceMongoDBCollection = self.smartdataCollection;
|
const convertFilterArgument = (keyPathArg: string, filterArg2: any) => {
|
||||||
} else if (self.smartdataDelayedCollection) {
|
if (typeof filterArg2 === 'object') {
|
||||||
referenceMongoDBCollection = self.smartdataDelayedCollection();
|
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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
const foundDocs = await referenceMongoDBCollection.find(filterArg);
|
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 item of foundDocs) {
|
||||||
const newInstance = new this();
|
const newInstance = new this();
|
||||||
newInstance.creationStatus = 'db';
|
(newInstance as any).creationStatus = 'db';
|
||||||
for (const key of Object.keys(item)) {
|
for (const key of Object.keys(item)) {
|
||||||
newInstance[key] = item[key];
|
newInstance[key] = item[key];
|
||||||
}
|
}
|
||||||
@ -111,8 +118,11 @@ export class SmartDataDbDoc<T, TImplements> {
|
|||||||
return returnArray;
|
return returnArray;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async getInstance<T>(filterArg): Promise<T> {
|
public static async getInstance<T>(
|
||||||
const result = await this.getInstances<T>(filterArg);
|
this: plugins.tsclass.typeFest.Class<T>,
|
||||||
|
filterArg: plugins.tsclass.typeFest.PartialDeep<T>
|
||||||
|
): Promise<T> {
|
||||||
|
const result = await (this as any).getInstances(filterArg);
|
||||||
if (result && result.length > 0) {
|
if (result && result.length > 0) {
|
||||||
return result[0];
|
return result[0];
|
||||||
}
|
}
|
||||||
@ -125,25 +135,26 @@ export class SmartDataDbDoc<T, TImplements> {
|
|||||||
public async save() {
|
public async save() {
|
||||||
// tslint:disable-next-line: no-this-assignment
|
// tslint:disable-next-line: no-this-assignment
|
||||||
const self: any = this;
|
const self: any = this;
|
||||||
|
let dbResult: any;
|
||||||
switch (this.creationStatus) {
|
switch (this.creationStatus) {
|
||||||
case 'db':
|
case 'db':
|
||||||
await this.collection.update(self);
|
dbResult = await this.collection.update(self);
|
||||||
break;
|
break;
|
||||||
case 'new':
|
case 'new':
|
||||||
const writeResult = await this.collection.insert(self);
|
dbResult = await this.collection.insert(self);
|
||||||
this.creationStatus = 'db';
|
this.creationStatus = 'db';
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
console.error('neither new nor in db?');
|
console.error('neither new nor in db?');
|
||||||
}
|
}
|
||||||
|
return dbResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* deletes a document from the database
|
* deletes a document from the database
|
||||||
*/
|
*/
|
||||||
public async delete() {
|
public async delete() {
|
||||||
const self: any = this;
|
await this.collection.delete(this);
|
||||||
await this.collection.delete(self);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,7 +0,0 @@
|
|||||||
export const addUsername = (mongoUrlArg: string, usernameArg: string): string => {
|
|
||||||
return mongoUrlArg.replace('<USERNAME>', usernameArg);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const addPassword = (mongoUrlArg: string, passwordArg: string): string => {
|
|
||||||
return mongoUrlArg.replace('<PASSWORD>', passwordArg);
|
|
||||||
};
|
|
@ -1,4 +1,9 @@
|
|||||||
import * as assert from 'assert';
|
// tsclass scope
|
||||||
|
import * as tsclass from '@tsclass/tsclass';
|
||||||
|
|
||||||
|
export { tsclass };
|
||||||
|
|
||||||
|
// @pushrocks scope
|
||||||
import * as smartlog from '@pushrocks/smartlog';
|
import * as smartlog from '@pushrocks/smartlog';
|
||||||
import * as lodash from 'lodash';
|
import * as lodash from 'lodash';
|
||||||
import * as mongodb from 'mongodb';
|
import * as mongodb from 'mongodb';
|
||||||
@ -6,4 +11,4 @@ import * as smartq from '@pushrocks/smartpromise';
|
|||||||
import * as smartstring from '@pushrocks/smartstring';
|
import * as smartstring from '@pushrocks/smartstring';
|
||||||
import * as smartunique from '@pushrocks/smartunique';
|
import * as smartunique from '@pushrocks/smartunique';
|
||||||
|
|
||||||
export { assert, smartlog, lodash, smartq, mongodb, smartstring, smartunique };
|
export { smartlog, lodash, smartq, mongodb, smartstring, smartunique };
|
||||||
|
Reference in New Issue
Block a user