// ============================================================ // Column Data Types // ============================================================ export type TClickhouseColumnType = | 'String' | 'UInt8' | 'UInt16' | 'UInt32' | 'UInt64' | 'Int8' | 'Int16' | 'Int32' | 'Int64' | 'Float32' | 'Float64' | 'Bool' | 'Date' | 'Date32' | 'DateTime' | 'DateTime64' | 'UUID' | 'IPv4' | 'IPv6' | (string & {}); // allow arbitrary ClickHouse types like "DateTime64(3, 'Europe/Berlin')" // ============================================================ // Engine Configuration // ============================================================ export type TClickhouseEngine = | 'MergeTree' | 'ReplacingMergeTree' | 'SummingMergeTree' | 'AggregatingMergeTree' | 'CollapsingMergeTree' | 'VersionedCollapsingMergeTree'; export interface IEngineConfig { engine: TClickhouseEngine; /** For ReplacingMergeTree: the version column name */ versionColumn?: string; /** For CollapsingMergeTree: the sign column name */ signColumn?: string; } // ============================================================ // Column Definition // ============================================================ export interface IColumnDefinition { name: string; type: TClickhouseColumnType; defaultExpression?: string; codec?: string; } // ============================================================ // Table Options // ============================================================ export interface IClickhouseTableOptions { tableName: string; database?: string; engine?: IEngineConfig; orderBy: (keyof T & string) | (keyof T & string)[]; partitionBy?: string; primaryKey?: (keyof T & string) | (keyof T & string)[]; ttl?: { column: keyof T & string; interval: string; // e.g., '30 DAY', '1 MONTH' }; columns?: IColumnDefinition[]; /** Enable auto-schema evolution (add columns from data). Default: true */ autoSchemaEvolution?: boolean; /** Data retention in days (shorthand for ttl). If ttl is set, this is ignored. */ retainDataForDays?: number; } // ============================================================ // Column Info from system.columns // ============================================================ export interface IColumnInfo { database: string; table: string; name: string; type: string; position: string; default_kind: string; default_expression: string; data_compressed_bytes: string; data_uncompressed_bytes: string; marks_bytes: string; comment: string; is_in_partition_key: 0 | 1; is_in_sorting_key: 0 | 1; is_in_primary_key: 0 | 1; is_in_sampling_key: 0 | 1; compression_codec: string; } // ============================================================ // Comparison Operators for Query Builder // ============================================================ export type TComparisonOperator = | '=' | '!=' | '>' | '>=' | '<' | '<=' | 'LIKE' | 'NOT LIKE' | 'IN' | 'NOT IN' | 'BETWEEN'; // ============================================================ // Value Escaping (SQL Injection Prevention) // ============================================================ export function escapeClickhouseValue(value: any): string { if (value === null || value === undefined) return 'NULL'; if (typeof value === 'number') return String(value); if (typeof value === 'boolean') return value ? '1' : '0'; if (value instanceof Date) return `'${value.toISOString().replace('T', ' ').replace('Z', '')}'`; if (Array.isArray(value)) { return `(${value.map(escapeClickhouseValue).join(', ')})`; } // String: escape single quotes and backslashes return `'${String(value).replace(/\\/g, '\\\\').replace(/'/g, "\\'")}'`; } // ============================================================ // ClickHouse Type Detection from JS Values // ============================================================ export function detectClickhouseType(value: any): TClickhouseColumnType | null { if (value === null || value === undefined) return null; if (typeof value === 'string') return 'String'; if (typeof value === 'number') return 'Float64'; if (typeof value === 'boolean') return 'UInt8'; if (value instanceof Array) { if (value.length === 0) return null; const elementType = detectClickhouseType(value[0]); if (!elementType) return null; return `Array(${elementType})` as TClickhouseColumnType; } return null; }