@housekit/orm 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +224 -0
- package/dist/builders/delete.d.ts +21 -0
- package/dist/builders/insert.d.ts +128 -0
- package/dist/builders/prepared.d.ts +11 -0
- package/dist/builders/select.d.ts +352 -0
- package/dist/builders/select.types.d.ts +76 -0
- package/dist/builders/update.d.ts +23 -0
- package/dist/client.d.ts +52 -0
- package/dist/codegen/zod.d.ts +4 -0
- package/dist/column.d.ts +76 -0
- package/dist/compiler.d.ts +27 -0
- package/dist/core.d.ts +6 -0
- package/dist/data-types.d.ts +150 -0
- package/dist/dictionary.d.ts +263 -0
- package/dist/engines.d.ts +558 -0
- package/dist/expressions.d.ts +72 -0
- package/dist/external.d.ts +177 -0
- package/dist/index.d.ts +187 -0
- package/dist/index.js +222 -0
- package/dist/logger.d.ts +8 -0
- package/dist/materialized-views.d.ts +271 -0
- package/dist/metadata.d.ts +33 -0
- package/dist/modules/aggregates.d.ts +205 -0
- package/dist/modules/array.d.ts +122 -0
- package/dist/modules/conditional.d.ts +110 -0
- package/dist/modules/conversion.d.ts +189 -0
- package/dist/modules/geo.d.ts +202 -0
- package/dist/modules/hash.d.ts +7 -0
- package/dist/modules/index.d.ts +12 -0
- package/dist/modules/json.d.ts +130 -0
- package/dist/modules/math.d.ts +28 -0
- package/dist/modules/string.d.ts +167 -0
- package/dist/modules/time.d.ts +154 -0
- package/dist/modules/types.d.ts +177 -0
- package/dist/modules/window.d.ts +27 -0
- package/dist/relational.d.ts +33 -0
- package/dist/relations.d.ts +15 -0
- package/dist/schema-builder.d.ts +172 -0
- package/dist/table.d.ts +172 -0
- package/dist/utils/background-batcher.d.ts +20 -0
- package/dist/utils/batch-transform.d.ts +20 -0
- package/dist/utils/binary-reader.d.ts +48 -0
- package/dist/utils/binary-serializer.d.ts +160 -0
- package/dist/utils/binary-worker-code.d.ts +1 -0
- package/dist/utils/binary-worker-pool.d.ts +76 -0
- package/dist/utils/binary-worker.d.ts +12 -0
- package/dist/utils/insert-processing.d.ts +23 -0
- package/dist/utils/lru-cache.d.ts +10 -0
- package/package.json +68 -0
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HouseKit Schema Builder - Fluent API for Table Definitions
|
|
3
|
+
*
|
|
4
|
+
* This module provides a modern fluent syntax for defining tables using
|
|
5
|
+
* a builder function pattern instead of individual imports.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```typescript
|
|
9
|
+
* import { defineTable, t } from '@housekit/orm';
|
|
10
|
+
*
|
|
11
|
+
* // Using the builder function pattern
|
|
12
|
+
* export const users = defineTable('users', (t) => ({
|
|
13
|
+
* id: t.uuid('id').primaryKey(),
|
|
14
|
+
* name: t.string('name'),
|
|
15
|
+
* email: t.string('email'),
|
|
16
|
+
* age: t.int32('age').nullable(),
|
|
17
|
+
* createdAt: t.datetime('created_at').default('now()'),
|
|
18
|
+
* }), { engine: Engine.MergeTree(), orderBy: 'createdAt' });
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
import { ClickHouseColumn } from './column';
|
|
22
|
+
import { chView, type TableOptions, type TableDefinition, type RelationDefinition, index, projection } from './table';
|
|
23
|
+
import { chMaterializedView, detectMaterializedViewDrift, extractMVQuery, createMigrationBridge, generateBlueGreenMigration } from './materialized-views';
|
|
24
|
+
export { detectMaterializedViewDrift, extractMVQuery, createMigrationBridge, generateBlueGreenMigration };
|
|
25
|
+
import { chDictionary } from './dictionary';
|
|
26
|
+
import { chProjection } from './materialized-views';
|
|
27
|
+
import { EngineConfiguration } from './engines';
|
|
28
|
+
export { index };
|
|
29
|
+
/**
|
|
30
|
+
* Enhanced table options with column key references for orderBy, partitionBy, etc.
|
|
31
|
+
*/
|
|
32
|
+
export type EnhancedTableOptions<TColKeys extends string = string> = Omit<TableOptions, 'orderBy' | 'partitionBy' | 'primaryKey' | 'sampleBy' | 'deduplicateBy' | 'versionColumn' | 'logicalPrimaryKey' | 'engine'> & {
|
|
33
|
+
engine: EngineConfiguration;
|
|
34
|
+
customEngine?: string;
|
|
35
|
+
/**
|
|
36
|
+
* Column(s) for ORDER BY. Can use column keys from your definition.
|
|
37
|
+
* @example orderBy: 'timestamp' or orderBy: ['user_id', 'timestamp']
|
|
38
|
+
*/
|
|
39
|
+
orderBy?: TColKeys | TColKeys[] | string | string[];
|
|
40
|
+
/**
|
|
41
|
+
* Column(s) for PARTITION BY. Can use column keys from your definition.
|
|
42
|
+
*/
|
|
43
|
+
partitionBy?: TColKeys | TColKeys[] | string | string[];
|
|
44
|
+
/**
|
|
45
|
+
* Column(s) for PRIMARY KEY. Can use column keys from your definition.
|
|
46
|
+
*/
|
|
47
|
+
primaryKey?: TColKeys | TColKeys[] | string | string[];
|
|
48
|
+
/**
|
|
49
|
+
* Column(s) for SAMPLE BY. Can use column keys from your definition.
|
|
50
|
+
*/
|
|
51
|
+
sampleBy?: TColKeys | TColKeys[] | string | string[];
|
|
52
|
+
/**
|
|
53
|
+
* Column(s) for deduplication (ReplacingMergeTree).
|
|
54
|
+
*/
|
|
55
|
+
deduplicateBy?: TColKeys | TColKeys[] | string | string[];
|
|
56
|
+
/**
|
|
57
|
+
* Version column for ReplacingMergeTree.
|
|
58
|
+
*/
|
|
59
|
+
versionColumn?: TColKeys | string;
|
|
60
|
+
/**
|
|
61
|
+
* Logical primary key (for documentation, not enforced).
|
|
62
|
+
*/
|
|
63
|
+
logicalPrimaryKey?: TColKeys | TColKeys[] | string | string[];
|
|
64
|
+
};
|
|
65
|
+
/**
|
|
66
|
+
* ClickHouse data types builder.
|
|
67
|
+
* All columns are NOT NULL by default, following ClickHouse philosophy.
|
|
68
|
+
*/
|
|
69
|
+
export declare const t: {
|
|
70
|
+
int8: (name: string) => ClickHouseColumn<number, true, false>;
|
|
71
|
+
int16: (name: string) => ClickHouseColumn<number, true, false>;
|
|
72
|
+
integer: (name: string) => ClickHouseColumn<number, true, false>;
|
|
73
|
+
/**
|
|
74
|
+
* Int32 type. Signed 32-bit integer.
|
|
75
|
+
* @range -2147483648 to 2147483647
|
|
76
|
+
*/
|
|
77
|
+
int32: (name: string) => ClickHouseColumn<number, true, false>;
|
|
78
|
+
int64: (name: string) => ClickHouseColumn<number, true, false>;
|
|
79
|
+
int128: (name: string) => ClickHouseColumn<number, true, false>;
|
|
80
|
+
int256: (name: string) => ClickHouseColumn<number, true, false>;
|
|
81
|
+
uint8: (name: string) => ClickHouseColumn<number, true, false>;
|
|
82
|
+
uint16: (name: string) => ClickHouseColumn<number, true, false>;
|
|
83
|
+
uint32: (name: string) => ClickHouseColumn<number, true, false>;
|
|
84
|
+
uint64: (name: string) => ClickHouseColumn<number, true, false>;
|
|
85
|
+
uint128: (name: string) => ClickHouseColumn<number, true, false>;
|
|
86
|
+
uint256: (name: string) => ClickHouseColumn<number, true, false>;
|
|
87
|
+
float32: (name: string) => ClickHouseColumn<number, true, false>;
|
|
88
|
+
float: (name: string) => ClickHouseColumn<number, true, false>;
|
|
89
|
+
float64: (name: string) => ClickHouseColumn<number, true, false>;
|
|
90
|
+
bfloat16: (name: string) => ClickHouseColumn<number, true, false>;
|
|
91
|
+
decimal: (name: string, precision?: number, scale?: number) => ClickHouseColumn<number, true, false>;
|
|
92
|
+
decimal32: (name: string, scale?: number) => ClickHouseColumn<number, true, false>;
|
|
93
|
+
decimal64: (name: string, scale?: number) => ClickHouseColumn<number, true, false>;
|
|
94
|
+
decimal128: (name: string, scale?: number) => ClickHouseColumn<number, true, false>;
|
|
95
|
+
decimal256: (name: string, scale?: number) => ClickHouseColumn<number, true, false>;
|
|
96
|
+
text: (name: string) => ClickHouseColumn<string, true, false>;
|
|
97
|
+
string: (name: string) => ClickHouseColumn<string, true, false>;
|
|
98
|
+
fixedString: (name: string, length: number) => ClickHouseColumn<string, true, false>;
|
|
99
|
+
varchar: (name: string, opts?: {
|
|
100
|
+
length?: number;
|
|
101
|
+
}) => ClickHouseColumn<string, true, false>;
|
|
102
|
+
date: (name: string) => ClickHouseColumn<string | Date, true, false>;
|
|
103
|
+
date32: (name: string) => ClickHouseColumn<string | Date, true, false>;
|
|
104
|
+
timestamp: (name: string, timezone?: string) => ClickHouseColumn<string | Date, true, false>;
|
|
105
|
+
/**
|
|
106
|
+
* DateTime type. Stores date and time.
|
|
107
|
+
* @param timezone - Optional. Example: 'UTC', 'Europe/Madrid'
|
|
108
|
+
*/
|
|
109
|
+
datetime: (name: string, timezone?: string) => ClickHouseColumn<string | Date, true, false>;
|
|
110
|
+
datetime64: (name: string, precision?: number, timezone?: string) => ClickHouseColumn<string | Date, true, false>;
|
|
111
|
+
boolean: (name: string) => ClickHouseColumn<boolean, true, false>;
|
|
112
|
+
bool: (name: string) => ClickHouseColumn<boolean, true, false>;
|
|
113
|
+
uuid: (name: string) => ClickHouseColumn<string, true, false>;
|
|
114
|
+
ipv4: (name: string) => ClickHouseColumn<string, true, false>;
|
|
115
|
+
ipv6: (name: string) => ClickHouseColumn<string, true, false>;
|
|
116
|
+
array: <T>(col: ClickHouseColumn<T>) => ClickHouseColumn<T[], true, false>;
|
|
117
|
+
tuple: (name: string, types: string[]) => ClickHouseColumn<any, true, false>;
|
|
118
|
+
map: (name: string, keyType?: string, valueType?: string) => ClickHouseColumn<Record<string, any>, true, false>;
|
|
119
|
+
nested: (name: string, fields: Record<string, string>) => ClickHouseColumn<any, true, false>;
|
|
120
|
+
json: <TSchema = Record<string, any>>(name: string) => ClickHouseColumn<TSchema, false, false>;
|
|
121
|
+
dynamic: (name: string, maxTypes?: number) => ClickHouseColumn<any, true, false>;
|
|
122
|
+
/**
|
|
123
|
+
* LowCardinality type. Optimizes columns with few unique values
|
|
124
|
+
* (typically < 10,000) for ultra-fast reading.
|
|
125
|
+
* @see https://clickhouse.com/docs/en/sql-reference/data-types/lowcardinality
|
|
126
|
+
*/
|
|
127
|
+
lowCardinality: <T, TNotNull extends boolean, TAutoGenerated extends boolean>(col: ClickHouseColumn<T, TNotNull, TAutoGenerated>) => ClickHouseColumn<T, TNotNull, TAutoGenerated>;
|
|
128
|
+
aggregateFunction: (name: string, funcName: string, ...argTypes: string[]) => ClickHouseColumn<any, true, false>;
|
|
129
|
+
simpleAggregateFunction: (name: string, funcName: string, argType: string) => ClickHouseColumn<any, true, false>;
|
|
130
|
+
point: (name: string) => ClickHouseColumn<[number, number], true, false>;
|
|
131
|
+
ring: (name: string) => ClickHouseColumn<[number, number][], true, false>;
|
|
132
|
+
polygon: (name: string) => ClickHouseColumn<[number, number][][], true, false>;
|
|
133
|
+
multiPolygon: (name: string) => ClickHouseColumn<[number, number][][][], true, false>;
|
|
134
|
+
enum: (name: string, values: readonly string[]) => ClickHouseColumn<string, false, false>;
|
|
135
|
+
};
|
|
136
|
+
export type ColumnBuilder = typeof t;
|
|
137
|
+
/**
|
|
138
|
+
* Define a strongly-typed ClickHouse table.
|
|
139
|
+
*
|
|
140
|
+
* @param name - Physical table name in ClickHouse.
|
|
141
|
+
* @param columns - Column definition object or callback using `t` builder.
|
|
142
|
+
* @param options - Engine configuration, sorting keys, partitioning, etc.
|
|
143
|
+
*/
|
|
144
|
+
export declare function defineTable<T extends Record<string, ClickHouseColumn<any, any, any>>>(tableName: string, columnsOrCallback: T | ((t: ColumnBuilder) => T), options: EnhancedTableOptions<keyof T & string>): TableDefinition<T, TableOptions>;
|
|
145
|
+
/**
|
|
146
|
+
* Aliases for modern API - providing both short and explicit naming.
|
|
147
|
+
*
|
|
148
|
+
* NOTE: defineTable is the preferred explicit naming for library consistency,
|
|
149
|
+
* while 'table' is provided as a shorthand similar to other ORMs.
|
|
150
|
+
*/
|
|
151
|
+
export declare const table: typeof defineTable;
|
|
152
|
+
export declare const view: typeof chView;
|
|
153
|
+
export declare const defineView: typeof chView;
|
|
154
|
+
export declare const defineMaterializedView: typeof chMaterializedView;
|
|
155
|
+
export declare const materializedView: typeof chMaterializedView;
|
|
156
|
+
export declare const dictionary: typeof chDictionary;
|
|
157
|
+
export declare const defineDictionary: typeof chDictionary;
|
|
158
|
+
export { projection };
|
|
159
|
+
export { chProjection as defineProjection };
|
|
160
|
+
/**
|
|
161
|
+
* Define relations for a table using a callback pattern.
|
|
162
|
+
*/
|
|
163
|
+
export declare function relations<TTable extends TableDefinition<any>>(table: TTable, relationsBuilder: (helpers: {
|
|
164
|
+
one: (table: TableDefinition<any>, config: {
|
|
165
|
+
fields: ClickHouseColumn<any, any, any>[];
|
|
166
|
+
references: ClickHouseColumn<any, any, any>[];
|
|
167
|
+
}) => RelationDefinition;
|
|
168
|
+
many: (table: TableDefinition<any>, config?: {
|
|
169
|
+
fields?: ClickHouseColumn<any, any, any>[];
|
|
170
|
+
references?: ClickHouseColumn<any, any, any>[];
|
|
171
|
+
}) => RelationDefinition;
|
|
172
|
+
}) => Record<string, RelationDefinition>): Record<string, RelationDefinition>;
|
package/dist/table.d.ts
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { ClickHouseColumn } from './column';
|
|
2
|
+
import { TTLRule } from './data-types';
|
|
3
|
+
import { EngineConfiguration } from './engines';
|
|
4
|
+
import { type MetadataVersion } from './metadata';
|
|
5
|
+
export interface TableOptions {
|
|
6
|
+
/**
|
|
7
|
+
* ClickHouse table engine configuration.
|
|
8
|
+
*
|
|
9
|
+
* // Raw string (escape hatch)
|
|
10
|
+
* customEngine: 'MergeTree()'
|
|
11
|
+
* ```
|
|
12
|
+
*/
|
|
13
|
+
engine?: EngineConfiguration;
|
|
14
|
+
customEngine?: string;
|
|
15
|
+
orderBy?: string | string[];
|
|
16
|
+
partitionBy?: string | string[];
|
|
17
|
+
primaryKey?: string | string[];
|
|
18
|
+
logicalPrimaryKey?: string | string[];
|
|
19
|
+
ttl?: TTLRule | TTLRule[] | string;
|
|
20
|
+
appendOnly?: boolean;
|
|
21
|
+
deduplicateBy?: string | string[];
|
|
22
|
+
versionColumn?: string;
|
|
23
|
+
externallyManaged?: boolean;
|
|
24
|
+
sampleBy?: string | string[];
|
|
25
|
+
onCluster?: string;
|
|
26
|
+
shardKey?: string | string[];
|
|
27
|
+
materializedView?: {
|
|
28
|
+
name: string;
|
|
29
|
+
toTable: string;
|
|
30
|
+
query: string;
|
|
31
|
+
populate?: boolean;
|
|
32
|
+
};
|
|
33
|
+
defaultFinal?: boolean;
|
|
34
|
+
metadataVersion?: MetadataVersion;
|
|
35
|
+
readOnly?: boolean;
|
|
36
|
+
indices?: IndexDefinition[];
|
|
37
|
+
projections?: ProjectionDefinition[];
|
|
38
|
+
asyncInsert?: boolean;
|
|
39
|
+
}
|
|
40
|
+
export type IndexDefinition = {
|
|
41
|
+
name: string;
|
|
42
|
+
cols: ClickHouseColumn[];
|
|
43
|
+
type: 'minmax' | 'set' | 'bloom_filter';
|
|
44
|
+
granularity?: number;
|
|
45
|
+
};
|
|
46
|
+
export type ProjectionDefinition = {
|
|
47
|
+
name: string;
|
|
48
|
+
query: string;
|
|
49
|
+
};
|
|
50
|
+
export declare const index: (name: string) => {
|
|
51
|
+
on: (...cols: ClickHouseColumn[]) => {
|
|
52
|
+
type: (type: IndexDefinition["type"], granularity?: number) => IndexDefinition;
|
|
53
|
+
};
|
|
54
|
+
};
|
|
55
|
+
export declare const projection: (name: string, query: string) => ProjectionDefinition;
|
|
56
|
+
export type RelationDefinition = {
|
|
57
|
+
relation: 'one';
|
|
58
|
+
name: string;
|
|
59
|
+
table: TableDefinition<any>;
|
|
60
|
+
fields: ClickHouseColumn[];
|
|
61
|
+
references: ClickHouseColumn[];
|
|
62
|
+
} | {
|
|
63
|
+
relation: 'many';
|
|
64
|
+
name: string;
|
|
65
|
+
table: TableDefinition<any>;
|
|
66
|
+
fields?: ClickHouseColumn[];
|
|
67
|
+
references?: ClickHouseColumn[];
|
|
68
|
+
};
|
|
69
|
+
export type TableColumns = Record<string, ClickHouseColumn<any, any, any>>;
|
|
70
|
+
export type TableRow<TCols extends TableColumns> = {
|
|
71
|
+
[K in keyof TCols]: TCols[K] extends ClickHouseColumn<infer T, infer NotNull, any> ? NotNull extends true ? T : T | null : never;
|
|
72
|
+
};
|
|
73
|
+
export type TableInsert<TCols extends TableColumns> = {
|
|
74
|
+
[K in keyof TCols as TCols[K] extends ClickHouseColumn<any, infer NotNull, infer Auto> ? NotNull extends true ? Auto extends true ? never : K : never : never]: TCols[K] extends ClickHouseColumn<infer T, any, any> ? T : never;
|
|
75
|
+
} & Partial<{
|
|
76
|
+
[K in keyof TCols as TCols[K] extends ClickHouseColumn<any, infer NotNull, infer Auto> ? NotNull extends true ? Auto extends true ? K : never : K : never]: TCols[K] extends ClickHouseColumn<infer T, any, any> ? T : never;
|
|
77
|
+
}>;
|
|
78
|
+
type GetColumnType<T extends ClickHouseColumn> = T extends ClickHouseColumn<infer Type, infer IsNotNull, any> ? IsNotNull extends true ? Type : Type | null : never;
|
|
79
|
+
export type InferSelectModel<T extends {
|
|
80
|
+
$columns: TableColumns;
|
|
81
|
+
}> = {
|
|
82
|
+
[K in keyof T['$columns']]: GetColumnType<T['$columns'][K]>;
|
|
83
|
+
};
|
|
84
|
+
export type InferInsertModel<T extends {
|
|
85
|
+
$columns: TableColumns;
|
|
86
|
+
}> = TableInsert<T['$columns']>;
|
|
87
|
+
export type TableDefinition<TCols extends TableColumns, TOptions = TableOptions> = {
|
|
88
|
+
$table: string;
|
|
89
|
+
$columns: TCols;
|
|
90
|
+
$options: TOptions;
|
|
91
|
+
$relations?: Record<string, RelationDefinition>;
|
|
92
|
+
toSQL(): string;
|
|
93
|
+
toSQLs?(): string[];
|
|
94
|
+
as(alias: string): TableDefinition<TCols, TOptions>;
|
|
95
|
+
$inferSelect?: InferSelectModel<{
|
|
96
|
+
$columns: TCols;
|
|
97
|
+
}>;
|
|
98
|
+
$inferInsert?: InferInsertModel<{
|
|
99
|
+
$columns: TCols;
|
|
100
|
+
}>;
|
|
101
|
+
} & TCols;
|
|
102
|
+
export interface VersionedMeta {
|
|
103
|
+
baseName: string;
|
|
104
|
+
version: string | number;
|
|
105
|
+
aliasName?: string;
|
|
106
|
+
}
|
|
107
|
+
type CommonViewOptions = {
|
|
108
|
+
onCluster?: string;
|
|
109
|
+
orReplace?: boolean;
|
|
110
|
+
};
|
|
111
|
+
export interface ViewOptions extends CommonViewOptions {
|
|
112
|
+
kind?: 'view';
|
|
113
|
+
}
|
|
114
|
+
export interface MaterializedViewOptions extends CommonViewOptions {
|
|
115
|
+
kind?: 'materializedView';
|
|
116
|
+
toTable?: string;
|
|
117
|
+
engine?: EngineConfiguration;
|
|
118
|
+
populate?: boolean;
|
|
119
|
+
}
|
|
120
|
+
export declare function chTable<T extends Record<string, ClickHouseColumn<any, any, any>>>(tableName: string, columns: T, options?: TableOptions): TableDefinition<T, TableOptions>;
|
|
121
|
+
export declare function chView<T extends Record<string, ClickHouseColumn<any, any, any>>>(name: string, columns: T, options: ViewOptions & {
|
|
122
|
+
query: string;
|
|
123
|
+
}): TableDefinition<T, ViewOptions & {
|
|
124
|
+
kind: 'view';
|
|
125
|
+
query: string;
|
|
126
|
+
}> & {
|
|
127
|
+
toSQLs: () => string[];
|
|
128
|
+
};
|
|
129
|
+
export declare function chView<T extends Record<string, ClickHouseColumn<any, any, any>>>(name: string, columns: T, query: string, options?: ViewOptions): TableDefinition<T, ViewOptions & {
|
|
130
|
+
kind: 'view';
|
|
131
|
+
query: string;
|
|
132
|
+
}> & {
|
|
133
|
+
toSQLs: () => string[];
|
|
134
|
+
};
|
|
135
|
+
/**
|
|
136
|
+
* Define a reusable set of columns with type inference.
|
|
137
|
+
*/
|
|
138
|
+
export declare function defineColumns<T extends TableColumns>(cols: T): T;
|
|
139
|
+
/**
|
|
140
|
+
* Compose column sets, throwing on duplicate keys to avoid accidental overrides.
|
|
141
|
+
*/
|
|
142
|
+
export declare function extendColumns<Base extends TableColumns, Extra extends TableColumns>(base: Base, extra: Extra): Base & Extra;
|
|
143
|
+
/**
|
|
144
|
+
* Define a versioned table (e.g., base_v2) with optional view alias to point to the latest version.
|
|
145
|
+
*/
|
|
146
|
+
export declare function versionedTable<T extends TableColumns>(baseName: string, version: string | number, columns: T, options?: TableOptions & {
|
|
147
|
+
latestAlias?: boolean;
|
|
148
|
+
aliasName?: string;
|
|
149
|
+
}): TableDefinition<T> & {
|
|
150
|
+
$versionMeta: VersionedMeta;
|
|
151
|
+
toSQLs: () => string[];
|
|
152
|
+
};
|
|
153
|
+
/**
|
|
154
|
+
* Define a derived (aggregated) table with a backing table and materialized view.
|
|
155
|
+
*/
|
|
156
|
+
export declare function deriveTable<T extends TableColumns>(source: TableDefinition<T>, config: {
|
|
157
|
+
name: string;
|
|
158
|
+
groupBy: string | string[];
|
|
159
|
+
aggregates: Record<string, string>;
|
|
160
|
+
options?: TableOptions;
|
|
161
|
+
}): TableDefinition<any> & {
|
|
162
|
+
toSQLs: () => string[];
|
|
163
|
+
};
|
|
164
|
+
/**
|
|
165
|
+
* Render CREATE statements for preview.
|
|
166
|
+
*/
|
|
167
|
+
export declare function renderSchema(def: TableDefinition<any>): any;
|
|
168
|
+
/**
|
|
169
|
+
* Generate a TypeScript type from a table definition (best effort mapping).
|
|
170
|
+
*/
|
|
171
|
+
export declare function generateTypes<T extends TableColumns>(def: TableDefinition<T>, typeName?: string): string;
|
|
172
|
+
export {};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { ClickHouseClient } from '@clickhouse/client';
|
|
2
|
+
import type { TableDefinition } from '../core';
|
|
3
|
+
export interface BatchConfig {
|
|
4
|
+
maxRows: number;
|
|
5
|
+
flushIntervalMs: number;
|
|
6
|
+
}
|
|
7
|
+
declare class BackgroundBatcher {
|
|
8
|
+
private client;
|
|
9
|
+
private queues;
|
|
10
|
+
private timers;
|
|
11
|
+
private tables;
|
|
12
|
+
private serializers;
|
|
13
|
+
constructor(client: ClickHouseClient);
|
|
14
|
+
private getSerializer;
|
|
15
|
+
add(table: TableDefinition<any>, row: any, config: BatchConfig): Promise<void>;
|
|
16
|
+
flush(tableName: string): Promise<void>;
|
|
17
|
+
flushAll(): Promise<void>;
|
|
18
|
+
}
|
|
19
|
+
export declare const globalBatcher: (client: ClickHouseClient) => BackgroundBatcher;
|
|
20
|
+
export {};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Transform, type TransformCallback } from 'stream';
|
|
2
|
+
import { InsertPlan } from './insert-processing';
|
|
3
|
+
export interface BatchTransformOptions {
|
|
4
|
+
batchSize?: number;
|
|
5
|
+
maxProcessingTime?: number;
|
|
6
|
+
}
|
|
7
|
+
export declare class BatchTransformStream extends Transform {
|
|
8
|
+
private plan;
|
|
9
|
+
private mode;
|
|
10
|
+
private batch;
|
|
11
|
+
private processingTimer;
|
|
12
|
+
private readonly batchSize;
|
|
13
|
+
private readonly maxProcessingTime;
|
|
14
|
+
constructor(plan: InsertPlan, mode: 'compact' | 'json', options?: BatchTransformOptions);
|
|
15
|
+
_transform(chunk: any, _encoding: BufferEncoding, callback: TransformCallback): void;
|
|
16
|
+
_flush(callback: TransformCallback): void;
|
|
17
|
+
private scheduleProcessing;
|
|
18
|
+
private processBatch;
|
|
19
|
+
}
|
|
20
|
+
export declare function createBatchTransformStream(plan: InsertPlan, mode: 'compact' | 'json', options?: BatchTransformOptions): BatchTransformStream;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HouseKit Binary Reader - Ultra-Fast RowBinary Decoding
|
|
3
|
+
*
|
|
4
|
+
* optimized for reading ClickHouse RowBinary format directly from buffers.
|
|
5
|
+
* This is 10-20x faster than JSON.parse() for large datasets.
|
|
6
|
+
*/
|
|
7
|
+
export declare class BinaryReader {
|
|
8
|
+
private buffer;
|
|
9
|
+
private offset;
|
|
10
|
+
private view;
|
|
11
|
+
constructor(buffer: Buffer);
|
|
12
|
+
reset(buffer: Buffer): void;
|
|
13
|
+
getOffset(): number;
|
|
14
|
+
isEOF(): boolean;
|
|
15
|
+
readInt8(): number;
|
|
16
|
+
readUInt8(): number;
|
|
17
|
+
readInt16(): number;
|
|
18
|
+
readUInt16(): number;
|
|
19
|
+
readInt32(): number;
|
|
20
|
+
readUInt32(): number;
|
|
21
|
+
readInt64(): bigint;
|
|
22
|
+
readUInt64(): bigint;
|
|
23
|
+
readInt128(): bigint;
|
|
24
|
+
readUInt128(): bigint;
|
|
25
|
+
readInt256(): bigint;
|
|
26
|
+
readUInt256(): bigint;
|
|
27
|
+
readFloat32(): number;
|
|
28
|
+
readFloat64(): number;
|
|
29
|
+
readVarInt(): number;
|
|
30
|
+
readString(): string;
|
|
31
|
+
readFixedString(length: number): string;
|
|
32
|
+
readUUID(): string;
|
|
33
|
+
readDate(): string;
|
|
34
|
+
readDate32(): string;
|
|
35
|
+
readDateTime(): Date;
|
|
36
|
+
readDateTime64(precision?: number): Date;
|
|
37
|
+
readNullable<T>(reader: () => T): T | null;
|
|
38
|
+
readArray<T>(itemReader: () => T): T[];
|
|
39
|
+
readMap<K, V>(keyReader: () => K, valueReader: () => V): Record<any, any>;
|
|
40
|
+
readDecimal32(scale: number): number;
|
|
41
|
+
readDecimal64(scale: number): number;
|
|
42
|
+
readDecimal128(scale: number): number;
|
|
43
|
+
readBool(): boolean;
|
|
44
|
+
readIPv4(): string;
|
|
45
|
+
readIPv6(): string;
|
|
46
|
+
}
|
|
47
|
+
export type BinaryDecoder = (reader: BinaryReader) => any;
|
|
48
|
+
export declare function createBinaryDecoder(type: string): BinaryDecoder;
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HouseKit Binary Serializer - Ultra-Fast RowBinary Encoding
|
|
3
|
+
*
|
|
4
|
+
* ClickHouse's RowBinary format sends data directly as bytes with no parsing overhead.
|
|
5
|
+
* This is the fastest possible way to insert data into ClickHouse.
|
|
6
|
+
*
|
|
7
|
+
* Benefits over JSONEachRow:
|
|
8
|
+
* - No JSON.stringify() overhead
|
|
9
|
+
* - No string escaping
|
|
10
|
+
* - No parsing on ClickHouse side
|
|
11
|
+
* - Smaller payload (Int64 = 8 bytes vs up to 20 bytes as string)
|
|
12
|
+
* - Lower GC pressure (no intermediate strings)
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* Efficient binary buffer writer that minimizes allocations.
|
|
16
|
+
* Uses a pre-allocated buffer that grows as needed.
|
|
17
|
+
*/
|
|
18
|
+
export declare class BinaryWriter {
|
|
19
|
+
private buffer;
|
|
20
|
+
private offset;
|
|
21
|
+
constructor(initialSize?: number);
|
|
22
|
+
/**
|
|
23
|
+
* Ensure buffer has enough space for n more bytes
|
|
24
|
+
*/
|
|
25
|
+
private ensureCapacity;
|
|
26
|
+
/**
|
|
27
|
+
* Reset the writer for reuse (avoids allocating new buffer)
|
|
28
|
+
*/
|
|
29
|
+
reset(): void;
|
|
30
|
+
/**
|
|
31
|
+
* Get the final buffer with only written bytes
|
|
32
|
+
*/
|
|
33
|
+
getBuffer(): Buffer;
|
|
34
|
+
/**
|
|
35
|
+
* Get a copy of the buffer (safe to use after reset)
|
|
36
|
+
*/
|
|
37
|
+
toBuffer(): Buffer;
|
|
38
|
+
writeInt8(value: number): void;
|
|
39
|
+
writeUInt8(value: number): void;
|
|
40
|
+
writeInt16(value: number): void;
|
|
41
|
+
writeUInt16(value: number): void;
|
|
42
|
+
writeInt32(value: number): void;
|
|
43
|
+
writeUInt32(value: number): void;
|
|
44
|
+
writeInt64(value: bigint | number): void;
|
|
45
|
+
writeUInt64(value: bigint | number): void;
|
|
46
|
+
writeInt128(value: bigint): void;
|
|
47
|
+
writeUInt128(value: bigint): void;
|
|
48
|
+
writeInt256(value: bigint): void;
|
|
49
|
+
writeUInt256(value: bigint): void;
|
|
50
|
+
writeFloat32(value: number): void;
|
|
51
|
+
writeFloat64(value: number): void;
|
|
52
|
+
/**
|
|
53
|
+
* Write a variable-length integer (LEB128).
|
|
54
|
+
* Used for string lengths in RowBinary format.
|
|
55
|
+
*/
|
|
56
|
+
writeVarInt(value: number): void;
|
|
57
|
+
/**
|
|
58
|
+
* Write a string in RowBinary format: [VarInt length][UTF-8 bytes]
|
|
59
|
+
*/
|
|
60
|
+
writeString(value: string): void;
|
|
61
|
+
/**
|
|
62
|
+
* Write a FixedString(N) - padded with null bytes if shorter
|
|
63
|
+
*/
|
|
64
|
+
writeFixedString(value: string, length: number): void;
|
|
65
|
+
/**
|
|
66
|
+
* Write raw bytes directly
|
|
67
|
+
*/
|
|
68
|
+
writeBytes(data: Buffer): void;
|
|
69
|
+
/**
|
|
70
|
+
* Write a UUID (16 bytes).
|
|
71
|
+
* ClickHouse stores UUIDs as two UInt64 in big-endian order!
|
|
72
|
+
* This is different from the usual little-endian storage.
|
|
73
|
+
*/
|
|
74
|
+
writeUUID(value: string): void;
|
|
75
|
+
/**
|
|
76
|
+
* Write a Date (days since epoch as UInt16)
|
|
77
|
+
*/
|
|
78
|
+
writeDate(value: Date | number): void;
|
|
79
|
+
/**
|
|
80
|
+
* Write a Date32 (days since epoch as Int32)
|
|
81
|
+
*/
|
|
82
|
+
writeDate32(value: Date | number): void;
|
|
83
|
+
/**
|
|
84
|
+
* Write a DateTime (seconds since epoch as UInt32)
|
|
85
|
+
*/
|
|
86
|
+
writeDateTime(value: Date | number): void;
|
|
87
|
+
/**
|
|
88
|
+
* Write a DateTime64 with specified precision
|
|
89
|
+
*/
|
|
90
|
+
writeDateTime64(value: Date | number, precision?: number): void;
|
|
91
|
+
/**
|
|
92
|
+
* Write a nullable prefix (0 = not null, 1 = null)
|
|
93
|
+
*/
|
|
94
|
+
writeNullable(isNull: boolean): void;
|
|
95
|
+
/**
|
|
96
|
+
* Write array length prefix
|
|
97
|
+
*/
|
|
98
|
+
writeArrayLength(length: number): void;
|
|
99
|
+
/**
|
|
100
|
+
* Write Decimal32 (stored as Int32)
|
|
101
|
+
*/
|
|
102
|
+
writeDecimal32(value: number, scale: number): void;
|
|
103
|
+
/**
|
|
104
|
+
* Write Decimal64 (stored as Int64)
|
|
105
|
+
*/
|
|
106
|
+
writeDecimal64(value: number, scale: number): void;
|
|
107
|
+
/**
|
|
108
|
+
* Write Decimal128 (stored as Int128)
|
|
109
|
+
*/
|
|
110
|
+
writeDecimal128(value: number | bigint, scale: number): void;
|
|
111
|
+
writeBool(value: boolean): void;
|
|
112
|
+
/**
|
|
113
|
+
* Write IPv4 address (UInt32 in network byte order)
|
|
114
|
+
*/
|
|
115
|
+
writeIPv4(value: string | number): void;
|
|
116
|
+
/**
|
|
117
|
+
* Write IPv6 address (16 bytes)
|
|
118
|
+
*/
|
|
119
|
+
writeIPv6(value: string | Buffer): void;
|
|
120
|
+
private expandIPv6;
|
|
121
|
+
writeEnum8(value: number): void;
|
|
122
|
+
writeEnum16(value: number): void;
|
|
123
|
+
}
|
|
124
|
+
export type BinaryEncoder = (writer: BinaryWriter, value: any) => void;
|
|
125
|
+
/**
|
|
126
|
+
* Create a binary encoder for a ClickHouse column type
|
|
127
|
+
*/
|
|
128
|
+
export declare function createBinaryEncoder(clickhouseType: string, isNullable?: boolean): BinaryEncoder;
|
|
129
|
+
/**
|
|
130
|
+
* Configuration for binary serialization
|
|
131
|
+
*/
|
|
132
|
+
export interface BinarySerializationConfig {
|
|
133
|
+
/** Column names in order */
|
|
134
|
+
columns: Array<{
|
|
135
|
+
name: string;
|
|
136
|
+
type: string;
|
|
137
|
+
isNullable: boolean;
|
|
138
|
+
}>;
|
|
139
|
+
/** Property key mapping (propKey -> column index) */
|
|
140
|
+
keyMapping: Map<string, number>;
|
|
141
|
+
/** Pre-compiled encoders for each column */
|
|
142
|
+
encoders: BinaryEncoder[];
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Build a binary serialization configuration from a table definition
|
|
146
|
+
*/
|
|
147
|
+
export declare function buildBinaryConfig(columns: Array<{
|
|
148
|
+
name: string;
|
|
149
|
+
type: string;
|
|
150
|
+
isNull: boolean;
|
|
151
|
+
propKey: string;
|
|
152
|
+
}>): BinarySerializationConfig;
|
|
153
|
+
/**
|
|
154
|
+
* Serialize a single row to RowBinary format
|
|
155
|
+
*/
|
|
156
|
+
export declare function serializeRowBinary(row: Record<string, any>, config: BinarySerializationConfig, writer?: BinaryWriter): Buffer;
|
|
157
|
+
/**
|
|
158
|
+
* Serialize multiple rows to a single RowBinary buffer
|
|
159
|
+
*/
|
|
160
|
+
export declare function serializeRowsBinary(rows: Array<Record<string, any>>, config: BinarySerializationConfig): Buffer;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const binaryWorkerCode = "import{parentPort as D,workerData as d}from\"worker_threads\";var X=[];for(let x=0;x<256;++x)X.push((x+256).toString(16).slice(1));function B(x,U=0){return(X[x[U+0]]+X[x[U+1]]+X[x[U+2]]+X[x[U+3]]+\"-\"+X[x[U+4]]+X[x[U+5]]+\"-\"+X[x[U+6]]+X[x[U+7]]+\"-\"+X[x[U+8]]+X[x[U+9]]+\"-\"+X[x[U+10]]+X[x[U+11]]+X[x[U+12]]+X[x[U+13]]+X[x[U+14]]+X[x[U+15]]).toLowerCase()}import{randomFillSync as o}from\"node:crypto\";var N=new Uint8Array(256),G=N.length;function P(){if(G>N.length-16)o(N),G=0;return N.slice(G,G+=16)}import{randomUUID as n}from\"node:crypto\";var S={randomUUID:n};function y(x,U,I){x=x||{};let A=x.random??x.rng?.()??P();if(A.length<16)throw Error(\"Random bytes length must be >= 16\");if(A[6]=A[6]&15|64,A[8]=A[8]&63|128,U){if(I=I||0,I<0||I+16>U.length)throw RangeError(`UUID byte range ${I}:${I+15} is out of buffer bounds`);for(let H=0;H<16;++H)U[I+H]=A[H];return U}return B(A)}function p(x,U,I){if(S.randomUUID&&!U&&!x)return S.randomUUID();return y(x,U,I)}var W=p;class z{buffer;offset=0;constructor(x=4096){this.buffer=Buffer.allocUnsafe(x)}ensureCapacity(x){let U=this.offset+x;if(U>this.buffer.length){let I=Math.max(this.buffer.length*2,U),A=Buffer.allocUnsafe(I);this.buffer.copy(A,0,0,this.offset),this.buffer=A}}reset(){this.offset=0}getBuffer(){return this.buffer.subarray(0,this.offset)}toBuffer(){return Buffer.from(this.buffer.subarray(0,this.offset))}writeInt8(x){this.ensureCapacity(1),this.buffer.writeInt8(x,this.offset),this.offset+=1}writeUInt8(x){this.ensureCapacity(1),this.buffer.writeUInt8(x,this.offset),this.offset+=1}writeInt16(x){this.ensureCapacity(2),this.buffer.writeInt16LE(x,this.offset),this.offset+=2}writeUInt16(x){this.ensureCapacity(2),this.buffer.writeUInt16LE(x,this.offset),this.offset+=2}writeInt32(x){this.ensureCapacity(4),this.buffer.writeInt32LE(x,this.offset),this.offset+=4}writeUInt32(x){this.ensureCapacity(4),this.buffer.writeUInt32LE(x,this.offset),this.offset+=4}writeInt64(x){this.ensureCapacity(8),this.buffer.writeBigInt64LE(BigInt(x),this.offset),this.offset+=8}writeUInt64(x){this.ensureCapacity(8),this.buffer.writeBigUInt64LE(BigInt(x),this.offset),this.offset+=8}writeInt128(x){this.ensureCapacity(16);let U=x&BigInt(\"0xFFFFFFFFFFFFFFFF\"),I=x>>BigInt(64);this.buffer.writeBigUInt64LE(U,this.offset),this.buffer.writeBigInt64LE(I,this.offset+8),this.offset+=16}writeUInt128(x){this.ensureCapacity(16);let U=x&BigInt(\"0xFFFFFFFFFFFFFFFF\"),I=x>>BigInt(64);this.buffer.writeBigUInt64LE(U,this.offset),this.buffer.writeBigUInt64LE(I,this.offset+8),this.offset+=16}writeInt256(x){this.ensureCapacity(32);for(let U=0;U<4;U++){let I=x&BigInt(\"0xFFFFFFFFFFFFFFFF\");this.buffer.writeBigUInt64LE(I,this.offset+U*8),x>>=BigInt(64)}this.offset+=32}writeUInt256(x){this.writeInt256(x)}writeFloat32(x){this.ensureCapacity(4),this.buffer.writeFloatLE(x,this.offset),this.offset+=4}writeFloat64(x){this.ensureCapacity(8),this.buffer.writeDoubleLE(x,this.offset),this.offset+=8}writeVarInt(x){if(x<128){this.ensureCapacity(1),this.buffer[this.offset++]=x;return}if(x<16384){this.ensureCapacity(2),this.buffer[this.offset++]=x&127|128,this.buffer[this.offset++]=x>>7;return}if(x<2097152){this.ensureCapacity(3),this.buffer[this.offset++]=x&127|128,this.buffer[this.offset++]=x>>7&127|128,this.buffer[this.offset++]=x>>14;return}this.ensureCapacity(10);while(x>=128)this.buffer[this.offset++]=x&127|128,x>>>=7;this.buffer[this.offset++]=x}writeString(x){let U=Buffer.from(x,\"utf-8\");this.writeVarInt(U.length),this.ensureCapacity(U.length),U.copy(this.buffer,this.offset),this.offset+=U.length}writeFixedString(x,U){this.ensureCapacity(U);let I=Buffer.from(x,\"utf-8\"),A=Math.min(I.length,U);if(I.copy(this.buffer,this.offset,0,A),A<U)this.buffer.fill(0,this.offset+A,this.offset+U);this.offset+=U}writeBytes(x){this.ensureCapacity(x.length),x.copy(this.buffer,this.offset),this.offset+=x.length}writeUUID(x){this.ensureCapacity(16);let U=x.replace(/-/g,\"\");if(U.length!==32)throw Error(`Invalid UUID: ${x}`);let I=Buffer.from(U,\"hex\");for(let A=7;A>=0;A--)this.buffer[this.offset++]=I[A];for(let A=15;A>=8;A--)this.buffer[this.offset++]=I[A]}writeDate(x){let U=typeof x===\"number\"?x:Math.floor(x.getTime()/86400000);this.writeUInt16(U)}writeDate32(x){let U=typeof x===\"number\"?x:Math.floor(x.getTime()/86400000);this.writeInt32(U)}writeDateTime(x){let U=typeof x===\"number\"?x:Math.floor(x.getTime()/1000);this.writeUInt32(U)}writeDateTime64(x,U=3){let I=Math.pow(10,U),A=typeof x===\"number\"?BigInt(Math.round(x*I)):BigInt(Math.round(x.getTime()*I/1000));this.writeInt64(A)}writeNullable(x){this.writeUInt8(x?1:0)}writeArrayLength(x){this.writeUInt64(x)}writeDecimal32(x,U){let I=Math.round(x*Math.pow(10,U));this.writeInt32(I)}writeDecimal64(x,U){let I=BigInt(Math.round(x*Math.pow(10,U)));this.writeInt64(I)}writeDecimal128(x,U){let I;if(typeof x===\"bigint\")I=x*BigInt(Math.pow(10,U));else I=BigInt(Math.round(x*Math.pow(10,U)));this.writeInt128(I)}writeBool(x){this.writeUInt8(x?1:0)}writeIPv4(x){if(typeof x===\"number\"){this.writeUInt32(x);return}let U=x.split(\".\").map(Number);if(U.length!==4)throw Error(`Invalid IPv4: ${x}`);let I=U[0]<<24|U[1]<<16|U[2]<<8|U[3];this.writeUInt32(I>>>0)}writeIPv6(x){if(Buffer.isBuffer(x)){if(x.length!==16)throw Error(\"IPv6 must be 16 bytes\");this.writeBytes(x);return}let I=this.expandIPv6(x).split(\":\");this.ensureCapacity(16);for(let A of I){let H=parseInt(A,16);this.buffer.writeUInt16BE(H,this.offset),this.offset+=2}}expandIPv6(x){let U=x.split(\"::\");if(U.length===1)return x;let I=U[0]?U[0].split(\":\"):[],A=U[1]?U[1].split(\":\"):[],H=8-I.length-A.length,K=Array(H).fill(\"0000\");return[...I,...K,...A].map((L)=>L.padStart(4,\"0\")).join(\":\")}writeEnum8(x){this.writeInt8(x)}writeEnum16(x){this.writeInt16(x)}}function m(x){let U=[],I=\"\",A=0;for(let H=0;H<x.length;H++){let K=x[H];if(K===\",\"&&A===0)U.push(I.trim()),I=\"\";else{if(K===\"(\")A++;if(K===\")\")A--;I+=K}}if(I.trim())U.push(I.trim());return U}function Q(x,U=!1){let I=x.toLowerCase().trim(),A=I.match(/^nullable\\((.+)\\)$/);if(A){let C=Q(A[1],!1);return($,F)=>{if(F===null||F===void 0)$.writeNullable(!0);else $.writeNullable(!1),C($,F)}}let H=I.match(/^array\\((.+)\\)$/);if(H){let C=Q(H[1],!1);return($,F)=>{let O=Array.isArray(F)?F:[];$.writeArrayLength(O.length);for(let J of O)C($,J)}}let K=I.match(/^map\\((.+)\\)$/);if(K){let[C,$]=m(K[1]);if(!C||!$)throw Error(`Invalid Map type: ${I}`);let F=Q(C),O=Q($);return(J,j)=>{let V;if(j instanceof Map)V=Array.from(j.entries());else if(typeof j===\"object\"&&j!==null)V=Object.entries(j);else V=[];J.writeUInt64(V.length);for(let[Y,q]of V)F(J,Y),O(J,q)}}let L=I.match(/^tuple\\((.+)\\)$/);if(L){let $=m(L[1]).map((F)=>Q(F));return(F,O)=>{let J=Array.isArray(O)?O:[];for(let j=0;j<$.length;j++)$[j](F,J[j])}}let T=I.match(/^nested\\((.+)\\)$/);if(T){let C=m(T[1]),F=`Tuple(${C.map((J)=>{let j=J.trim().split(/\\s+/);if(j.length<2)return\"String\";return j.slice(1).join(\" \")}).join(\", \")})`,O=Q(F);return(J,j)=>{let V=Array.isArray(j)?j:[];J.writeArrayLength(V.length);for(let Y of V){let q=Y;if(!Array.isArray(Y)&&typeof Y===\"object\")q=C.map((h)=>{let g=h.trim().split(/\\s+/)[0];return Y[g]});O(J,q)}}}let b=I.match(/^lowcardinality\\((.+)\\)$/);if(b)return Q(b[1]);let k=I.match(/^fixedstring\\((\\d+)\\)$/);if(k){let C=parseInt(k[1],10);return($,F)=>{$.writeFixedString(String(F??\"\"),C)}}let E=I.match(/^decimal(?:32|64|128)?\\((\\d+),\\s*(\\d+)\\)$/);if(E){let C=parseInt(E[2],10);if(I.includes(\"decimal128\"))return($,F)=>$.writeDecimal128(F,C);if(I.includes(\"decimal64\"))return($,F)=>$.writeDecimal64(F,C);return($,F)=>$.writeDecimal32(F,C)}let M=I.match(/^datetime64\\((\\d+)/);if(M){let C=parseInt(M[1],10);return($,F)=>$.writeDateTime64(F,C)}if(I.match(/^enum8\\(/))return(C,$)=>C.writeEnum8(Number($));if(I.match(/^enum16\\(/))return(C,$)=>C.writeEnum16(Number($));let R=w(I);if(U)return(C,$)=>{if($===null||$===void 0)C.writeNullable(!0);else C.writeNullable(!1),R(C,$)};if(I===\"uuid\")return(C,$)=>{if($===void 0||$===null)R(C,W());else R(C,$)};return R}function w(x){if(x===\"int8\")return(U,I)=>U.writeInt8(Number(I));if(x===\"uint8\")return(U,I)=>U.writeUInt8(Number(I));if(x===\"int16\")return(U,I)=>U.writeInt16(Number(I));if(x===\"uint16\")return(U,I)=>U.writeUInt16(Number(I));if(x===\"int32\")return(U,I)=>U.writeInt32(Number(I));if(x===\"uint32\")return(U,I)=>U.writeUInt32(Number(I));if(x===\"int64\")return(U,I)=>U.writeInt64(I);if(x===\"uint64\")return(U,I)=>U.writeUInt64(I);if(x===\"int128\")return(U,I)=>U.writeInt128(BigInt(I));if(x===\"uint128\")return(U,I)=>U.writeUInt128(BigInt(I));if(x===\"int256\")return(U,I)=>U.writeInt256(BigInt(I));if(x===\"uint256\")return(U,I)=>U.writeUInt256(BigInt(I));if(x===\"float32\")return(U,I)=>U.writeFloat32(Number(I));if(x===\"float64\")return(U,I)=>U.writeFloat64(Number(I));if(x===\"string\")return(U,I)=>U.writeString(String(I??\"\"));if(x===\"uuid\")return(U,I)=>U.writeUUID(String(I));if(x===\"date\")return(U,I)=>U.writeDate(I);if(x===\"date32\")return(U,I)=>U.writeDate32(I);if(x===\"datetime\")return(U,I)=>U.writeDateTime(I);if(x.startsWith(\"datetime64\"))return(U,I)=>U.writeDateTime64(I,3);if(x===\"bool\"||x===\"boolean\")return(U,I)=>U.writeBool(Boolean(I));if(x===\"ipv4\")return(U,I)=>U.writeIPv4(I);if(x===\"ipv6\")return(U,I)=>U.writeIPv6(I);return(U,I)=>U.writeString(String(I??\"\"))}var Z=null,_=null;function s(x,U){if(!Z||!_)throw Error(\"Worker not configured\");_.reset();for(let I of x)for(let A=0;A<Z.columns.length;A++){let H=Z.columns[A],K=I[H.name];Z.encoders[A](_,K)}return _.toBuffer()}function f(x){try{switch(x.type){case\"configure\":{let U=x.columns.map((I)=>Q(I.type,I.isNullable));Z={columns:x.columns,keyMapping:new Map,encoders:U},_=new z(1048576),D?.postMessage({type:\"ready\"});break}case\"serialize\":{let U=s(x.rows,x.batchId),I=new ArrayBuffer(U.length);new Uint8Array(I).set(U),D?.postMessage({type:\"result\",batchId:x.batchId,buffer:Buffer.from(I),rowCount:x.rows.length},[I]);break}case\"shutdown\":process.exit(0)}}catch(U){D?.postMessage({type:\"error\",batchId:x.batchId,error:U instanceof Error?U.message:String(U)})}}if(D){if(D.on(\"message\",f),d?.columns)f({type:\"configure\",columns:d.columns})}\n";
|