@intentius/chant-lexicon-sql 0.124.31 → 0.124.33
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/dist/change-set.js +250 -0
- package/dist/clickhouse/access.js +722 -0
- package/dist/clickhouse/apply/apply.js +243 -0
- package/dist/clickhouse/apply/mutations.js +66 -0
- package/dist/clickhouse/apply/statements.js +545 -0
- package/dist/clickhouse/catalog-types.js +7 -0
- package/dist/clickhouse/container.js +152 -0
- package/dist/clickhouse/engine-syntax.js +159 -0
- package/dist/clickhouse/entities.js +593 -0
- package/dist/clickhouse/expressions.js +107 -0
- package/dist/clickhouse/http.js +55 -0
- package/dist/clickhouse/import/generator.js +192 -0
- package/dist/clickhouse/import/inlined.js +207 -0
- package/dist/clickhouse/import/ir.js +160 -0
- package/dist/clickhouse/import/live-export.js +131 -0
- package/dist/clickhouse/import/parser.js +17 -0
- package/dist/clickhouse/live/bind.js +116 -0
- package/dist/clickhouse/live/catalog.js +223 -0
- package/dist/clickhouse/live/describe-resources.js +91 -0
- package/dist/clickhouse/live/undeclarable.js +59 -0
- package/dist/clickhouse/overlays/codecs.js +57 -0
- package/dist/clickhouse/overlays/engines.js +101 -0
- package/dist/clickhouse/overlays/kinds.js +1 -0
- package/dist/clickhouse/overlays/projections.js +26 -0
- package/dist/clickhouse/overlays/skip-indexes.js +40 -0
- package/dist/clickhouse/overlays/ttl.js +34 -0
- package/dist/clickhouse/overlays/types.js +59 -0
- package/dist/clickhouse/ownership.js +83 -0
- package/dist/clickhouse/parser.js +674 -0
- package/dist/clickhouse/plan/commands.js +159 -0
- package/dist/clickhouse/plan/deep.js +345 -0
- package/dist/clickhouse/plan/diff.js +312 -0
- package/dist/clickhouse/plan/disruption.js +73 -0
- package/dist/clickhouse/plan/normalize.js +545 -0
- package/dist/clickhouse/plan/rebuild-handoff.js +57 -0
- package/dist/clickhouse/plan/report.js +26 -0
- package/dist/clickhouse/plan/rules.js +72 -0
- package/dist/clickhouse/plan/schema.js +67 -0
- package/dist/clickhouse/plan/server-format.js +35 -0
- package/dist/clickhouse/rebuild/backfill.js +265 -0
- package/dist/clickhouse/rebuild/engines.js +146 -0
- package/dist/clickhouse/rebuild/observe.js +260 -0
- package/dist/clickhouse/rebuild/op.js +152 -0
- package/dist/clickhouse/rebuild/partitions.js +65 -0
- package/dist/clickhouse/rebuild/receipts.js +120 -0
- package/dist/clickhouse/rebuild/replicas.js +121 -0
- package/dist/clickhouse/rebuild/shards.js +76 -0
- package/dist/clickhouse/rebuild/steps.js +383 -0
- package/dist/clickhouse/rebuild/verify.js +279 -0
- package/dist/clickhouse/row-types.js +151 -0
- package/dist/clickhouse/testing/fake-server.js +47 -0
- package/dist/clickhouse/testing/roundtrip-schema.js +25 -0
- package/dist/clickhouse/testing/writable-server.js +123 -0
- package/dist/clickhouse/tokens.js +23 -0
- package/dist/clickhouse/topology.js +463 -0
- package/dist/clickhouse/type-syntax.js +73 -0
- package/dist/clickhouse.js +25 -0
- package/dist/codegen/classifier-page.js +93 -0
- package/dist/codegen/clickhouse-module.js +249 -0
- package/dist/codegen/coverage-page.js +70 -0
- package/dist/codegen/docs-cli.js +3 -0
- package/dist/codegen/docs.js +222 -0
- package/dist/codegen/generate-cli.js +13 -0
- package/dist/codegen/generate.js +97 -0
- package/dist/codegen/package.js +28 -0
- package/dist/codegen/postgres-classifier-page.js +95 -0
- package/dist/codegen/postgres-module.js +418 -0
- package/dist/codegen/registry.js +52 -0
- package/dist/composites/audit-log-table.js +35 -0
- package/dist/composites/catalog.js +524 -0
- package/dist/composites/cdc-mirror.js +32 -0
- package/dist/composites/clickhouse.js +6 -0
- package/dist/composites/events-table.js +26 -0
- package/dist/composites/index.js +8 -0
- package/dist/composites/join-table.js +25 -0
- package/dist/composites/postgres.js +6 -0
- package/dist/composites/refreshed-view.js +24 -0
- package/dist/composites/replacing-table.js +28 -0
- package/dist/composites/rollup-view.js +29 -0
- package/dist/composites/sharded-table.js +27 -0
- package/dist/composites/soft-delete-table.js +34 -0
- package/dist/composites/tenant-table.js +26 -0
- package/dist/composites/typed.js +8 -0
- package/dist/config.js +206 -0
- package/dist/core/apply.js +93 -0
- package/dist/core/classifier.js +115 -0
- package/dist/core/container.js +69 -0
- package/dist/core/cursor.js +261 -0
- package/dist/core/diff.js +48 -0
- package/dist/core/entity.js +58 -0
- package/dist/core/find-templates.js +118 -0
- package/dist/core/foreign-tables.js +27 -0
- package/dist/core/handoff.js +32 -0
- package/dist/core/index.js +64 -0
- package/dist/core/interpolation.js +191 -0
- package/dist/core/normalize.js +43 -0
- package/dist/core/ownership.js +119 -0
- package/dist/core/receipts.js +22 -0
- package/dist/core/references.js +61 -0
- package/dist/core/statements.js +42 -0
- package/dist/core/template.js +79 -0
- package/dist/core/testing/http-stub.js +21 -0
- package/dist/core/tokens.js +202 -0
- package/dist/core/typed.js +40 -0
- package/dist/core/undeclarable.js +46 -0
- package/dist/coverage.js +161 -0
- package/dist/detect.js +32 -0
- package/dist/dialects.js +18 -0
- package/dist/files/build-root.js +72 -0
- package/dist/files/clickhouse.js +138 -0
- package/dist/files/common.js +58 -0
- package/dist/files/postgres.js +389 -0
- package/dist/generated/clickhouse-types.js +5 -0
- package/dist/generated/clickhouse.js +4361 -0
- package/dist/generated/postgres-types.js +227 -0
- package/dist/generated/postgres.js +3667 -0
- package/dist/import-generator.js +14 -0
- package/dist/import-parser.js +71 -0
- package/dist/index.js +24 -0
- package/dist/init-templates.js +290 -0
- package/dist/integrity.json +2 -2
- package/dist/lint/audit-catalog.js +31 -0
- package/dist/lint/audit-lineage.js +22 -0
- package/dist/lint/post-synth/audit-entries.js +34 -0
- package/dist/lint/post-synth/clickhouse-helpers.js +79 -0
- package/dist/lint/post-synth/clickhouse-type-check.js +162 -0
- package/dist/lint/post-synth/index.js +112 -0
- package/dist/lint/post-synth/postgres-audit-entries.js +35 -0
- package/dist/lint/post-synth/postgres-helpers.js +65 -0
- package/dist/lint/post-synth/postgres-names.js +507 -0
- package/dist/lint/post-synth/sql-helpers.js +23 -0
- package/dist/lint/post-synth/sql101.js +59 -0
- package/dist/lint/post-synth/sql102.js +34 -0
- package/dist/lint/post-synth/sqlch101.js +34 -0
- package/dist/lint/post-synth/sqlch102.js +23 -0
- package/dist/lint/post-synth/sqlch103.js +45 -0
- package/dist/lint/post-synth/sqlch104.js +41 -0
- package/dist/lint/post-synth/sqlch105.js +36 -0
- package/dist/lint/post-synth/sqlch106.js +27 -0
- package/dist/lint/post-synth/sqlch107.js +39 -0
- package/dist/lint/post-synth/sqlch108.js +28 -0
- package/dist/lint/post-synth/sqlch109.js +21 -0
- package/dist/lint/post-synth/sqlch110.js +31 -0
- package/dist/lint/post-synth/sqlch111.js +41 -0
- package/dist/lint/post-synth/sqlch112.js +28 -0
- package/dist/lint/post-synth/sqlch113.js +19 -0
- package/dist/lint/post-synth/sqlch114.js +26 -0
- package/dist/lint/post-synth/sqlch115.js +30 -0
- package/dist/lint/post-synth/sqlch116.js +22 -0
- package/dist/lint/post-synth/sqlch117.js +26 -0
- package/dist/lint/post-synth/sqlch118.js +27 -0
- package/dist/lint/post-synth/sqlch119.js +32 -0
- package/dist/lint/post-synth/sqlch120.js +20 -0
- package/dist/lint/post-synth/sqlch121.js +11 -0
- package/dist/lint/post-synth/sqlch122.js +11 -0
- package/dist/lint/post-synth/sqlch123.js +10 -0
- package/dist/lint/post-synth/sqlch124.js +21 -0
- package/dist/lint/post-synth/sqlch125.js +55 -0
- package/dist/lint/post-synth/sqlch126.js +62 -0
- package/dist/lint/post-synth/sqlch127.js +132 -0
- package/dist/lint/post-synth/sqlpg101.js +25 -0
- package/dist/lint/post-synth/sqlpg102.js +35 -0
- package/dist/lint/post-synth/sqlpg103.js +23 -0
- package/dist/lint/post-synth/sqlpg104.js +23 -0
- package/dist/lint/post-synth/sqlpg105.js +22 -0
- package/dist/lint/post-synth/sqlpg106.js +22 -0
- package/dist/lint/post-synth/sqlpg107.js +22 -0
- package/dist/lint/post-synth/sqlpg108.js +28 -0
- package/dist/lint/post-synth/sqlpg109.js +39 -0
- package/dist/lint/post-synth/sqlpg110.js +38 -0
- package/dist/lint/post-synth/sqlpg111.js +23 -0
- package/dist/lint/post-synth/sqlpg112.js +25 -0
- package/dist/lint/post-synth/sqlpg113.js +29 -0
- package/dist/lint/post-synth/sqlpg114.js +39 -0
- package/dist/lint/post-synth/sqlpg115.js +48 -0
- package/dist/lint/post-synth/sqlpg116.js +26 -0
- package/dist/lint/post-synth/sqlpg117.js +24 -0
- package/dist/lint/post-synth/sqlpg118.js +22 -0
- package/dist/lint/post-synth/sqlpg119.js +41 -0
- package/dist/lint/post-synth/sqlpg120.js +83 -0
- package/dist/lint/post-synth/sqlpg121.js +33 -0
- package/dist/lint/post-synth/sqlpg122.js +27 -0
- package/dist/lint/post-synth/sqlpg123.js +69 -0
- package/dist/lint/post-synth/sqlpg124.js +50 -0
- package/dist/lint/post-synth/sqlpg125.js +41 -0
- package/dist/lint/post-synth/sqlpg126.js +38 -0
- package/dist/lint/rules/index.js +12 -0
- package/dist/lint/rules/postgres-templates.js +27 -0
- package/dist/lint/rules/sqlch001.js +79 -0
- package/dist/lint/rules/sqlch002.js +124 -0
- package/dist/lint/rules/sqlch003.js +69 -0
- package/dist/lint/rules/sqlch004.js +83 -0
- package/dist/lint/rules/sqlpg001.js +68 -0
- package/dist/lint/rules/sqlpg002.js +69 -0
- package/dist/lint/rules/sqlpg003.js +58 -0
- package/dist/lint/rules/sqlpg004.js +77 -0
- package/dist/lint/rules/sqlpg005.js +86 -0
- package/dist/lint/rules/templates.js +25 -0
- package/dist/lint/rules/typed-names.js +132 -0
- package/dist/live-dialect.js +32 -0
- package/dist/lsp/catalog.js +44 -0
- package/dist/lsp/completions.js +136 -0
- package/dist/lsp/hover.js +115 -0
- package/dist/lsp/postgres-catalog.js +176 -0
- package/dist/lsp/postgres-template.js +171 -0
- package/dist/lsp/postgres.js +266 -0
- package/dist/lsp/refs.js +60 -0
- package/dist/lsp/registry.d.ts.map +1 -1
- package/dist/lsp/registry.js +19 -0
- package/dist/lsp/template.js +143 -0
- package/dist/manifest.json +1 -1
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +293 -0
- package/dist/mcp/postgres.js +117 -0
- package/dist/migration-statements.js +243 -0
- package/dist/op/activities/clickhouse-apply.js +83 -0
- package/dist/op/activities/clickhouse-emulator.js +53 -0
- package/dist/op/activities/clickhouse-rebuild.js +119 -0
- package/dist/op/activities/index.js +26 -0
- package/dist/op/activities/postgres-apply.js +126 -0
- package/dist/op/activities/postgres-emulator.js +70 -0
- package/dist/op/activities/postgres-migration.js +156 -0
- package/dist/op/activities/sql-exec.js +57 -0
- package/dist/op/activity-contracts.js +103 -0
- package/dist/package-cli.js +14 -0
- package/dist/plugin.js +259 -0
- package/dist/postgres/access/acl.js +344 -0
- package/dist/postgres/access/changes.js +30 -0
- package/dist/postgres/access/import.js +61 -0
- package/dist/postgres/access/live.js +96 -0
- package/dist/postgres/apply/apply.js +557 -0
- package/dist/postgres/apply/statements.js +882 -0
- package/dist/postgres/catalog-types.js +18 -0
- package/dist/postgres/container.js +58 -0
- package/dist/postgres/entities.js +1390 -0
- package/dist/postgres/entity-types.js +28 -0
- package/dist/postgres/import/generator.js +283 -0
- package/dist/postgres/import/ir.js +53 -0
- package/dist/postgres/import/live-export.js +83 -0
- package/dist/postgres/keywords.js +32 -0
- package/dist/postgres/live/bind.js +130 -0
- package/dist/postgres/live/catalog-kinds.js +301 -0
- package/dist/postgres/live/catalog.js +644 -0
- package/dist/postgres/live/client.js +151 -0
- package/dist/postgres/live/describe-resources.js +135 -0
- package/dist/postgres/live/undeclarable.js +111 -0
- package/dist/postgres/migrate/backfill.js +170 -0
- package/dist/postgres/migrate/batches.js +122 -0
- package/dist/postgres/migrate/carry.js +518 -0
- package/dist/postgres/migrate/handoff.js +59 -0
- package/dist/postgres/migrate/names.js +61 -0
- package/dist/postgres/migrate/observe.js +360 -0
- package/dist/postgres/migrate/op.js +178 -0
- package/dist/postgres/migrate/receipts.js +117 -0
- package/dist/postgres/migrate/replication.js +106 -0
- package/dist/postgres/migrate/steps.js +514 -0
- package/dist/postgres/overlays/columns.js +31 -0
- package/dist/postgres/overlays/constraints.js +52 -0
- package/dist/postgres/overlays/extension-objects.js +88 -0
- package/dist/postgres/overlays/indexes.js +25 -0
- package/dist/postgres/overlays/kinds.js +2 -0
- package/dist/postgres/overlays/partitioning.js +23 -0
- package/dist/postgres/overlays/relations.js +25 -0
- package/dist/postgres/overlays/storage.js +65 -0
- package/dist/postgres/overlays/type-ddl.js +36 -0
- package/dist/postgres/overlays/types.js +74 -0
- package/dist/postgres/parser.js +1824 -0
- package/dist/postgres/plan/commands.js +137 -0
- package/dist/postgres/plan/deep.js +324 -0
- package/dist/postgres/plan/diff.js +499 -0
- package/dist/postgres/plan/disruption.js +64 -0
- package/dist/postgres/plan/normalize.js +889 -0
- package/dist/postgres/plan/report.js +21 -0
- package/dist/postgres/plan/rules.js +115 -0
- package/dist/postgres/plan/schema.js +105 -0
- package/dist/postgres/plan/server-normalize.js +166 -0
- package/dist/postgres/providers/aurora.js +44 -0
- package/dist/postgres/providers/azure.js +53 -0
- package/dist/postgres/providers/cloud-sql.js +41 -0
- package/dist/postgres/providers/index.js +73 -0
- package/dist/postgres/providers/neon.js +44 -0
- package/dist/postgres/providers/rds.js +47 -0
- package/dist/postgres/providers/supabase.js +45 -0
- package/dist/postgres/providers/types.js +21 -0
- package/dist/postgres/row-types.js +107 -0
- package/dist/postgres/testing/fake-client.js +34 -0
- package/dist/postgres/testing/migration.js +48 -0
- package/dist/postgres/testing/roundtrip-schema.js +64 -0
- package/dist/postgres/testing/server.js +47 -0
- package/dist/postgres/testing/writable-server.js +160 -0
- package/dist/postgres/tokens.js +41 -0
- package/dist/postgres.js +15 -0
- package/dist/read/clickhouse.js +82 -0
- package/dist/read/objects.js +44 -0
- package/dist/read/postgres.js +104 -0
- package/dist/read.js +52 -0
- package/dist/receipts.js +207 -0
- package/dist/serializer.js +172 -0
- package/dist/skill-defs.js +93 -0
- package/dist/spec/catalog.js +191 -0
- package/dist/spec/fetch.d.ts.map +1 -1
- package/dist/spec/fetch.js +90 -0
- package/dist/spec/pin.js +42 -0
- package/dist/spec/postgres-catalog.js +171 -0
- package/dist/spec/postgres-fetch.js +91 -0
- package/dist/spec/postgres-pin.js +82 -0
- package/dist/sql-files.js +206 -0
- package/dist/sql-types-command.js +97 -0
- package/dist/sql-types.js +323 -0
- package/dist/token-source.js +156 -0
- package/dist/validate-cli.js +5 -0
- package/dist/validate.js +151 -0
- package/dist/workspace-outputs.js +191 -0
- package/package.json +7 -7
- package/src/codegen/package.ts +2 -2
- package/src/lint/rules/typescript-7.test.ts +2 -1
- package/src/lsp/catalog.ts +2 -2
- package/src/lsp/postgres-catalog.ts +2 -2
- package/src/lsp/registry.ts +2 -1
- package/src/mcp/index.ts +4 -2
- package/src/spec/fetch.ts +2 -2
- package/src/spec/postgres-fetch.ts +2 -2
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Render `src/generated/clickhouse.ts`, the ClickHouse dialect's generated
|
|
3
|
+
* surface: string-literal unions for every named thing in the catalog, the two
|
|
4
|
+
* settings interfaces, and the tables lint and the LSP read (engines with
|
|
5
|
+
* their typed arguments, type families, codecs, skip index types, settings).
|
|
6
|
+
*
|
|
7
|
+
* The overlays are merged here, and checked against the catalog in both
|
|
8
|
+
* directions. An overlay key the pinned server does not have, or a codec at
|
|
9
|
+
* the pin with no overlay entry, is an error: a pin move that changes the
|
|
10
|
+
* grammar has to change the overlay in the same commit.
|
|
11
|
+
*/
|
|
12
|
+
import { parseEngineSyntax } from "../clickhouse/engine-syntax.js";
|
|
13
|
+
import { ENGINE_ARGUMENTS } from "../clickhouse/overlays/engines.js";
|
|
14
|
+
import { SKIP_INDEX_PARAMETERS } from "../clickhouse/overlays/skip-indexes.js";
|
|
15
|
+
import { CODEC_OVERLAY } from "../clickhouse/overlays/codecs.js";
|
|
16
|
+
import { TYPE_PARAMETERS } from "../clickhouse/overlays/types.js";
|
|
17
|
+
import { TTL_SETTINGS } from "../clickhouse/overlays/ttl.js";
|
|
18
|
+
import { PROJECTION_SETTINGS } from "../clickhouse/overlays/projections.js";
|
|
19
|
+
/** Setting types with a TypeScript form; every enum-typed setting (no member list in the catalog) is `string`. */
|
|
20
|
+
const SETTING_TS_TYPES = {
|
|
21
|
+
Bool: "boolean",
|
|
22
|
+
BoolAuto: 'boolean | "auto"',
|
|
23
|
+
UInt64: "number",
|
|
24
|
+
Int64: "number",
|
|
25
|
+
UInt32: "number",
|
|
26
|
+
Int32: "number",
|
|
27
|
+
Float: "number",
|
|
28
|
+
Double: "number",
|
|
29
|
+
Seconds: "number",
|
|
30
|
+
Milliseconds: "number",
|
|
31
|
+
NonZeroUInt64: "number",
|
|
32
|
+
MaxThreads: 'number | "auto"',
|
|
33
|
+
UInt64Auto: 'number | "auto"',
|
|
34
|
+
FloatAuto: 'number | "auto"',
|
|
35
|
+
};
|
|
36
|
+
export function settingTsType(type) {
|
|
37
|
+
return SETTING_TS_TYPES[type] ?? "string";
|
|
38
|
+
}
|
|
39
|
+
const lit = (names) => names.length > 0 ? names.map((n) => JSON.stringify(n)).join(" | ") : "never";
|
|
40
|
+
const key = (name) => (/^[A-Za-z_$][\w$]*$/.test(name) ? name : JSON.stringify(name));
|
|
41
|
+
/** A JSDoc line cannot contain `*\/`. */
|
|
42
|
+
const doc = (text) => text.replace(/\*\//g, "*\\/");
|
|
43
|
+
function mergeArguments(owner, parsed, overlay, errors) {
|
|
44
|
+
if (!parsed) {
|
|
45
|
+
if (overlay)
|
|
46
|
+
errors.push(`${owner}: the overlay types arguments, but the syntax line is not readable`);
|
|
47
|
+
return { typed: false };
|
|
48
|
+
}
|
|
49
|
+
const names = new Set(parsed.args.map((a) => a.name));
|
|
50
|
+
for (const name of Object.keys(overlay ?? {})) {
|
|
51
|
+
if (!names.has(name))
|
|
52
|
+
errors.push(`${owner}: overlay argument "${name}" is not in the syntax line at this pin`);
|
|
53
|
+
}
|
|
54
|
+
const args = parsed.args.map((a) => {
|
|
55
|
+
const o = overlay?.[a.name];
|
|
56
|
+
return {
|
|
57
|
+
name: a.name,
|
|
58
|
+
position: a.position,
|
|
59
|
+
optional: o?.optional ?? a.optional,
|
|
60
|
+
repeated: a.repeated,
|
|
61
|
+
named: a.named,
|
|
62
|
+
kind: o?.kind ?? (a.quoted ? "string" : "unknown"),
|
|
63
|
+
...(o?.values ? { values: o.values } : {}),
|
|
64
|
+
...(o?.range ? { range: o.range } : {}),
|
|
65
|
+
...(o?.note ? { note: o.note } : {}),
|
|
66
|
+
};
|
|
67
|
+
});
|
|
68
|
+
return { args, typed: args.every((a) => a.kind !== "unknown") };
|
|
69
|
+
}
|
|
70
|
+
function settingsInterface(name, rows) {
|
|
71
|
+
const lines = [`export interface ${name} {`];
|
|
72
|
+
for (const r of rows) {
|
|
73
|
+
const tags = [doc(r.summary)];
|
|
74
|
+
if (r.obsolete || r.tier === "Obsolete")
|
|
75
|
+
tags.push("@deprecated obsolete at this pin");
|
|
76
|
+
if (r.tier === "Experimental" || r.tier === "Beta")
|
|
77
|
+
tags.push(`@tier ${r.tier}`);
|
|
78
|
+
if (r.aliasFor)
|
|
79
|
+
tags.push(`@alias ${r.aliasFor}`);
|
|
80
|
+
tags.push(`@default ${doc(JSON.stringify(r.default))}`);
|
|
81
|
+
lines.push(` /** ${tags.filter(Boolean).join(" | ")} */`);
|
|
82
|
+
lines.push(` ${key(r.name)}?: ${settingTsType(r.type)};`);
|
|
83
|
+
}
|
|
84
|
+
lines.push("}");
|
|
85
|
+
return lines.join("\n");
|
|
86
|
+
}
|
|
87
|
+
function settingsTable(name, keyType, rows) {
|
|
88
|
+
const lines = [`export const ${name}: Readonly<Record<${keyType}, SettingSpec>> = {`];
|
|
89
|
+
for (const r of rows) {
|
|
90
|
+
lines.push(` ${key(r.name)}: ${JSON.stringify({ type: r.type, default: r.default, tier: r.tier, obsolete: r.obsolete, readonly: r.readonly })},`);
|
|
91
|
+
}
|
|
92
|
+
lines.push("};");
|
|
93
|
+
return lines.join("\n");
|
|
94
|
+
}
|
|
95
|
+
export function renderClickHouseModule(catalog) {
|
|
96
|
+
const errors = [];
|
|
97
|
+
const notes = [];
|
|
98
|
+
// ── Cross-checks of the overlays against the catalog ──────────────
|
|
99
|
+
const engineNames = new Set(catalog.tableEngines.map((e) => e.name));
|
|
100
|
+
for (const name of Object.keys(ENGINE_ARGUMENTS)) {
|
|
101
|
+
if (!engineNames.has(name))
|
|
102
|
+
errors.push(`overlays/engines.ts: engine ${name} is not in the catalog at ${catalog.version}`);
|
|
103
|
+
}
|
|
104
|
+
const indexNames = new Set(catalog.skipIndexTypes.map((e) => e.name));
|
|
105
|
+
for (const name of Object.keys(SKIP_INDEX_PARAMETERS)) {
|
|
106
|
+
if (!indexNames.has(name))
|
|
107
|
+
errors.push(`overlays/skip-indexes.ts: index type ${name} is not in the catalog`);
|
|
108
|
+
}
|
|
109
|
+
const codecNames = new Set(catalog.codecs.map((c) => c.name));
|
|
110
|
+
for (const name of Object.keys(CODEC_OVERLAY)) {
|
|
111
|
+
if (!codecNames.has(name))
|
|
112
|
+
errors.push(`overlays/codecs.ts: codec ${name} is not in the catalog`);
|
|
113
|
+
}
|
|
114
|
+
for (const name of codecNames) {
|
|
115
|
+
if (!CODEC_OVERLAY[name])
|
|
116
|
+
errors.push(`overlays/codecs.ts: codec ${name} at ${catalog.version} has no entry`);
|
|
117
|
+
}
|
|
118
|
+
const families = new Set(catalog.typeFamilies.filter((t) => !t.aliasOf).map((t) => t.name));
|
|
119
|
+
for (const name of Object.keys(TYPE_PARAMETERS)) {
|
|
120
|
+
if (!families.has(name))
|
|
121
|
+
errors.push(`overlays/types.ts: type family ${name} is not in the catalog`);
|
|
122
|
+
}
|
|
123
|
+
const mtSettings = new Set(catalog.mergeTreeSettings.map((s) => s.name));
|
|
124
|
+
for (const name of [...TTL_SETTINGS, ...PROJECTION_SETTINGS]) {
|
|
125
|
+
if (!mtSettings.has(name))
|
|
126
|
+
errors.push(`overlays: MergeTree setting ${name} is not in the catalog`);
|
|
127
|
+
}
|
|
128
|
+
// ── Engines ────────────────────────────────────────────────────────
|
|
129
|
+
const engineLines = [];
|
|
130
|
+
for (const e of catalog.tableEngines) {
|
|
131
|
+
const parsed = parseEngineSyntax(e.syntax);
|
|
132
|
+
const { args, typed } = mergeArguments(`engine ${e.name}`, parsed, ENGINE_ARGUMENTS[e.name], errors);
|
|
133
|
+
const mergeTree = /MergeTree$/.test(e.name);
|
|
134
|
+
const replicates = /^Replicated.+MergeTree$/.test(e.name) ? e.name.slice("Replicated".length) : undefined;
|
|
135
|
+
if (mergeTree && !typed)
|
|
136
|
+
notes.push(`engine ${e.name}: arguments not fully typed`);
|
|
137
|
+
const spec = {
|
|
138
|
+
capabilities: e.capabilities,
|
|
139
|
+
syntax: e.syntax,
|
|
140
|
+
...(args ? { args } : {}),
|
|
141
|
+
typed,
|
|
142
|
+
mergeTree,
|
|
143
|
+
...(replicates ? { replicates } : {}),
|
|
144
|
+
summary: e.summary,
|
|
145
|
+
};
|
|
146
|
+
engineLines.push(` ${key(e.name)}: ${JSON.stringify(spec)},`);
|
|
147
|
+
}
|
|
148
|
+
const indexLines = [];
|
|
149
|
+
for (const t of catalog.skipIndexTypes) {
|
|
150
|
+
const { args } = mergeArguments(`index ${t.name}`, parseEngineSyntax(t.syntax), SKIP_INDEX_PARAMETERS[t.name], errors);
|
|
151
|
+
indexLines.push(` ${key(t.name)}: ${JSON.stringify({ syntax: t.syntax, ...(args ? { args } : {}), summary: t.summary })},`);
|
|
152
|
+
}
|
|
153
|
+
if (errors.length > 0) {
|
|
154
|
+
throw new Error(`The ClickHouse overlays disagree with the catalog at ${catalog.version}:\n ${errors.join("\n ")}\n` +
|
|
155
|
+
"Update src/clickhouse/overlays/ for this pin.");
|
|
156
|
+
}
|
|
157
|
+
const canonical = catalog.typeFamilies.filter((t) => !t.aliasOf);
|
|
158
|
+
const aliases = catalog.typeFamilies.filter((t) => t.aliasOf);
|
|
159
|
+
const mergeTreeEngines = catalog.tableEngines.filter((e) => /MergeTree$/.test(e.name));
|
|
160
|
+
const header = (what) => [
|
|
161
|
+
`// Generated by \`npm run generate\` from the ClickHouse catalog at ${catalog.version}`,
|
|
162
|
+
`// (src/spec/clickhouse-catalog.snapshot.json) and the overlays in src/clickhouse/overlays/. Do not edit.`,
|
|
163
|
+
`// ${what}`,
|
|
164
|
+
"",
|
|
165
|
+
];
|
|
166
|
+
const declarations = [
|
|
167
|
+
...header("The type surface: unions of every named thing in the catalog, and the two settings interfaces."),
|
|
168
|
+
`/** The ClickHouse release these types were read from. */`,
|
|
169
|
+
`export const CLICKHOUSE_VERSION = ${JSON.stringify(catalog.version)};`,
|
|
170
|
+
"",
|
|
171
|
+
`export type TableEngineName = ${lit(catalog.tableEngines.map((e) => e.name))};`,
|
|
172
|
+
`export type MergeTreeEngineName = ${lit(mergeTreeEngines.map((e) => e.name))};`,
|
|
173
|
+
`export type DatabaseEngineName = ${lit(catalog.databaseEngines.map((e) => e.name))};`,
|
|
174
|
+
`export type ColumnTypeFamily = ${lit(canonical.map((t) => t.name))};`,
|
|
175
|
+
`export type ColumnTypeAlias = ${lit(aliases.map((t) => t.name))};`,
|
|
176
|
+
`export type ColumnTypeName = ColumnTypeFamily | ColumnTypeAlias;`,
|
|
177
|
+
`export type CodecName = ${lit(catalog.codecs.map((c) => c.name))};`,
|
|
178
|
+
`export type SkipIndexType = ${lit(catalog.skipIndexTypes.map((c) => c.name))};`,
|
|
179
|
+
`export type AggregateCombinator = ${lit(catalog.aggregateCombinators.filter((c) => !c.internal).map((c) => c.name))};`,
|
|
180
|
+
`export type TableFunctionName = ${lit(catalog.tableFunctions)};`,
|
|
181
|
+
`export type FormatName = ${lit(catalog.formats.map((f) => f.name))};`,
|
|
182
|
+
`export type InputFormatName = ${lit(catalog.formats.filter((f) => f.input).map((f) => f.name))};`,
|
|
183
|
+
`export type OutputFormatName = ${lit(catalog.formats.filter((f) => f.output).map((f) => f.name))};`,
|
|
184
|
+
`export type AggregateFunctionName = ${lit(catalog.functions.filter((f) => f.aggregate).map((f) => f.name))};`,
|
|
185
|
+
`export type ScalarFunctionName = ${lit(catalog.functions.filter((f) => !f.aggregate).map((f) => f.name))};`,
|
|
186
|
+
"",
|
|
187
|
+
settingsInterface("MergeTreeSettings", catalog.mergeTreeSettings),
|
|
188
|
+
"",
|
|
189
|
+
settingsInterface("QuerySettings", catalog.querySettings),
|
|
190
|
+
"",
|
|
191
|
+
].join("\n");
|
|
192
|
+
const tables = [
|
|
193
|
+
...header("The tables lint and the LSP read, typed by ./clickhouse-types."),
|
|
194
|
+
`import type { CodecSpec, DatabaseEngineSpec, FunctionSpec, SettingSpec, SkipIndexSpec, TableEngineSpec, TypeFamilySpec } from "../clickhouse/catalog-types.js";`,
|
|
195
|
+
`import type { CodecName, ColumnTypeName, DatabaseEngineName, MergeTreeSettings, QuerySettings, SkipIndexType, TableEngineName } from "./clickhouse-types";`,
|
|
196
|
+
"",
|
|
197
|
+
`export * from "./clickhouse-types";`,
|
|
198
|
+
"",
|
|
199
|
+
`export const TABLE_ENGINES: Readonly<Record<TableEngineName, TableEngineSpec>> = {`,
|
|
200
|
+
...engineLines,
|
|
201
|
+
"};",
|
|
202
|
+
"",
|
|
203
|
+
`export const DATABASE_ENGINES: Readonly<Record<DatabaseEngineName, DatabaseEngineSpec>> = {`,
|
|
204
|
+
...catalog.databaseEngines.map((e) => ` ${key(e.name)}: ${JSON.stringify({ syntax: e.syntax, summary: e.summary })},`),
|
|
205
|
+
"};",
|
|
206
|
+
"",
|
|
207
|
+
`export const TYPE_FAMILIES: Readonly<Record<ColumnTypeName, TypeFamilySpec>> = {`,
|
|
208
|
+
...catalog.typeFamilies.map((t) => ` ${key(t.name)}: ${JSON.stringify({ canonical: t.aliasOf ?? t.name, caseInsensitive: t.caseInsensitive })},`),
|
|
209
|
+
"};",
|
|
210
|
+
"",
|
|
211
|
+
`export const CODECS: Readonly<Record<CodecName, CodecSpec>> = {`,
|
|
212
|
+
...catalog.codecs.map((c) => {
|
|
213
|
+
const o = CODEC_OVERLAY[c.name];
|
|
214
|
+
const spec = {
|
|
215
|
+
compression: c.compression,
|
|
216
|
+
generic: c.generic,
|
|
217
|
+
encryption: c.encryption,
|
|
218
|
+
timeseries: c.timeseries,
|
|
219
|
+
experimental: c.experimental,
|
|
220
|
+
role: o.role,
|
|
221
|
+
parameters: o.parameters,
|
|
222
|
+
summary: c.summary,
|
|
223
|
+
};
|
|
224
|
+
return ` ${key(c.name)}: ${JSON.stringify(spec)},`;
|
|
225
|
+
}),
|
|
226
|
+
"};",
|
|
227
|
+
"",
|
|
228
|
+
`/** Every function the server has (\`system.functions\`, origin System), aliases included. */`,
|
|
229
|
+
`export const FUNCTIONS: Readonly<Record<string, FunctionSpec>> = {`,
|
|
230
|
+
...catalog.functions.map((f) => ` ${key(f.name)}: ${JSON.stringify({ aggregate: f.aggregate, caseInsensitive: f.caseInsensitive, ...(f.aliasOf ? { aliasOf: f.aliasOf } : {}) })},`),
|
|
231
|
+
"};",
|
|
232
|
+
"",
|
|
233
|
+
`/** The aggregate function combinators (\`system.aggregate_function_combinators\`): the suffixes of \`countIf\`, \`sumState\`. */`,
|
|
234
|
+
`export const AGGREGATE_COMBINATORS: readonly string[] = ${JSON.stringify(catalog.aggregateCombinators.map((c) => c.name))};`,
|
|
235
|
+
"",
|
|
236
|
+
`/** The table functions (\`system.table_functions\`): \`numbers\`, \`remote\`, \`s3\`. */`,
|
|
237
|
+
`export const TABLE_FUNCTIONS: readonly string[] = ${JSON.stringify(catalog.tableFunctions)};`,
|
|
238
|
+
"",
|
|
239
|
+
`export const SKIP_INDEX_TYPES: Readonly<Record<SkipIndexType, SkipIndexSpec>> = {`,
|
|
240
|
+
...indexLines,
|
|
241
|
+
"};",
|
|
242
|
+
"",
|
|
243
|
+
settingsTable("MERGE_TREE_SETTINGS", "keyof MergeTreeSettings", catalog.mergeTreeSettings),
|
|
244
|
+
"",
|
|
245
|
+
settingsTable("QUERY_SETTINGS", "keyof QuerySettings", catalog.querySettings),
|
|
246
|
+
"",
|
|
247
|
+
].join("\n");
|
|
248
|
+
return { declarations, tables, notes };
|
|
249
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `docs/pages/object-coverage.mdx`, written from the coverage tables
|
|
3
|
+
* (`../coverage/<dialect>.json`) by `npm run docs`, so the page cannot
|
|
4
|
+
* disagree with what import refuses.
|
|
5
|
+
*/
|
|
6
|
+
import { KIND_COVERAGE, PINNED_COMMANDS } from "../coverage.js";
|
|
7
|
+
const cell = (s) => s.replace(/\|/g, "\\|").replace(/[{}<>]/g, (c) => `\\${c}`);
|
|
8
|
+
const STATUS = { declared: "declared", refused: "refused", "out-of-scope": "out of scope" };
|
|
9
|
+
function table(dialect) {
|
|
10
|
+
const rows = [...KIND_COVERAGE[dialect]].sort((a, b) => (a.command < b.command ? -1 : a.command > b.command ? 1 : 0));
|
|
11
|
+
return [
|
|
12
|
+
"| Command | Kind | Status | Declared by, or why not |",
|
|
13
|
+
"|---|---|---|---|",
|
|
14
|
+
...rows.map((r) => {
|
|
15
|
+
const command = `\`${r.command}\`${r.form ? ` (${cell(r.form)})` : ""}`;
|
|
16
|
+
const why = r.status === "declared" ? `\`${r.entity}\`${r.note ? `: ${cell(r.note)}` : ""}` : cell(r.reason ?? "");
|
|
17
|
+
return `| ${command} | ${cell(r.kind)} | ${STATUS[r.status]} | ${why} |`;
|
|
18
|
+
}),
|
|
19
|
+
].join("\n");
|
|
20
|
+
}
|
|
21
|
+
function counts(dialect) {
|
|
22
|
+
const rows = KIND_COVERAGE[dialect];
|
|
23
|
+
const n = (s) => rows.filter((r) => r.status === s).length;
|
|
24
|
+
return `${n("declared")} declared, ${n("refused")} refused, ${n("out-of-scope")} out of scope`;
|
|
25
|
+
}
|
|
26
|
+
export function renderCoveragePage() {
|
|
27
|
+
const pg = PINNED_COMMANDS.postgres.map((p) => p.version).join(", ");
|
|
28
|
+
const ch = PINNED_COMMANDS.clickhouse.map((p) => p.version).join(", ");
|
|
29
|
+
return `---
|
|
30
|
+
title: "Object Coverage"
|
|
31
|
+
label: "Object Coverage"
|
|
32
|
+
description: "Every kind of object each pinned Postgres and ClickHouse server can create, marked declared, refused with a reason, or out of scope, and what import does with each"
|
|
33
|
+
diataxis: reference
|
|
34
|
+
order: 3
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
{/* Written by src/codegen/coverage-page.ts from src/coverage/postgres.json and src/coverage/clickhouse.json. Edit the tables, then run npm run docs. */}
|
|
38
|
+
|
|
39
|
+
Each row is a \`CREATE\` command a pinned server has, or one form of a command where chant treats the forms apart (\`CREATE TYPE ... AS ENUM\` is declared, \`CREATE TYPE ... AS RANGE\` is not). The commands come from the servers' own sources at each pinned version (\`scripts/sql-create-commands.ts\`), and a test fails when a pinned server has a command with no row here, so a new server release cannot add a kind nobody looked at.
|
|
40
|
+
|
|
41
|
+
- **declared**: a tag declares it, and import writes it as that declaration.
|
|
42
|
+
- **refused**: no declaration holds it yet. \`chant import --from <env>\` fails when the server has one, naming every such object (kind, schema, name) at once, and \`chant import schema.sql\` fails on the statement. Nothing is left out without a word.
|
|
43
|
+
- **out of scope**: the environment's, not a schema's: import never reads it.
|
|
44
|
+
|
|
45
|
+
\`--skip-undeclarable\` (\`--parser-option skipUndeclarable\` for a file) imports everything else and lists the refused objects as warnings, for an adopter who keeps those objects by hand for now:
|
|
46
|
+
|
|
47
|
+
\`\`\`bash
|
|
48
|
+
chant import --from prod --skip-undeclarable
|
|
49
|
+
chant import schema.sql --parser-option skipUndeclarable
|
|
50
|
+
\`\`\`
|
|
51
|
+
|
|
52
|
+
What a managed provider, an extension or the server's configuration files define is never refused: an extension's aggregates and casts are the extension's, declared with it, and a quota from \`users.xml\` is the server's. An import with \`--type\`, \`--name\` or \`--owned\` asks only for objects chant can hold, and does not look for the rest.
|
|
53
|
+
|
|
54
|
+
## Postgres
|
|
55
|
+
|
|
56
|
+
Pinned majors: ${pg}. ${counts("postgres")}.
|
|
57
|
+
|
|
58
|
+
${table("postgres")}
|
|
59
|
+
|
|
60
|
+
## ClickHouse
|
|
61
|
+
|
|
62
|
+
Pinned release: ${ch}. ${counts("clickhouse")}.
|
|
63
|
+
|
|
64
|
+
${table("clickhouse")}
|
|
65
|
+
|
|
66
|
+
## Declaring a refused kind
|
|
67
|
+
|
|
68
|
+
A kind becomes declarable in three steps: a tag that declares it, the catalog reader reading it (\`src/postgres/live/catalog.ts\`, \`src/clickhouse/live/catalog.ts\`), and its row flipped to \`declared\` with the entity type, its reason taken out. The row's flip is what stops import refusing the kind. After moving a pin, run \`npx tsx scripts/sql-create-commands.ts\` and give each new command a row.
|
|
69
|
+
`;
|
|
70
|
+
}
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Documentation generation for the sql lexicon: the generated reference pages
|
|
3
|
+
* from the core docs pipeline, plus the authored pages in docs/pages/.
|
|
4
|
+
*/
|
|
5
|
+
import { dirname, join } from "path";
|
|
6
|
+
import { fileURLToPath } from "url";
|
|
7
|
+
import { writeFileSync } from "fs";
|
|
8
|
+
import { docsPipeline, writeDocsSite } from "@intentius/chant/codegen/docs";
|
|
9
|
+
import { renderClassifierPage } from "./classifier-page.js";
|
|
10
|
+
import { renderPostgresClassifierPage } from "./postgres-classifier-page.js";
|
|
11
|
+
import { renderCoveragePage } from "./coverage-page.js";
|
|
12
|
+
const overview = `The sql lexicon declares database schema in TypeScript. It has two dialects,
|
|
13
|
+
each a subpath of the one package: ClickHouse at
|
|
14
|
+
\`@intentius/chant-lexicon-sql/clickhouse\` and Postgres at
|
|
15
|
+
\`@intentius/chant-lexicon-sql/postgres\`. A declaration is the database's own
|
|
16
|
+
\`CREATE\` statement in a tagged template, and an interpolated object or
|
|
17
|
+
column stays a reference. Install it with
|
|
18
|
+
\`npm install --save-dev @intentius/chant @intentius/chant-lexicon-sql\`; each
|
|
19
|
+
dialect's Getting Started page runs the example the lexicon ships.
|
|
20
|
+
|
|
21
|
+
\`\`\`ts
|
|
22
|
+
import { database, table, view } from "@intentius/chant-lexicon-sql/clickhouse";
|
|
23
|
+
|
|
24
|
+
export const analytics = database\`CREATE DATABASE analytics ENGINE = Atomic\`;
|
|
25
|
+
|
|
26
|
+
export const events = table\`
|
|
27
|
+
CREATE TABLE \${analytics}.events (
|
|
28
|
+
user_id UUID,
|
|
29
|
+
kind LowCardinality(String),
|
|
30
|
+
ts DateTime
|
|
31
|
+
)
|
|
32
|
+
ENGINE = MergeTree
|
|
33
|
+
ORDER BY (user_id, kind, ts)\`;
|
|
34
|
+
\`\`\`
|
|
35
|
+
|
|
36
|
+
\`\`\`ts
|
|
37
|
+
import { schema, table, index } from "@intentius/chant-lexicon-sql/postgres";
|
|
38
|
+
|
|
39
|
+
export const app = schema\`CREATE SCHEMA app\`;
|
|
40
|
+
|
|
41
|
+
export const users = table\`
|
|
42
|
+
CREATE TABLE \${app}.users (
|
|
43
|
+
id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
|
|
44
|
+
email text NOT NULL UNIQUE
|
|
45
|
+
)\`;
|
|
46
|
+
|
|
47
|
+
export const usersEmail = index\`
|
|
48
|
+
CREATE INDEX CONCURRENTLY users_email_lower_idx ON \${users} (lower(\${users.columns.email}))\`;
|
|
49
|
+
\`\`\`
|
|
50
|
+
|
|
51
|
+
## Spec-true per dialect
|
|
52
|
+
|
|
53
|
+
Each dialect is true to its own database. For SQL the spec is the database's
|
|
54
|
+
own DDL, so a ClickHouse declaration is a ClickHouse \`CREATE\` statement and a
|
|
55
|
+
Postgres declaration a Postgres one. The names a declaration can use (engines,
|
|
56
|
+
codecs and settings for ClickHouse; types, access methods, storage parameters
|
|
57
|
+
and extensions for Postgres) are generated from a pinned server's own catalog:
|
|
58
|
+
ClickHouse's \`system.*\` tables, and Postgres's \`pg_catalog\` at one pinned
|
|
59
|
+
release of each supported major. There is no neutral schema model that the
|
|
60
|
+
dialects are translated from.
|
|
61
|
+
|
|
62
|
+
The reason is that the databases differ exactly where a schema tool does its
|
|
63
|
+
work. ClickHouse has no foreign keys and no transactional DDL, and it cannot
|
|
64
|
+
change a table's sort key, partition key or engine in place: the rows have to
|
|
65
|
+
be copied into a new table. Postgres makes most changes in place and inside a
|
|
66
|
+
transaction, and what a change costs there is the lock it takes: adding a
|
|
67
|
+
column with a constant default is a catalog change, a type change that
|
|
68
|
+
rewrites the table blocks every reader until it finishes, and an index built
|
|
69
|
+
without \`CONCURRENTLY\` blocks every writer. A neutral model would have to hide
|
|
70
|
+
those differences, so a plan could not say what a change will cost, or carry
|
|
71
|
+
every dialect's features and check each one against the target anyway.
|
|
72
|
+
|
|
73
|
+
So each dialect has its own types, parser, lint rules and post-synth checks,
|
|
74
|
+
change classifier, applier, migration Op, composites and skills. What the two
|
|
75
|
+
share is the way of working:
|
|
76
|
+
|
|
77
|
+
| | ClickHouse | Postgres |
|
|
78
|
+
|---|---|---|
|
|
79
|
+
| Declaring | \`database\`, \`table\`, \`view\` | \`schema\`, \`table\`, \`index\`, \`view\`, \`sequence\`, \`type\`, \`domain\`, \`extension\` |
|
|
80
|
+
| Types from | one pinned \`clickhouse-server\` release | one pinned \`postgres\` release per major, 14 to 18 |
|
|
81
|
+
| Rule ids | SQLCH001-003, SQLCH101-120, SQLCH200-250 | SQLPG001-004, SQLPG101-118, SQLPG200-270 |
|
|
82
|
+
| Change classes | metadata only, background rewrite, rebuild | metadata only, validates under a weaker lock, needs \`CONCURRENTLY\`, \`ACCESS EXCLUSIVE\` rewrite or scan, expand and contract |
|
|
83
|
+
| Applier (\`ApplyOp\` target) | \`clickhouseApply\` (\`clickhouse\`) | \`postgresApply\` (\`postgres\`) |
|
|
84
|
+
| What a plan refuses runs as | \`ClickHouseRebuildOp\` | \`PostgresMigrationOp\` |
|
|
85
|
+
| Ownership marker | a trailer on the object's comment | a trailer on the object's comment |
|
|
86
|
+
|
|
87
|
+
References, dependency order and column lineage work the same way in both, as
|
|
88
|
+
do \`chant sql diff\` and \`chant sql plan\` (they read the build's
|
|
89
|
+
\`dialect\`), import with \`chant import --from <env>\`, the \`-- previously:\`
|
|
90
|
+
rename hint, and the comment trailer that marks what chant owns.
|
|
91
|
+
|
|
92
|
+
One build holds one dialect. A project that declares both ClickHouse and
|
|
93
|
+
Postgres objects fails the build naming one of each; a Postgres database and
|
|
94
|
+
a ClickHouse database are two projects, which a workspace can hold as two
|
|
95
|
+
members. \`sql.dialect\` in \`chant.config.ts\` says which dialect a project is
|
|
96
|
+
when nothing declared says so, as for an import into an empty project.
|
|
97
|
+
|
|
98
|
+
## Pages
|
|
99
|
+
|
|
100
|
+
ClickHouse:
|
|
101
|
+
|
|
102
|
+
- [Getting Started with ClickHouse](./getting-started/): declare a schema,
|
|
103
|
+
build it, apply it to a local server and plan a change against it.
|
|
104
|
+
- [Declaring ClickHouse Tables and Views](./clickhouse-ddl/): databases,
|
|
105
|
+
tables, views and materialized views, and what each kind of interpolation
|
|
106
|
+
means.
|
|
107
|
+
- [Importing a ClickHouse Server](./importing/): \`chant import --from <env>\`
|
|
108
|
+
from \`SHOW CREATE\`.
|
|
109
|
+
- [Planning and the Change Classifier](./change-classifier/): every change
|
|
110
|
+
classified as metadata only, a background rewrite or a rebuild.
|
|
111
|
+
- [Applying to a ClickHouse Server](./applying/): \`clickhouseApply\`, the
|
|
112
|
+
ownership marker, prune and the local server.
|
|
113
|
+
- [Rebuilding a Table](./rebuild/): \`ClickHouseRebuildOp\` for the changes
|
|
114
|
+
ClickHouse cannot make in place.
|
|
115
|
+
- [Where the ClickHouse Types Come From](./clickhouse-catalog/): the pinned
|
|
116
|
+
server and how to move the pin.
|
|
117
|
+
|
|
118
|
+
Postgres:
|
|
119
|
+
|
|
120
|
+
- [Getting Started with Postgres](./postgres-getting-started/): declare a
|
|
121
|
+
schema, apply it to a local server, add a column and an index, and see a
|
|
122
|
+
rename refused.
|
|
123
|
+
- [Declaring Postgres Objects](./postgres-ddl/): the eight tags,
|
|
124
|
+
constraints, \`nextval(\${seq})\`, \`COMMENT ON\` and \`literal()\`.
|
|
125
|
+
- [Importing a Postgres Server](./postgres-importing/): canonical text from
|
|
126
|
+
the catalog's printers, and the objects that belong to someone else.
|
|
127
|
+
- [Postgres Locks and the Change Classifier](./postgres-change-classifier/):
|
|
128
|
+
every change classified by the lock it takes.
|
|
129
|
+
- [Applying to a Postgres Server](./postgres-applying/): transactions,
|
|
130
|
+
\`CONCURRENTLY\`, timeouts, ownership, prune and the local server.
|
|
131
|
+
- [Migrating a Column](./postgres-migration/): \`PostgresMigrationOp\`, the
|
|
132
|
+
expand-and-contract Op for a column rename or type change.
|
|
133
|
+
- [Managed Providers](./postgres-providers/): \`sql.provider\`, SQLPG004, and
|
|
134
|
+
what each provider's data has not verified.
|
|
135
|
+
- [The Postgres Pin and Supported Majors](./postgres-majors/): one pin per
|
|
136
|
+
major, \`sql.postgresMajor\`, and moving a pin.
|
|
137
|
+
|
|
138
|
+
Both dialects:
|
|
139
|
+
|
|
140
|
+
- [References and Lineage](./references-and-lineage/): how references become
|
|
141
|
+
dependency order and column-level lineage.
|
|
142
|
+
- [Composites](./composites/): five ClickHouse and five Postgres composites.
|
|
143
|
+
- [Lint Rules and Checks](./lint-rules/): every lint rule and post-synth
|
|
144
|
+
check.
|
|
145
|
+
- [Object Coverage](./object-coverage/): every kind of object the pinned
|
|
146
|
+
servers can create, declared, refused or out of scope, and what import
|
|
147
|
+
does with each.
|
|
148
|
+
|
|
149
|
+
## Schema changes and \`chant migrate\`
|
|
150
|
+
|
|
151
|
+
\`chant migrate\` translates a file from one lexicon's format into another's,
|
|
152
|
+
such as a GitHub Actions workflow into GitLab CI. It does not run schema
|
|
153
|
+
migrations, and the sql lexicon registers nothing for it. A schema change is a
|
|
154
|
+
change to the declarations: \`chant sql diff\` or \`chant sql plan\` classifies
|
|
155
|
+
it, the dialect's applier makes the changes it can make in place, and a change
|
|
156
|
+
it cannot make runs as a gated migration Op: \`ClickHouseRebuildOp\` (see
|
|
157
|
+
[Rebuilding a Table](./rebuild/)) or \`PostgresMigrationOp\` (see
|
|
158
|
+
[Migrating a Column](./postgres-migration/)).
|
|
159
|
+
`;
|
|
160
|
+
const outputFormat = `A build writes two files, beside each other. Which pair depends on the
|
|
161
|
+
dialect the project declares.
|
|
162
|
+
|
|
163
|
+
- The primary output (the \`-o\` file, \`dist/schema.json\` by convention), one
|
|
164
|
+
JSON document. \`dialect\` is \`clickhouse\` or \`postgres\`. \`applyOrder\`
|
|
165
|
+
lists the export names in the order the objects have to be created.
|
|
166
|
+
\`objects\` holds one entry per declared object, in that order: its export
|
|
167
|
+
name (\`export\`), its type, its SQL name (\`sqlName\`), its parsed
|
|
168
|
+
definition, \`dependsOn\`, and its \`ddl\`. References are written as export
|
|
169
|
+
names and lineage as \`export.column\`.
|
|
170
|
+
- ClickHouse: the types are \`ClickHouse::Database\`, \`::Table\`, \`::View\`
|
|
171
|
+
and \`::MaterializedView\`, and the definition holds columns, engine, keys,
|
|
172
|
+
TTL, settings, indexes, projections and constraints, and for a view its
|
|
173
|
+
\`select\`, \`reads\`, \`to\` and \`lineage\`.
|
|
174
|
+
- Postgres: the document also carries \`postgresMajor\`, the major the
|
|
175
|
+
project targets (\`sql.postgresMajor\`, else 18, the newest pinned). The
|
|
176
|
+
types are \`Postgres::Schema\`, \`::Table\`, \`::Index\`, \`::View\`,
|
|
177
|
+
\`::MaterializedView\`, \`::Sequence\`, \`::Enum\`, \`::Domain\` and
|
|
178
|
+
\`::Extension\`. A table's definition holds its columns, primary key,
|
|
179
|
+
uniques, checks, foreign keys, exclusions and the rest of its clauses; a
|
|
180
|
+
view's its \`query\`, \`reads\` and \`lineage\`; an index's its table,
|
|
181
|
+
method and elements. \`dependsOn\` names the objects and the columns the
|
|
182
|
+
statement references.
|
|
183
|
+
- \`clickhouse.sql\` or \`postgres.sql\`: every statement in \`applyOrder\`, each
|
|
184
|
+
ending in \`;\`, written byte for byte as declared, with a Postgres
|
|
185
|
+
template's \`COMMENT ON\` statements after its \`CREATE\`.
|
|
186
|
+
|
|
187
|
+
The order follows the references: a table after its database or schema and the
|
|
188
|
+
types and sequences it uses, a view after the tables it reads, an index after
|
|
189
|
+
its table, a materialized view after its \`TO\` target. Ties go by export name,
|
|
190
|
+
so the output does not depend on the order files were found in. A reference
|
|
191
|
+
cycle fails the build and names the cycle.
|
|
192
|
+
|
|
193
|
+
\`chant sql diff\`, \`chant sql plan\`, the post-synth checks and the appliers
|
|
194
|
+
read the JSON document. Neither file carries chant's ownership marker: the
|
|
195
|
+
applier adds it to each object's comment when it creates the object (see
|
|
196
|
+
[Applying to a ClickHouse Server](../applying/) and
|
|
197
|
+
[Applying to a Postgres Server](../postgres-applying/)).
|
|
198
|
+
`;
|
|
199
|
+
export async function generateDocs(opts) {
|
|
200
|
+
const pkgDir = dirname(dirname(dirname(fileURLToPath(import.meta.url))));
|
|
201
|
+
writeFileSync(join(pkgDir, "docs", "pages", "change-classifier.mdx"), renderClassifierPage());
|
|
202
|
+
writeFileSync(join(pkgDir, "docs", "pages", "postgres-change-classifier.mdx"), renderPostgresClassifierPage());
|
|
203
|
+
writeFileSync(join(pkgDir, "docs", "pages", "object-coverage.mdx"), renderCoveragePage());
|
|
204
|
+
const config = {
|
|
205
|
+
name: "sql",
|
|
206
|
+
displayName: "SQL",
|
|
207
|
+
description: "Database schema as typed declarations in each database's own DDL: ClickHouse and Postgres",
|
|
208
|
+
distDir: join(pkgDir, "dist"),
|
|
209
|
+
outDir: join(pkgDir, "docs"),
|
|
210
|
+
basePath: process.env.DOCS_BASE_PATH ?? "/chant/lexicons/sql/",
|
|
211
|
+
overview,
|
|
212
|
+
outputFormat,
|
|
213
|
+
serviceFromType: (type) => type.split("::")[0] ?? "SQL",
|
|
214
|
+
srcDir: join(pkgDir, "src"),
|
|
215
|
+
examplesDir: join(pkgDir, "examples"),
|
|
216
|
+
};
|
|
217
|
+
const result = docsPipeline(config);
|
|
218
|
+
writeDocsSite(config, result);
|
|
219
|
+
if (opts?.verbose) {
|
|
220
|
+
console.error(`Generated ${result.pages.size} documentation pages`);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
|
+
import { generate, generatePostgres, writeGeneratedFiles } from "./generate.js";
|
|
3
|
+
// `npm run generate -- --force` reads the pinned servers even when the snapshots match the pins;
|
|
4
|
+
// `--major=18` limits the Postgres read to one major.
|
|
5
|
+
const force = process.argv.includes("--force");
|
|
6
|
+
const majors = process.argv
|
|
7
|
+
.filter((a) => a.startsWith("--major="))
|
|
8
|
+
.map((a) => Number.parseInt(a.slice("--major=".length), 10));
|
|
9
|
+
const result = await generate({ verbose: true, force });
|
|
10
|
+
const postgres = await generatePostgres({ force, ...(majors.length > 0 ? { majors } : {}) });
|
|
11
|
+
for (const note of postgres.notes)
|
|
12
|
+
console.error(`[sql] ${note}`);
|
|
13
|
+
writeGeneratedFiles(result, undefined, postgres);
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The sql lexicon's generation pipeline.
|
|
3
|
+
*
|
|
4
|
+
* Two dialects. ClickHouse's "schema" is the catalog a pinned
|
|
5
|
+
* `clickhouse-server` reports from `system.*`, committed as
|
|
6
|
+
* `src/spec/clickhouse-catalog.snapshot.json` (chant #3195). `fetchSchemas`
|
|
7
|
+
* reads that snapshot, and starts the pinned server only on a pin move; see
|
|
8
|
+
* `src/spec/fetch.ts`.
|
|
9
|
+
*
|
|
10
|
+
* Outputs, under `src/generated/`:
|
|
11
|
+
*
|
|
12
|
+
* - `clickhouse-types.ts` (and `index.d.ts`, the packaged copy): unions of every
|
|
13
|
+
* engine, type family, codec, skip index type, format and function name, and
|
|
14
|
+
* the `MergeTreeSettings` / `QuerySettings` interfaces.
|
|
15
|
+
* - `clickhouse.ts`: the tables lint and the LSP read, with the hand-written
|
|
16
|
+
* overlays (engine argument kinds, codec parameters) merged in.
|
|
17
|
+
* - `lexicon-sql.json`: the entity registry.
|
|
18
|
+
*/
|
|
19
|
+
import { generatePipeline, writeGeneratedArtifacts, } from "@intentius/chant/codegen/generate";
|
|
20
|
+
import { NamingStrategy } from "@intentius/chant/codegen/naming";
|
|
21
|
+
import { dirname } from "path";
|
|
22
|
+
import { fileURLToPath } from "url";
|
|
23
|
+
import { CATALOG_KEY, fetchSchemas } from "../spec/fetch.js";
|
|
24
|
+
import { parseCatalog } from "../spec/catalog.js";
|
|
25
|
+
import { renderClickHouseModule } from "./clickhouse-module.js";
|
|
26
|
+
import { buildRegistry } from "./registry.js";
|
|
27
|
+
import { fetchCatalogs } from "../spec/postgres-fetch.js";
|
|
28
|
+
import { renderPostgresModule } from "./postgres-module.js";
|
|
29
|
+
export async function generate(opts = {}) {
|
|
30
|
+
let notes = [];
|
|
31
|
+
let tables = "";
|
|
32
|
+
const result = await generatePipeline({
|
|
33
|
+
fetchSchemas: (fetchOpts) => fetchSchemas({ force: fetchOpts.force }),
|
|
34
|
+
parseSchema: (typeName, data) => {
|
|
35
|
+
if (typeName !== CATALOG_KEY)
|
|
36
|
+
return null;
|
|
37
|
+
const catalog = parseCatalog(data.toString("utf-8"));
|
|
38
|
+
return {
|
|
39
|
+
typeName,
|
|
40
|
+
catalog,
|
|
41
|
+
propertyTypes: [{ name: "MergeTreeSettings" }, { name: "QuerySettings" }],
|
|
42
|
+
enums: [],
|
|
43
|
+
};
|
|
44
|
+
},
|
|
45
|
+
createNaming: (results) => new NamingStrategy(results.map((r) => ({ typeName: r.typeName, propertyTypes: r.propertyTypes })), {
|
|
46
|
+
priorityNames: {},
|
|
47
|
+
priorityAliases: {},
|
|
48
|
+
priorityPropertyAliases: {},
|
|
49
|
+
serviceAbbreviations: {},
|
|
50
|
+
shortName: (t) => t.split("::").pop(),
|
|
51
|
+
serviceName: (t) => t.split("::")[0] ?? t,
|
|
52
|
+
}),
|
|
53
|
+
generateRegistry: () => buildRegistry(),
|
|
54
|
+
generateTypes: (results) => {
|
|
55
|
+
const catalog = results.find((r) => r.typeName === CATALOG_KEY)?.catalog;
|
|
56
|
+
if (!catalog)
|
|
57
|
+
throw new Error("no ClickHouse catalog was parsed");
|
|
58
|
+
const rendered = renderClickHouseModule(catalog);
|
|
59
|
+
notes = rendered.notes;
|
|
60
|
+
tables = rendered.tables;
|
|
61
|
+
return rendered.declarations;
|
|
62
|
+
},
|
|
63
|
+
generateRuntimeIndex: () => tables,
|
|
64
|
+
}, opts);
|
|
65
|
+
if (result.warnings.length > 0) {
|
|
66
|
+
throw new Error(`sql generation failed:\n ${result.warnings.map((w) => `${w.file}: ${w.error}`).join("\n ")}`);
|
|
67
|
+
}
|
|
68
|
+
if (opts.verbose)
|
|
69
|
+
for (const note of notes)
|
|
70
|
+
console.error(`[sql] ${note}`);
|
|
71
|
+
return result;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Generate the Postgres types: the union of the catalogs of every supported
|
|
75
|
+
* major (`src/spec/postgres-catalog-<major>.snapshot.json`), rendered with the
|
|
76
|
+
* overlays. A server is started only for a major whose pin moved, or with
|
|
77
|
+
* `force`; see `src/spec/postgres-fetch.ts`. The types stay internal to the
|
|
78
|
+
* package until the `/postgres` subpath has entities to export with them.
|
|
79
|
+
*/
|
|
80
|
+
export async function generatePostgres(opts = {}) {
|
|
81
|
+
const catalogs = await fetchCatalogs(opts);
|
|
82
|
+
return renderPostgresModule(catalogs);
|
|
83
|
+
}
|
|
84
|
+
/** Write the generated files under `src/generated/`. */
|
|
85
|
+
export function writeGeneratedFiles(result, pkgDir, postgres) {
|
|
86
|
+
const baseDir = pkgDir ?? dirname(dirname(dirname(fileURLToPath(import.meta.url))));
|
|
87
|
+
writeGeneratedArtifacts({
|
|
88
|
+
baseDir,
|
|
89
|
+
files: {
|
|
90
|
+
"lexicon-sql.json": result.lexiconJSON,
|
|
91
|
+
"index.d.ts": result.typesDTS,
|
|
92
|
+
"clickhouse-types.ts": result.typesDTS,
|
|
93
|
+
"clickhouse.ts": result.indexTS,
|
|
94
|
+
...(postgres ? { "postgres-types.ts": postgres.declarations, "postgres.ts": postgres.tables } : {}),
|
|
95
|
+
},
|
|
96
|
+
});
|
|
97
|
+
}
|