@onesy/mongo
Version:
Utils for easier using of mongodb library.
168 lines (163 loc) • 5.7 kB
JavaScript
import _defineProperty from "@babel/runtime/helpers/defineProperty";
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
import * as mongodb from 'mongodb';
import { merge, wait } from '@onesy/utils';
import { Query } from '@onesy/models';
import OnesyLog from '@onesy/log';
import OnesySubscription from '@onesy/subscription';
export const mongoOptionsDefault = {
reconnectInterval: 5000,
maxReconnectAttempts: 10
};
export class Mongo {
get options() {
return this.options_;
}
set options(options) {
this.options_ = merge(options, mongoOptionsDefault);
}
constructor() {
let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : mongoOptionsDefault;
_defineProperty(this, "db", void 0);
_defineProperty(this, "connected", false);
_defineProperty(this, "client", void 0);
_defineProperty(this, "onesyLog", void 0);
_defineProperty(this, "options_", mongoOptionsDefault);
_defineProperty(this, "collections", void 0);
// For listening on mongo events
_defineProperty(this, "subscription", new OnesySubscription());
_defineProperty(this, "indexed", false);
_defineProperty(this, "retrying", false);
this.options = options;
this.onesyLog = new OnesyLog(_objectSpread({
arguments: {
pre: ['Mongo']
}
}, options.log_options));
}
async createIndexes() {
if (this.options.indexes?.length) {
for (const item of this.options.indexes) {
const name = item.name;
if (name && item.indexes?.length) {
for (const index of item.indexes) await this.db.collection(name).createIndex(index.keys, index.options);
}
}
}
return true;
}
get connection() {
return new Promise(async resolve => {
if (this.connected) return resolve(this.db);
let db = null;
this.retrying = true;
while (!db) {
try {
db = await this.connect();
// Create indexes
if (!this.indexed) {
await this.createIndexes();
this.indexed = true;
}
this.retrying = false;
return resolve(db);
} catch (error) {
this.onesyLog.important('get connection() error', error);
await wait(1e3);
}
}
});
}
get disconnect() {
this.connected = false;
this.db = undefined;
this.client = undefined;
return new Promise(async resolve => {
try {
if (this.client && this.client.close) {
await this.client.close();
this.onesyLog.important(`Disconnected`);
this.subscription.emit('disconnected');
}
} catch (error) {
this.onesyLog.important('get disconnect error', error);
}
resolve();
});
}
async getCollections() {
let refetch = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
if (this.collections && !refetch) return this.collections;
try {
this.collections = await this.db.listCollections().toArray();
return this.collections;
} catch (error) {
this.onesyLog.important('getCollections error', error);
throw error;
}
}
// Be very careful with this one,
// it drops the entire database,
// usually used for testing only
async reset(name) {
if (this.db && name && this.db.databaseName === name) {
await this.db.dropDatabase();
this.onesyLog.important(`Reset`);
this.subscription.emit('reset');
}
}
async connect() {
const {
uri,
name
} = this.options;
try {
const clientOptions = {
connectTimeoutMS: 10000,
socketTimeoutMS: 15000,
retryWrites: true,
retryReads: true,
serverSelectionTimeoutMS: 5000
};
this.client = await mongodb.MongoClient.connect(uri, clientOptions);
this.db = this.client.db(name);
this.connected = true;
this.onesyLog.info('Connected to MongoDB');
// event listeners
this.setupConnectionListeners();
// Get meta about existing collections
const collections = await this.getCollections(true);
// Add collections to Query model
Query.collections = collections.map(collection => collection.name);
this.subscription.emit('connected');
return this.db;
} catch (error) {
this.onesyLog.warn('Initial connection error', error);
this.subscription.emit('error', error);
return null;
}
}
setupConnectionListeners() {
if (!this.client) return;
this.client.on('close', () => {
this.disconnect;
});
this.client.on('error', error => {
this.onesyLog.warn('MongoDB connection error', error);
if (!this.retrying) this.connection;
});
this.client.on('reconnect', () => {
this.onesyLog.info('MongoDB reconnected');
this.connected = true;
this.subscription.emit('reconnected');
});
}
}
_defineProperty(Mongo, "defaults", {
aggregateOptions: {
allowDiskUse: false
},
limitCount: 1e3
});
export default Mongo;