import { Pool } from 'pg'; // import os from 'os'; import { Migrator } from './Migrator'; import { PoolClient } from 'pg'; import { Repositories } from './Repositories'; export interface DbConnection { user: string; password: string; host: string; port: number; database: string; } export interface ConnectionStringObj { connectionString: string; } export type TransactionClient = PoolClient; export class ConnectionManager { public readonly pool: Pool; public readonly repositories: T; constructor( protected applicationName: string, connection: string | DbConnection, protected migrationDirectory: string, protected migrationList: string[], repositoryCreator: (dbManager: ConnectionManager) => T, ) { let connectionInfo: ConnectionStringObj | DbConnection; if (typeof connection === 'string') { connectionInfo = { connectionString: connection }; } else { connectionInfo = connection; } this.pool = new Pool({ ...connectionInfo, application_name: applicationName, query_timeout: 5000, // TODO consider // idleTimeoutMillis: 0, // TODO consider // connectionTimeoutMillis: 2000, // max: os.cpus().length * 2, }); this.repositories = repositoryCreator(this); } public async applyMigrations() { const connection = await this.pool.connect(); const migrator = new Migrator(this.migrationDirectory, this.migrationList, connection); await migrator.migrate(); } public async close() { await this.pool.end(); this.pool.removeAllListeners(); } public async executeInTransaction(func: (client: TransactionClient) => Promise): Promise { const client = await this.pool.connect(); try { await client.query('BEGIN'); const value = await func(client); await client.query('COMMIT'); return value; } catch (e) { await client.query('ROLLBACK'); throw e; } finally { if (client) { client.release(); } } } }