import { SQLiteClient } from '../rag/sqlite-client.js';
import { Logger, ConsoleLogger } from '../rag/sqlite-client.js';
import { MetricsCollector, NoOpMetrics } from '../rag/sqlite-client.js';
export interface ConnectionPoolConfig {
dbPath?: string;
logger?: Logger;
metrics?: MetricsCollector;
autoInitialize?: boolean;
}
export class ConnectionPool {
private static instance: ConnectionPool | null = null;
private sqliteClient: SQLiteClient | null = null;
private isInitializing = false;
private initPromise: Promise<void> | null = null;
private readonly config: Required<ConnectionPoolConfig>;
private readonly logger: Logger;
private readonly metrics: MetricsCollector;
private constructor(config: ConnectionPoolConfig = {}) {
this.config = {
dbPath: './data/rag.db',
logger: new ConsoleLogger(),
metrics: new NoOpMetrics(),
autoInitialize: true,
...config
};
this.logger = this.config.logger;
this.metrics = this.config.metrics;
}
/**
* Получить единственный экземпляр ConnectionPool (Singleton)
*/
public static getInstance(config?: ConnectionPoolConfig): ConnectionPool {
if (!ConnectionPool.instance) {
ConnectionPool.instance = new ConnectionPool(config);
}
return ConnectionPool.instance;
}
/**
* Получить SQLiteClient, автоматически инициализируя его при необходимости
*/
public async getSQLiteClient(): Promise<SQLiteClient> {
if (!this.sqliteClient) {
await this.initialize();
}
return this.sqliteClient!;
}
/**
* Инициализировать пул соединений
*/
public async initialize(): Promise<void> {
if (this.sqliteClient) {
return; // Уже инициализирован
}
if (this.isInitializing) {
// Дождаться завершения текущей инициализации
if (this.initPromise) {
await this.initPromise;
return;
}
}
this.isInitializing = true;
this.initPromise = this.performInitialization();
try {
await this.initPromise;
} finally {
this.isInitializing = false;
this.initPromise = null;
}
}
/**
* Выполнить инициализацию
*/
private async performInitialization(): Promise<void> {
try {
this.logger.info('Initializing ConnectionPool', {
dbPath: this.config.dbPath,
autoInitialize: this.config.autoInitialize
});
// Создаем SQLiteClient
this.sqliteClient = new SQLiteClient(
this.config.dbPath,
this.logger,
this.metrics
);
// Инициализируем базу данных
const initResult = await this.sqliteClient.initialize();
if (initResult.isErr()) {
throw new Error(`Failed to initialize SQLiteClient: ${initResult.error.message}`);
}
this.logger.info('ConnectionPool initialized successfully');
this.metrics.recordOperation('connectionPool.initialize');
} catch (error) {
const errorObj = error instanceof Error ? error : new Error(String(error));
this.logger.error('Failed to initialize ConnectionPool', errorObj);
this.metrics.recordError('connectionPool.initialize');
// Сбрасываем состояние при ошибке
this.sqliteClient = null;
throw errorObj;
}
}
/**
* Проверить, инициализирован ли пул
*/
public isInitialized(): boolean {
return this.sqliteClient !== null;
}
/**
* Проверить подключение к базе данных
*/
public async isConnected(): Promise<boolean> {
try {
const client = await this.getSQLiteClient();
return await client.isConnected();
} catch {
return false;
}
}
/**
* Получить статистику базы данных
*/
public async getStats() {
try {
const client = await this.getSQLiteClient();
return await client.getStats();
} catch (error) {
const errorObj = error instanceof Error ? error : new Error(String(error));
this.logger.error('Failed to get database stats', errorObj);
throw errorObj;
}
}
/**
* Закрыть все соединения
*/
public async close(): Promise<void> {
if (this.sqliteClient) {
try {
await this.sqliteClient.close();
this.logger.info('ConnectionPool connections closed');
} catch (error) {
const errorObj = error instanceof Error ? error : new Error(String(error));
this.logger.error('Error closing ConnectionPool', errorObj);
} finally {
this.sqliteClient = null;
}
}
}
/**
* Сбросить пул (для тестов)
*/
public static reset(): void {
if (ConnectionPool.instance) {
ConnectionPool.instance.close();
ConnectionPool.instance = null;
}
}
/**
* Получить информацию о состоянии пула
*/
public getStatus() {
return {
isInitialized: this.isInitialized(),
isInitializing: this.isInitializing,
dbPath: this.config.dbPath,
hasClient: !!this.sqliteClient
};
}
}
// Экспортируем удобные функции
export const getConnectionPool = (config?: ConnectionPoolConfig) => ConnectionPool.getInstance(config);
export const resetConnectionPool = () => ConnectionPool.reset();