Compare commits

..

30 Commits

Author SHA1 Message Date
e433b9e212 3.1.17 2019-09-02 16:51:22 +02:00
bf3656f792 fix(core): update 2019-09-02 16:51:22 +02:00
7e9fc62ce7 3.1.16 2019-09-02 16:50:23 +02:00
670a0c63fb fix(core): update 2019-09-02 16:50:22 +02:00
64e76b3ed1 3.1.15 2019-09-02 16:42:30 +02:00
25803330de fix(core): update 2019-09-02 16:42:29 +02:00
c6cbff1308 3.1.14 2019-02-13 22:08:58 +01:00
3eeac7b936 fix(structure): format 2019-02-13 22:08:58 +01:00
761b742e21 3.1.13 2019-01-08 19:55:14 +01:00
e56def621c fix(core): update 2019-01-08 19:55:13 +01:00
ab1799f4f2 3.1.12 2019-01-08 18:59:36 +01:00
9985b849d1 3.1.11 2019-01-08 18:45:31 +01:00
1800273b25 fix(core): update 2019-01-08 18:45:30 +01:00
e715cc6d37 3.1.10 2019-01-08 18:22:48 +01:00
f7abc175aa fix(core): update 2019-01-08 18:22:48 +01:00
bbcb3a614e 3.1.9 2019-01-08 14:37:17 +01:00
941d2f0902 fix(core): update 2019-01-08 14:37:17 +01:00
5c78f83a28 3.1.8 2019-01-08 13:52:09 +01:00
124f117352 fix(core): update 2019-01-08 13:52:08 +01:00
f67da898ae 3.1.7 2019-01-08 12:39:00 +01:00
3c8f70f77e fix(core): update 2019-01-08 12:38:59 +01:00
3674d7d9a5 3.1.6 2019-01-08 00:09:43 +01:00
fe2a622488 3.1.5 2019-01-07 02:50:10 +01:00
f092eefbf3 fix(core): update 2019-01-07 02:50:09 +01:00
8d0aa361f9 3.1.4 2019-01-07 02:41:38 +01:00
692a1223a8 fix(core): update 2019-01-07 02:41:38 +01:00
ae7d101ab9 3.1.3 2019-01-07 02:38:30 +01:00
3825b15a65 fix(core): update 2019-01-07 02:38:30 +01:00
3fc41678d2 3.1.2 2018-07-10 21:45:26 +02:00
39f1b7ada1 fix(test): fix import 2018-07-10 21:45:26 +02:00
17 changed files with 1973 additions and 811 deletions

24
.gitignore vendored
View File

@ -1,4 +1,22 @@
node_modules/
public/
coverage/
.nogit/ .nogit/
# artifacts
coverage/
public/
pages/
# installs
node_modules/
# caches
.yarn/
.cache/
.rpt2_cache
# builds
dist/
dist_web/
dist_serve/
dist_ts_web/
# custom

View File

@ -1,5 +1,5 @@
# gitzone standard # gitzone ci_default
image: hosttoday/ht-docker-node:npmci image: registry.gitlab.com/hosttoday/ht-docker-node:npmci
cache: cache:
paths: paths:
@ -26,6 +26,7 @@ mirror:
snyk: snyk:
stage: security stage: security
script: script:
- npmci npm prepare
- npmci command npm install -g snyk - npmci command npm install -g snyk
- npmci command npm install --ignore-scripts - npmci command npm install --ignore-scripts
- npmci command snyk test - npmci command snyk test
@ -36,44 +37,35 @@ snyk:
# ==================== # ====================
# test stage # test stage
# ==================== # ====================
testLEGACY:
stage: test
script:
- npmci node install legacy
- npmci npm install
- npmci npm test
coverage: /\d+.?\d+?\%\s*coverage/
tags:
- docker
- notpriv
allow_failure: true
testLTS: testStable:
stage: test
script:
- npmci node install lts
- npmci npm install
- npmci npm test
coverage: /\d+.?\d+?\%\s*coverage/
tags:
- docker
- notpriv
testSTABLE:
stage: test stage: test
script: script:
- 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:
stage: test
script:
- npmci npm prepare
- npmci node install lts
- npmci npm install
- npmci command npm run build
coverage: /\d+.?\d+?\%\s*coverage/
tags:
- docker
- notpriv - notpriv
release: release:
stage: release stage: release
script: script:
- npmci node install stable - npmci node install lts
- npmci npm publish - npmci npm publish
only: only:
- tags - tags
@ -86,19 +78,11 @@ release:
# ==================== # ====================
codequality: codequality:
stage: metadata stage: metadata
image: docker:stable
allow_failure: true allow_failure: true
services:
- docker:stable-dind
script: script:
- export SP_VERSION=$(echo "$CI_SERVER_VERSION" | sed 's/^\([0-9]*\)\.\([0-9]*\).*/\1-\2-stable/') - npmci command npm install -g tslint typescript
- docker run - npmci npm install
--env SOURCE_CODE="$PWD" - npmci command "tslint -c tslint.json ./ts/**/*.ts"
--volume "$PWD":/code
--volume /var/run/docker.sock:/var/run/docker.sock
"registry.gitlab.com/gitlab-org/security-products/codequality:$SP_VERSION" /code
artifacts:
paths: [codeclimate.json]
tags: tags:
- docker - docker
- priv - priv
@ -114,11 +98,15 @@ trigger:
- notpriv - notpriv
pages: pages:
image: hosttoday/ht-docker-node:npmci image: hosttoday/ht-docker-dbase:npmci
services:
- docker:stable-dind
stage: metadata stage: metadata
script: script:
- npmci command npm install -g npmpage - npmci command npm install -g @gitzone/tsdoc
- npmci command npmpage - npmci npm prepare
- npmci npm install
- npmci command tsdoc
tags: tags:
- docker - docker
- notpriv - notpriv
@ -129,13 +117,3 @@ pages:
paths: paths:
- public - public
allow_failure: true allow_failure: true
windowsCompatibility:
image: stefanscherer/node-windows:10-build-tools
stage: metadata
script:
- npm install & npm test
coverage: /\d+.?\d+?\%\s*coverage/
tags:
- windows
allow_failure: true

View File

@ -1,26 +1,20 @@
# @pushrocks/smartdata # @pushrocks/smartdata
do more with data
do more with data and RethinkDB ## Availabililty and Links
* [npmjs.org (npm package)](https://www.npmjs.com/package/@pushrocks/smartdata)
## Availabililty * [gitlab.com (source)](https://gitlab.com/pushrocks/smartdata)
* [github.com (source mirror)](https://github.com/pushrocks/smartdata)
[![npm](https://pushrocks.gitlab.io/assets/repo-button-npm.svg)](https://www.npmjs.com/package/smartdata) * [docs (typedoc)](https://pushrocks.gitlab.io/smartdata/)
[![git](https://pushrocks.gitlab.io/assets/repo-button-git.svg)](https://GitLab.com/pushrocks/smartdata)
[![git](https://pushrocks.gitlab.io/assets/repo-button-mirror.svg)](https://github.com/pushrocks/smartdata)
[![docs](https://pushrocks.gitlab.io/assets/repo-button-docs.svg)](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)
[![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)
[![coverage report](https://GitLab.com/pushrocks/smartdata/badges/master/coverage.svg)](https://GitLab.com/pushrocks/smartdata/commits/master) [![npm downloads per month](https://img.shields.io/npm/dm/@pushrocks/smartdata.svg)](https://www.npmjs.com/package/@pushrocks/smartdata)
[![npm downloads per month](https://img.shields.io/npm/dm/smartdata.svg)](https://www.npmjs.com/package/smartdata) [![Known Vulnerabilities](https://snyk.io/test/npm/@pushrocks/smartdata/badge.svg)](https://snyk.io/test/npm/@pushrocks/smartdata)
[![Dependency Status](https://david-dm.org/pushrocks/smartdata.svg)](https://david-dm.org/pushrocks/smartdata) [![TypeScript](https://img.shields.io/badge/TypeScript->=%203.x-blue.svg)](https://nodejs.org/dist/latest-v10.x/docs/api/)
[![bitHound Dependencies](https://www.bithound.io/github/pushrocks/smartdata/badges/dependencies.svg)](https://www.bithound.io/github/pushrocks/smartdata/master/dependencies/npm) [![node](https://img.shields.io/badge/node->=%2010.x.x-blue.svg)](https://nodejs.org/dist/latest-v10.x/docs/api/)
[![bitHound Code](https://www.bithound.io/github/pushrocks/smartdata/badges/code.svg)](https://www.bithound.io/github/pushrocks/smartdata) [![JavaScript Style Guide](https://img.shields.io/badge/code%20style-prettier-ff69b4.svg)](https://prettier.io/)
[![Known Vulnerabilities](https://snyk.io/test/npm/smartdata/badge.svg)](https://snyk.io/test/npm/smartdata)
[![TypeScript](https://img.shields.io/badge/TypeScript-2.x-blue.svg)](https://nodejs.org/dist/latest-v6.x/docs/api/)
[![node](https://img.shields.io/badge/node->=%206.x.x-blue.svg)](https://nodejs.org/dist/latest-v6.x/docs/api/)
[![JavaScript Style Guide](https://img.shields.io/badge/code%20style-standard-brightgreen.svg)](http://standardjs.com/)
## Usage ## Usage
@ -38,7 +32,7 @@ This is why we started smartdata.
How RethinkDB's terms map to the ones of smartdata: How RethinkDB's terms map to the ones of smartdata:
| MongoDb term | smartdata class | | MongoDb term | smartdata class |
| -------------- | ------------------------------| | ------------ | ----------------------------- |
| Database | smartdata.SmartdataDb | | Database | smartdata.SmartdataDb |
| Collection | smartdata.SmartdataCollection | | Collection | smartdata.SmartdataCollection |
| Document | smartdata.SmartadataDoc | | Document | smartdata.SmartadataDoc |
@ -121,9 +115,9 @@ you should get all the Intellisense and type checking you love when using smartd
smartdata itself also bundles typings. smartdata itself also bundles typings.
So you don't need to install any additional types when importing smartdata. So you don't need to install any additional types when importing smartdata.
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 | **©** [Lossless GmbH](https://lossless.gmbh) > MIT licensed | **©** [Lossless GmbH](https://lossless.gmbh)
> | By using this npm module you agree to our [privacy policy](https://lossless.gmbH/privacy.html) | By using this npm module you agree to our [privacy policy](https://lossless.gmbH/privacy)
[![repo-footer](https://pushrocks.gitlab.io/assets/repo-footer.svg)](https://push.rocks) [![repo-footer](https://lossless.gitlab.io/publicrelations/repofooter.svg)](https://maintainedby.lossless.com)

View File

@ -1,29 +0,0 @@
# smartdata
do more with data
## Availabililty
[![npm](https://pushrocks.gitlab.io/assets/repo-button-npm.svg)](https://www.npmjs.com/package/smartdata)
[![git](https://pushrocks.gitlab.io/assets/repo-button-git.svg)](https://GitLab.com/pushrocks/smartdata)
[![git](https://pushrocks.gitlab.io/assets/repo-button-mirror.svg)](https://github.com/pushrocks/smartdata)
[![docs](https://pushrocks.gitlab.io/assets/repo-button-docs.svg)](https://pushrocks.gitlab.io/smartdata/)
## 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)
[![npm downloads per month](https://img.shields.io/npm/dm/smartdata.svg)](https://www.npmjs.com/package/smartdata)
[![Dependency Status](https://david-dm.org/pushrocks/smartdata.svg)](https://david-dm.org/pushrocks/smartdata)
[![bitHound Dependencies](https://www.bithound.io/github/pushrocks/smartdata/badges/dependencies.svg)](https://www.bithound.io/github/pushrocks/smartdata/master/dependencies/npm)
[![bitHound Code](https://www.bithound.io/github/pushrocks/smartdata/badges/code.svg)](https://www.bithound.io/github/pushrocks/smartdata)
[![TypeScript](https://img.shields.io/badge/TypeScript-2.x-blue.svg)](https://nodejs.org/dist/latest-v6.x/docs/api/)
[![node](https://img.shields.io/badge/node->=%206.x.x-blue.svg)](https://nodejs.org/dist/latest-v6.x/docs/api/)
[![JavaScript Style Guide](https://img.shields.io/badge/code%20style-standard-brightgreen.svg)](http://standardjs.com/)
For further information read the linked docs at the top of this README.
> MIT licensed | **©** [Lossless GmbH](https://lossless.gmbh)
> | By using this npm module you agree to our [privacy policy](https://lossless.gmbH/privacy.html)
[![repo-footer](https://pushrocks.gitlab.io/assets/repo-footer.svg)](https://push.rocks)

View File

@ -5,14 +5,18 @@
"dockerSock": false "dockerSock": false
}, },
"npmci": { "npmci": {
"npmGlobalTools": [ "npmGlobalTools": [],
"@gitzone/npmts" "npmAccessLevel": "public",
], "npmRegistryUrl": "registry.npmjs.org"
"npmAccessLevel": "public"
}, },
"npmts": { "gitzone": {
"testConfig": { "module": {
"parallel": false "githost": "gitlab.com",
"gitscope": "pushrocks",
"gitrepo": "smartdata",
"shortDescription": "do more with data",
"npmPackagename": "@pushrocks/smartdata",
"license": "MIT"
} }
} }
} }

2227
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.1", "version": "3.1.17",
"private": false, "private": false,
"description": "do more with data", "description": "do more with data",
"main": "dist/index.js", "main": "dist/index.js",
"typings": "dist/index.d.ts", "typings": "dist/index.d.ts",
"scripts": { "scripts": {
"test": "tsrun test/test.ts", "test": "(tstest test/)",
"testLocal": "(npmdocker)", "testLocal": "(npmdocker)",
"build": "(npmts)" "build": "(tsbuild)"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
@ -21,23 +21,38 @@
}, },
"homepage": "https://gitlab.com/pushrocks/smartdata#README", "homepage": "https://gitlab.com/pushrocks/smartdata#README",
"dependencies": { "dependencies": {
"@pushrocks/smartlog": "^1.0.6", "@pushrocks/lik": "^3.0.11",
"@pushrocks/smartpromise": "^2.0.5", "@pushrocks/smartlog": "^2.0.19",
"@types/lodash": "^4.14.110", "@pushrocks/smartpromise": "^3.0.2",
"@types/mongodb": "^3.1.1", "@pushrocks/smartstring": "^3.0.10",
"lik": "^2.0.5", "@pushrocks/smartunique": "^3.0.1",
"lodash": "^4.17.10", "@types/lodash": "^4.14.138",
"mongodb": "^3.1.1", "@types/mongodb": "^3.3.1",
"runtime-type-checks": "0.0.4", "lodash": "^4.17.15",
"smartstring": "^2.0.28" "mongodb": "^3.3.2",
"runtime-type-checks": "0.0.4"
}, },
"devDependencies": { "devDependencies": {
"@gitzone/tsrun": "^1.1.2", "@gitzone/tsbuild": "^2.1.17",
"@types/node": "^10.5.2", "@gitzone/tstest": "^1.0.24",
"@pushrocks/qenv": "^4.0.4",
"@pushrocks/tapbundle": "^3.0.13",
"@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": "^1.9.0", "mongodb-memory-server": "^5.2.0",
"qenv": "^1.1.7", "tslint": "^5.19.0",
"shortid": "^2.2.11", "tslint-config-prettier": "^1.18.0"
"tapbundle": "^2.0.2" },
} "files": [
"ts/*",
"ts_web/*",
"dist/*",
"dist_web/*",
"dist_ts_web/*",
"assets/*",
"cli.js",
"npmextra.json",
"readme.md"
]
} }

View File

@ -1,4 +1,4 @@
vars: required:
- MONGO_URL - MONGO_URL
- MONGO_DBNAME - MONGO_DBNAME
- MONGO_PASS - MONGO_PASS

View File

@ -1,26 +1,44 @@
import { tap, expect } from 'tapbundle'; import { tap, expect } from '@pushrocks/tapbundle';
import * as smartpromise from '@pushrocks/smartpromise'; import { Qenv } from '@pushrocks/qenv';
import { Qenv } from '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'; 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);
testDb = new smartdata.SmartdataDb(smartdataOptions);
});
tap.skip.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 () => {
await testDb.connect(); await testDb.init();
}); });
// ======================================= // =======================================
@ -31,11 +49,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 +72,37 @@ 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

@ -1,3 +1,5 @@
export * from './smartdata.classes.db'; export * from './smartdata.classes.db';
export * from './smartdata.classes.collection'; export * from './smartdata.classes.collection';
export * from './smartdata.classes.doc'; export * from './smartdata.classes.doc';
export { IMongoDescriptor } from './interfaces';

1
ts/interfaces/index.ts Normal file
View File

@ -0,0 +1 @@
export * from './mongodescriptor';

View File

@ -0,0 +1,5 @@
export interface IMongoDescriptor {
mongoDbName: string;
mongoDbUrl: string;
mongoDbPass: string;
}

View File

@ -13,13 +13,22 @@ export interface IDocValidationFunc<T> {
(doc: T): boolean; (doc: T): boolean;
} }
export type TDelayedDbCreation = () => SmartdataDb;
/** /**
* 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 db * @param dbArg
*/ */
export function Collection(db: SmartdataDb) { export function Collection(dbArg: SmartdataDb | TDelayedDbCreation) {
return function(constructor) { return function(constructor) {
constructor['smartdataCollection'] = new SmartdataCollection(constructor, db); if (dbArg instanceof SmartdataDb) {
// tslint:disable-next-line: no-string-literal
constructor['smartdataCollection'] = new SmartdataCollection(constructor, dbArg);
} else {
constructor['smartdataDelayedCollection'] = () => {
return new SmartdataCollection(constructor, dbArg());
};
}
}; };
} }
@ -27,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
@ -45,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();
@ -56,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
@ -78,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;
@ -94,12 +103,11 @@ 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);
const saveableObject = await dbDocArg.createSavableObject(); const saveableObject = await dbDocArg.createSavableObject();
console.log(saveableObject);
const result = await this.mongoDbCollection.insertOne(saveableObject); const result = await this.mongoDbCollection.insertOne(saveableObject);
return result; return result;
} }
@ -107,11 +115,33 @@ export class SmartdataCollection<T> {
/** /**
* inserts object into the DbCollection * inserts object into the DbCollection
*/ */
async update(dbDocArg: T & SmartDataDbDoc<T>): Promise<any> { public async update(dbDocArg: T & SmartDataDbDoc<T>): Promise<any> {
await this.init(); await this.init();
await this.checkDoc(dbDocArg); await this.checkDoc(dbDocArg);
const identifiableObject = await dbDocArg.createIdentifiableObject();
const saveableObject = await dbDocArg.createSavableObject(); const saveableObject = await dbDocArg.createSavableObject();
this.mongoDbCollection.updateOne(saveableObject.dbDocUniqueId, 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> {
await this.init();
await this.checkDoc(dbDocArg);
const identifiableObject = await dbDocArg.createIdentifiableObject();
this.mongoDbCollection.deleteOne(identifiableObject);
} }
/** /**
@ -119,7 +149,7 @@ export class SmartdataCollection<T> {
* if this.objectValidation is not set it passes. * if this.objectValidation is not set it passes.
*/ */
private checkDoc(docArg: T): Promise<void> { private checkDoc(docArg: T): Promise<void> {
let done = plugins.smartq.defer<void>(); const done = plugins.smartq.defer<void>();
let validationResult = true; let validationResult = true;
if (this.objectValidation) { if (this.objectValidation) {
validationResult = this.objectValidation(docArg); validationResult = this.objectValidation(docArg);

View File

@ -1,5 +1,5 @@
import * as plugins from './smartdata.plugins'; import * as plugins from './smartdata.plugins';
import { Objectmap } from 'lik'; import { Objectmap } from '@pushrocks/lik';
import { SmartdataCollection } from './smartdata.classes.collection'; import { SmartdataCollection } from './smartdata.classes.collection';
@ -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 connect(): 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,13 +52,10 @@ export class SmartdataDb {
this.smartdataOptions.mongoDbPass this.smartdataOptions.mongoDbPass
); );
} }
console.log(finalConnectionUrl); console.log(`connection Url: ${finalConnectionUrl}`);
this.mongoDbClient = await plugins.mongodb.MongoClient.connect( this.mongoDbClient = await plugins.mongodb.MongoClient.connect(finalConnectionUrl, {
finalConnectionUrl,
{
useNewUrlParser: true useNewUrlParser: true
} });
);
this.mongoDb = this.mongoDbClient.db(this.smartdataOptions.mongoDbName); this.mongoDb = this.mongoDbClient.db(this.smartdataOptions.mongoDbName);
this.status = 'connected'; this.status = 'connected';
console.log(`Connected to database ${this.smartdataOptions.mongoDbName}`); console.log(`Connected to database ${this.smartdataOptions.mongoDbName}`);
@ -67,17 +64,18 @@ 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 plugins.smartlog.defaultLogger.log(
.getDefaultLogger() 'info',
.info(`disconnected from database ${this.smartdataOptions.mongoDbName}`); `disconnected from database ${this.smartdataOptions.mongoDbName}`
);
} }
// 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);
} }
@ -86,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

@ -1,6 +1,6 @@
import * as plugins from './smartdata.plugins'; import * as plugins from './smartdata.plugins';
import { Objectmap } from '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';
@ -45,49 +45,65 @@ 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
*/ */
constructor() { constructor() {
this.name = this.constructor['name']; this.name = this.constructor['name'];
if (this.constructor['smartdataCollection']) {
// tslint:disable-next-line: no-string-literal
this.collection = this.constructor['smartdataCollection']; 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');
}
} }
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> = self.smartdataCollection; let referenceMongoDBCollection: SmartdataCollection<T>;
if (self.smartdataCollection) {
referenceMongoDBCollection = self.smartdataCollection;
} else if (self.smartdataDelayedCollection) {
referenceMongoDBCollection = self.smartdataDelayedCollection();
}
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];
} }
@ -98,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];
} }
@ -108,14 +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() {
let self: any = this; // tslint:disable-next-line: no-this-assignment
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:
@ -123,29 +140,48 @@ export class SmartDataDbDoc<T> {
} }
} }
/**
* deletes a document from the database
*/
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);
} }
} }
} }
async createSavableObject() { /**
let saveableObject: any = {}; // is not exposed to outside, so any is ok here * creates a saveable object so the instance can be persisted as json in the database
for (let propertyNameString of this.saveableProperties) { */
public async createSavableObject() {
const saveableObject: any = {}; // is not exposed to outside, so any is ok here
for (const propertyNameString of this.saveableProperties) {
saveableObject[propertyNameString] = this[propertyNameString]; saveableObject[propertyNameString] = this[propertyNameString];
} }
return saveableObject; return saveableObject;
} }
/**
* creates an identifiable object for operations that require filtering
*/
public async createIdentifiableObject() {
const identifiableObject: any = {}; // is not exposed to outside, so any is ok here
for (const propertyNameString of this.uniqueIndexes) {
identifiableObject[propertyNameString] = this[propertyNameString];
}
return identifiableObject;
}
} }

View File

@ -2,7 +2,8 @@ import * as assert from 'assert';
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';
import * as smartq from 'smartq'; import * as smartq from '@pushrocks/smartpromise';
import * as smartstring from '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 };

17
tslint.json Normal file
View File

@ -0,0 +1,17 @@
{
"extends": ["tslint:latest", "tslint-config-prettier"],
"rules": {
"semicolon": [true, "always"],
"no-console": false,
"ordered-imports": false,
"object-literal-sort-keys": false,
"member-ordering": {
"options":{
"order": [
"static-method"
]
}
}
},
"defaultSeverity": "warning"
}