Compare commits
47 Commits
Author | SHA1 | Date | |
---|---|---|---|
90d9a25b3f | |||
e49811eecd | |||
9cbdf317dc | |||
d55339013a | |||
9acdbd2842 | |||
dfce8cfcc0 | |||
38446fc79b | |||
af8c41ad6c | |||
3a24f829b4 | |||
67db1325c1 | |||
6683c05c22 | |||
f7f7852b7f | |||
df4346e0a2 | |||
eb54fbcd0d | |||
f13c12cd47 | |||
08d53f22f5 | |||
5b6523e6f4 | |||
138290a7b8 | |||
036cafc282 | |||
7764ba5cb8 | |||
7f77634ea1 | |||
acf3c29939 | |||
925cd639b4 | |||
af8de58dcd | |||
f39703b8d9 | |||
fa1951b4dd | |||
8c37a367a0 | |||
37f388e998 | |||
78bdb6760e | |||
ce1dceb60c | |||
16add8bff0 | |||
11149b2712 | |||
e508a942e3 | |||
5b093c68e4 | |||
d1b0a65993 | |||
316030be7c | |||
411b0b1ae9 | |||
50a6a1a690 | |||
ee3c3580d3 | |||
6dd82994a6 | |||
295096de24 | |||
50b5f84955 | |||
1557c713cd | |||
4ce457fadf | |||
56d6e0fd45 | |||
89ebf23d46 | |||
a861444c30 |
105
README.md
Normal file
105
README.md
Normal file
@ -0,0 +1,105 @@
|
||||
# smartdata
|
||||
|
||||
> Note: Still in Beta
|
||||
|
||||
## Availabililty
|
||||
[](https://www.npmjs.com/package/smartdata)
|
||||
[](https://gitlab.com/pushrocks/smartdata)
|
||||
[](https://github.com/pushrocks/smartdata)
|
||||
[](https://pushrocks.gitlab.io/smartdata/)
|
||||
|
||||
## Status for master
|
||||
[](https://gitlab.com/pushrocks/smartdata/commits/master)
|
||||
[](https://gitlab.com/pushrocks/smartdata/commits/master)
|
||||
[](https://david-dm.org/pushrocks/smartdata)
|
||||
[](https://www.bithound.io/github/pushrocks/smartdata/master/dependencies/npm)
|
||||
[](https://www.bithound.io/github/pushrocks/smartdata)
|
||||
[](https://nodejs.org/dist/latest-v6.x/docs/api/)
|
||||
[](https://nodejs.org/dist/latest-v6.x/docs/api/)
|
||||
[](http://standardjs.com/)
|
||||
|
||||
smartdata is an ODM that adheres to TypeScript practices and uses classes to organize data.
|
||||
It uses MongoDB or NeDb as persistent storage.
|
||||
|
||||
## Intention
|
||||
There are many ODMs out there, however when we searched for an ODM that uses TypeScript,
|
||||
acts smart while still embracing the NoSQL idea we didn't find a matching solution.
|
||||
This is why we started smartdata.
|
||||
|
||||
How MongoDB terms map to smartdata classes
|
||||
|
||||
MongoDB term | smartdata class
|
||||
--- | ---
|
||||
Database | smartdata.Db
|
||||
Collection | smartdata.DbCollection
|
||||
Document | smartdata.DbDoc
|
||||
|
||||
### class Db
|
||||
represents a Database. Naturally it has .connect() etc. methods on it.
|
||||
Since it is a class you can have multiple DBs defined.
|
||||
```javascript
|
||||
import * as smartdata from 'smartdata'
|
||||
|
||||
// mongodb
|
||||
let myDb1 = new smartdata.Db('someConnectionUrl')
|
||||
let myDb2 = new smartdata.Db('someConnectionUrl')
|
||||
|
||||
// nedb
|
||||
let myDb3 = new smartdata('/some/path/for/persistence', 'nedb') // you may set first argument to null for just in memory db
|
||||
|
||||
myDb1.connect()
|
||||
myDb2.connect()
|
||||
|
||||
// continues in next block...
|
||||
```
|
||||
|
||||
### class DbCollection
|
||||
represents a collection of objects.
|
||||
A collection is defined by the object class (that is extending smartdata.dbdoc) it respresents
|
||||
|
||||
So to get to get access to a specific collection you document
|
||||
```javascript
|
||||
// continues from the block before...
|
||||
|
||||
@Collection(myDb1)
|
||||
class myObject extends smartdata.DbDoc<myObject> { // read the next block about DbDoc
|
||||
property1:string
|
||||
property2:number
|
||||
constructor(optionsArg:{
|
||||
property1:string,
|
||||
property2:number
|
||||
}) {
|
||||
super()
|
||||
}
|
||||
}
|
||||
let myCollection = myDb1.getCollectionByName<myObject>(myObject)
|
||||
|
||||
// start to instantiate classes from scratch or database
|
||||
```
|
||||
|
||||
> Alert: You NEVER instantiate a collection.
|
||||
This is done for you!!!
|
||||
|
||||
### class DbDoc
|
||||
represents a individual document in a collection
|
||||
and thereby is ideally suited to extend the class you want to actually store.
|
||||
|
||||
DbDoc extends your class with the following methods:
|
||||
|
||||
* `.save()` will save (or update) the object you call it on only. Any referenced non-savable objects will not get stored.
|
||||
* `.saveDeep()` does the same like `.save()`.
|
||||
In addition it will look for properties that reference an object
|
||||
that extends DbDoc as well and call .saveDeep() on them as well.
|
||||
Loops are prevented
|
||||
|
||||
So now we can **store** instances of classes to Db...
|
||||
How do we **get** a new class instance from a Doc in the DB?
|
||||
|
||||
## TypeScript
|
||||
How does TypeScript play into this?
|
||||
Since you define your classes in TypeScript and types flow through smartdata in a generic way
|
||||
you should get all the Intellisense and type checking you love when using smartdata.
|
||||
smartdata itself also bundles typings.
|
||||
So you don't need to install any additional types when importing smartdata.
|
||||
|
||||
[](https://push.rocks)
|
17
dist/index.d.ts
vendored
17
dist/index.d.ts
vendored
@ -1,14 +1,3 @@
|
||||
/// <reference types="q" />
|
||||
import * as plugins from './smartdata.plugins';
|
||||
export declare class DbCollection<T> {
|
||||
constructor(nameArg: string, db: plugins.mongodb.Db);
|
||||
}
|
||||
export declare type TDbConnectionStatus = 'disconnected' | 'connected' | 'failed';
|
||||
export declare class DbConnection {
|
||||
dbUrl: string;
|
||||
db: plugins.mongodb.Db;
|
||||
status: TDbConnectionStatus;
|
||||
constructor(dbUrl: string);
|
||||
connect(): plugins.q.Promise<any>;
|
||||
close(): plugins.q.Promise<any>;
|
||||
}
|
||||
export * from './smartdata.classes.db';
|
||||
export * from './smartdata.classes.dbcollection';
|
||||
export * from './smartdata.classes.dbdoc';
|
||||
|
39
dist/index.js
vendored
39
dist/index.js
vendored
@ -1,35 +1,8 @@
|
||||
"use strict";
|
||||
const plugins = require('./smartdata.plugins');
|
||||
class DbCollection {
|
||||
constructor(nameArg, db) {
|
||||
let collection = db.collection(nameArg);
|
||||
}
|
||||
function __export(m) {
|
||||
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
|
||||
}
|
||||
exports.DbCollection = DbCollection;
|
||||
class DbConnection {
|
||||
constructor(dbUrl) {
|
||||
this.dbUrl = dbUrl;
|
||||
}
|
||||
connect() {
|
||||
let done = plugins.q.defer();
|
||||
plugins.mongodb.MongoClient.connect(this.dbUrl, (err, db) => {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
}
|
||||
plugins.assert.equal(null, err);
|
||||
this.db = db;
|
||||
plugins.beautylog.success(`connected to database at ${this.dbUrl}`);
|
||||
done.resolve(this.db);
|
||||
});
|
||||
return done.promise;
|
||||
}
|
||||
close() {
|
||||
let done = plugins.q.defer();
|
||||
this.db.close();
|
||||
plugins.beautylog.ok(`disconnected to database at ${this.dbUrl}`);
|
||||
done.resolve();
|
||||
return done.promise;
|
||||
}
|
||||
}
|
||||
exports.DbConnection = DbConnection;
|
||||
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUEsTUFBWSxPQUFPLFdBQU0scUJBRXpCLENBQUMsQ0FGNkM7QUFFOUM7SUFDSSxZQUFZLE9BQWUsRUFBRSxFQUFzQjtRQUMvQyxJQUFJLFVBQVUsR0FBRyxFQUFFLENBQUMsVUFBVSxDQUFDLE9BQU8sQ0FBQyxDQUFBO0lBQzNDLENBQUM7QUFDTCxDQUFDO0FBSlksb0JBQVksZUFJeEIsQ0FBQTtBQUlEO0lBS0ksWUFBWSxLQUFhO1FBQ3JCLElBQUksQ0FBQyxLQUFLLEdBQUcsS0FBSyxDQUFBO0lBQ3RCLENBQUM7SUFFRCxPQUFPO1FBQ0gsSUFBSSxJQUFJLEdBQUcsT0FBTyxDQUFDLENBQUMsQ0FBQyxLQUFLLEVBQUUsQ0FBQTtRQUM1QixPQUFPLENBQUMsT0FBTyxDQUFDLFdBQVcsQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLEtBQUssRUFBRSxDQUFDLEdBQUcsRUFBRSxFQUFFO1lBQ3BELEVBQUUsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUM7Z0JBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQTtZQUFDLENBQUM7WUFDN0IsT0FBTyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsSUFBSSxFQUFFLEdBQUcsQ0FBQyxDQUFBO1lBQy9CLElBQUksQ0FBQyxFQUFFLEdBQUcsRUFBRSxDQUFBO1lBQ1osT0FBTyxDQUFDLFNBQVMsQ0FBQyxPQUFPLENBQUMsNEJBQTRCLElBQUksQ0FBQyxLQUFLLEVBQUUsQ0FBQyxDQUFBO1lBQ25FLElBQUksQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFBO1FBQ3pCLENBQUMsQ0FBQyxDQUFBO1FBQ0YsTUFBTSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUE7SUFDdkIsQ0FBQztJQUVELEtBQUs7UUFDRCxJQUFJLElBQUksR0FBRyxPQUFPLENBQUMsQ0FBQyxDQUFDLEtBQUssRUFBRSxDQUFBO1FBQzVCLElBQUksQ0FBQyxFQUFFLENBQUMsS0FBSyxFQUFFLENBQUE7UUFDZixPQUFPLENBQUMsU0FBUyxDQUFDLEVBQUUsQ0FBQywrQkFBK0IsSUFBSSxDQUFDLEtBQUssRUFBRSxDQUFDLENBQUE7UUFDakUsSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFBO1FBQ2QsTUFBTSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUE7SUFDdkIsQ0FBQztBQUNMLENBQUM7QUE1Qlksb0JBQVksZUE0QnhCLENBQUEifQ==
|
||||
__export(require("./smartdata.classes.db"));
|
||||
__export(require("./smartdata.classes.dbcollection"));
|
||||
__export(require("./smartdata.classes.dbdoc"));
|
||||
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7O0FBRUEsNENBQXNDO0FBQ3RDLHNEQUFnRDtBQUNoRCwrQ0FBeUMifQ==
|
33
dist/smartdata.classes.db.d.ts
vendored
Normal file
33
dist/smartdata.classes.db.d.ts
vendored
Normal file
@ -0,0 +1,33 @@
|
||||
/// <reference types="q" />
|
||||
import * as plugins from './smartdata.plugins';
|
||||
import { Objectmap } from 'lik';
|
||||
import { DbCollection } from './smartdata.classes.dbcollection';
|
||||
/**
|
||||
* interface - indicates the database type
|
||||
*/
|
||||
export declare type TDbType = 'mongodb' | 'nedb';
|
||||
/**
|
||||
* interface - indicates the connection status of the db
|
||||
*/
|
||||
export declare type TConnectionStatus = 'disconnected' | 'connected' | 'failed';
|
||||
export declare class Db {
|
||||
dbType: TDbType;
|
||||
dbUrl: string;
|
||||
db: plugins.mongodb.Db;
|
||||
status: TConnectionStatus;
|
||||
collections: Objectmap<DbCollection<any>>;
|
||||
constructor(dbUrlArg: string, dbTypeArg?: TDbType);
|
||||
/**
|
||||
* connects to the database that was specified during instance creation
|
||||
*/
|
||||
connect(): plugins.q.Promise<any>;
|
||||
/**
|
||||
* closes the connection to the databse
|
||||
*/
|
||||
close(): plugins.q.Promise<any>;
|
||||
/**
|
||||
* gets a collection by name: string
|
||||
*/
|
||||
getCollectionByName<T>(nameArg: string): plugins.q.Promise<DbCollection<T>>;
|
||||
addCollection(dbCollectionArg: DbCollection<any>): void;
|
||||
}
|
64
dist/smartdata.classes.db.js
vendored
Normal file
64
dist/smartdata.classes.db.js
vendored
Normal file
@ -0,0 +1,64 @@
|
||||
"use strict";
|
||||
const plugins = require("./smartdata.plugins");
|
||||
const lik_1 = require("lik");
|
||||
class Db {
|
||||
constructor(dbUrlArg, dbTypeArg = 'mongodb') {
|
||||
this.collections = new lik_1.Objectmap();
|
||||
this.dbType = dbTypeArg;
|
||||
this.dbUrl = dbUrlArg;
|
||||
}
|
||||
// basic connection stuff ----------------------------------------------
|
||||
/**
|
||||
* connects to the database that was specified during instance creation
|
||||
*/
|
||||
connect() {
|
||||
let done = plugins.q.defer();
|
||||
if (this.dbType === 'mongodb') {
|
||||
plugins.mongodb.MongoClient.connect(this.dbUrl, (err, db) => {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
}
|
||||
plugins.assert.equal(null, err);
|
||||
this.db = db;
|
||||
plugins.beautylog.success(`connected to database at ${this.dbUrl}`);
|
||||
done.resolve(this.db);
|
||||
});
|
||||
}
|
||||
else if (this.dbType === 'nedb') {
|
||||
this.db = null;
|
||||
}
|
||||
return done.promise;
|
||||
}
|
||||
/**
|
||||
* closes the connection to the databse
|
||||
*/
|
||||
close() {
|
||||
let done = plugins.q.defer();
|
||||
if (this.dbType === 'mongodb') {
|
||||
this.db.close();
|
||||
}
|
||||
plugins.beautylog.ok(`disconnected to database at ${this.dbUrl}`);
|
||||
done.resolve();
|
||||
return done.promise;
|
||||
}
|
||||
// advanced communication with the database --------------------------------
|
||||
/**
|
||||
* gets a collection by name: string
|
||||
*/
|
||||
getCollectionByName(nameArg) {
|
||||
let done = plugins.q.defer();
|
||||
let resultCollection = this.collections.find((dbCollectionArg) => {
|
||||
return dbCollectionArg.name === nameArg;
|
||||
});
|
||||
if (resultCollection !== null) {
|
||||
done.resolve(resultCollection);
|
||||
}
|
||||
return done.promise;
|
||||
}
|
||||
;
|
||||
addCollection(dbCollectionArg) {
|
||||
this.collections.add(dbCollectionArg);
|
||||
}
|
||||
}
|
||||
exports.Db = Db;
|
||||
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnRkYXRhLmNsYXNzZXMuZGIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9zbWFydGRhdGEuY2xhc3Nlcy5kYi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUEsK0NBQThDO0FBQzlDLDZCQUErQjtBQWMvQjtJQU9JLFlBQVksUUFBZ0IsRUFBRSxZQUFxQixTQUFTO1FBRjVELGdCQUFXLEdBQUcsSUFBSSxlQUFTLEVBQXFCLENBQUE7UUFHNUMsSUFBSSxDQUFDLE1BQU0sR0FBRyxTQUFTLENBQUE7UUFDdkIsSUFBSSxDQUFDLEtBQUssR0FBRyxRQUFRLENBQUE7SUFDekIsQ0FBQztJQUVELHdFQUF3RTtJQUV4RTs7T0FFRztJQUNILE9BQU87UUFDSCxJQUFJLElBQUksR0FBRyxPQUFPLENBQUMsQ0FBQyxDQUFDLEtBQUssRUFBRSxDQUFBO1FBQzVCLEVBQUUsQ0FBQyxDQUFDLElBQUksQ0FBQyxNQUFNLEtBQUssU0FBUyxDQUFDLENBQUMsQ0FBQztZQUM1QixPQUFPLENBQUMsT0FBTyxDQUFDLFdBQVcsQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLEtBQUssRUFBRSxDQUFDLEdBQUcsRUFBRSxFQUFFO2dCQUNwRCxFQUFFLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO29CQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUE7Z0JBQUMsQ0FBQztnQkFDN0IsT0FBTyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsSUFBSSxFQUFFLEdBQUcsQ0FBQyxDQUFBO2dCQUMvQixJQUFJLENBQUMsRUFBRSxHQUFHLEVBQUUsQ0FBQTtnQkFDWixPQUFPLENBQUMsU0FBUyxDQUFDLE9BQU8sQ0FBQyw0QkFBNEIsSUFBSSxDQUFDLEtBQUssRUFBRSxDQUFDLENBQUE7Z0JBQ25FLElBQUksQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFBO1lBQ3pCLENBQUMsQ0FBQyxDQUFBO1FBQ04sQ0FBQztRQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQyxJQUFJLENBQUMsTUFBTSxLQUFLLE1BQU0sQ0FBQyxDQUFDLENBQUM7WUFDaEMsSUFBSSxDQUFDLEVBQUUsR0FBRyxJQUFJLENBQUE7UUFDbEIsQ0FBQztRQUNELE1BQU0sQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFBO0lBQ3ZCLENBQUM7SUFFRDs7T0FFRztJQUNILEtBQUs7UUFDRCxJQUFJLElBQUksR0FBRyxPQUFPLENBQUMsQ0FBQyxDQUFDLEtBQUssRUFBRSxDQUFBO1FBQzVCLEVBQUUsQ0FBQyxDQUFDLElBQUksQ0FBQyxNQUFNLEtBQUssU0FBUyxDQUFDLENBQUMsQ0FBQztZQUM1QixJQUFJLENBQUMsRUFBRSxDQUFDLEtBQUssRUFBRSxDQUFBO1FBQ25CLENBQUM7UUFDRCxPQUFPLENBQUMsU0FBUyxDQUFDLEVBQUUsQ0FBQywrQkFBK0IsSUFBSSxDQUFDLEtBQUssRUFBRSxDQUFDLENBQUE7UUFDakUsSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFBO1FBQ2QsTUFBTSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUE7SUFDdkIsQ0FBQztJQUVELDRFQUE0RTtJQUU1RTs7T0FFRztJQUNILG1CQUFtQixDQUFJLE9BQWU7UUFDbEMsSUFBSSxJQUFJLEdBQUcsT0FBTyxDQUFDLENBQUMsQ0FBQyxLQUFLLEVBQXFCLENBQUE7UUFDL0MsSUFBSSxnQkFBZ0IsR0FBRyxJQUFJLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQyxDQUFDLGVBQWU7WUFDekQsTUFBTSxDQUFDLGVBQWUsQ0FBQyxJQUFJLEtBQUssT0FBTyxDQUFBO1FBQzNDLENBQUMsQ0FBQyxDQUFBO1FBQ0YsRUFBRSxDQUFDLENBQUMsZ0JBQWdCLEtBQUssSUFBSSxDQUFDLENBQUMsQ0FBQztZQUM1QixJQUFJLENBQUMsT0FBTyxDQUFDLGdCQUFnQixDQUFDLENBQUE7UUFDbEMsQ0FBQztRQUNELE1BQU0sQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFBO0lBQ3ZCLENBQUM7SUFBQSxDQUFDO0lBRUYsYUFBYSxDQUFDLGVBQWtDO1FBQzVDLElBQUksQ0FBQyxXQUFXLENBQUMsR0FBRyxDQUFDLGVBQWUsQ0FBQyxDQUFBO0lBQ3pDLENBQUM7Q0FFSjtBQWxFRCxnQkFrRUMifQ==
|
41
dist/smartdata.classes.dbcollection.d.ts
vendored
Normal file
41
dist/smartdata.classes.dbcollection.d.ts
vendored
Normal file
@ -0,0 +1,41 @@
|
||||
/// <reference types="q" />
|
||||
import * as plugins from './smartdata.plugins';
|
||||
import { Db } from './smartdata.classes.db';
|
||||
export interface IFindOptions {
|
||||
limit?: number;
|
||||
}
|
||||
export interface IDocValidation<T> {
|
||||
(doc: T): boolean;
|
||||
}
|
||||
export declare function Collection(db: Db): (constructor: any) => void;
|
||||
export declare class DbCollection<T> {
|
||||
/**
|
||||
* the collection that is used, defaults to mongodb collection,
|
||||
* can be nedb datastore (sub api of mongodb)
|
||||
*/
|
||||
collection: plugins.mongodb.Collection;
|
||||
name: string;
|
||||
db: Db;
|
||||
objectValidation: IDocValidation<T>;
|
||||
constructor(nameArg: string, dbArg: Db);
|
||||
/**
|
||||
* adds a validation function that all newly inserted and updated objects have to pass
|
||||
*/
|
||||
addDocValidation(funcArg: IDocValidation<T>): void;
|
||||
/**
|
||||
* finds an object in the DbCollection
|
||||
*/
|
||||
find(docMatchArg: T | any, optionsArg?: IFindOptions): plugins.q.Promise<T[]>;
|
||||
/**
|
||||
* inserts object into the DbCollection
|
||||
*/
|
||||
insertOne(docArg: T): plugins.q.Promise<void>;
|
||||
/**
|
||||
* inserts many objects at once into the DbCollection
|
||||
*/
|
||||
insertMany(docArrayArg: T[]): plugins.q.Promise<void>;
|
||||
/**
|
||||
* checks a Doc for constraints
|
||||
*/
|
||||
private checkDoc(docArg);
|
||||
}
|
128
dist/smartdata.classes.dbcollection.js
vendored
Normal file
128
dist/smartdata.classes.dbcollection.js
vendored
Normal file
File diff suppressed because one or more lines are too long
34
dist/smartdata.classes.dbdoc.d.ts
vendored
Normal file
34
dist/smartdata.classes.dbdoc.d.ts
vendored
Normal file
@ -0,0 +1,34 @@
|
||||
import { DbCollection } from './smartdata.classes.dbcollection';
|
||||
export declare type TDocCreation = 'db' | 'data' | 'mixed';
|
||||
/**
|
||||
* sva - saveable decorator to be used on class properties
|
||||
*/
|
||||
export declare function saveable(target: DbDoc<any>, key: string): void;
|
||||
export declare class DbDoc<T> {
|
||||
/**
|
||||
* the collection object an Doc belongs to
|
||||
*/
|
||||
collection: DbCollection<T>;
|
||||
/**
|
||||
* how the Doc in memory was created, may prove useful later.
|
||||
*/
|
||||
creationType: TDocCreation;
|
||||
/**
|
||||
* an array of saveable properties of a doc
|
||||
*/
|
||||
saveableProperties: string[];
|
||||
/**
|
||||
* class constructor
|
||||
*/
|
||||
constructor();
|
||||
/**
|
||||
* saves this instance but not any connected items
|
||||
* may lead to data inconsistencies, but is faster
|
||||
*/
|
||||
save(): void;
|
||||
/**
|
||||
* also store any referenced objects to DB
|
||||
* better for data consistency
|
||||
*/
|
||||
saveDeep(): void;
|
||||
}
|
39
dist/smartdata.classes.dbdoc.js
vendored
Normal file
39
dist/smartdata.classes.dbdoc.js
vendored
Normal file
@ -0,0 +1,39 @@
|
||||
"use strict";
|
||||
/**
|
||||
* sva - saveable decorator to be used on class properties
|
||||
*/
|
||||
function saveable(target, key) {
|
||||
console.log('called sva');
|
||||
if (!target.saveableProperties) {
|
||||
target.saveableProperties = [];
|
||||
}
|
||||
target.saveableProperties.push(key);
|
||||
}
|
||||
exports.saveable = saveable;
|
||||
class DbDoc {
|
||||
/**
|
||||
* class constructor
|
||||
*/
|
||||
constructor() {
|
||||
this.collection = this.constructor['dbCollection'];
|
||||
}
|
||||
/**
|
||||
* saves this instance but not any connected items
|
||||
* may lead to data inconsistencies, but is faster
|
||||
*/
|
||||
save() {
|
||||
let saveableObject = {};
|
||||
for (let propertyNameString of this.saveableProperties) {
|
||||
saveableObject[propertyNameString] = this[propertyNameString];
|
||||
}
|
||||
}
|
||||
/**
|
||||
* also store any referenced objects to DB
|
||||
* better for data consistency
|
||||
*/
|
||||
saveDeep() {
|
||||
this.save();
|
||||
}
|
||||
}
|
||||
exports.DbDoc = DbDoc;
|
||||
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnRkYXRhLmNsYXNzZXMuZGJkb2MuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9zbWFydGRhdGEuY2xhc3Nlcy5kYmRvYy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBT0E7O0dBRUc7QUFDSCxrQkFBeUIsTUFBa0IsRUFBRSxHQUFXO0lBQ3BELE9BQU8sQ0FBQyxHQUFHLENBQUMsWUFBWSxDQUFDLENBQUE7SUFDekIsRUFBRSxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsa0JBQWtCLENBQUMsQ0FBQyxDQUFDO1FBQUMsTUFBTSxDQUFDLGtCQUFrQixHQUFHLEVBQUUsQ0FBQTtJQUFDLENBQUM7SUFDbEUsTUFBTSxDQUFDLGtCQUFrQixDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQTtBQUN2QyxDQUFDO0FBSkQsNEJBSUM7QUFFRDtJQWlCSTs7T0FFRztJQUNIO1FBQ0ksSUFBSSxDQUFDLFVBQVUsR0FBRyxJQUFJLENBQUMsV0FBVyxDQUFDLGNBQWMsQ0FBQyxDQUFBO0lBQ3RELENBQUM7SUFFRDs7O09BR0c7SUFDSCxJQUFJO1FBQ0EsSUFBSSxjQUFjLEdBQUcsRUFBRSxDQUFBO1FBQ3ZCLEdBQUcsQ0FBQyxDQUFDLElBQUksa0JBQWtCLElBQUksSUFBSSxDQUFDLGtCQUFrQixDQUFDLENBQUMsQ0FBQztZQUNyRCxjQUFjLENBQUMsa0JBQWtCLENBQUMsR0FBRyxJQUFJLENBQUMsa0JBQWtCLENBQUMsQ0FBQTtRQUNqRSxDQUFDO0lBQ0wsQ0FBQztJQUVEOzs7T0FHRztJQUNILFFBQVE7UUFDSixJQUFJLENBQUMsSUFBSSxFQUFFLENBQUE7SUFDZixDQUFDO0NBQ0o7QUExQ0Qsc0JBMENDIn0=
|
11
dist/smartdata.plugins.d.ts
vendored
11
dist/smartdata.plugins.d.ts
vendored
@ -1,5 +1,8 @@
|
||||
import 'typings-global';
|
||||
export import assert = require('assert');
|
||||
export import beautylog = require('beautylog');
|
||||
export import mongodb = require('mongodb');
|
||||
export import q = require('q');
|
||||
import * as assert from 'assert';
|
||||
import * as beautylog from 'beautylog';
|
||||
import * as lodash from 'lodash';
|
||||
import * as mongodb from 'mongodb';
|
||||
import * as q from 'q';
|
||||
declare let nedb: any;
|
||||
export { assert, beautylog, lodash, mongodb, q, nedb };
|
||||
|
20
dist/smartdata.plugins.js
vendored
20
dist/smartdata.plugins.js
vendored
@ -1,7 +1,15 @@
|
||||
"use strict";
|
||||
require('typings-global');
|
||||
exports.assert = require('assert');
|
||||
exports.beautylog = require('beautylog');
|
||||
exports.mongodb = require('mongodb');
|
||||
exports.q = require('q');
|
||||
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnRkYXRhLnBsdWdpbnMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9zbWFydGRhdGEucGx1Z2lucy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUEsUUFBTyxnQkFDUCxDQUFDLENBRHNCO0FBQ1QsY0FBTSxXQUFXLFFBQVEsQ0FBQyxDQUFBO0FBQzFCLGlCQUFTLFdBQVcsV0FBVyxDQUFDLENBQUE7QUFDaEMsZUFBTyxXQUFXLFNBQVMsQ0FBQyxDQUFBO0FBQzVCLFNBQUMsV0FBVyxHQUFHLENBQUMsQ0FBQSJ9
|
||||
require("typings-global");
|
||||
const assert = require("assert");
|
||||
exports.assert = assert;
|
||||
const beautylog = require("beautylog");
|
||||
exports.beautylog = beautylog;
|
||||
const lodash = require("lodash");
|
||||
exports.lodash = lodash;
|
||||
const mongodb = require("mongodb");
|
||||
exports.mongodb = mongodb;
|
||||
const q = require("q");
|
||||
exports.q = q;
|
||||
let nedb = require('nedb');
|
||||
exports.nedb = nedb;
|
||||
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21hcnRkYXRhLnBsdWdpbnMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9zbWFydGRhdGEucGx1Z2lucy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUEsMEJBQXVCO0FBQ3ZCLGlDQUFnQztBQVE1Qix3QkFBTTtBQVBWLHVDQUFzQztBQVFsQyw4QkFBUztBQVBiLGlDQUFnQztBQVE1Qix3QkFBTTtBQVBWLG1DQUFrQztBQVE5QiwwQkFBTztBQVBYLHVCQUFzQjtBQVFsQixjQUFDO0FBUEwsSUFBSSxJQUFJLEdBQUcsT0FBTyxDQUFDLE1BQU0sQ0FBQyxDQUFBO0FBUXRCLG9CQUFJIn0=
|
19
docs/index.md
Normal file
19
docs/index.md
Normal file
@ -0,0 +1,19 @@
|
||||
# smartdata
|
||||
|
||||
smartdata is a ODM that adheres to TypeScript practices and uses classes to organize data.
|
||||
It uses MongoDB as persistent storage.
|
||||
|
||||
## Intention
|
||||
There are many ODMs out there, however when we searched for a ODM that uses TypeScript,
|
||||
acts smart while still embracing an easy the NoSQL idea we didn't find a matching solution.
|
||||
This is why we started smartdata
|
||||
|
||||
How MongoDB terms map to smartdata classes
|
||||
|
||||
MongoDB term | smartdata class
|
||||
--- | ---
|
||||
Database | smartdata.DbConnection
|
||||
Collection | smartdata.DbCollection
|
||||
Document | smartdata.DbDoc
|
||||
|
||||
[](https://push.rocks)
|
28
package.json
28
package.json
@ -1,11 +1,12 @@
|
||||
{
|
||||
"name": "smartdata",
|
||||
"version": "1.0.1",
|
||||
"version": "1.0.19",
|
||||
"description": "do more with data",
|
||||
"main": "dist/index.js",
|
||||
"typings": "dist/index.d.ts",
|
||||
"scripts": {
|
||||
"test": "(npmts)"
|
||||
"test": "(npm run prepareMongo && npmts)",
|
||||
"prepareMongo": "(rm -rf ./test/data && mkdir ./test/data/)"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@ -18,18 +19,25 @@
|
||||
},
|
||||
"homepage": "https://gitlab.com/pushrocks/smartdata#README",
|
||||
"dependencies": {
|
||||
"@types/mongodb": "^2.1.32",
|
||||
"@types/q": "0.0.30",
|
||||
"beautylog": "^5.0.23",
|
||||
"mongodb": "^2.2.9",
|
||||
"@types/lodash": "^4.14.39",
|
||||
"@types/mongodb": "^2.1.34",
|
||||
"@types/nedb": "0.0.31",
|
||||
"@types/q": "0.0.32",
|
||||
"beautylog": "^6.0.0",
|
||||
"lik": "^1.0.24",
|
||||
"lodash": "^4.17.2",
|
||||
"mongodb": "^2.2.11",
|
||||
"nedb": "^1.8.0",
|
||||
"q": "^1.4.1",
|
||||
"runtime-type-checks": "0.0.4",
|
||||
"typings-global": "^1.0.14"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/shelljs": "^0.3.30",
|
||||
"@types/should": "^8.1.29",
|
||||
"shelljs": "^0.7.4",
|
||||
"should": "^11.1.0",
|
||||
"@types/shelljs": "^0.3.32",
|
||||
"@types/should": "^8.1.30",
|
||||
"shelljs": "^0.7.5",
|
||||
"should": "^11.1.1",
|
||||
"smartstring": "^2.0.22",
|
||||
"typings-test": "^1.0.3"
|
||||
}
|
||||
}
|
||||
|
121
test/test.js
121
test/test.js
File diff suppressed because one or more lines are too long
136
test/test.ts
136
test/test.ts
@ -1,35 +1,133 @@
|
||||
import 'typings-test'
|
||||
|
||||
import * as shelljs from 'shelljs'
|
||||
import * as should from 'should'
|
||||
import * as smartstring from 'smartstring'
|
||||
|
||||
// the tested module
|
||||
import * as smartdata from '../dist/index'
|
||||
|
||||
|
||||
let mongoChildProcess
|
||||
let testDbConnection: smartdata.DbConnection
|
||||
let testDb: smartdata.Db
|
||||
|
||||
interface ITestObject1 {
|
||||
value1: string
|
||||
value2?: number
|
||||
value3?: string
|
||||
}
|
||||
|
||||
describe('mongodb',function(){
|
||||
it('should start mongodb',function(done){
|
||||
mongoChildProcess = shelljs.exec('mongod --dbpath=./test/data --port 27017',{async: true})
|
||||
setTimeout(() => { done() }, 1500)
|
||||
})
|
||||
})
|
||||
describe('smartdata',function(){
|
||||
it('should establish a connection to mongodb',function(done){
|
||||
testDbConnection = new smartdata.DbConnection('mongodb://localhost:27017/smartdata')
|
||||
testDbConnection.connect().then(() => { done() })
|
||||
})
|
||||
it('should create a collection',function(){
|
||||
let testDbCollection: smartdata.DbCollection<ITestObject1>
|
||||
|
||||
})
|
||||
it('should close the db Connection',function(){
|
||||
testDbConnection.close()
|
||||
describe('mongodb', function () {
|
||||
it('should start mongodb', function (done) {
|
||||
this.timeout(30000)
|
||||
mongoChildProcess = shelljs.exec('mongod --dbpath=./test/data --port 27017', { async: true, silent: true })
|
||||
let doneCalled = false
|
||||
mongoChildProcess.stdout.on('data', function (data) {
|
||||
console.log(smartstring.indent.indentWithPrefix(data, '*** MongoDB Process *** : '))
|
||||
if (!doneCalled) {
|
||||
if (/waiting for connections on port 27017/.test(data)) {
|
||||
doneCalled = true
|
||||
done()
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('mongodb',function(){
|
||||
it('should kill mongodb',function(){
|
||||
describe('smartdata', function () {
|
||||
it('should establish a connection to mongodb', function (done) {
|
||||
testDb = new smartdata.Db('mongodb://localhost:27017/smartdata')
|
||||
testDb.connect().then(() => { done() })
|
||||
})
|
||||
it('should create a collection', function () {
|
||||
testDbCollection = new smartdata.DbCollection<ITestObject1>('something', testDb)
|
||||
})
|
||||
it('should insert a doc into the collection', function (done) {
|
||||
testDbCollection.insertOne({ value1: 'test' }).then(() => { done() })
|
||||
})
|
||||
it('should find all docs of testDbCollection', function (done) {
|
||||
testDbCollection.find({}).then((resultArray) => {
|
||||
console.log(resultArray)
|
||||
should(resultArray[0].value1).equal('test')
|
||||
done()
|
||||
})
|
||||
})
|
||||
it('should insert many docs into the collection', function (done) {
|
||||
testDbCollection.insertMany([
|
||||
{ value1: 'test2' },
|
||||
{ value1: 'test', value2: 3, value3: 'hi' }
|
||||
]).then(() => { done() })
|
||||
})
|
||||
it('should find a specified doc', function (done) {
|
||||
testDbCollection.find({ 'value3': { '$exists': true } }).then((resultArray) => {
|
||||
console.log(resultArray)
|
||||
should(resultArray[0].value3).equal('hi')
|
||||
done()
|
||||
}).catch(console.log)
|
||||
})
|
||||
it('should close the db Connection', function () {
|
||||
testDb.close()
|
||||
})
|
||||
it('should create an extended class', function () {
|
||||
@smartdata.Collection(testDb)
|
||||
class TestCar extends smartdata.DbDoc<TestCar> {
|
||||
@smartdata.saveable
|
||||
color: string
|
||||
constructor(optionsArg: {
|
||||
color: string,
|
||||
property2: number
|
||||
}) {
|
||||
super()
|
||||
this.color = optionsArg.color
|
||||
}
|
||||
};
|
||||
let testCarInstance = new TestCar({
|
||||
color: 'red',
|
||||
property2: 2
|
||||
})
|
||||
|
||||
should(testCarInstance.saveableProperties[0]).equal('color')
|
||||
console.log(TestCar)
|
||||
should(testCarInstance.collection).be.instanceof(smartdata.DbCollection)
|
||||
should(testCarInstance).be.instanceof(smartdata.DbDoc)
|
||||
testCarInstance.save()
|
||||
it('should get a collection for testCar', function () {
|
||||
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('mongodb', function () {
|
||||
it('should kill mongodb', function (done) {
|
||||
this.timeout(30000)
|
||||
mongoChildProcess.stdout.on('data', function (data) {
|
||||
if (/dbexit: rc: 0/.test(data)) {
|
||||
done()
|
||||
}
|
||||
})
|
||||
shelljs.exec('mongod --dbpath=./test/data --shutdown')
|
||||
mongoChildProcess.kill('SIGTERM')
|
||||
})
|
||||
})
|
||||
|
||||
describe('smartdata with nedb', function () {
|
||||
let testDb: smartdata.Db
|
||||
let testCollection: smartdata.DbCollection<ITestObject1>
|
||||
it('should create a DB with nedb', function () {
|
||||
testDb = new smartdata.Db('any', 'nedb')
|
||||
testDb.connect()
|
||||
testCollection = new smartdata.DbCollection<ITestObject1>('anyName', testDb)
|
||||
})
|
||||
|
||||
it('should insert a doc', function(done){
|
||||
testCollection.insertOne({ value1: 'hi' }).then(() => {done()})
|
||||
})
|
||||
|
||||
it('should find the inserted document', function(done){
|
||||
testCollection.find({ value1: 'hi' }).then(x => {
|
||||
console.log(x)
|
||||
done()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
40
ts/index.ts
40
ts/index.ts
@ -1,39 +1,5 @@
|
||||
import * as plugins from './smartdata.plugins'
|
||||
|
||||
export class DbCollection<T> {
|
||||
constructor(nameArg: string, db: plugins.mongodb.Db) {
|
||||
let collection = db.collection(nameArg)
|
||||
}
|
||||
}
|
||||
|
||||
export type TDbConnectionStatus = 'disconnected' | 'connected' | 'failed'
|
||||
|
||||
export class DbConnection {
|
||||
dbUrl: string
|
||||
db: plugins.mongodb.Db
|
||||
status: TDbConnectionStatus
|
||||
|
||||
constructor(dbUrl: string) {
|
||||
this.dbUrl = dbUrl
|
||||
}
|
||||
|
||||
connect(): plugins.q.Promise<any> {
|
||||
let done = plugins.q.defer()
|
||||
plugins.mongodb.MongoClient.connect(this.dbUrl, (err, db) => {
|
||||
if (err) { console.log(err) }
|
||||
plugins.assert.equal(null, err)
|
||||
this.db = db
|
||||
plugins.beautylog.success(`connected to database at ${this.dbUrl}`)
|
||||
done.resolve(this.db)
|
||||
})
|
||||
return done.promise
|
||||
}
|
||||
|
||||
close(): plugins.q.Promise<any> {
|
||||
let done = plugins.q.defer()
|
||||
this.db.close()
|
||||
plugins.beautylog.ok(`disconnected to database at ${this.dbUrl}`)
|
||||
done.resolve()
|
||||
return done.promise
|
||||
}
|
||||
}
|
||||
export * from './smartdata.classes.db'
|
||||
export * from './smartdata.classes.dbcollection'
|
||||
export * from './smartdata.classes.dbdoc'
|
||||
|
82
ts/smartdata.classes.db.ts
Normal file
82
ts/smartdata.classes.db.ts
Normal file
@ -0,0 +1,82 @@
|
||||
import * as plugins from './smartdata.plugins'
|
||||
import { Objectmap } from 'lik'
|
||||
|
||||
import { DbCollection } from './smartdata.classes.dbcollection'
|
||||
|
||||
/**
|
||||
* interface - indicates the database type
|
||||
*/
|
||||
export type TDbType = 'mongodb' | 'nedb'
|
||||
|
||||
/**
|
||||
* interface - indicates the connection status of the db
|
||||
*/
|
||||
export type TConnectionStatus = 'disconnected' | 'connected' | 'failed'
|
||||
|
||||
export class Db {
|
||||
dbType: TDbType
|
||||
dbUrl: string
|
||||
db: plugins.mongodb.Db
|
||||
status: TConnectionStatus
|
||||
collections = new Objectmap<DbCollection<any>>()
|
||||
|
||||
constructor(dbUrlArg: string, dbTypeArg: TDbType = 'mongodb') {
|
||||
this.dbType = dbTypeArg
|
||||
this.dbUrl = dbUrlArg
|
||||
}
|
||||
|
||||
// basic connection stuff ----------------------------------------------
|
||||
|
||||
/**
|
||||
* connects to the database that was specified during instance creation
|
||||
*/
|
||||
connect(): plugins.q.Promise<any> {
|
||||
let done = plugins.q.defer()
|
||||
if (this.dbType === 'mongodb') {
|
||||
plugins.mongodb.MongoClient.connect(this.dbUrl, (err, db) => {
|
||||
if (err) { console.log(err) }
|
||||
plugins.assert.equal(null, err)
|
||||
this.db = db
|
||||
plugins.beautylog.success(`connected to database at ${this.dbUrl}`)
|
||||
done.resolve(this.db)
|
||||
})
|
||||
} else if (this.dbType === 'nedb') {
|
||||
this.db = null
|
||||
}
|
||||
return done.promise
|
||||
}
|
||||
|
||||
/**
|
||||
* closes the connection to the databse
|
||||
*/
|
||||
close(): plugins.q.Promise<any> {
|
||||
let done = plugins.q.defer()
|
||||
if (this.dbType === 'mongodb') {
|
||||
this.db.close()
|
||||
}
|
||||
plugins.beautylog.ok(`disconnected to database at ${this.dbUrl}`)
|
||||
done.resolve()
|
||||
return done.promise
|
||||
}
|
||||
|
||||
// advanced communication with the database --------------------------------
|
||||
|
||||
/**
|
||||
* gets a collection by name: string
|
||||
*/
|
||||
getCollectionByName<T>(nameArg: string): plugins.q.Promise<DbCollection<T>> {
|
||||
let done = plugins.q.defer<DbCollection<any>>()
|
||||
let resultCollection = this.collections.find((dbCollectionArg) => {
|
||||
return dbCollectionArg.name === nameArg
|
||||
})
|
||||
if (resultCollection !== null) {
|
||||
done.resolve(resultCollection)
|
||||
}
|
||||
return done.promise
|
||||
};
|
||||
|
||||
addCollection(dbCollectionArg: DbCollection<any>) {
|
||||
this.collections.add(dbCollectionArg)
|
||||
}
|
||||
|
||||
}
|
144
ts/smartdata.classes.dbcollection.ts
Normal file
144
ts/smartdata.classes.dbcollection.ts
Normal file
@ -0,0 +1,144 @@
|
||||
import * as plugins from './smartdata.plugins'
|
||||
import { Db } from './smartdata.classes.db'
|
||||
|
||||
export interface IFindOptions {
|
||||
limit?: number
|
||||
}
|
||||
|
||||
export interface IDocValidation<T> {
|
||||
(doc: T): boolean
|
||||
}
|
||||
|
||||
export function Collection(db: Db) {
|
||||
return function (constructor) {
|
||||
constructor['dbCollection'] = new DbCollection(constructor.name, db)
|
||||
}
|
||||
}
|
||||
|
||||
export class DbCollection<T> {
|
||||
/**
|
||||
* the collection that is used, defaults to mongodb collection,
|
||||
* can be nedb datastore (sub api of mongodb)
|
||||
*/
|
||||
collection: plugins.mongodb.Collection
|
||||
name: string
|
||||
db: Db
|
||||
objectValidation: IDocValidation<T> = null
|
||||
|
||||
|
||||
constructor(nameArg: string, dbArg: Db) {
|
||||
this.name = nameArg
|
||||
this.db = dbArg
|
||||
if (this.db.dbType === 'mongodb') {
|
||||
this.collection = dbArg.db.collection(nameArg)
|
||||
} else {
|
||||
this.collection = new plugins.nedb()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* adds a validation function that all newly inserted and updated objects have to pass
|
||||
*/
|
||||
addDocValidation(funcArg: IDocValidation<T>) {
|
||||
this.objectValidation = funcArg
|
||||
}
|
||||
|
||||
/**
|
||||
* finds an object in the DbCollection
|
||||
*/
|
||||
find(docMatchArg: T | any, optionsArg?: IFindOptions): plugins.q.Promise<T[]> {
|
||||
let done = plugins.q.defer<T[]>()
|
||||
if (this.db.dbType === 'mongodb') {
|
||||
let findCursor = this.collection.find(docMatchArg)
|
||||
if (optionsArg) {
|
||||
if (optionsArg.limit) { findCursor = findCursor.limit(1) }
|
||||
}
|
||||
findCursor.toArray((err, docs) => {
|
||||
if (err) {
|
||||
done.reject(err)
|
||||
throw err
|
||||
}
|
||||
done.resolve(docs)
|
||||
})
|
||||
} else if (this.db.dbType === 'nedb') {
|
||||
this.collection.find(docMatchArg, (err, docs) => {
|
||||
if (err) {
|
||||
done.reject(err)
|
||||
throw err
|
||||
}
|
||||
done.resolve(docs)
|
||||
})
|
||||
}
|
||||
return done.promise
|
||||
}
|
||||
|
||||
/**
|
||||
* inserts object into the DbCollection
|
||||
*/
|
||||
insertOne(docArg: T): plugins.q.Promise<void> {
|
||||
let done = plugins.q.defer<void>()
|
||||
this.checkDoc(docArg).then(
|
||||
() => {
|
||||
if (this.db.dbType === 'mongodb') {
|
||||
this.collection.insertOne(docArg)
|
||||
.then(() => { done.resolve() })
|
||||
} else if (this.db.dbType === 'nedb') {
|
||||
this.collection.insert(docArg, (err, newDoc) => {
|
||||
if (err) {
|
||||
done.reject(err)
|
||||
throw err
|
||||
}
|
||||
done.resolve()
|
||||
})
|
||||
}
|
||||
},
|
||||
() => {
|
||||
done.reject(new Error('one the docs did not pass validation'))
|
||||
})
|
||||
return done.promise
|
||||
}
|
||||
|
||||
/**
|
||||
* inserts many objects at once into the DbCollection
|
||||
*/
|
||||
insertMany(docArrayArg: T[]): plugins.q.Promise<void> {
|
||||
let done = plugins.q.defer<void>()
|
||||
let checkDocPromiseArray: plugins.q.Promise<void>[] = []
|
||||
for (let docArg of docArrayArg) {
|
||||
checkDocPromiseArray.push(this.checkDoc(docArg))
|
||||
}
|
||||
plugins.q.all(checkDocPromiseArray).then(() => {
|
||||
if (this.db.dbType === 'mongodb') {
|
||||
this.collection.insertMany(docArrayArg)
|
||||
.then(() => { done.resolve() })
|
||||
} else if (this.db.dbType === 'nedb') {
|
||||
let paramArray = plugins.lodash.concat<any>(docArrayArg, (err, newDoc) => {
|
||||
if (err) {
|
||||
done.reject(err)
|
||||
throw err
|
||||
}
|
||||
done.resolve()
|
||||
})
|
||||
this.collection.insert.apply(null, paramArray)
|
||||
}
|
||||
})
|
||||
return done.promise
|
||||
}
|
||||
|
||||
/**
|
||||
* checks a Doc for constraints
|
||||
*/
|
||||
private checkDoc(docArg: T): plugins.q.Promise<void> {
|
||||
let done = plugins.q.defer<void>()
|
||||
let validationResult = true
|
||||
if (this.objectValidation) {
|
||||
validationResult = this.objectValidation(docArg)
|
||||
}
|
||||
if (validationResult) {
|
||||
done.resolve()
|
||||
} else {
|
||||
done.reject('validation of object did not pass')
|
||||
}
|
||||
return done.promise
|
||||
}
|
||||
}
|
59
ts/smartdata.classes.dbdoc.ts
Normal file
59
ts/smartdata.classes.dbdoc.ts
Normal file
@ -0,0 +1,59 @@
|
||||
import * as plugins from './smartdata.plugins'
|
||||
|
||||
import { Db } from './smartdata.classes.db'
|
||||
import { DbCollection } from './smartdata.classes.dbcollection'
|
||||
|
||||
export type TDocCreation = 'db' | 'data' | 'mixed'
|
||||
|
||||
/**
|
||||
* sva - saveable decorator to be used on class properties
|
||||
*/
|
||||
export function saveable(target: DbDoc<any>, key: string) {
|
||||
console.log('called sva')
|
||||
if (!target.saveableProperties) { target.saveableProperties = [] }
|
||||
target.saveableProperties.push(key)
|
||||
}
|
||||
|
||||
export class DbDoc<T> {
|
||||
|
||||
/**
|
||||
* the collection object an Doc belongs to
|
||||
*/
|
||||
collection: DbCollection<T>
|
||||
|
||||
/**
|
||||
* how the Doc in memory was created, may prove useful later.
|
||||
*/
|
||||
creationType: TDocCreation
|
||||
|
||||
/**
|
||||
* an array of saveable properties of a doc
|
||||
*/
|
||||
saveableProperties: string[]
|
||||
|
||||
/**
|
||||
* class constructor
|
||||
*/
|
||||
constructor() {
|
||||
this.collection = this.constructor['dbCollection']
|
||||
}
|
||||
|
||||
/**
|
||||
* saves this instance but not any connected items
|
||||
* may lead to data inconsistencies, but is faster
|
||||
*/
|
||||
save() {
|
||||
let saveableObject = {}
|
||||
for (let propertyNameString of this.saveableProperties) {
|
||||
saveableObject[propertyNameString] = this[propertyNameString]
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* also store any referenced objects to DB
|
||||
* better for data consistency
|
||||
*/
|
||||
saveDeep() {
|
||||
this.save()
|
||||
}
|
||||
}
|
@ -1,5 +1,16 @@
|
||||
import 'typings-global'
|
||||
export import assert = require('assert')
|
||||
export import beautylog = require('beautylog')
|
||||
export import mongodb = require('mongodb')
|
||||
export import q = require('q')
|
||||
import * as assert from 'assert'
|
||||
import * as beautylog from 'beautylog'
|
||||
import * as lodash from 'lodash'
|
||||
import * as mongodb from 'mongodb'
|
||||
import * as q from 'q'
|
||||
let nedb = require('nedb')
|
||||
|
||||
export {
|
||||
assert,
|
||||
beautylog,
|
||||
lodash,
|
||||
mongodb,
|
||||
q,
|
||||
nedb
|
||||
}
|
||||
|
5
tsconfig.json
Normal file
5
tsconfig.json
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"experimentalDecorators": true
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user