@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,557 @@
1
+ /**
2
+ * The Postgres applier (#3280): make a server hold what a build declares, for
3
+ * every change the classifier (`../plan/rules.ts`) does not refuse, and
4
+ * refuse the rest.
5
+ *
6
+ * Per declared object, exactly one verdict (lexicon-authoring/applying.mdx):
7
+ *
8
+ * - APPLIED `created`: absent on the server; created from its declared
9
+ * statements, with chant's ownership marker set by `COMMENT ON`.
10
+ * - APPLIED `updated`: present, and the statements for its changes ran and
11
+ * committed.
12
+ * - APPLIED `unchanged`: present, nothing to change, the marker in place.
13
+ * - NOT-ATTEMPTED `unsupported-kind`: a change only expand and contract
14
+ * makes (a column rename, a type change across kinds, a NOT NULL column
15
+ * with no default), or one with no in-place statement. Nothing is sent for
16
+ * the object; the detail names each rule, the restriction and the
17
+ * expand-and-contract migration Op (#3281).
18
+ * - NOT-ATTEMPTED `filtered`: the change drops a column, which destroys its
19
+ * data, and the apply was not allowed to delete; or another tool keeps the
20
+ * object (an ORM's revision table, a managed provider's schema).
21
+ * - NOT-ATTEMPTED `dependency-failed`: an object it references is not on the
22
+ * server, or its statements ran in a transaction that rolled back because
23
+ * another object's statement failed. The detail names that statement.
24
+ * - NOT-ATTEMPTED with the binding's reason: no server to apply to.
25
+ *
26
+ * A statement the server refuses fails its object, which was attempted and
27
+ * did not converge. Its transaction rolls back, the rest of the apply goes on,
28
+ * and the applier then throws {@link PostgresApplyError}, which carries the
29
+ * outcome so far.
30
+ *
31
+ * ## Transactions
32
+ *
33
+ * Statements run in the build's order, each object's in the order its
34
+ * changes need, and are grouped:
35
+ *
36
+ * 1. Consecutive statements that change only the catalog (create, metadata,
37
+ * drop) share one transaction, across objects, so they land together or
38
+ * not at all.
39
+ * 2. A statement that reads or rewrites a table's rows (an `ACCESS
40
+ * EXCLUSIVE` rewrite or scan, a validation, a non-concurrent index build)
41
+ * runs in a transaction of its own object, so a long scan holds locks on
42
+ * that one table and the changes before it have committed.
43
+ * 3. A statement that refuses a transaction block (`CREATE INDEX
44
+ * CONCURRENTLY`, `DROP INDEX CONCURRENTLY`) runs alone, outside any
45
+ * transaction, and so does `ALTER TYPE ... ADD VALUE`, whose new label
46
+ * cannot be used in the transaction that adds it.
47
+ *
48
+ * ## Timeouts
49
+ *
50
+ * Every statement runs with its own `lock_timeout` and `statement_timeout`
51
+ * (`SET LOCAL` in a transaction, `SET` before one outside), so a statement
52
+ * blocked behind another session's lock fails fast instead of queueing every
53
+ * query behind it. Defaults: a lock is waited for 5 s; a catalog-only
54
+ * statement may run 60 s; a statement that reads or rewrites rows has no
55
+ * limit. `sql.profiles.<env>` sets them (`lockTimeoutMs`,
56
+ * `statementTimeoutMs`, `scanTimeoutMs`), and the outcome records the values
57
+ * each statement ran with.
58
+ *
59
+ * ## Prune
60
+ *
61
+ * When asked for, prune drops the objects in the declared schemas that the
62
+ * build no longer declares and whose comment carries this project's marker
63
+ * (stack and env): views first, schemas last, never `CASCADE`, so an object
64
+ * something else still depends on is kept and reported. An object without
65
+ * the marker is not chant's and is never touched; one another tool keeps is
66
+ * never read as an orphan at all.
67
+ */
68
+ import { SqlApplyError, dependencyFailedDetail, missingDependencies, readBuildObjects } from "../../core/apply.js";
69
+ import { carriesMarker, isChantManaged } from "../../core/ownership.js";
70
+ import { DEFAULT_LOCK_TIMEOUT_MS, PostgresQueryError, withCatalogLockTimeout } from "../live/client.js";
71
+ import { liveProps } from "../plan/deep.js";
72
+ import { diffObject, qualifiedKey } from "../plan/schema.js";
73
+ import { POSTGRES_LATEST_MAJOR } from "../../spec/postgres-pin.js";
74
+ import { matchPgObjects } from "../plan/diff.js";
75
+ import { planAgainstClient } from "../plan/commands.js";
76
+ import { quoteIdent } from "../keywords.js";
77
+ import { planPgStatements, scansRows } from "./statements.js";
78
+ import { ACCESS_KINDS, ACCESS_MANAGED_KINDS } from "../plan/normalize.js";
79
+ import { declaredAccess, diffAccess, targetKey } from "../access/acl.js";
80
+ import { readLiveAccess } from "../access/live.js";
81
+ export const DEFAULT_POSTGRES_APPLY_TIMEOUTS = { lockTimeoutMs: DEFAULT_LOCK_TIMEOUT_MS, statementTimeoutMs: 60000, scanTimeoutMs: 0 };
82
+ /** An apply in which the server refused a statement. The outcome says what did and did not happen. */
83
+ export class PostgresApplyError extends SqlApplyError {
84
+ constructor(outcome) {
85
+ super("Postgres", outcome);
86
+ this.name = "PostgresApplyError";
87
+ }
88
+ }
89
+ /**
90
+ * The name an apply result gives an object: `schema.name`, or a schema's or
91
+ * extension's own name; a routine's with its parameter types
92
+ * (`app.touch()`), a trigger's with its table (`touch ON app.users`).
93
+ */
94
+ export const refName = (o) => o.kind === "trigger" || o.kind === "policy"
95
+ ? `${o.name}${o.signature ?? ""}`
96
+ : o.kind === "schema" || o.kind === "extension" || o.kind === "role" || o.schema === undefined
97
+ ? o.name
98
+ : `${o.schema}.${o.name}${o.kind === "function" || o.kind === "procedure" || o.kind === "aggregate" ? (o.signature ?? "") : ""}`;
99
+ /**
100
+ * The objects a Postgres `chant build` output declares, in creation order,
101
+ * each parsed with its tag and in canonical form. Takes the sql lexicon's
102
+ * primary output, or a multi-lexicon output holding it under `sql`.
103
+ */
104
+ export function declaredObjects(json, defaultSchema = "public") {
105
+ return readBuildObjects(json, "postgres", (o) => {
106
+ const canonical = { ...diffObject(o.type, o.ddl, defaultSchema), exportName: o.export };
107
+ return {
108
+ exportName: o.export,
109
+ type: o.type,
110
+ name: refName(canonical),
111
+ key: qualifiedKey(canonical),
112
+ ddl: o.ddl,
113
+ props: liveProps({ type: o.type, statement: o.ddl }),
114
+ canonical,
115
+ dependsOn: o.dependsOn,
116
+ };
117
+ });
118
+ }
119
+ /** The plan axis: one ref per declared object, by its type and its name on the server. */
120
+ export const planRefs = (declared) => declared.map((o) => ({ kind: o.type, name: o.name }));
121
+ const SQLSTATE_LOCK_NOT_AVAILABLE = "55P03";
122
+ const SQLSTATE_QUERY_CANCELED = "57014";
123
+ const SQLSTATE_DEPENDENT_OBJECTS = "2BP01";
124
+ const SQLSTATE_UNDEFINED = new Set(["42P01", "42704", "3F000"]);
125
+ const ms = (n) => `'${Math.max(0, Math.floor(n))}ms'`;
126
+ /** A server error as a detail: its message, and what the timeouts mean when one fired. */
127
+ function errorText(err, t) {
128
+ const message = err instanceof Error ? err.message.split("\n")[0] : String(err);
129
+ const code = err instanceof PostgresQueryError ? err.code : undefined;
130
+ if (code === SQLSTATE_LOCK_NOT_AVAILABLE)
131
+ return `${message} (lock_timeout ${t.lockTimeoutMs}ms: another session holds a lock this statement needs; SQLSTATE 55P03)`;
132
+ if (code === SQLSTATE_QUERY_CANCELED)
133
+ return `${message} (statement_timeout ${t.statementTimeoutMs}ms; SQLSTATE 57014)`;
134
+ return code ? `${message} (SQLSTATE ${code})` : message;
135
+ }
136
+ /**
137
+ * Apply the declarations to the server `client` is connected to. Returns
138
+ * every declared object in exactly one of applied or not attempted, and every
139
+ * pruned orphan; throws {@link PostgresApplyError} when the server refused a
140
+ * statement. The client is left open; the caller ends it.
141
+ */
142
+ export async function applyPostgres(client, target, declared, opts = {}) {
143
+ const log = opts.log ?? (() => undefined);
144
+ const timeouts = { ...DEFAULT_POSTGRES_APPLY_TIMEOUTS, ...target.timeouts, ...opts.timeouts };
145
+ const outcome = {
146
+ target: target.endpoint.url,
147
+ source: target.source,
148
+ applied: [],
149
+ pruned: [],
150
+ notAttempted: [],
151
+ failed: [],
152
+ timeouts,
153
+ statements: [],
154
+ transactions: [],
155
+ };
156
+ // ── Plan: the same diff `chant sql plan` shows. ──
157
+ // The catalog reads wait under lockTimeoutMs, as a plan's do (#3726): one blocked behind ACCESS EXCLUSIVE fails naming the holder instead of hanging.
158
+ const reader = await withCatalogLockTimeout(client, timeouts.lockTimeoutMs);
159
+ const build = declared.map((o) => ({ key: o.exportName, canonical: o.canonical }));
160
+ const plan = await planAgainstClient(reader, target, build, {
161
+ ...(opts.major !== undefined ? { major: opts.major } : {}),
162
+ ...(opts.readLive ? { readLive: opts.readLive } : {}),
163
+ ...(opts.serverNormalize ? { serverNormalize: opts.serverNormalize } : {}),
164
+ });
165
+ const normalizedByKey = new Map(plan.declared.map((o) => [o.key, o.canonical]));
166
+ const liveRawByKey = new Map(plan.liveObjects.map((o) => [qualifiedKey(liveCanonicalAddress(o)), o]));
167
+ const managed = target.access === true;
168
+ // Access declarations a profile does not manage are not applied; grants and default privileges run after every object, as access.
169
+ for (const o of declared) {
170
+ if (!managed && ACCESS_MANAGED_KINDS.has(o.canonical.kind)) {
171
+ outcome.notAttempted.push({
172
+ kind: o.type,
173
+ name: o.name,
174
+ reason: "filtered",
175
+ detail: `access is not managed in this environment: set sql.profiles.<env>.access to plan and apply policies, roles, grants and row-level security`,
176
+ });
177
+ }
178
+ }
179
+ const objects = declared
180
+ .filter((o) => !ACCESS_KINDS.has(o.canonical.kind) && (managed || !ACCESS_MANAGED_KINDS.has(o.canonical.kind)))
181
+ .map((original) => ({ ...original, canonical: { ...original.canonical, ...normalizedByKey.get(original.key) } }));
182
+ const matchedLive = new Set();
183
+ for (const m of matchPgObjects(plan.live, plan.declared))
184
+ if (m.kind === "matched")
185
+ matchedLive.add(m.after.key);
186
+ // An extension's own comment stays under the trailer when the declaration sets none.
187
+ const extensionComments = await extensionDefaults(reader, objects.filter((o) => o.canonical.kind === "extension" && !matchedLive.has(o.key)).map((o) => o.canonical.name));
188
+ // ── Each object's statements, or its verdict when it has none to send. ──
189
+ const statements = planPgStatements({
190
+ declared: objects,
191
+ changes: plan.diff.changes,
192
+ current: plan.live,
193
+ major: plan.major ?? POSTGRES_LATEST_MAJOR,
194
+ allowDestructive: opts.prune === true,
195
+ carriesMarker: (_live, key) => carriesMarker(liveRawByKey.get(key)?.comment, opts.marker),
196
+ extensionComment: (name) => extensionComments.get(name),
197
+ access: managed,
198
+ ...(opts.marker ? { marker: opts.marker } : {}),
199
+ });
200
+ const units = [];
201
+ const onServer = new Set();
202
+ const exportNames = new Set(declared.map((o) => o.exportName));
203
+ for (const entry of statements.objects) {
204
+ const obj = entry.obj;
205
+ const ref = { kind: obj.type, name: obj.name };
206
+ const liveRaw = entry.live ? liveRawByKey.get(qualifiedKey(entry.live)) : undefined;
207
+ switch (entry.verdict) {
208
+ case "foreign":
209
+ case "withheld":
210
+ case "unsupported":
211
+ onServer.add(obj.exportName);
212
+ outcome.notAttempted.push({ ...ref, reason: entry.verdict === "unsupported" ? "unsupported-kind" : "filtered", detail: entry.detail });
213
+ continue;
214
+ case "refused":
215
+ if (entry.live)
216
+ onServer.add(obj.exportName);
217
+ outcome.notAttempted.push({ ...ref, reason: "unsupported-kind", detail: entry.detail });
218
+ continue;
219
+ }
220
+ if (entry.steps.length === 0) {
221
+ onServer.add(obj.exportName);
222
+ outcome.applied.push({ ...ref, action: "unchanged", ...(liveRaw ? { physicalId: liveRaw.oid } : {}), statements: [] });
223
+ continue;
224
+ }
225
+ units.push({ obj, ref, created: !entry.live, ...(liveRaw ? { physicalId: liveRaw.oid } : {}), steps: entry.steps, ran: [], pending: [], done: 0, state: "planned" });
226
+ }
227
+ // ── Run them, grouped into transactions. ──
228
+ // Statements use the default schema for a bare name, as the declarations do; the catalog was read with an empty search_path.
229
+ await client.query("SELECT pg_catalog.set_config('search_path', $1, false)", [quoteIdent(target.defaultSchema)]);
230
+ let tx;
231
+ const finish = (u) => {
232
+ if (u.state !== "planned" || u.done < u.steps.length || u.pending.length > 0)
233
+ return;
234
+ u.state = "applied";
235
+ onServer.add(u.obj.exportName);
236
+ outcome.applied.push({ ...u.ref, action: u.created ? "created" : "updated", ...(u.physicalId ? { physicalId: u.physicalId } : {}), statements: u.ran });
237
+ };
238
+ const fail = (u, error) => {
239
+ u.state = "failed";
240
+ if (!u.created)
241
+ onServer.add(u.obj.exportName);
242
+ outcome.failed.push({ ...u.ref, error, statements: u.ran });
243
+ };
244
+ const commit = async () => {
245
+ if (!tx)
246
+ return;
247
+ const t = tx;
248
+ tx = undefined;
249
+ try {
250
+ log("COMMIT");
251
+ await client.query("COMMIT");
252
+ }
253
+ catch (err) {
254
+ await rollBack(t, "COMMIT", err instanceof Error ? err.message : String(err), undefined);
255
+ return;
256
+ }
257
+ outcome.transactions.push({ objects: [...t.members].map((u) => u.ref.name), result: "committed" });
258
+ for (const u of t.members) {
259
+ u.ran.push(...u.pending);
260
+ u.pending = [];
261
+ finish(u);
262
+ }
263
+ };
264
+ /** Roll the open transaction back: the failing object fails, the others in it are rolled back with it. */
265
+ const rollBack = async (t, sql, error, failing) => {
266
+ log("ROLLBACK");
267
+ await client.query("ROLLBACK").catch(() => undefined);
268
+ outcome.transactions.push({ objects: [...t.members].map((u) => u.ref.name), result: "rolled-back", failedAt: { sql, error } });
269
+ for (const u of t.members) {
270
+ u.pending = [];
271
+ if (u === failing)
272
+ continue;
273
+ if (u.state !== "planned" && u.state !== "applied")
274
+ continue;
275
+ if (u.ran.length > 0)
276
+ fail(u, `rolled back with the transaction that failed at ${sql}: ${error}`);
277
+ else {
278
+ u.state = "rolled-back";
279
+ outcome.notAttempted.push({
280
+ ...u.ref,
281
+ reason: "dependency-failed",
282
+ detail: `its statements ran in a transaction that rolled back, so nothing of it was kept: the transaction failed at ${sql}: ${error}`,
283
+ });
284
+ }
285
+ }
286
+ if (failing)
287
+ fail(failing, error);
288
+ };
289
+ for (const u of units) {
290
+ for (const s of u.steps) {
291
+ opts.signal?.throwIfAborted();
292
+ if (u.state !== "planned")
293
+ break;
294
+ const heavy = scansRows(s.class);
295
+ const t = { lockTimeoutMs: timeouts.lockTimeoutMs, statementTimeoutMs: heavy ? timeouts.scanTimeoutMs : timeouts.statementTimeoutMs };
296
+ // Close the open transaction when this statement cannot join it.
297
+ if (tx && (!s.transactional || tx.heavy !== heavy || (heavy && tx.owner !== u)))
298
+ await commit();
299
+ if (u.state !== "planned")
300
+ break;
301
+ if (u.done === 0 && !tx?.members.has(u)) {
302
+ // An object whose statements all ran in the open transaction is on the server as far as this transaction sees.
303
+ const seen = new Set([...onServer, ...[...(tx?.members ?? [])].filter((m) => m.state === "planned" && m.done === m.steps.length).map((m) => m.obj.exportName)]);
304
+ const missing = missingDependencies(u.obj.exportName, u.obj.dependsOn, exportNames, seen);
305
+ if (missing.length > 0) {
306
+ u.state = "skipped";
307
+ if (!u.created)
308
+ onServer.add(u.obj.exportName);
309
+ outcome.notAttempted.push({ ...u.ref, reason: "dependency-failed", detail: dependencyFailedDetail(missing) });
310
+ break;
311
+ }
312
+ }
313
+ if (!s.transactional) {
314
+ const record = { object: u.ref.name, sql: s.sql, class: s.class, ...t };
315
+ try {
316
+ for (const set of [`SET lock_timeout = ${ms(t.lockTimeoutMs)}`, `SET statement_timeout = ${ms(t.statementTimeoutMs)}`]) {
317
+ log(set);
318
+ await client.query(set);
319
+ }
320
+ log(s.sql);
321
+ outcome.statements.push(record);
322
+ await client.query(s.sql);
323
+ u.ran.push(s.sql);
324
+ u.done++;
325
+ finish(u);
326
+ }
327
+ catch (err) {
328
+ if (opts.signal?.aborted)
329
+ throw err;
330
+ if (s.buildsIndex)
331
+ await dropInvalidIndex(client, s.buildsIndex, log);
332
+ fail(u, `${errorText(err, t)}, at ${s.sql}`);
333
+ }
334
+ continue;
335
+ }
336
+ if (!tx) {
337
+ log("BEGIN");
338
+ await client.query("BEGIN");
339
+ tx = { number: outcome.transactions.length, heavy, ...(heavy ? { owner: u } : {}), members: new Set(), statements: [] };
340
+ }
341
+ tx.members.add(u);
342
+ const record = { object: u.ref.name, sql: s.sql, class: s.class, ...t, transaction: tx.number };
343
+ try {
344
+ for (const set of [`SET LOCAL lock_timeout = ${ms(t.lockTimeoutMs)}`, `SET LOCAL statement_timeout = ${ms(t.statementTimeoutMs)}`]) {
345
+ log(set);
346
+ await client.query(set);
347
+ }
348
+ log(s.sql);
349
+ outcome.statements.push(record);
350
+ await client.query(s.sql);
351
+ u.pending.push(s.sql);
352
+ u.done++;
353
+ }
354
+ catch (err) {
355
+ if (opts.signal?.aborted) {
356
+ await client.query("ROLLBACK").catch(() => undefined);
357
+ throw err;
358
+ }
359
+ const failed = tx;
360
+ tx = undefined;
361
+ await rollBack(failed, s.sql, errorText(err, t), u);
362
+ }
363
+ }
364
+ }
365
+ await commit();
366
+ if (managed)
367
+ await applyAccess(client, reader, declared, onServer, exportNames, { ...opts, major: plan.major ?? opts.major ?? POSTGRES_LATEST_MAJOR, ...(plan.scope ? { schemas: plan.scope } : {}) }, timeouts, outcome, log);
368
+ if (opts.prune)
369
+ await prune(client, statements.drops, liveRawByKey, opts, timeouts, outcome, log);
370
+ if (outcome.failed.length > 0)
371
+ throw new PostgresApplyError(outcome);
372
+ return outcome;
373
+ }
374
+ /**
375
+ * Access, after every object (#3681): the privileges and default privileges
376
+ * the declarations add up to, against what the server holds now that the
377
+ * objects exist, made in one transaction. A grant or default-privileges
378
+ * declaration is `updated` when a statement ran for it and `unchanged`
379
+ * otherwise; a privilege nothing declares is revoked under the object's name.
380
+ */
381
+ async function applyAccess(client, reader, declared, onServer, exportNames, opts, timeouts, outcome, log) {
382
+ const decls = declared.filter((o) => ACCESS_KINDS.has(o.canonical.kind));
383
+ const ref = (o) => ({ kind: o.type, name: o.canonical.name });
384
+ const ready = [];
385
+ for (const o of decls) {
386
+ const missing = missingDependencies(o.exportName, o.dependsOn, exportNames, onServer);
387
+ if (missing.length > 0)
388
+ outcome.notAttempted.push({ ...ref(o), reason: "dependency-failed", detail: dependencyFailedDetail(missing) });
389
+ else
390
+ ready.push(o);
391
+ }
392
+ const skipped = new Set(decls.filter((o) => !ready.includes(o)).map((o) => o.exportName));
393
+ const [me] = await reader.query("SELECT current_user AS self");
394
+ const want = declaredAccess(declared.filter((o) => !skipped.has(o.exportName)).map((o) => ({ key: o.exportName, canonical: o.canonical })), { major: opts.major, ...(me?.self ? { self: me.self } : {}) });
395
+ const have = await readLiveAccess(reader, want.targets, {
396
+ ...(opts.schemas ? { schemas: opts.schemas } : {}),
397
+ forRoles: want.forRoles,
398
+ declaredDefaults: want.targets.filter((t) => t.kind === "default"),
399
+ });
400
+ // A target that is not on the server (its object failed) is left for the next apply.
401
+ const changes = diffAccess(have.state, want.state, want.exportsOf).filter((c) => c.target.kind === "default" || have.present.has(targetKey(c.target.kind === "column" ? { kind: "table", name: c.target.name } : c.target)));
402
+ const ranFor = new Map();
403
+ if (changes.length > 0) {
404
+ const t = { lockTimeoutMs: timeouts.lockTimeoutMs, statementTimeoutMs: timeouts.statementTimeoutMs };
405
+ const number = outcome.transactions.length;
406
+ const members = new Set();
407
+ log("BEGIN");
408
+ await client.query("BEGIN");
409
+ try {
410
+ for (const set of [`SET LOCAL lock_timeout = ${ms(t.lockTimeoutMs)}`, `SET LOCAL statement_timeout = ${ms(t.statementTimeoutMs)}`]) {
411
+ log(set);
412
+ await client.query(set);
413
+ }
414
+ for (const c of changes) {
415
+ const object = c.exports[0] !== undefined ? (declared.find((o) => o.exportName === c.exports[0])?.canonical.name ?? c.change.object) : c.change.object.slice(4);
416
+ members.add(object);
417
+ for (const sql of c.sql) {
418
+ opts.signal?.throwIfAborted();
419
+ log(sql);
420
+ outcome.statements.push({ object, sql, class: c.change.class, ...t, transaction: number });
421
+ await client.query(sql);
422
+ for (const e of c.exports)
423
+ ranFor.set(e, [...(ranFor.get(e) ?? []), sql]);
424
+ }
425
+ }
426
+ log("COMMIT");
427
+ await client.query("COMMIT");
428
+ outcome.transactions.push({ objects: [...members], result: "committed" });
429
+ }
430
+ catch (err) {
431
+ if (opts.signal?.aborted) {
432
+ await client.query("ROLLBACK").catch(() => undefined);
433
+ throw err;
434
+ }
435
+ const error = errorText(err, t);
436
+ const failedAt = outcome.statements[outcome.statements.length - 1]?.sql ?? "BEGIN";
437
+ log("ROLLBACK");
438
+ await client.query("ROLLBACK").catch(() => undefined);
439
+ outcome.transactions.push({ objects: [...members], result: "rolled-back", failedAt: { sql: failedAt, error } });
440
+ for (const o of ready) {
441
+ if (changes.some((c) => c.exports.includes(o.exportName)))
442
+ outcome.failed.push({ ...ref(o), error: `${error}, in the access transaction at ${failedAt}`, statements: [] });
443
+ else
444
+ outcome.applied.push({ ...ref(o), action: "unchanged", statements: [] });
445
+ }
446
+ return;
447
+ }
448
+ }
449
+ for (const o of ready) {
450
+ const ran = ranFor.get(o.exportName) ?? [];
451
+ outcome.applied.push({ ...ref(o), action: ran.length > 0 ? "updated" : "unchanged", statements: ran });
452
+ }
453
+ }
454
+ /** The address a live object is keyed by in the diff. */
455
+ function liveCanonicalAddress(o) {
456
+ const kind = {
457
+ "Postgres::Schema": "schema",
458
+ "Postgres::Table": "table",
459
+ "Postgres::Index": "index",
460
+ "Postgres::View": "view",
461
+ "Postgres::MaterializedView": "materializedView",
462
+ "Postgres::Sequence": "sequence",
463
+ "Postgres::Enum": "enum",
464
+ "Postgres::CompositeType": "composite",
465
+ "Postgres::RangeType": "range",
466
+ "Postgres::Domain": "domain",
467
+ "Postgres::Aggregate": "aggregate",
468
+ "Postgres::Collation": "collation",
469
+ "Postgres::Cast": "cast",
470
+ "Postgres::EventTrigger": "eventTrigger",
471
+ "Postgres::Extension": "extension",
472
+ "Postgres::Function": "function",
473
+ "Postgres::Procedure": "procedure",
474
+ "Postgres::Trigger": "trigger",
475
+ "Postgres::Policy": "policy",
476
+ "Postgres::Role": "role",
477
+ "Postgres::Grant": "grant",
478
+ "Postgres::DefaultPrivileges": "defaultPrivileges",
479
+ }[o.type];
480
+ return {
481
+ kind,
482
+ ...(o.schema !== undefined && kind !== "schema" && kind !== "extension" && kind !== "role" && kind !== "cast" && kind !== "eventTrigger" ? { schema: o.schema } : {}),
483
+ name: o.name,
484
+ ...(o.signature !== undefined ? { signature: o.signature } : {}),
485
+ };
486
+ }
487
+ /** The comments the extensions' control files set, by extension name. */
488
+ async function extensionDefaults(client, names) {
489
+ if (names.length === 0)
490
+ return new Map();
491
+ const rows = await client
492
+ .query("SELECT name, comment FROM pg_catalog.pg_available_extensions WHERE name = ANY($1::text[])", [[...names]])
493
+ .catch(() => []);
494
+ return new Map(rows.filter((r) => r.comment).map((r) => [r.name, r.comment]));
495
+ }
496
+ /** After a failed CREATE INDEX CONCURRENTLY: drop the INVALID index it left, and only an INVALID one. */
497
+ async function dropInvalidIndex(client, index, log) {
498
+ try {
499
+ const [row] = await client.query("SELECT NOT i.indisvalid AS invalid FROM pg_catalog.pg_index i WHERE i.indexrelid = pg_catalog.to_regclass($1)", [index]);
500
+ if (!row?.invalid)
501
+ return;
502
+ const sql = `DROP INDEX CONCURRENTLY IF EXISTS ${index}`;
503
+ log(sql);
504
+ await client.query(sql);
505
+ }
506
+ catch {
507
+ // Left for the next apply, which reads it and builds it again.
508
+ }
509
+ }
510
+ async function prune(client, drops, liveRawByKey, opts, timeouts, outcome, log) {
511
+ for (const drop of drops) {
512
+ const raw = liveRawByKey.get(drop.key);
513
+ if (!raw || raw.foreign)
514
+ continue;
515
+ const address = liveCanonicalAddress(raw);
516
+ const ref = { kind: raw.type, name: refName(address) };
517
+ if (!isChantManaged(raw.comment))
518
+ continue; // not chant's: never touched, never reported
519
+ if (!opts.marker?.stack) {
520
+ outcome.notAttempted.push({
521
+ ...ref,
522
+ reason: "not-prunable",
523
+ detail: "the project declares no ownership.stack, so this project's objects cannot be told from another chant project's",
524
+ });
525
+ continue;
526
+ }
527
+ if (!carriesMarker(raw.comment, opts.marker))
528
+ continue; // another stack's or env's
529
+ const s = drop.step;
530
+ const t = { lockTimeoutMs: timeouts.lockTimeoutMs, statementTimeoutMs: scansRows(s.class) ? timeouts.scanTimeoutMs : timeouts.statementTimeoutMs };
531
+ try {
532
+ opts.signal?.throwIfAborted();
533
+ for (const set of [`SET lock_timeout = ${ms(t.lockTimeoutMs)}`, `SET statement_timeout = ${ms(t.statementTimeoutMs)}`]) {
534
+ log(set);
535
+ await client.query(set);
536
+ }
537
+ log(s.sql);
538
+ outcome.statements.push({ object: ref.name, sql: s.sql, class: s.class, ...t });
539
+ await client.query(s.sql);
540
+ outcome.pruned.push({ ...ref, deleted: true, statement: s.sql });
541
+ }
542
+ catch (err) {
543
+ if (opts.signal?.aborted)
544
+ throw err;
545
+ const code = err instanceof PostgresQueryError ? err.code : undefined;
546
+ if (code === SQLSTATE_DEPENDENT_OBJECTS) {
547
+ outcome.notAttempted.push({ ...ref, reason: "not-prunable", detail: `${errorText(err, t)}; dropping it would take what depends on it, which this apply does not drop` });
548
+ }
549
+ else if (code && SQLSTATE_UNDEFINED.has(code)) {
550
+ // Gone with an object dropped before it (a table's own index or sequence).
551
+ outcome.pruned.push({ ...ref, deleted: false, statement: s.sql });
552
+ }
553
+ else
554
+ outcome.failed.push({ ...ref, error: `${errorText(err, t)}, at ${s.sql}`, statements: [] });
555
+ }
556
+ }
557
+ }