Repository navigation
Add the Layer 3 fluent query builder SDK - #55
Merged
wudidapaopao merged 7 commits intoJun 25, 2026
Merged
Conversation
ShawnChen-Sirius
force-pushed
the
feat/layer3-fluent-sdk-v2
branch
from
June 24, 2026 06:56
6b024c3 to
710a8ea
Compare
Contributor
Author
|
@chibugai, review this |
There was a problem hiding this comment.
Pull request overview
This pull request introduces Layer 3, a fluent, immutable query builder on top of the existing Layer 1 runtime, along with a chdb-gen-types CLI for typed schema generation and an Arrow C Data Interface input path for zero-copy columnar ingestion.
Changes:
- Adds Layer 3 builder surface (SELECT/INSERT/UPDATE/DELETE), compiler, execution terminals, and local-engine introspection.
- Adds federation via
connect()with URL-scheme → table-function mapping and metadata discovery helpers. - Adds schema codegen (runtime introspection + static Prisma/Drizzle parsing) and an Arrow table registration API backed by new N-API exports.
Reviewed changes
Copilot reviewed 45 out of 47 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| test/v3/layer3/types.test.ts | Type-level assertions for CH type literal → TS type mapping and row inference. |
| test/v3/layer3/static-codegen.test.ts | Tests static schema conversion (Prisma/Drizzle) and CLI output behavior. |
| test/v3/layer3/introspection.test.ts | Exercises db.introspection against the embedded engine. |
| test/v3/layer3/functions.test.ts | Tests function/table-function helpers compilation and one execution path. |
| test/v3/layer3/fixtures/prisma-schema.prisma | Prisma fixture for static conversion tests. |
| test/v3/layer3/fixtures/drizzle-schema.ts | Drizzle-shaped TS fixture for static conversion tests. |
| test/v3/layer3/execute.test.ts | End-to-end execution tests for core builder behavior and types. |
| test/v3/layer3/dialect.test.ts | Tests ClickHouse dialect sugar compilation + observable execution behavior. |
| test/v3/layer3/connect.test.ts | Tests URL-scheme mapping, injection resistance, metadata SQL, and execution. |
| test/v3/layer3/compile.test.ts | Golden-SQL compilation tests to enforce value-binding and quoting. |
| test/v3/layer3/codegen.test.ts | Tests runtime introspection, deterministic emission, and CLI behavior. |
| test/v3/layer3/arrow-input.test.ts | Tests Arrow input registration, refresh/close semantics, and validation. |
| src/layer3/types/infer.ts | Defines schema → row inference and RowOf helper for builder typing. |
| src/layer3/types/ch-types.ts | Implements CH type literal → TS type mapping via template literal types. |
| src/layer3/runtime.ts | Lazy Layer 1 runtime accessor + minimal runtime interface for Layer 3. |
| src/layer3/introspection.ts | Kysely-shaped introspector implementation over system.* tables. |
| src/layer3/index.ts | Layer 3 public exports surface. |
| src/layer3/execute/terminal.ts | Execution boundary forwarding compiled queries to Layer 1 bind APIs. |
| src/layer3/execute/format.ts | Output-view planning (json/arrow/raw) and JSONEachRow parsing. |
| src/layer3/execute/arrow-input.ts | JS API for registering Arrow columnar buffers as arrowstream() sources. |
| src/layer3/database.ts | Root factories (selectFrom, database, session, connect) and context binding. |
| src/layer3/connect/url-scheme.ts | URL-scheme → table-function mapping and validation for federation sources. |
| src/layer3/connect/snapshot.ts | Builds INSERT … SELECT snapshot node for one-shot materialization. |
| src/layer3/connect/connect.ts | Connection wrapper: table expression, describe, catalog listing, snapshot. |
| src/layer3/compiler/param.ts | Placeholder naming + JS value → CH type inference for server-side binding. |
| src/layer3/compiler/nodes.ts | AST node definitions for the builder/compiler boundary. |
| src/layer3/compiler/identifier.ts | Identifier quoting + function name validation. |
| src/layer3/compiler/compile.ts | SQL compiler producing { sql, parameters } and settings/format rendering. |
| src/layer3/codegen/introspect.ts | Runtime DESCRIBE-based introspection over tables/files/expressions/URLs. |
| src/layer3/codegen/from-prisma.ts | Static Prisma schema parsing → IntrospectedDatabase conversion. |
| src/layer3/codegen/from-drizzle.ts | Static Drizzle schema parsing (TypeScript AST) → IntrospectedDatabase conversion. |
| src/layer3/codegen/emit.ts | Deterministic TS emitter for schema interfaces (ClickHouse type literals). |
| src/layer3/codegen/cli.ts | chdb gen-types CLI implementation and argument planning. |
| src/layer3/builder/update.ts | UPDATE builder compiling to ClickHouse mutations. |
| src/layer3/builder/table-functions.ts | chTable helpers for common table functions with bound arguments. |
| src/layer3/builder/select.ts | Immutable SELECT builder + dialect sugar and execution terminals. |
| src/layer3/builder/insert.ts | INSERT builder supporting row inserts and INSERT … SELECT. |
| src/layer3/builder/functions.ts | chFn helper functions including parametric aggregates. |
| src/layer3/builder/expression.ts | sql tag and expression helpers (ref, val, fn) for AST construction. |
| src/layer3/builder/delete.ts | DELETE builder compiling to ClickHouse mutations. |
| src/errors.ts | Adds ChdbCompileError for Layer 3 build/contract failures. |
| package.json | Adds chdb-gen-types binary entrypoint. |
| lib/chdb_node.cpp | Adds Arrow C Data Interface registration/unregistration N-API bindings. |
| index.mjs | Exposes ChdbCompileError as a named ESM export. |
| index.js | Exposes low-level Arrow registration/unregistration and re-exports Layer 3. |
| index.d.ts | Re-exports generated Layer 3 TypeScript declarations from dist/layer3. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
chibugai
reviewed
Jun 24, 2026
Scaffold the Layer 3 package and ChdbCompileError, and implement the SQL compiler with server-side value binding ({pN:Type} placeholders + raw values via Layer 1 queryBindAsync; identifiers backtick-quoted). Add the SELECT/INSERT/UPDATE(ALTER..UPDATE)/DELETE(ALTER..DELETE)/INSERT..SELECT builders, expression helpers, terminals, and root factory; ClickHouse dialect sugar (final/sample/prewhere/settings/format/limitBy); chTable and chFn helpers; and golden-SQL, injection, and execution tests.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Map all 14 URL schemes to table functions with every arg bound, and expose Connection.table()/describe()/databases()/tables()/snapshot(). Wire metadata for ClickHouse, Postgres, and MySQL; forward clickhouseSettings to chDB and accept-and-ignore remote-only options. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Infer row types from a typed Database<DB> through to .execute(). Add the chdb-gen-types CLI with runtime introspection helpers, plus static Drizzle and Prisma schema conversion. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…face) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
ShawnChen-Sirius
force-pushed
the
feat/layer3-fluent-sdk-v2
branch
from
June 24, 2026 09:34
710a8ea to
f14908c
Compare
Native (lib/chdb_node.cpp):
- erase a connection's Arrow-table registry entries on every close path
(release_session_conn, the default-conn handoff, hard_close_all) so pinned JS
buffers aren't leaked and a reused connection address can't collide with a
stale key.
- reject negative length/nullCount and replace the rootLength == -1 sentinel
with a bool flag so a 0-row column is handled correctly.
Builder / compiler:
- SETTINGS string values escape ' by SQL-standard doubling ('') instead of
backslash, matching src/connection/chdb-connection.ts.
- exhaustiveness guards on the expr() and compileQuery() switches.
- chTable s3/postgresql/mysql/iceberg/deltaLake reject a half-supplied
credential pair instead of silently dropping both.
- executeTakeFirst[OrThrow] narrow options to the row view so format:'arrow'/raw
can't yield a malformed rows[0].
Codegen / introspection:
- stripComments no longer truncates // inside quoted strings (e.g. URLs);
parsePrismaSchema/modelToColumns use null-prototype maps (no __proto__
pollution).
- emitDatabase validates the interface name against IDENT_RE.
- gen-types CLI errors on duplicate --table and wraps the output write in
try/catch with a clean exit code.
- introspection isNullable unwraps LowCardinality(Nullable(...)).
Execute:
- parseRows wraps JSON.parse to surface a typed ChdbInternalError (with the
offending line) instead of a bare SyntaxError.
- registerArrowTable validates the nulls mask length.
Adds test/v3/layer3/review-fixes.test.ts covering these.
CI (fold-in of the earlier "Fix Layer 3 CI" commit):
- cleanroom failed in `npm pack` (TS5055 "would overwrite input file"): the pack
step re-ran build:ts after `npm run build` had populated dist, and the second
tsc pass reached dist/*.d.ts as inputs through the root index.d.ts barrel and
refused to overwrite them. build:ts now `rm -rf dist` first so each pass starts
clean.
- the test job failed with `ArrowRegisterColumns is not a function`: the loader
prefers the published @chdb/lib-<platform> subpackage over a local build, and
that prebuilt binary predates the Layer 3 Arrow C Data Interface methods. The
job now drops the installed subpackage after building so loadNative() falls
through to the freshly built build/Release/chdb_node.node.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
registerArrowTable pins JS buffers via Napi::Reference until the table is
unregistered. A handle dropped without close() previously leaked those pins
for the connection's lifetime, so a long-lived session registering tables in
a loop grew memory monotonically.
Add a module-level FinalizationRegistry that best-effort unregisters a
collected handle. The held value carries only rt/conn/name and a shared
{ live } flag — never the handle or the encoded buffers, which would pin the
very things we want freed. close() cancels the finalizer (handle is its own
token) and shares the live flag, so an explicit close never races a redundant
unregister, and a second close is a no-op. This is non-deterministic by spec;
explicit close() (ideally try/finally) is still required.
Test via a leaked handle plus driven GC; --expose-gc is wired through vitest
execArgv so it runs by default and self-skips otherwise.
Also add AGENT.md documenting the Arrow input lifecycle (close/refresh/
single-pass/GC fallback), the one-connection-per-process constraint, and the
build/test split. A lazy .stream() terminal is recorded there as a follow-up
rather than shipped: Layer 1's streaming C ABI (query_conn_streaming_n) takes
no params, so a streaming terminal could not bind server-side without either a
footgun (throw on bound queries) or putting values into SQL text (violates the
no-values-in-SQL invariant). The clean fix is upstream; build .stream() once
against it later.
Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
ShawnChen-Sirius
force-pushed
the
feat/layer3-fluent-sdk-v2
branch
from
June 25, 2026 02:33
f14908c to
795440a
Compare
wudidapaopao
approved these changes
Jun 25, 2026
ShawnChen-Sirius
added a commit
that referenced
this pull request
Jul 7, 2026
…w integrations Additive minor release on top of 3.1.0 (2026-06-24). No breaking changes; existing 3.1.0 APIs continue to work unchanged. libchdb bits are unchanged (chdb-core v26.5.1-rc.1 packaged as @chdb/lib-* 26.5.2 — no republish needed, the subpackage-matrix job will idempotent-skip). ## What's new ### Layer 3 fluent query builder SDK (#55, #59) First-class typed fluent query API — Kysely-/Drizzle-style: const db = connect({ session }) const rows = await db .from('users') .where(r => r.age.gt(18)) .select('id', 'name') .execute() - `src/layer3/{builder,execute,compile,dialect,introspection,connect,types,codegen}/` - `chdb-gen-types` CLI — generates row types from a schema (Drizzle / Prisma / raw SQL sources) - `.stream()` terminal with server-side parameter binding - Arrow C Data Interface support: register JS columnar data as `arrowstream()` tables - 12 new test files under `test/v3/layer3/` ### Cross-language agent-tool contract + 2 framework adapters (#61, #66) - `chdb/ai-sdk` — Vercel AI SDK tools (`generateText`/`streamText`) - `chdb/mastra` — Mastra tools + `ChDBVector` (HNSW RAG store) + `ChDBStore` - Both are thin wrappers over `ChDBTool.call()` from `integrations/agents/`, which implements the cross-language contract vendored from `chdb-io/chdb` (`chdb/agents/CONTRACT.md`, chdb-io/chdb#597). - 7 canonical tools: `run_select_query` / `list_databases` / `list_tables` / `describe_table` / `get_sample_data` / `list_functions` / `attach_file` - 5 pillars enforced: engine-level readonly=2 (P1), value-vs-identifier separation (P2), truncation flag (P3), error envelope for model self-correction (P4), resource/source controls (P5) - Behavior verified against the shared `conformance/cases.jsonl` fixture ### `chdb/hypequery` DatabaseAdapter (#63, #65) Lets `@hypequery/clickhouse` query builder run on embedded chDB instead of a remote ClickHouse server. Uses hypequery's own `substituteParameters` (imported, not copied) so rendered SQL stays byte-identical to hypequery's built-in HTTP adapter. ### `chdb/connection` stabilization for @clickhouse/client 1.23.0 - `peerDependency: "@clickhouse/client: >=1.23.0"` (optional) — old client triggers a clear npm warning instead of a runtime TS error - Parity runner switched to track `ClickHouse/clickhouse-js` release tag `client-1.23.0` (per the sync-policy table; #52 shipped the initial hook) - Runner auto-detects upstream Vitest layout (pre-/post-clickhouse-js#931) - Runner re-synced when clickhouse-js reorganized into a monorepo (#62) ### AI-discovery docs (#60) - Top-level `AGENTS.md` + `llms-full.txt` - Per-subpath `AGENTS.md` (`src/layer3/`, `src/connection/`, etc.) - All packaged in `files` so agents crawling the installed tarball find them ## Fixes / infrastructure - Bind `null` / `undefined` query params as SQL `\N` (contributor @dfrankland, #68) — matches `@clickhouse/client` behavior - `close()`-mid-flight engine abort + ResultSet teardown race (#56) - `ChDBVector` HNSW granularity / filter binding / dimension guard (#61) - Release workflow: publish → `unverified` dist-tag → clean-install verify matrix → promote to `latest` (#64). A broken release now never reaches `latest` users. - CI: cache deps + harden npm registry fetch against transient resets ## User-facing installation matrix ``` npm install chdb # base + Layer 3 SDK npm install chdb @clickhouse/client # + chdb/connection npm install chdb @hypequery/clickhouse # + chdb/hypequery npm install chdb ai zod # + chdb/ai-sdk npm install chdb @mastra/core zod # + chdb/mastra ``` Native libchdb: chdb-core v26.5.1-rc.1 (packaged as @chdb/lib-* 26.5.2), unchanged from 3.1.0. Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Layer 3 — fluent, immutable query builder for chdb-node
This PR adds Layer 3, the Kysely-shaped fluent query builder, on top of the pluggable
Connectionintroduced in #52 (now merged intomain). Code:src/layer3/, tests:test/v3/layer3/. Spec:chdb_node_layer3_lld_en.md.What's included
{pN:Type}placeholders plus raw values and calls Layer 1queryBindAsync; Layer 1 owns value serialization (src/serialize.ts). No value ever enters the SQL string, identifiers are backtick-quoted.ChdbCompileErroris the only net-new (build-time) error. Layer 1nullsemantics are left exactly as they are onmain.ALTER … UPDATE), DELETE (ALTER … DELETE), and INSERT…SELECT; terminals.compile/.execute/.executeTakeFirst[OrThrow]; json/arrow/raw format views; root factory (selectFrom/database/session).final/sample/prewhere/settings/format/limitBy;chTabletable-function helpers (args bound);chFnfunction helper incl. parametricname(params)(args).connect()federation — maps all 14 URL schemes to table functions with every arg bound;Connection.table()/.describe()/.databases()/.tables()/.snapshot(). Metadata wired for ClickHouse, Postgres, and MySQL;clickhouseSettingsforwarded to chDB, remote-only options accepted-and-ignored (no throw).Database<DB>flows through to.execute();chdb-gen-typesCLI with runtime introspection plus static Drizzle/Prisma schema conversion.registerArrowTable(name, columns)/chTable.arrowstream(name)register JS columnar buffers zero-copy via 4 new N-API methods inlib/chdb_node.cpp.db.introspection— Kysely-instance-shapedgetTables/getSchemas/getMetadataoversystem.databases/tables/columns.Testing
build:tsclean, native addon rebuilt.🤖 Generated with Claude Code