import * as plugins from './smartclickhouse.plugins.js'; import { ClickhouseTable } from './smartclickhouse.classes.clickhousetable.js'; import { TimeDataTable } from './smartclickhouse.classes.timedatatable.js'; import { ClickhouseHttpClient } from './smartclickhouse.classes.httpclient.js'; import type { IClickhouseTableOptions } from './smartclickhouse.types.js'; export interface IClickhouseConstructorOptions { url: string; database: string; username?: string; password?: string; /** * Allow services to exit when waiting for clickhouse startup. * This allows to leave the lifecycle flow to other processes * like a listening server. */ unref?: boolean; } export class SmartClickHouseDb { public options: IClickhouseConstructorOptions; public clickhouseHttpClient: ClickhouseHttpClient; constructor(optionsArg: IClickhouseConstructorOptions) { this.options = optionsArg; } /** * Starts the connection to the Clickhouse db */ public async start(dropOld = false) { console.log(`Connecting to default database first.`); this.clickhouseHttpClient = await ClickhouseHttpClient.createAndStart(this.options); await this.pingDatabaseUntilAvailable(); console.log(`Create database ${this.options.database}, if it does not exist...`); await this.createDatabase(dropOld); } public async createDatabase(dropOld: boolean = false) { if (dropOld) { await this.clickhouseHttpClient.queryPromise(`DROP DATABASE IF EXISTS ${this.options.database}`); } await this.clickhouseHttpClient.queryPromise( `CREATE DATABASE IF NOT EXISTS ${this.options.database}` ); } public async pingDatabaseUntilAvailable() { let available = false; while (!available) { available = await this.clickhouseHttpClient.ping().catch(() => false); if (!available) { console.log(`NOT OK: tried pinging ${this.options.url}... Trying again in 5 seconds.`); await plugins.smartdelay.delayFor(5000, null, this.options.unref); } } } // ---- NEW: Generic typed table factory ---- /** * Create a typed ClickHouse table with full configuration */ public async createTable>( options: IClickhouseTableOptions, ): Promise> { return ClickhouseTable.create(this, { ...options, database: options.database || this.options.database, }); } // ---- BACKWARD COMPAT: TimeDataTable factory ---- /** * Get a TimeDataTable (backward compatible) */ public async getTable(tableName: string): Promise { return TimeDataTable.getTable(this, tableName); } // ---- RAW QUERY ---- /** * Execute a raw SQL query and return typed results */ public async query(sql: string): Promise { return this.clickhouseHttpClient.queryTyped(sql); } }