135 lines
4.4 KiB
TypeScript
135 lines
4.4 KiB
TypeScript
// ============================================================
|
|
// 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<T = any> {
|
|
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;
|
|
}
|