Compare commits

...

31 Commits

Author SHA1 Message Date
c17789e92e 3.1.36 2020-08-18 12:46:14 +00:00
0bf2ba554d fix(core): update 2020-08-18 12:46:14 +00:00
5cbf1a222a 3.1.35 2020-08-18 12:36:41 +00:00
f075530838 fix(core): update 2020-08-18 12:36:41 +00:00
efb83853fb 3.1.34 2020-08-18 12:35:16 +00:00
73300ca4d3 fix(core): update 2020-08-18 12:35:16 +00:00
1e946cdceb 3.1.33 2020-08-18 12:33:17 +00:00
608ff93a41 fix(core): update 2020-08-18 12:33:16 +00:00
6211953f14 3.1.32 2020-08-18 12:32:55 +00:00
99e520b776 fix(core): update 2020-08-18 12:32:54 +00:00
eda8297356 3.1.31 2020-08-18 12:05:08 +00:00
ffa52a5883 fix(core): update 2020-08-18 12:05:07 +00:00
1e83f0a0ef 3.1.30 2020-08-18 12:01:47 +00:00
0203eabdfd fix(core): update 2020-08-18 12:01:46 +00:00
72894e3ef1 3.1.29 2020-06-12 05:59:08 +00:00
bbe5f8c6a8 fix(core): update 2020-06-12 05:59:07 +00:00
02af9f5c4b 3.1.28 2020-06-11 23:08:38 +00:00
17de480272 fix(core): update 2020-06-11 23:08:38 +00:00
776fd3ee4e 3.1.27 2020-06-11 23:05:46 +00:00
3272bb7235 fix(core): update 2020-06-11 23:05:45 +00:00
116dfbc3b0 update module structure 2020-06-11 23:05:32 +00:00
3f714b1a33 3.1.26 2020-02-19 18:30:35 +00:00
e58fa57525 fix(core): update 2020-02-19 18:30:34 +00:00
8e7ad5210f 3.1.25 2020-02-08 14:37:45 +00:00
cea6c662ac fix(core): update 2020-02-08 14:37:44 +00:00
6eb43a4b9f 3.1.24 2020-02-08 14:01:55 +00:00
7f89cbeecd fix(core): update 2020-02-08 14:01:55 +00:00
a042a589a0 3.1.23 2019-09-11 12:36:03 +02:00
75b5f6af08 fix(core): update 2019-09-11 12:36:02 +02:00
e6a36f22ac 3.1.22 2019-09-11 12:12:51 +02:00
246e3486f0 fix(id field now properly populated): update 2019-09-11 12:12:50 +02:00
15 changed files with 10300 additions and 1319 deletions

4
.gitignore vendored
View File

@ -15,8 +15,6 @@ node_modules/
# builds # builds
dist/ dist/
dist_web/ dist_*/
dist_serve/
dist_ts_web/
# custom # custom

View File

@ -3,14 +3,14 @@ image: registry.gitlab.com/hosttoday/ht-docker-node:npmci
cache: cache:
paths: paths:
- .npmci_cache/ - .npmci_cache/
key: "$CI_BUILD_STAGE" key: '$CI_BUILD_STAGE'
stages: stages:
- security - security
- test - test
- release - release
- metadata - metadata
# ==================== # ====================
# security stage # security stage
@ -18,21 +18,36 @@ stages:
mirror: mirror:
stage: security stage: security
script: script:
- npmci git mirror - npmci git mirror
only:
- tags
tags: tags:
- docker - lossless
- notpriv - docker
- notpriv
snyk: auditProductionDependencies:
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 -g snyk - npmci command npm install --production --ignore-scripts
- npmci command npm install --ignore-scripts - npmci command npm config set registry https://registry.npmjs.org
- npmci command snyk test - npmci command npm audit --audit-level=high --only=prod --production
tags: tags:
- docker - docker
- notpriv
auditDevDependencies:
image: registry.gitlab.com/hosttoday/ht-docker-node:npmci
stage: security
script:
- npmci npm prepare
- npmci command npm install --ignore-scripts
- npmci command npm config set registry https://registry.npmjs.org
- npmci command npm audit --audit-level=high --only=dev
tags:
- docker
allow_failure: true
# ==================== # ====================
# test stage # test stage
@ -41,37 +56,36 @@ snyk:
testStable: testStable:
stage: test stage: test
script: script:
- npmci npm prepare - npmci npm prepare
- npmci node install stable - npmci node install stable
- npmci npm install - npmci npm install
- npmci npm test - npmci npm test
coverage: /\d+.?\d+?\%\s*coverage/ coverage: /\d+.?\d+?\%\s*coverage/
tags: tags:
- docker - docker
- priv
testBuild: testBuild:
stage: test stage: test
script: script:
- npmci npm prepare - npmci npm prepare
- npmci node install lts - npmci node install stable
- npmci npm install - npmci npm install
- npmci command npm run build - npmci command npm run build
coverage: /\d+.?\d+?\%\s*coverage/ coverage: /\d+.?\d+?\%\s*coverage/
tags: tags:
- docker - docker
- notpriv
release: release:
stage: release stage: release
script: script:
- npmci node install lts - npmci node install stable
- npmci npm publish - npmci npm publish
only: only:
- tags - tags
tags: tags:
- docker - lossless
- notpriv - docker
- notpriv
# ==================== # ====================
# metadata stage # metadata stage
@ -79,35 +93,39 @@ 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 install - npmci npm install
- npmci command "tslint -c tslint.json ./ts/**/*.ts" - npmci command "tslint -c tslint.json ./ts/**/*.ts"
tags: tags:
- docker - lossless
- priv - docker
- priv
trigger: trigger:
stage: metadata stage: metadata
script: script:
- npmci trigger - npmci trigger
only: only:
- tags - tags
tags: tags:
- docker - lossless
- notpriv - docker
- notpriv
pages: pages:
image: hosttoday/ht-docker-dbase:npmci
services:
- docker:stable-dind
stage: metadata stage: metadata
script: script:
- npmci node install lts
- npmci command npm install -g @gitzone/tsdoc - npmci command npm install -g @gitzone/tsdoc
- npmci npm prepare - npmci npm prepare
- npmci npm install - npmci npm install
- npmci command tsdoc - npmci command tsdoc
tags: tags:
- lossless
- docker - docker
- notpriv - notpriv
only: only:
@ -115,5 +133,5 @@ pages:
artifacts: artifacts:
expire_in: 1 week expire_in: 1 week
paths: paths:
- public - public
allow_failure: true allow_failure: true

29
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,29 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "current file",
"type": "node",
"request": "launch",
"args": [
"${relativeFile}"
],
"runtimeArgs": ["-r", "@gitzone/tsrun"],
"cwd": "${workspaceRoot}",
"protocol": "inspector",
"internalConsoleOptions": "openOnSessionStart"
},
{
"name": "test.ts",
"type": "node",
"request": "launch",
"args": [
"test/test.ts"
],
"runtimeArgs": ["-r", "@gitzone/tsrun"],
"cwd": "${workspaceRoot}",
"protocol": "inspector",
"internalConsoleOptions": "openOnSessionStart"
}
]
}

26
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,26 @@
{
"json.schemas": [
{
"fileMatch": ["/npmextra.json"],
"schema": {
"type": "object",
"properties": {
"npmci": {
"type": "object",
"description": "settings for npmci"
},
"gitzone": {
"type": "object",
"description": "settings for gitzone",
"properties": {
"projectType": {
"type": "string",
"enum": ["website", "element", "service", "npm", "wcc"]
}
}
}
}
}
}
]
}

View File

@ -10,6 +10,7 @@
"npmRegistryUrl": "registry.npmjs.org" "npmRegistryUrl": "registry.npmjs.org"
}, },
"gitzone": { "gitzone": {
"projectType": "npm",
"module": { "module": {
"githost": "gitlab.com", "githost": "gitlab.com",
"gitscope": "pushrocks", "gitscope": "pushrocks",

11179
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,14 +1,14 @@
{ {
"name": "@pushrocks/smartdata", "name": "@pushrocks/smartdata",
"version": "3.1.21", "version": "3.1.36",
"private": false, "private": false,
"description": "do more with data", "description": "do more with data",
"main": "dist/index.js", "main": "dist_ts/index.js",
"typings": "dist/index.d.ts", "typings": "dist_ts/index.d.ts",
"scripts": { "scripts": {
"test": "(tstest test/)", "test": "(tstest test/)",
"testLocal": "(npmdocker)", "testLocal": "(npmdocker)",
"build": "(tsbuild)" "build": "(tsbuild --web)"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
@ -21,38 +21,42 @@
}, },
"homepage": "https://gitlab.com/pushrocks/smartdata#README", "homepage": "https://gitlab.com/pushrocks/smartdata#README",
"dependencies": { "dependencies": {
"@pushrocks/lik": "^3.0.11", "@pushrocks/lik": "^4.0.17",
"@pushrocks/smartlog": "^2.0.19", "@pushrocks/smartlog": "^2.0.36",
"@pushrocks/smartpromise": "^3.0.2", "@pushrocks/smartpromise": "^3.0.6",
"@pushrocks/smartstring": "^3.0.10", "@pushrocks/smartstring": "^3.0.18",
"@pushrocks/smartunique": "^3.0.1", "@pushrocks/smartunique": "^3.0.3",
"@types/lodash": "^4.14.138", "@types/lodash": "^4.14.159",
"@types/mongodb": "^3.3.1", "@types/mongodb": "^3.5.26",
"lodash": "^4.17.15", "lodash": "^4.17.20",
"mongodb": "^3.3.2", "mongodb": "^3.6.0",
"runtime-type-checks": "0.0.4" "runtime-type-checks": "0.0.4"
}, },
"devDependencies": { "devDependencies": {
"@gitzone/tsbuild": "^2.1.17", "@gitzone/tsbuild": "^2.1.25",
"@gitzone/tstest": "^1.0.24", "@gitzone/tstest": "^1.0.44",
"@pushrocks/qenv": "^4.0.4", "@pushrocks/qenv": "^4.0.10",
"@pushrocks/tapbundle": "^3.0.13", "@pushrocks/tapbundle": "^3.2.9",
"@types/mongodb-memory-server": "^1.8.0", "@types/mongodb-memory-server": "^2.3.0",
"@types/node": "^12.7.3", "@types/node": "^14.6.0",
"@types/shortid": "0.0.29", "@types/shortid": "0.0.29",
"mongodb-memory-server": "^5.2.0", "mongodb-memory-server": "6.6.3",
"tslint": "^5.19.0", "tslint": "^6.1.3",
"tslint-config-prettier": "^1.18.0" "tslint-config-prettier": "^1.18.0"
}, },
"files": [ "files": [
"ts/*", "ts/**/*",
"ts_web/*", "ts_web/**/*",
"dist/*", "dist/**/*",
"dist_web/*", "dist_*/**/*",
"dist_ts_web/*", "dist_ts/**/*",
"assets/*", "dist_ts_web/**/*",
"assets/**/*",
"cli.js", "cli.js",
"npmextra.json", "npmextra.json",
"readme.md" "readme.md"
],
"browserslist": [
"last 1 chrome versions"
] ]
} }

View File

@ -8,13 +8,20 @@ do more with data
* [docs (typedoc)](https://pushrocks.gitlab.io/smartdata/) * [docs (typedoc)](https://pushrocks.gitlab.io/smartdata/)
## Status for master ## Status for master
[![build status](https://gitlab.com/pushrocks/smartdata/badges/master/build.svg)](https://gitlab.com/pushrocks/smartdata/commits/master)
[![coverage report](https://gitlab.com/pushrocks/smartdata/badges/master/coverage.svg)](https://gitlab.com/pushrocks/smartdata/commits/master) Status Category | Status Badge
[![npm downloads per month](https://img.shields.io/npm/dm/@pushrocks/smartdata.svg)](https://www.npmjs.com/package/@pushrocks/smartdata) -- | --
[![Known Vulnerabilities](https://snyk.io/test/npm/@pushrocks/smartdata/badge.svg)](https://snyk.io/test/npm/@pushrocks/smartdata) GitLab Pipelines | [![pipeline status](https://gitlab.com/pushrocks/smartdata/badges/master/pipeline.svg)](https://lossless.cloud)
[![TypeScript](https://img.shields.io/badge/TypeScript->=%203.x-blue.svg)](https://nodejs.org/dist/latest-v10.x/docs/api/) GitLab Pipline Test Coverage | [![coverage report](https://gitlab.com/pushrocks/smartdata/badges/master/coverage.svg)](https://lossless.cloud)
[![node](https://img.shields.io/badge/node->=%2010.x.x-blue.svg)](https://nodejs.org/dist/latest-v10.x/docs/api/) npm | [![npm downloads per month](https://badgen.net/npm/dy/@pushrocks/smartdata)](https://lossless.cloud)
[![JavaScript Style Guide](https://img.shields.io/badge/code%20style-prettier-ff69b4.svg)](https://prettier.io/) Snyk | [![Known Vulnerabilities](https://badgen.net/snyk/pushrocks/smartdata)](https://lossless.cloud)
TypeScript Support | [![TypeScript](https://badgen.net/badge/TypeScript/>=%203.x/blue?icon=typescript)](https://lossless.cloud)
node Support | [![node](https://img.shields.io/badge/node->=%2010.x.x-blue.svg)](https://nodejs.org/dist/latest-v10.x/docs/api/)
Code Style | [![Code Style](https://badgen.net/badge/style/prettier/purple)](https://lossless.cloud)
PackagePhobia (total standalone install weight) | [![PackagePhobia](https://badgen.net/packagephobia/install/@pushrocks/smartdata)](https://lossless.cloud)
PackagePhobia (package size on registry) | [![PackagePhobia](https://badgen.net/packagephobia/publish/@pushrocks/smartdata)](https://lossless.cloud)
BundlePhobia (total size when bundled) | [![BundlePhobia](https://badgen.net/bundlephobia/minzip/@pushrocks/smartdata)](https://lossless.cloud)
Platform support | [![Supports Windows 10](https://badgen.net/badge/supports%20Windows%2010/yes/green?icon=windows)](https://lossless.cloud) [![Supports Mac OS X](https://badgen.net/badge/supports%20Mac%20OS%20X/yes/green?icon=apple)](https://lossless.cloud)
## Usage ## Usage
@ -47,7 +54,7 @@ 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(); smartdataDb.connect();
@ -68,9 +75,9 @@ class MyObject extends smartdata.DbDoc<MyObject> {
// 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
property2: number; // this one is not marked, so it won't be save upon calling this.save() property2: number; // this one is not marked, so it won't be save upon calling this.save()
constructor() { constructor() {
super(); // the super call is important ;) But you probably know that. super(); // the super call is important ;) But you probably know that.
} }
@ -80,14 +87,14 @@ class MyObject extends smartdata.DbDoc<MyObject> {
const localObject = new MyObject({ const localObject = new MyObject({
property1: 'hi', property1: 'hi',
property2: 2 property2: 2,
}); });
localObject.save(); // saves the object to the database localObject.save(); // saves the object to the database
// start retrieving instances // start retrieving instances
MyObject.getInstance<MyObject>({ MyObject.getInstance<MyObject>({
property: 'hi' property: 'hi',
}); // outputs a new instance of MyObject with the values from db assigned }); // outputs a new instance of MyObject with the values from db assigned
``` ```
@ -97,7 +104,8 @@ represents a individual document in a collection
and thereby is ideally suited to extend the class you want to actually store. and thereby is ideally suited to extend the class you want to actually store.
### CRUD operations ### CRUD operations
smartdata supports full CRUD operations
smartdata supports full CRUD operations
**Store** or **Update** instances of classes to MongoDB: **Store** or **Update** instances of classes to MongoDB:
DbDoc extends your class with the following methods: DbDoc extends your class with the following methods:
@ -111,16 +119,13 @@ DbDoc extends your class with the following methods:
**Get** a new class instance from MongoDB: **Get** a new class instance from MongoDB:
DbDoc exposes a static method that allows you specify a filter to retrieve a cloned class of the one you used to that doc at some point later in time: DbDoc exposes a static method that allows you specify a filter to retrieve a cloned class of the one you used to that doc at some point later in time:
* static async `.getInstance({ /* filter props here */ })` gets you an instance that has the data of the first matched document as properties. - static async `.getInstance({ /* filter props here */ })` gets you an instance that has the data of the first matched document as properties.
* static async `getInstances({ /* filter props here */ })` get you an array instances (one instance for every matched document). - static async `getInstances({ /* filter props here */ })` get you an array instances (one instance for every matched document).
**Delete** instances from MongoDb: **Delete** instances from MongoDb:
smartdata extends your class with a method to easily delete the doucment from DB: smartdata extends your class with a method to easily delete the doucment from DB:
* async `.delete()`will delete the document from DB. - async `.delete()`will delete the document from DB.
## TypeScript ## TypeScript
@ -129,6 +134,10 @@ 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
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). :)
For further information read the linked docs at the top of this readme. For further information read the linked docs at the top of this readme.
> MIT licensed | **&copy;** [Lossless GmbH](https://lossless.gmbh) > MIT licensed | **&copy;** [Lossless GmbH](https://lossless.gmbh)

View File

@ -15,29 +15,23 @@ import * as mongoPlugin from 'mongodb-memory-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 () => { tap.test('should create a testinstance as database', async () => {
mongod = new mongoPlugin.MongoMemoryServer(); mongod = new mongoPlugin.MongoMemoryServer({
autoStart: true,
});
smartdataOptions = { smartdataOptions = {
mongoDbName: await mongod.getDbName(), mongoDbName: await mongod.getDbName(),
mongoDbPass: '', mongoDbPass: '',
mongoDbUrl: await mongod.getConnectionString() mongoDbUrl: await mongod.getConnectionString(),
}; };
console.log(smartdataOptions); console.log(smartdataOptions);
testDb = new smartdata.SmartdataDb(smartdataOptions); testDb = new smartdata.SmartdataDb(smartdataOptions);
}); });
tap.skip.test('should create a smartdb', async () => { tap.test('should establish a connection to mongod', 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 () => {
await testDb.init(); await testDb.init();
}); });
@ -52,7 +46,7 @@ tap.test('should establish a connection to the rethink Db cluster', async () =>
@smartdata.Collection(() => { @smartdata.Collection(() => {
return testDb; return testDb;
}) })
class Car extends smartdata.SmartDataDbDoc<Car> { class Car extends smartdata.SmartDataDbDoc<Car, Car> {
@smartdata.unI() @smartdata.unI()
public index: string = smartunique.shortId(); public index: string = smartunique.shortId();
@ -82,14 +76,14 @@ tap.test('should save the car to the db', async () => {
tap.test('expect to get instance of Car', async () => { tap.test('expect to get instance of Car', async () => {
const 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 () => { 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';
@ -98,24 +92,22 @@ 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 myCar = await Car.getInstance<Car>({
brand: 'Volvo' brand: 'Volvo',
}); });
expect(myCar.color).to.equal('blue'); expect(myCar.color).to.equal('blue');
await myCar.delete(); 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');
}); });
// tslint:disable-next-line: max-classes-per-file // tslint:disable-next-line: max-classes-per-file
@smartdata.Collection(() => { @smartdata.Collection(() => {
return testDb; return testDb;
}) })
class Truck extends smartdata.SmartDataDbDoc<Car> { class Truck extends smartdata.SmartDataDbDoc<Car, Car> {
@smartdata.unI() @smartdata.unI()
public id: string = smartunique.shortId(); public id: string = smartunique.shortId();
@ -135,16 +127,17 @@ class Truck extends smartdata.SmartDataDbDoc<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<Truck>({ color: 'blue' });
console.log(myTruck); myTruck.id = 'foo';
await myTruck.save();
const myTruck2 = await Truck.getInstance<Truck>({ color: 'blue' });
console.log(myTruck2);
}); });
// ======================================= // =======================================
// 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(); await mongod.stop();
}); });

View File

@ -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;
} }

View File

@ -20,7 +20,7 @@ export type TDelayedDbCreation = () => SmartdataDb;
* @param dbArg * @param dbArg
*/ */
export function Collection(dbArg: SmartdataDb | TDelayedDbCreation) { export function Collection(dbArg: SmartdataDb | TDelayedDbCreation) {
return function(constructor) { return function (constructor) {
if (dbArg instanceof SmartdataDb) { if (dbArg instanceof SmartdataDb) {
// tslint:disable-next-line: no-string-literal // tslint:disable-next-line: no-string-literal
constructor['smartdataCollection'] = new SmartdataCollection(constructor, dbArg); constructor['smartdataCollection'] = new SmartdataCollection(constructor, dbArg);
@ -42,7 +42,7 @@ export class SmartdataCollection<T> {
public smartdataDb: SmartdataDb; public smartdataDb: SmartdataDb;
public uniqueIndexes: string[] = []; public uniqueIndexes: string[] = [];
constructor(collectedClassArg: T & SmartDataDbDoc<T>, smartDataDbArg: SmartdataDb) { constructor(collectedClassArg: T & SmartDataDbDoc<T, unknown>, smartDataDbArg: SmartdataDb) {
// tell the collection where it belongs // tell the collection where it belongs
this.collectionName = collectedClassArg.name; this.collectionName = collectedClassArg.name;
this.smartdataDb = smartDataDbArg; this.smartdataDb = smartDataDbArg;
@ -58,7 +58,7 @@ 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) {
@ -76,7 +76,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);
@ -103,7 +103,7 @@ export class SmartdataCollection<T> {
/** /**
* create an object in the database * create an object in the database
*/ */
public async insert(dbDocArg: T & SmartDataDbDoc<T>): Promise<any> { public async insert(dbDocArg: T & SmartDataDbDoc<T, unknown>): Promise<any> {
await this.init(); await this.init();
await this.checkDoc(dbDocArg); await this.checkDoc(dbDocArg);
this.markUniqueIndexes(dbDocArg.uniqueIndexes); this.markUniqueIndexes(dbDocArg.uniqueIndexes);
@ -115,13 +115,11 @@ export class SmartdataCollection<T> {
/** /**
* inserts object into the DbCollection * inserts object into the DbCollection
*/ */
public async update(dbDocArg: T & SmartDataDbDoc<T>): Promise<any> { public async update(dbDocArg: T & SmartDataDbDoc<T, unknown>): Promise<any> {
await this.init(); await this.init();
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();
console.log(identifiableObject);
console.log(saveableObject);
const updateableObject: any = {}; const updateableObject: any = {};
for (const key of Object.keys(saveableObject)) { for (const key of Object.keys(saveableObject)) {
if (identifiableObject[key]) { if (identifiableObject[key]) {
@ -129,7 +127,6 @@ export class SmartdataCollection<T> {
} }
updateableObject[key] = saveableObject[key]; updateableObject[key] = saveableObject[key];
} }
console.log(updateableObject);
this.mongoDbCollection.updateOne( this.mongoDbCollection.updateOne(
identifiableObject, identifiableObject,
{ $set: updateableObject }, { $set: updateableObject },
@ -137,11 +134,13 @@ export class SmartdataCollection<T> {
); );
} }
public async delete(dbDocArg: T & SmartDataDbDoc<T>): Promise<any> { public async delete(dbDocArg: T & SmartDataDbDoc<T, unknown>): Promise<any> {
await this.init(); await this.init();
await this.checkDoc(dbDocArg); await this.checkDoc(dbDocArg);
const identifiableObject = await dbDocArg.createIdentifiableObject(); const identifiableObject = await dbDocArg.createIdentifiableObject();
this.mongoDbCollection.deleteOne(identifiableObject); await this.mongoDbCollection.deleteOne(identifiableObject, {
w: 1,
});
} }
/** /**

View File

@ -1,40 +1,24 @@
import * as plugins from './smartdata.plugins'; import * as plugins from './smartdata.plugins';
import { Objectmap } from '@pushrocks/lik'; 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 { 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';
} }
@ -45,16 +29,17 @@ 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('<PASSWORD>', this.smartdataOptions.mongoDbPass)
this.smartdataOptions.mongoDbPass .replace('<password>', this.smartdataOptions.mongoDbPass)
); .replace('<DBNAME>', this.smartdataOptions.mongoDbName)
} .replace('<dbname>', this.smartdataOptions.mongoDbName);
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,
useUnifiedTopology: true,
}); });
this.mongoDb = this.mongoDbClient.db(this.smartdataOptions.mongoDbName); this.mongoDb = this.mongoDbClient.db(this.smartdataOptions.mongoDbName);
this.status = 'connected'; this.status = 'connected';
@ -67,10 +52,7 @@ export class SmartdataDb {
public 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( logger.log('info', `disconnected from database ${this.smartdataOptions.mongoDbName}`);
'info',
`disconnected from database ${this.smartdataOptions.mongoDbName}`
);
} }
// handle table to class distribution // handle table to class distribution
@ -85,7 +67,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;

View File

@ -1,6 +1,6 @@
import * as plugins from './smartdata.plugins'; 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 { SmartdataCollection } from './smartdata.classes.collection';
@ -11,7 +11,7 @@ export type TDocCreation = 'db' | 'new' | 'mixed';
* saveable - saveable decorator to be used on class properties * saveable - saveable decorator to be used on class properties
*/ */
export function svDb() { export function svDb() {
return (target: SmartDataDbDoc<any>, key: string) => { return (target: SmartDataDbDoc<unknown, unknown>, key: string) => {
console.log(`called svDb() on ${key}`); console.log(`called svDb() on ${key}`);
if (!target.saveableProperties) { if (!target.saveableProperties) {
target.saveableProperties = []; target.saveableProperties = [];
@ -24,7 +24,7 @@ export function svDb() {
* unique index - decorator to mark a unique index * unique index - decorator to mark a unique index
*/ */
export function unI() { export function unI() {
return (target: SmartDataDbDoc<any>, key: string) => { return (target: SmartDataDbDoc<unknown, unknown>, key: string) => {
console.log('called unI'); console.log('called unI');
// mark the index as unique // mark the index as unique
@ -41,7 +41,7 @@ export function unI() {
}; };
} }
export class SmartDataDbDoc<T> { export class SmartDataDbDoc<T, TImplements> {
/** /**
* the collection object an Doc belongs to * the collection object an Doc belongs to
*/ */
@ -89,7 +89,7 @@ export class SmartDataDbDoc<T> {
} }
} }
public static async getInstances<T>(filterArg): Promise<T[]> { public static async getInstances<T>(filterArg: Partial<T>): Promise<T[]> {
const self: any = this; // fool typesystem const self: any = this; // fool typesystem
let referenceMongoDBCollection: SmartdataCollection<T>; let referenceMongoDBCollection: SmartdataCollection<T>;
@ -103,17 +103,15 @@ export class SmartDataDbDoc<T> {
for (const item of foundDocs) { for (const item of foundDocs) {
const newInstance = new this(); const newInstance = new this();
newInstance.creationStatus = 'db'; newInstance.creationStatus = 'db';
for (const key in item) { for (const key of Object.keys(item)) {
if (key !== 'id') { newInstance[key] = item[key];
newInstance[key] = item[key];
}
} }
returnArray.push(newInstance); returnArray.push(newInstance);
} }
return returnArray; return returnArray;
} }
public static async getInstance<T>(filterArg): Promise<T> { public static async getInstance<T>(filterArg: Partial<T>): Promise<T> {
const 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];
@ -152,9 +150,9 @@ export class SmartDataDbDoc<T> {
* also store any referenced objects to DB * also store any referenced objects to DB
* better for data consistency * better for data consistency
*/ */
public saveDeep(savedMapArg: Objectmap<SmartDataDbDoc<any>> = null) { public saveDeep(savedMapArg: ObjectMap<SmartDataDbDoc<any, any>> = null) {
if (!savedMapArg) { if (!savedMapArg) {
savedMapArg = new Objectmap<SmartDataDbDoc<any>>(); savedMapArg = new ObjectMap<SmartDataDbDoc<any, any>>();
} }
savedMapArg.add(this); savedMapArg.add(this);
this.save(); this.save();
@ -169,12 +167,12 @@ export class SmartDataDbDoc<T> {
/** /**
* creates a saveable object so the instance can be persisted as json in the database * creates a saveable object so the instance can be persisted as json in the database
*/ */
public async createSavableObject() { public async createSavableObject(): Promise<TImplements> {
const saveableObject: any = {}; // is not exposed to outside, so any is ok here const saveableObject: unknown = {}; // is not exposed to outside, so any is ok here
for (const propertyNameString of this.saveableProperties) { for (const propertyNameString of this.saveableProperties) {
saveableObject[propertyNameString] = this[propertyNameString]; saveableObject[propertyNameString] = this[propertyNameString];
} }
return saveableObject; return saveableObject as TImplements;
} }
/** /**

3
ts/smartdata.logging.ts Normal file
View File

@ -0,0 +1,3 @@
import * as plugins from './smartdata.plugins';
export const logger = new plugins.smartlog.ConsoleLog();

View File

@ -1,3 +0,0 @@
export const addPassword = (mongoUrlArg: string, passwordArg: string): string => {
return mongoUrlArg.replace('<PASSWORD>', passwordArg);
};