UNPKG

@platform/fsdb.mongo

Version:

Standard IDb abstraction over mongodb.

148 lines (147 loc) 4.94 kB
import { Subject } from 'rxjs'; import { share } from 'rxjs/operators'; import { defaultValue, keys, mongodb } from '../common'; const MongoClient = mongodb.MongoClient; export class MongoStore { constructor(args) { this._dispose$ = new Subject(); this.dispose$ = this._dispose$.pipe(share()); this.isConnected = false; const { uri } = args; this.client = new MongoClient(uri, { useNewUrlParser: true, useUnifiedTopology: true }); this._args = args; if (args.connect) { this.ensureConnected(); } } static create(args) { return new MongoStore(args); } dispose() { this.client.close(); this.isConnected = false; this._dispose$.next(); this._dispose$.complete(); } get isDisposed() { return this._dispose$.isStopped; } ensureConnected() { this.throwIfDisposed('ensureConnected'); return new Promise((resolve, reject) => { if (this.isConnected) { return resolve(); } this.client.connect(err => { if (err) { reject(err); } this.db = this.client.db(this._args.db); this.collection = this.db.collection(this._args.collection); this.isConnected = true; resolve(); }); }); } async insert(doc, options = {}) { this.throwIfDisposed('insert'); return (await this.insertMany([doc], options))[0]; } insertMany(docs, options = {}) { this.throwIfDisposed('insertMany'); return new Promise(async (resolve, reject) => { await this.ensureConnected(); if (defaultValue(options.escapeKeys, true)) { docs = keys.encodeObjectKeys(docs); } this.collection.insertMany(docs, (err, res) => { if (err) { reject(err); } else { resolve(res.ops); } }); }); } updateOne(query, update, options = {}) { this.throwIfDisposed('update'); return new Promise(async (resolve, reject) => { await this.ensureConnected(); this.collection.updateOne(query, { $set: update }, options, (err, res) => { if (err) { reject(err); } else { const upsert = res.upsertedCount > 0; const modified = upsert ? res.upsertedCount > 0 : res.modifiedCount > 0; const doc = upsert ? Object.assign(Object.assign({}, update), { _id: res.upsertedId._id.toString() }) : undefined; resolve({ modified, upsert, doc }); } }); }); } find(query) { this.throwIfDisposed('find'); return new Promise(async (resolve, reject) => { await this.ensureConnected(); try { const cursor = this.collection.find(query); const docs = []; await cursor.forEach((doc) => docs.push(doc)); resolve(docs); } catch (error) { reject(error); } }); } findOne(query) { this.throwIfDisposed('findOne'); return new Promise(async (resolve, reject) => { await this.ensureConnected(); this.collection.findOne(query, (err, res) => { if (err) { reject(err); } else { let doc = res ? Object.assign(Object.assign({}, res), { _id: res._id.toString() }) : undefined; doc = keys.decodeObjectKeys(doc); resolve(doc); } }); }); } remove(query, options = {}) { this.throwIfDisposed('remove'); return new Promise(async (resolve, reject) => { await this.ensureConnected(); const { multi } = options; const single = !Boolean(multi); try { await this.collection.remove(query, { single }); resolve({}); } catch (error) { reject(error); } }); } async drop() { await this.ensureConnected(); const exists = await this.exists(); if (exists) { await this.collection.drop(); } } async exists() { await this.ensureConnected(); const name = this._args.collection; return (await this.db.collections()).some(c => c.collectionName === name); } throwIfDisposed(action) { if (this.isDisposed) { throw new Error(`Cannot ${action} because MongoStore is disposed.`); } } }