@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.
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,152 @@
1
+ /**
2
+ * A throwaway `clickhouse-server` in a container: started on a random loopback
3
+ * port under a unique name, and always removed (the shared core's
4
+ * `../core/container.ts`, ready when it answers `/ping`).
5
+ *
6
+ * Generation uses it on a pin move to read the pinned server's catalog. The
7
+ * live tests use the same helper so every container chant starts is started
8
+ * and cleaned up one way. A cluster of replicas with embedded Keeper is
9
+ * ClickHouse's own.
10
+ */
11
+ import { execFile } from "node:child_process";
12
+ import { chmodSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
13
+ import { tmpdir } from "node:os";
14
+ import { join } from "node:path";
15
+ import { promisify } from "node:util";
16
+ import { clickhousePing, clickhouseQuery } from "./http.js";
17
+ import { publishedPort, startScratchContainer, uniqueContainerName } from "../core/container.js";
18
+ export { dockerAvailable } from "../core/container.js";
19
+ const exec = promisify(execFile);
20
+ /**
21
+ * Start `image` and wait until it answers `/ping`. Pulls the image when it is
22
+ * not present, which is the one network step here.
23
+ */
24
+ export async function startScratchServer(image, options = {}) {
25
+ const endpointOf = (port) => ({ url: `http://127.0.0.1:${port}` });
26
+ const c = await startScratchContainer({
27
+ image,
28
+ namePrefix: options.namePrefix ?? "chant-sql",
29
+ containerPort: 8123,
30
+ env: { CLICKHOUSE_SKIP_USER_SETUP: "1" },
31
+ ready: (port) => clickhousePing(endpointOf(port)),
32
+ readyTimeoutMs: options.readyTimeoutMs ?? 60000,
33
+ notReady: "did not answer /ping",
34
+ });
35
+ return { endpoint: endpointOf(c.port), name: c.name, stop: c.stop };
36
+ }
37
+ /**
38
+ * Start servers of `image` on their own Docker network, and wait until each
39
+ * answers and reaches Keeper: `replicas` servers as one shard of replicas,
40
+ * or, with `shards`, that many replicas in each shard (`[2, 1]` is a shard of
41
+ * two replicas and a shard of one server).
42
+ *
43
+ * Keeper is the server's embedded one (`keeper_server`), run by the first
44
+ * server, so the pinned server image and its digest pin Keeper too. Each
45
+ * server gets the macros `{shard}` = `s<n>` and `{replica}` = `r<n>` (the
46
+ * replica numbered within its shard), which a `Replicated` database's and a
47
+ * `Replicated*MergeTree`'s arguments name, and `remote_servers` defines the
48
+ * cluster `cluster` (default `chant`) over all of them, with
49
+ * `internal_replication`, so `ON CLUSTER` reaches every server. Configuration
50
+ * is copied into each container before it starts, with no bind mount.
51
+ */
52
+ export async function startScratchCluster(image, options = {}) {
53
+ const shards = options.shards ?? [options.replicas ?? 2];
54
+ const clusterName = options.cluster ?? "chant";
55
+ const name = uniqueContainerName(options.namePrefix ?? "chant-sql-cluster");
56
+ const network = `${name}-net`;
57
+ // One shard keeps the names the single-shard cluster always had (`<name>-r<n>`).
58
+ const layout = shards.flatMap((replicas, s) => Array.from({ length: replicas }, (_, r) => ({
59
+ shard: `s${s + 1}`,
60
+ replica: `r${r + 1}`,
61
+ host: shards.length === 1 ? `${name}-r${r + 1}` : `${name}-s${s + 1}r${r + 1}`,
62
+ })));
63
+ const nodes = layout.map((l) => l.host);
64
+ const dir = mkdtempSync(join(tmpdir(), "chant-sql-cluster-"));
65
+ let removed = false;
66
+ const stop = async () => {
67
+ if (removed)
68
+ return;
69
+ removed = true;
70
+ await exec("docker", ["rm", "-f", ...nodes]).catch(() => undefined);
71
+ await exec("docker", ["network", "rm", network]).catch(() => undefined);
72
+ rmSync(dir, { recursive: true, force: true });
73
+ };
74
+ const keeper = nodes[0];
75
+ const remoteServers = shards
76
+ .map((_, s) => {
77
+ const hosts = layout.filter((l) => l.shard === `s${s + 1}`).map((l) => `<replica><host>${l.host}</host><port>9000</port></replica>`);
78
+ return `<shard><internal_replication>true</internal_replication>${hosts.join("")}</shard>`;
79
+ })
80
+ .join("");
81
+ const config = (node, i) => `<clickhouse>
82
+ ${i === 0
83
+ ? ` <keeper_server>
84
+ <tcp_port>9181</tcp_port>
85
+ <server_id>1</server_id>
86
+ <log_storage_path>/var/lib/clickhouse/coordination/log</log_storage_path>
87
+ <snapshot_storage_path>/var/lib/clickhouse/coordination/snapshots</snapshot_storage_path>
88
+ <raft_configuration><server><id>1</id><hostname>${keeper}</hostname><port>9234</port></server></raft_configuration>
89
+ </keeper_server>
90
+ `
91
+ : ""} <zookeeper><node><host>${keeper}</host><port>9181</port></node></zookeeper>
92
+ <distributed_ddl><path>/clickhouse/task_queue/ddl</path></distributed_ddl>
93
+ <remote_servers><${clusterName}>${remoteServers}</${clusterName}></remote_servers>
94
+ <macros><shard>${layout[i].shard}</shard><replica>${layout[i].replica}</replica></macros>
95
+ <interserver_http_host>${node}</interserver_http_host>
96
+ </clickhouse>
97
+ `;
98
+ const hostEndpoint = async (node) => ({ url: `http://127.0.0.1:${await publishedPort(node, 8123)}` });
99
+ const waitReady = async (node, endpoint, deadline) => {
100
+ for (;;) {
101
+ const ready = (await clickhousePing(endpoint)) && (await clickhouseQuery(endpoint, "SELECT count() FROM system.zookeeper WHERE path = '/'").then(() => true, () => false));
102
+ if (ready)
103
+ return;
104
+ if (Date.now() > deadline)
105
+ throw new Error(`${node} did not answer and reach Keeper within the timeout`);
106
+ await new Promise((r) => setTimeout(r, 500));
107
+ }
108
+ };
109
+ try {
110
+ await exec("docker", ["network", "create", network]);
111
+ const endpoints = await Promise.all(nodes.map(async (node, i) => {
112
+ await exec("docker", ["create", "--name", node, "--hostname", node, "--network", network, "-p", "127.0.0.1::8123", "-e", "CLICKHOUSE_SKIP_USER_SETUP=1", image], { timeout: 600000 });
113
+ const file = join(dir, `${node}.xml`);
114
+ writeFileSync(file, config(node, i));
115
+ // Readable by the server's own user once copied in, whatever the umask made it.
116
+ chmodSync(file, 0o644);
117
+ await exec("docker", ["cp", file, `${node}:/etc/clickhouse-server/config.d/chant-cluster.xml`]);
118
+ await exec("docker", ["start", node]);
119
+ return hostEndpoint(node);
120
+ }));
121
+ const deadline = Date.now() + (options.readyTimeoutMs ?? 90000);
122
+ for (const [i, endpoint] of endpoints.entries())
123
+ await waitReady(nodes[i], endpoint, deadline);
124
+ const node = (index) => {
125
+ const n = nodes[index];
126
+ if (!n)
127
+ throw new Error(`no replica ${index} in ${name}`);
128
+ return n;
129
+ };
130
+ return {
131
+ replicas: endpoints,
132
+ layout,
133
+ cluster: clusterName,
134
+ name,
135
+ stop,
136
+ async stopReplica(index) {
137
+ await exec("docker", ["stop", node(index)], { timeout: 120000 });
138
+ },
139
+ async startReplica(index) {
140
+ await exec("docker", ["start", node(index)]);
141
+ const endpoint = await hostEndpoint(node(index));
142
+ await waitReady(node(index), endpoint, Date.now() + (options.readyTimeoutMs ?? 90000));
143
+ endpoints[index] = endpoint;
144
+ return endpoint;
145
+ },
146
+ };
147
+ }
148
+ catch (err) {
149
+ await stop();
150
+ throw err;
151
+ }
152
+ }
@@ -0,0 +1,159 @@
1
+ /**
2
+ * Read the argument list out of a ClickHouse engine's one-line `syntax`
3
+ * (`system.table_engines.syntax`, `system.data_skipping_index_types.syntax`).
4
+ *
5
+ * The line is prose, not grammar: `ReplacingMergeTree([ver [, is_deleted]])`,
6
+ * `Join(join_strictness, join_type, k1[, k2, ...])`,
7
+ * `File(format[, path | fd])`. What it does give reliably is each argument's
8
+ * name, position, whether it sits inside brackets (optional), whether it is a
9
+ * quoted placeholder (a string literal), and a trailing `...` (repeatable).
10
+ * That is the generated half of an engine's argument types; what kind of value
11
+ * each argument takes is the overlay's half (`overlays/engines.ts`).
12
+ *
13
+ * A line this reader cannot follow yields `undefined`, never a guess, and the
14
+ * engine's arguments stay untyped.
15
+ */
16
+ function tokenize(text) {
17
+ const out = [];
18
+ let i = 0;
19
+ while (i < text.length) {
20
+ const c = text[i];
21
+ if (/\s/.test(c)) {
22
+ i++;
23
+ }
24
+ else if (c === "[" || c === "]" || c === "," || c === "|" || c === "=") {
25
+ out.push({ t: c });
26
+ i++;
27
+ }
28
+ else if (text.startsWith("...", i)) {
29
+ out.push({ t: "..." });
30
+ i += 3;
31
+ }
32
+ else if (c === "'") {
33
+ const end = text.indexOf("'", i + 1);
34
+ if (end < 0)
35
+ return undefined;
36
+ out.push({ t: "quoted", v: text.slice(i + 1, end) });
37
+ i = end + 1;
38
+ }
39
+ else {
40
+ const m = /^[A-Za-z_][\w.]*/.exec(text.slice(i));
41
+ if (!m)
42
+ return undefined;
43
+ out.push({ t: "name", v: m[0] });
44
+ i += m[0].length;
45
+ }
46
+ }
47
+ return out;
48
+ }
49
+ /** The text between the first `(` after the name and its matching `)`. */
50
+ function argumentText(rest) {
51
+ if (!rest.startsWith("("))
52
+ return undefined;
53
+ let depth = 0;
54
+ for (let i = 0; i < rest.length; i++) {
55
+ if (rest[i] === "(")
56
+ depth++;
57
+ else if (rest[i] === ")") {
58
+ depth--;
59
+ if (depth === 0)
60
+ return rest.slice(1, i);
61
+ }
62
+ }
63
+ return undefined;
64
+ }
65
+ /**
66
+ * Parse `ENGINE = Name(args) ...` or `INDEX name expr TYPE Name(args) ...`.
67
+ * Returns `undefined` for a line that is not one of those shapes or whose
68
+ * argument list does not follow the bracket-and-comma convention.
69
+ */
70
+ export function parseEngineSyntax(syntax) {
71
+ const head = /^(?:ENGINE\s*=\s*|INDEX\s+\S+\s+\S+\s+TYPE\s+)([A-Za-z_]\w*)/.exec(syntax.trim());
72
+ if (!head)
73
+ return undefined;
74
+ const name = head[1];
75
+ const rest = syntax.trim().slice(head[0].length);
76
+ if (!rest.startsWith("("))
77
+ return { name, parenthesised: false, args: [] };
78
+ const inner = argumentText(rest);
79
+ if (inner === undefined)
80
+ return undefined;
81
+ const tokens = tokenize(inner);
82
+ if (!tokens)
83
+ return undefined;
84
+ const args = [];
85
+ let depth = 0;
86
+ let pending;
87
+ let afterBar = false;
88
+ let afterEquals = false;
89
+ const flush = () => {
90
+ if (!pending)
91
+ return;
92
+ args.push({
93
+ name: pending.names.join("|"),
94
+ position: args.length,
95
+ optional: pending.optional,
96
+ quoted: pending.quoted,
97
+ repeated: false,
98
+ named: pending.named,
99
+ });
100
+ pending = undefined;
101
+ };
102
+ for (const tok of tokens) {
103
+ switch (tok.t) {
104
+ case "[":
105
+ depth++;
106
+ break;
107
+ case "]":
108
+ if (depth === 0)
109
+ return undefined;
110
+ depth--;
111
+ break;
112
+ case ",":
113
+ flush();
114
+ afterBar = false;
115
+ afterEquals = false;
116
+ break;
117
+ case "|":
118
+ if (!pending)
119
+ return undefined;
120
+ afterBar = true;
121
+ break;
122
+ case "...":
123
+ // `input_query...` repeats the argument it follows; `k2, ...` repeats the last one.
124
+ flush();
125
+ if (args.length === 0)
126
+ return undefined;
127
+ args[args.length - 1].repeated = true;
128
+ break;
129
+ case "=":
130
+ // `key = value, ...` is a settings tail (BigQuery); `tokenizer = x` names a parameter (text index).
131
+ if (!pending || pending.names.length !== 1)
132
+ return undefined;
133
+ pending.named = true;
134
+ afterEquals = true;
135
+ break;
136
+ case "name":
137
+ case "quoted": {
138
+ if (pending && afterEquals) {
139
+ // The value placeholder after `=` is an example, not a second argument.
140
+ afterEquals = false;
141
+ break;
142
+ }
143
+ if (pending && afterBar) {
144
+ pending.names.push(tok.v);
145
+ afterBar = false;
146
+ break;
147
+ }
148
+ if (pending)
149
+ return undefined;
150
+ pending = { names: [tok.v], quoted: tok.t === "quoted", optional: depth > 0, named: false };
151
+ break;
152
+ }
153
+ }
154
+ }
155
+ flush();
156
+ if (depth !== 0)
157
+ return undefined;
158
+ return { name, parenthesised: true, args };
159
+ }