@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.
- package/dist/builders/select.d.ts +4 -9
- package/dist/index.js +15 -498
- package/package.json +1 -1
|
@@ -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
|
-
*
|
|
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
|
-
* @
|
|
269
|
-
*
|
|
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
|
-
|
|
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
|
-
|
|
3292
|
-
|
|
3293
|
-
|
|
3294
|
-
|
|
3295
|
-
const
|
|
3296
|
-
const
|
|
3297
|
-
|
|
3298
|
-
|
|
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
|
|
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] =
|
|
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 =
|
|
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 =
|
|
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.
|
|
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",
|