Skip to content

Add ch dictionary primitive#191

Open
jose-enrique-barco wants to merge 9 commits into
mainfrom
feat/add-ch-dictionary-primitive
Open

Add ch dictionary primitive#191
jose-enrique-barco wants to merge 9 commits into
mainfrom
feat/add-ch-dictionary-primitive

Conversation

@jose-enrique-barco

Copy link
Copy Markdown

No description provided.

jose-enrique-barco and others added 9 commits July 14, 2026 12:19
Add DictionaryDefinition/DictionaryAttribute types, the dictionary()
builder, validation rules, canonicalization, CREATE DICTIONARY SQL
rendering, and a binary planner diff (ClickHouse dictionaries have no
ALTER — any structural change becomes a single CREATE OR REPLACE
DICTIONARY, with the source password masked so a redacted [HIDDEN]
value never causes phantom drift).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
… waits

Classify drop_dictionary as destructive (SQL-scan rule + planner-marker
path, with a dependency-break warning), add dictionary to the drift
existence-comparison kind union (following the materialized_view
precedent — existence-drift, not deep-shape), and wait on
system.tables for create_dictionary/drop_dictionary DDL propagation.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…nto schema files

Add create-dictionary-parser.ts to parse attributes/primaryKey/
source/layout/lifetime/comment out of a dictionary's create_table_query
(verified live: DDL dictionaries populate system.tables.create_table_query,
with inline passwords already redacted to [HIDDEN]). Map engine
'Dictionary' to kind 'dictionary' instead of skipping it, and render
pulled dictionaries as dictionary({...}) calls with a leading comment
when the source password was redacted.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Emit a TypeScript interface (and Zod schema when emitZod is enabled)
from a dictionary's attributes, sharing the same field-rendering path
as table row types. Dictionaries are always included in codegen output
regardless of includeViews, since their shape is structured rather than
an arbitrary query.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Add waitForDictionary() (polls system.dictionaries) alongside
waitForTable/waitForView, and migrate-dictionary.e2e.test.ts covering
create -> insert -> dictGet -> structural CREATE OR REPLACE -> dictGet
-> drift-clean -> hand-drop -> drift-dirty (missing_object) -> restore
-> drop-blocked-without---allow-destructive. Add CREATE DICTIONARY /
CREATE OR REPLACE DICTIONARY / dictionary drop cases to the EXPLAIN AST
SQL-validation suite.

Verified end-to-end against a local ClickHouse 26.6 Docker container:
all cases pass, plus a manual pull round-trip against a
CLICKHOUSE()-sourced dictionary confirmed system.tables.create_table_query
is populated for DDL dictionaries and the pulled schema file typechecks.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Add dictionary() to the DSL reference (fields, attributes, credential
handling via env-var interpolation, no-ALTER semantics), mention it in
the schema overview and ClickHouse compatibility guide, and document
the pull plugin's [HIDDEN]-password handling and codegen's dictionary
interface generation.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…, and BIDIRECTIONAL

The dictionary model, SQL renderer, and introspection parser only covered
PRIMARY KEY/SOURCE/LAYOUT/LIFETIME and a handful of attribute modifiers, so
chkit silently dropped RANGE(...) (required by RANGE_HASHED layouts),
SETTINGS(...), and the BIDIRECTIONAL attribute modifier on every pull and
re-render. Verified the exact rendered DDL against a live ClickHouse
instance, including the full introspect-then-parse round trip.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…STER on replace

Dictionary renamedFrom was dead API surface — nothing read it, so a renamed
dictionary always diffed as drop_dictionary + create_dictionary. Wired it
into the same schema/CLI rename-mapping pipeline tables already use
(remap-before-diff + post-hoc operation injection), added a matching
--rename-dictionary flag, and confirmed RENAME DICTIONARY IF EXISTS is
accepted and idempotent against a live ClickHouse instance.

Also fixes a related gap found in the process: ON CLUSTER injection matched
on the literal "CREATE DICTIONARY" prefix, so it silently never applied to
CREATE OR REPLACE DICTIONARY — meaning every structural change to a
dictionary (there is no ALTER DICTIONARY) went unreplicated in cluster mode.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Covers the full dictionary() feature shipped on this branch: DSL/validation/
SQL/planner support, RANGE/SETTINGS/BIDIRECTIONAL, pull introspection,
codegen, destructive-op safety, rename support, and the ON CLUSTER fix.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant