import mongoose from 'mongoose'; import cfenv from 'cfenv'; // database urls, prod db url is retrieved automatically const TESTING_URL = 'mongodb://localhost/dfopdb_test'; const DEV_URL = 'mongodb://localhost/dfopdb'; export default class db { private static state = { // db object and current mode (test, dev, prod) db: null, mode: null, }; static connect (mode = '', done: Function = () => {}) { // set mode to test for unit/integration tests, otherwise skip parameter. done is also only needed for testing if (this.state.db) return done(); // db is already connected // find right connection url let connectionString: string = ""; if (mode === 'test') { // testing connectionString = TESTING_URL; this.state.mode = 'test'; } else if(process.env.NODE_ENV === 'production') { let services = cfenv.getAppEnv().getServices(); for (let service in services) { if(services[service].tags.indexOf("mongodb") >= 0) { connectionString = services[service]["credentials"].uri; } } this.state.mode = 'prod'; } else { connectionString = DEV_URL; this.state.mode = 'dev'; } // connect to db mongoose.connect(connectionString, {useNewUrlParser: true, useUnifiedTopology: true}, err => { if (err) done(err); }); mongoose.connection.on('error', console.error.bind(console, 'connection error:')); mongoose.connection.on('disconnected', () => { // reset state on disconnect console.log('Database disconnected'); this.state.db = 0; done(); }); process.on('SIGINT', () => { // close connection when app is terminated mongoose.connection.close(() => { console.log('Mongoose default connection disconnected through app termination'); process.exit(0); }); }); mongoose.connection.once('open', () => { mongoose.set('useFindAndModify', false); console.log(process.env.NODE_ENV === 'test' ? '' : `Connected to ${connectionString}`); this.state.db = mongoose.connection; done(); }); } static getState () { return this.state; } static drop (done: Function = () => {}) { // drop all collections of connected db (only dev and test for safety reasons ;) if (!this.state.db || this.state.mode === 'prod') return done(); // no db connection or prod db this.state.db.db.listCollections().toArray((err, collections) => { // get list of all collections if (collections.length === 0) { // there are no collections to drop return done(); } else { let dropCounter = 0; // count number of dropped collections to know when to return done() collections.forEach(collection => { // drop each collection this.state.db.dropCollection(collection.name, () => { if (++ dropCounter >= collections.length) { // all collections dropped done(); } }); }); } }); } static loadJson (json, done: Function = () => {}) { // insert given JSON data into db, uses core mongodb methods if (!this.state.db || !json.hasOwnProperty('collections') || json.collections.length === 0) { return done(); } // no db connection or nothing to load let loadCounter = 0; // count number of loaded collections to know when to return done() Object.keys(json.collections).forEach(collectionName => { // create each collection for(let i in json.collections[collectionName]) { // convert $oid fields to actual ObjectIds console.log(json.collections[collectionName][i]); Object.keys(json.collections[collectionName][i]).forEach(key => { json.collections[collectionName][i][key] = json.collections[collectionName][i][key].hasOwnProperty('$oid') ? mongoose.Types.ObjectId(json.collections[collectionName][i][key].$oid) : json.collections[collectionName][i][key]; }) } this.state.db.createCollection(collectionName, (err, collection) => { collection.insertMany(json.collections[collectionName], () => { // insert JSON data if (++ loadCounter >= Object.keys(json.collections).length) { // all collections loaded done(); } }); }); }); } };