@intentius/chant-lexicon-sql 0.124.30 → 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,73 @@
1
+ /**
2
+ * Managed-provider knowledge for the Postgres dialect (#3282): which roles
3
+ * and schemas a provider owns, which extensions it lets a customer create,
4
+ * and which statements it refuses. See ./types.ts for what a list means and
5
+ * how stale one can be.
6
+ */
7
+ import { aurora } from "./aurora.js";
8
+ import { azure } from "./azure.js";
9
+ import { cloudSql } from "./cloud-sql.js";
10
+ import { neon } from "./neon.js";
11
+ import { rds } from "./rds.js";
12
+ import { supabase } from "./supabase.js";
13
+ import { POSTGRES_PROVIDERS } from "./types.js";
14
+ export { POSTGRES_PROVIDERS, COMMON_REFUSED } from "./types.js";
15
+ const DATA = {
16
+ rds,
17
+ aurora,
18
+ "cloud-sql": cloudSql,
19
+ azure,
20
+ neon,
21
+ supabase,
22
+ };
23
+ /** The data for one provider. */
24
+ export function providerData(provider) {
25
+ return DATA[provider];
26
+ }
27
+ export const isPostgresProvider = (v) => typeof v === "string" && POSTGRES_PROVIDERS.includes(v);
28
+ /** Role and schema names fold to lower case unless quoted; the lists are lower case. */
29
+ const fold = (name) => name.toLowerCase();
30
+ /**
31
+ * Whether the provider lets a customer create the extension. `undefined` when
32
+ * the provider's list is partial and does not name it: the answer is unknown,
33
+ * not no.
34
+ */
35
+ export function providerAllowsExtension(provider, name) {
36
+ const data = DATA[provider];
37
+ if (data.allowedExtensions.includes(fold(name)))
38
+ return true;
39
+ return data.extensionListComplete ? false : undefined;
40
+ }
41
+ /**
42
+ * Whether the provider owns a live object, so import and describe can read it
43
+ * as foreign (not the project's to declare or change). A role or schema the
44
+ * provider created, an extension the provider installs, or a `pg_` built-in
45
+ * role. Names are compared case-folded.
46
+ */
47
+ export function isProviderOwned(provider, object) {
48
+ const data = DATA[provider];
49
+ const name = fold(object.name);
50
+ switch (object.kind) {
51
+ case "role":
52
+ return data.reservedRoles.includes(name) || name.startsWith("pg_");
53
+ case "schema":
54
+ return data.reservedSchemas.includes(name);
55
+ case "extension":
56
+ return data.providerExtensions.includes(name);
57
+ }
58
+ }
59
+ /** Reduce a statement to what the refused-statement patterns match: comments and strings removed, upper case, whitespace collapsed. */
60
+ export function normalizeStatement(sql) {
61
+ return sql
62
+ .replace(/\/\*[\s\S]*?\*\//g, " ")
63
+ .replace(/--[^\n]*/g, " ")
64
+ .replace(/'(?:[^']|'')*'/g, "''")
65
+ .replace(/\s+/g, " ")
66
+ .trim()
67
+ .toUpperCase();
68
+ }
69
+ /** The refused-statement entry a statement matches on the provider, if any. */
70
+ export function refusedStatement(provider, sql) {
71
+ const text = normalizeStatement(sql);
72
+ return DATA[provider].refusedStatements.find((r) => r.pattern.test(text));
73
+ }
@@ -0,0 +1,44 @@
1
+ import { words, COMMON_REFUSED } from "./types.js";
2
+ /**
3
+ * Neon. The extension list is the "Postgres extensions" table, the entries
4
+ * with a PG18 version (entries marked `-` for PG18, such as plv8, rum and
5
+ * pg_search, are left out), read 2026-10-03. Table names were mapped to
6
+ * `CREATE EXTENSION` names where the page says so: pgvector is `vector`,
7
+ * pg_roaringbitmap is `roaringbitmap`. wal2json is a decoder plugin the page
8
+ * says needs no CREATE EXTENSION, so it is not listed. Reserved roles are
9
+ * the "Reserved role names" list plus neon_service, which the roles page
10
+ * describes as internal.
11
+ */
12
+ export const neon = {
13
+ provider: "neon",
14
+ label: "Neon",
15
+ sources: [
16
+ { url: "https://neon.com/docs/extensions/pg-extensions", readOn: "2026-10-03", covers: "allowedExtensions (PG18 column)" },
17
+ { url: "https://neon.com/docs/manage/roles", readOn: "2026-10-03", covers: "reservedRoles, neon_superuser, internal roles" },
18
+ { url: "https://neon.com/docs/reference/compatibility", readOn: "2026-10-03", covers: "no superuser, no tablespaces" },
19
+ ],
20
+ reservedRoles: ["neon_superuser", "cloud_admin", "zenith_admin", "neon_service"],
21
+ reservedSchemas: [],
22
+ allowedExtensions: words(`
23
+ address_standardizer address_standardizer_data_us anon autoinc bloom btree_gin btree_gist citext cube dblink
24
+ dict_int earthdistance fuzzystrmatch h3 h3_postgis hll hstore hypopg insert_username intagg intarray ip4r isn
25
+ lakebase_text lakebase_tokenizer lakebase_vector lo ltree moddatetime neon neon_utils pg_cron pg_graphql
26
+ pg_hashids pg_hint_plan pg_ivm pg_jsonschema pg_partman pg_prewarm pg_repack pg_session_jwt pg_stat_statements
27
+ pg_tiktoken pg_trgm pg_uuidv7 pgcrypto pgjwt pgrag pgrouting pgrowlocks pgstattuple pgtap pgx_ulid plpgsql
28
+ plpgsql_check postgis postgis_raster postgis_sfcgal postgis_tiger_geocoder postgis_topology postgres_fdw prefix
29
+ rdkit refint roaringbitmap seg semver tablefunc tcn timescaledb tsm_system_rows tsm_system_time unaccent
30
+ uuid-ossp vector xml2
31
+ `),
32
+ extensionListComplete: true,
33
+ providerExtensions: ["neon", "neon_utils", "pg_session_jwt", "lakebase_text", "lakebase_tokenizer", "lakebase_vector"],
34
+ refusedStatements: [
35
+ ...COMMON_REFUSED,
36
+ { id: "create-tablespace", pattern: /^CREATE TABLESPACE\b/, reason: "Neon does not support tablespaces" },
37
+ { id: "alter-neon-superuser", pattern: /^(ALTER|DROP) (ROLE|USER) "?NEON_SUPERUSER"?\b/, reason: "neon_superuser is not intended to be modified" },
38
+ ],
39
+ toCheck: [
40
+ "reservedSchemas: none read from a page: https://neon.com/docs/manage/roles",
41
+ "pg_repack needs a paid plan and Neon Support to enable, pg_ivm is not available for new installs: https://neon.com/docs/extensions/pg-extensions",
42
+ "older majors' columns",
43
+ ],
44
+ };
@@ -0,0 +1,47 @@
1
+ import { words, COMMON_REFUSED } from "./types.js";
2
+ /**
3
+ * Amazon RDS for PostgreSQL. The extension list is the table for major 18 on
4
+ * the "Extensions supported for RDS for PostgreSQL" page, read 2026-10-03;
5
+ * the other majors differ at the edges and are not modelled (the list is the
6
+ * newest GA major's). Package names on that page were mapped to extension
7
+ * names: pgvector is `vector`, h3-pg is `h3` and `h3_postgis`.
8
+ */
9
+ export const rds = {
10
+ provider: "rds",
11
+ label: "Amazon RDS for PostgreSQL",
12
+ sources: [
13
+ {
14
+ url: "https://docs.aws.amazon.com/AmazonRDS/latest/PostgreSQLReleaseNotes/postgresql-extensions.html",
15
+ readOn: "2026-10-03",
16
+ covers: "allowedExtensions (major 18 table)",
17
+ },
18
+ {
19
+ url: "https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Appendix.PostgreSQL.CommonDBATasks.Roles.html",
20
+ readOn: "2026-10-03",
21
+ covers: "the master user is a member of rds_superuser, not a superuser",
22
+ },
23
+ ],
24
+ reservedRoles: ["rdsadmin", "rds_superuser", "rds_replication", "rds_password", "rds_iam", "rds_ad", "rdsrepladmin"],
25
+ reservedSchemas: [],
26
+ allowedExtensions: words(`
27
+ address_standardizer address_standardizer_data_us amcheck auto_explain aws_commons aws_lambda aws_s3 bloom
28
+ btree_gin btree_gist citext cube dblink dict_int dict_xsyn earthdistance fuzzystrmatch h3 h3_postgis hll hstore
29
+ hstore_plperl hypopg intagg intarray ip4r isn lo log_fdw ltree mysql_fdw oracle_fdw orafce pageinspect pg_bigm
30
+ pg_buffercache pg_cron pg_freespacemap pg_hint_plan pg_logicalinspect pg_partman pg_prewarm pg_proctab pg_repack
31
+ pg_similarity pg_stat_monitor pg_stat_statements pg_tle pg_transport pg_trgm pg_visibility pg_walinspect pgaudit
32
+ pgcrypto pglogical pgrouting pgrowlocks pgstattuple pgtap plperl plpgsql plprofiler pltcl plv8 postgis
33
+ postgis_raster postgis_tiger_geocoder postgis_topology postgres_fdw prefix rdkit roaringbitmap seg sslinfo
34
+ tablefunc tcn tds_fdw tsm_system_rows tsm_system_time unaccent uuid-ossp vector wal2json
35
+ `),
36
+ extensionListComplete: true,
37
+ providerExtensions: ["aws_commons", "aws_lambda", "aws_s3", "rds_tools", "log_fdw", "pg_transport"],
38
+ refusedStatements: [
39
+ ...COMMON_REFUSED,
40
+ { id: "create-tablespace-location", pattern: /^CREATE TABLESPACE\b/, reason: "RDS refuses tablespaces on a customer-chosen LOCATION" },
41
+ ],
42
+ toCheck: [
43
+ "reservedRoles beyond rds_superuser were not read from a page: https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Appendix.PostgreSQL.CommonDBATasks.Roles.html",
44
+ "refusedStatements beyond the common three are from the documented master-user model, not a statement list",
45
+ "per-major differences in the extension list",
46
+ ],
47
+ };
@@ -0,0 +1,45 @@
1
+ import { words } from "./types.js";
2
+ /**
3
+ * Supabase. The extension names are the ones the extensions overview's
4
+ * sidebar documents (plv8, pgjwt, timescaledb and pgsodium are marked
5
+ * deprecated there and left out), read 2026-10-03. The overview's full list
6
+ * is rendered by script and could not be read, so the list is partial:
7
+ * `extensionListComplete` is false and SQLPG004 does not report a name
8
+ * outside it. Roles are the "Supabase roles" section of the roles page. The
9
+ * unsupported operations are the two the roles-and-superuser page names.
10
+ */
11
+ export const supabase = {
12
+ provider: "supabase",
13
+ label: "Supabase",
14
+ sources: [
15
+ { url: "https://supabase.com/docs/guides/database/extensions", readOn: "2026-10-03", covers: "allowedExtensions (partial: the documented extension pages)" },
16
+ { url: "https://supabase.com/docs/guides/database/postgres/roles", readOn: "2026-10-03", covers: "reservedRoles; auth, storage and etl schemas" },
17
+ {
18
+ url: "https://raw.githubusercontent.com/supabase/supabase/master/apps/docs/content/guides/database/postgres/roles-superuser.mdx",
19
+ readOn: "2026-10-03",
20
+ covers: "superuser-only statements (the source of https://supabase.com/docs/guides/database/postgres/roles-superuser)",
21
+ },
22
+ ],
23
+ reservedRoles: [
24
+ "postgres", "anon", "authenticator", "authenticated", "service_role", "supabase_auth_admin",
25
+ "supabase_storage_admin", "supabase_etl_admin", "dashboard_user", "supabase_admin",
26
+ ],
27
+ reservedSchemas: ["auth", "storage", "etl"],
28
+ allowedExtensions: words(`
29
+ hypopg http index_advisor pgaudit pgroonga pgrouting pg_cron pg_graphql pg_hashids pg_jsonschema pg_net
30
+ pg_partman pg_plan_filter postgres_fdw vector pg_stat_statements pg_repack postgis pgmq pgtap plpgsql_check
31
+ uuid-ossp rum
32
+ `),
33
+ extensionListComplete: false,
34
+ providerExtensions: ["pg_graphql", "pg_net", "pgmq", "index_advisor"],
35
+ refusedStatements: [
36
+ { id: "copy-program", pattern: /^COPY\b.*\b(FROM|TO) PROGRAM\b/, reason: "COPY ... FROM PROGRAM needs a superuser, which Supabase does not give out" },
37
+ { id: "superuser-role", pattern: /^(CREATE|ALTER) (ROLE|USER)\b.*\bSUPERUSER\b/, reason: "the SUPERUSER attribute cannot be granted on Supabase" },
38
+ ],
39
+ toCheck: [
40
+ "the full extension list (page body is script-rendered): https://supabase.com/docs/guides/database/extensions",
41
+ "reservedSchemas beyond auth, storage and etl (extensions, realtime, graphql, graphql_public, vault, net, supabase_functions, pgbouncer were not read from a page): https://supabase.com/docs/guides/database/postgres/roles",
42
+ "refused statements beyond the two the roles-and-superuser page lists (ALTER SYSTEM was not stated): https://supabase.com/docs/guides/database/postgres/roles-superuser",
43
+ "providerExtensions are inferred from the extension pages' names, not from a statement of ownership",
44
+ ],
45
+ };
@@ -0,0 +1,21 @@
1
+ /**
2
+ * What the Postgres dialect knows about a managed provider (#3282): the
3
+ * roles and schemas the provider owns, the extensions it lets a customer
4
+ * create, and the statements it refuses because they need a superuser.
5
+ *
6
+ * The lists are data, one file per provider, each citing the page it was read
7
+ * from and the date it was read. A provider changes its lists without
8
+ * announcing it, so a list is a snapshot, not a contract: an extension a
9
+ * provider added since is reported by SQLPG004 as not allowed until the list
10
+ * is refreshed, and `toCheck` names what a file did not verify.
11
+ */
12
+ /** The providers the dialect has data for. */
13
+ export const POSTGRES_PROVIDERS = ["rds", "aurora", "cloud-sql", "azure", "neon", "supabase"];
14
+ /** Split a whitespace-separated list, so a long extension list stays readable in source. */
15
+ export const words = (s) => s.split(/\s+/).filter(Boolean);
16
+ /** Statements that need the superuser every managed provider withholds. */
17
+ export const COMMON_REFUSED = [
18
+ { id: "alter-system", pattern: /^ALTER SYSTEM\b/, reason: "ALTER SYSTEM writes postgresql.auto.conf, which a managed service owns; use the provider's parameter settings" },
19
+ { id: "copy-program", pattern: /^COPY\b.*\b(FROM|TO) PROGRAM\b/, reason: "COPY ... PROGRAM runs a command on the host, which the provider does not give out" },
20
+ { id: "superuser-role", pattern: /^(CREATE|ALTER) (ROLE|USER)\b.*\bSUPERUSER\b/, reason: "the SUPERUSER attribute cannot be granted on a managed service" },
21
+ ];
@@ -0,0 +1,107 @@
1
+ /**
2
+ * What a Postgres column's value is in TypeScript, for `RowOf` (#3751): the
3
+ * value node-postgres (`pg`, the driver the lexicon itself uses) hands back
4
+ * with its default type parsers. `bigint` and `numeric` are strings, since a
5
+ * JavaScript number cannot hold every value; `integer`, `smallint`, `real`
6
+ * and `double precision` are numbers; dates and timestamps are `Date`s;
7
+ * `json` and `jsonb` are parsed, so their shape is the application's
8
+ * (`unknown`); everything the driver does not parse is its text form.
9
+ *
10
+ * The table names every built-in type of every supported major's catalog
11
+ * (`COLUMN_TYPES`), and a test fails on one it does not, so a type a new
12
+ * catalog adds is a decision rather than a silent `unknown`.
13
+ */
14
+ const NUMBER = "number";
15
+ const STRING = "string";
16
+ const DATE = "Date";
17
+ /** The TypeScript type of each built-in type's value, by its `format_type()` name. */
18
+ export const POSTGRES_ROW_TYPES = {
19
+ // Numbers the driver parses; the 64-bit and arbitrary-precision ones stay text.
20
+ smallint: NUMBER,
21
+ integer: NUMBER,
22
+ real: NUMBER,
23
+ "double precision": NUMBER,
24
+ oid: NUMBER,
25
+ bigint: STRING,
26
+ numeric: STRING,
27
+ money: STRING,
28
+ regclass: STRING,
29
+ regcollation: STRING,
30
+ regconfig: STRING,
31
+ regdictionary: STRING,
32
+ regnamespace: STRING,
33
+ regoper: STRING,
34
+ regoperator: STRING,
35
+ regproc: STRING,
36
+ regprocedure: STRING,
37
+ regrole: STRING,
38
+ regtype: STRING,
39
+ boolean: "boolean",
40
+ // Strings.
41
+ text: STRING,
42
+ "character varying": STRING,
43
+ character: STRING,
44
+ name: STRING,
45
+ '"char"': STRING,
46
+ uuid: STRING,
47
+ xml: STRING,
48
+ bit: STRING,
49
+ "bit varying": STRING,
50
+ cidr: STRING,
51
+ inet: STRING,
52
+ macaddr: STRING,
53
+ macaddr8: STRING,
54
+ tsvector: STRING,
55
+ tsquery: STRING,
56
+ jsonpath: STRING,
57
+ pg_lsn: STRING,
58
+ pg_snapshot: STRING,
59
+ txid_snapshot: STRING,
60
+ refcursor: STRING,
61
+ aclitem: STRING,
62
+ cid: STRING,
63
+ tid: STRING,
64
+ xid: STRING,
65
+ xid8: STRING,
66
+ int2vector: STRING,
67
+ oidvector: STRING,
68
+ gtsvector: STRING,
69
+ pg_brin_bloom_summary: STRING,
70
+ pg_brin_minmax_multi_summary: STRING,
71
+ pg_dependencies: STRING,
72
+ pg_mcv_list: STRING,
73
+ pg_ndistinct: STRING,
74
+ pg_node_tree: STRING,
75
+ // Dates and times: the driver parses dates and timestamps, not times of day.
76
+ date: DATE,
77
+ "timestamp without time zone": DATE,
78
+ "timestamp with time zone": DATE,
79
+ "time without time zone": STRING,
80
+ "time with time zone": STRING,
81
+ interval: "{ years?: number; months?: number; days?: number; hours?: number; minutes?: number; seconds?: number; milliseconds?: number }",
82
+ // Ranges and multiranges arrive as their text form.
83
+ int4range: STRING,
84
+ int8range: STRING,
85
+ numrange: STRING,
86
+ tsrange: STRING,
87
+ tstzrange: STRING,
88
+ daterange: STRING,
89
+ int4multirange: STRING,
90
+ int8multirange: STRING,
91
+ nummultirange: STRING,
92
+ tsmultirange: STRING,
93
+ tstzmultirange: STRING,
94
+ datemultirange: STRING,
95
+ // Geometry: the driver parses a point and a circle.
96
+ point: "{ x: number; y: number }",
97
+ circle: "{ x: number; y: number; radius: number }",
98
+ line: STRING,
99
+ lseg: STRING,
100
+ box: STRING,
101
+ path: STRING,
102
+ polygon: STRING,
103
+ // Parsed, so the application's own shape.
104
+ json: "unknown",
105
+ jsonb: "unknown",
106
+ bytea: "Uint8Array",
107
+ };
@@ -0,0 +1,34 @@
1
+ /**
2
+ * A fake Postgres client for unit tests: answers the catalog reader's queries
3
+ * (`../live/catalog.ts`) from rows the test gives, by which catalog each query
4
+ * reads. Anything else answers no rows.
5
+ */
6
+ export function fakeClient(catalog, log = []) {
7
+ let oid = 16384;
8
+ const tables = (catalog.tables ?? []).map((t) => ({ ...t, oid: String(oid++) }));
9
+ return {
10
+ async query(sql) {
11
+ log.push(sql);
12
+ const rows = (r) => r;
13
+ // A probe for one undeclarable kind (`../live/undeclarable.ts`), which its comment names.
14
+ const probe = /^\/\* chant undeclarable: (.+?) \*\//.exec(sql);
15
+ if (probe)
16
+ return rows((catalog.undeclarable ?? []).filter((u) => u.kind === probe[1]).map((u) => ({ schema: u.schema ?? null, name: u.name, owner: null })));
17
+ if (sql.includes("FROM pg_catalog.pg_namespace n WHERE"))
18
+ return rows((catalog.schemas ?? []).map((s, i) => ({ oid: String(100 + i), name: s.name, comment: s.comment ?? null })));
19
+ if (sql.includes("c.relkind IN ('r', 'p')")) {
20
+ return rows(tables.map((t) => ({ oid: t.oid, schema: t.schema, name: t.name, kind: "r", persistence: "p", ispartition: false, typed: false, partkey: null, bound: null, parents: [], reloptions: null, am: "heap", tablespace: null, comment: t.comment ?? null })));
21
+ }
22
+ if (sql.includes("FROM pg_catalog.pg_attribute a JOIN")) {
23
+ return rows(tables.flatMap((t) => (t.columns ?? []).map((c, i) => ({ rel: t.oid, num: i + 1, name: c.name, type: c.type, notnull: c.notnull ?? false, identity: "", generated: "", islocal: true, dflt: c.dflt ?? null, collation: null, comment: null, compression: "", storage: "x", typstorage: "x" }))));
24
+ }
25
+ if (sql.includes("c.relkind IN ('v', 'm')")) {
26
+ return rows((catalog.views ?? []).map((v) => ({ oid: String(oid++), schema: v.schema, name: v.name, kind: v.materialized ? "m" : "v", def: v.def, reloptions: null, populated: true, am: null, tablespace: null, comment: v.comment ?? null, column_comments: [] })));
27
+ }
28
+ if (sql.includes("FROM pg_catalog.pg_index i"))
29
+ return rows((catalog.indexes ?? []).map((x) => ({ oid: String(oid++), schema: x.schema, name: x.name, table_name: x.table, def: x.def, comment: null })));
30
+ return [];
31
+ },
32
+ async end() { },
33
+ };
34
+ }
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Running `PostgresMigrationOp` in a live test (#3281, #3322): the Op's
3
+ * activities with the test's config and server, core's local executor, and
4
+ * an in-memory gate ledger a test approves on.
5
+ */
6
+ import { memoryGateLedgerPort, runOpLocally, loadProfiles } from "@intentius/chant/op";
7
+ import * as migrationActivities from "../../op/activities/postgres-migration.js";
8
+ import { PostgresMigrationOp } from "../migrate/op.js";
9
+ /** The migration activities, each called with `deps()`, as the local executor resolves them. */
10
+ export function migrationActivityMap(deps) {
11
+ const map = new Map();
12
+ for (const [name, fn] of Object.entries(migrationActivities)) {
13
+ if (typeof fn !== "function" || !name.startsWith("postgresMigration"))
14
+ continue;
15
+ map.set(name, ((args, signal) => fn(args, signal, deps())));
16
+ }
17
+ return map;
18
+ }
19
+ /** One run of the Op through core's local executor, as far as its next gate. */
20
+ export async function runMigrationOp(config, gates, deps) {
21
+ const { op } = PostgresMigrationOp(config);
22
+ const props = op.props;
23
+ return runOpLocally(props, migrationActivityMap(deps), await loadProfiles(), undefined, { gates, now: new Date().toISOString() });
24
+ }
25
+ /** An in-memory gate ledger a person approves on: each approval answers the gate the last run stopped at, for the plan it recorded. */
26
+ export class ApprovingLedger {
27
+ constructor() {
28
+ this.pending = [];
29
+ this.resolutions = [];
30
+ this.port = memoryGateLedgerPort();
31
+ }
32
+ approveLast() {
33
+ const last = this.port.appended.at(-1);
34
+ this.pending.push(...this.port.appended);
35
+ this.resolutions.push({
36
+ version: 1,
37
+ kind: "resolution",
38
+ op: last.op,
39
+ gate: last.gate,
40
+ resolvedBy: "e2e",
41
+ timestamp: new Date(Date.parse(last.timestamp) + 1000).toISOString(),
42
+ ...(last.planDigest ? { planDigest: last.planDigest } : {}),
43
+ });
44
+ this.port = memoryGateLedgerPort({ pending: this.pending, resolutions: this.resolutions });
45
+ }
46
+ }
47
+ /** An outcome attribute a run recorded. */
48
+ export const runOutcome = (r, name) => r.records.flatMap((x) => x.outcomes ?? []).find((o) => o.name === name)?.value;
@@ -0,0 +1,64 @@
1
+ /**
2
+ * The schema the live round trip creates on its source server: every object
3
+ * kind the dialect declares, with what the catalog's printers rewrite most
4
+ * (type aliases, literal casts, `IN` lists, unnamed constraints, identity and
5
+ * sequence options, storage parameters, comments), an extension and the
6
+ * domain over its type, a collation, composite and range types (and a
7
+ * multirange column), plain and ordered-set aggregates, a cast and an event
8
+ * trigger (#3911), a partitioned table and a partition, an ORM's
9
+ * revision table that import leaves out, and an object carrying chant's
10
+ * ownership trailer.
11
+ */
12
+ export const ROUNDTRIP_SCHEMA = `
13
+ CREATE SCHEMA app;
14
+ COMMENT ON SCHEMA app IS 'The shop';
15
+ CREATE EXTENSION citext WITH SCHEMA app;
16
+ CREATE TYPE app.order_status AS ENUM ('placed', 'paid', 'shipped');
17
+ CREATE DOMAIN app.email AS app.citext CONSTRAINT email_shape CHECK (VALUE LIKE '%@%');
18
+ COMMENT ON CONSTRAINT email_shape ON DOMAIN app.email IS 'needs an @';
19
+ CREATE SEQUENCE app.invoice_seq AS integer START WITH 1000 CACHE 10;
20
+ CREATE TABLE app.users (
21
+ id bigint GENERATED ALWAYS AS IDENTITY (START WITH 10) PRIMARY KEY,
22
+ email app.email NOT NULL UNIQUE,
23
+ plan text NOT NULL DEFAULT 'free' CHECK (plan IN ('free', 'pro')),
24
+ created_at timestamptz NOT NULL DEFAULT now()
25
+ ) WITH (fillfactor = 90);
26
+ COMMENT ON TABLE app.users IS 'Accounts [chant managed-by=chant stack=shop env=e2e]';
27
+ COMMENT ON COLUMN app.users.email IS 'Login name';
28
+ CREATE TABLE app.orders (
29
+ id serial PRIMARY KEY,
30
+ user_id bigint NOT NULL REFERENCES app.users (id) ON DELETE CASCADE,
31
+ invoice_no integer NOT NULL DEFAULT nextval('app.invoice_seq'),
32
+ status app.order_status NOT NULL DEFAULT 'placed',
33
+ amount numeric(12, 2) NOT NULL CONSTRAINT amount_positive CHECK (amount >= 0),
34
+ discount int DEFAULT -1,
35
+ total numeric GENERATED ALWAYS AS (amount * 2) STORED,
36
+ placed_at timestamp(3) without time zone
37
+ );
38
+ CREATE INDEX orders_user_idx ON app.orders (user_id, placed_at DESC) WHERE status <> 'shipped';
39
+ CREATE UNIQUE INDEX orders_invoice_idx ON app.orders USING btree (invoice_no) INCLUDE (amount);
40
+ CREATE TABLE app.measures (ts date NOT NULL, v double precision) PARTITION BY RANGE (ts);
41
+ CREATE TABLE app.measures_2026 PARTITION OF app.measures FOR VALUES FROM ('2026-01-01') TO ('2027-01-01');
42
+ CREATE VIEW app.order_totals AS
43
+ SELECT u.id AS user_id, u.email, count(o.id) AS n, coalesce(sum(o.amount), 0) AS total
44
+ FROM app.users u LEFT JOIN app.orders o ON o.user_id = u.id
45
+ GROUP BY u.id, u.email;
46
+ CREATE MATERIALIZED VIEW app.daily AS SELECT placed_at::date AS day, count(*) AS n FROM app.orders GROUP BY 1 WITH NO DATA;
47
+ CREATE COLLATION app.ci (provider = icu, locale = 'und-u-ks-level2', deterministic = false);
48
+ COMMENT ON COLLATION app.ci IS 'Case-insensitive';
49
+ CREATE TYPE app.pair AS (a integer, b text COLLATE "C");
50
+ COMMENT ON TYPE app.pair IS 'Two values';
51
+ CREATE TYPE app.floatrange AS RANGE (SUBTYPE = float8, SUBTYPE_DIFF = float8mi);
52
+ CREATE TABLE app.people (id integer PRIMARY KEY, nick text COLLATE app.ci, span app.floatrange, tags app.floatmultirange);
53
+ CREATE FUNCTION app.add2(a integer, b integer) RETURNS integer LANGUAGE sql IMMUTABLE AS $$ SELECT a + b $$;
54
+ CREATE AGGREGATE app.total(integer) (SFUNC = app.add2, STYPE = integer, INITCOND = '0', PARALLEL = SAFE);
55
+ COMMENT ON AGGREGATE app.total(integer) IS 'A sum';
56
+ CREATE FUNCTION app.middle(v double precision[]) RETURNS double precision LANGUAGE sql IMMUTABLE AS $$ SELECT v[(array_length(v, 1) + 1) / 2] $$;
57
+ CREATE AGGREGATE app.median_of(ORDER BY double precision) (SFUNC = pg_catalog.array_append, STYPE = double precision[], FINALFUNC = app.middle);
58
+ CREATE FUNCTION app.pair_text(p app.pair) RETURNS text LANGUAGE sql IMMUTABLE AS $$ SELECT p.a || ':' || p.b $$;
59
+ CREATE CAST (app.pair AS text) WITH FUNCTION app.pair_text(app.pair) AS ASSIGNMENT;
60
+ COMMENT ON CAST (app.pair AS text) IS 'a:b';
61
+ CREATE FUNCTION app.audit() RETURNS event_trigger LANGUAGE plpgsql AS $$ BEGIN END $$;
62
+ CREATE EVENT TRIGGER app_audit ON ddl_command_end WHEN TAG IN ('CREATE TABLE') EXECUTE FUNCTION app.audit();
63
+ CREATE TABLE public._prisma_migrations (id varchar(36) PRIMARY KEY, checksum varchar(64) NOT NULL);
64
+ `;
@@ -0,0 +1,47 @@
1
+ /**
2
+ * A throwaway Postgres server for the live tests: the pinned image on a random
3
+ * loopback port, a client for it, and a URL for a second database on it.
4
+ * Always removed with its volume.
5
+ */
6
+ import { execFile } from "node:child_process";
7
+ import { promisify } from "node:util";
8
+ import { startScratchContainer } from "../../core/container.js";
9
+ import { postgresImage, POSTGRES_LATEST_MAJOR } from "../../spec/postgres-pin.js";
10
+ import { connectPostgres } from "../live/client.js";
11
+ export { dockerAvailable } from "../../core/container.js";
12
+ const PASSWORD = "chant";
13
+ const exec = promisify(execFile);
14
+ export async function startTestPostgres(major = POSTGRES_LATEST_MAJOR) {
15
+ let port = "";
16
+ let name = "";
17
+ const endpoint = (db = "postgres") => ({ url: `postgres://postgres@127.0.0.1:${port}/${db}`, password: PASSWORD });
18
+ const container = await startScratchContainer({
19
+ image: postgresImage(major),
20
+ namePrefix: "chant-sql-pg-test",
21
+ containerPort: 5432,
22
+ env: { POSTGRES_PASSWORD: PASSWORD },
23
+ removeVolumes: true,
24
+ readyTimeoutMs: 120000,
25
+ notReady: "did not accept a connection",
26
+ onStarted: (n) => {
27
+ name = n;
28
+ },
29
+ ready: async (p) => {
30
+ port = p;
31
+ // The image runs a temporary server for initdb and then restarts it: ready is the second "ready" line.
32
+ const logs = await exec("docker", ["logs", name]).then((r) => `${r.stdout}${r.stderr}`, () => "");
33
+ if ((logs.match(/database system is ready to accept connections/g) ?? []).length < 2)
34
+ return false;
35
+ try {
36
+ const c = await connectPostgres(endpoint());
37
+ await c.query("SELECT 1");
38
+ await c.end();
39
+ return true;
40
+ }
41
+ catch {
42
+ return false;
43
+ }
44
+ },
45
+ });
46
+ return { name: container.name, endpoint, connect: (db) => connectPostgres(endpoint(db)), stop: () => container.stop() };
47
+ }