@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,91 @@
1
+ /**
2
+ * `describeResources()` for the ClickHouse dialect: which declared databases,
3
+ * tables and views exist on the environment's server.
4
+ *
5
+ * One read of `system.databases`, `system.tables` and `system.functions` per
6
+ * run, then a lookup per declared entity, so N entities are three queries,
7
+ * not N. An object the
8
+ * catalog does not list is absent, and the `queried` address says which
9
+ * server and name were asked. A server that cannot be reached, or refuses the
10
+ * credentials, leaves every entity unobserved with that reason: never absent.
11
+ *
12
+ * Ownership is read from chant's marker, the trailer the applier appends to
13
+ * the object's comment (`../ownership.ts`): `owned` when the comment carries
14
+ * it, `foreign` when it does not. With `owned: true` a foreign object is
15
+ * withheld as `filtered`, which says it exists and is not chant's, never that
16
+ * it is absent.
17
+ */
18
+ import { observeEntities, } from "@intentius/chant/observation";
19
+ import { bindClickHouse, classifyClickHouseFailure } from "./bind.js";
20
+ import { ACCESS_ENTITY_TYPES, ACCESS_UNMANAGED_DETAIL, accessOf, readLiveAccess, readLiveSchema } from "./catalog.js";
21
+ import { CLICKHOUSE_ENTITY_TYPES } from "../entities.js";
22
+ import { objectKey } from "../plan/normalize.js";
23
+ import { isChantManaged, readMarker, stripMarker } from "../ownership.js";
24
+ /** The database and name a declared entity is created as. */
25
+ export function declaredAddress(entity, defaultDatabase) {
26
+ const name = String(entity.props.name ?? "");
27
+ if (entity.type === CLICKHOUSE_ENTITY_TYPES.database ||
28
+ entity.type === CLICKHOUSE_ENTITY_TYPES.function ||
29
+ entity.type === CLICKHOUSE_ENTITY_TYPES.user ||
30
+ entity.type === CLICKHOUSE_ENTITY_TYPES.role ||
31
+ entity.type === CLICKHOUSE_ENTITY_TYPES.quota ||
32
+ entity.type === CLICKHOUSE_ENTITY_TYPES.settingsProfile) {
33
+ return { name };
34
+ }
35
+ return { database: typeof entity.props.database === "string" ? entity.props.database : defaultDatabase, name };
36
+ }
37
+ function adapter(options) {
38
+ return {
39
+ async bind() {
40
+ const target = await bindClickHouse(options);
41
+ const byKey = new Map();
42
+ const access = target.access === true ? await readLiveAccess(target, options.access?.(target.defaultDatabase) ?? [], { withStatements: false }) : [];
43
+ for (const o of [...(await readLiveSchema(target, { withStatements: false })), ...access]) {
44
+ byKey.set(objectKey(o), o);
45
+ }
46
+ return { target, byKey };
47
+ },
48
+ classifyBindFailure: (err) => classifyClickHouseFailure(err),
49
+ async read({ target, byKey }, entity) {
50
+ if (!entity.type.startsWith("ClickHouse::")) {
51
+ return { unobserved: { reason: "unsupported-kind", detail: entity.type } };
52
+ }
53
+ if (target.access !== true && ACCESS_ENTITY_TYPES.has(entity.type)) {
54
+ return { unobserved: { reason: "filtered", detail: ACCESS_UNMANAGED_DETAIL } };
55
+ }
56
+ if (entity.type === CLICKHOUSE_ENTITY_TYPES.grant) {
57
+ return { unobserved: { reason: "unsupported-kind", detail: "a grant is compared as part of its grantees' grants, which chant sql plan reports" } };
58
+ }
59
+ const { database, name } = declaredAddress(entity, target.defaultDatabase);
60
+ const queried = `${target.endpoint.url} ${database ? `${database}.` : ""}${name}`;
61
+ const table = typeof entity.props.table === "string" ? entity.props.table : undefined;
62
+ const live = byKey.get(objectKey({ type: entity.type, ...(database !== undefined ? { database } : {}), name, ...(table !== undefined ? { table } : {}) }));
63
+ if (!live)
64
+ return { absent: true, queried };
65
+ const owned = isChantManaged(live.comment);
66
+ if (options.owned && !owned) {
67
+ return { unobserved: { reason: "filtered", detail: "the object's comment carries no chant ownership marker and owned was requested" }, queried };
68
+ }
69
+ const marker = readMarker(live.comment);
70
+ const comment = live.comment ? stripMarker(live.comment) : "";
71
+ return {
72
+ present: {
73
+ type: live.type,
74
+ physicalId: live.uuid ?? (database ? `${database}.${name}` : name),
75
+ status: live.engine,
76
+ attributes: { engine: live.engine, ...(live.uuid ? { uuid: live.uuid } : {}), ...(comment ? { comment } : {}) },
77
+ ownership: owned ? "owned" : "foreign",
78
+ ...(owned && marker?.stack ? { marker: { stack: marker.stack, ...(marker.env ? { env: marker.env } : {}) } } : {}),
79
+ },
80
+ queried,
81
+ };
82
+ },
83
+ };
84
+ }
85
+ export async function describeResources(options) {
86
+ const declared = options.entityNames.map((name) => {
87
+ const entity = options.entities.get(name);
88
+ return { name, type: entity?.entityType ?? "", props: entity?.props ?? {} };
89
+ });
90
+ return observeEntities(declared, adapter({ ...options, access: (db) => accessOf(options.entities, db) }));
91
+ }
@@ -0,0 +1,59 @@
1
+ /**
2
+ * The objects on a live ClickHouse server of the kinds no declaration holds
3
+ * (#3911), found so import can refuse them by name instead of leaving them
4
+ * out (`../../core/undeclarable.ts`).
5
+ *
6
+ * One `system.*` query per kind the coverage table marks refused
7
+ * (`../../coverage/clickhouse.json`), keyed by the row's `kind`. A kind whose
8
+ * row is flipped to declared is no longer asked about.
9
+ *
10
+ * What the server's configuration files define (`storage = 'users_xml'`, a
11
+ * named collection whose source is the config, an executable function) is
12
+ * the server's, not a schema's, and is left out; so is what is in a database
13
+ * out of scope. A server-wide object (a quota, a settings profile, a
14
+ * workload) is always looked for.
15
+ */
16
+ import { clickhouseQuery } from "../http.js";
17
+ import { SYSTEM_DATABASES } from "./catalog.js";
18
+ import { KIND_COVERAGE } from "../../coverage.js";
19
+ const quote = (s) => `'${s.replace(/\\/g, "\\\\").replace(/'/g, "\\'")}'`;
20
+ const serverWide = (table, where = "1") => () => `SELECT '' AS database, name FROM system.${table} WHERE ${where}`;
21
+ const SQL_DEFINED = "storage != 'users_xml'";
22
+ export const CLICKHOUSE_PROBES = {
23
+ "non-SQL function": serverWide("functions", "origin NOT IN ('System', 'SQLUserDefined', 'ExecutableUserDefined')"),
24
+ "HTTP handler": serverWide("handlers"),
25
+ "masking policy": (scope) => `SELECT database, short_name || ' ON ' || table AS name FROM system.masking_policies WHERE ${SQL_DEFINED} AND ${scope("database")}`,
26
+ "named collection": serverWide("named_collections", "source = 'SQL'"),
27
+ quota: serverWide("quotas", SQL_DEFINED),
28
+ "workload resource": serverWide("resources"),
29
+ "settings profile": serverWide("settings_profiles", SQL_DEFINED),
30
+ "window view": (scope) => `SELECT database, name FROM system.tables WHERE engine = 'WindowView' AND NOT is_temporary AND ${scope("database")}`,
31
+ workload: serverWide("workloads"),
32
+ };
33
+ /**
34
+ * Every object in scope of a kind the coverage table refuses, kind by kind
35
+ * in the table's order, each by database then name. A kind the reader may
36
+ * not read (no grant on its `system` table) is a problem in `unread`, not a
37
+ * pass.
38
+ */
39
+ export async function readUndeclarable(target) {
40
+ const scope = (column) => target.databases ? `${column} IN (${target.databases.map(quote).join(", ")})` : `${column} NOT IN (${[...SYSTEM_DATABASES].map(quote).join(", ")})`;
41
+ const objects = [];
42
+ const unread = [];
43
+ for (const row of KIND_COVERAGE.clickhouse) {
44
+ if (row.status !== "refused")
45
+ continue;
46
+ const probe = CLICKHOUSE_PROBES[row.kind];
47
+ if (!probe)
48
+ throw new Error(`no system table query finds a ClickHouse ${row.kind} (src/clickhouse/live/undeclarable.ts)`);
49
+ try {
50
+ const rows = await clickhouseQuery(target.endpoint, `/* chant undeclarable: ${row.kind} */ SELECT database, name FROM (${probe(scope)}) ORDER BY database, name`);
51
+ for (const r of rows)
52
+ objects.push({ kind: row.kind, ...(r.database ? { schema: r.database } : {}), name: r.name });
53
+ }
54
+ catch (err) {
55
+ unread.push(`${row.kind}: ${err instanceof Error ? err.message.split("\n")[0] : String(err)}`);
56
+ }
57
+ }
58
+ return { objects, unread };
59
+ }
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Codec parameters and chaining: the overlay half.
3
+ *
4
+ * `system.codecs` gives the 17 names and their flags (compression, generic,
5
+ * encryption, time series, experimental). The parameters (`ZSTD(level)`,
6
+ * `Delta(bytes)`) and the order a chain like `CODEC(Delta, ZSTD(3))` must
7
+ * follow are in no table.
8
+ *
9
+ * Every codec at the pin has an entry, and generation fails when one does not,
10
+ * so a codec a pin move adds is a decision rather than a silent `string`.
11
+ * `"unknown"` is that decision for the experimental codecs whose parameters
12
+ * are not documented: they are accepted as written and not checked.
13
+ */
14
+ const WIDTH = {
15
+ name: "bytes",
16
+ kind: "number",
17
+ optional: true,
18
+ values: ["1", "2", "4", "8"],
19
+ note: "1, 2, 4 or 8; the column type's width when omitted.",
20
+ };
21
+ export const CODEC_OVERLAY = {
22
+ NONE: { parameters: [], role: "none" },
23
+ LZ4: { parameters: [], role: "compression" },
24
+ LZ4HC: {
25
+ parameters: [{ name: "level", kind: "number", optional: true, range: [0, 12], note: "9 when omitted or 0." }],
26
+ role: "compression",
27
+ },
28
+ ZSTD: {
29
+ parameters: [
30
+ { name: "level", kind: "number", optional: true, range: [1, 22], note: "1 when omitted." },
31
+ { name: "window_log", kind: "number", optional: true, range: [10, 31], note: "Turns on long-range matching with this window log." },
32
+ ],
33
+ role: "compression",
34
+ },
35
+ Delta: { parameters: [WIDTH], role: "preprocessing" },
36
+ DoubleDelta: { parameters: [WIDTH], role: "compression" },
37
+ Gorilla: { parameters: [WIDTH], role: "compression" },
38
+ GCD: { parameters: [], role: "preprocessing" },
39
+ T64: {
40
+ parameters: [{ name: "variant", kind: "keyword", optional: true, values: ["'byte'", "'bit'"] }],
41
+ role: "compression",
42
+ },
43
+ FPC: {
44
+ parameters: [
45
+ { name: "level", kind: "number", optional: true, range: [1, 28], note: "12 when omitted." },
46
+ { name: "float_size", kind: "number", optional: true, values: ["4", "8"], note: "4 or 8; the column type's width when omitted." },
47
+ ],
48
+ role: "compression",
49
+ },
50
+ AES_128_GCM_SIV: { parameters: [], role: "encryption" },
51
+ AES_256_GCM_SIV: { parameters: [], role: "encryption" },
52
+ ALP: { parameters: "unknown", role: "compression" },
53
+ SZ3: { parameters: "unknown", role: "compression" },
54
+ ZXC: { parameters: "unknown", role: "compression" },
55
+ Quantized: { parameters: "unknown", role: "preprocessing" },
56
+ Multiple: { parameters: "unknown", role: "internal" },
57
+ };
@@ -0,0 +1,101 @@
1
+ /**
2
+ * Engine arguments: the overlay half (chant #3195).
3
+ *
4
+ * The generator reads each engine's argument names, positions and optionality
5
+ * from the server's `syntax` line (`engine-syntax.ts`). This table adds what
6
+ * that line cannot say: whether `ver` is a column, `cluster` a name, `min_time`
7
+ * a number. Keys are the argument names exactly as the syntax line spells
8
+ * them, and generation fails when one no longer appears there, so a pin move
9
+ * that renames or drops an argument is caught rather than mistyped.
10
+ *
11
+ * Covered: the MergeTree family and its Replicated twins, and the engines a
12
+ * schema commonly declares beside them (Distributed, Buffer, Join, Merge,
13
+ * Dictionary, File, URL, Alias, KeeperMap, EmbeddedRocksDB, GenerateRandom).
14
+ * Integration engines (S3, Kafka, the lake engines, the database bridges) keep
15
+ * their arguments untyped: they are connection strings and credentials, which
16
+ * lint has no business guessing at.
17
+ */
18
+ const REPLICATED = {
19
+ zoo_path: {
20
+ kind: "string",
21
+ optional: true,
22
+ note: "May be omitted together with replica_name when the server sets default_replica_path and default_replica_name.",
23
+ },
24
+ replica_name: { kind: "string", optional: true, note: "Omitted together with zoo_path." },
25
+ };
26
+ const SIGN = { kind: "column", note: "An Int8 column holding 1 for a state row and -1 for a cancel row." };
27
+ const VERSION = { kind: "column", note: "An unsigned integer, date or datetime column." };
28
+ const SUMMED = { kind: "columns", note: "Numeric columns to sum; every numeric column outside the sort key when omitted." };
29
+ const REPLACING = {
30
+ ver: { kind: "column", note: "The version column: the row with the highest version wins; the last inserted when omitted." },
31
+ is_deleted: { kind: "column", note: "A UInt8 column; 1 marks a deleted row. Requires ver." },
32
+ };
33
+ export const ENGINE_ARGUMENTS = {
34
+ ReplacingMergeTree: REPLACING,
35
+ SummingMergeTree: { columns: SUMMED },
36
+ CoalescingMergeTree: { columns: SUMMED },
37
+ CollapsingMergeTree: { sign: SIGN },
38
+ VersionedCollapsingMergeTree: { sign: SIGN, version: VERSION },
39
+ GraphiteMergeTree: { config_section: { kind: "string", note: "The graphite_rollup section of the server config." } },
40
+ ReplicatedMergeTree: REPLICATED,
41
+ ReplicatedAggregatingMergeTree: REPLICATED,
42
+ ReplicatedReplacingMergeTree: { ...REPLICATED, ...REPLACING },
43
+ ReplicatedSummingMergeTree: { ...REPLICATED, columns: SUMMED },
44
+ ReplicatedCoalescingMergeTree: { ...REPLICATED, columns: SUMMED },
45
+ ReplicatedCollapsingMergeTree: { ...REPLICATED, sign: SIGN },
46
+ ReplicatedVersionedCollapsingMergeTree: { ...REPLICATED, sign: SIGN, version: VERSION },
47
+ ReplicatedGraphiteMergeTree: { ...REPLICATED, config_section: { kind: "string" } },
48
+ Distributed: {
49
+ cluster: { kind: "identifier", note: "A cluster named in the server's remote_servers config." },
50
+ database: { kind: "identifier" },
51
+ table: { kind: "identifier" },
52
+ sharding_key: { kind: "expression", note: "Required for INSERTs into a cluster of more than one shard." },
53
+ policy_name: { kind: "string", note: "A storage policy for the files queued for sending." },
54
+ },
55
+ Buffer: {
56
+ database: { kind: "identifier" },
57
+ table: { kind: "identifier" },
58
+ num_buckets: { kind: "number", range: [1, 1000], note: "Independent buffers; 16 is the documented default." },
59
+ min_time: { kind: "number" },
60
+ max_time: { kind: "number" },
61
+ min_rows: { kind: "number" },
62
+ max_rows: { kind: "number" },
63
+ min_bytes: { kind: "number" },
64
+ max_bytes: { kind: "number" },
65
+ flush_time: { kind: "number" },
66
+ flush_rows: { kind: "number" },
67
+ flush_bytes: { kind: "number" },
68
+ },
69
+ Join: {
70
+ join_strictness: { kind: "keyword", values: ["ANY", "ALL", "SEMI", "ANTI"] },
71
+ join_type: { kind: "keyword", values: ["INNER", "LEFT", "RIGHT", "FULL", "CROSS"] },
72
+ k1: { kind: "column" },
73
+ k2: { kind: "column" },
74
+ },
75
+ Merge: {
76
+ db_name: { kind: "expression", note: "A database name, or REGEXP('pattern')." },
77
+ tables_regexp: { kind: "string" },
78
+ },
79
+ Dictionary: { dictionary_name: { kind: "identifier" } },
80
+ File: {
81
+ format: { kind: "identifier", note: "An input/output format name from system.formats." },
82
+ "path|fd": { kind: "string" },
83
+ },
84
+ URL: {
85
+ url: { kind: "string" },
86
+ format: { kind: "identifier", note: "A format name from system.formats." },
87
+ compression: { kind: "string" },
88
+ },
89
+ Alias: { target_db: { kind: "identifier" }, target_table: { kind: "identifier" } },
90
+ KeeperMap: { root_path: { kind: "string" }, keys_limit: { kind: "number" } },
91
+ EmbeddedRocksDB: {
92
+ ttl: { kind: "number" },
93
+ rocksdb_dir: { kind: "string" },
94
+ read_only: { kind: "number", range: [0, 1] },
95
+ },
96
+ GenerateRandom: {
97
+ random_seed: { kind: "number" },
98
+ max_string_length: { kind: "number" },
99
+ max_array_length: { kind: "number" },
100
+ },
101
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Projections: the overlay half.
3
+ *
4
+ * `system.table_engines.supports_projections` says which engines accept a
5
+ * projection, and is generated. The projection's own grammar is fixed and in
6
+ * no table: a name and a parenthesised query over the table, either a
7
+ * reordering (`SELECT * ORDER BY x`) or an aggregation (`SELECT k, sum(v)
8
+ * GROUP BY k`). `system.projections` is runtime state, not grammar.
9
+ *
10
+ * PROJECTION name (SELECT <columns or *> [GROUP BY ...] [ORDER BY ...])
11
+ */
12
+ export const PROJECTION_FORMS = [
13
+ { form: "normal", marker: "ORDER BY", summary: "A copy of the selected columns in another sort order." },
14
+ { form: "aggregate", marker: "GROUP BY", summary: "Pre-aggregated rows, kept current by merges like an AggregatingMergeTree." },
15
+ ];
16
+ /**
17
+ * MergeTree settings that decide what a mutation or deduplicating merge does to
18
+ * a table with projections. Changing either is metadata only; leaving them at
19
+ * their defaults makes `ALTER ... UPDATE` on such a table an error.
20
+ */
21
+ export const PROJECTION_SETTINGS = [
22
+ "deduplicate_merge_projection_mode",
23
+ "lightweight_mutation_projection_mode",
24
+ ];
25
+ /** Clauses a projection's query may not carry. */
26
+ export const PROJECTION_FORBIDDEN_CLAUSES = ["WHERE", "JOIN", "LIMIT", "HAVING", "ARRAY JOIN"];
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Skip index parameters: the overlay half.
3
+ *
4
+ * `system.data_skipping_index_types` names each type and gives a syntax line,
5
+ * from which the generator reads parameter names and optionality. This adds
6
+ * their kinds and ranges. `GRANULARITY` is fixed grammar the parser owns.
7
+ */
8
+ const HASHES = { kind: "number", range: [1, 1000000], note: "Hash functions per value." };
9
+ const BYTES = { kind: "number", note: "Bloom filter size in bytes." };
10
+ const SEED = { kind: "number", note: "Seed for the hash functions." };
11
+ export const SKIP_INDEX_PARAMETERS = {
12
+ bloom_filter: {
13
+ false_positive_rate: { kind: "number", range: [0, 1], note: "Exclusive of 0 and 1; 0.025 when omitted." },
14
+ },
15
+ set: { max_rows: { kind: "number", note: "0 keeps every distinct value." } },
16
+ ngrambf_v1: {
17
+ n: { kind: "number", range: [1, 256], note: "N-gram size." },
18
+ size_in_bytes: BYTES,
19
+ num_hash_functions: HASHES,
20
+ seed: SEED,
21
+ },
22
+ tokenbf_v1: { size_in_bytes: BYTES, num_hash_functions: HASHES, seed: SEED },
23
+ sparse_grams: {
24
+ min_ngram_length: { kind: "number" },
25
+ max_ngram_length: { kind: "number" },
26
+ min_cutoff_length: { kind: "number" },
27
+ size_in_bytes: BYTES,
28
+ num_hash_functions: HASHES,
29
+ seed: SEED,
30
+ },
31
+ text: { tokenizer: { kind: "expression", note: "A tokenizer such as splitByNonAlpha, ngrams(N) or array." } },
32
+ vector_similarity: {
33
+ hnsw: { kind: "keyword", values: ["hnsw"], note: "The only method." },
34
+ distance_function: { kind: "keyword", values: ["L2Distance", "cosineDistance"] },
35
+ dimensions: { kind: "number" },
36
+ quantization: { kind: "keyword", values: ["f64", "f32", "f16", "bf16", "i8", "b1"] },
37
+ hnsw_max_connections_per_layer: { kind: "number" },
38
+ hnsw_candidate_list_size_for_construction: { kind: "number" },
39
+ },
40
+ };
@@ -0,0 +1,34 @@
1
+ /**
2
+ * TTL clauses: the whole grammar is overlay.
3
+ *
4
+ * No system table describes TTL. A table TTL is a list of rules, each an
5
+ * expression evaluating to a `Date` or `DateTime` and an action; a column TTL
6
+ * is a single expression with no action, after which the column resets to its
7
+ * default. Which engines accept TTL at all is generated
8
+ * (`capabilities.ttl` from `system.table_engines.supports_ttl`).
9
+ *
10
+ * TTL expr [DELETE | RECOMPRESS codec | TO DISK 'd' | TO VOLUME 'v'] [WHERE cond]
11
+ * [, expr GROUP BY key_columns SET col = agg(col), ...]
12
+ */
13
+ export const TTL_ACTIONS = [
14
+ { keywords: "DELETE", where: true, impliedWhenOmitted: true },
15
+ { keywords: "RECOMPRESS", argument: { kind: "codec", note: "A CODEC(...) expression." }, where: true },
16
+ { keywords: "TO DISK", argument: { kind: "string", note: "A disk of the table's storage policy." }, where: true },
17
+ { keywords: "TO VOLUME", argument: { kind: "string", note: "A volume of the table's storage policy." }, where: true },
18
+ {
19
+ keywords: "GROUP BY",
20
+ argument: { kind: "columns", note: "A prefix of the sort key, then SET col = aggregate(col), ..." },
21
+ where: true,
22
+ },
23
+ ];
24
+ /** A column TTL takes an expression and nothing else. */
25
+ export const COLUMN_TTL_ACTIONS = [];
26
+ /** The types a TTL expression must evaluate to. */
27
+ export const TTL_RESULT_TYPES = ["Date", "Date32", "DateTime", "DateTime64"];
28
+ /** MergeTree settings that change how TTL runs, for lint and hover to point at. */
29
+ export const TTL_SETTINGS = [
30
+ "merge_with_ttl_timeout",
31
+ "merge_with_recompression_ttl_timeout",
32
+ "ttl_only_drop_parts",
33
+ "materialize_ttl_recalculate_only",
34
+ ];
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Column type parameters: the overlay half.
3
+ *
4
+ * `system.data_type_families` lists the families and their aliases. The
5
+ * parameter grammar (`Decimal(P, S)`, `DateTime64(precision[, tz])`,
6
+ * `Enum8('a' = 1)`) is in no system table. A family missing here takes no
7
+ * parameters; generation fails when a key here is not a family at the pin.
8
+ */
9
+ const P = (name, kind, extra = {}) => ({
10
+ name,
11
+ kind,
12
+ ...extra,
13
+ });
14
+ const TZ = P("timezone", "string", { optional: true });
15
+ /**
16
+ * The server takes and ignores a MySQL-style display width on an integer
17
+ * (`INT(11)`, `UInt64(8)`), a precision and scale on a float (`DOUBLE(10, 2)`)
18
+ * and a length on a string (`VARCHAR(255)`), so each is an optional parameter
19
+ * here rather than a mistake.
20
+ */
21
+ const WIDTH = [P("display_width", "number", { optional: true })];
22
+ const FLOAT = [P("precision", "number", { optional: true }), P("scale", "number", { optional: true })];
23
+ const INTEGERS = ["Int8", "Int16", "Int32", "Int64", "Int128", "Int256", "UInt8", "UInt16", "UInt32", "UInt64", "UInt128", "UInt256"];
24
+ export const TYPE_PARAMETERS = {
25
+ ...Object.fromEntries(INTEGERS.map((name) => [name, WIDTH])),
26
+ Float32: FLOAT,
27
+ Float64: FLOAT,
28
+ BFloat16: FLOAT,
29
+ String: [P("length", "number", { optional: true })],
30
+ /** A bare `Decimal` is `Decimal(10, 0)`. */
31
+ Decimal: [P("precision", "number", { optional: true, range: [1, 76] }), P("scale", "number", { optional: true, range: [0, 76] })],
32
+ Decimal32: [P("scale", "number", { range: [0, 9] })],
33
+ Decimal64: [P("scale", "number", { range: [0, 18] })],
34
+ Decimal128: [P("scale", "number", { range: [0, 38] })],
35
+ Decimal256: [P("scale", "number", { range: [0, 76] })],
36
+ DateTime: [TZ],
37
+ DateTime32: [TZ],
38
+ /** A bare `DateTime64` has precision 3. */
39
+ DateTime64: [P("precision", "number", { optional: true, range: [0, 9] }), TZ],
40
+ Time64: [P("precision", "number", { optional: true, range: [0, 9] })],
41
+ FixedString: [P("length", "number", { range: [1, Number.MAX_SAFE_INTEGER] })],
42
+ Enum: [P("member", "enum-member", { repeated: true })],
43
+ Enum8: [P("member", "enum-member", { repeated: true })],
44
+ Enum16: [P("member", "enum-member", { repeated: true })],
45
+ Nullable: [P("type", "type")],
46
+ LowCardinality: [P("type", "type")],
47
+ Array: [P("type", "type")],
48
+ Map: [P("key", "type"), P("value", "type")],
49
+ Tuple: [P("element", "named-type", { repeated: true })],
50
+ Nested: [P("field", "named-type", { repeated: true })],
51
+ Variant: [P("type", "type", { repeated: true })],
52
+ AggregateFunction: [P("function", "function"), P("argument", "type", { repeated: true })],
53
+ SimpleAggregateFunction: [P("function", "function"), P("argument", "type")],
54
+ JSON: [P("setting", "expression", { optional: true, repeated: true })],
55
+ Dynamic: [P("max_types", "expression", { optional: true })],
56
+ QBit: [P("element", "type"), P("dimension", "number")],
57
+ };
58
+ /** Families that wrap another type and pass its nullability and sort-key rules through. */
59
+ export const WRAPPER_TYPES = ["LowCardinality"];
@@ -0,0 +1,83 @@
1
+ /**
2
+ * chant's ownership marker on ClickHouse objects (#3208): a trailer on the
3
+ * object's own `COMMENT`.
4
+ *
5
+ * ClickHouse objects carry no tags or labels. The channels considered:
6
+ *
7
+ * - The object `COMMENT`. Every object kind has one (a table of any engine, a
8
+ * view, a materialized view, a database), it is set in the `CREATE` itself
9
+ * so an object is never created unmarked, `MODIFY COMMENT` restamps it, and
10
+ * `system.tables` / `system.databases` return it with the catalog read
11
+ * observation already makes. The #3046 candidate.
12
+ * - Table `SETTINGS`: a MergeTree table refuses a setting it does not know.
13
+ * - A registry table on the server naming the objects chant created: a record
14
+ * apart from the object, which is the state file chant does not keep, and
15
+ * one that goes on claiming a table someone dropped and created again.
16
+ *
17
+ * So the comment, and the question is the user's own comment, which is a
18
+ * declared property (`COMMENT 'Raw events'`, classified by SQLCH203). The
19
+ * marker never replaces it: it is appended as a bracketed trailer,
20
+ *
21
+ * COMMENT 'Raw events [chant managed-by=chant stack=shop env=prod]'
22
+ *
23
+ * and taken off again wherever chant reads a definition (`readLiveSchema`
24
+ * strips it from `SHOW CREATE`), so planning, the deep diff and import compare
25
+ * and write the declared comment alone. Someone who edits the comment by hand
26
+ * and drops the trailer makes the object read as foreign, which is the safe
27
+ * direction: it is never pruned, and the next apply of its declaration
28
+ * stamps it again.
29
+ *
30
+ * Values are percent-encoded outside `[A-Za-z0-9._-]`, so the trailer never
31
+ * holds a quote, a backslash, a space or a bracket of its own.
32
+ *
33
+ * The trailer itself is the shared core's (`../core/ownership.ts`), the same in
34
+ * every dialect. What is ClickHouse's here: the channel the plugin declares,
35
+ * taking the trailer off a printed `COMMENT '...'` clause, and the trailer keys
36
+ * of the rebuild migration's working objects.
37
+ */
38
+ import { COMMENT_OWNERSHIP_KEYS, RECEIPTS_TRAILER_KEY, TRAILER_PAIR, hasChantTrailerKey } from "../core/ownership.js";
39
+ export { carriesMarker, isChantManaged, markerTrailer, readMarker, readTrailerPairs, RECEIPTS_TRAILER_KEY, stampedComment, stripMarker, } from "../core/ownership.js";
40
+ /** The keys inside the trailer. */
41
+ export const CLICKHOUSE_COMMENT_OWNERSHIP_KEYS = COMMENT_OWNERSHIP_KEYS;
42
+ /**
43
+ * Where the marker is read back (#1348): `describeResources` and
44
+ * `exportResources` read the comment from `system.tables` and
45
+ * `system.databases`. The deep read takes it off with the rest of `SHOW CREATE`
46
+ * and reports no verdict.
47
+ */
48
+ export const SQL_OWNERSHIP_CHANNEL = {
49
+ keys: CLICKHOUSE_COMMENT_OWNERSHIP_KEYS,
50
+ reads: ["describeResources", "exportResources"],
51
+ };
52
+ /** A comment that is the trailer alone, in a printed statement: the whole `COMMENT '...'` clause. */
53
+ const ONLY_TRAILER_CLAUSE = new RegExp(`\\s*\\bCOMMENT\\s+'\\[chant(?: ${TRAILER_PAIR})+\\]'`, "g");
54
+ /** The trailer inside a printed comment literal, just before its closing quote. */
55
+ const TRAILER_IN_LITERAL = new RegExp(`\\s+\\[chant(?: ${TRAILER_PAIR})+\\]'`, "g");
56
+ /**
57
+ * The trailer key naming the table a rebuild migration object belongs to
58
+ * (`./rebuild/`). An object carrying it is the rebuild's own working object,
59
+ * not a declaration: a new table being filled, the dual-write view, an old
60
+ * table being retained. Reading a schema leaves those out
61
+ * (`./live/catalog.ts`), so a plan, an import or a prune never sees them.
62
+ */
63
+ export const REBUILD_TRAILER_KEY = "rebuild";
64
+ /** Whether a comment marks a rebuild migration's working object. */
65
+ export function isRebuildObject(comment) {
66
+ return hasChantTrailerKey(comment, [REBUILD_TRAILER_KEY]);
67
+ }
68
+ /**
69
+ * Whether a comment marks one of chant's own working objects: a rebuild's
70
+ * new, dual-write or retained table, or the receipts database and table.
71
+ * Schema reads leave them out.
72
+ */
73
+ export function isChantWorkingObject(comment) {
74
+ return hasChantTrailerKey(comment, [REBUILD_TRAILER_KEY, RECEIPTS_TRAILER_KEY]);
75
+ }
76
+ /**
77
+ * A `SHOW CREATE` statement with the trailer taken off its object comment, so
78
+ * the statement reads as the declaration it came from. A comment that was the
79
+ * trailer alone loses its whole `COMMENT` clause.
80
+ */
81
+ export function stripMarkerFromStatement(statement) {
82
+ return statement.replace(ONLY_TRAILER_CLAUSE, "").replace(TRAILER_IN_LITERAL, "'");
83
+ }