/** * Database Factory * * Creates the appropriate database adapter based on environment configuration. */ import { logger } from '../logger.js'; import { PostgresAdapter } from './postgresAdapter.js'; import { SqliteAdapter } from './sqliteAdapter.js'; import type { DatabaseAdapter } from './interface.js'; import { join, dirname } from 'path'; import { fileURLToPath } from 'url'; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); /** * Create a database adapter based on environment variables * @param allowClose - If false, the adapter won't be closed when close() is called (for singletons) */ export function createDatabaseAdapter(dbType?: string, dbPath?: string, allowClose: boolean = true): DatabaseAdapter { const type = dbType || process.env.DATABASE_TYPE || 'sqlite'; const databaseUrl = process.env.DATABASE_URL; if (type === 'postgres' || type === 'postgresql') { if (!databaseUrl) { // Try to construct from individual components const host = process.env.DATABASE_HOST || 'localhost'; const port = process.env.DATABASE_PORT || '5432'; const name = process.env.DATABASE_NAME || 'cmdb'; const user = process.env.DATABASE_USER || 'cmdb'; const password = process.env.DATABASE_PASSWORD || ''; // Azure PostgreSQL requires SSL - always use sslmode=require for Azure const isAzure = host.includes('.postgres.database.azure.com'); const ssl = (process.env.DATABASE_SSL === 'true' || isAzure) ? '?sslmode=require' : ''; const constructedUrl = `postgresql://${user}:${password}@${host}:${port}/${name}${ssl}`; logger.info('Creating PostgreSQL adapter with constructed connection string'); logger.info(`Database: ${name}, SSL: ${ssl ? 'required' : 'not required'}`); return new PostgresAdapter(constructedUrl, allowClose); } logger.info('Creating PostgreSQL adapter'); return new PostgresAdapter(databaseUrl, allowClose); } // Default to SQLite const defaultPath = dbPath || join(__dirname, '../../data/cmdb-cache.db'); logger.info(`Creating SQLite adapter with path: ${defaultPath}`); return new SqliteAdapter(defaultPath); } /** * Create a database adapter for the classifications database */ export function createClassificationsDatabaseAdapter(): DatabaseAdapter { const type = process.env.DATABASE_TYPE || 'sqlite'; const databaseUrl = process.env.CLASSIFICATIONS_DATABASE_URL || process.env.DATABASE_URL; if (type === 'postgres' || type === 'postgresql') { if (!databaseUrl) { // Try to construct from individual components const host = process.env.DATABASE_HOST || 'localhost'; const port = process.env.DATABASE_PORT || '5432'; const name = process.env.CLASSIFICATIONS_DATABASE_NAME || process.env.DATABASE_NAME || 'cmdb'; const user = process.env.DATABASE_USER || 'cmdb'; const password = process.env.DATABASE_PASSWORD || ''; // Azure PostgreSQL requires SSL - always use sslmode=require for Azure const isAzure = host.includes('.postgres.database.azure.com'); const ssl = (process.env.DATABASE_SSL === 'true' || isAzure) ? '?sslmode=require' : ''; const constructedUrl = `postgresql://${user}:${password}@${host}:${port}/${name}${ssl}`; logger.info('Creating PostgreSQL adapter for classifications with constructed connection string'); return new PostgresAdapter(constructedUrl); } logger.info('Creating PostgreSQL adapter for classifications'); return new PostgresAdapter(databaseUrl); } // Default to SQLite const defaultPath = join(__dirname, '../../data/classifications.db'); logger.info(`Creating SQLite adapter for classifications with path: ${defaultPath}`); return new SqliteAdapter(defaultPath); }