@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,243 @@
1
+ /**
2
+ * The ClickHouse applier (#3208): make a server hold what a build declares,
3
+ * for every change the classifier (`../plan/rules.ts`) puts in the metadata
4
+ * or background-rewrite class, and refuse the rest.
5
+ *
6
+ * Per declared object, exactly one verdict (lexicon-authoring/applying.mdx):
7
+ *
8
+ * - APPLIED `created`: absent on the server; created from its declared
9
+ * `CREATE`, with chant's ownership marker in its comment.
10
+ * - APPLIED `updated`: present, and the `ALTER`s for its changes ran. A
11
+ * background rewrite (a column type change, a TTL change) is waited on in
12
+ * `system.mutations` before the object counts as applied.
13
+ * - APPLIED `unchanged`: present, nothing to change, the marker in place.
14
+ * - NOT-ATTEMPTED `unsupported-kind`: a change ClickHouse cannot make with
15
+ * `ALTER` (a sorting key, a partition key, an engine, a key column's type).
16
+ * Nothing is sent for the object; the detail names each rule and the
17
+ * restriction behind it, and names the rebuild migration Op to run instead
18
+ * (`ClickHouseRebuildOp`, #3198).
19
+ * - NOT-ATTEMPTED `filtered`: the change drops a column, which destroys its
20
+ * data, and the apply was not allowed to delete.
21
+ * - NOT-ATTEMPTED `dependency-failed`: an object it references is not on the
22
+ * server, because creating it failed or was not attempted.
23
+ * - NOT-ATTEMPTED with the binding's reason: no server to apply to.
24
+ *
25
+ * A statement the server refuses is neither: the object was attempted and did
26
+ * not converge. The rest of the apply goes on, and the applier then throws
27
+ * {@link ClickHouseApplyError}, which carries the outcome so far.
28
+ *
29
+ * Prune, when asked for, drops the objects in the declared databases that the
30
+ * build no longer declares and whose comment carries this project's marker
31
+ * (stack and env). Nothing else is ever dropped: an object without the marker
32
+ * is not chant's, and one with another stack's marker is that stack's.
33
+ */
34
+ import { SqlApplyError, dependencyFailedDetail, missingDependencies, readBuildObjects, } from "../../core/apply.js";
35
+ import { clickhouseQuery } from "../http.js";
36
+ import { ACCESS_KINDS, ACCESS_UNMANAGED_DETAIL, declaredAccess, readLiveAccess, readLiveSchema } from "../live/catalog.js";
37
+ import { canonicalObject, grantsObject, liveCanonical, objectKey, scopeOf } from "../plan/normalize.js";
38
+ import { grantsByGrantee } from "../access.js";
39
+ import { diffSchemas } from "../plan/diff.js";
40
+ import { dropFormattingOnly } from "../plan/server-format.js";
41
+ import { CLICKHOUSE_ENTITY_TYPES } from "../entities.js";
42
+ import { carriesMarker, isChantManaged } from "../ownership.js";
43
+ import { planStatements, sqlString } from "./statements.js";
44
+ import { waitForMutations } from "./mutations.js";
45
+ import { renderFor } from "../topology.js";
46
+ /**
47
+ * The objects a `chant build` output declares, in creation order. Takes the
48
+ * sql lexicon's primary output, or a multi-lexicon output holding it under
49
+ * `sql` (the shared core's reader).
50
+ *
51
+ * With a `topology`, each declaration is rendered for it first
52
+ * (`../topology.ts`): the engine and `ON CLUSTER` it runs with there, which
53
+ * is what the changes compare and every `CREATE` sends.
54
+ */
55
+ export function declaredObjects(json, defaultDatabase = "default", topology) {
56
+ const objects = readBuildObjects(json, "clickhouse", (o) => o);
57
+ const declared = objects
58
+ .filter((o) => o.type !== CLICKHOUSE_ENTITY_TYPES.grant)
59
+ .map((o) => {
60
+ const ddl = renderFor(o.ddl, topology);
61
+ const canonical = canonicalObject(ddl, defaultDatabase);
62
+ return { exportName: o.export, type: o.type, key: objectKey(canonical), ddl, canonical, dependsOn: o.dependsOn };
63
+ });
64
+ // Grants are compared per grantee (`../access.ts`), once every other object exists, and wait for the
65
+ // grantee when the build declares it: a user the environment has still to create gets none.
66
+ const principals = new Map(declared.filter((o) => o.canonical.kind === "user" || o.canonical.kind === "role").map((o) => [o.canonical.name, o.exportName]));
67
+ for (const g of grantsByGrantee(objects)) {
68
+ const canonical = grantsObject(g.ddl, g.grantee, defaultDatabase);
69
+ const key = objectKey(canonical);
70
+ const grantee = principals.get(g.grantee);
71
+ const dependsOn = grantee !== undefined && !g.dependsOn.includes(grantee) ? [...g.dependsOn, grantee] : g.dependsOn;
72
+ declared.push({ exportName: key, type: CLICKHOUSE_ENTITY_TYPES.grant, key, ddl: g.ddl, canonical, dependsOn });
73
+ }
74
+ return declared;
75
+ }
76
+ /** The plan axis: one ref per declared object, by its kind and its name on the server. */
77
+ export const planRefs = (declared) => declared.map((o) => ({ kind: o.type, name: o.key }));
78
+ /** An apply in which the server refused a statement. The outcome says what did and did not happen. */
79
+ export class ClickHouseApplyError extends SqlApplyError {
80
+ constructor(outcome) {
81
+ super("ClickHouse", outcome);
82
+ this.name = "ClickHouseApplyError";
83
+ }
84
+ }
85
+ const liveKey = (o) => objectKey(o);
86
+ /**
87
+ * The server's objects in the databases the declarations use, as the diff
88
+ * compares them. The `default` database itself is never part of a schema.
89
+ */
90
+ async function liveSchema(target, declared) {
91
+ const scope = new Set(declared.map((o) => scopeOf(o.canonical)));
92
+ const objects = [...(await readLiveSchema(target)), ...(await readLiveAccess(target, declaredAccess(declared.map((o) => o.canonical))))]
93
+ .filter((o) => !(o.type === CLICKHOUSE_ENTITY_TYPES.database && o.name === "default"))
94
+ .filter((o) => scope.has(scopeOf(o)));
95
+ return { objects, canonical: new Map(objects.map((o) => [liveKey(o), liveCanonical(o, target.defaultDatabase)])) };
96
+ }
97
+ /**
98
+ * The classified changes from the server to the declarations, keyed by the
99
+ * declared object (`database.name`), with formatting-only differences dropped
100
+ * by asking the server, as `chant sql plan` does.
101
+ */
102
+ export async function plannedChanges(target, declared, live) {
103
+ const diff = diffSchemas([...live].map(([key, canonical]) => ({ key, canonical })), declared.map((o) => ({ key: o.key, canonical: o.canonical })));
104
+ return dropFormattingOnly(target.endpoint, diff.changes);
105
+ }
106
+ /**
107
+ * Apply the declarations to the server. Returns every declared object in
108
+ * exactly one of applied or not attempted, and every pruned orphan; throws
109
+ * {@link ClickHouseApplyError} when the server refused a statement.
110
+ */
111
+ export async function applyClickHouse(target, all, opts = {}) {
112
+ const log = opts.log ?? (() => undefined);
113
+ // Access declarations a profile does not manage are not applied, and the server's access is not read (#3716).
114
+ const managed = target.access === true;
115
+ const declared = managed ? all : all.filter((o) => !ACCESS_KINDS.has(o.canonical.kind));
116
+ const { objects: liveObjects, canonical: live } = await liveSchema(target, declared);
117
+ const liveByKey = new Map(liveObjects.map((o) => [liveKey(o), o]));
118
+ const changes = await plannedChanges(target, declared, live);
119
+ const outcome = { target: target.endpoint.url, source: target.source, applied: [], pruned: [], notAttempted: [], failed: [] };
120
+ if (!managed) {
121
+ for (const o of all)
122
+ if (ACCESS_KINDS.has(o.canonical.kind))
123
+ outcome.notAttempted.push({ kind: o.type, name: o.key, reason: "filtered", detail: ACCESS_UNMANAGED_DETAIL });
124
+ }
125
+ /** Export names whose object is on the server. */
126
+ const onServer = new Set();
127
+ const exportNames = new Set(declared.map((o) => o.exportName));
128
+ const run = async (step, obj, ran) => {
129
+ opts.signal?.throwIfAborted();
130
+ log(step.sql);
131
+ await clickhouseQuery(target.endpoint, step.sql);
132
+ ran.push(step.sql);
133
+ if (step.rewrite && obj.database !== undefined) {
134
+ const ids = await waitForMutations(target.endpoint, obj.database, obj.name, {
135
+ ...(opts.mutationTimeoutMs !== undefined ? { timeoutMs: opts.mutationTimeoutMs } : {}),
136
+ ...(opts.signal ? { signal: opts.signal } : {}),
137
+ });
138
+ if (ids.length > 0)
139
+ log(`-- waited for ${ids.join(", ")}`);
140
+ }
141
+ };
142
+ const plan = planStatements({
143
+ declared,
144
+ changes,
145
+ current: live,
146
+ allowDestructive: opts.prune === true,
147
+ carriesMarker: (key) => carriesMarker(liveByKey.get(key)?.comment, opts.marker),
148
+ ...(target.topology ? { topology: target.topology } : {}),
149
+ ...(opts.marker ? { marker: opts.marker } : {}),
150
+ });
151
+ for (const entry of plan.objects) {
152
+ const obj = entry.obj;
153
+ const ref = { kind: obj.type, name: obj.key };
154
+ const renamedFrom = entry.changes.find((c) => c.rule === "SQLCH230" || c.rule === "SQLCH231")?.before;
155
+ const liveObject = liveByKey.get(renamedFrom ?? obj.key);
156
+ if (entry.verdict === "rebuild") {
157
+ if (liveObject)
158
+ onServer.add(obj.exportName);
159
+ outcome.notAttempted.push({ ...ref, reason: "unsupported-kind", detail: entry.detail });
160
+ continue;
161
+ }
162
+ if (entry.verdict === "withheld") {
163
+ // A user the environment has still to create is not on the server, so nothing that needs it is attempted.
164
+ if (liveObject)
165
+ onServer.add(obj.exportName);
166
+ outcome.notAttempted.push({ ...ref, reason: "filtered", detail: entry.detail });
167
+ continue;
168
+ }
169
+ const created = entry.verdict === "create";
170
+ const steps = entry.steps;
171
+ if (steps.length === 0) {
172
+ onServer.add(obj.exportName);
173
+ outcome.applied.push({ ...ref, action: "unchanged", ...(liveObject?.uuid ? { physicalId: liveObject.uuid } : {}), statements: [] });
174
+ continue;
175
+ }
176
+ const missing = missingDependencies(obj.exportName, obj.dependsOn, exportNames, onServer);
177
+ if (missing.length > 0) {
178
+ if (!created)
179
+ onServer.add(obj.exportName);
180
+ outcome.notAttempted.push({ ...ref, reason: "dependency-failed", detail: dependencyFailedDetail(missing) });
181
+ continue;
182
+ }
183
+ const ran = [];
184
+ try {
185
+ for (const step of steps)
186
+ await run(step, { ...(obj.canonical.database !== undefined ? { database: obj.canonical.database } : {}), name: obj.canonical.name }, ran);
187
+ onServer.add(obj.exportName);
188
+ outcome.applied.push({ ...ref, action: created ? "created" : "updated", ...(liveObject?.uuid ? { physicalId: liveObject.uuid } : {}), statements: ran });
189
+ }
190
+ catch (err) {
191
+ if (opts.signal?.aborted)
192
+ throw err;
193
+ if (!created)
194
+ onServer.add(obj.exportName);
195
+ outcome.failed.push({ ...ref, error: err instanceof Error ? err.message : String(err), statements: ran });
196
+ }
197
+ }
198
+ if (opts.prune)
199
+ await prune(target, plan.drops, liveByKey, opts, outcome, log);
200
+ if (outcome.failed.length > 0)
201
+ throw new ClickHouseApplyError(outcome);
202
+ return outcome;
203
+ }
204
+ async function prune(target, drops, liveByKey, opts, outcome, log) {
205
+ for (const drop of drops) {
206
+ const o = liveByKey.get(drop.key);
207
+ if (!o)
208
+ continue;
209
+ const ref = { kind: o.type, name: liveKey(o) };
210
+ if (!isChantManaged(o.comment))
211
+ continue; // not chant's: never touched, never reported
212
+ if (!opts.marker?.stack) {
213
+ outcome.notAttempted.push({
214
+ ...ref,
215
+ reason: "not-prunable",
216
+ detail: "the project declares no ownership.stack, so this project's objects cannot be told from another chant project's",
217
+ });
218
+ continue;
219
+ }
220
+ if (!carriesMarker(o.comment, opts.marker))
221
+ continue; // another stack's or env's
222
+ try {
223
+ if (o.type === CLICKHOUSE_ENTITY_TYPES.database) {
224
+ const [row] = await clickhouseQuery(target.endpoint, `SELECT count() AS n FROM system.tables WHERE database = ${sqlString(o.name)}`);
225
+ const n = Number(row?.n ?? 0);
226
+ if (n > 0) {
227
+ outcome.notAttempted.push({ ...ref, reason: "not-prunable", detail: `still holds ${n} object(s) this apply does not drop; dropping the database would drop them` });
228
+ continue;
229
+ }
230
+ }
231
+ const sql = drop.step.sql;
232
+ opts.signal?.throwIfAborted();
233
+ log(sql);
234
+ await clickhouseQuery(target.endpoint, sql);
235
+ outcome.pruned.push({ ...ref, deleted: true, statement: sql });
236
+ }
237
+ catch (err) {
238
+ if (opts.signal?.aborted)
239
+ throw err;
240
+ outcome.failed.push({ ...ref, error: err instanceof Error ? err.message : String(err), statements: [] });
241
+ }
242
+ }
243
+ }
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Waiting on a background rewrite (#3208).
3
+ *
4
+ * A column type change or a TTL change returns as soon as the server has
5
+ * recorded it; the rewrite of existing parts runs afterwards as a mutation,
6
+ * listed in `system.mutations` until it is done. An apply that reported
7
+ * APPLIED at that point would claim a table had converged while its parts
8
+ * were still being rewritten, so the applier waits for every unfinished
9
+ * mutation on the table, and reports the ids when it stops waiting.
10
+ */
11
+ import { clickhouseQuery } from "../http.js";
12
+ import { sqlString } from "./statements.js";
13
+ /** A mutation that did not finish in time. The ids are what `system.mutations` and `KILL MUTATION` name. */
14
+ export class MutationTimeoutError extends Error {
15
+ constructor(table, mutationIds, timeoutMs) {
16
+ super(`${table}: mutation ${mutationIds.join(", ")} was still running after ${Math.round(timeoutMs / 1000)}s. ` +
17
+ `It goes on in the background; follow it in system.mutations, or stop it with KILL MUTATION WHERE mutation_id = '${mutationIds[0]}'.`);
18
+ this.table = table;
19
+ this.mutationIds = mutationIds;
20
+ this.timeoutMs = timeoutMs;
21
+ this.name = "MutationTimeoutError";
22
+ }
23
+ }
24
+ /** A mutation the server keeps failing. It is retried forever, so waiting longer does not help. */
25
+ export class MutationFailedError extends Error {
26
+ constructor(table, mutationId, reason) {
27
+ super(`${table}: mutation ${mutationId} is failing: ${reason.split("\n")[0]}. ` +
28
+ `The server retries it until it is killed: KILL MUTATION WHERE mutation_id = '${mutationId}'.`);
29
+ this.table = table;
30
+ this.mutationId = mutationId;
31
+ this.reason = reason;
32
+ this.name = "MutationFailedError";
33
+ }
34
+ }
35
+ /** The table's mutations that are not done. */
36
+ export async function pendingMutations(endpoint, database, table, source = "system.mutations") {
37
+ return clickhouseQuery(endpoint, `SELECT mutation_id, command, latest_fail_reason FROM ${source} ` +
38
+ `WHERE database = ${sqlString(database)} AND table = ${sqlString(table)} AND NOT is_done ORDER BY create_time`);
39
+ }
40
+ /**
41
+ * Wait until the table has no unfinished mutation. Returns the ids waited on.
42
+ * Throws {@link MutationFailedError} as soon as one reports a failure, and
43
+ * {@link MutationTimeoutError} naming the ids still running at the deadline.
44
+ */
45
+ export async function waitForMutations(endpoint, database, table, opts = {}) {
46
+ const timeoutMs = opts.timeoutMs ?? 600000;
47
+ const deadline = Date.now() + timeoutMs;
48
+ let interval = opts.intervalMs ?? 100;
49
+ const seen = new Set();
50
+ const name = `${database}.${table}`;
51
+ for (;;) {
52
+ opts.signal?.throwIfAborted();
53
+ const pending = await pendingMutations(endpoint, database, table, opts.source);
54
+ for (const m of pending)
55
+ seen.add(m.mutation_id);
56
+ if (pending.length === 0)
57
+ return [...seen];
58
+ const failing = pending.find((m) => m.latest_fail_reason);
59
+ if (failing)
60
+ throw new MutationFailedError(name, failing.mutation_id, failing.latest_fail_reason);
61
+ if (Date.now() >= deadline)
62
+ throw new MutationTimeoutError(name, pending.map((m) => m.mutation_id), timeoutMs);
63
+ await new Promise((r) => setTimeout(r, Math.min(interval, Math.max(0, deadline - Date.now()))));
64
+ interval = Math.min(interval * 2, 2000);
65
+ }
66
+ }