@intentius/chant-lexicon-sql 0.124.31 → 0.124.32

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.
Files changed (322) hide show
  1. package/dist/change-set.js +250 -0
  2. package/dist/clickhouse/access.js +722 -0
  3. package/dist/clickhouse/apply/apply.js +243 -0
  4. package/dist/clickhouse/apply/mutations.js +66 -0
  5. package/dist/clickhouse/apply/statements.js +545 -0
  6. package/dist/clickhouse/catalog-types.js +7 -0
  7. package/dist/clickhouse/container.js +152 -0
  8. package/dist/clickhouse/engine-syntax.js +159 -0
  9. package/dist/clickhouse/entities.js +593 -0
  10. package/dist/clickhouse/expressions.js +107 -0
  11. package/dist/clickhouse/http.js +55 -0
  12. package/dist/clickhouse/import/generator.js +192 -0
  13. package/dist/clickhouse/import/inlined.js +207 -0
  14. package/dist/clickhouse/import/ir.js +160 -0
  15. package/dist/clickhouse/import/live-export.js +131 -0
  16. package/dist/clickhouse/import/parser.js +17 -0
  17. package/dist/clickhouse/live/bind.js +116 -0
  18. package/dist/clickhouse/live/catalog.js +223 -0
  19. package/dist/clickhouse/live/describe-resources.js +91 -0
  20. package/dist/clickhouse/live/undeclarable.js +59 -0
  21. package/dist/clickhouse/overlays/codecs.js +57 -0
  22. package/dist/clickhouse/overlays/engines.js +101 -0
  23. package/dist/clickhouse/overlays/kinds.js +1 -0
  24. package/dist/clickhouse/overlays/projections.js +26 -0
  25. package/dist/clickhouse/overlays/skip-indexes.js +40 -0
  26. package/dist/clickhouse/overlays/ttl.js +34 -0
  27. package/dist/clickhouse/overlays/types.js +59 -0
  28. package/dist/clickhouse/ownership.js +83 -0
  29. package/dist/clickhouse/parser.js +674 -0
  30. package/dist/clickhouse/plan/commands.js +159 -0
  31. package/dist/clickhouse/plan/deep.js +345 -0
  32. package/dist/clickhouse/plan/diff.js +312 -0
  33. package/dist/clickhouse/plan/disruption.js +73 -0
  34. package/dist/clickhouse/plan/normalize.js +545 -0
  35. package/dist/clickhouse/plan/rebuild-handoff.js +57 -0
  36. package/dist/clickhouse/plan/report.js +26 -0
  37. package/dist/clickhouse/plan/rules.js +72 -0
  38. package/dist/clickhouse/plan/schema.js +67 -0
  39. package/dist/clickhouse/plan/server-format.js +35 -0
  40. package/dist/clickhouse/rebuild/backfill.js +265 -0
  41. package/dist/clickhouse/rebuild/engines.js +146 -0
  42. package/dist/clickhouse/rebuild/observe.js +260 -0
  43. package/dist/clickhouse/rebuild/op.js +152 -0
  44. package/dist/clickhouse/rebuild/partitions.js +65 -0
  45. package/dist/clickhouse/rebuild/receipts.js +120 -0
  46. package/dist/clickhouse/rebuild/replicas.js +121 -0
  47. package/dist/clickhouse/rebuild/shards.js +76 -0
  48. package/dist/clickhouse/rebuild/steps.js +383 -0
  49. package/dist/clickhouse/rebuild/verify.js +279 -0
  50. package/dist/clickhouse/row-types.js +151 -0
  51. package/dist/clickhouse/testing/fake-server.js +47 -0
  52. package/dist/clickhouse/testing/roundtrip-schema.js +25 -0
  53. package/dist/clickhouse/testing/writable-server.js +123 -0
  54. package/dist/clickhouse/tokens.js +23 -0
  55. package/dist/clickhouse/topology.js +463 -0
  56. package/dist/clickhouse/type-syntax.js +73 -0
  57. package/dist/clickhouse.js +25 -0
  58. package/dist/codegen/classifier-page.js +93 -0
  59. package/dist/codegen/clickhouse-module.js +249 -0
  60. package/dist/codegen/coverage-page.js +70 -0
  61. package/dist/codegen/docs-cli.js +3 -0
  62. package/dist/codegen/docs.js +222 -0
  63. package/dist/codegen/generate-cli.js +13 -0
  64. package/dist/codegen/generate.js +97 -0
  65. package/dist/codegen/package.js +28 -0
  66. package/dist/codegen/postgres-classifier-page.js +95 -0
  67. package/dist/codegen/postgres-module.js +418 -0
  68. package/dist/codegen/registry.js +52 -0
  69. package/dist/composites/audit-log-table.js +35 -0
  70. package/dist/composites/catalog.js +524 -0
  71. package/dist/composites/cdc-mirror.js +32 -0
  72. package/dist/composites/clickhouse.js +6 -0
  73. package/dist/composites/events-table.js +26 -0
  74. package/dist/composites/index.js +8 -0
  75. package/dist/composites/join-table.js +25 -0
  76. package/dist/composites/postgres.js +6 -0
  77. package/dist/composites/refreshed-view.js +24 -0
  78. package/dist/composites/replacing-table.js +28 -0
  79. package/dist/composites/rollup-view.js +29 -0
  80. package/dist/composites/sharded-table.js +27 -0
  81. package/dist/composites/soft-delete-table.js +34 -0
  82. package/dist/composites/tenant-table.js +26 -0
  83. package/dist/composites/typed.js +8 -0
  84. package/dist/config.js +206 -0
  85. package/dist/core/apply.js +93 -0
  86. package/dist/core/classifier.js +115 -0
  87. package/dist/core/container.js +69 -0
  88. package/dist/core/cursor.js +261 -0
  89. package/dist/core/diff.js +48 -0
  90. package/dist/core/entity.js +58 -0
  91. package/dist/core/find-templates.js +118 -0
  92. package/dist/core/foreign-tables.js +27 -0
  93. package/dist/core/handoff.js +32 -0
  94. package/dist/core/index.js +64 -0
  95. package/dist/core/interpolation.js +191 -0
  96. package/dist/core/normalize.js +43 -0
  97. package/dist/core/ownership.js +119 -0
  98. package/dist/core/receipts.js +22 -0
  99. package/dist/core/references.js +61 -0
  100. package/dist/core/statements.js +42 -0
  101. package/dist/core/template.js +79 -0
  102. package/dist/core/testing/http-stub.js +21 -0
  103. package/dist/core/tokens.js +202 -0
  104. package/dist/core/typed.js +40 -0
  105. package/dist/core/undeclarable.js +46 -0
  106. package/dist/coverage.js +161 -0
  107. package/dist/detect.js +32 -0
  108. package/dist/dialects.js +18 -0
  109. package/dist/files/build-root.js +72 -0
  110. package/dist/files/clickhouse.js +138 -0
  111. package/dist/files/common.js +58 -0
  112. package/dist/files/postgres.js +389 -0
  113. package/dist/generated/clickhouse-types.js +5 -0
  114. package/dist/generated/clickhouse.js +4361 -0
  115. package/dist/generated/postgres-types.js +227 -0
  116. package/dist/generated/postgres.js +3667 -0
  117. package/dist/import-generator.js +14 -0
  118. package/dist/import-parser.js +71 -0
  119. package/dist/index.js +24 -0
  120. package/dist/init-templates.js +290 -0
  121. package/dist/integrity.json +2 -2
  122. package/dist/lint/audit-catalog.js +31 -0
  123. package/dist/lint/audit-lineage.js +22 -0
  124. package/dist/lint/post-synth/audit-entries.js +34 -0
  125. package/dist/lint/post-synth/clickhouse-helpers.js +79 -0
  126. package/dist/lint/post-synth/clickhouse-type-check.js +162 -0
  127. package/dist/lint/post-synth/index.js +112 -0
  128. package/dist/lint/post-synth/postgres-audit-entries.js +35 -0
  129. package/dist/lint/post-synth/postgres-helpers.js +65 -0
  130. package/dist/lint/post-synth/postgres-names.js +507 -0
  131. package/dist/lint/post-synth/sql-helpers.js +23 -0
  132. package/dist/lint/post-synth/sql101.js +59 -0
  133. package/dist/lint/post-synth/sql102.js +34 -0
  134. package/dist/lint/post-synth/sqlch101.js +34 -0
  135. package/dist/lint/post-synth/sqlch102.js +23 -0
  136. package/dist/lint/post-synth/sqlch103.js +45 -0
  137. package/dist/lint/post-synth/sqlch104.js +41 -0
  138. package/dist/lint/post-synth/sqlch105.js +36 -0
  139. package/dist/lint/post-synth/sqlch106.js +27 -0
  140. package/dist/lint/post-synth/sqlch107.js +39 -0
  141. package/dist/lint/post-synth/sqlch108.js +28 -0
  142. package/dist/lint/post-synth/sqlch109.js +21 -0
  143. package/dist/lint/post-synth/sqlch110.js +31 -0
  144. package/dist/lint/post-synth/sqlch111.js +41 -0
  145. package/dist/lint/post-synth/sqlch112.js +28 -0
  146. package/dist/lint/post-synth/sqlch113.js +19 -0
  147. package/dist/lint/post-synth/sqlch114.js +26 -0
  148. package/dist/lint/post-synth/sqlch115.js +30 -0
  149. package/dist/lint/post-synth/sqlch116.js +22 -0
  150. package/dist/lint/post-synth/sqlch117.js +26 -0
  151. package/dist/lint/post-synth/sqlch118.js +27 -0
  152. package/dist/lint/post-synth/sqlch119.js +32 -0
  153. package/dist/lint/post-synth/sqlch120.js +20 -0
  154. package/dist/lint/post-synth/sqlch121.js +11 -0
  155. package/dist/lint/post-synth/sqlch122.js +11 -0
  156. package/dist/lint/post-synth/sqlch123.js +10 -0
  157. package/dist/lint/post-synth/sqlch124.js +21 -0
  158. package/dist/lint/post-synth/sqlch125.js +55 -0
  159. package/dist/lint/post-synth/sqlch126.js +62 -0
  160. package/dist/lint/post-synth/sqlch127.js +132 -0
  161. package/dist/lint/post-synth/sqlpg101.js +25 -0
  162. package/dist/lint/post-synth/sqlpg102.js +35 -0
  163. package/dist/lint/post-synth/sqlpg103.js +23 -0
  164. package/dist/lint/post-synth/sqlpg104.js +23 -0
  165. package/dist/lint/post-synth/sqlpg105.js +22 -0
  166. package/dist/lint/post-synth/sqlpg106.js +22 -0
  167. package/dist/lint/post-synth/sqlpg107.js +22 -0
  168. package/dist/lint/post-synth/sqlpg108.js +28 -0
  169. package/dist/lint/post-synth/sqlpg109.js +39 -0
  170. package/dist/lint/post-synth/sqlpg110.js +38 -0
  171. package/dist/lint/post-synth/sqlpg111.js +23 -0
  172. package/dist/lint/post-synth/sqlpg112.js +25 -0
  173. package/dist/lint/post-synth/sqlpg113.js +29 -0
  174. package/dist/lint/post-synth/sqlpg114.js +39 -0
  175. package/dist/lint/post-synth/sqlpg115.js +48 -0
  176. package/dist/lint/post-synth/sqlpg116.js +26 -0
  177. package/dist/lint/post-synth/sqlpg117.js +24 -0
  178. package/dist/lint/post-synth/sqlpg118.js +22 -0
  179. package/dist/lint/post-synth/sqlpg119.js +41 -0
  180. package/dist/lint/post-synth/sqlpg120.js +83 -0
  181. package/dist/lint/post-synth/sqlpg121.js +33 -0
  182. package/dist/lint/post-synth/sqlpg122.js +27 -0
  183. package/dist/lint/post-synth/sqlpg123.js +69 -0
  184. package/dist/lint/post-synth/sqlpg124.js +50 -0
  185. package/dist/lint/post-synth/sqlpg125.js +41 -0
  186. package/dist/lint/post-synth/sqlpg126.js +38 -0
  187. package/dist/lint/rules/index.js +12 -0
  188. package/dist/lint/rules/postgres-templates.js +27 -0
  189. package/dist/lint/rules/sqlch001.js +79 -0
  190. package/dist/lint/rules/sqlch002.js +124 -0
  191. package/dist/lint/rules/sqlch003.js +69 -0
  192. package/dist/lint/rules/sqlch004.js +83 -0
  193. package/dist/lint/rules/sqlpg001.js +68 -0
  194. package/dist/lint/rules/sqlpg002.js +69 -0
  195. package/dist/lint/rules/sqlpg003.js +58 -0
  196. package/dist/lint/rules/sqlpg004.js +77 -0
  197. package/dist/lint/rules/sqlpg005.js +86 -0
  198. package/dist/lint/rules/templates.js +25 -0
  199. package/dist/lint/rules/typed-names.js +132 -0
  200. package/dist/live-dialect.js +32 -0
  201. package/dist/lsp/catalog.js +44 -0
  202. package/dist/lsp/completions.js +136 -0
  203. package/dist/lsp/hover.js +115 -0
  204. package/dist/lsp/postgres-catalog.js +176 -0
  205. package/dist/lsp/postgres-template.js +171 -0
  206. package/dist/lsp/postgres.js +266 -0
  207. package/dist/lsp/refs.js +60 -0
  208. package/dist/lsp/registry.d.ts.map +1 -1
  209. package/dist/lsp/registry.js +19 -0
  210. package/dist/lsp/template.js +143 -0
  211. package/dist/manifest.json +1 -1
  212. package/dist/mcp/index.d.ts.map +1 -1
  213. package/dist/mcp/index.js +293 -0
  214. package/dist/mcp/postgres.js +117 -0
  215. package/dist/migration-statements.js +243 -0
  216. package/dist/op/activities/clickhouse-apply.js +83 -0
  217. package/dist/op/activities/clickhouse-emulator.js +53 -0
  218. package/dist/op/activities/clickhouse-rebuild.js +119 -0
  219. package/dist/op/activities/index.js +26 -0
  220. package/dist/op/activities/postgres-apply.js +126 -0
  221. package/dist/op/activities/postgres-emulator.js +70 -0
  222. package/dist/op/activities/postgres-migration.js +156 -0
  223. package/dist/op/activities/sql-exec.js +57 -0
  224. package/dist/op/activity-contracts.js +103 -0
  225. package/dist/package-cli.js +14 -0
  226. package/dist/plugin.js +259 -0
  227. package/dist/postgres/access/acl.js +344 -0
  228. package/dist/postgres/access/changes.js +30 -0
  229. package/dist/postgres/access/import.js +61 -0
  230. package/dist/postgres/access/live.js +96 -0
  231. package/dist/postgres/apply/apply.js +557 -0
  232. package/dist/postgres/apply/statements.js +882 -0
  233. package/dist/postgres/catalog-types.js +18 -0
  234. package/dist/postgres/container.js +58 -0
  235. package/dist/postgres/entities.js +1390 -0
  236. package/dist/postgres/entity-types.js +28 -0
  237. package/dist/postgres/import/generator.js +283 -0
  238. package/dist/postgres/import/ir.js +53 -0
  239. package/dist/postgres/import/live-export.js +83 -0
  240. package/dist/postgres/keywords.js +32 -0
  241. package/dist/postgres/live/bind.js +130 -0
  242. package/dist/postgres/live/catalog-kinds.js +301 -0
  243. package/dist/postgres/live/catalog.js +644 -0
  244. package/dist/postgres/live/client.js +151 -0
  245. package/dist/postgres/live/describe-resources.js +135 -0
  246. package/dist/postgres/live/undeclarable.js +111 -0
  247. package/dist/postgres/migrate/backfill.js +170 -0
  248. package/dist/postgres/migrate/batches.js +122 -0
  249. package/dist/postgres/migrate/carry.js +518 -0
  250. package/dist/postgres/migrate/handoff.js +59 -0
  251. package/dist/postgres/migrate/names.js +61 -0
  252. package/dist/postgres/migrate/observe.js +360 -0
  253. package/dist/postgres/migrate/op.js +178 -0
  254. package/dist/postgres/migrate/receipts.js +117 -0
  255. package/dist/postgres/migrate/replication.js +106 -0
  256. package/dist/postgres/migrate/steps.js +514 -0
  257. package/dist/postgres/overlays/columns.js +31 -0
  258. package/dist/postgres/overlays/constraints.js +52 -0
  259. package/dist/postgres/overlays/extension-objects.js +88 -0
  260. package/dist/postgres/overlays/indexes.js +25 -0
  261. package/dist/postgres/overlays/kinds.js +2 -0
  262. package/dist/postgres/overlays/partitioning.js +23 -0
  263. package/dist/postgres/overlays/relations.js +25 -0
  264. package/dist/postgres/overlays/storage.js +65 -0
  265. package/dist/postgres/overlays/type-ddl.js +36 -0
  266. package/dist/postgres/overlays/types.js +74 -0
  267. package/dist/postgres/parser.js +1824 -0
  268. package/dist/postgres/plan/commands.js +137 -0
  269. package/dist/postgres/plan/deep.js +324 -0
  270. package/dist/postgres/plan/diff.js +499 -0
  271. package/dist/postgres/plan/disruption.js +64 -0
  272. package/dist/postgres/plan/normalize.js +889 -0
  273. package/dist/postgres/plan/report.js +21 -0
  274. package/dist/postgres/plan/rules.js +115 -0
  275. package/dist/postgres/plan/schema.js +105 -0
  276. package/dist/postgres/plan/server-normalize.js +166 -0
  277. package/dist/postgres/providers/aurora.js +44 -0
  278. package/dist/postgres/providers/azure.js +53 -0
  279. package/dist/postgres/providers/cloud-sql.js +41 -0
  280. package/dist/postgres/providers/index.js +73 -0
  281. package/dist/postgres/providers/neon.js +44 -0
  282. package/dist/postgres/providers/rds.js +47 -0
  283. package/dist/postgres/providers/supabase.js +45 -0
  284. package/dist/postgres/providers/types.js +21 -0
  285. package/dist/postgres/row-types.js +107 -0
  286. package/dist/postgres/testing/fake-client.js +34 -0
  287. package/dist/postgres/testing/migration.js +48 -0
  288. package/dist/postgres/testing/roundtrip-schema.js +64 -0
  289. package/dist/postgres/testing/server.js +47 -0
  290. package/dist/postgres/testing/writable-server.js +160 -0
  291. package/dist/postgres/tokens.js +41 -0
  292. package/dist/postgres.js +15 -0
  293. package/dist/read/clickhouse.js +82 -0
  294. package/dist/read/objects.js +44 -0
  295. package/dist/read/postgres.js +104 -0
  296. package/dist/read.js +52 -0
  297. package/dist/receipts.js +207 -0
  298. package/dist/serializer.js +172 -0
  299. package/dist/skill-defs.js +93 -0
  300. package/dist/spec/catalog.js +191 -0
  301. package/dist/spec/fetch.d.ts.map +1 -1
  302. package/dist/spec/fetch.js +90 -0
  303. package/dist/spec/pin.js +42 -0
  304. package/dist/spec/postgres-catalog.js +171 -0
  305. package/dist/spec/postgres-fetch.js +91 -0
  306. package/dist/spec/postgres-pin.js +82 -0
  307. package/dist/sql-files.js +206 -0
  308. package/dist/sql-types-command.js +97 -0
  309. package/dist/sql-types.js +323 -0
  310. package/dist/token-source.js +156 -0
  311. package/dist/validate-cli.js +5 -0
  312. package/dist/validate.js +151 -0
  313. package/dist/workspace-outputs.js +191 -0
  314. package/package.json +7 -7
  315. package/src/codegen/package.ts +2 -2
  316. package/src/lint/rules/typescript-7.test.ts +2 -1
  317. package/src/lsp/catalog.ts +2 -2
  318. package/src/lsp/postgres-catalog.ts +2 -2
  319. package/src/lsp/registry.ts +2 -1
  320. package/src/mcp/index.ts +4 -2
  321. package/src/spec/fetch.ts +2 -2
  322. package/src/spec/postgres-fetch.ts +2 -2
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Where generation gets the ClickHouse catalog.
3
+ *
4
+ * The committed snapshot, `clickhouse-catalog.snapshot.json`, is the source
5
+ * every ordinary run reads: a fresh clone, CI and `npm run prepack` generate
6
+ * from it with no Docker and no network. A server is read only when the
7
+ * snapshot cannot serve the pin:
8
+ *
9
+ * - the pin moved (`CLICKHOUSE_VERSION` differs from the snapshot's version),
10
+ * - `force` is set, or
11
+ * - `CHANT_SQL_CLICKHOUSE_URL` names a server to read instead of starting one.
12
+ *
13
+ * Reading a server means starting the pinned image in a throwaway container
14
+ * (or using the named one), checking that its `version()` is the pin, reading
15
+ * `system.*`, and rewriting the snapshot. A server at any other version is
16
+ * refused: a snapshot labelled with one pin and holding another's surface is
17
+ * the failure the pin exists to prevent.
18
+ */
19
+ import { readFileSync, writeFileSync } from "node:fs";
20
+ import { join } from "node:path";
21
+ import { moduleSourceDir } from "@intentius/chant/module-source";
22
+ import { CLICKHOUSE_VERSION, clickhouseImage } from "./pin.js";
23
+ import { parseCatalog, readCatalog, stringifyCatalog } from "./catalog.js";
24
+ import { startScratchServer } from "../clickhouse/container.js";
25
+ export const SNAPSHOT_FILE = join(moduleSourceDir(import.meta.url), "clickhouse-catalog.snapshot.json");
26
+ /** The key the single catalog document is filed under in the pipeline's schema map. */
27
+ export const CATALOG_KEY = "ClickHouse::Catalog";
28
+ function readSnapshot(file) {
29
+ try {
30
+ return parseCatalog(readFileSync(file, "utf-8"));
31
+ }
32
+ catch {
33
+ return undefined;
34
+ }
35
+ }
36
+ /** Read the pinned catalog from a server and refuse any other version. */
37
+ export async function catalogFromServer(endpoint, image) {
38
+ const catalog = await readCatalog(endpoint, image);
39
+ if (catalog.version !== CLICKHOUSE_VERSION) {
40
+ throw new Error(`the server at ${endpoint.url} is ClickHouse ${catalog.version}, not the pinned ${CLICKHOUSE_VERSION}. ` +
41
+ "Point CHANT_SQL_CLICKHOUSE_URL at a server running the pin, or update CLICKHOUSE_IMAGE_DIGEST in src/spec/pin.ts " +
42
+ "together with CLICKHOUSE_VERSION.");
43
+ }
44
+ return catalog;
45
+ }
46
+ /**
47
+ * The catalog for the current pin: the snapshot when it matches, otherwise a
48
+ * fresh read that also rewrites the snapshot.
49
+ */
50
+ export async function fetchCatalog(options = {}) {
51
+ const file = options.snapshotFile ?? SNAPSHOT_FILE;
52
+ const log = options.log ?? ((line) => console.error(line));
53
+ const serverUrl = options.serverUrl ?? process.env.CHANT_SQL_CLICKHOUSE_URL;
54
+ const snapshot = readSnapshot(file);
55
+ if (snapshot && snapshot.version === CLICKHOUSE_VERSION && !options.force && !serverUrl) {
56
+ log(`[sql] clickhouse catalog: committed snapshot at ${snapshot.version}`);
57
+ return snapshot;
58
+ }
59
+ const reason = !snapshot
60
+ ? "no readable snapshot"
61
+ : snapshot.version !== CLICKHOUSE_VERSION
62
+ ? `the pin moved from ${snapshot.version} to ${CLICKHOUSE_VERSION}`
63
+ : serverUrl
64
+ ? "CHANT_SQL_CLICKHOUSE_URL is set"
65
+ : "force";
66
+ let catalog;
67
+ if (serverUrl) {
68
+ log(`[sql] clickhouse catalog: reading ${serverUrl} (${reason})`);
69
+ catalog = await catalogFromServer({ url: serverUrl }, clickhouseImage());
70
+ }
71
+ else {
72
+ const image = clickhouseImage();
73
+ log(`[sql] clickhouse catalog: starting ${image} (${reason})`);
74
+ const server = await startScratchServer(image, { namePrefix: "chant-sql-catalog" });
75
+ try {
76
+ catalog = await catalogFromServer(server.endpoint, image);
77
+ }
78
+ finally {
79
+ await server.stop();
80
+ }
81
+ }
82
+ writeFileSync(file, stringifyCatalog(catalog));
83
+ log(`[sql] clickhouse catalog: wrote ${file}`);
84
+ return catalog;
85
+ }
86
+ /** The pipeline's `fetchSchemas`: one document, the catalog, keyed {@link CATALOG_KEY}. */
87
+ export async function fetchSchemas(options = {}) {
88
+ const catalog = await fetchCatalog(options);
89
+ return new Map([[CATALOG_KEY, Buffer.from(stringifyCatalog(catalog), "utf-8")]]);
90
+ }
@@ -0,0 +1,42 @@
1
+ /**
2
+ * The pinned ClickHouse server the ClickHouse dialect's types come from.
3
+ *
4
+ * ClickHouse publishes no schema for its DDL. The engine names, column type
5
+ * families, codecs, skip index types and both settings surfaces are read from a
6
+ * running server's `system.*` tables (chant #3195), so the pin is a server
7
+ * image, not a document.
8
+ *
9
+ * Pinned to an exact patch of the 26.8 LTS line. 26.3 LTS lacks the `syntax`
10
+ * column on `system.table_engines` and the `system.data_skipping_index_types`
11
+ * table the engine-argument and skip-index types are built from, and two
12
+ * patches of one line differ (26.8.5.13 and 26.8.15.10 differ by nine query
13
+ * settings), so a floating `26.8` tag would change generated output with no
14
+ * commit. The digest sits beside the tag so a re-pushed tag cannot change it
15
+ * unseen either: generation runs `image@digest` and refuses a server whose
16
+ * `version()` is not {@link CLICKHOUSE_VERSION}.
17
+ *
18
+ * Moving the pin: change both constants, then `chant dev generate` (or
19
+ * `npm run generate`). The committed snapshot no longer matches the pin, so
20
+ * generation starts the pinned server, rewrites
21
+ * `src/spec/clickhouse-catalog.snapshot.json`, and the pull request's diff of
22
+ * that file is the surface change. Read its `-` lines: a removed engine or
23
+ * function is what breaks a user's declarations.
24
+ */
25
+ /** The pinned `clickhouse-server` release, as `SELECT version()` reports it. */
26
+ export const CLICKHOUSE_VERSION = "26.8.15.10";
27
+ /** The image digest of `clickhouse/clickhouse-server:<CLICKHOUSE_VERSION>`. Move it with the version. */
28
+ export const CLICKHOUSE_IMAGE_DIGEST = "sha256:9716a352d25f538bd19d868b001141e7a60e4d035bc9b823658c6a071660aa61";
29
+ /** The official server image. */
30
+ export const CLICKHOUSE_IMAGE_REPOSITORY = "clickhouse/clickhouse-server";
31
+ /** The full image reference generation runs: tag for the reader, digest for the runtime. */
32
+ export function clickhouseImage() {
33
+ return `${CLICKHOUSE_IMAGE_REPOSITORY}:${CLICKHOUSE_VERSION}@${CLICKHOUSE_IMAGE_DIGEST}`;
34
+ }
35
+ /**
36
+ * ClickHouse tags its LTS releases `v<version>-lts` on GitHub. The upgrade
37
+ * tooling hands `replace` the raw tag; the constant holds the bare version,
38
+ * which is also the docker tag.
39
+ */
40
+ export function versionFromReleaseTag(tag) {
41
+ return tag.replace(/^v/, "").replace(/-lts$/, "");
42
+ }
@@ -0,0 +1,171 @@
1
+ /**
2
+ * The Postgres catalog: what generation reads from one pinned server's
3
+ * catalog, in the shape the committed snapshot stores (one snapshot per major).
4
+ *
5
+ * Every section is sorted with an explicit `COLLATE "C"`, and the snapshot is
6
+ * written one entry per line, so a pin move is a line diff a reviewer can
7
+ * read. Nothing here depends on the host: `pg_settings.setting` and
8
+ * `reset_val` reflect the scratch server's configuration and are never read
9
+ * (`boot_val` is the compiled default), the Debian build suffix is stripped
10
+ * from `server_version`, and nothing is timestamped.
11
+ */
12
+ import { STORAGE_PARAMETER_SEED } from "../postgres/overlays/storage.js";
13
+ /** The list sections, in the order the snapshot writes them; `storageParameters` follows. */
14
+ export const CATALOG_SECTIONS = [
15
+ "types",
16
+ "accessMethods",
17
+ "opclasses",
18
+ "functions",
19
+ "operators",
20
+ "settings",
21
+ "keywords",
22
+ "extensions",
23
+ ];
24
+ /** The major of a version string: `18.6` is 18. */
25
+ export function majorOf(version) {
26
+ return Number.parseInt(version, 10);
27
+ }
28
+ // ── Reading a server ─────────────────────────────────────────────────
29
+ const C = `collate "C"`;
30
+ const agg = (select, order) => `select coalesce(json_agg(t order by ${order}), '[]'::json) from (${select}) t;`;
31
+ const AGG_SUPPORT_OIDS = `select unnest(array[aggtransfn::oid, aggfinalfn::oid, aggcombinefn::oid, aggserialfn::oid, aggdeserialfn::oid, aggmtransfn::oid, aggminvtransfn::oid, aggmfinalfn::oid]) as oid from pg_aggregate`;
32
+ const QUERIES = {
33
+ version: `select to_json(split_part(current_setting('server_version'), ' ', 1));`,
34
+ versionNum: `select to_json(current_setting('server_version_num')::int);`,
35
+ // Non-array, non-composite types in pg_catalog. format_type() is the SQL
36
+ // spelling, so int4 is integer and bool is boolean.
37
+ types: agg(`select t.typname::text as name, format_type(t.oid, null) as "sqlName", t.typtype::text as kind,
38
+ t.typcategory::text as category, t.typlen::int as len, t.typbyval as byval
39
+ from pg_type t join pg_namespace n on n.oid = t.typnamespace
40
+ where n.nspname = 'pg_catalog' and t.typtype in ('b','d','e','m','p','r')
41
+ and not (t.typcategory = 'A' and t.typname like '\\_%')`, `t.name ${C}`),
42
+ accessMethods: agg(`select a.amname::text as name, a.amtype::text as type,
43
+ case when a.amtype = 'i' then (select json_agg(p order by p ${C}) from unnest(array['asc','desc','nulls_first','nulls_last','orderable','distance_orderable','returnable','search_array','search_nulls','clusterable','index_scan','bitmap_scan','backward_scan','can_order','can_unique','can_multi_col','can_exclude','can_include']) p where pg_indexam_has_property(a.oid, p)) end as properties
44
+ from pg_am a`, `t.name ${C}`),
45
+ opclasses: agg(`select am.amname::text as am, c.opcname::text as name, format_type(c.opcintype, null) as "inputType",
46
+ c.opcdefault as "default", f.opfname::text as family
47
+ from pg_opclass c join pg_am am on am.oid = c.opcmethod join pg_opfamily f on f.oid = c.opcfamily
48
+ join pg_namespace n on n.oid = c.opcnamespace where n.nspname = 'pg_catalog'`, `t.am ${C}, t.name ${C}, t."inputType" ${C}`),
49
+ // One row per name in pg_catalog. Type I/O functions are not callable in any useful way.
50
+ functions: agg(`select p.proname::text as name, string_agg(distinct p.prokind::text, '' order by p.prokind::text) as kinds, count(*)::int as overloads,
51
+ (p.proname like 'pg\\_%' or p.proname like 'binary\\_upgrade%' or p.proname like '%support'
52
+ or coalesce(bool_and(p.oid in (${AGG_SUPPORT_OIDS})), false)) as internal
53
+ from pg_proc p join pg_namespace n on n.oid = p.pronamespace
54
+ where n.nspname = 'pg_catalog'
55
+ and p.oid not in (select unnest(array[typinput::oid, typoutput::oid, typreceive::oid, typsend::oid, typmodin::oid, typmodout::oid, typanalyze::oid, typsubscript::oid]) from pg_type)
56
+ group by p.proname`, `t.name ${C}`),
57
+ operators: agg(`select o.oprname::text as name, string_agg(distinct o.oprkind::text, '' order by o.oprkind::text) as kinds, count(*)::int as overloads
58
+ from pg_operator o join pg_namespace n on n.oid = o.oprnamespace where n.nspname = 'pg_catalog' group by o.oprname`, `t.name ${C}`),
59
+ settings: agg(`select name::text, vartype::text as type, context::text, category::text, unit::text, boot_val as "default", min_val as min, max_val as max, enumvals::text[] as enumvals
60
+ from pg_settings where name not like 'server\\_version%'`, `t.name ${C}`),
61
+ keywords: agg(`select word::text, catcode::text as code, catdesc::text as description from pg_get_keywords()`, `t.word ${C}, t.code ${C}`),
62
+ extensions: agg(`select name::text, default_version::text as "defaultVersion", comment::text as description from pg_available_extensions`, `t.name ${C}`),
63
+ };
64
+ /**
65
+ * Storage parameters (reloptions) are compiled into `reloptions.c`; no catalog
66
+ * lists them. Try every candidate on every relation kind and keep the names
67
+ * the server does not reject as unrecognized. Candidates are every
68
+ * `pg_settings` name plus the overlay's seed. An out-of-range value error
69
+ * counts as accepted.
70
+ */
71
+ function storageProbe() {
72
+ const index = { btree: "a", hash: "a", brin: "a", gin: "arr", gist: "r", spgist: "r" };
73
+ const targets = [
74
+ ["table", "create table probe.x (a int) with (%C=1)"],
75
+ ["toast", "create table probe.x (a text) with (toast.%C=1)"],
76
+ ["view", "create view probe.x with (%C=1) as select 1 as a"],
77
+ ["materialized view", "create materialized view probe.x with (%C=1) as select 1 as a"],
78
+ ...Object.entries(index).map(([am, col]) => [`index:${am}`, `create index x on probe.base using ${am} (${col}) with (%C=1)`]),
79
+ ];
80
+ const cases = targets.map(([t, s]) => `('${t}', $q$${s}$q$)`).join(",\n");
81
+ return `
82
+ drop schema if exists probe cascade; create schema probe;
83
+ create table probe.base (a int, arr int[], r int4range);
84
+ create temp table res (target text, cand text);
85
+ do $do$
86
+ declare t record; c record; msg text;
87
+ begin
88
+ for t in select * from (values ${cases}) v(target, stmt) loop
89
+ for c in select distinct n as cand from (select name::text as n from pg_settings union select unnest(string_to_array($seed$${STORAGE_PARAMETER_SEED.join(",")}$seed$, ','))) s(n) loop
90
+ begin
91
+ execute replace(t.stmt, '%C', quote_ident(c.cand));
92
+ insert into res values (t.target, c.cand);
93
+ execute case when t.target like 'index%' then 'drop index probe.x'
94
+ when t.target like 'mat%' then 'drop materialized view probe.x'
95
+ when t.target = 'view' then 'drop view probe.x' else 'drop table probe.x' end;
96
+ exception when others then
97
+ get stacked diagnostics msg = message_text;
98
+ if msg not like 'unrecognized parameter%' and msg not like 'syntax error%' then
99
+ insert into res values (t.target, c.cand);
100
+ end if;
101
+ end;
102
+ end loop;
103
+ end loop;
104
+ end $do$;
105
+ drop schema probe cascade;
106
+ ${agg(`select target, cand as name from res`, `t.target ${C}, t.name ${C}`)}`;
107
+ }
108
+ /** Read the catalog from a server. The caller checks that its version is the pin. */
109
+ export async function readCatalog(reader, image) {
110
+ var _a, _b;
111
+ const q = async (key) => (await reader.query(QUERIES[key]));
112
+ const catalog = {
113
+ dialect: "postgres",
114
+ version: await q("version"),
115
+ versionNum: await q("versionNum"),
116
+ image,
117
+ types: await q("types"),
118
+ accessMethods: await q("accessMethods"),
119
+ opclasses: await q("opclasses"),
120
+ functions: await q("functions"),
121
+ operators: await q("operators"),
122
+ settings: await q("settings"),
123
+ keywords: await q("keywords"),
124
+ extensions: await q("extensions"),
125
+ storageParameters: {},
126
+ };
127
+ const probed = (await reader.query(storageProbe()));
128
+ for (const r of probed)
129
+ ((_a = catalog.storageParameters)[_b = r.target] ?? (_a[_b] = [])).push(r.name);
130
+ return catalog;
131
+ }
132
+ // ── The snapshot's text form ─────────────────────────────────────────
133
+ /** Write the catalog with one array entry per line, so a pin move is one changed line per changed entry. */
134
+ export function stringifyCatalog(catalog) {
135
+ const lines = ["{"];
136
+ lines.push(` "dialect": ${JSON.stringify(catalog.dialect)},`);
137
+ lines.push(` "version": ${JSON.stringify(catalog.version)},`);
138
+ lines.push(` "versionNum": ${catalog.versionNum},`);
139
+ lines.push(` "image": ${JSON.stringify(catalog.image)},`);
140
+ for (const section of CATALOG_SECTIONS) {
141
+ const rows = catalog[section];
142
+ if (rows.length === 0) {
143
+ lines.push(` ${JSON.stringify(section)}: [],`);
144
+ continue;
145
+ }
146
+ lines.push(` ${JSON.stringify(section)}: [`);
147
+ rows.forEach((row, j) => lines.push(` ${JSON.stringify(row)}${j === rows.length - 1 ? "" : ","}`));
148
+ lines.push(" ],");
149
+ }
150
+ const targets = Object.keys(catalog.storageParameters);
151
+ lines.push(` "storageParameters": {`);
152
+ targets.forEach((t, j) => lines.push(` ${JSON.stringify(t)}: ${JSON.stringify(catalog.storageParameters[t])}${j === targets.length - 1 ? "" : ","}`));
153
+ lines.push(" }", "}");
154
+ return `${lines.join("\n")}\n`;
155
+ }
156
+ /** Parse and shape-check a snapshot. Throws naming the first section that is missing or not a list. */
157
+ export function parseCatalog(text) {
158
+ const value = JSON.parse(text);
159
+ if (value.dialect !== "postgres")
160
+ throw new Error(`not a Postgres catalog (dialect ${String(value.dialect)})`);
161
+ if (typeof value.version !== "string")
162
+ throw new Error("catalog has no version");
163
+ for (const section of CATALOG_SECTIONS) {
164
+ if (!Array.isArray(value[section]))
165
+ throw new Error(`catalog section ${section} is missing or not a list`);
166
+ }
167
+ if (typeof value.storageParameters !== "object" || value.storageParameters === null) {
168
+ throw new Error("catalog section storageParameters is missing");
169
+ }
170
+ return value;
171
+ }
@@ -0,0 +1,91 @@
1
+ /**
2
+ * Where generation gets the Postgres catalogs.
3
+ *
4
+ * The committed snapshots, `postgres-catalog-<major>.snapshot.json`, are the
5
+ * source every ordinary run reads: a fresh clone, CI and `npm run prepack`
6
+ * generate from them with no Docker and no network. A server is read, one per
7
+ * major, only when a snapshot cannot serve its pin:
8
+ *
9
+ * - the major's pin moved (its `version` in `postgres-pin.ts` differs from the
10
+ * snapshot's) or the snapshot is missing or unreadable, or
11
+ * - `force` is set.
12
+ *
13
+ * Reading a server means starting that major's image by tag and digest in a
14
+ * throwaway container, checking that its `server_version` is the pin, reading
15
+ * the catalog, and rewriting the snapshot. A server at any other version is
16
+ * refused: a snapshot labelled with one pin and holding another's surface is
17
+ * the failure the pin exists to prevent.
18
+ */
19
+ import { readFileSync, writeFileSync } from "node:fs";
20
+ import { join } from "node:path";
21
+ import { moduleSourceDir } from "@intentius/chant/module-source";
22
+ import { POSTGRES_PINS, postgresImage, postgresPin } from "./postgres-pin.js";
23
+ import { parseCatalog, readCatalog, stringifyCatalog } from "./postgres-catalog.js";
24
+ import { startScratchPostgres } from "../postgres/container.js";
25
+ const specDir = moduleSourceDir(import.meta.url);
26
+ /** The committed snapshot of one major. */
27
+ export const snapshotFile = (major, dir = specDir) => join(dir, `postgres-catalog-${major}.snapshot.json`);
28
+ function readSnapshot(file) {
29
+ try {
30
+ return parseCatalog(readFileSync(file, "utf-8"));
31
+ }
32
+ catch {
33
+ return undefined;
34
+ }
35
+ }
36
+ /** Read one pin's catalog from a server and refuse any other version. */
37
+ export async function catalogFromServer(reader, pin, image) {
38
+ const catalog = await readCatalog(reader, image);
39
+ if (catalog.version !== pin.version) {
40
+ throw new Error(`the server for Postgres ${pin.major} is ${catalog.version}, not the pinned ${pin.version}. ` +
41
+ `Run the pinned image, or update the ${pin.major} line of src/spec/postgres-pin.ts: version and digest together.`);
42
+ }
43
+ return catalog;
44
+ }
45
+ const defaultStart = async (image) => {
46
+ const server = await startScratchPostgres(image, { namePrefix: "chant-sql-pg-catalog" });
47
+ return {
48
+ reader: { query: async (sql) => JSON.parse((await server.psql(sql)).trim()) },
49
+ stop: server.stop,
50
+ };
51
+ };
52
+ /**
53
+ * The catalogs for the current pins, oldest major first: each snapshot that
54
+ * matches its pin, and a fresh read (which rewrites the snapshot) for each
55
+ * that does not. Servers run one at a time.
56
+ */
57
+ export async function fetchCatalogs(options = {}) {
58
+ const log = options.log ?? ((line) => console.error(line));
59
+ const start = options.startServer ?? defaultStart;
60
+ const wanted = options.majors ?? POSTGRES_PINS.map((p) => p.major);
61
+ const catalogs = [];
62
+ for (const pin of POSTGRES_PINS) {
63
+ const file = snapshotFile(pin.major, options.snapshotDir);
64
+ const snapshot = readSnapshot(file);
65
+ const read = wanted.includes(pin.major);
66
+ if (snapshot && snapshot.version === pin.version && !(options.force && read)) {
67
+ log(`[sql] postgres ${pin.major} catalog: committed snapshot at ${snapshot.version}`);
68
+ catalogs.push(snapshot);
69
+ continue;
70
+ }
71
+ const reason = !snapshot
72
+ ? "no readable snapshot"
73
+ : snapshot.version !== pin.version
74
+ ? `the pin moved from ${snapshot.version} to ${pin.version}`
75
+ : "force";
76
+ const image = postgresImage(pin.major);
77
+ log(`[sql] postgres ${pin.major} catalog: starting ${image} (${reason})`);
78
+ const server = await start(image);
79
+ let catalog;
80
+ try {
81
+ catalog = await catalogFromServer(server.reader, postgresPin(pin.major), image);
82
+ }
83
+ finally {
84
+ await server.stop();
85
+ }
86
+ writeFileSync(file, stringifyCatalog(catalog));
87
+ log(`[sql] postgres ${pin.major} catalog: wrote ${file}`);
88
+ catalogs.push(catalog);
89
+ }
90
+ return catalogs;
91
+ }
@@ -0,0 +1,82 @@
1
+ /**
2
+ * The pinned Postgres servers the Postgres dialect's types come from.
3
+ *
4
+ * Postgres publishes no schema for its DDL either. Types, access methods,
5
+ * operator classes, settings, keywords, function names and extensions are read
6
+ * from a running server's catalog (chant #3277), so a pin is a server image.
7
+ * One snapshot per supported major, 14 to 18 (14 leaves community support in
8
+ * November 2026, and dropping it is deleting its entry and its snapshot), and
9
+ * the generated types are the union of the five with a `since` and an `until`
10
+ * major on every entry that is not in all of them.
11
+ *
12
+ * Each entry pins an exact minor by tag and by digest. The type surface does
13
+ * not move between minors (17.9 against 17.11 differs by one setting), but a
14
+ * floating `18` tag would change generated output with no commit, and a
15
+ * re-pushed tag must not change it unseen either: generation runs
16
+ * `image@digest` and refuses a server whose `server_version` is not the
17
+ * entry's version. The digest is the multi-arch manifest list's.
18
+ *
19
+ * Moving a pin: change that major's `version` and `digest` on its one line,
20
+ * then `chant dev generate` (or `npm run generate`). The committed snapshot no
21
+ * longer matches, so generation starts that image, rewrites
22
+ * `src/spec/postgres-catalog-<major>.snapshot.json`, and the pull request's
23
+ * diff of that file is the surface change. Read its `-` lines: a removed
24
+ * setting or function is what breaks declarations. Adding a major is one more
25
+ * line here and one more snapshot.
26
+ *
27
+ * The lines are written one per major, in this exact shape, because
28
+ * {@link postgresUpstreamPin} finds a major's version with a regular
29
+ * expression over its line.
30
+ */
31
+ /** The official server image. */
32
+ export const POSTGRES_IMAGE_REPOSITORY = "postgres";
33
+ /** One pin per supported major, oldest first. */
34
+ export const POSTGRES_PINS = [
35
+ { major: 14, version: "14.24", digest: "sha256:c2427de38f998489d36de7ca3553db2134872c400f2b08be4b824e5c50e4d619" },
36
+ { major: 15, version: "15.19", digest: "sha256:724292da1f2e50bdccfc3302ce75bbba7f4a6076701b588cc795fcac65683550" },
37
+ { major: 16, version: "16.15", digest: "sha256:1a6ab3f5345eb6dbe04a1349529caabdb0ab09293a09590fad07b2246bfa4b54" },
38
+ { major: 17, version: "17.11", digest: "sha256:d74eeac9a635390a49bc21bd49fccd973de707e2a53a76ac49b552b8712ec46f" },
39
+ { major: 18, version: "18.6", digest: "sha256:5a5a84b19854a9ffaa54082c166ff4ec27473a361e496e5ea167f298f2da9722" },
40
+ ];
41
+ /** The supported majors, oldest first. */
42
+ export const POSTGRES_MAJORS = POSTGRES_PINS.map((p) => p.major);
43
+ /** The latest supported major: the emulator image and the default for a project that names no version. */
44
+ export const POSTGRES_LATEST_MAJOR = POSTGRES_MAJORS[POSTGRES_MAJORS.length - 1];
45
+ export function postgresPin(major) {
46
+ const pin = POSTGRES_PINS.find((p) => p.major === major);
47
+ if (!pin)
48
+ throw new Error(`Postgres ${major} is not a supported major (${POSTGRES_MAJORS.join(", ")})`);
49
+ return pin;
50
+ }
51
+ /** The full image reference generation runs: tag for the reader, digest for the runtime. */
52
+ export function postgresImage(major) {
53
+ const pin = postgresPin(major);
54
+ return `${POSTGRES_IMAGE_REPOSITORY}:${pin.version}@${pin.digest}`;
55
+ }
56
+ /**
57
+ * `postgres/postgres` publishes no GitHub releases, only tags: `REL_18_6`,
58
+ * `REL_18_BETA1`, `REL_18_RC1`, `REL9_6_24`, `Release_2_0`. A stable release
59
+ * maps to `18.6`; every other spelling is skipped.
60
+ */
61
+ export function versionFromReleaseTag(tag) {
62
+ const m = /^REL_(\d+)_(\d+)$/.exec(tag);
63
+ return m ? `${m[1]}.${m[2]}` : null;
64
+ }
65
+ /**
66
+ * The upstream pin descriptor for one major's line in this file, labelled
67
+ * `postgres-<major>`. The sql plugin lists all five in `upstreamPins` beside
68
+ * ClickHouse's `upstreamPin`, so `chant dev pinned-upgrade` and the upgrade Op
69
+ * report each. Each tracks only its own major (`trackMajor`), so the 17 pin
70
+ * reports `17.12` and never `18.6`.
71
+ */
72
+ export function postgresUpstreamPin(major) {
73
+ postgresPin(major);
74
+ return {
75
+ label: `postgres-${major}`,
76
+ file: "src/spec/postgres-pin.ts",
77
+ pattern: new RegExp(`\\{ major: ${major}, version: "([^"]+)"`),
78
+ replace: (v, line) => line.replace(/version: "[^"]+"/, `version: "${versionFromReleaseTag(v) ?? v}"`),
79
+ alsoMoves: `the digest on the same line of src/spec/postgres-pin.ts moves with the version: set version to the new minor, set digest to that tag's image digest (docker buildx imagetools inspect postgres:<version>), then run \`chant dev generate\` and read the diff of src/spec/postgres-catalog-${major}.snapshot.json. A git tag lands a few days before its image tag, so the report can name a version that has no image yet.`,
80
+ upstream: { owner: "postgres", repo: "postgres", kind: "tags", tagVersion: versionFromReleaseTag, trackMajor: true },
81
+ };
82
+ }