Skip to content

feat: multi-database support (two-part) — serve multiple ClickHouse databases, and make cache keys, NATS subjects, policy, and stream params database-aware #404

Description

@taitelee

Two-part issue requested in the #343 review (#343 (review)): multi-database support would break several things at once today, because the bare table name is the identity everywhere — nothing carries the database.

WaveHouse today is single-database (clickhouse.database): schema discovery, ingest, structured queries, pipes, and cache invalidation all assume one database. #343's dependency resolution made the constraint visible: a cross-database read can't be version-invalidated (nothing ever bumps a cross-database table's version), so such reads are now detected and the cached result is TTL-capped (~10 s), and a view reading a cross-database source is unfoldable (its readers TTL-cap too). That bounds staleness but doesn't support the workload — people will reasonably want multiple databases within ClickHouse to separate concerns.

Part 1 — support multiple databases

  • Schema discovery/registry over a configured set of databases (today: one database string; SchemaRegistry keys everything by bare name).
  • Ingest into database-qualified tables (worker insert path + validation).
  • Structured queries and pipes reading across databases; dependency resolution keeping database-qualified names instead of dropping/flagging foreign-database tables (discovery.ResolveTables currently keeps only configured-database names and marks anything else external).

Part 2 — make every identity surface database-aware, in lockstep

The write side and read side must keep building identical namespace keys, so all of these have to move together:

  • NATS subjects: ingest.<table>[.<scope>], dlq.<table> (chsql.SafeEncodeNATS tokens have no database segment).
  • Cache namespaces (table, scope), VersionManager.QueryKey folding, and the base→view cascade (SetDependents), all keyed by bare table name.
  • The database-wide fallback version introduced in feat(pipes): resolve table dependencies for cache invalidation #343 (cache.DatabaseVersionTable, the reserved "*" namespace): with several databases this should become per-database versions.
  • Stream/live-query URL parameters (?table=), policy file table keys, and the SDK surfaces that name tables.
  • Schema refresh + IsKnown + ClearResolvedDeps semantics per database.

Adjacent identity work worth coordinating with: #214 (per-table policy storage / auth scopes), #235 (implement scope — the (table, scope) second dimension).

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/apiHTTP handlers, routing, middlewarearea/cacheLocal / shared / tiered cachingarea/policyAccess control policies (Hasura-style)breaking-changeBreaking change to public API, CLI, or config

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    Status
    Backlog

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions