@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 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
- - **🏎️ Binary Inserts by Default**: Native `RowBinary` serialization is used automatically. **5-10x faster** than JSON.
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
- // Binary insert (default, fastest)
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
- ### Binary Insert (Default)
167
+ ### Default Insert (Sync Mode)
168
168
 
169
- Binary format is used by default for maximum performance:
169
+ HouseKit uses synchronous inserts by default for maximum speed:
170
170
 
171
171
  ```typescript
172
- // Binary insert (no data returned)
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 and table capabilities.
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: ClickHouseClientConfigOptions, options?: {
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 = true;
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
- const canUseBinary = this.canUseBinaryFormat(plan);
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.28",
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",