Expand description
§smooai-clickhouse-kit (imports as clickhouse_kit)
A safe-by-construction ClickHouse schema toolkit with two jobs:
- TS→Rust bridge for developer-authored (static) tables: TypeScript owns
the schema;
introspectreads the live ClickHouse back into Rust andcodegenemits#[derive(Row)]structs, withcheck_driftasserting the Rust view ≡ the live DB. Rows stay Serde-native. - Runtime toolkit for user-defined / multi-tenant (dynamic) tables: an
allowlisted type system, identifier safety, DDL generation,
flexible_table, forward-only migrations, and additive evolution — the safe-by-construction path for turning untrusted customer input into SQL (that guarantee only counts in the process holding the input, which is why this layer is canonical in Rust).
See the repo ROADMAP.md.
Re-exports§
pub use client::ChError;pub use client::ChExecutor;pub use codegen::ch_type_to_rust;pub use codegen::rust_row_struct;pub use drift::check_drift;pub use drift::Drift;pub use drift::DriftResult;pub use evolve::alter_add_columns_sql;pub use evolve::diff_columns;pub use evolve::ColumnDiff;pub use evolve::LiveColumn;pub use flatten::coerce_to_table;pub use flatten::flatten_record;pub use flatten::CoerceResult;pub use flatten::FlattenOptions;pub use flexible::flexible_table;pub use flexible::FlexibleConfig;pub use introspect::introspect_columns;pub use introspect::introspect_row_struct;pub use migrate::run_migrations;pub use migrate::split_sql_statements;pub use migrate::MigrationRunResult;pub use safety::assert_column_count;pub use safety::assert_not_reserved;pub use safety::quote_identifier;pub use safety::validate_identifier;pub use safety::ColumnTypeSpec;pub use safety::ScalarType;pub use safety::SchemaError;pub use safety::SchemaLimits;pub use safety::StringOnly;pub use safety::DEFAULT_RESERVED_COLUMNS;pub use table::to_create_table_sql;pub use table::ColumnSpec;pub use table::TableSpec;
Modules§
- client
- The bring-your-own-client seam.
clickhouse-kitnever depends on a concrete ClickHouse driver — the I/O layer (migration runner, drift gate) is written against the smallChExecutortrait, and the caller implements it over whatever client they already have (theclickhousecrate, an HTTP shim, a test double). This keeps the crate driver-agnostic and dependency-light. - codegen
- TS→Rust bridge codegen. TypeScript owns the (static) schema; this turns a
ClickHouse table’s live/spec columns into a Rust row struct —
#[derive(Row, Deserialize)]— so the Rust services get faithful, drift-checked rows for the TS-authored tables instead of hand-writing them (the class of bug that bit api-prime’s hand-copied structs). Pair withintrospect+check_drift: the generated rows are asserted ≡ the live ClickHouse in CI. - drift
- Drift gate: compare a set of expected
TableSpecs against the live schema introspected fromsystem.columns. Read-only — it reports divergence, it never mutates. Intended to run in CI to catch a deployed schema that no longer matches the code’s model. - evolve
- Additive, bounded schema evolution — grow a dynamic per-tenant table to match
its
TableSpecwithout ever dropping or modifying existing columns. - flatten
- Flatten + coerce — where arbitrary input meets a table.
- flexible
- The flexible/hybrid multi-tenant table — the most-reused shape.
- introspect
- The live→Rust half of the TS→Rust bridge. TypeScript authors the (static)
schema and ClickHouse holds it; this reads it back into Rust — columns for
check_drift, and a generated row struct viacodegen— so the Rust side is a faithful, drift-checked view of the TS-owned schema and can never silently diverge. - migrate
- Forward-only migration runner. Applies
*.sqlfiles from a directory in lexical order, recording each in a_ch_migrationsbookkeeping table so re-runs are idempotent. There is no auto-diff and no down-migration — schema change is expressed as ordered, append-only SQL files. - safety
- Safe-by-construction primitives for user-defined / multi-tenant ClickHouse
schemas — the Rust-canonical port of
@smooai/clickhouse-kit’s safety core. - table
- Runtime table construction from untrusted specs →
CREATE TABLEDDL. Every identifier is validated and every type goes through the allowlist (ColumnTypeSpec), so a spec built from customer input cannot inject SQL.