95 lines
2.0 KiB
TypeScript
95 lines
2.0 KiB
TypeScript
|
|
/**
|
||
|
|
* PostgreSQL database client with connection pooling
|
||
|
|
*/
|
||
|
|
|
||
|
|
import { Pool, PoolConfig, QueryResult, QueryResultRow } from 'pg';
|
||
|
|
|
||
|
|
// Re-export types for use in other modules
|
||
|
|
export type { QueryResult, QueryResultRow };
|
||
|
|
|
||
|
|
export interface DatabaseConfig {
|
||
|
|
connectionString?: string;
|
||
|
|
host?: string;
|
||
|
|
port?: number;
|
||
|
|
database?: string;
|
||
|
|
user?: string;
|
||
|
|
password?: string;
|
||
|
|
max?: number;
|
||
|
|
idleTimeoutMillis?: number;
|
||
|
|
connectionTimeoutMillis?: number;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Create a PostgreSQL connection pool
|
||
|
|
*/
|
||
|
|
export function createPool(config: DatabaseConfig): Pool {
|
||
|
|
const poolConfig: PoolConfig = {
|
||
|
|
connectionString: config.connectionString,
|
||
|
|
host: config.host,
|
||
|
|
port: config.port,
|
||
|
|
database: config.database,
|
||
|
|
user: config.user,
|
||
|
|
password: config.password,
|
||
|
|
max: config.max || 20,
|
||
|
|
idleTimeoutMillis: config.idleTimeoutMillis || 30000,
|
||
|
|
connectionTimeoutMillis: config.connectionTimeoutMillis || 2000,
|
||
|
|
};
|
||
|
|
|
||
|
|
return new Pool(poolConfig);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Default database pool instance
|
||
|
|
*/
|
||
|
|
let defaultPool: Pool | null = null;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Get or create the default database pool
|
||
|
|
*/
|
||
|
|
export function getPool(config?: DatabaseConfig): Pool {
|
||
|
|
if (!defaultPool) {
|
||
|
|
if (!config) {
|
||
|
|
throw new Error('Database configuration required for first pool creation');
|
||
|
|
}
|
||
|
|
defaultPool = createPool(config);
|
||
|
|
}
|
||
|
|
return defaultPool;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Execute a query
|
||
|
|
*/
|
||
|
|
export async function query<T extends QueryResultRow = QueryResultRow>(
|
||
|
|
text: string,
|
||
|
|
params?: unknown[]
|
||
|
|
): Promise<QueryResult<T>> {
|
||
|
|
if (!defaultPool) {
|
||
|
|
throw new Error('Database pool not initialized. Call getPool() with configuration first.');
|
||
|
|
}
|
||
|
|
return defaultPool.query<T>(text, params);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Close the database pool
|
||
|
|
*/
|
||
|
|
export async function closePool(): Promise<void> {
|
||
|
|
if (defaultPool) {
|
||
|
|
await defaultPool.end();
|
||
|
|
defaultPool = null;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Health check for database connection
|
||
|
|
*/
|
||
|
|
export async function healthCheck(): Promise<boolean> {
|
||
|
|
try {
|
||
|
|
const pool = getPool();
|
||
|
|
await pool.query('SELECT 1');
|
||
|
|
return true;
|
||
|
|
} catch {
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|