import { getLogger, type Logger } from '@stock-bot/logger'; import type { ConnectionFactory as IConnectionFactory, ConnectionPool, ConnectionFactoryConfig, MongoDBPoolConfig, PostgreSQLPoolConfig, CachePoolConfig, QueuePoolConfig, PoolMetrics, } from './types'; export class ConnectionFactory implements IConnectionFactory { private readonly logger: Logger; private readonly pools: Map> = new Map(); private readonly config: ConnectionFactoryConfig; constructor(config: ConnectionFactoryConfig) { this.config = config; this.logger = getLogger(`connection-factory:${config.service}`); // Note: config is stored for future use and used in logger name } async createMongoDB(poolConfig: MongoDBPoolConfig): Promise> { const key = `mongodb:${poolConfig.name}`; if (this.pools.has(key)) { this.logger.debug('Reusing existing MongoDB pool', { name: poolConfig.name }); return this.pools.get(key)!; } this.logger.info('Creating MongoDB connection pool', { name: poolConfig.name, poolSize: poolConfig.poolSize, }); try { // Dynamic import to avoid circular dependency const { createMongoDBClient } = await import('@stock-bot/mongodb'); const events = { onConnect: () => { this.logger.debug('MongoDB connected', { pool: poolConfig.name }); }, onDisconnect: () => { this.logger.debug('MongoDB disconnected', { pool: poolConfig.name }); }, onError: (error: any) => { this.logger.error('MongoDB error', { pool: poolConfig.name, error }); }, }; const client = createMongoDBClient(poolConfig.config as any, events); await client.connect(); if (poolConfig.minConnections) { await client.warmupPool(); } const pool: ConnectionPool = { name: poolConfig.name, client, metrics: client.getPoolMetrics(), health: async () => { try { await client.getDatabase().admin().ping(); return true; } catch { return false; } }, dispose: async () => { await client.disconnect(); this.pools.delete(key); }, }; this.pools.set(key, pool); return pool; } catch (error) { this.logger.error('Failed to create MongoDB pool', { name: poolConfig.name, error }); throw error; } } async createPostgreSQL(poolConfig: PostgreSQLPoolConfig): Promise> { const key = `postgres:${poolConfig.name}`; if (this.pools.has(key)) { this.logger.debug('Reusing existing PostgreSQL pool', { name: poolConfig.name }); return this.pools.get(key)!; } this.logger.info('Creating PostgreSQL connection pool', { name: poolConfig.name, poolSize: poolConfig.poolSize, }); try { // Dynamic import to avoid circular dependency const { createPostgreSQLClient } = await import('@stock-bot/postgres'); // Events will be handled by the client internally const client = createPostgreSQLClient(poolConfig.config as any); await client.connect(); if (poolConfig.minConnections) { await client.warmupPool(); } const pool: ConnectionPool = { name: poolConfig.name, client, metrics: client.getPoolMetrics(), health: async () => client.connected, dispose: async () => { await client.disconnect(); this.pools.delete(key); }, }; this.pools.set(key, pool); return pool; } catch (error) { this.logger.error('Failed to create PostgreSQL pool', { name: poolConfig.name, error }); throw error; } } createCache(poolConfig: CachePoolConfig): ConnectionPool { const key = `cache:${poolConfig.name}`; if (this.pools.has(key)) { this.logger.debug('Reusing existing cache pool', { name: poolConfig.name }); return this.pools.get(key)!; } this.logger.info('Creating cache connection pool', { name: poolConfig.name, }); try { // TODO: Implement cache creation with dynamic import throw new Error('Cache creation temporarily disabled'); } catch (error) { this.logger.error('Failed to create cache pool', { name: poolConfig.name, error }); throw error; } } createQueue(poolConfig: QueuePoolConfig): ConnectionPool { const key = `queue:${poolConfig.name}`; if (this.pools.has(key)) { this.logger.debug('Reusing existing queue manager', { name: poolConfig.name }); return this.pools.get(key)!; } this.logger.info('Creating queue manager', { name: poolConfig.name, }); try { // TODO: Implement queue creation with dynamic import throw new Error('Queue creation temporarily disabled'); } catch (error) { this.logger.error('Failed to create queue manager', { name: poolConfig.name, error }); throw error; } } getPool(type: 'mongodb' | 'postgres' | 'cache' | 'queue', name: string): ConnectionPool | undefined { const key = `${type}:${name}`; return this.pools.get(key); } listPools(): Array<{ type: string; name: string; metrics: PoolMetrics }> { const result: Array<{ type: string; name: string; metrics: PoolMetrics }> = []; for (const [key, pool] of this.pools) { const [type] = key.split(':'); result.push({ type: type || 'unknown', name: pool.name, metrics: pool.metrics, }); } return result; } async disposeAll(): Promise { this.logger.info('Disposing all connection pools', { service: this.config.service }); const disposePromises = Array.from(this.pools.values()).map(pool => pool.dispose()); await Promise.all(disposePromises); this.pools.clear(); } }