@housekit/orm 0.1.28 → 0.1.30
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/README.md +39 -58
- package/dist/builders/insert.d.ts +2 -13
- package/dist/index.d.ts +2 -3
- package/dist/index.js +2 -15
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -14,7 +14,7 @@ HouseKit ORM is a modern database toolkit designed specifically for ClickHouse.
|
|
|
14
14
|
## 🚀 Key Features
|
|
15
15
|
|
|
16
16
|
- **🛡️ First-Class TypeScript**: Full type inference for every query. Schema definition acts as the single source of truth.
|
|
17
|
-
- **🏎️
|
|
17
|
+
- **🏎️ High-Performance Inserts**: Optimized streaming with JSONCompact format and sync insert mode.
|
|
18
18
|
- **🏗️ ClickHouse Native Engines**: Fluent DSL for `MergeTree`, `ReplacingMergeTree`, `SummingMergeTree`, `Distributed`, `Buffer`, and more.
|
|
19
19
|
- **🔍 Advanced Analytics**: Specialized support for `ASOF JOIN`, `ARRAY JOIN`, `PREWHERE`, and complex Window Functions.
|
|
20
20
|
- **🤝 Smart Relational API**: Query relations using `groupArray` internally, preventing row duplication.
|
|
@@ -74,7 +74,7 @@ import * as schema from './schema';
|
|
|
74
74
|
|
|
75
75
|
const db = housekit({ url: 'http://localhost:8123' }, { schema });
|
|
76
76
|
|
|
77
|
-
//
|
|
77
|
+
// Standard insert (no data returned)
|
|
78
78
|
await db.insert(schema.users).values({ email: 'a@b.com', role: 'admin' });
|
|
79
79
|
|
|
80
80
|
// JSON insert with returning data
|
|
@@ -164,18 +164,26 @@ orderBy: [desc(users.createdAt), asc(users.name)]
|
|
|
164
164
|
|
|
165
165
|
## 🚀 High-Performance Inserts
|
|
166
166
|
|
|
167
|
-
###
|
|
167
|
+
### Default Insert (Sync Mode)
|
|
168
168
|
|
|
169
|
-
|
|
169
|
+
HouseKit uses synchronous inserts by default for maximum speed:
|
|
170
170
|
|
|
171
171
|
```typescript
|
|
172
|
-
//
|
|
172
|
+
// Standard insert - uses sync mode automatically
|
|
173
173
|
await db.insert(events).values([
|
|
174
174
|
{ type: 'click', userId: '...' },
|
|
175
175
|
{ type: 'view', userId: '...' },
|
|
176
176
|
]);
|
|
177
177
|
```
|
|
178
178
|
|
|
179
|
+
### Async Insert (Server-Side Batching)
|
|
180
|
+
|
|
181
|
+
Use `.asyncInsert()` when you want ClickHouse to batch writes internally:
|
|
182
|
+
|
|
183
|
+
```typescript
|
|
184
|
+
await db.insert(events).values(data).asyncInsert();
|
|
185
|
+
```
|
|
186
|
+
|
|
179
187
|
### JSON Insert with Returning
|
|
180
188
|
|
|
181
189
|
Use `.returningOne()` for single inserts or `.returning()` for multiple:
|
|
@@ -196,12 +204,6 @@ const [user1, user2] = await db
|
|
|
196
204
|
.returning();
|
|
197
205
|
```
|
|
198
206
|
|
|
199
|
-
### Force JSON Format
|
|
200
|
-
|
|
201
|
-
```typescript
|
|
202
|
-
await db.insert(events).values(data).useJsonFormat();
|
|
203
|
-
```
|
|
204
|
-
|
|
205
207
|
### Background Batching
|
|
206
208
|
|
|
207
209
|
Collect small writes into efficient batches:
|
|
@@ -300,6 +302,32 @@ const query = await db.select()
|
|
|
300
302
|
|
|
301
303
|
---
|
|
302
304
|
|
|
305
|
+
## 📊 Benchmarks
|
|
306
|
+
|
|
307
|
+
Performance tested on local ClickHouse (Docker) with Bun runtime:
|
|
308
|
+
|
|
309
|
+
| Rows | Method | Time | Throughput |
|
|
310
|
+
|------|--------|------|------------|
|
|
311
|
+
| 1,000 | JSON | 19ms | 52,632 rows/sec |
|
|
312
|
+
| 1,000 | JSON Sync | 13ms | 76,923 rows/sec |
|
|
313
|
+
| 5,000 | JSON | 118ms | 42,373 rows/sec |
|
|
314
|
+
| 5,000 | JSON Sync | 54ms | 92,593 rows/sec |
|
|
315
|
+
| 10,000 | JSON | 159ms | 62,893 rows/sec |
|
|
316
|
+
| 10,000 | JSON Sync | 161ms | 62,112 rows/sec |
|
|
317
|
+
|
|
318
|
+
Key findings:
|
|
319
|
+
- **Sync insert is the default** - fastest for most use cases
|
|
320
|
+
- For batches <5k rows, sync is up to **2x faster**
|
|
321
|
+
- For larger batches (10k+), performance is similar
|
|
322
|
+
- Use `.asyncInsert()` only when you need server-side batching
|
|
323
|
+
|
|
324
|
+
Run the benchmark yourself:
|
|
325
|
+
```bash
|
|
326
|
+
bun run benchmark # in app directory
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
---
|
|
330
|
+
|
|
303
331
|
## ⚡ Performance Optimizations
|
|
304
332
|
|
|
305
333
|
HouseKit includes several optimizations for maximum throughput in production environments.
|
|
@@ -334,53 +362,6 @@ const db = housekit({
|
|
|
334
362
|
await db.insert(events).values(data).skipValidation();
|
|
335
363
|
```
|
|
336
364
|
|
|
337
|
-
### Object Pooling
|
|
338
|
-
|
|
339
|
-
HouseKit automatically pools `BinaryWriter` instances to reduce GC pressure. For advanced use cases:
|
|
340
|
-
|
|
341
|
-
```typescript
|
|
342
|
-
import { acquireWriter, releaseWriter } from '@housekit/orm';
|
|
343
|
-
|
|
344
|
-
const writer = acquireWriter();
|
|
345
|
-
try {
|
|
346
|
-
// Use writer for custom serialization
|
|
347
|
-
} finally {
|
|
348
|
-
releaseWriter(writer);
|
|
349
|
-
}
|
|
350
|
-
```
|
|
351
|
-
|
|
352
|
-
### Optimized Serialization
|
|
353
|
-
|
|
354
|
-
For maximum performance with large batches:
|
|
355
|
-
|
|
356
|
-
```typescript
|
|
357
|
-
import {
|
|
358
|
-
buildOptimizedBinaryConfig,
|
|
359
|
-
serializeRowsOptimized
|
|
360
|
-
} from '@housekit/orm';
|
|
361
|
-
|
|
362
|
-
// Pre-compile accessors once
|
|
363
|
-
const config = buildOptimizedBinaryConfig(columns, {
|
|
364
|
-
skipValidation: true
|
|
365
|
-
});
|
|
366
|
-
|
|
367
|
-
// Serialize batches with pooled writer + pre-compiled accessors
|
|
368
|
-
const buffer = serializeRowsOptimized(rows, config);
|
|
369
|
-
```
|
|
370
|
-
|
|
371
|
-
### TypedArray for Numeric Data
|
|
372
|
-
|
|
373
|
-
For schemas with mostly numeric columns:
|
|
374
|
-
|
|
375
|
-
```typescript
|
|
376
|
-
import { isNumericHeavySchema, serializeNumericBatch } from '@housekit/orm';
|
|
377
|
-
|
|
378
|
-
if (isNumericHeavySchema(columns)) {
|
|
379
|
-
// Uses Float64Array for better memory layout
|
|
380
|
-
const { numericBuffer, otherData } = serializeNumericBatch(rows, config, numericIndices);
|
|
381
|
-
}
|
|
382
|
-
```
|
|
383
|
-
|
|
384
365
|
---
|
|
385
366
|
|
|
386
367
|
## 🛠 Observability
|
|
@@ -125,21 +125,10 @@ export declare class ClickHouseInsertBuilder<TTable extends TableRuntime<any, an
|
|
|
125
125
|
turbo(): this;
|
|
126
126
|
execute(): Promise<TReturn>;
|
|
127
127
|
/**
|
|
128
|
-
* Resolve the actual format to use based on settings
|
|
129
|
-
*
|
|
130
|
-
* Binary is preferred when:
|
|
131
|
-
* - No columns require server-side UUID generation
|
|
132
|
-
* - All column types are supported by our binary encoder
|
|
133
|
-
*
|
|
134
|
-
* Falls back to JSON when:
|
|
135
|
-
* - Columns use server-side defaults (e.g., generateUUIDv4())
|
|
136
|
-
* - Unsupported types are detected
|
|
128
|
+
* Resolve the actual format to use based on settings.
|
|
129
|
+
* Default is JSON (most reliable and well-optimized by the official client).
|
|
137
130
|
*/
|
|
138
131
|
private resolveFormat;
|
|
139
|
-
/**
|
|
140
|
-
* Check if table and data are compatible with binary format
|
|
141
|
-
*/
|
|
142
|
-
private canUseBinaryFormat;
|
|
143
132
|
/**
|
|
144
133
|
* Execute insert using JSON format
|
|
145
134
|
*/
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import type { ClickHouseClientConfigOptions } from '@clickhouse/client';
|
|
2
1
|
import { type TableDefinition, type TableColumns } from './core';
|
|
3
|
-
import { createClientFromConfigObject, type ClientConfigWithSchema, type HousekitClient as HousekitClientType } from './client';
|
|
2
|
+
import { createClientFromConfigObject, type ClientConfigWithSchema, type HousekitClient as HousekitClientType, type HousekitClientConfig } from './client';
|
|
4
3
|
import { generateSelectSchema, generateInsertSchema } from './codegen/zod';
|
|
5
4
|
export { ClickHouseColumn } from './column';
|
|
6
5
|
export { type TableDefinition, type TableColumns, type TableOptions, type IndexDefinition, type ProjectionDefinition, type InsertModel, type TableModel, type TableInsertArray, type TableRuntime, type TableInsert, index, projection, deriveTable, renderSchema } from './table';
|
|
@@ -67,7 +66,7 @@ export interface HouseKitConfig {
|
|
|
67
66
|
* Load housekit.config.js/ts and create a client by name.
|
|
68
67
|
*/
|
|
69
68
|
export declare function createClientFromConfig(databaseName?: string): Promise<HousekitClient>;
|
|
70
|
-
export declare function housekit<TSchema extends Record<string, TableDefinition<any>> = Record<string, TableDefinition<any>>>(config:
|
|
69
|
+
export declare function housekit<TSchema extends Record<string, TableDefinition<any>> = Record<string, TableDefinition<any>>>(config: HousekitClientConfig, options?: {
|
|
71
70
|
schema?: TSchema;
|
|
72
71
|
}): HousekitClientType<TSchema>;
|
|
73
72
|
export declare function createSchema<TCols extends TableColumns>(table: TableDefinition<TCols>): {
|
package/dist/index.js
CHANGED
|
@@ -4671,7 +4671,7 @@ class ClickHouseInsertBuilder {
|
|
|
4671
4671
|
table;
|
|
4672
4672
|
connectionConfig;
|
|
4673
4673
|
_values = null;
|
|
4674
|
-
_async =
|
|
4674
|
+
_async = false;
|
|
4675
4675
|
_waitForAsync = true;
|
|
4676
4676
|
_batchOptions = {};
|
|
4677
4677
|
_format = "auto";
|
|
@@ -4822,20 +4822,7 @@ class ClickHouseInsertBuilder {
|
|
|
4822
4822
|
if (this._format !== "auto") {
|
|
4823
4823
|
return this._format;
|
|
4824
4824
|
}
|
|
4825
|
-
|
|
4826
|
-
return canUseBinary ? "binary" : plan.useCompact ? "compact" : "json";
|
|
4827
|
-
}
|
|
4828
|
-
canUseBinaryFormat(plan) {
|
|
4829
|
-
for (const col of plan.columns) {
|
|
4830
|
-
if (col.useServerUUID) {
|
|
4831
|
-
return false;
|
|
4832
|
-
}
|
|
4833
|
-
const type = col.column.type.toLowerCase();
|
|
4834
|
-
if (type.includes("map(") || type.includes("tuple(") || type.includes("nested(") || type.includes("lowcardinality(")) {
|
|
4835
|
-
return false;
|
|
4836
|
-
}
|
|
4837
|
-
}
|
|
4838
|
-
return true;
|
|
4825
|
+
return plan.useCompact ? "compact" : "json";
|
|
4839
4826
|
}
|
|
4840
4827
|
async executeJsonInsert(plan, tableName, format) {
|
|
4841
4828
|
const mode = format === "compact" ? "compact" : "json";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@housekit/orm",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.30",
|
|
4
4
|
"description": "Type-safe ClickHouse ORM with modern DX and ClickHouse-specific optimizations. Features Turbo Mode (RowBinary), full engine support, and advanced query capabilities.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|