blow-data
Version:
Data access layer for Blow.
187 lines (186 loc) • 6.2 kB
JavaScript
'use strict';
const util_1 = require('util');
const rxjs_1 = require('rxjs');
const mongodb = require('mongodb');
const blow_query_1 = require('blow-query');
const Adapter_1 = require('./Adapter');
const DEFAULT_ID_PROPERTY_NAME = '_id';
const DEFAULT_ID_PROPERTY_TYPE = 'string';
function connect(url) {
return rxjs_1.Observable.create(observer => {
mongodb.MongoClient.connect(url, (err, db) => {
if (err) {
observer.error(err);
}
else {
observer.next(db);
}
});
});
}
class MongoDBAdapter extends Adapter_1.Adapter {
get idPropertyName() {
return DEFAULT_ID_PROPERTY_NAME;
}
get idPropertyType() {
return DEFAULT_ID_PROPERTY_TYPE;
}
_connect() {
return connect(MongoDBAdapter.getConnectionUrl(this._options))
.map(db => {
this._db = db;
return this;
});
}
_collection(metadata) {
return this._db.collection(metadata.pluralName);
}
_prepareQuery(query) {
if (query) {
if (query instanceof blow_query_1.Query) {
query = query.toJSON();
}
}
return query;
}
count(metadata, where) {
return rxjs_1.Observable.from(this._collection(metadata).count(where));
}
create(metadata, data) {
return rxjs_1.Observable.from(this._collection(metadata).insertOne(MongoDBAdapter.toDB(metadata, data)))
.map(result => MongoDBAdapter.fromDB(metadata, result['ops'][0]));
}
destroy(metadata, where) {
return rxjs_1.Observable.from(this._collection(metadata).deleteMany(where))
.map(result => result['deletedCount']);
}
destroyById(metadata, id) {
return this.destroy(metadata, MongoDBAdapter.buildWhereWithId(metadata, id)).map(count => !!count);
}
exists(metadata, id) {
return this.findById(metadata, id).map(row => !!row);
}
find(metadata, query) {
const q = this._prepareQuery(query);
let exec = this._collection(metadata).find(q.where);
if (q.limit) {
exec = exec.limit(q.limit);
}
if (q.skip) {
exec = exec.skip(q.skip);
}
if (q.sort) {
exec = exec.sort(q.sort);
}
return rxjs_1.Observable.from(exec.toArray())
.mergeMap(rows => rxjs_1.Observable.from(rows))
.map(row => MongoDBAdapter.fromDB(metadata, row));
}
findOne(metadata, query) {
query = this._prepareQuery(query);
query['limit'] = 1;
return this.find(metadata, query);
}
findById(metadata, id) {
const where = MongoDBAdapter.buildWhereWithId(metadata, id);
return this.find(metadata, { where: where, limit: 1 });
}
findOrCreate(metadata, where, data) {
return rxjs_1.Observable.create(observer => {
const emit = row => {
observer.next(row);
observer.complete();
};
this.findOne(metadata, { where: where })
.subscribe(emit, err => observer.error(err), () => {
this.create(metadata, MongoDBAdapter.toDB(metadata, data))
.subscribe(emit);
});
});
}
update(metadata, where, data) {
return rxjs_1.Observable.from(this._collection(metadata).updateMany(where, { $set: data }))
.map(result => result['modifiedCount']);
}
updateOrCreate(metadata, data) {
const idName = metadata.idProperty.name;
if (data[idName]) {
return this.exists(metadata, data[idName]).mergeMap(exists => {
if (exists) {
return this.update(metadata, { _id: data[idName] }, data).mapTo(data);
}
else {
return this.create(metadata, data);
}
});
}
else {
return this.create(metadata, data);
}
}
static toDB(metadata, data) {
const idName = metadata.idProperty.name;
const idValue = data[idName];
if (util_1.isNull(idValue)) {
delete data[idName];
}
else {
data[DEFAULT_ID_PROPERTY_NAME] = this.buildId(idValue);
if (idName !== DEFAULT_ID_PROPERTY_NAME) {
delete data[idName];
}
}
return data;
}
static fromDB(metadata, data) {
const idName = metadata.idProperty.name;
if (!data) {
return null;
}
if (data[DEFAULT_ID_PROPERTY_NAME]) {
data[idName] = data[DEFAULT_ID_PROPERTY_NAME].toHexString();
if (idName !== DEFAULT_ID_PROPERTY_NAME) {
delete data[DEFAULT_ID_PROPERTY_NAME];
}
}
return data;
}
static buildWhereWithId(metadata, id) {
const idKey = metadata.idProperty.name;
const where = {};
where[idKey] = id;
return this.buildWhere(metadata, where);
}
static buildWhere(metadata, where) {
where = where || {};
const idKey = metadata.idProperty.name;
return Object.keys(where).reduce((w, k) => {
if (k === idKey) {
w[DEFAULT_ID_PROPERTY_NAME] = this.buildId(where[k]);
if (idKey !== DEFAULT_ID_PROPERTY_NAME) {
delete w[idKey];
}
}
else {
w[k] = where[k];
}
return w;
}, {});
}
static buildId(id) {
if (id instanceof mongodb.ObjectID) {
return id;
}
return new mongodb.ObjectID(id);
}
static getConnectionUrl(options) {
if (!util_1.isUndefined(options.url)) {
return options.url;
}
else {
const auth = (options.user && options.password) ? [options.user, options.password].join(':') : '';
return 'mongodb://' + (auth ? auth + '@' : '') + options.host + ':' + options.port + '/' + options.dbname;
}
}
}
exports.MongoDBAdapter = MongoDBAdapter;