@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,160 @@
1
+ /**
2
+ * A fake Postgres server for the applier's unit tests (#3280): a client that
3
+ * keeps the objects it was sent `CREATE` for, their comments set by
4
+ * `COMMENT ON`, and drops them on `DROP`, with transactions that roll back;
5
+ * and a catalog reader over what it keeps, standing in for
6
+ * `../live/catalog.ts`. What it was sent is recorded, so a test asserts on
7
+ * the transport.
8
+ *
9
+ * It parses statements with the dialect's own parser, so what it stores reads
10
+ * back as the declaration it came from. It does not model locks, column
11
+ * changes or dependencies: a test that needs those runs against the pinned
12
+ * server (`../../op/activities/postgres-apply.e2e.test.ts`).
13
+ */
14
+ import { PostgresQueryError } from "../live/client.js";
15
+ import { stripMarker } from "../../core/ownership.js";
16
+ import { tokenizeText } from "../tokens.js";
17
+ import { parseStatements } from "../parser.js";
18
+ import { POSTGRES_ENTITY_TYPES } from "../entity-types.js";
19
+ import { quoteIdent } from "../keywords.js";
20
+ const KIND_WORD = {
21
+ [POSTGRES_ENTITY_TYPES.schema]: "SCHEMA",
22
+ [POSTGRES_ENTITY_TYPES.table]: "TABLE",
23
+ [POSTGRES_ENTITY_TYPES.index]: "INDEX",
24
+ [POSTGRES_ENTITY_TYPES.view]: "VIEW",
25
+ [POSTGRES_ENTITY_TYPES.materializedView]: "MATERIALIZED VIEW",
26
+ [POSTGRES_ENTITY_TYPES.sequence]: "SEQUENCE",
27
+ [POSTGRES_ENTITY_TYPES.enum]: "TYPE",
28
+ [POSTGRES_ENTITY_TYPES.domain]: "DOMAIN",
29
+ [POSTGRES_ENTITY_TYPES.extension]: "EXTENSION",
30
+ };
31
+ const flat = (type) => type === POSTGRES_ENTITY_TYPES.schema || type === POSTGRES_ENTITY_TYPES.extension;
32
+ const qname = (o) => (flat(o.type) || !o.schema ? quoteIdent(o.name) : `${quoteIdent(o.schema)}.${quoteIdent(o.name)}`);
33
+ const split = (n, defaultSchema = "public") => n.pieces.length > 1 ? { schema: n.pieces[0], name: n.pieces[1] } : { schema: defaultSchema, name: n.pieces[0] };
34
+ const unquote = (s) => s.replace(/^'/, "").replace(/'$/, "").replace(/''/g, "'");
35
+ export function writablePostgres(seed = []) {
36
+ let objects = seed.map((o) => ({ ...o }));
37
+ let snapshot;
38
+ const server = {
39
+ objects,
40
+ writes: [],
41
+ deletes: [],
42
+ control: [],
43
+ readLive: async () => server.objects.map((o, i) => {
44
+ const own = o.comment !== undefined ? stripMarker(o.comment) : "";
45
+ return {
46
+ type: o.type,
47
+ ...(flat(o.type) ? {} : { schema: o.schema }),
48
+ name: o.name,
49
+ oid: String(16384 + i),
50
+ ...(o.comment !== undefined ? { comment: o.comment } : {}),
51
+ ...(o.foreign ? { foreign: o.foreign } : {}),
52
+ statement: [o.create, ...(own ? [`COMMENT ON ${KIND_WORD[o.type]} ${qname(o)} IS '${own.replace(/'/g, "''")}'`] : [])].join(";\n"),
53
+ };
54
+ }),
55
+ client: {
56
+ async query(sql) {
57
+ const s = sql.trim();
58
+ if (/^BEGIN$/i.test(s)) {
59
+ server.control.push("BEGIN");
60
+ snapshot = server.objects.map((o) => ({ ...o }));
61
+ return [];
62
+ }
63
+ if (/^COMMIT$/i.test(s)) {
64
+ server.control.push("COMMIT");
65
+ snapshot = undefined;
66
+ return [];
67
+ }
68
+ if (/^ROLLBACK$/i.test(s)) {
69
+ server.control.push("ROLLBACK");
70
+ if (snapshot)
71
+ server.objects = objects = snapshot;
72
+ snapshot = undefined;
73
+ return [];
74
+ }
75
+ if (/^(SET|SELECT|RESET)\b/i.test(s))
76
+ return [];
77
+ if (server.refuse?.test(s))
78
+ throw new PostgresQueryError(`refused: ${s.split("\n")[0]}`, server.refuseCode ?? "XX000");
79
+ server.writes.push(s);
80
+ const drop = /^DROP\s+(MATERIALIZED VIEW|INDEX(?:\s+CONCURRENTLY)?|TABLE|VIEW|SEQUENCE|TYPE|DOMAIN|EXTENSION|SCHEMA)\s+(.+)$/i.exec(s);
81
+ if (drop) {
82
+ server.deletes.push(s);
83
+ const word = drop[1].toUpperCase().replace(/\s+CONCURRENTLY$/, "");
84
+ const at = server.objects.findIndex((o) => KIND_WORD[o.type] === word && qname(o) === drop[2].trim());
85
+ if (at >= 0)
86
+ server.objects.splice(at, 1);
87
+ return [];
88
+ }
89
+ let node;
90
+ try {
91
+ node = parseStatements(tokenizeText(s, 0))[0];
92
+ }
93
+ catch {
94
+ return []; // ALTER and the rest: recorded, not modelled
95
+ }
96
+ if (!node)
97
+ return [];
98
+ if (node.statement === "comment") {
99
+ const c = node;
100
+ const entry = Object.entries(KIND_WORD).find(([, w]) => w === c.objectType.toUpperCase());
101
+ if (!entry)
102
+ return [];
103
+ const type = entry[0];
104
+ const n = flat(type) ? { name: c.target.pieces[0] } : split(c.target);
105
+ const o = server.objects.find((x) => x.type === type && x.name === n.name && (flat(type) || x.schema === n.schema));
106
+ const text = c.text ? unquote(/IS\s+('(?:[^']|'')*')\s*$/i.exec(s)?.[1] ?? "") : undefined;
107
+ if (o) {
108
+ if (text === undefined)
109
+ delete o.comment;
110
+ else
111
+ o.comment = text;
112
+ }
113
+ return [];
114
+ }
115
+ const add = (type, schema, name) => {
116
+ if (server.objects.some((x) => x.type === type && x.name === name && x.schema === schema)) {
117
+ throw new PostgresQueryError(`relation "${name}" already exists`, "42P07");
118
+ }
119
+ server.objects.push({ type, ...(schema !== undefined ? { schema } : {}), name, create: s.replace(/\bCREATE\s+OR\s+REPLACE\s+/i, "CREATE ") });
120
+ };
121
+ switch (node.statement) {
122
+ case "schema":
123
+ add(POSTGRES_ENTITY_TYPES.schema, undefined, node.name.pieces[0]);
124
+ break;
125
+ case "extension":
126
+ add(POSTGRES_ENTITY_TYPES.extension, undefined, node.name.pieces[0]);
127
+ break;
128
+ case "table":
129
+ case "sequence":
130
+ case "enum":
131
+ case "domain": {
132
+ const n = split(node.name);
133
+ const type = { table: POSTGRES_ENTITY_TYPES.table, sequence: POSTGRES_ENTITY_TYPES.sequence, enum: POSTGRES_ENTITY_TYPES.enum, domain: POSTGRES_ENTITY_TYPES.domain }[node.statement];
134
+ add(type, n.schema, n.name);
135
+ break;
136
+ }
137
+ case "view": {
138
+ const n = split(node.name);
139
+ const type = node.materialized ? POSTGRES_ENTITY_TYPES.materializedView : POSTGRES_ENTITY_TYPES.view;
140
+ if (node.orReplace) {
141
+ const o = server.objects.find((x) => x.type === type && x.name === n.name && x.schema === n.schema);
142
+ if (o) {
143
+ o.create = s.replace(/\bCREATE\s+OR\s+REPLACE\s+/i, "CREATE ");
144
+ break;
145
+ }
146
+ }
147
+ add(type, n.schema, n.name);
148
+ break;
149
+ }
150
+ case "index":
151
+ add(POSTGRES_ENTITY_TYPES.index, split(node.table).schema, node.name.pieces[0]);
152
+ break;
153
+ }
154
+ return [];
155
+ },
156
+ async end() { },
157
+ },
158
+ };
159
+ return server;
160
+ }
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Postgres's lexical rules over the shared lossless tokenizer
3
+ * (`../core/tokens.ts`, chant #3278), from the Postgres 18 reference,
4
+ * "Lexical Structure":
5
+ *
6
+ * - `"` quotes an identifier; a backtick is an operator character.
7
+ * - A backslash is an ordinary character in `'...'` (standard_conforming_strings
8
+ * is on by default since 9.1) and escapes only in an `E'...'` string. `B'...'`,
9
+ * `X'...'`, `N'...'` and `U&'...'` are strings too, each one token.
10
+ * - `$$...$$` and `$tag$...$tag$` are strings; `$1` is a parameter.
11
+ * - Block comments nest.
12
+ * - `( ) , ; . [ ]` are punctuation; `=` is an operator, so `WITH (a = 1)`
13
+ * reads `=` as an `op` token.
14
+ * - A number never runs into a name: `42`, `3.5`, `.5`, `1e-3`, `0x1F`,
15
+ * `0o17`, `0b101`, `1_000`.
16
+ * - A multi-character operator does not end in `+` or `-` unless it holds
17
+ * one of `~ ! @ # % ^ & | \` ?`, so `fillfactor=-30` reads `=` then `-`.
18
+ */
19
+ import { tokenize as tokenizeWith, tokenizeText as tokenizeTextWith } from "../core/tokens.js";
20
+ export { isTrivia, SqlSyntaxError, untokenize } from "../core/tokens.js";
21
+ export const POSTGRES_LEXICAL = {
22
+ identQuotes: '"',
23
+ backslashEscapes: false,
24
+ punct: "(),;.[]",
25
+ // The operator characters (sql-syntax-lexical, "Operators"), and `:` for the `::` cast.
26
+ opChars: /[+\-*/<>=~!@#%^&|`?:]/,
27
+ prefixedStrings: true,
28
+ dollarQuotes: true,
29
+ nestedComments: true,
30
+ numbers: "sql",
31
+ unicodeIdentifiers: true,
32
+ operatorsEndWithoutSign: true,
33
+ };
34
+ /** Tokenize one string with Postgres's rules. `part` is the part index recorded on each token and on an error. */
35
+ export function tokenizeText(src, part) {
36
+ return tokenizeTextWith(src, part, POSTGRES_LEXICAL);
37
+ }
38
+ /** Tokenize a template's parts with Postgres's rules, with a `ref` token for each interpolation between them. */
39
+ export function tokenize(parts) {
40
+ return tokenizeWith(parts, POSTGRES_LEXICAL);
41
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * `@intentius/chant-lexicon-sql/postgres`: the Postgres dialect (#3289).
3
+ *
4
+ * Everything here is spec-true to Postgres, not a database-agnostic model:
5
+ * the statements are Postgres's own DDL, parsed at build time into entities,
6
+ * and the names fold and quote as Postgres folds and quotes them.
7
+ */
8
+ export { schema, table, index, view, sequence, type, domain, extension, func, procedure, aggregate, trigger, eventTrigger, collation, cast, policy, role, grant, literal, SqlLiteral, SqlTemplateError, PostgresObject, POSTGRES_ENTITY_TYPES, isPostgresObject, isColumnRef, quoteIdent, } from "./postgres/entities.js";
9
+ export { POSTGRES_PROVIDERS, COMMON_REFUSED, providerData, isPostgresProvider, providerAllowsExtension, isProviderOwned, refusedStatement, normalizeStatement, } from "./postgres/providers/index.js";
10
+ export { PostgresMigrationOp, } from "./postgres/migrate/op.js";
11
+ export { POSTGRES_RECEIPTS_TABLE } from "./postgres/migrate/receipts.js";
12
+ export * from "./composites/postgres.js";
13
+ // The build's Postgres objects as typed values, for a project's own
14
+ // `lint.policies` (#3870); also at `@intentius/chant-lexicon-sql/read`.
15
+ export { readPostgres, canonicalPostgresType, } from "./read/postgres.js";
@@ -0,0 +1,82 @@
1
+ /**
2
+ * The ClickHouse half of the public read API (`../read.ts`): the build's
3
+ * tables, columns, sort keys, skip indexes, engines and views as typed values,
4
+ * built from the serialized output. The lexicon's post-synth checks read the
5
+ * same values (`../lint/post-synth/clickhouse-helpers.ts`).
6
+ */
7
+ import { relationKey } from "../core/typed.js";
8
+ import { bareName, baseEngineName, isMergeTree, isNullableType, keyElements, typeFamily, unwrapType } from "../clickhouse/expressions.js";
9
+ import { dialectObjects } from "./objects.js";
10
+ function columnInfo(c, sortKey) {
11
+ const inner = /^LowCardinality\s*\(/i.test((c.type ?? "").trim());
12
+ const nullable = c.nullable === true || isNullableType(c.type) || (inner && isNullableType(unwrapLowCardinality(c.type)));
13
+ return {
14
+ ...c,
15
+ nullable,
16
+ lowCardinality: inner,
17
+ ...(c.type !== undefined ? { baseType: unwrapType(c.type), family: typeFamily(c.type) } : {}),
18
+ inSortKey: sortKey.has(c.name),
19
+ };
20
+ }
21
+ function unwrapLowCardinality(type) {
22
+ return type.trim().replace(/^LowCardinality\s*\(([\s\S]*)\)$/i, "$1").trim();
23
+ }
24
+ function build(objects) {
25
+ const tables = objects
26
+ .filter((o) => o.type === "ClickHouse::Table")
27
+ .map((o) => {
28
+ const t = o;
29
+ const sortKey = t.orderBy ? keyElements(t.orderBy) : [];
30
+ const bare = new Set(sortKey.map(bareName).filter((n) => n !== undefined));
31
+ const columns = (t.columns ?? []).map((c) => columnInfo(c, bare));
32
+ return {
33
+ ...t,
34
+ qualifiedName: relationKey(t),
35
+ columns,
36
+ ...(t.engine ? { engineFamily: baseEngineName(t.engine) } : {}),
37
+ mergeTree: isMergeTree(t.engine),
38
+ sortKey,
39
+ primaryKeyElements: t.primaryKey ? keyElements(t.primaryKey) : sortKey,
40
+ column: (name) => columns.find((c) => c.name === name),
41
+ };
42
+ });
43
+ const views = objects
44
+ .filter((o) => o.type === "ClickHouse::View" || o.type === "ClickHouse::MaterializedView")
45
+ .map((o) => {
46
+ const v = o;
47
+ const columns = (v.columns ?? []).map((c) => columnInfo(c, new Set()));
48
+ return {
49
+ ...v,
50
+ qualifiedName: relationKey(v),
51
+ materialized: v.type === "ClickHouse::MaterializedView",
52
+ columns,
53
+ outputs: columns.length > 0 ? columns.map((c) => c.name) : (v.lineage ?? []).map((e) => e.output),
54
+ };
55
+ });
56
+ return {
57
+ dialect: "clickhouse",
58
+ tables,
59
+ views,
60
+ objects,
61
+ table: (ref) => tables.find((t) => t.export === ref) ?? tables.find((t) => t.qualifiedName === ref) ?? tables.find((t) => t.name === ref),
62
+ };
63
+ }
64
+ const cache = new WeakMap();
65
+ /**
66
+ * What a ClickHouse build declares, read from a post-synth context's `docs`
67
+ * (a `lint.policies` check's `ctx`), or from the serialized output document
68
+ * itself. Empty when the build has no ClickHouse output. The result is cached
69
+ * per context; treat it as read-only.
70
+ */
71
+ export function readClickHouse(source) {
72
+ if ("objects" in source)
73
+ return build(source.dialect === "clickhouse" ? source.objects : []);
74
+ const key = source.docs;
75
+ const hit = key ? cache.get(key) : undefined;
76
+ if (hit)
77
+ return hit;
78
+ const read = build(dialectObjects(source, "clickhouse"));
79
+ if (key)
80
+ cache.set(key, read);
81
+ return read;
82
+ }
@@ -0,0 +1,44 @@
1
+ /**
2
+ * The sql build output as the serializer writes it (`../serializer.ts`): one
3
+ * JSON document per build with `dialect`, `applyOrder` and `objects`, each
4
+ * object its entity's props with the template source dropped, the DDL moved
5
+ * to the end, and every reference to another declared object written as that
6
+ * object's export name.
7
+ *
8
+ * This is the one place that finds those documents in a post-synth context.
9
+ * The public read API (`../read.ts`) and the lexicon's own post-synth checks
10
+ * (`../lint/post-synth/sql-helpers.ts`) both start here.
11
+ */
12
+ // ── Finding the documents ─────────────────────────────────────────────
13
+ /** True for a value shaped like the serializer's document. */
14
+ export function isSqlOutputDocument(value) {
15
+ const v = value;
16
+ return v !== null && typeof v === "object" && (v.dialect === "clickhouse" || v.dialect === "postgres") && Array.isArray(v.objects);
17
+ }
18
+ /** Every sql output document in the context, in output order. */
19
+ export function sqlDocuments(source) {
20
+ const out = [];
21
+ for (const doc of source.docs ?? []) {
22
+ if (doc.error || doc.lexicon !== "sql" || doc.format !== "json")
23
+ continue;
24
+ if (isSqlOutputDocument(doc.value))
25
+ out.push(doc.value);
26
+ }
27
+ return out;
28
+ }
29
+ /** Every serialized object of one dialect, across the context's sql documents. */
30
+ export function dialectObjects(source, dialect) {
31
+ const out = [];
32
+ for (const doc of sqlDocuments(source))
33
+ if (doc.dialect === dialect)
34
+ out.push(...doc.objects);
35
+ return out;
36
+ }
37
+ /** The Postgres major the build output records, else `fallback`. */
38
+ export function recordedPostgresMajor(source, fallback) {
39
+ for (const doc of sqlDocuments(source)) {
40
+ if (doc.dialect === "postgres" && typeof doc.postgresMajor === "number")
41
+ return doc.postgresMajor;
42
+ }
43
+ return fallback;
44
+ }
@@ -0,0 +1,104 @@
1
+ /**
2
+ * The Postgres half of the public read API (`../read.ts`): the build's
3
+ * tables, columns, keys, indexes and views as typed values, built from the
4
+ * serialized output. The lexicon's post-synth checks read the same values
5
+ * (`../lint/post-synth/postgres-helpers.ts`).
6
+ */
7
+ import { POSTGRES_MAJORS } from "../generated/postgres.js";
8
+ import { relationKey } from "../core/typed.js";
9
+ import { parseType, projectFromObjects, resolveType, typeLabel } from "../lint/post-synth/postgres-names.js";
10
+ import { dialectObjects, recordedPostgresMajor, } from "./objects.js";
11
+ const PINNED_MAJOR = POSTGRES_MAJORS[POSTGRES_MAJORS.length - 1];
12
+ /** A column type's canonical name, array-ness and serial-ness against a project. */
13
+ function typeOf(p, text) {
14
+ const t = parseType(text);
15
+ if (!t)
16
+ return { ...(text ? { typeName: text.trim().toLowerCase() } : {}), array: false, serial: false };
17
+ const r = resolveType(p, t, { serial: true });
18
+ const typeName = r.kind === "builtin" || r.kind === "absent" ? r.canonical : r.kind === "declared" ? String(r.object.sqlName ?? r.object.name) : typeLabel(t);
19
+ return { typeName, array: t.array, serial: r.kind === "builtin" && r.serial === true };
20
+ }
21
+ /**
22
+ * The canonical name of a Postgres type as written: `timestamptz` and
23
+ * `TIMESTAMP WITH TIME ZONE` are both `timestamp with time zone`, `int4` is
24
+ * `integer`. Compare a column's {@link PostgresColumnInfo.typeName} with it,
25
+ * so a rule does not depend on how the DDL spelled the type.
26
+ */
27
+ export function canonicalPostgresType(text) {
28
+ return typeOf(projectFromObjects([], PINNED_MAJOR), text).typeName;
29
+ }
30
+ function columnInfo(p, c, pk) {
31
+ const { typeName, array, serial } = typeOf(p, c.type);
32
+ const inPrimaryKey = pk.has(c.name);
33
+ const nullable = !(c.notNull === true || inPrimaryKey || c.generated?.kind === "identity" || serial);
34
+ return { ...c, nullable, ...(typeName !== undefined ? { typeName } : {}), array, inPrimaryKey };
35
+ }
36
+ function indexInfo(i) {
37
+ const columns = [];
38
+ for (const e of i.elements ?? []) {
39
+ if (!e.column)
40
+ break;
41
+ columns.push(e.column);
42
+ }
43
+ return { ...i, columns };
44
+ }
45
+ function build(objects, major) {
46
+ const p = projectFromObjects(objects, major);
47
+ const indexes = objects.filter((o) => o.type === "Postgres::Index").map((o) => indexInfo(o));
48
+ const tables = objects
49
+ .filter((o) => o.type === "Postgres::Table")
50
+ .map((o) => {
51
+ const t = o;
52
+ const pk = new Set(t.primaryKey?.columns ?? []);
53
+ const columns = (t.columns ?? []).map((c) => columnInfo(p, c, pk));
54
+ return {
55
+ ...t,
56
+ qualifiedName: relationKey(t),
57
+ columns,
58
+ indexes: indexes.filter((i) => i.table === t.export || i.tableName === t.sqlName),
59
+ column: (name) => columns.find((c) => c.name === name),
60
+ };
61
+ });
62
+ const views = objects
63
+ .filter((o) => o.type === "Postgres::View" || o.type === "Postgres::MaterializedView")
64
+ .map((o) => {
65
+ const v = o;
66
+ const declared = v.columns ?? [];
67
+ return {
68
+ ...v,
69
+ qualifiedName: relationKey(v),
70
+ materialized: v.type === "Postgres::MaterializedView",
71
+ outputs: declared.length > 0 ? [...declared] : (v.lineage ?? []).map((e) => e.output),
72
+ };
73
+ });
74
+ return {
75
+ dialect: "postgres",
76
+ major,
77
+ tables,
78
+ views,
79
+ indexes,
80
+ objects,
81
+ table: (ref) => tables.find((t) => t.export === ref) ?? tables.find((t) => t.qualifiedName === ref) ?? tables.find((t) => t.name === ref),
82
+ };
83
+ }
84
+ const cache = new WeakMap();
85
+ /**
86
+ * What a Postgres build declares, read from a post-synth context's `docs`
87
+ * (a `lint.policies` check's `ctx`), or from the serialized output document
88
+ * itself. Empty when the build has no Postgres output. The result is cached
89
+ * per context; treat it as read-only.
90
+ */
91
+ export function readPostgres(source) {
92
+ if ("objects" in source) {
93
+ const objects = source.dialect === "postgres" ? source.objects : [];
94
+ return build(objects, typeof source.postgresMajor === "number" ? source.postgresMajor : PINNED_MAJOR);
95
+ }
96
+ const key = source.docs;
97
+ const hit = key ? cache.get(key) : undefined;
98
+ if (hit)
99
+ return hit;
100
+ const read = build(dialectObjects(source, "postgres"), recordedPostgresMajor(source, PINNED_MAJOR));
101
+ if (key)
102
+ cache.set(key, read);
103
+ return read;
104
+ }
package/dist/read.js ADDED
@@ -0,0 +1,52 @@
1
+ /**
2
+ * `@intentius/chant-lexicon-sql/read`: a typed, read-only view of the SQL
3
+ * objects a build declares (#3870), for a project's own `lint.policies`.
4
+ *
5
+ * A policy's `check(ctx)` gets the build's parsed output in `ctx.docs`.
6
+ * {@link readPostgres} and {@link readClickHouse} turn the sql lexicon's part
7
+ * of it into tables with typed columns (SQL type, nullability, default,
8
+ * comment), keys, indexes and engines, and views with their outputs and
9
+ * column lineage. The lexicon's own post-synth checks read the same values,
10
+ * so a project rule sees exactly what `SQLPG101` or `SQLCH113` sees.
11
+ *
12
+ * ```ts
13
+ * import type { PostSynthCheck } from "@intentius/chant/lint/post-synth";
14
+ * import { canonicalPostgresType, readPostgres } from "@intentius/chant-lexicon-sql/read";
15
+ *
16
+ * const TIMESTAMPTZ = canonicalPostgresType("timestamptz");
17
+ *
18
+ * export const createdAt: PostSynthCheck = {
19
+ * id: "ORG-CREATED-AT",
20
+ * description: "every table has created_at timestamptz NOT NULL",
21
+ * check(ctx) {
22
+ * return readPostgres(ctx).tables
23
+ * .filter((t) => { const c = t.column("created_at"); return !c || c.typeName !== TIMESTAMPTZ || c.nullable; })
24
+ * .map((t) => ({ checkId: "ORG-CREATED-AT", severity: "error", entity: t.export,
25
+ * message: `${t.qualifiedName} needs created_at timestamptz NOT NULL` }));
26
+ * },
27
+ * };
28
+ * ```
29
+ *
30
+ * Every value keeps the fields the serializer writes (see the Serialization
31
+ * page) and adds the derived ones documented on each type. The reads also take
32
+ * the serialized document itself (`{ dialect, objects }`), for a tool that
33
+ * holds a recorded build rather than a post-synth context.
34
+ */
35
+ export { readPostgres, canonicalPostgresType } from "./read/postgres.js";
36
+ export { readClickHouse } from "./read/clickhouse.js";
37
+ export { sqlDocuments, isSqlOutputDocument } from "./read/objects.js";
38
+ import { readClickHouse } from "./read/clickhouse.js";
39
+ import { readPostgres } from "./read/postgres.js";
40
+ import { sqlDocuments } from "./read/objects.js";
41
+ /**
42
+ * The build's SQL objects in whichever dialect it declares: one build holds
43
+ * one dialect. Undefined when the build has no sql output.
44
+ */
45
+ export function readSql(source) {
46
+ const dialect = "objects" in source ? source.dialect : sqlDocuments(source)[0]?.dialect;
47
+ if (dialect === "postgres")
48
+ return readPostgres(source);
49
+ if (dialect === "clickhouse")
50
+ return readClickHouse(source);
51
+ return undefined;
52
+ }