import {Container, Inject, Singleton} from '../../di' import {DatabaseService} from '../DatabaseService' import {PostgresConnection} from '../connection/PostgresConnection' import {ErrorWithContext} from '../../util' import {Unit} from '../../lifecycle/Unit' import {Config} from '../../service/Config' import {Logging} from '../../service/Logging' import {MigratorFactory} from '../migrations/MigratorFactory' import {SQLiteConnection} from '../connection/SQLiteConnection' /** * Application unit responsible for loading and creating database connections from config. */ @Singleton() export class Database extends Unit { @Inject() protected readonly config!: Config @Inject() protected readonly dbService!: DatabaseService @Inject() protected readonly logging!: Logging @Inject('injector') protected readonly injector!: Container /** * Load the `database.connections` config and register Connection instances for each config. * Automatically initializes the connections. */ public async up(): Promise { const connections = this.config.get('database.connections') const promises = [] // Register the migrator factory this.injector.registerFactory(this.injector.make(MigratorFactory)) for ( const key in connections ) { if ( !Object.prototype.hasOwnProperty.call(connections, key) ) { continue } const config = connections[key] this.logging.info(`Initializing database connection: ${key}`) this.logging.verbose(config) let conn if ( config?.dialect === 'postgres' ) { conn = this.app().make(PostgresConnection, key, config) } else if ( config?.dialect === 'sqlite' ) { conn = this.app().make(SQLiteConnection, key, config) } else { const e = new ErrorWithContext(`Invalid or missing database dialect: ${config.dialect}. Should be one of: postgres`) e.context = { connectionName: key } throw e } this.dbService.register(key, conn) promises.push(conn.init()) } await Promise.all(promises) this.logging.info('Database connections opened.') } /** * Close the configured connections cleanly before exit. */ public async down(): Promise { await Promise.all(this.dbService.names() .map(name => this.dbService.get(name).close())) } }