@housekit/orm 0.1.43 → 0.1.44

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.
@@ -254,25 +254,20 @@ export declare class ClickHouseQueryBuilder<TTable extends TableDefinition<any>
254
254
  stream(): AsyncIterableIterator<TResult>;
255
255
  /**
256
256
  * Native binary mode for high-performance data retrieval.
257
- * Reads data using ClickHouse 'RowBinary' format and parses it directly in Node.js.
258
- * Up to 10x faster than standard JSON select for large datasets.
259
257
  *
260
- * Requirements: All selected columns must be strictly typed (ClickHouseColumn instances).
258
+ * @deprecated RowBinary streaming is not supported by @clickhouse/client 1.15+.
259
+ * Use standard select() which uses optimized JSONEachRow format.
261
260
  */
262
261
  native(): Promise<TResult[]>;
263
262
  /**
264
263
  * Vector mode for columnar data retrieval.
265
- * Returns data in Columnar format (TypedArrays) instead of Row-based objects.
266
- * Ideal for analytical processing, charting, or passing to libraries like Apache Arrow.
267
264
  *
268
- * @example
269
- * const { prices } = await db.select({ prices: trades.price }).vector();
270
- * // prices is a Float64Array
265
+ * @deprecated RowBinary streaming is not supported by @clickhouse/client 1.15+.
266
+ * Use standard select() which uses optimized JSONEachRow format.
271
267
  */
272
268
  vector(): Promise<{
273
269
  [K in keyof TResult]: TResult[K] extends number ? (TResult[K] extends number ? Float64Array | Int32Array : Array<TResult[K]>) : Array<TResult[K]>;
274
270
  }>;
275
- private executeBinary;
276
271
  explain(): Promise<any>;
277
272
  explainPipeline(): Promise<any>;
278
273
  /**
package/dist/index.js CHANGED
@@ -15,379 +15,8 @@ var __toESM = (mod, isNodeMode, target) => {
15
15
  });
16
16
  return to;
17
17
  };
18
- var __export = (target, all) => {
19
- for (var name in all)
20
- __defProp(target, name, {
21
- get: all[name],
22
- enumerable: true,
23
- configurable: true,
24
- set: (newValue) => all[name] = () => newValue
25
- });
26
- };
27
18
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
28
19
 
29
- // src/utils/binary-reader.ts
30
- var exports_binary_reader = {};
31
- __export(exports_binary_reader, {
32
- createBinaryDecoder: () => createBinaryDecoder,
33
- BinaryReader: () => BinaryReader
34
- });
35
-
36
- class BinaryReader {
37
- buffer;
38
- offset = 0;
39
- view;
40
- constructor(buffer) {
41
- this.buffer = buffer;
42
- this.view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength);
43
- }
44
- reset(buffer) {
45
- this.buffer = buffer;
46
- this.offset = 0;
47
- this.view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength);
48
- }
49
- getOffset() {
50
- return this.offset;
51
- }
52
- isEOF() {
53
- return this.offset >= this.buffer.length;
54
- }
55
- readInt8() {
56
- const val = this.view.getInt8(this.offset);
57
- this.offset += 1;
58
- return val;
59
- }
60
- readUInt8() {
61
- const val = this.view.getUint8(this.offset);
62
- this.offset += 1;
63
- return val;
64
- }
65
- readInt16() {
66
- const val = this.view.getInt16(this.offset, true);
67
- this.offset += 2;
68
- return val;
69
- }
70
- readUInt16() {
71
- const val = this.view.getUint16(this.offset, true);
72
- this.offset += 2;
73
- return val;
74
- }
75
- readInt32() {
76
- const val = this.view.getInt32(this.offset, true);
77
- this.offset += 4;
78
- return val;
79
- }
80
- readUInt32() {
81
- const val = this.view.getUint32(this.offset, true);
82
- this.offset += 4;
83
- return val;
84
- }
85
- readInt64() {
86
- const val = this.view.getBigInt64(this.offset, true);
87
- this.offset += 8;
88
- return val;
89
- }
90
- readUInt64() {
91
- const val = this.view.getBigUint64(this.offset, true);
92
- this.offset += 8;
93
- return val;
94
- }
95
- readInt128() {
96
- const low = this.view.getBigUint64(this.offset, true);
97
- const high = this.view.getBigInt64(this.offset + 8, true);
98
- this.offset += 16;
99
- return high << 64n | low;
100
- }
101
- readUInt128() {
102
- const low = this.view.getBigUint64(this.offset, true);
103
- const high = this.view.getBigUint64(this.offset + 8, true);
104
- this.offset += 16;
105
- return high << 64n | low;
106
- }
107
- readInt256() {
108
- let val = 0n;
109
- for (let i = 0;i < 4; i++) {
110
- const word = this.view.getBigUint64(this.offset + i * 8, true);
111
- val |= word << BigInt(i) * 64n;
112
- }
113
- this.offset += 32;
114
- return val;
115
- }
116
- readUInt256() {
117
- return this.readInt256();
118
- }
119
- readFloat32() {
120
- const val = this.view.getFloat32(this.offset, true);
121
- this.offset += 4;
122
- return val;
123
- }
124
- readFloat64() {
125
- const val = this.view.getFloat64(this.offset, true);
126
- this.offset += 8;
127
- return val;
128
- }
129
- readVarInt() {
130
- let result = 0;
131
- let shift = 0;
132
- while (true) {
133
- const byte = this.buffer[this.offset++];
134
- result |= (byte & 127) << shift;
135
- if ((byte & 128) === 0)
136
- break;
137
- shift += 7;
138
- }
139
- return result;
140
- }
141
- readString() {
142
- const len = this.readVarInt();
143
- if (len === 0)
144
- return "";
145
- const str = this.buffer.toString("utf-8", this.offset, this.offset + len);
146
- this.offset += len;
147
- return str;
148
- }
149
- readFixedString(length) {
150
- const str = this.buffer.toString("utf-8", this.offset, this.offset + length);
151
- this.offset += length;
152
- return str.replace(/\u0000+$/, "");
153
- }
154
- readUUID() {
155
- const bytes = this.buffer.subarray(this.offset, this.offset + 16);
156
- this.offset += 16;
157
- const hex = Buffer.allocUnsafe(16);
158
- for (let i = 0;i < 8; i++) {
159
- hex[i] = bytes[7 - i];
160
- }
161
- for (let i = 0;i < 8; i++) {
162
- hex[8 + i] = bytes[15 - i];
163
- }
164
- const s = hex.toString("hex");
165
- return `${s.slice(0, 8)}-${s.slice(8, 12)}-${s.slice(12, 16)}-${s.slice(16, 20)}-${s.slice(20)}`;
166
- }
167
- readDate() {
168
- const days = this.readUInt16();
169
- const date = new Date(days * 24 * 60 * 60 * 1000);
170
- return date.toISOString().split("T")[0];
171
- }
172
- readDate32() {
173
- const days = this.readInt32();
174
- const date = new Date(days * 24 * 60 * 60 * 1000);
175
- return date.toISOString().split("T")[0];
176
- }
177
- readDateTime() {
178
- const seconds = this.readUInt32();
179
- return new Date(seconds * 1000);
180
- }
181
- readDateTime64(precision = 3) {
182
- const ticks = this.readInt64();
183
- const divisor = BigInt(Math.pow(10, precision));
184
- let ms;
185
- if (precision === 3) {
186
- ms = ticks;
187
- } else if (precision > 3) {
188
- ms = ticks / BigInt(Math.pow(10, precision - 3));
189
- } else {
190
- ms = ticks * BigInt(Math.pow(10, 3 - precision));
191
- }
192
- return new Date(Number(ms));
193
- }
194
- readNullable(reader) {
195
- const isNull2 = this.readUInt8();
196
- if (isNull2 === 1)
197
- return null;
198
- return reader();
199
- }
200
- readArray(itemReader) {
201
- const lenBig = this.readUInt64();
202
- const length = Number(lenBig);
203
- const res = new Array(length);
204
- for (let i = 0;i < length; i++) {
205
- res[i] = itemReader();
206
- }
207
- return res;
208
- }
209
- readMap(keyReader, valueReader) {
210
- const lenBig = this.readUInt64();
211
- const length = Number(lenBig);
212
- const res = {};
213
- for (let i = 0;i < length; i++) {
214
- const key = keyReader();
215
- const value = valueReader();
216
- res[key] = value;
217
- }
218
- return res;
219
- }
220
- readDecimal32(scale) {
221
- const val = this.readInt32();
222
- return val / Math.pow(10, scale);
223
- }
224
- readDecimal64(scale) {
225
- const val = this.readInt64();
226
- return Number(val) / Math.pow(10, scale);
227
- }
228
- readDecimal128(scale) {
229
- const val = this.readInt128();
230
- return Number(val) / Math.pow(10, scale);
231
- }
232
- readBool() {
233
- return this.readUInt8() === 1;
234
- }
235
- readIPv4() {
236
- const val = this.readUInt32();
237
- return [
238
- val & 255,
239
- val >> 8 & 255,
240
- val >> 16 & 255,
241
- val >> 24 & 255
242
- ].join(".");
243
- }
244
- readIPv6() {
245
- const buffer = this.buffer.subarray(this.offset, this.offset + 16);
246
- this.offset += 16;
247
- const parts = [];
248
- for (let i = 0;i < 16; i += 2) {
249
- const group = buffer.readUInt16BE(i).toString(16);
250
- parts.push(group);
251
- }
252
- return parts.join(":").replace(/(^|:)0(:0)*:0(:|$)/, "::");
253
- }
254
- }
255
- function createBinaryDecoder(type) {
256
- const t = type.toLowerCase().trim();
257
- if (t.startsWith("nullable(")) {
258
- const inner = t.match(/^nullable\((.+)\)$/)[1];
259
- const innerDecoder = createBinaryDecoder(inner);
260
- return (r) => r.readNullable(() => innerDecoder(r));
261
- }
262
- if (t.startsWith("array(")) {
263
- const inner = t.match(/^array\((.+)\)$/)[1];
264
- const innerDecoder = createBinaryDecoder(inner);
265
- return (r) => r.readArray(() => innerDecoder(r));
266
- }
267
- if (t.startsWith("map(")) {
268
- const inner = t.match(/^map\((.+)\)$/)[1];
269
- const [keyType, valueType] = parseGenericTypes(inner);
270
- const keyDecoder = createBinaryDecoder(keyType);
271
- const valueDecoder = createBinaryDecoder(valueType);
272
- return (r) => r.readMap(() => keyDecoder(r), () => valueDecoder(r));
273
- }
274
- if (t.startsWith("tuple(")) {
275
- const inner = t.match(/^tuple\((.+)\)$/)[1];
276
- const types = parseGenericTypes(inner);
277
- const decoders = types.map((type2) => createBinaryDecoder(type2));
278
- return (r) => decoders.map((d) => d(r));
279
- }
280
- if (t.startsWith("nested(")) {
281
- const inner = t.match(/^nested\((.+)\)$/)[1];
282
- const fields = parseGenericTypes(inner);
283
- const types = fields.map((f) => {
284
- const parts = f.trim().split(/\s+/);
285
- return parts.length < 2 ? "String" : parts.slice(1).join(" ");
286
- });
287
- const tupleDecoders = types.map((type2) => createBinaryDecoder(type2));
288
- return (r) => r.readArray(() => tupleDecoders.map((d) => d(r)));
289
- }
290
- if (t.startsWith("lowcardinality(")) {
291
- const inner = t.match(/^lowcardinality\((.+)\)$/)[1];
292
- return createBinaryDecoder(inner);
293
- }
294
- if (t.startsWith("fixedstring(")) {
295
- const len = parseInt(t.match(/\d+/)[0], 10);
296
- return (r) => r.readFixedString(len);
297
- }
298
- if (t.startsWith("decimal")) {
299
- const match = t.match(/^decimal(?:32|64|128)?\((\d+),\s*(\d+)\)$/);
300
- if (match) {
301
- const scale = parseInt(match[2], 10);
302
- if (t.includes("decimal128"))
303
- return (r) => r.readDecimal128(scale);
304
- if (t.includes("decimal64"))
305
- return (r) => r.readDecimal64(scale);
306
- return (r) => r.readDecimal32(scale);
307
- }
308
- }
309
- if (t.startsWith("datetime64")) {
310
- const match = t.match(/^datetime64\((\d+)/);
311
- const precision = match ? parseInt(match[1], 10) : 3;
312
- return (r) => r.readDateTime64(precision);
313
- }
314
- if (t.startsWith("enum")) {
315
- if (t.startsWith("enum8"))
316
- return (r) => r.readInt8();
317
- return (r) => r.readInt16();
318
- }
319
- switch (t) {
320
- case "uint8":
321
- return (r) => r.readUInt8();
322
- case "int8":
323
- return (r) => r.readInt8();
324
- case "uint16":
325
- return (r) => r.readUInt16();
326
- case "int16":
327
- return (r) => r.readInt16();
328
- case "uint32":
329
- return (r) => r.readUInt32();
330
- case "int32":
331
- return (r) => r.readInt32();
332
- case "uint64":
333
- return (r) => r.readUInt64();
334
- case "int64":
335
- return (r) => r.readInt64();
336
- case "uint128":
337
- return (r) => r.readUInt128();
338
- case "int128":
339
- return (r) => r.readInt128();
340
- case "uint256":
341
- return (r) => r.readUInt256();
342
- case "int256":
343
- return (r) => r.readInt256();
344
- case "float32":
345
- return (r) => r.readFloat32();
346
- case "float64":
347
- return (r) => r.readFloat64();
348
- case "string":
349
- return (r) => r.readString();
350
- case "uuid":
351
- return (r) => r.readUUID();
352
- case "bool":
353
- return (r) => r.readBool();
354
- case "date":
355
- return (r) => r.readDate();
356
- case "date32":
357
- return (r) => r.readDate32();
358
- case "datetime":
359
- return (r) => r.readDateTime();
360
- case "ipv4":
361
- return (r) => r.readIPv4();
362
- case "ipv6":
363
- return (r) => r.readIPv6();
364
- default:
365
- return (r) => r.readString();
366
- }
367
- }
368
- function parseGenericTypes(typeString) {
369
- const args = [];
370
- let current = "";
371
- let parenDepth = 0;
372
- for (let i = 0;i < typeString.length; i++) {
373
- const char = typeString[i];
374
- if (char === "," && parenDepth === 0) {
375
- args.push(current.trim());
376
- current = "";
377
- } else {
378
- if (char === "(")
379
- parenDepth++;
380
- if (char === ")")
381
- parenDepth--;
382
- current += char;
383
- }
384
- }
385
- if (current.trim()) {
386
- args.push(current.trim());
387
- }
388
- return args;
389
- }
390
-
391
20
  // src/index.ts
392
21
  import { resolve, join } from "path";
393
22
  import { existsSync, readdirSync } from "fs";
@@ -2361,34 +1990,6 @@ class PreparedQuery {
2361
1990
  query_params[this.paramKeys[i]] = values2[i];
2362
1991
  }
2363
1992
  }
2364
- const limitMatch = this.sql.match(/LIMIT\s+(\d+)/i);
2365
- const limit = limitMatch ? parseInt(limitMatch[1], 10) : Infinity;
2366
- const useBinary = limit >= 1e5 && this.columnTypes.length > 0;
2367
- if (useBinary) {
2368
- const resultSet2 = await this.client.query({
2369
- query: this.sql,
2370
- query_params,
2371
- format: "RowBinary"
2372
- });
2373
- const { BinaryReader: BinaryReader2, createBinaryDecoder: createBinaryDecoder2 } = await Promise.resolve().then(() => exports_binary_reader);
2374
- const response = await resultSet2.stream();
2375
- const decoder = this.columnTypes.map((type) => createBinaryDecoder2(type));
2376
- const results = [];
2377
- const chunks = [];
2378
- for await (const chunk of response) {
2379
- chunks.push(chunk);
2380
- }
2381
- const fullBuffer = Buffer.concat(chunks);
2382
- const reader = new BinaryReader2(fullBuffer);
2383
- while (!reader.isEOF()) {
2384
- const row = {};
2385
- for (let i = 0;i < this.columnNames.length; i++) {
2386
- row[this.columnNames[i]] = decoder[i](reader);
2387
- }
2388
- results.push(row);
2389
- }
2390
- return results;
2391
- }
2392
1993
  const resultSet = await this.client.query({
2393
1994
  query: this.sql,
2394
1995
  query_params,
@@ -3285,104 +2886,20 @@ class ClickHouseQueryBuilder {
3285
2886
  return this[Symbol.asyncIterator]();
3286
2887
  }
3287
2888
  async native() {
3288
- return this.executeBinary("object");
2889
+ console.warn("[HouseKit] native() is deprecated. RowBinary streaming is not supported by @clickhouse/client 1.15+. Using JSONEachRow instead.");
2890
+ return this.then((data) => data);
3289
2891
  }
3290
2892
  async vector() {
3291
- return this.executeBinary("vector");
3292
- }
3293
- async executeBinary(mode) {
3294
- const compiler = new QueryCompiler;
3295
- const state = this.getState();
3296
- const columns = [];
3297
- if (state.select) {
3298
- for (const [key, val] of Object.entries(state.select)) {
3299
- if (val instanceof ClickHouseColumn) {
3300
- columns.push({ name: key, type: val.type, decoder: createBinaryDecoder(val.type) });
3301
- } else if (val && typeof val === "object" && "_type" in val && val.type) {
3302
- throw new Error(`[HouseKit] Binary mode requires strictly typed columns. Field '${key}' is an expression without type info.`);
3303
- } else {
3304
- throw new Error(`[HouseKit] Binary mode requires strictly typed columns. Field '${key}' is not a ClickHouseColumn.`);
3305
- }
3306
- }
3307
- } else if (state.table) {
3308
- const tableCols = state.table.$columns;
3309
- for (const [key, col] of Object.entries(tableCols)) {
3310
- columns.push({ name: key, type: col.type, decoder: createBinaryDecoder(col.type) });
3311
- }
3312
- } else {
3313
- throw new Error("[HouseKit] Binary mode requires a table or explicit selection.");
3314
- }
3315
- const { cachedQuery, values: values2 } = compiler.compileWithCache(state, this.client);
3316
- const query_params = {};
3317
- for (let i = 0;i < values2.length; i++) {
3318
- query_params[`p_${i + 1}`] = values2[i];
3319
- }
3320
- const resultSet = await this.client.query({
3321
- query: cachedQuery.sql,
3322
- query_params,
3323
- format: "RowBinary"
3324
- });
3325
- const chunks = [];
3326
- const stream = resultSet.stream();
3327
- for await (const chunk of stream) {
3328
- chunks.push(chunk);
3329
- }
3330
- const fullBuffer = Buffer.concat(chunks);
3331
- const reader = new BinaryReader(fullBuffer);
3332
- const count = fullBuffer.length;
3333
- if (mode === "object") {
3334
- const rows = [];
3335
- while (!reader.isEOF()) {
3336
- const row = {};
3337
- for (const col of columns) {
3338
- row[col.name] = col.decoder(reader);
3339
- }
3340
- rows.push(row);
3341
- }
3342
- return rows;
3343
- } else {
3344
- const data = {};
3345
- for (const col of columns) {
3346
- data[col.name] = [];
3347
- }
3348
- while (!reader.isEOF()) {
3349
- for (const col of columns) {
3350
- data[col.name].push(col.decoder(reader));
3351
- }
3352
- }
3353
- const finalVectors = {};
3354
- for (const col of columns) {
3355
- const arr = data[col.name];
3356
- const type = col.type.toLowerCase();
3357
- if (type.includes("int") || type.includes("float")) {
3358
- if (type === "int8")
3359
- finalVectors[col.name] = new Int8Array(arr);
3360
- else if (type === "uint8")
3361
- finalVectors[col.name] = new Uint8Array(arr);
3362
- else if (type === "int16")
3363
- finalVectors[col.name] = new Int16Array(arr);
3364
- else if (type === "uint16")
3365
- finalVectors[col.name] = new Uint16Array(arr);
3366
- else if (type === "int32")
3367
- finalVectors[col.name] = new Int32Array(arr);
3368
- else if (type === "uint32")
3369
- finalVectors[col.name] = new Uint32Array(arr);
3370
- else if (type === "int64")
3371
- finalVectors[col.name] = new BigInt64Array(arr);
3372
- else if (type === "uint64")
3373
- finalVectors[col.name] = new BigUint64Array(arr);
3374
- else if (type === "float32")
3375
- finalVectors[col.name] = new Float32Array(arr);
3376
- else if (type === "float64")
3377
- finalVectors[col.name] = new Float64Array(arr);
3378
- else
3379
- finalVectors[col.name] = arr;
3380
- } else {
3381
- finalVectors[col.name] = arr;
3382
- }
3383
- }
3384
- return finalVectors;
2893
+ console.warn("[HouseKit] vector() is deprecated. RowBinary streaming is not supported by @clickhouse/client 1.15+. Using JSONEachRow instead.");
2894
+ const rows = await this.then((data) => data);
2895
+ if (rows.length === 0)
2896
+ return {};
2897
+ const result = {};
2898
+ const keys = Object.keys(rows[0]);
2899
+ for (const key of keys) {
2900
+ result[key] = rows.map((row) => row[key]);
3385
2901
  }
2902
+ return result;
3386
2903
  }
3387
2904
  async explain() {
3388
2905
  const { query, params } = this.toSQL();
@@ -4022,7 +3539,7 @@ class BinaryWriter {
4022
3539
  this.writeInt16(value);
4023
3540
  }
4024
3541
  }
4025
- function parseGenericTypes2(typeString) {
3542
+ function parseGenericTypes(typeString) {
4026
3543
  const args = [];
4027
3544
  let current = "";
4028
3545
  let parenDepth = 0;
@@ -4071,7 +3588,7 @@ function createBinaryEncoder(clickhouseType, isNullable = false) {
4071
3588
  }
4072
3589
  const mapMatch = type.match(/^map\((.+)\)$/);
4073
3590
  if (mapMatch) {
4074
- const [keyType, valueType] = parseGenericTypes2(mapMatch[1]);
3591
+ const [keyType, valueType] = parseGenericTypes(mapMatch[1]);
4075
3592
  if (!keyType || !valueType)
4076
3593
  throw new Error(`Invalid Map type: ${type}`);
4077
3594
  const keyEncoder = createBinaryEncoder(keyType);
@@ -4094,7 +3611,7 @@ function createBinaryEncoder(clickhouseType, isNullable = false) {
4094
3611
  }
4095
3612
  const tupleMatch = type.match(/^tuple\((.+)\)$/);
4096
3613
  if (tupleMatch) {
4097
- const types = parseGenericTypes2(tupleMatch[1]);
3614
+ const types = parseGenericTypes(tupleMatch[1]);
4098
3615
  const encoders = types.map((t) => createBinaryEncoder(t));
4099
3616
  return (writer, value) => {
4100
3617
  const arr = Array.isArray(value) ? value : [];
@@ -4105,7 +3622,7 @@ function createBinaryEncoder(clickhouseType, isNullable = false) {
4105
3622
  }
4106
3623
  const nestedMatch = type.match(/^nested\((.+)\)$/);
4107
3624
  if (nestedMatch) {
4108
- const fields = parseGenericTypes2(nestedMatch[1]);
3625
+ const fields = parseGenericTypes(nestedMatch[1]);
4109
3626
  const types = fields.map((f) => {
4110
3627
  const parts = f.trim().split(/\s+/);
4111
3628
  if (parts.length < 2)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@housekit/orm",
3
- "version": "0.1.43",
3
+ "version": "0.1.44",
4
4
  "description": "Type-safe ClickHouse ORM with modern DX and ClickHouse-specific optimizations. Features optimized JSONCompact streaming, full engine support, and advanced query capabilities.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",