2020-04-22 17:24:15 +02:00
import mongoose from 'mongoose' ;
import cfenv from 'cfenv' ;
2020-05-04 15:48:07 +02:00
// mongoose.set('debug', true); // enable mongoose debug
2020-04-22 17:24:15 +02:00
// 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
2020-05-06 14:39:04 +02:00
mongoose . connect ( connectionString , { useNewUrlParser : true , useUnifiedTopology : true , useCreateIndex : true , connectTimeoutMS : 10000 } , err = > {
2020-04-22 17:24:15 +02:00
if ( err ) done ( err ) ;
} ) ;
mongoose . connection . on ( 'error' , console . error . bind ( console , 'connection error:' ) ) ;
2020-04-23 13:59:45 +02:00
mongoose . connection . on ( 'disconnected' , ( ) = > { // reset state on disconnect
2020-05-07 21:55:29 +02:00
console . info ( 'Database disconnected' ) ;
2020-04-23 13:59:45 +02:00
this . state . db = 0 ;
done ( ) ;
} ) ;
process . on ( 'SIGINT' , ( ) = > { // close connection when app is terminated
mongoose . connection . close ( ( ) = > {
2020-05-07 21:55:29 +02:00
console . info ( 'Mongoose default connection disconnected through app termination' ) ;
2020-04-23 13:59:45 +02:00
process . exit ( 0 ) ;
} ) ;
} ) ;
2020-04-22 17:24:15 +02:00
mongoose . connection . once ( 'open' , ( ) = > {
2020-04-23 17:46:00 +02:00
mongoose . set ( 'useFindAndModify' , false ) ;
2020-05-07 21:55:29 +02:00
console . info ( process . env . NODE_ENV === 'test' ? '' : ` Connected to ${ connectionString } ` ) ;
2020-04-22 17:24:15 +02:00
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
2020-05-07 21:55:29 +02:00
json . collections [ collectionName ] = this . oidResolve ( json . collections [ collectionName ] ) ;
2020-04-22 17:24:15 +02:00
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 ( ) ;
}
} ) ;
} ) ;
} ) ;
}
2020-05-07 21:55:29 +02:00
private static oidResolve ( object : any ) { // resolve $oid fields to actual ObjectIds recursively
Object . keys ( object ) . forEach ( key = > {
if ( object [ key ] !== null && object [ key ] . hasOwnProperty ( '$oid' ) ) {
object [ key ] = mongoose . Types . ObjectId ( object [ key ] . $oid ) ;
}
else if ( typeof object [ key ] === 'object' && object [ key ] !== null ) {
object [ key ] = this . oidResolve ( object [ key ] ) ;
}
} ) ;
return object ;
}
2020-04-22 17:24:15 +02:00
} ;