UNPKG

blow-data-service

Version:

Observable data service for Blow.

204 lines (168 loc) 5.28 kB
'use strict'; import {Query} from 'blow-query'; import {Observable} from 'rxjs'; import * as mongodb from 'mongodb'; import {DataConnector} from './DataConnector'; import {Entity} from '../Entity'; export interface ConnectOptions { uriDecodeAuth: boolean; db: Object; server: Object; replSet: Object; mongos: Object; } export class MongoClient { static connect(url: string, options?: ConnectOptions): Observable<Db> { return Observable.from<mongodb.Db>(mongodb.MongoClient.connect(url, options)) .map(db => new Db(db)); } } export class Db { protected _db: mongodb.Db; constructor(db: mongodb.Db) { this._db = db; } collection<T>(name: string): Collection<T> { return new Collection(this._db.collection(name)); } delete() { return Observable.from(this._db.dropDatabase()) .mergeMap(() => this.close()); } close(): Observable<boolean> { return Observable.from(this._db.close()); } } export class Collection<T> { protected _collection: mongodb.Collection; constructor(collection: mongodb.Collection) { this._collection = collection; } find(query?): Observable<T> { query = Object.assign({}, { where: {} }, query || {}); let cursor = this._collection.find(query.where); Object.keys(query).forEach(key => { if (key !== 'where') { cursor = cursor[key](query[key]); } }); return Observable.create(subscriber => { cursor.forEach(document => { subscriber.next(document); }, error => { if (error) { subscriber.error(error); } subscriber.complete(); }); }); } count(query?): Observable<number> { query = query || {}; return Observable.from(this._collection.count(query)); } delete(query?): Observable<number> { query = query || {}; return Observable.from(this._collection.deleteMany(query)); } insert(doc): Observable<T> { return Observable.from(this._collection.insertOne(doc)) .map(response => response['ops'][0]); } update(query, doc, options?): Observable<T> { return Observable.from(this._collection.updateOne(query, { $set: doc }, options)) .map(response => { if (response['modifiedCount']) { doc._id = query._id.toString(); return doc; } else { return null; } }); } } export class MongoDBConnector extends DataConnector { protected _db: Db; protected _buildQueryWhereForId(id: string) { return this._prepareQueryWhere({ _id: id }); } protected _normalizeId(value) { let id; try { id = new mongodb.ObjectID(value); } catch (e) { id = value; } return id; } protected _prepareQueryWhere(queryWhere: { [key: string]: any }): { [key: string]: any } { const where = {}; Object.keys(queryWhere).forEach(key => { let value = queryWhere[key]; if (key === '_id') { value = this._normalizeId(value); } where[key] = value; }); return where; } protected _collection<T>(collectionName: string): Collection<T> { return this._db.collection<T>(collectionName); } connect(): Observable<MongoDBConnector> { this._state.connecting(); return Observable.from<Db>(MongoClient.connect(<string>this._settings['url'])) .do(db => { this._db = db; this._state.connected(); }) .mapTo(this); } disconnect(): Observable<MongoDBConnector> { this._state.disconnecting(); return Observable.from(this._db.close()) .do(() => this._state.disconnected()) .mapTo(this); } destroyDb(): Observable<MongoDBConnector> { return this._db.delete(); } find<T>(collectionName: string, query?: Query): Observable<T> { return this._collection(collectionName) .find(this._prepareQuery(query)); } count(collectionName: string, query?: Query): Observable<number> { return this._collection(collectionName) .count(this._prepareQuery(query).where); } delete(collectionName: string, query?: Query): Observable<number> { return this._collection(collectionName) .delete(this._prepareQuery(query).where) .map(response => response['result'].n); } deleteById(collectionName: string, id: string): Observable<boolean> { return this._collection(collectionName) .delete(this._buildQueryWhereForId(id)) .map(response => response['result'].n === 1); } get<T>(collectionName: string, id: string): Observable<T> { return this._collection(collectionName) .find({ where: this._buildQueryWhereForId(id) }); } save<T>(collectionName: string, doc: Entity): Observable<T> { const hasId = Object.keys(doc).indexOf('_id') > -1 && doc['_id']; if (!hasId) { return this._collection(collectionName).insert(doc); } else { return this._collection(collectionName).update(this._buildQueryWhereForId(doc['_id']), doc, {upsert: true}); } } updateAttributes<T>(collectionName: string, id: string, attributes: Entity): Observable<T> { delete attributes['_id']; return this.get<T>(collectionName, id) .map(result => Object.assign(result, attributes)) .mergeMap(doc => this.save<T>(collectionName, doc)); } }