@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,19 @@
1
+ import { createRequire } from "module";
2
+ import { moduleSourceUrl } from "@intentius/chant/module-source";
3
+ import { LexiconIndex } from "@intentius/chant/lsp/lexicon-providers";
4
+ const require = createRequire(moduleSourceUrl(import.meta.url));
5
+ let cached = null;
6
+ /** The generated entity registry, indexed once. Empty when generation has not run. */
7
+ export function registryIndex() {
8
+ if (cached)
9
+ return cached;
10
+ let data = {};
11
+ try {
12
+ data = require("../generated/lexicon-sql.json");
13
+ }
14
+ catch {
15
+ // No src/generated/ yet (a fresh clone before `npm run generate`): nothing to complete.
16
+ }
17
+ cached = new LexiconIndex(data);
18
+ return cached;
19
+ }
@@ -0,0 +1,143 @@
1
+ /**
2
+ * Finding where the cursor is inside a `database`, `table` or `view` template,
3
+ * and what the SQL before it says should come next. Shares the template finder
4
+ * with the lint rules, so the editor and `chant lint` agree on what a template
5
+ * is and which module's tags count.
6
+ */
7
+ import { ts } from "@intentius/chant/lint/typescript";
8
+ import { isTrivia, tokenize } from "../clickhouse/tokens.js";
9
+ import { parseCreate } from "../clickhouse/parser.js";
10
+ import { CLICKHOUSE_TEMPLATE_SOURCE, findTemplates } from "../lint/rules/templates.js";
11
+ import { locateIn } from "../core/find-templates.js";
12
+ export { offsetAt, wordAround } from "../core/find-templates.js";
13
+ /** The ClickHouse template the source offset `at` is inside, and where in it. */
14
+ export function locate(content, at, fileName = "file.ts") {
15
+ return locateIn(content, at, [CLICKHOUSE_TEMPLATE_SOURCE], fileName);
16
+ }
17
+ /** Significant tokens of the template up to `offset` in `part`; undefined when the text before it does not tokenize. */
18
+ export function tokensBefore(found, part, offset) {
19
+ try {
20
+ const parts = [...found.parts.slice(0, part), found.parts[part].slice(0, offset)];
21
+ return tokenize(parts).filter((t) => !isTrivia(t));
22
+ }
23
+ catch {
24
+ return undefined;
25
+ }
26
+ }
27
+ const upper = (t) => (t?.kind === "ident" ? t.text.toUpperCase() : "");
28
+ const isPunct = (t, text) => t?.kind === "punct" && t.text === text;
29
+ /** Words that end a SETTINGS list, or start something that is not one. */
30
+ const CLAUSE = new Set([
31
+ "ENGINE", "ORDER", "PARTITION", "PRIMARY", "SAMPLE", "TTL", "AS", "SELECT", "COMMENT", "FROM", "WHERE", "GROUP",
32
+ "HAVING", "LIMIT", "UNION", "TO", "POPULATE", "REFRESH", "WITH",
33
+ ]);
34
+ /** Words after which an expression is written. */
35
+ const EXPRESSION_AFTER = new Set(["DEFAULT", "MATERIALIZED", "ALIAS", "TTL", "BY", "CHECK", "ASSUME", "SELECT", "WHERE", "HAVING", "ON", "AND", "OR", "WHEN", "THEN", "ELSE"]);
36
+ const TYPE_WRAPPERS = new Set(["NULLABLE", "ARRAY", "LOWCARDINALITY", "MAP", "TUPLE", "NESTED"]);
37
+ const NOT_A_COLUMN = new Set(["INDEX", "PROJECTION", "CONSTRAINT", "PRIMARY"]);
38
+ export function expectAfter(sig, tag) {
39
+ const last = sig[sig.length - 1];
40
+ if (!last)
41
+ return undefined;
42
+ const prev = sig[sig.length - 2];
43
+ if (upper(last) === "ENGINE" || (isPunct(last, "=") && upper(prev) === "ENGINE"))
44
+ return "engine";
45
+ if (upper(last) === "TYPE")
46
+ return "index-type";
47
+ // The innermost open parenthesis, and the word before it.
48
+ const open = [];
49
+ sig.forEach((t, i) => {
50
+ if (isPunct(t, "("))
51
+ open.push(i);
52
+ else if (isPunct(t, ")"))
53
+ open.pop();
54
+ });
55
+ const opener = open[open.length - 1];
56
+ const fn = opener === undefined ? undefined : sig[opener - 1];
57
+ const afterOpenOrComma = isPunct(last, "(") || isPunct(last, ",");
58
+ if (afterOpenOrComma && opener !== undefined && upper(fn) === "CODEC")
59
+ return "codec";
60
+ if (isPunct(last, "(") && TYPE_WRAPPERS.has(upper(fn)))
61
+ return "type";
62
+ // A column's type: `(name |` in the column list, which is the first parenthesis of a table or view.
63
+ if (tag !== "database" && open.length === 1 && (last.kind === "ident" || last.kind === "qident")) {
64
+ const inColumnList = !sig.some((t) => upper(t) === "ENGINE" || upper(t) === "AS") && opener === firstParen(sig);
65
+ if (inColumnList && (isPunct(prev, "(") || isPunct(prev, ",")) && !NOT_A_COLUMN.has(upper(last)))
66
+ return "type";
67
+ }
68
+ // SETTINGS name = value, name = value: a name goes first, or after a comma.
69
+ if (tag !== "database") {
70
+ let depth = 0;
71
+ for (let i = sig.length - 1; i >= 0; i--) {
72
+ const t = sig[i];
73
+ if (isPunct(t, ")"))
74
+ depth++;
75
+ else if (isPunct(t, "(")) {
76
+ if (depth === 0)
77
+ break;
78
+ depth--;
79
+ }
80
+ else if (depth === 0) {
81
+ const w = upper(t);
82
+ if (w === "SETTINGS") {
83
+ if (i === sig.length - 1 || isPunct(last, ",")) {
84
+ return sig.slice(0, i).some((x) => upper(x) === "SELECT") ? "query-setting" : "merge-tree-setting";
85
+ }
86
+ break;
87
+ }
88
+ if (CLAUSE.has(w))
89
+ break;
90
+ }
91
+ }
92
+ }
93
+ if (EXPRESSION_AFTER.has(upper(last)))
94
+ return "function";
95
+ if (sig.some((t) => upper(t) === "SELECT") && (afterOpenOrComma || last.kind === "op"))
96
+ return "function";
97
+ return undefined;
98
+ }
99
+ function firstParen(sig) {
100
+ return sig.findIndex((t) => isPunct(t, "("));
101
+ }
102
+ function spanText(found, tokens, span, source) {
103
+ if (!span || span.to <= span.from)
104
+ return undefined;
105
+ return tokens
106
+ .slice(span.from, span.to)
107
+ .map((t) => (t.kind === "ref" ? `\${${found.expressions[t.part]?.getText(source) ?? "..."}}` : t.text))
108
+ .join("")
109
+ .trim();
110
+ }
111
+ /** Every `const x = table\`...\`` in the content that parses, by const name. */
112
+ export function declarations(content, fileName = "file.ts") {
113
+ const source = ts.createSourceFile(fileName, content, ts.ScriptTarget.Latest, true);
114
+ const out = [];
115
+ for (const found of findTemplates(source)) {
116
+ const decl = found.node.parent;
117
+ if (!decl || !ts.isVariableDeclaration(decl) || !ts.isIdentifier(decl.name))
118
+ continue;
119
+ try {
120
+ const tokens = tokenize(found.parts);
121
+ const node = parseCreate(tokens);
122
+ const columns = node.statement === "database" || node.statement === "function"
123
+ ? []
124
+ : (node.statement === "dictionary" ? node.attributes : node.columns).map((c) => ({
125
+ name: c.name || spanText(found, tokens, c.nameSpan, source) || "",
126
+ ...(spanText(found, tokens, c.type, source) ? { type: spanText(found, tokens, c.type, source) } : {}),
127
+ }));
128
+ const engine = node.statement === "dictionary" || node.statement === "function" ? undefined : node.engine?.name || spanText(found, tokens, node.engine?.nameSpan, source);
129
+ out.push({
130
+ name: decl.name.text,
131
+ tag: found.tag,
132
+ sqlName: spanText(found, tokens, node.name, source) ?? decl.name.text,
133
+ materialized: node.statement === "view" && node.materialized,
134
+ columns,
135
+ ...(engine ? { engine } : {}),
136
+ });
137
+ }
138
+ catch {
139
+ // A template that does not parse is SQLCH001's to report; it has no columns to offer.
140
+ }
141
+ }
142
+ return out;
143
+ }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sql",
3
- "version": "0.124.31",
3
+ "version": "0.124.33",
4
4
  "chantVersion": ">=0.1.0",
5
5
  "namespace": "SQL",
6
6
  "intrinsics": [],
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/mcp/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,uBAAuB,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAwO/F,6CAA6C;AAC7C,wBAAgB,WAAW,IAAI,mBAAmB,EAAE,CAQnD;AAsBD,iDAAiD;AACjD,wBAAgB,eAAe,IAAI,uBAAuB,EAAE,CA+B3D"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/mcp/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,uBAAuB,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AAyO/F,6CAA6C;AAC7C,wBAAgB,WAAW,IAAI,mBAAmB,EAAE,CAQnD;AAsBD,iDAAiD;AACjD,wBAAgB,eAAe,IAAI,uBAAuB,EAAE,CAgC3D"}
@@ -0,0 +1,293 @@
1
+ /**
2
+ * MCP contributions for the sql lexicon (chant #3210). Tools answer from the
3
+ * committed ClickHouse catalog and the tag parser, so an agent can look up an
4
+ * engine, a type or a setting, and check a statement, without a server.
5
+ *
6
+ * Tools register as `sql:<verb>` and resources as `chant://sql/<path>`.
7
+ */
8
+ import { createCatalogResource, createDiffTool } from "@intentius/chant/lexicon-plugin-helpers";
9
+ import { moduleSourceUrl } from "@intentius/chant/module-source";
10
+ import { sqlSerializer } from "../serializer.js";
11
+ import { catalogIndex } from "../lsp/catalog.js";
12
+ import { database, dictionary, func, grant, policy, quota, role, settingsProfile, table, user, view } from "../clickhouse/entities.js";
13
+ import { SqlSyntaxError } from "../clickhouse/tokens.js";
14
+ import { existsSync, readFileSync } from "fs";
15
+ import { diffSchemas } from "../clickhouse/plan/diff.js";
16
+ import { renderDiff } from "../clickhouse/plan/report.js";
17
+ import { rebuildOpSuggestions } from "../clickhouse/plan/rebuild-handoff.js";
18
+ import { CLASSIFIER_RULES } from "../clickhouse/plan/rules.js";
19
+ import { schemaFromBuildFile, schemaFromBuildOutput } from "../clickhouse/plan/schema.js";
20
+ import { asMajor, POSTGRES_KINDS, POSTGRES_TAGS, postgresLookup, postgresMcpResources, postgresParse, postgresSearch } from "./postgres.js";
21
+ import { diffPgSchemas } from "../postgres/plan/diff.js";
22
+ import { renderPgDiff } from "../postgres/plan/report.js";
23
+ import { PG_CLASSIFIER_RULES } from "../postgres/plan/rules.js";
24
+ import { pgSchemaFromBuildFile, pgSchemaFromBuildOutput } from "../postgres/plan/schema.js";
25
+ import { migrationOpSuggestions } from "../postgres/migrate/handoff.js";
26
+ import { CLICKHOUSE_IMAGE_DIGEST, CLICKHOUSE_VERSION, clickhouseImage } from "../spec/pin.js";
27
+ const KINDS = ["engine", "database-engine", "type", "codec", "index-type", "setting", "function", "format"];
28
+ const kindProp = {
29
+ type: "string",
30
+ enum: [...new Set([...KINDS, ...POSTGRES_KINDS])],
31
+ description: `Which part of the catalog. ClickHouse: ${KINDS.join(", ")}. Postgres: ${POSTGRES_KINDS.join(", ")}`,
32
+ };
33
+ const dialectProp = { type: "string", enum: ["clickhouse", "postgres"], description: "The dialect to answer for (default clickhouse)" };
34
+ const majorProp = { type: "number", description: "Postgres only: answer for this major (14 to 18; for classify-change, the server's major); omitted, every major, with since/until on names not in all" };
35
+ function asDialect(value) {
36
+ if (value === undefined || value === "clickhouse")
37
+ return "clickhouse";
38
+ if (value === "postgres")
39
+ return "postgres";
40
+ throw new Error("dialect must be clickhouse or postgres");
41
+ }
42
+ function rows(kind) {
43
+ const index = catalogIndex();
44
+ if (!index)
45
+ throw new Error("the ClickHouse catalog snapshot could not be read");
46
+ const { catalog } = index;
47
+ switch (kind) {
48
+ case "engine":
49
+ return catalog.tableEngines;
50
+ case "database-engine":
51
+ return catalog.databaseEngines;
52
+ case "type":
53
+ return catalog.typeFamilies;
54
+ case "codec":
55
+ return catalog.codecs;
56
+ case "index-type":
57
+ return catalog.skipIndexTypes;
58
+ case "setting":
59
+ return [
60
+ ...catalog.mergeTreeSettings.map((s) => ({ ...s, scope: "merge-tree" })),
61
+ ...catalog.querySettings.map((s) => ({ ...s, scope: "query" })),
62
+ ];
63
+ case "function":
64
+ return catalog.functions;
65
+ case "format":
66
+ return catalog.formats;
67
+ }
68
+ }
69
+ function asKind(value) {
70
+ if (!KINDS.includes(value))
71
+ throw new Error(`kind must be one of: ${KINDS.join(", ")}`);
72
+ return value;
73
+ }
74
+ const lookupTool = {
75
+ name: "lookup",
76
+ description: "Look up a catalog entry by name. ClickHouse (default): engine, type family, codec, skip index type, setting, function or format, from the pinned server (" +
77
+ CLICKHOUSE_VERSION +
78
+ "). Postgres (dialect postgres): type or alias, index or table access method, storage parameter, setting, function, key word or extension, from the pinned servers of majors 14 to 18, with since/until. Returns every catalog row with that name, or the closest names when there is none.",
79
+ inputSchema: { type: "object", properties: { dialect: dialectProp, kind: kindProp, name: { type: "string" }, major: majorProp }, required: ["kind", "name"] },
80
+ async handler(params) {
81
+ if (asDialect(params.dialect) === "postgres")
82
+ return postgresLookup(params);
83
+ const kind = asKind(params.kind);
84
+ const name = String(params.name ?? "");
85
+ const all = rows(kind);
86
+ const exact = all.filter((r) => r.name === name);
87
+ const found = exact.length ? exact : all.filter((r) => r.name.toLowerCase() === name.toLowerCase());
88
+ if (found.length)
89
+ return { kind, version: CLICKHOUSE_VERSION, matches: found };
90
+ const near = all.filter((r) => r.name.toLowerCase().includes(name.toLowerCase())).slice(0, 10).map((r) => r.name);
91
+ return { kind, version: CLICKHOUSE_VERSION, matches: [], closest: near };
92
+ },
93
+ };
94
+ const searchTool = {
95
+ name: "search",
96
+ description: "Search one part of a dialect's catalog by a name substring. Returns names with the first line of their description.",
97
+ inputSchema: {
98
+ type: "object",
99
+ properties: { dialect: dialectProp, kind: kindProp, query: { type: "string" }, major: majorProp, limit: { type: "number", description: "At most this many results (default 25)" } },
100
+ required: ["kind", "query"],
101
+ },
102
+ async handler(params) {
103
+ if (asDialect(params.dialect) === "postgres")
104
+ return postgresSearch(params);
105
+ const kind = asKind(params.kind);
106
+ const query = String(params.query ?? "").toLowerCase();
107
+ const limit = Math.max(1, Math.min(200, Number(params.limit ?? 25)));
108
+ const hits = rows(kind).filter((r) => r.name.toLowerCase().includes(query));
109
+ return {
110
+ kind,
111
+ total: hits.length,
112
+ results: hits.slice(0, limit).map((r) => ({ name: r.name, ...(typeof r.summary === "string" ? { summary: r.summary } : {}) })),
113
+ };
114
+ },
115
+ };
116
+ const parseTool = {
117
+ name: "parse-ddl",
118
+ description: "Parse one CREATE statement the way its tag does (dialect clickhouse, the default: table, view, database, dictionary, func, user, role, policy, quota, settingsProfile, grant; dialect postgres: schema, table, index, view, sequence, type, domain, extension), and return the entity it builds (columns, engine, keys, settings, and for a view its lineage). A statement that does not parse comes back as the error with its line and column, the same one SQLCH001 (ClickHouse) or SQLPG001 (Postgres) reports. The statement is plain DDL: there are no interpolations.",
119
+ inputSchema: {
120
+ type: "object",
121
+ properties: {
122
+ dialect: dialectProp,
123
+ tag: { type: "string", enum: [...new Set(["table", "view", "database", "dictionary", "func", "user", "role", "policy", "quota", "settingsProfile", "grant", ...POSTGRES_TAGS])], description: "The tag the statement belongs in (ClickHouse: table, view, database, dictionary, func, user, role, policy, quota, settingsProfile, grant; Postgres: " + POSTGRES_TAGS.join(", ") + ")" },
124
+ ddl: { type: "string", description: "The CREATE statement" },
125
+ },
126
+ required: ["tag", "ddl"],
127
+ },
128
+ async handler(params) {
129
+ const ddl = String(params.ddl ?? "");
130
+ const tag = String(params.tag);
131
+ if (asDialect(params.dialect) === "postgres")
132
+ return postgresParse(tag, ddl, position);
133
+ const build = tag === "table" ? table : tag === "view" ? view : tag === "database" ? database : tag === "dictionary" ? dictionary : tag === "func" ? func : tag === "user" ? user : tag === "role" ? role : tag === "policy" ? policy : tag === "quota" ? quota : tag === "settingsProfile" ? settingsProfile : tag === "grant" ? grant : undefined;
134
+ if (!build)
135
+ throw new Error("tag must be table, view, database, dictionary, func, user, role, policy, quota, settingsProfile or grant");
136
+ const strings = Object.assign([ddl], { raw: [ddl] });
137
+ try {
138
+ const entity = build(strings);
139
+ return { ok: true, entityType: entity.entityType, name: entity.sqlName, props: JSON.parse(JSON.stringify(entity.props)) };
140
+ }
141
+ catch (err) {
142
+ const message = err instanceof Error ? err.message : String(err);
143
+ const offset = err.offset;
144
+ const where = typeof offset === "number" ? position(ddl, offset) : undefined;
145
+ const syntax = err instanceof SqlSyntaxError || err.name === "SqlTemplateError";
146
+ return { ok: false, rule: syntax ? "SQLCH001" : undefined, message, ...(where ?? {}) };
147
+ }
148
+ },
149
+ };
150
+ const classifyTool = {
151
+ name: "classify-change",
152
+ description: "Classify the schema change between two revisions of a sql lexicon build, offline. Each side is a `chant build` output (a path to the file, or its JSON text); the dialect is the one the output names, or `dialect`. ClickHouse: every change with its class (create, drop, metadata, rewrite, rebuild), the SQLCH2xx rule and the ClickHouse restriction behind it with its documentation link, the rebuilds a plan must refuse in place with the ClickHouseRebuildOp declaration to run each one as, rename hints, and a rendered report. Postgres: every change with its class by the lock it takes (create, metadata, validate, concurrently, rewrite, expand, drop), the SQLPG2xx rule and its restriction with its Postgres documentation link, the `refused` changes that can only be made as expand and contract with the PostgresMigrationOp declaration to run each column rename or type change across kinds as (`migrationOps`), rename hints and a rendered report; `major` is the server's major (default the newest pinned).",
153
+ inputSchema: {
154
+ type: "object",
155
+ properties: {
156
+ before: { type: "string", description: "The earlier build output: a file path or the JSON text" },
157
+ after: { type: "string", description: "The later build output: a file path or the JSON text" },
158
+ dialect: dialectProp,
159
+ major: majorProp,
160
+ },
161
+ required: ["before", "after"],
162
+ },
163
+ async handler(params) {
164
+ if (buildDialect(params) === "postgres")
165
+ return classifyPostgres(params);
166
+ const side = (v) => {
167
+ const text = String(v ?? "");
168
+ return !text.trimStart().startsWith("{") && existsSync(text) ? schemaFromBuildFile(text) : schemaFromBuildOutput(text);
169
+ };
170
+ const after = side(params.after);
171
+ const plain = diffSchemas(side(params.before), after);
172
+ const rebuildOps = rebuildOpSuggestions(plain, new Map(after.map((o) => [o.key, o.canonical])), "<env>");
173
+ const diff = rebuildOps.length > 0 ? { ...plain, rebuildOps } : plain;
174
+ const classes = {};
175
+ for (const c of diff.changes)
176
+ classes[c.class] = (classes[c.class] ?? 0) + 1;
177
+ return {
178
+ summary: classes,
179
+ changes: diff.changes.map((c) => ({ ...c, restriction: CLASSIFIER_RULES[c.rule].restriction, cite: CLASSIFIER_RULES[c.rule].cite })),
180
+ rebuilds: diff.rebuilds,
181
+ rebuildOps,
182
+ hints: diff.hints,
183
+ report: renderDiff(diff),
184
+ };
185
+ },
186
+ };
187
+ /** The dialect a classify call is for: `dialect`, else the one either build output names, else ClickHouse. */
188
+ function buildDialect(params) {
189
+ if (params.dialect !== undefined)
190
+ return asDialect(params.dialect);
191
+ for (const v of [params.after, params.before]) {
192
+ const text = String(v ?? "");
193
+ try {
194
+ const json = text.trimStart().startsWith("{") ? text : existsSync(text) ? readFileSync(text, "utf-8") : "";
195
+ const d = JSON.parse(json).dialect;
196
+ if (d === "postgres")
197
+ return "postgres";
198
+ if (d === "clickhouse")
199
+ return "clickhouse";
200
+ }
201
+ catch {
202
+ // Not JSON we can read: the schema reader reports it.
203
+ }
204
+ }
205
+ return "clickhouse";
206
+ }
207
+ function classifyPostgres(params) {
208
+ const side = (v) => {
209
+ const text = String(v ?? "");
210
+ return !text.trimStart().startsWith("{") && existsSync(text) ? pgSchemaFromBuildFile(text) : pgSchemaFromBuildOutput(text);
211
+ };
212
+ const after = side(params.after);
213
+ const plain = diffPgSchemas(side(params.before), after, { major: asMajor(params.major) });
214
+ const migrationOps = migrationOpSuggestions(plain.refused, new Map(after.map((o) => [o.key, o.canonical])), "<env>");
215
+ const diff = migrationOps.length > 0 ? { ...plain, migrationOps } : plain;
216
+ const classes = {};
217
+ for (const c of diff.changes)
218
+ classes[c.class] = (classes[c.class] ?? 0) + 1;
219
+ return {
220
+ dialect: "postgres",
221
+ summary: classes,
222
+ changes: diff.changes.map((c) => ({ ...c, restriction: PG_CLASSIFIER_RULES[c.rule].restriction, cite: PG_CLASSIFIER_RULES[c.rule].cite })),
223
+ refused: diff.refused.map((c) => ({
224
+ object: c.object,
225
+ field: c.field,
226
+ rule: c.rule,
227
+ advice: "No in-place change keeps old readers working: run it as expand and contract (add the new, write both, backfill, move readers, drop the old), as a migration Op.",
228
+ })),
229
+ migrationOps,
230
+ hints: diff.hints,
231
+ report: renderPgDiff(diff),
232
+ };
233
+ }
234
+ function position(text, offset) {
235
+ const before = text.slice(0, offset).split("\n");
236
+ return { line: before.length, column: before[before.length - 1].length + 1 };
237
+ }
238
+ /** The tools the sql lexicon contributes. */
239
+ export function sqlMcpTools() {
240
+ return [
241
+ lookupTool,
242
+ searchTool,
243
+ parseTool,
244
+ classifyTool,
245
+ createDiffTool(sqlSerializer, "Compare current sql build output against the previous build", "sql"),
246
+ ];
247
+ }
248
+ const json = (value) => JSON.stringify(value, null, 2);
249
+ function catalogResource(uri, name, description, read) {
250
+ return {
251
+ uri,
252
+ name,
253
+ description,
254
+ mimeType: "application/json",
255
+ async handler() {
256
+ return json(read());
257
+ },
258
+ };
259
+ }
260
+ const need = () => {
261
+ const index = catalogIndex();
262
+ if (!index)
263
+ throw new Error("the ClickHouse catalog snapshot could not be read");
264
+ return index.catalog;
265
+ };
266
+ /** The resources the sql lexicon contributes. */
267
+ export function sqlMcpResources() {
268
+ return [
269
+ // `generated/` sits beside plugin.ts, which is where the helper looks. The
270
+ // source URL, so a compiled module names src/plugin.ts too (#3981).
271
+ createCatalogResource(new URL("../plugin.ts", moduleSourceUrl(import.meta.url)).href, "SQL Entity Catalog", "The entity kinds the sql lexicon declares (database, table, view, materialized view, dictionary, function, user, role, row policy, grant)", "lexicon-sql.json", "sql"),
272
+ ...postgresMcpResources(),
273
+ catalogResource("clickhouse-pin", "ClickHouse Pin", "The pinned ClickHouse server the catalog was read from", () => ({
274
+ version: CLICKHOUSE_VERSION,
275
+ image: clickhouseImage(),
276
+ digest: CLICKHOUSE_IMAGE_DIGEST,
277
+ })),
278
+ catalogResource("clickhouse-engines", "ClickHouse Engines", "Table and database engines with their usage line, summary and capabilities", () => ({
279
+ tableEngines: need().tableEngines,
280
+ databaseEngines: need().databaseEngines,
281
+ })),
282
+ catalogResource("clickhouse-types", "ClickHouse Types", "Column type families, with aliases and case sensitivity", () => need().typeFamilies),
283
+ catalogResource("clickhouse-codecs", "ClickHouse Codecs", "Column codecs and skip index types", () => ({
284
+ codecs: need().codecs,
285
+ skipIndexTypes: need().skipIndexTypes,
286
+ })),
287
+ catalogResource("clickhouse-settings", "ClickHouse Settings", "MergeTree and query settings with type, default and tier", () => ({
288
+ mergeTreeSettings: need().mergeTreeSettings,
289
+ querySettings: need().querySettings,
290
+ })),
291
+ catalogResource("clickhouse-functions", "ClickHouse Functions", "Function names, with which are aggregate and which are aliases", () => need().functions),
292
+ ];
293
+ }
@@ -0,0 +1,117 @@
1
+ /**
2
+ * The Postgres side of the sql MCP tools and resources (chant #3283). Rows
3
+ * come from the committed catalogs of the pinned servers, one per major; a
4
+ * name present in only some majors carries `since` and `until`, as the
5
+ * generated types' `@since` / `@until` do.
6
+ */
7
+ import { POSTGRES_LATEST_MAJOR, POSTGRES_MAJORS, POSTGRES_PINS, postgresImage } from "../spec/postgres-pin.js";
8
+ import { section } from "../lsp/postgres-catalog.js";
9
+ import * as pg from "../postgres/entities.js";
10
+ import { SqlSyntaxError } from "../postgres/tokens.js";
11
+ export const POSTGRES_KINDS = ["type", "index-method", "table-method", "storage-parameter", "setting", "function", "keyword", "extension"];
12
+ const SECTION = {
13
+ type: "types",
14
+ "index-method": "accessMethods",
15
+ "table-method": "accessMethods",
16
+ "storage-parameter": "storageParameters",
17
+ setting: "settings",
18
+ function: "functions",
19
+ keyword: "keywords",
20
+ extension: "extensions",
21
+ };
22
+ export function asPostgresKind(value) {
23
+ if (!POSTGRES_KINDS.includes(value))
24
+ throw new Error(`kind must be one of: ${POSTGRES_KINDS.join(", ")}`);
25
+ return value;
26
+ }
27
+ /** The major a tool call is about: `major` when given, else every major (undefined). */
28
+ export function asMajor(value) {
29
+ if (value === undefined || value === null || value === "")
30
+ return undefined;
31
+ const n = Number(value);
32
+ if (!POSTGRES_MAJORS.includes(n))
33
+ throw new Error(`major must be one of: ${POSTGRES_MAJORS.join(", ")}`);
34
+ return n;
35
+ }
36
+ /** The rows of a kind, each with its range; only those at `major` when one is given. */
37
+ export function postgresRows(kind, major) {
38
+ const s = section(SECTION[kind]);
39
+ if (!s)
40
+ throw new Error("the Postgres catalog snapshots could not be read");
41
+ const wantType = kind === "index-method" ? "index" : kind === "table-method" ? "table" : undefined;
42
+ const out = [];
43
+ for (const e of s.values()) {
44
+ if (major !== undefined && !e.majors.includes(major))
45
+ continue;
46
+ if (wantType && e.row.type !== wantType)
47
+ continue;
48
+ const summary = typeof e.row.description === "string" ? e.row.description : e.detail;
49
+ out.push({ ...e.row, name: e.name, ...(summary ? { summary } : {}), ...e.range });
50
+ }
51
+ return out;
52
+ }
53
+ export function postgresLookup(params) {
54
+ const kind = asPostgresKind(params.kind);
55
+ const major = asMajor(params.major);
56
+ const name = String(params.name ?? "");
57
+ const all = postgresRows(kind, major);
58
+ const exact = all.filter((r) => r.name === name);
59
+ const found = exact.length ? exact : all.filter((r) => r.name.toLowerCase() === name.toLowerCase());
60
+ const base = { dialect: "postgres", kind, majors: major !== undefined ? [major] : POSTGRES_MAJORS };
61
+ if (found.length)
62
+ return { ...base, matches: found };
63
+ const near = all.filter((r) => r.name.toLowerCase().includes(name.toLowerCase())).slice(0, 10).map((r) => r.name);
64
+ return { ...base, matches: [], closest: near };
65
+ }
66
+ export function postgresSearch(params) {
67
+ const kind = asPostgresKind(params.kind);
68
+ const query = String(params.query ?? "").toLowerCase();
69
+ const limit = Math.max(1, Math.min(200, Number(params.limit ?? 25)));
70
+ const hits = postgresRows(kind, asMajor(params.major)).filter((r) => r.name.toLowerCase().includes(query));
71
+ return {
72
+ dialect: "postgres",
73
+ kind,
74
+ total: hits.length,
75
+ results: hits.slice(0, limit).map((r) => ({ name: r.name, ...(r.summary ? { summary: r.summary } : {}), ...(r.since ? { since: r.since } : {}), ...(r.until ? { until: r.until } : {}) })),
76
+ };
77
+ }
78
+ const TAGS = { schema: pg.schema, table: pg.table, index: pg.index, view: pg.view, sequence: pg.sequence, type: pg.type, domain: pg.domain, extension: pg.extension, func: pg.func, procedure: pg.procedure, aggregate: pg.aggregate, trigger: pg.trigger, eventTrigger: pg.eventTrigger, collation: pg.collation, cast: pg.cast, policy: pg.policy, role: pg.role, grant: pg.grant };
79
+ export const POSTGRES_TAGS = Object.keys(TAGS);
80
+ /** Parse one statement with the Postgres tag; an error comes back as SQLPG001 with its line and column. */
81
+ export function postgresParse(tag, ddl, position) {
82
+ const build = TAGS[tag];
83
+ if (!build)
84
+ throw new Error(`tag must be one of: ${POSTGRES_TAGS.join(", ")}`);
85
+ const strings = Object.assign([ddl], { raw: [ddl] });
86
+ try {
87
+ const entity = build(strings);
88
+ return { ok: true, dialect: "postgres", entityType: entity.entityType, name: entity.sqlName, props: JSON.parse(JSON.stringify(entity.props)) };
89
+ }
90
+ catch (err) {
91
+ const message = err instanceof Error ? err.message : String(err);
92
+ const offset = err.offset;
93
+ const where = typeof offset === "number" ? position(ddl, offset) : undefined;
94
+ const syntax = err instanceof SqlSyntaxError || err.name === "SqlTemplateError";
95
+ return { ok: false, dialect: "postgres", rule: syntax ? "SQLPG001" : undefined, message, ...(where ?? {}) };
96
+ }
97
+ }
98
+ const json = (value) => JSON.stringify(value, null, 2);
99
+ function resource(uri, name, description, read) {
100
+ return { uri, name, description, mimeType: "application/json", async handler() { return json(read()); } };
101
+ }
102
+ /** The Postgres resources: every supported major's names in one list, each with `since` / `until` when not in all. */
103
+ export function postgresMcpResources() {
104
+ const all = (...kinds) => Object.fromEntries(kinds.map((k) => [k, postgresRows(k)]));
105
+ return [
106
+ resource("postgres-pin", "Postgres Pins", "The pinned server for each supported major the catalogs were read from", () => ({
107
+ latest: POSTGRES_LATEST_MAJOR,
108
+ pins: POSTGRES_PINS.map((p) => ({ ...p, image: postgresImage(p.major) })),
109
+ })),
110
+ resource("postgres-types", "Postgres Types", "Column types and their aliases, with since/until majors", () => postgresRows("type")),
111
+ resource("postgres-access-methods", "Postgres Access Methods", "Index access methods (btree, gin...) and table access methods", () => all("index-method", "table-method")),
112
+ resource("postgres-storage-parameters", "Postgres Storage Parameters", "WITH (...) parameters, the relation kinds that accept each, and their types", () => postgresRows("storage-parameter")),
113
+ resource("postgres-functions", "Postgres Functions", "Built-in function names with since/until majors", () => postgresRows("function")),
114
+ resource("postgres-keywords", "Postgres Keywords", "Key words and their categories", () => postgresRows("keyword")),
115
+ resource("postgres-settings", "Postgres Settings", "Server settings with type, default and range", () => postgresRows("setting")),
116
+ ];
117
+ }