import { createLogger } from '@gongt/ts-stl-library/debug/create-logger'; import { LOG_LEVEL } from '@gongt/ts-stl-library/debug/levels'; import { DependencyInjector } from '@gongt/ts-stl-library/DI'; import { Connection, createConnection, Model, } from 'mongoose'; import { pushInitList } from '../boot/app-wait-start'; import { createWaiter, IWaitter } from '../boot/wait'; import { CallbackList } from '@gongt/ts-stl-library/pattern/callback-list'; const debug = createLogger(LOG_LEVEL.DEBUG, 'db'); const info = createLogger(LOG_LEVEL.INFO, 'db'); const error = createLogger(LOG_LEVEL.ERROR, 'db'); /** @internal */ export const di = new DependencyInjector<{[id: string]: ConnectionRegistry}>('database'); /** @internal */ export interface ConnectionRegistry extends Connection { // this registry is for prevent multiple new SameModel() cause mongoose's "re init same table" error rr: DependencyInjector<{[id: string]: Model}>; } /** @internal */ export let testDatabaseMuted = false; export function muteDatabaseConnectionForTest() { testDatabaseMuted = true; } /** @internal */ export let databaseInitComplete = false; let cbList: CallbackList; let allDatabaseConnected: Promise; let waitInternal: IWaitter; (function () { let resolve; cbList = new CallbackList(); registerModel('start', () => { debug('databaseInitComplete() is now TRUE.'); databaseInitComplete = true; return false; }); allDatabaseConnected = new Promise((_resolve) => { resolve = () => { _resolve(); allDatabaseConnected = null; }; }); waitInternal = createWaiter(() => { waitInternal = null; debug('start init all model (async)'); cbList.run(void 0); cbList = null; resolve(); }); waitInternal('empty wait', new Promise((resolve, reject) => { setImmediate(resolve); })); })(); export function initDatabaseConnection(name: string, uri: string) { info('connecting to database: %s: %s', name, uri); const database: Connection = createConnection(uri, { reconnectTries: 0, autoReconnect: false, promiseLibrary: Promise, }); database.on('error', () => { error('connection error (to %s [%s])', name, uri); }); database.on('disconnected', () => { error(`!!! ${name} disconnected !!!`); setImmediate(() => { process.exit(1); }); }); const subregistry = new DependencyInjector<{[id: string]: Model}>('model@' + name); di.set(name, Object.assign(database, { rr: subregistry, })); const wait = new Promise((resolve, reject) => { database.on('error', reject); database.on('open', () => resolve()); }); waitInternal('connect to mongo "' + name + '"', wait); pushInitList('mongodb connection: ' + name, wait); } waitDatabaseConnection().then(() => { debug('waitDatabaseConnection() is finish now'); }); export function waitDatabaseConnection() { if (databaseInitComplete) { return Promise.resolve(); } else { return allDatabaseConnected; } } /**@internal*/ export function registerModel(name: string, fn: () => false) { cbList.add(fn, name); }