@intentius/chant-lexicon-sql 0.124.31 → 0.124.32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (322) hide show
  1. package/dist/change-set.js +250 -0
  2. package/dist/clickhouse/access.js +722 -0
  3. package/dist/clickhouse/apply/apply.js +243 -0
  4. package/dist/clickhouse/apply/mutations.js +66 -0
  5. package/dist/clickhouse/apply/statements.js +545 -0
  6. package/dist/clickhouse/catalog-types.js +7 -0
  7. package/dist/clickhouse/container.js +152 -0
  8. package/dist/clickhouse/engine-syntax.js +159 -0
  9. package/dist/clickhouse/entities.js +593 -0
  10. package/dist/clickhouse/expressions.js +107 -0
  11. package/dist/clickhouse/http.js +55 -0
  12. package/dist/clickhouse/import/generator.js +192 -0
  13. package/dist/clickhouse/import/inlined.js +207 -0
  14. package/dist/clickhouse/import/ir.js +160 -0
  15. package/dist/clickhouse/import/live-export.js +131 -0
  16. package/dist/clickhouse/import/parser.js +17 -0
  17. package/dist/clickhouse/live/bind.js +116 -0
  18. package/dist/clickhouse/live/catalog.js +223 -0
  19. package/dist/clickhouse/live/describe-resources.js +91 -0
  20. package/dist/clickhouse/live/undeclarable.js +59 -0
  21. package/dist/clickhouse/overlays/codecs.js +57 -0
  22. package/dist/clickhouse/overlays/engines.js +101 -0
  23. package/dist/clickhouse/overlays/kinds.js +1 -0
  24. package/dist/clickhouse/overlays/projections.js +26 -0
  25. package/dist/clickhouse/overlays/skip-indexes.js +40 -0
  26. package/dist/clickhouse/overlays/ttl.js +34 -0
  27. package/dist/clickhouse/overlays/types.js +59 -0
  28. package/dist/clickhouse/ownership.js +83 -0
  29. package/dist/clickhouse/parser.js +674 -0
  30. package/dist/clickhouse/plan/commands.js +159 -0
  31. package/dist/clickhouse/plan/deep.js +345 -0
  32. package/dist/clickhouse/plan/diff.js +312 -0
  33. package/dist/clickhouse/plan/disruption.js +73 -0
  34. package/dist/clickhouse/plan/normalize.js +545 -0
  35. package/dist/clickhouse/plan/rebuild-handoff.js +57 -0
  36. package/dist/clickhouse/plan/report.js +26 -0
  37. package/dist/clickhouse/plan/rules.js +72 -0
  38. package/dist/clickhouse/plan/schema.js +67 -0
  39. package/dist/clickhouse/plan/server-format.js +35 -0
  40. package/dist/clickhouse/rebuild/backfill.js +265 -0
  41. package/dist/clickhouse/rebuild/engines.js +146 -0
  42. package/dist/clickhouse/rebuild/observe.js +260 -0
  43. package/dist/clickhouse/rebuild/op.js +152 -0
  44. package/dist/clickhouse/rebuild/partitions.js +65 -0
  45. package/dist/clickhouse/rebuild/receipts.js +120 -0
  46. package/dist/clickhouse/rebuild/replicas.js +121 -0
  47. package/dist/clickhouse/rebuild/shards.js +76 -0
  48. package/dist/clickhouse/rebuild/steps.js +383 -0
  49. package/dist/clickhouse/rebuild/verify.js +279 -0
  50. package/dist/clickhouse/row-types.js +151 -0
  51. package/dist/clickhouse/testing/fake-server.js +47 -0
  52. package/dist/clickhouse/testing/roundtrip-schema.js +25 -0
  53. package/dist/clickhouse/testing/writable-server.js +123 -0
  54. package/dist/clickhouse/tokens.js +23 -0
  55. package/dist/clickhouse/topology.js +463 -0
  56. package/dist/clickhouse/type-syntax.js +73 -0
  57. package/dist/clickhouse.js +25 -0
  58. package/dist/codegen/classifier-page.js +93 -0
  59. package/dist/codegen/clickhouse-module.js +249 -0
  60. package/dist/codegen/coverage-page.js +70 -0
  61. package/dist/codegen/docs-cli.js +3 -0
  62. package/dist/codegen/docs.js +222 -0
  63. package/dist/codegen/generate-cli.js +13 -0
  64. package/dist/codegen/generate.js +97 -0
  65. package/dist/codegen/package.js +28 -0
  66. package/dist/codegen/postgres-classifier-page.js +95 -0
  67. package/dist/codegen/postgres-module.js +418 -0
  68. package/dist/codegen/registry.js +52 -0
  69. package/dist/composites/audit-log-table.js +35 -0
  70. package/dist/composites/catalog.js +524 -0
  71. package/dist/composites/cdc-mirror.js +32 -0
  72. package/dist/composites/clickhouse.js +6 -0
  73. package/dist/composites/events-table.js +26 -0
  74. package/dist/composites/index.js +8 -0
  75. package/dist/composites/join-table.js +25 -0
  76. package/dist/composites/postgres.js +6 -0
  77. package/dist/composites/refreshed-view.js +24 -0
  78. package/dist/composites/replacing-table.js +28 -0
  79. package/dist/composites/rollup-view.js +29 -0
  80. package/dist/composites/sharded-table.js +27 -0
  81. package/dist/composites/soft-delete-table.js +34 -0
  82. package/dist/composites/tenant-table.js +26 -0
  83. package/dist/composites/typed.js +8 -0
  84. package/dist/config.js +206 -0
  85. package/dist/core/apply.js +93 -0
  86. package/dist/core/classifier.js +115 -0
  87. package/dist/core/container.js +69 -0
  88. package/dist/core/cursor.js +261 -0
  89. package/dist/core/diff.js +48 -0
  90. package/dist/core/entity.js +58 -0
  91. package/dist/core/find-templates.js +118 -0
  92. package/dist/core/foreign-tables.js +27 -0
  93. package/dist/core/handoff.js +32 -0
  94. package/dist/core/index.js +64 -0
  95. package/dist/core/interpolation.js +191 -0
  96. package/dist/core/normalize.js +43 -0
  97. package/dist/core/ownership.js +119 -0
  98. package/dist/core/receipts.js +22 -0
  99. package/dist/core/references.js +61 -0
  100. package/dist/core/statements.js +42 -0
  101. package/dist/core/template.js +79 -0
  102. package/dist/core/testing/http-stub.js +21 -0
  103. package/dist/core/tokens.js +202 -0
  104. package/dist/core/typed.js +40 -0
  105. package/dist/core/undeclarable.js +46 -0
  106. package/dist/coverage.js +161 -0
  107. package/dist/detect.js +32 -0
  108. package/dist/dialects.js +18 -0
  109. package/dist/files/build-root.js +72 -0
  110. package/dist/files/clickhouse.js +138 -0
  111. package/dist/files/common.js +58 -0
  112. package/dist/files/postgres.js +389 -0
  113. package/dist/generated/clickhouse-types.js +5 -0
  114. package/dist/generated/clickhouse.js +4361 -0
  115. package/dist/generated/postgres-types.js +227 -0
  116. package/dist/generated/postgres.js +3667 -0
  117. package/dist/import-generator.js +14 -0
  118. package/dist/import-parser.js +71 -0
  119. package/dist/index.js +24 -0
  120. package/dist/init-templates.js +290 -0
  121. package/dist/integrity.json +2 -2
  122. package/dist/lint/audit-catalog.js +31 -0
  123. package/dist/lint/audit-lineage.js +22 -0
  124. package/dist/lint/post-synth/audit-entries.js +34 -0
  125. package/dist/lint/post-synth/clickhouse-helpers.js +79 -0
  126. package/dist/lint/post-synth/clickhouse-type-check.js +162 -0
  127. package/dist/lint/post-synth/index.js +112 -0
  128. package/dist/lint/post-synth/postgres-audit-entries.js +35 -0
  129. package/dist/lint/post-synth/postgres-helpers.js +65 -0
  130. package/dist/lint/post-synth/postgres-names.js +507 -0
  131. package/dist/lint/post-synth/sql-helpers.js +23 -0
  132. package/dist/lint/post-synth/sql101.js +59 -0
  133. package/dist/lint/post-synth/sql102.js +34 -0
  134. package/dist/lint/post-synth/sqlch101.js +34 -0
  135. package/dist/lint/post-synth/sqlch102.js +23 -0
  136. package/dist/lint/post-synth/sqlch103.js +45 -0
  137. package/dist/lint/post-synth/sqlch104.js +41 -0
  138. package/dist/lint/post-synth/sqlch105.js +36 -0
  139. package/dist/lint/post-synth/sqlch106.js +27 -0
  140. package/dist/lint/post-synth/sqlch107.js +39 -0
  141. package/dist/lint/post-synth/sqlch108.js +28 -0
  142. package/dist/lint/post-synth/sqlch109.js +21 -0
  143. package/dist/lint/post-synth/sqlch110.js +31 -0
  144. package/dist/lint/post-synth/sqlch111.js +41 -0
  145. package/dist/lint/post-synth/sqlch112.js +28 -0
  146. package/dist/lint/post-synth/sqlch113.js +19 -0
  147. package/dist/lint/post-synth/sqlch114.js +26 -0
  148. package/dist/lint/post-synth/sqlch115.js +30 -0
  149. package/dist/lint/post-synth/sqlch116.js +22 -0
  150. package/dist/lint/post-synth/sqlch117.js +26 -0
  151. package/dist/lint/post-synth/sqlch118.js +27 -0
  152. package/dist/lint/post-synth/sqlch119.js +32 -0
  153. package/dist/lint/post-synth/sqlch120.js +20 -0
  154. package/dist/lint/post-synth/sqlch121.js +11 -0
  155. package/dist/lint/post-synth/sqlch122.js +11 -0
  156. package/dist/lint/post-synth/sqlch123.js +10 -0
  157. package/dist/lint/post-synth/sqlch124.js +21 -0
  158. package/dist/lint/post-synth/sqlch125.js +55 -0
  159. package/dist/lint/post-synth/sqlch126.js +62 -0
  160. package/dist/lint/post-synth/sqlch127.js +132 -0
  161. package/dist/lint/post-synth/sqlpg101.js +25 -0
  162. package/dist/lint/post-synth/sqlpg102.js +35 -0
  163. package/dist/lint/post-synth/sqlpg103.js +23 -0
  164. package/dist/lint/post-synth/sqlpg104.js +23 -0
  165. package/dist/lint/post-synth/sqlpg105.js +22 -0
  166. package/dist/lint/post-synth/sqlpg106.js +22 -0
  167. package/dist/lint/post-synth/sqlpg107.js +22 -0
  168. package/dist/lint/post-synth/sqlpg108.js +28 -0
  169. package/dist/lint/post-synth/sqlpg109.js +39 -0
  170. package/dist/lint/post-synth/sqlpg110.js +38 -0
  171. package/dist/lint/post-synth/sqlpg111.js +23 -0
  172. package/dist/lint/post-synth/sqlpg112.js +25 -0
  173. package/dist/lint/post-synth/sqlpg113.js +29 -0
  174. package/dist/lint/post-synth/sqlpg114.js +39 -0
  175. package/dist/lint/post-synth/sqlpg115.js +48 -0
  176. package/dist/lint/post-synth/sqlpg116.js +26 -0
  177. package/dist/lint/post-synth/sqlpg117.js +24 -0
  178. package/dist/lint/post-synth/sqlpg118.js +22 -0
  179. package/dist/lint/post-synth/sqlpg119.js +41 -0
  180. package/dist/lint/post-synth/sqlpg120.js +83 -0
  181. package/dist/lint/post-synth/sqlpg121.js +33 -0
  182. package/dist/lint/post-synth/sqlpg122.js +27 -0
  183. package/dist/lint/post-synth/sqlpg123.js +69 -0
  184. package/dist/lint/post-synth/sqlpg124.js +50 -0
  185. package/dist/lint/post-synth/sqlpg125.js +41 -0
  186. package/dist/lint/post-synth/sqlpg126.js +38 -0
  187. package/dist/lint/rules/index.js +12 -0
  188. package/dist/lint/rules/postgres-templates.js +27 -0
  189. package/dist/lint/rules/sqlch001.js +79 -0
  190. package/dist/lint/rules/sqlch002.js +124 -0
  191. package/dist/lint/rules/sqlch003.js +69 -0
  192. package/dist/lint/rules/sqlch004.js +83 -0
  193. package/dist/lint/rules/sqlpg001.js +68 -0
  194. package/dist/lint/rules/sqlpg002.js +69 -0
  195. package/dist/lint/rules/sqlpg003.js +58 -0
  196. package/dist/lint/rules/sqlpg004.js +77 -0
  197. package/dist/lint/rules/sqlpg005.js +86 -0
  198. package/dist/lint/rules/templates.js +25 -0
  199. package/dist/lint/rules/typed-names.js +132 -0
  200. package/dist/live-dialect.js +32 -0
  201. package/dist/lsp/catalog.js +44 -0
  202. package/dist/lsp/completions.js +136 -0
  203. package/dist/lsp/hover.js +115 -0
  204. package/dist/lsp/postgres-catalog.js +176 -0
  205. package/dist/lsp/postgres-template.js +171 -0
  206. package/dist/lsp/postgres.js +266 -0
  207. package/dist/lsp/refs.js +60 -0
  208. package/dist/lsp/registry.d.ts.map +1 -1
  209. package/dist/lsp/registry.js +19 -0
  210. package/dist/lsp/template.js +143 -0
  211. package/dist/manifest.json +1 -1
  212. package/dist/mcp/index.d.ts.map +1 -1
  213. package/dist/mcp/index.js +293 -0
  214. package/dist/mcp/postgres.js +117 -0
  215. package/dist/migration-statements.js +243 -0
  216. package/dist/op/activities/clickhouse-apply.js +83 -0
  217. package/dist/op/activities/clickhouse-emulator.js +53 -0
  218. package/dist/op/activities/clickhouse-rebuild.js +119 -0
  219. package/dist/op/activities/index.js +26 -0
  220. package/dist/op/activities/postgres-apply.js +126 -0
  221. package/dist/op/activities/postgres-emulator.js +70 -0
  222. package/dist/op/activities/postgres-migration.js +156 -0
  223. package/dist/op/activities/sql-exec.js +57 -0
  224. package/dist/op/activity-contracts.js +103 -0
  225. package/dist/package-cli.js +14 -0
  226. package/dist/plugin.js +259 -0
  227. package/dist/postgres/access/acl.js +344 -0
  228. package/dist/postgres/access/changes.js +30 -0
  229. package/dist/postgres/access/import.js +61 -0
  230. package/dist/postgres/access/live.js +96 -0
  231. package/dist/postgres/apply/apply.js +557 -0
  232. package/dist/postgres/apply/statements.js +882 -0
  233. package/dist/postgres/catalog-types.js +18 -0
  234. package/dist/postgres/container.js +58 -0
  235. package/dist/postgres/entities.js +1390 -0
  236. package/dist/postgres/entity-types.js +28 -0
  237. package/dist/postgres/import/generator.js +283 -0
  238. package/dist/postgres/import/ir.js +53 -0
  239. package/dist/postgres/import/live-export.js +83 -0
  240. package/dist/postgres/keywords.js +32 -0
  241. package/dist/postgres/live/bind.js +130 -0
  242. package/dist/postgres/live/catalog-kinds.js +301 -0
  243. package/dist/postgres/live/catalog.js +644 -0
  244. package/dist/postgres/live/client.js +151 -0
  245. package/dist/postgres/live/describe-resources.js +135 -0
  246. package/dist/postgres/live/undeclarable.js +111 -0
  247. package/dist/postgres/migrate/backfill.js +170 -0
  248. package/dist/postgres/migrate/batches.js +122 -0
  249. package/dist/postgres/migrate/carry.js +518 -0
  250. package/dist/postgres/migrate/handoff.js +59 -0
  251. package/dist/postgres/migrate/names.js +61 -0
  252. package/dist/postgres/migrate/observe.js +360 -0
  253. package/dist/postgres/migrate/op.js +178 -0
  254. package/dist/postgres/migrate/receipts.js +117 -0
  255. package/dist/postgres/migrate/replication.js +106 -0
  256. package/dist/postgres/migrate/steps.js +514 -0
  257. package/dist/postgres/overlays/columns.js +31 -0
  258. package/dist/postgres/overlays/constraints.js +52 -0
  259. package/dist/postgres/overlays/extension-objects.js +88 -0
  260. package/dist/postgres/overlays/indexes.js +25 -0
  261. package/dist/postgres/overlays/kinds.js +2 -0
  262. package/dist/postgres/overlays/partitioning.js +23 -0
  263. package/dist/postgres/overlays/relations.js +25 -0
  264. package/dist/postgres/overlays/storage.js +65 -0
  265. package/dist/postgres/overlays/type-ddl.js +36 -0
  266. package/dist/postgres/overlays/types.js +74 -0
  267. package/dist/postgres/parser.js +1824 -0
  268. package/dist/postgres/plan/commands.js +137 -0
  269. package/dist/postgres/plan/deep.js +324 -0
  270. package/dist/postgres/plan/diff.js +499 -0
  271. package/dist/postgres/plan/disruption.js +64 -0
  272. package/dist/postgres/plan/normalize.js +889 -0
  273. package/dist/postgres/plan/report.js +21 -0
  274. package/dist/postgres/plan/rules.js +115 -0
  275. package/dist/postgres/plan/schema.js +105 -0
  276. package/dist/postgres/plan/server-normalize.js +166 -0
  277. package/dist/postgres/providers/aurora.js +44 -0
  278. package/dist/postgres/providers/azure.js +53 -0
  279. package/dist/postgres/providers/cloud-sql.js +41 -0
  280. package/dist/postgres/providers/index.js +73 -0
  281. package/dist/postgres/providers/neon.js +44 -0
  282. package/dist/postgres/providers/rds.js +47 -0
  283. package/dist/postgres/providers/supabase.js +45 -0
  284. package/dist/postgres/providers/types.js +21 -0
  285. package/dist/postgres/row-types.js +107 -0
  286. package/dist/postgres/testing/fake-client.js +34 -0
  287. package/dist/postgres/testing/migration.js +48 -0
  288. package/dist/postgres/testing/roundtrip-schema.js +64 -0
  289. package/dist/postgres/testing/server.js +47 -0
  290. package/dist/postgres/testing/writable-server.js +160 -0
  291. package/dist/postgres/tokens.js +41 -0
  292. package/dist/postgres.js +15 -0
  293. package/dist/read/clickhouse.js +82 -0
  294. package/dist/read/objects.js +44 -0
  295. package/dist/read/postgres.js +104 -0
  296. package/dist/read.js +52 -0
  297. package/dist/receipts.js +207 -0
  298. package/dist/serializer.js +172 -0
  299. package/dist/skill-defs.js +93 -0
  300. package/dist/spec/catalog.js +191 -0
  301. package/dist/spec/fetch.d.ts.map +1 -1
  302. package/dist/spec/fetch.js +90 -0
  303. package/dist/spec/pin.js +42 -0
  304. package/dist/spec/postgres-catalog.js +171 -0
  305. package/dist/spec/postgres-fetch.js +91 -0
  306. package/dist/spec/postgres-pin.js +82 -0
  307. package/dist/sql-files.js +206 -0
  308. package/dist/sql-types-command.js +97 -0
  309. package/dist/sql-types.js +323 -0
  310. package/dist/token-source.js +156 -0
  311. package/dist/validate-cli.js +5 -0
  312. package/dist/validate.js +151 -0
  313. package/dist/workspace-outputs.js +191 -0
  314. package/package.json +7 -7
  315. package/src/codegen/package.ts +2 -2
  316. package/src/lint/rules/typescript-7.test.ts +2 -1
  317. package/src/lsp/catalog.ts +2 -2
  318. package/src/lsp/postgres-catalog.ts +2 -2
  319. package/src/lsp/registry.ts +2 -1
  320. package/src/mcp/index.ts +4 -2
  321. package/src/spec/fetch.ts +2 -2
  322. package/src/spec/postgres-fetch.ts +2 -2
@@ -0,0 +1,138 @@
1
+ /**
2
+ * A file of ClickHouse DDL as the objects it declares: one per `CREATE
3
+ * DATABASE`, `TABLE`, `VIEW`, `MATERIALIZED VIEW`, `DICTIONARY` or `FUNCTION`, as `chant import
4
+ * <file>.sql` reads them, and one per `CREATE USER`, `CREATE ROLE`, `CREATE
5
+ * ROW POLICY`, `CREATE QUOTA`, `CREATE SETTINGS PROFILE` (#3911) and `GRANT`
6
+ * (#3711), each read by its tag, so what the tag
7
+ * refuses (`IDENTIFIED BY`, a `REVOKE`) is refused with the tag's message.
8
+ * Any other statement, and any statement the parser refuses, is a problem
9
+ * naming it.
10
+ *
11
+ * With `schema` (a database), an object's unqualified name is qualified with
12
+ * it, and so is the table a row policy or a grant is on; a function, a user
13
+ * and a role belong to no database and keep their names.
14
+ */
15
+ import { isTrivia, tokenizeText } from "../clickhouse/tokens.js";
16
+ import { parseCreate } from "../clickhouse/parser.js";
17
+ import { CLICKHOUSE_ENTITY_TYPES, database, dictionary, func, grant, policy, quota, role, settingsProfile, table, user, view } from "../clickhouse/entities.js";
18
+ import { isAccessStatement, parseAccess } from "../clickhouse/access.js";
19
+ import { CLICKHOUSE_TAG_OF } from "../clickhouse/import/generator.js";
20
+ import { describeStatement } from "../clickhouse/import/ir.js";
21
+ import { fileUnparsed, firstLine, lineAt, quoteBare, splitTokens, tokensText, undeclarableStatement } from "./common.js";
22
+ import { templateSafe, templateStrings } from "./postgres.js";
23
+ const TAGS = { database, table, view, dictionary, func, user, role, policy, quota, settingsProfile, grant };
24
+ /** The tag an access statement's words name: `CREATE USER`, `CREATE SETTINGS PROFILE`, `GRANT`. */
25
+ function accessTag(words) {
26
+ if (words[0] !== "CREATE")
27
+ return grant;
28
+ return words[1] === "USER" ? user : words[1] === "ROLE" ? role : words[1] === "QUOTA" ? quota : words[1] === "SETTINGS" || words[1] === "PROFILE" ? settingsProfile : policy;
29
+ }
30
+ /** Tokens with `[db.]name`'s bare name qualified with `schema`. A `*` (all tables) is left alone. */
31
+ function qualifyBare(tokens, span, schema) {
32
+ if (!span)
33
+ return undefined;
34
+ const name = tokens.slice(span.from, span.to).filter((t) => !isTrivia(t));
35
+ const [only] = name;
36
+ if (!only || name.length !== 1 || (only.kind !== "ident" && only.kind !== "qident"))
37
+ return undefined;
38
+ const at = tokens.indexOf(only);
39
+ return tokensText(tokens.slice(0, at)) + `${quoteBare(schema)}.` + tokensText(tokens.slice(at));
40
+ }
41
+ /** An access statement as the object its tag declares (#3711), or the tag's refusal. */
42
+ function readAccess(sql, options) {
43
+ let tokens = tokenizeText(sql, 0);
44
+ let node;
45
+ try {
46
+ node = parseAccess(tokens);
47
+ }
48
+ catch (e) {
49
+ // What the tag refuses (a password) is refused in the tag's words.
50
+ const tag = accessTag(sql.replace(/--[^\n]*\n/g, " ").trim().split(/\s+/, 2).map((w) => w.toUpperCase()));
51
+ try {
52
+ tag(templateStrings([templateSafe(sql)]));
53
+ }
54
+ catch (refused) {
55
+ return refused instanceof Error ? refused.message : String(refused);
56
+ }
57
+ throw e;
58
+ }
59
+ if (options.schema) {
60
+ const qualified = qualifyBare(tokens, node.statement === "rowPolicy" ? node.table : node.statement === "grant" ? node.target : undefined, options.schema);
61
+ if (qualified !== undefined) {
62
+ sql = qualified;
63
+ tokens = tokenizeText(sql, 0);
64
+ node = parseAccess(tokens);
65
+ }
66
+ }
67
+ const tag = { user, role, rowPolicy: policy, quota, settingsProfile, grant }[node.statement];
68
+ let props;
69
+ try {
70
+ props = tag(templateStrings([templateSafe(sql)])).props;
71
+ }
72
+ catch (e) {
73
+ return e instanceof Error ? e.message : String(e);
74
+ }
75
+ if (node.statement === "user")
76
+ return { type: CLICKHOUSE_ENTITY_TYPES.user, name: props.name, ddl: sql };
77
+ if (node.statement === "role")
78
+ return { type: CLICKHOUSE_ENTITY_TYPES.role, name: props.name, ddl: sql };
79
+ if (node.statement === "quota")
80
+ return { type: CLICKHOUSE_ENTITY_TYPES.quota, name: props.name, ddl: sql };
81
+ if (node.statement === "settingsProfile")
82
+ return { type: CLICKHOUSE_ENTITY_TYPES.settingsProfile, name: props.name, ddl: sql };
83
+ if (node.statement === "rowPolicy")
84
+ return { type: CLICKHOUSE_ENTITY_TYPES.rowPolicy, ...(props.database ? { database: props.database } : {}), name: props.name, ddl: sql };
85
+ // A grant has no name of its own: what it grants, on what, to whom.
86
+ return { type: CLICKHOUSE_ENTITY_TYPES.grant, name: `grant ${tokensText(tokens.slice(tokens.findIndex((t) => !isTrivia(t)) + 1)).replace(/\s+/g, " ").trim().toLowerCase()}`, ddl: sql };
87
+ }
88
+ /** The tag that declares an entity type. */
89
+ export function clickhouseTag(type) {
90
+ const name = CLICKHOUSE_TAG_OF[type];
91
+ return name ? TAGS[name] : undefined;
92
+ }
93
+ /** The objects a file of ClickHouse DDL declares. Problems are collected, not thrown, so a file is reported whole. */
94
+ export function readClickHouse(ddl, options, problems) {
95
+ const objects = [];
96
+ for (const stmt of splitTokens(tokenizeText(ddl, 0), isTrivia)) {
97
+ let sql = tokensText(stmt);
98
+ const line = lineAt(ddl, stmt[0].start);
99
+ const undeclarable = undeclarableStatement("clickhouse", sql);
100
+ if (undeclarable) {
101
+ (options.undeclarable ?? problems).push(undeclarable);
102
+ continue;
103
+ }
104
+ if (isAccessStatement(sql)) {
105
+ try {
106
+ const read = readAccess(sql, options);
107
+ if (typeof read === "string")
108
+ problems.push(`${read}: ${firstLine(sql)}`);
109
+ else
110
+ objects.push({ ...read, line });
111
+ }
112
+ catch (e) {
113
+ problems.push(`does not parse (${e instanceof Error ? e.message : String(e)}): ${firstLine(sql)}`);
114
+ }
115
+ continue;
116
+ }
117
+ if (!/^CREATE\b/i.test(sql)) {
118
+ problems.push(`not a CREATE statement: ${firstLine(sql)}`);
119
+ continue;
120
+ }
121
+ try {
122
+ const tokens = tokenizeText(sql, 0);
123
+ const node = parseCreate(tokens);
124
+ const name = tokens.slice(node.name.from, node.name.to).filter((t) => !isTrivia(t));
125
+ const [only] = name;
126
+ if (options.schema && node.statement !== "database" && node.statement !== "function" && only && name.length === 1) {
127
+ const at = tokens.indexOf(only);
128
+ sql = tokensText(tokens.slice(0, at)) + `${quoteBare(options.schema)}.` + tokensText(tokens.slice(at));
129
+ }
130
+ const unparsed = fileUnparsed(node.unknown, tokens, sql, line);
131
+ objects.push({ ...describeStatement(sql), line, ...(unparsed ? { unparsed } : {}) });
132
+ }
133
+ catch (e) {
134
+ problems.push(`does not parse (${e instanceof Error ? e.message : String(e)}): ${firstLine(sql)}`);
135
+ }
136
+ }
137
+ return objects;
138
+ }
@@ -0,0 +1,58 @@
1
+ /** What reading a file of DDL shares across dialects. */
2
+ import { statementKind } from "../coverage.js";
3
+ /**
4
+ * A `CREATE` of a kind the coverage table does not mark declared, as the line
5
+ * that names it with why, or undefined for any other statement.
6
+ */
7
+ export function undeclarableStatement(dialect, sql) {
8
+ const row = statementKind(dialect, sql);
9
+ if (!row || row.status === "declared")
10
+ return undefined;
11
+ return `${row.kind}: chant cannot declare it (${row.reason ?? row.status}): ${firstLine(sql)}`;
12
+ }
13
+ /** A file of DDL with statements that declare nothing chant can hold: each problem names its statement. */
14
+ export class SqlFileError extends Error {
15
+ constructor(origin, problems) {
16
+ super(`${origin}: ${problems.length === 1 ? "a statement" : `${String(problems.length)} statements`} chant cannot read as declarations:\n${problems.map((p) => ` - ${p}`).join("\n")}`);
17
+ this.origin = origin;
18
+ this.problems = problems;
19
+ this.name = "SqlFileError";
20
+ }
21
+ }
22
+ /** The statements of a file, each as its tokens (trivia kept inside, trimmed at the ends), split on top-level `;`. */
23
+ export function splitTokens(tokens, isTrivia) {
24
+ const out = [];
25
+ let current = [];
26
+ const flush = () => {
27
+ let from = 0;
28
+ let to = current.length;
29
+ while (from < to && isTrivia(current[from]))
30
+ from++;
31
+ while (to > from && isTrivia(current[to - 1]))
32
+ to--;
33
+ if (to > from)
34
+ out.push(current.slice(from, to));
35
+ current = [];
36
+ };
37
+ for (const t of tokens) {
38
+ if (t.kind === "punct" && t.text === ";")
39
+ flush();
40
+ else
41
+ current.push(t);
42
+ }
43
+ flush();
44
+ return out;
45
+ }
46
+ export const tokensText = (tokens) => tokens.map((t) => t.text).join("");
47
+ /** A statement's unknown clauses with their lines in the file: `line` is the statement's, `sql` its text, `tokens` its tokens. */
48
+ export function fileUnparsed(unknown, tokens, sql, line) {
49
+ if (!unknown || unknown.length === 0)
50
+ return undefined;
51
+ return unknown.map((u) => ({ clause: u.clause, line: line + lineAt(sql, tokens[u.span.from]?.start ?? 0) - 1, ...(u.column !== undefined ? { column: u.column } : {}) }));
52
+ }
53
+ /** The line, from 1, that offset `at` of `text` is on. */
54
+ export const lineAt = (text, at) => text.slice(0, at).split("\n").length;
55
+ /** A statement's first line, for a message. */
56
+ export const firstLine = (s) => (s.split("\n")[0] ?? "").slice(0, 100);
57
+ /** A name as SQL text: bare when it is a plain lower-case identifier, else double-quoted. */
58
+ export const quoteBare = (name) => (/^[a-z_][a-z0-9_]*$/.test(name) ? name : `"${name.replace(/"/g, '""')}"`);
@@ -0,0 +1,389 @@
1
+ /**
2
+ * A file of Postgres DDL as the objects it declares: each `CREATE` (and each
3
+ * `GRANT`, `REVOKE` and `ALTER DEFAULT PRIVILEGES`) is one object, and the
4
+ * statements that only finish one are folded into it:
5
+ *
6
+ * - `COMMENT ON` joins the object it comments on, wherever in the file it is;
7
+ * - `ALTER TABLE ... ENABLE | DISABLE | FORCE ROW LEVEL SECURITY` joins its table;
8
+ * - `ALTER TABLE <t> ADD [CONSTRAINT <c>] FOREIGN KEY | UNIQUE | PRIMARY KEY |
9
+ * CHECK | EXCLUDE ...`, the form `pg_dump` and ORMs print constraints in,
10
+ * becomes a table constraint in `<t>`'s `CREATE TABLE`.
11
+ *
12
+ * `BEGIN` and `COMMIT` are skipped. Any other statement, and any statement
13
+ * the parser or its tag refuses, is a problem naming it: a statement left
14
+ * out would be a schema change nobody declared.
15
+ *
16
+ * With `schema`, the names the DDL leaves unqualified are qualified with it,
17
+ * as an ORM's connection would: an object's own name, an index's, trigger's
18
+ * or policy's table, a foreign key's table, a comment's target, and a column
19
+ * type naming an enum, composite, range or domain type the file creates.
20
+ */
21
+ import { isTrivia, tokenizeText } from "../postgres/tokens.js";
22
+ import { identValue, parseStatements } from "../postgres/parser.js";
23
+ import * as tags from "../postgres/entities.js";
24
+ import { POSTGRES_ENTITY_TYPES } from "../postgres/entity-types.js";
25
+ import { POSTGRES_TAG_OF } from "../postgres/import/generator.js";
26
+ import { fileUnparsed, firstLine, lineAt, quoteBare, splitTokens, tokensText, undeclarableStatement } from "./common.js";
27
+ /** The tag that declares an entity type. */
28
+ export function postgresTag(type) {
29
+ const name = POSTGRES_TAG_OF[type];
30
+ return name ? (tags[name] ?? undefined) : undefined;
31
+ }
32
+ /** A tagged-template call's strings from template-literal text: `raw` as written, as the tag reads it. */
33
+ export function templateStrings(parts) {
34
+ return Object.assign([...parts], { raw: [...parts] });
35
+ }
36
+ const isName = (t) => t !== undefined && (t.kind === "ident" || t.kind === "qident");
37
+ const word = (t, ...words) => t !== undefined && t.kind === "ident" && words.includes(t.text.toUpperCase());
38
+ /** Text that sits inside a template literal: a backquote and `${` escaped. */
39
+ /** Text that sits inside a template literal: a backquote and `${` escaped. */
40
+ export const templateSafe = (s) => s.replace(/\\(?=`|\$\{)/g, "\\\\").replace(/`/g, "\\`").replace(/\$\{/g, "\\${");
41
+ /** Transaction control, which declares nothing. */
42
+ function isTransactionControl(sig) {
43
+ const words = sig.map((t) => (t.kind === "ident" ? t.text.toUpperCase() : ""));
44
+ const [first, ...rest] = words;
45
+ if (first === "BEGIN" || first === "COMMIT" || first === "END")
46
+ return rest.every((w) => w === "TRANSACTION" || w === "WORK");
47
+ return first === "START" && rest.length === 1 && rest[0] === "TRANSACTION";
48
+ }
49
+ /**
50
+ * The objects a file of Postgres DDL declares, each with its statements
51
+ * joined as one declaration's DDL. Problems are collected, not thrown, so a
52
+ * file is reported whole.
53
+ */
54
+ export function readPostgres(ddl, options, problems) {
55
+ const parsed = [];
56
+ const alters = [];
57
+ for (const stmt of splitTokens(tokenizeText(ddl, 0), isTrivia)) {
58
+ const sig = stmt.filter((t) => !isTrivia(t));
59
+ const sql = tokensText(stmt);
60
+ if (isTransactionControl(sig))
61
+ continue;
62
+ if (word(sig[0], "ALTER") && word(sig[1], "TABLE")) {
63
+ const alter = readAlterAdd(stmt, sig);
64
+ if (alter) {
65
+ alters.push({ ...alter, sql });
66
+ continue;
67
+ }
68
+ }
69
+ if (!word(sig[0], "CREATE", "COMMENT", "GRANT", "REVOKE", "ALTER")) {
70
+ problems.push(`not a statement that declares an object: ${firstLine(sql)}`);
71
+ continue;
72
+ }
73
+ const undeclarable = undeclarableStatement("postgres", sql);
74
+ if (undeclarable) {
75
+ (options.undeclarable ?? problems).push(undeclarable);
76
+ continue;
77
+ }
78
+ try {
79
+ const tokens = tokenizeText(sql, 0);
80
+ for (const node of parseStatements(tokens))
81
+ parsed.push({ tokens, node, line: lineAt(ddl, stmt[0].start) });
82
+ }
83
+ catch (e) {
84
+ const what = word(sig[0], "ALTER") && word(sig[1], "TABLE") ? "an ALTER TABLE other than ADD of a table constraint or ROW LEVEL SECURITY" : `does not parse (${e instanceof Error ? e.message : String(e)})`;
85
+ problems.push(`${what}: ${firstLine(sql)}`);
86
+ }
87
+ }
88
+ const nameOf = (tokens, n) => n.pieces.length > 0 && n.pieces.every((p) => p !== "") ? n.pieces : tokens.slice(n.span.from, n.span.to).filter((t) => isName(t)).map((t) => identValue(t));
89
+ const qualify = (pieces) => {
90
+ const name = pieces[pieces.length - 1] ?? "";
91
+ const schema = pieces.length >= 2 ? pieces[pieces.length - 2] : options.schema;
92
+ return schema ? { schema, name } : { name };
93
+ };
94
+ const key = (q) => `${q.schema ?? ""}.${q.name}`;
95
+ // The types the file creates, so a column of one is qualified with the rest.
96
+ const fileTypes = new Set();
97
+ for (const { tokens, node } of parsed) {
98
+ if (node.statement === "enum" || node.statement === "domain" || node.statement === "composite" || node.statement === "range") {
99
+ const pieces = nameOf(tokens, node.name);
100
+ if (pieces.length === 1)
101
+ fileTypes.add(pieces[0]);
102
+ }
103
+ }
104
+ const objects = [];
105
+ /** Objects by namespace and name: `rel` (anything in a schema), `index`, `schema`, `extension`, `role`, and `trigger`/`policy` with their table. */
106
+ const owners = new Map();
107
+ const followOns = [];
108
+ for (const { tokens, node, line } of parsed) {
109
+ const inserts = new Set();
110
+ /** Qualifies an unqualified name in the statement, when `schema` is set. */
111
+ const mark = (n) => {
112
+ if (!n || !options.schema)
113
+ return;
114
+ const names = tokens.slice(n.span.from, n.span.to).filter((t) => !isTrivia(t));
115
+ const [only] = names;
116
+ if (only && names.length === 1 && isName(only))
117
+ inserts.add(tokens.indexOf(only));
118
+ };
119
+ switch (node.statement) {
120
+ case "comment":
121
+ if (!["SCHEMA", "EXTENSION", "ROLE", "TRIGGER", "POLICY", "CONSTRAINT", "COLUMN", "CAST", "EVENT TRIGGER"].includes(node.objectType))
122
+ mark(node.target);
123
+ if (node.objectType === "COLUMN" && nameOf(tokens, node.target).length === 2 && options.schema) {
124
+ const first = tokens.slice(node.target.span.from, node.target.span.to).find((t) => !isTrivia(t));
125
+ if (first)
126
+ inserts.add(tokens.indexOf(first));
127
+ }
128
+ mark(node.on);
129
+ followOns.push({ tokens, node, inserts });
130
+ continue;
131
+ case "rowSecurity":
132
+ mark(node.table);
133
+ followOns.push({ tokens, node, inserts });
134
+ continue;
135
+ case "index":
136
+ case "trigger":
137
+ case "policy":
138
+ mark(node.table);
139
+ break;
140
+ case "table":
141
+ for (const c of [...node.columns.flatMap((col) => col.constraints), ...node.constraints])
142
+ mark(c.references?.table);
143
+ if (options.schema) {
144
+ for (const col of node.columns) {
145
+ if (!col.type)
146
+ continue;
147
+ const type = tokens.slice(col.type.from, col.type.to).filter((t) => !isTrivia(t));
148
+ const first = type[0];
149
+ if (first && isName(first) && fileTypes.has(identValue(first)) && !(type[1]?.kind === "punct" && type[1].text === "."))
150
+ inserts.add(tokens.indexOf(first));
151
+ }
152
+ }
153
+ break;
154
+ default:
155
+ break;
156
+ }
157
+ if (node.statement === "schema" && !node.name) {
158
+ problems.push(`a CREATE SCHEMA with no name: ${firstLine(tokensText(tokens))}`);
159
+ continue;
160
+ }
161
+ if (node.statement === "index" && !node.name) {
162
+ problems.push(`an index with no name (its declaration needs one): ${firstLine(tokensText(tokens))}`);
163
+ continue;
164
+ }
165
+ const ownName = !["schema", "extension", "index", "trigger", "policy", "role", "grant", "cast", "eventTrigger"].includes(node.statement);
166
+ if (ownName && "name" in node)
167
+ mark(node.name);
168
+ const object = { node, statements: [rewrite(tokens, inserts, options.schema)], constraints: [], line, unparsed: fileUnparsed("unknown" in node ? node.unknown : undefined, tokens, tokensText(tokens), line) };
169
+ objects.push(object);
170
+ const k = ownerKey(node, tokens, nameOf, qualify);
171
+ if (k)
172
+ owners.set(k, object);
173
+ }
174
+ for (const f of followOns) {
175
+ const k = followOnOwner(f.node, f.tokens, nameOf, qualify);
176
+ const owner = k ? owners.get(k) : undefined;
177
+ if (!owner) {
178
+ const what = f.node.statement === "comment" ? `COMMENT ON ${f.node.objectType}` : "ALTER TABLE ... ROW LEVEL SECURITY";
179
+ problems.push(`${what} for an object the file does not create: ${firstLine(tokensText(f.tokens))}`);
180
+ continue;
181
+ }
182
+ owner.statements.push(rewrite(f.tokens, f.inserts, options.schema));
183
+ }
184
+ for (const alter of alters) {
185
+ const table = owners.get(`rel ${key(qualify(alter.table))}`);
186
+ if (!table || table.node.statement !== "table") {
187
+ problems.push(`ALTER TABLE of a table the file does not create: ${firstLine(alter.sql)}`);
188
+ continue;
189
+ }
190
+ table.constraints.push(qualifyConstraint(alter.constraint, options.schema));
191
+ }
192
+ const out = [];
193
+ for (const o of objects) {
194
+ const [create = [], ...rest] = o.statements;
195
+ const ddlText = [o.constraints.length > 0 ? addConstraints(create, o.constraints) : tokensText(create), ...rest.map((c) => tokensText(c))].join(";\n");
196
+ const identity = identify(ddlText);
197
+ if (typeof identity === "string") {
198
+ problems.push(`${identity}: ${firstLine(ddlText)}`);
199
+ continue;
200
+ }
201
+ out.push({ ...identity, ddl: ddlText, line: o.line, ...(o.unparsed ? { unparsed: o.unparsed } : {}) });
202
+ }
203
+ return out;
204
+ }
205
+ /** An object's entity type, schema and name, read by declaring it with its tag; a string is the tag's refusal. */
206
+ function identify(ddl) {
207
+ let tokens;
208
+ let node;
209
+ try {
210
+ tokens = tokenizeText(ddl, 0);
211
+ [node] = parseStatements(tokens);
212
+ }
213
+ catch (e) {
214
+ return `does not parse (${e instanceof Error ? e.message : String(e)})`;
215
+ }
216
+ const type = node ? entityTypeOf(node) : undefined;
217
+ const tag = type ? postgresTag(type) : undefined;
218
+ if (!type || !tag)
219
+ return "not a statement that declares an object";
220
+ try {
221
+ const entity = tag(templateStrings([templateSafe(ddl)]));
222
+ const p = entity.props;
223
+ return { type: entity.entityType, ...(p.schema ? { schema: p.schema } : {}), name: p.name };
224
+ }
225
+ catch (e) {
226
+ return e instanceof Error ? e.message : String(e);
227
+ }
228
+ }
229
+ /** The entity type a statement declares. */
230
+ function entityTypeOf(node) {
231
+ switch (node.statement) {
232
+ case "view":
233
+ return node.materialized ? POSTGRES_ENTITY_TYPES.materializedView : POSTGRES_ENTITY_TYPES.view;
234
+ case "grant":
235
+ return node.defaults ? POSTGRES_ENTITY_TYPES.defaultPrivileges : POSTGRES_ENTITY_TYPES.grant;
236
+ case "comment":
237
+ case "rowSecurity":
238
+ return undefined;
239
+ default:
240
+ return POSTGRES_ENTITY_TYPES[node.statement];
241
+ }
242
+ }
243
+ const qkey = (q) => `${q.schema ?? ""}.${q.name}`;
244
+ /** The key a created object is found under by the statements folded into it. */
245
+ function ownerKey(node, tokens, nameOf, qualify) {
246
+ switch (node.statement) {
247
+ case "schema":
248
+ return node.name ? `schema ${nameOf(tokens, node.name).at(-1) ?? ""}` : undefined;
249
+ case "extension":
250
+ return `extension ${nameOf(tokens, node.name).at(-1) ?? ""}`;
251
+ case "role":
252
+ return `role ${nameOf(tokens, node.name).at(-1) ?? ""}`;
253
+ case "index": {
254
+ // An index is in its table's schema.
255
+ const table = nameOf(tokens, node.table);
256
+ return node.name ? `index ${qkey(qualify([...table.slice(0, -1), nameOf(tokens, node.name).at(-1) ?? ""]))}` : undefined;
257
+ }
258
+ case "trigger":
259
+ case "policy":
260
+ return `${node.statement} ${nameOf(tokens, node.name).at(-1) ?? ""} ON ${qkey(qualify(nameOf(tokens, node.table)))}`;
261
+ case "eventTrigger":
262
+ return `eventTrigger ${nameOf(tokens, node.name).at(-1) ?? ""}`;
263
+ case "cast":
264
+ return `cast ${castKey(tokens, node.source, node.target)}`;
265
+ case "grant":
266
+ case "comment":
267
+ case "rowSecurity":
268
+ return undefined;
269
+ default:
270
+ return `rel ${qkey(qualify(nameOf(tokens, node.name)))}`;
271
+ }
272
+ }
273
+ /** The key of the object a COMMENT ON or ALTER TABLE ... ROW LEVEL SECURITY finishes. */
274
+ function followOnOwner(node, tokens, nameOf, qualify) {
275
+ if (node.statement === "rowSecurity")
276
+ return `rel ${qkey(qualify(nameOf(tokens, node.table)))}`;
277
+ if (node.statement !== "comment")
278
+ return undefined;
279
+ const target = nameOf(tokens, node.target);
280
+ switch (node.objectType) {
281
+ case "SCHEMA":
282
+ return `schema ${target.at(-1) ?? ""}`;
283
+ case "EXTENSION":
284
+ return `extension ${target.at(-1) ?? ""}`;
285
+ case "ROLE":
286
+ return `role ${target.at(-1) ?? ""}`;
287
+ case "INDEX":
288
+ return `index ${qkey(qualify(target))}`;
289
+ case "COLUMN":
290
+ return `rel ${qkey(qualify(target.slice(0, -1)))}`;
291
+ case "TRIGGER":
292
+ case "POLICY":
293
+ return node.on ? `${node.objectType.toLowerCase()} ${target.at(-1) ?? ""} ON ${qkey(qualify(nameOf(tokens, node.on)))}` : undefined;
294
+ case "EVENT TRIGGER":
295
+ return `eventTrigger ${target.at(-1) ?? ""}`;
296
+ case "CAST":
297
+ return node.cast ? `cast ${castKey(tokens, node.cast.source, node.cast.target)}` : undefined;
298
+ case "CONSTRAINT":
299
+ case "DOMAIN CONSTRAINT":
300
+ return node.on ? `rel ${qkey(qualify(nameOf(tokens, node.on)))}` : undefined;
301
+ default:
302
+ return `rel ${qkey(qualify(target))}`;
303
+ }
304
+ }
305
+ /** A cast's two types as one key, spacing and case aside. */
306
+ function castKey(tokens, source, target) {
307
+ const text = (sp) => tokens.slice(sp.from, sp.to).filter((t) => !isTrivia(t)).map((t) => (t.kind === "ident" ? t.text.toLowerCase() : t.text)).join(" ");
308
+ return `(${text(source)} AS ${text(target)})`;
309
+ }
310
+ /** The statement's tokens with `schema.` inserted before each marked one. */
311
+ function rewrite(tokens, inserts, schema) {
312
+ if (!schema || inserts.size === 0)
313
+ return [...tokens];
314
+ const out = [];
315
+ tokens.forEach((t, i) => {
316
+ if (inserts.has(i))
317
+ out.push({ kind: "ident", text: `${quoteBare(schema)}.`, part: 0, start: 0, end: 0 });
318
+ out.push(t);
319
+ });
320
+ return out;
321
+ }
322
+ /** `ALTER TABLE [IF EXISTS] [ONLY] <name> ADD <table constraint>`: the table's name pieces and the constraint's text. */
323
+ function readAlterAdd(stmt, sig) {
324
+ let i = 2;
325
+ if (word(sig[i], "IF") && word(sig[i + 1], "EXISTS"))
326
+ i += 2;
327
+ if (word(sig[i], "ONLY"))
328
+ i++;
329
+ const table = [];
330
+ for (let t = sig[i]; t && isName(t); t = sig[i]) {
331
+ table.push(identValue(t));
332
+ i++;
333
+ const dot = sig[i];
334
+ if (dot?.kind === "punct" && dot.text === ".")
335
+ i++;
336
+ else
337
+ break;
338
+ }
339
+ if (table.length === 0 || !word(sig[i], "ADD"))
340
+ return undefined;
341
+ i++;
342
+ if (!word(sig[i], "CONSTRAINT", "FOREIGN", "UNIQUE", "PRIMARY", "CHECK", "EXCLUDE"))
343
+ return undefined;
344
+ // One constraint: a comma at depth 0 starts another ALTER action, which is not read.
345
+ let depth = 0;
346
+ for (const t of sig.slice(i)) {
347
+ if (t.kind === "punct" && t.text === "(")
348
+ depth++;
349
+ else if (t.kind === "punct" && t.text === ")")
350
+ depth--;
351
+ else if (t.kind === "punct" && t.text === "," && depth === 0)
352
+ return undefined;
353
+ }
354
+ const start = sig[i];
355
+ return start ? { table, constraint: tokensText(stmt.slice(stmt.indexOf(start))) } : undefined;
356
+ }
357
+ /** Qualifies the table a folded FOREIGN KEY references, when it is unqualified. */
358
+ function qualifyConstraint(constraint, schema) {
359
+ if (!schema)
360
+ return constraint;
361
+ const tokens = tokenizeText(constraint, 0);
362
+ const sig = tokens.map((t, i) => ({ t, i })).filter((x) => !isTrivia(x.t));
363
+ const inserts = new Set();
364
+ sig.forEach((x, k) => {
365
+ const target = sig[k + 1];
366
+ const dot = sig[k + 2]?.t;
367
+ if (word(x.t, "REFERENCES") && target && isName(target.t) && !(dot?.kind === "punct" && dot.text === "."))
368
+ inserts.add(target.i);
369
+ });
370
+ return tokensText(rewrite(tokens, inserts, schema));
371
+ }
372
+ /** A CREATE TABLE with table constraints added at the end of its column list (the `)` matching the first `(`). */
373
+ function addConstraints(create, constraints) {
374
+ let depth = 0;
375
+ const close = create.findIndex((t) => {
376
+ if (t.kind !== "punct")
377
+ return false;
378
+ if (t.text === "(")
379
+ depth++;
380
+ else if (t.text === ")")
381
+ return --depth === 0;
382
+ return false;
383
+ });
384
+ if (close < 0)
385
+ return tokensText(create);
386
+ const before = tokensText(create.slice(0, close)).replace(/\s+$/, "");
387
+ const indent = /\n([ \t]+)\S[^\n]*$/.exec(before)?.[1] ?? " ";
388
+ return `${before}${constraints.map((c) => `,\n${indent}${c}`).join("")}\n${tokensText(create.slice(close))}`;
389
+ }
@@ -0,0 +1,5 @@
1
+ // Generated by `npm run generate` from the ClickHouse catalog at 26.8.15.10
2
+ // (src/spec/clickhouse-catalog.snapshot.json) and the overlays in src/clickhouse/overlays/. Do not edit.
3
+ // The type surface: unions of every named thing in the catalog, and the two settings interfaces.
4
+ /** The ClickHouse release these types were read from. */
5
+ export const CLICKHOUSE_VERSION = "26.8.15.10";