import { Injectable, OnModuleDestroy, OnModuleInit } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; import { drizzle } from 'drizzle-orm/node-postgres'; import { Pool } from 'pg'; import * as schema from './schema'; import { runMigrations } from './migrations/migrate'; @Injectable() export class DatabaseService implements OnModuleInit, OnModuleDestroy { private readonly pool: Pool; private readonly db: ReturnType; constructor(private configService: ConfigService) { // Create the PostgreSQL pool const connectionString = this.getDatabaseConnectionString(); this.pool = new Pool({ connectionString, }); // Create the Drizzle ORM instance this.db = drizzle(this.pool, { schema }); } async onModuleInit() { // Log database connection console.log('Connecting to database...'); // Test the connection try { const client = await this.pool.connect(); try { await client.query('SELECT NOW()'); console.log('Database connection established successfully'); } finally { client.release(); } } catch (error) { console.error('Failed to connect to database:', error.message); throw error; } // Run migrations in all environments const result = await runMigrations({ migrationsFolder: './src/database/migrations/sql' }); // In production, we want to fail if migrations fail if (!result.success && this.configService.get('NODE_ENV') === 'production') { throw result.error; } } async onModuleDestroy() { // Close the database connection await this.pool.end(); console.log('Database connection closed'); } // Get the database connection string from environment variables private getDatabaseConnectionString(): string { // First try to get the full DATABASE_URL const databaseUrl = this.configService.get('DATABASE_URL'); if (databaseUrl) { return databaseUrl; } // If DATABASE_URL is not provided, construct it from individual variables const password = this.configService.get('POSTGRES_PASSWORD'); const username = this.configService.get('POSTGRES_USER'); const host = this.configService.get('POSTGRES_HOST'); const port = this.configService.get('POSTGRES_PORT'); const database = this.configService.get('POSTGRES_DB'); const missingVars: string[] = []; if (!password) missingVars.push('POSTGRES_PASSWORD'); if (!username) missingVars.push('POSTGRES_USER'); if (!host) missingVars.push('POSTGRES_HOST'); if (!port) missingVars.push('POSTGRES_PORT'); if (!database) missingVars.push('POSTGRES_DB'); if (missingVars.length > 0) { throw new Error( `Database configuration is missing. Missing variables: ${missingVars.join(', ')}. Please check your .env file.`, ); } return `postgres://${username}:${password}@${host}:${port}/${database}`; } // Get the Drizzle ORM instance getDb() { return this.db; } // Get the PostgreSQL pool getPool() { return this.pool; } }