@supabase/pg-delta 1.0.0-alpha.2 → 1.0.0-alpha.4

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 (464) hide show
  1. package/README.md +22 -0
  2. package/dist/cli/bin/cli.js +0 -0
  3. package/dist/cli/commands/plan.js +21 -0
  4. package/dist/cli/utils.d.ts +2 -0
  5. package/dist/cli/utils.js +1 -1
  6. package/dist/core/integrations/supabase.js +2 -0
  7. package/dist/core/objects/table/table.model.d.ts +4 -2
  8. package/dist/core/objects/table/table.model.js +3 -0
  9. package/dist/core/objects/trigger/changes/trigger.alter.js +23 -0
  10. package/dist/core/objects/trigger/changes/trigger.create.js +2 -1
  11. package/dist/core/objects/trigger/trigger.model.d.ts +1 -0
  12. package/dist/core/objects/trigger/trigger.model.js +3 -0
  13. package/dist/core/plan/apply.js +3 -3
  14. package/dist/core/plan/create.js +34 -15
  15. package/dist/core/plan/sql-format/constants.d.ts +2 -0
  16. package/dist/core/plan/sql-format/constants.js +11 -0
  17. package/dist/core/plan/sql-format/fixtures.d.ts +2 -0
  18. package/dist/core/plan/sql-format/fixtures.js +2449 -0
  19. package/dist/core/plan/sql-format/format-utils.d.ts +37 -0
  20. package/dist/core/plan/sql-format/format-utils.js +274 -0
  21. package/dist/core/plan/sql-format/formatters.d.ts +20 -0
  22. package/dist/core/plan/sql-format/formatters.js +737 -0
  23. package/dist/core/plan/sql-format/index.d.ts +2 -0
  24. package/dist/core/plan/sql-format/index.js +98 -0
  25. package/dist/core/plan/sql-format/keyword-case.d.ts +2 -0
  26. package/dist/core/plan/sql-format/keyword-case.js +868 -0
  27. package/dist/core/plan/sql-format/protect.d.ts +3 -0
  28. package/dist/core/plan/sql-format/protect.js +269 -0
  29. package/dist/core/plan/sql-format/sql-scanner.d.ts +59 -0
  30. package/dist/core/plan/sql-format/sql-scanner.js +202 -0
  31. package/dist/core/plan/sql-format/tokenizer.d.ts +22 -0
  32. package/dist/core/plan/sql-format/tokenizer.js +118 -0
  33. package/dist/core/plan/sql-format/types.d.ts +28 -0
  34. package/dist/core/plan/sql-format/types.js +1 -0
  35. package/dist/core/plan/sql-format/wrap.d.ts +2 -0
  36. package/dist/core/plan/sql-format/wrap.js +165 -0
  37. package/dist/core/plan/sql-format.d.ts +2 -0
  38. package/dist/core/plan/sql-format.js +1 -0
  39. package/dist/core/plan/statements.d.ts +2 -1
  40. package/dist/core/plan/statements.js +6 -2
  41. package/dist/core/postgres-config.d.ts +15 -0
  42. package/dist/core/postgres-config.js +30 -0
  43. package/dist/index.d.ts +2 -0
  44. package/dist/index.js +1 -0
  45. package/package.json +37 -22
  46. package/src/cli/app.ts +28 -0
  47. package/src/cli/bin/cli.ts +9 -0
  48. package/src/cli/commands/apply.ts +101 -0
  49. package/src/cli/commands/plan.ts +195 -0
  50. package/src/cli/commands/sync.ts +185 -0
  51. package/src/cli/formatters/index.ts +5 -0
  52. package/src/cli/formatters/tree/tree-builder.ts +380 -0
  53. package/src/cli/formatters/tree/tree-renderer.ts +372 -0
  54. package/src/cli/formatters/tree/tree.ts +237 -0
  55. package/src/cli/utils/integrations.ts +42 -0
  56. package/src/cli/utils.ts +231 -0
  57. package/src/core/catalog.diff.ts +246 -0
  58. package/src/core/catalog.model.ts +384 -0
  59. package/src/core/change.types.ts +44 -0
  60. package/src/core/context.ts +26 -0
  61. package/src/core/depend.ts +1870 -0
  62. package/src/core/expand-replace-dependencies.ts +380 -0
  63. package/src/core/fingerprint.ts +204 -0
  64. package/src/core/integrations/filter/dsl.ts +204 -0
  65. package/src/core/integrations/filter/extractors.ts +145 -0
  66. package/src/core/integrations/filter/filter.types.ts +3 -0
  67. package/src/core/integrations/integration-dsl.ts +24 -0
  68. package/src/core/integrations/integration.types.ts +7 -0
  69. package/src/core/integrations/serialize/dsl.ts +77 -0
  70. package/src/core/integrations/serialize/serialize.types.ts +3 -0
  71. package/src/core/integrations/supabase.ts +121 -0
  72. package/src/core/objects/aggregate/aggregate.diff.test.ts +215 -0
  73. package/src/core/objects/aggregate/aggregate.diff.ts +278 -0
  74. package/src/core/objects/aggregate/aggregate.model.ts +317 -0
  75. package/src/core/objects/aggregate/changes/aggregate.alter.test.ts +64 -0
  76. package/src/core/objects/aggregate/changes/aggregate.alter.ts +32 -0
  77. package/src/core/objects/aggregate/changes/aggregate.base.ts +20 -0
  78. package/src/core/objects/aggregate/changes/aggregate.comment.test.ts +86 -0
  79. package/src/core/objects/aggregate/changes/aggregate.comment.ts +62 -0
  80. package/src/core/objects/aggregate/changes/aggregate.create.test.ts +101 -0
  81. package/src/core/objects/aggregate/changes/aggregate.create.ts +329 -0
  82. package/src/core/objects/aggregate/changes/aggregate.drop.test.ts +78 -0
  83. package/src/core/objects/aggregate/changes/aggregate.drop.ts +32 -0
  84. package/src/core/objects/aggregate/changes/aggregate.privilege.test.ts +130 -0
  85. package/src/core/objects/aggregate/changes/aggregate.privilege.ts +146 -0
  86. package/src/core/objects/aggregate/changes/aggregate.types.ts +12 -0
  87. package/src/core/objects/base.change.ts +62 -0
  88. package/src/core/objects/base.default-privileges.ts +204 -0
  89. package/src/core/objects/base.diff.ts +20 -0
  90. package/src/core/objects/base.model.ts +82 -0
  91. package/src/core/objects/base.privilege-diff.ts +299 -0
  92. package/src/core/objects/base.privilege.ts +184 -0
  93. package/src/core/objects/collation/changes/collation.alter.test.ts +63 -0
  94. package/src/core/objects/collation/changes/collation.alter.ts +79 -0
  95. package/src/core/objects/collation/changes/collation.base.ts +20 -0
  96. package/src/core/objects/collation/changes/collation.comment.ts +68 -0
  97. package/src/core/objects/collation/changes/collation.create.test.ts +51 -0
  98. package/src/core/objects/collation/changes/collation.create.ts +106 -0
  99. package/src/core/objects/collation/changes/collation.drop.test.ts +28 -0
  100. package/src/core/objects/collation/changes/collation.drop.ts +37 -0
  101. package/src/core/objects/collation/changes/collation.types.ts +10 -0
  102. package/src/core/objects/collation/collation.diff.test.ts +100 -0
  103. package/src/core/objects/collation/collation.diff.ts +126 -0
  104. package/src/core/objects/collation/collation.model.ts +224 -0
  105. package/src/core/objects/domain/changes/domain.alter.test.ts +316 -0
  106. package/src/core/objects/domain/changes/domain.alter.ts +286 -0
  107. package/src/core/objects/domain/changes/domain.base.ts +20 -0
  108. package/src/core/objects/domain/changes/domain.comment.ts +59 -0
  109. package/src/core/objects/domain/changes/domain.create.test.ts +65 -0
  110. package/src/core/objects/domain/changes/domain.create.ts +118 -0
  111. package/src/core/objects/domain/changes/domain.drop.test.ts +30 -0
  112. package/src/core/objects/domain/changes/domain.drop.ts +34 -0
  113. package/src/core/objects/domain/changes/domain.privilege.ts +171 -0
  114. package/src/core/objects/domain/changes/domain.types.ts +12 -0
  115. package/src/core/objects/domain/domain.diff.test.ts +284 -0
  116. package/src/core/objects/domain/domain.diff.ts +358 -0
  117. package/src/core/objects/domain/domain.model.ts +190 -0
  118. package/src/core/objects/event-trigger/changes/event-trigger.alter.test.ts +50 -0
  119. package/src/core/objects/event-trigger/changes/event-trigger.alter.ts +82 -0
  120. package/src/core/objects/event-trigger/changes/event-trigger.base.ts +20 -0
  121. package/src/core/objects/event-trigger/changes/event-trigger.comment.ts +66 -0
  122. package/src/core/objects/event-trigger/changes/event-trigger.create.test.ts +24 -0
  123. package/src/core/objects/event-trigger/changes/event-trigger.create.ts +72 -0
  124. package/src/core/objects/event-trigger/changes/event-trigger.drop.test.ts +22 -0
  125. package/src/core/objects/event-trigger/changes/event-trigger.drop.ts +34 -0
  126. package/src/core/objects/event-trigger/changes/event-trigger.types.ts +10 -0
  127. package/src/core/objects/event-trigger/event-trigger.diff.test.ts +126 -0
  128. package/src/core/objects/event-trigger/event-trigger.diff.ts +126 -0
  129. package/src/core/objects/event-trigger/event-trigger.model.ts +106 -0
  130. package/src/core/objects/extension/changes/extension.alter.test.ts +58 -0
  131. package/src/core/objects/extension/changes/extension.alter.ts +78 -0
  132. package/src/core/objects/extension/changes/extension.base.ts +20 -0
  133. package/src/core/objects/extension/changes/extension.comment.ts +64 -0
  134. package/src/core/objects/extension/changes/extension.create.test.ts +25 -0
  135. package/src/core/objects/extension/changes/extension.create.ts +63 -0
  136. package/src/core/objects/extension/changes/extension.drop.test.ts +23 -0
  137. package/src/core/objects/extension/changes/extension.drop.ts +34 -0
  138. package/src/core/objects/extension/changes/extension.types.ts +10 -0
  139. package/src/core/objects/extension/extension.diff.test.ts +42 -0
  140. package/src/core/objects/extension/extension.diff.ts +90 -0
  141. package/src/core/objects/extension/extension.model.ts +280 -0
  142. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.alter.test.ts +125 -0
  143. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.alter.ts +101 -0
  144. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.base.ts +20 -0
  145. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.comment.ts +72 -0
  146. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.create.test.ts +125 -0
  147. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.create.ts +95 -0
  148. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.drop.test.ts +23 -0
  149. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.drop.ts +36 -0
  150. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.privilege.ts +172 -0
  151. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.types.ts +12 -0
  152. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/foreign-data-wrapper.diff.test.ts +179 -0
  153. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/foreign-data-wrapper.diff.ts +341 -0
  154. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/foreign-data-wrapper.model.ts +149 -0
  155. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper.types.ts +10 -0
  156. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.alter.test.ts +309 -0
  157. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.alter.ts +341 -0
  158. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.base.ts +20 -0
  159. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.comment.ts +72 -0
  160. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.create.test.ts +201 -0
  161. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.create.ts +81 -0
  162. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.drop.test.ts +43 -0
  163. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.drop.ts +37 -0
  164. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.privilege.ts +181 -0
  165. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.types.ts +12 -0
  166. package/src/core/objects/foreign-data-wrapper/foreign-table/foreign-table.diff.test.ts +813 -0
  167. package/src/core/objects/foreign-data-wrapper/foreign-table/foreign-table.diff.ts +406 -0
  168. package/src/core/objects/foreign-data-wrapper/foreign-table/foreign-table.model.ts +242 -0
  169. package/src/core/objects/foreign-data-wrapper/server/changes/server.alter.test.ts +168 -0
  170. package/src/core/objects/foreign-data-wrapper/server/changes/server.alter.ts +126 -0
  171. package/src/core/objects/foreign-data-wrapper/server/changes/server.base.ts +20 -0
  172. package/src/core/objects/foreign-data-wrapper/server/changes/server.comment.ts +60 -0
  173. package/src/core/objects/foreign-data-wrapper/server/changes/server.create.test.ts +131 -0
  174. package/src/core/objects/foreign-data-wrapper/server/changes/server.create.ts +81 -0
  175. package/src/core/objects/foreign-data-wrapper/server/changes/server.drop.test.ts +24 -0
  176. package/src/core/objects/foreign-data-wrapper/server/changes/server.drop.ts +34 -0
  177. package/src/core/objects/foreign-data-wrapper/server/changes/server.privilege.ts +164 -0
  178. package/src/core/objects/foreign-data-wrapper/server/changes/server.types.ts +12 -0
  179. package/src/core/objects/foreign-data-wrapper/server/server.diff.test.ts +167 -0
  180. package/src/core/objects/foreign-data-wrapper/server/server.diff.ts +317 -0
  181. package/src/core/objects/foreign-data-wrapper/server/server.model.ts +133 -0
  182. package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.alter.test.ts +82 -0
  183. package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.alter.ts +69 -0
  184. package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.base.ts +20 -0
  185. package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.create.test.ts +85 -0
  186. package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.create.ts +66 -0
  187. package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.drop.test.ts +53 -0
  188. package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.drop.ts +40 -0
  189. package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.types.ts +8 -0
  190. package/src/core/objects/foreign-data-wrapper/user-mapping/user-mapping.diff.test.ts +77 -0
  191. package/src/core/objects/foreign-data-wrapper/user-mapping/user-mapping.diff.ts +107 -0
  192. package/src/core/objects/foreign-data-wrapper/user-mapping/user-mapping.model.ts +96 -0
  193. package/src/core/objects/index/changes/index.alter.test.ts +200 -0
  194. package/src/core/objects/index/changes/index.alter.ts +144 -0
  195. package/src/core/objects/index/changes/index.base.ts +20 -0
  196. package/src/core/objects/index/changes/index.comment.ts +63 -0
  197. package/src/core/objects/index/changes/index.create.test.ts +66 -0
  198. package/src/core/objects/index/changes/index.create.ts +68 -0
  199. package/src/core/objects/index/changes/index.drop.test.ts +44 -0
  200. package/src/core/objects/index/changes/index.drop.ts +34 -0
  201. package/src/core/objects/index/changes/index.types.ts +6 -0
  202. package/src/core/objects/index/changes/utils.ts +16 -0
  203. package/src/core/objects/index/index.diff.test.ts +153 -0
  204. package/src/core/objects/index/index.diff.ts +243 -0
  205. package/src/core/objects/index/index.model.ts +370 -0
  206. package/src/core/objects/language/changes/language.alter.test.ts +33 -0
  207. package/src/core/objects/language/changes/language.alter.ts +53 -0
  208. package/src/core/objects/language/changes/language.base.ts +20 -0
  209. package/src/core/objects/language/changes/language.comment.ts +58 -0
  210. package/src/core/objects/language/changes/language.create.test.ts +27 -0
  211. package/src/core/objects/language/changes/language.create.ts +104 -0
  212. package/src/core/objects/language/changes/language.drop.test.ts +25 -0
  213. package/src/core/objects/language/changes/language.drop.ts +39 -0
  214. package/src/core/objects/language/changes/language.privilege.ts +172 -0
  215. package/src/core/objects/language/changes/language.types.ts +12 -0
  216. package/src/core/objects/language/language.diff.test.ts +53 -0
  217. package/src/core/objects/language/language.diff.ts +176 -0
  218. package/src/core/objects/language/language.model.ts +150 -0
  219. package/src/core/objects/materialized-view/changes/materialized-view.alter.test.ts +123 -0
  220. package/src/core/objects/materialized-view/changes/materialized-view.alter.ts +113 -0
  221. package/src/core/objects/materialized-view/changes/materialized-view.base.ts +20 -0
  222. package/src/core/objects/materialized-view/changes/materialized-view.comment.ts +176 -0
  223. package/src/core/objects/materialized-view/changes/materialized-view.create.test.ts +64 -0
  224. package/src/core/objects/materialized-view/changes/materialized-view.create.ts +93 -0
  225. package/src/core/objects/materialized-view/changes/materialized-view.drop.test.ts +34 -0
  226. package/src/core/objects/materialized-view/changes/materialized-view.drop.ts +60 -0
  227. package/src/core/objects/materialized-view/changes/materialized-view.privilege.ts +212 -0
  228. package/src/core/objects/materialized-view/changes/materialized-view.types.ts +12 -0
  229. package/src/core/objects/materialized-view/materialized-view.diff.test.ts +102 -0
  230. package/src/core/objects/materialized-view/materialized-view.diff.ts +451 -0
  231. package/src/core/objects/materialized-view/materialized-view.model.ts +258 -0
  232. package/src/core/objects/procedure/changes/procedure.alter.test.ts +1005 -0
  233. package/src/core/objects/procedure/changes/procedure.alter.ts +287 -0
  234. package/src/core/objects/procedure/changes/procedure.base.ts +20 -0
  235. package/src/core/objects/procedure/changes/procedure.comment.ts +70 -0
  236. package/src/core/objects/procedure/changes/procedure.create.test.ts +48 -0
  237. package/src/core/objects/procedure/changes/procedure.create.ts +92 -0
  238. package/src/core/objects/procedure/changes/procedure.drop.test.ts +85 -0
  239. package/src/core/objects/procedure/changes/procedure.drop.ts +49 -0
  240. package/src/core/objects/procedure/changes/procedure.privilege.ts +188 -0
  241. package/src/core/objects/procedure/changes/procedure.types.ts +12 -0
  242. package/src/core/objects/procedure/procedure.diff.test.ts +161 -0
  243. package/src/core/objects/procedure/procedure.diff.ts +404 -0
  244. package/src/core/objects/procedure/procedure.model.ts +264 -0
  245. package/src/core/objects/procedure/utils.ts +58 -0
  246. package/src/core/objects/publication/changes/publication.alter.test.ts +223 -0
  247. package/src/core/objects/publication/changes/publication.alter.ts +243 -0
  248. package/src/core/objects/publication/changes/publication.base.ts +20 -0
  249. package/src/core/objects/publication/changes/publication.comment.test.ts +70 -0
  250. package/src/core/objects/publication/changes/publication.comment.ts +64 -0
  251. package/src/core/objects/publication/changes/publication.create.test.ts +87 -0
  252. package/src/core/objects/publication/changes/publication.create.ts +82 -0
  253. package/src/core/objects/publication/changes/publication.drop.test.ts +46 -0
  254. package/src/core/objects/publication/changes/publication.drop.ts +29 -0
  255. package/src/core/objects/publication/changes/publication.types.ts +26 -0
  256. package/src/core/objects/publication/publication.diff.test.ts +292 -0
  257. package/src/core/objects/publication/publication.diff.ts +253 -0
  258. package/src/core/objects/publication/publication.model.ts +206 -0
  259. package/src/core/objects/publication/utils.ts +55 -0
  260. package/src/core/objects/rls-policy/changes/rls-policy.alter.test.ts +250 -0
  261. package/src/core/objects/rls-policy/changes/rls-policy.alter.ts +128 -0
  262. package/src/core/objects/rls-policy/changes/rls-policy.base.ts +20 -0
  263. package/src/core/objects/rls-policy/changes/rls-policy.comment.ts +69 -0
  264. package/src/core/objects/rls-policy/changes/rls-policy.create.test.ts +74 -0
  265. package/src/core/objects/rls-policy/changes/rls-policy.create.ts +100 -0
  266. package/src/core/objects/rls-policy/changes/rls-policy.drop.test.ts +28 -0
  267. package/src/core/objects/rls-policy/changes/rls-policy.drop.ts +39 -0
  268. package/src/core/objects/rls-policy/changes/rls-policy.types.ts +10 -0
  269. package/src/core/objects/rls-policy/rls-policy.diff.test.ts +79 -0
  270. package/src/core/objects/rls-policy/rls-policy.diff.ts +121 -0
  271. package/src/core/objects/rls-policy/rls-policy.model.ts +140 -0
  272. package/src/core/objects/role/changes/role.alter.test.ts +346 -0
  273. package/src/core/objects/role/changes/role.alter.ts +110 -0
  274. package/src/core/objects/role/changes/role.base.ts +24 -0
  275. package/src/core/objects/role/changes/role.comment.ts +55 -0
  276. package/src/core/objects/role/changes/role.create.test.ts +52 -0
  277. package/src/core/objects/role/changes/role.create.ts +102 -0
  278. package/src/core/objects/role/changes/role.drop.test.ts +29 -0
  279. package/src/core/objects/role/changes/role.drop.ts +34 -0
  280. package/src/core/objects/role/changes/role.privilege.ts +376 -0
  281. package/src/core/objects/role/changes/role.types.ts +12 -0
  282. package/src/core/objects/role/role.diff.test.ts +44 -0
  283. package/src/core/objects/role/role.diff.ts +479 -0
  284. package/src/core/objects/role/role.model.ts +344 -0
  285. package/src/core/objects/rule/changes/rule.alter.test.ts +78 -0
  286. package/src/core/objects/rule/changes/rule.alter.ts +72 -0
  287. package/src/core/objects/rule/changes/rule.base.ts +20 -0
  288. package/src/core/objects/rule/changes/rule.comment.test.ts +55 -0
  289. package/src/core/objects/rule/changes/rule.comment.ts +62 -0
  290. package/src/core/objects/rule/changes/rule.create.test.ts +59 -0
  291. package/src/core/objects/rule/changes/rule.create.ts +42 -0
  292. package/src/core/objects/rule/changes/rule.drop.test.ts +38 -0
  293. package/src/core/objects/rule/changes/rule.drop.ts +29 -0
  294. package/src/core/objects/rule/changes/rule.types.ts +12 -0
  295. package/src/core/objects/rule/rule.diff.test.ts +132 -0
  296. package/src/core/objects/rule/rule.diff.ts +79 -0
  297. package/src/core/objects/rule/rule.model.ts +173 -0
  298. package/src/core/objects/schema/changes/schema.alter.test.ts +28 -0
  299. package/src/core/objects/schema/changes/schema.alter.ts +45 -0
  300. package/src/core/objects/schema/changes/schema.base.ts +20 -0
  301. package/src/core/objects/schema/changes/schema.comment.ts +56 -0
  302. package/src/core/objects/schema/changes/schema.create.test.ts +22 -0
  303. package/src/core/objects/schema/changes/schema.create.ts +47 -0
  304. package/src/core/objects/schema/changes/schema.drop.test.ts +20 -0
  305. package/src/core/objects/schema/changes/schema.drop.ts +34 -0
  306. package/src/core/objects/schema/changes/schema.privilege.ts +175 -0
  307. package/src/core/objects/schema/changes/schema.types.ts +12 -0
  308. package/src/core/objects/schema/schema.diff.test.ts +42 -0
  309. package/src/core/objects/schema/schema.diff.ts +209 -0
  310. package/src/core/objects/schema/schema.model.ts +107 -0
  311. package/src/core/objects/sequence/changes/sequence.alter.test.ts +151 -0
  312. package/src/core/objects/sequence/changes/sequence.alter.ts +115 -0
  313. package/src/core/objects/sequence/changes/sequence.base.ts +20 -0
  314. package/src/core/objects/sequence/changes/sequence.comment.ts +60 -0
  315. package/src/core/objects/sequence/changes/sequence.create.test.ts +84 -0
  316. package/src/core/objects/sequence/changes/sequence.create.ts +111 -0
  317. package/src/core/objects/sequence/changes/sequence.drop.test.ts +32 -0
  318. package/src/core/objects/sequence/changes/sequence.drop.ts +37 -0
  319. package/src/core/objects/sequence/changes/sequence.privilege.ts +179 -0
  320. package/src/core/objects/sequence/changes/sequence.types.ts +12 -0
  321. package/src/core/objects/sequence/sequence.diff.test.ts +141 -0
  322. package/src/core/objects/sequence/sequence.diff.ts +359 -0
  323. package/src/core/objects/sequence/sequence.model.ts +185 -0
  324. package/src/core/objects/subscription/changes/subscription.alter.test.ts +124 -0
  325. package/src/core/objects/subscription/changes/subscription.alter.ts +110 -0
  326. package/src/core/objects/subscription/changes/subscription.base.ts +20 -0
  327. package/src/core/objects/subscription/changes/subscription.comment.test.ts +67 -0
  328. package/src/core/objects/subscription/changes/subscription.comment.ts +64 -0
  329. package/src/core/objects/subscription/changes/subscription.create.test.ts +77 -0
  330. package/src/core/objects/subscription/changes/subscription.create.ts +69 -0
  331. package/src/core/objects/subscription/changes/subscription.drop.test.ts +46 -0
  332. package/src/core/objects/subscription/changes/subscription.drop.ts +20 -0
  333. package/src/core/objects/subscription/changes/subscription.types.ts +22 -0
  334. package/src/core/objects/subscription/subscription.diff.test.ts +232 -0
  335. package/src/core/objects/subscription/subscription.diff.ts +241 -0
  336. package/src/core/objects/subscription/subscription.model.ts +190 -0
  337. package/src/core/objects/subscription/utils.ts +156 -0
  338. package/src/core/objects/table/changes/table.alter.test.ts +823 -0
  339. package/src/core/objects/table/changes/table.alter.ts +806 -0
  340. package/src/core/objects/table/changes/table.base.ts +20 -0
  341. package/src/core/objects/table/changes/table.comment.ts +266 -0
  342. package/src/core/objects/table/changes/table.create.test.ts +150 -0
  343. package/src/core/objects/table/changes/table.create.ts +188 -0
  344. package/src/core/objects/table/changes/table.drop.test.ts +34 -0
  345. package/src/core/objects/table/changes/table.drop.ts +45 -0
  346. package/src/core/objects/table/changes/table.privilege.ts +200 -0
  347. package/src/core/objects/table/changes/table.types.ts +12 -0
  348. package/src/core/objects/table/table.diff.test.ts +711 -0
  349. package/src/core/objects/table/table.diff.ts +953 -0
  350. package/src/core/objects/table/table.model.ts +460 -0
  351. package/src/core/objects/trigger/changes/trigger.alter.test.ts +46 -0
  352. package/src/core/objects/trigger/changes/trigger.alter.ts +76 -0
  353. package/src/core/objects/trigger/changes/trigger.base.ts +20 -0
  354. package/src/core/objects/trigger/changes/trigger.comment.ts +64 -0
  355. package/src/core/objects/trigger/changes/trigger.create.test.ts +43 -0
  356. package/src/core/objects/trigger/changes/trigger.create.ts +85 -0
  357. package/src/core/objects/trigger/changes/trigger.drop.test.ts +43 -0
  358. package/src/core/objects/trigger/changes/trigger.drop.ts +39 -0
  359. package/src/core/objects/trigger/changes/trigger.types.ts +10 -0
  360. package/src/core/objects/trigger/trigger.diff.test.ts +83 -0
  361. package/src/core/objects/trigger/trigger.diff.ts +116 -0
  362. package/src/core/objects/trigger/trigger.model.ts +252 -0
  363. package/src/core/objects/type/composite-type/changes/composite-type.alter.test.ts +202 -0
  364. package/src/core/objects/type/composite-type/changes/composite-type.alter.ts +174 -0
  365. package/src/core/objects/type/composite-type/changes/composite-type.base.ts +20 -0
  366. package/src/core/objects/type/composite-type/changes/composite-type.comment.ts +145 -0
  367. package/src/core/objects/type/composite-type/changes/composite-type.create.test.ts +101 -0
  368. package/src/core/objects/type/composite-type/changes/composite-type.create.ts +95 -0
  369. package/src/core/objects/type/composite-type/changes/composite-type.drop.test.ts +33 -0
  370. package/src/core/objects/type/composite-type/changes/composite-type.drop.ts +37 -0
  371. package/src/core/objects/type/composite-type/changes/composite-type.privilege.ts +175 -0
  372. package/src/core/objects/type/composite-type/changes/composite-type.types.ts +12 -0
  373. package/src/core/objects/type/composite-type/composite-type.diff.test.ts +191 -0
  374. package/src/core/objects/type/composite-type/composite-type.diff.ts +372 -0
  375. package/src/core/objects/type/composite-type/composite-type.model.ts +252 -0
  376. package/src/core/objects/type/enum/changes/enum.alter.test.ts +104 -0
  377. package/src/core/objects/type/enum/changes/enum.alter.ts +91 -0
  378. package/src/core/objects/type/enum/changes/enum.base.ts +20 -0
  379. package/src/core/objects/type/enum/changes/enum.comment.ts +64 -0
  380. package/src/core/objects/type/enum/changes/enum.create.test.ts +28 -0
  381. package/src/core/objects/type/enum/changes/enum.create.ts +56 -0
  382. package/src/core/objects/type/enum/changes/enum.drop.test.ts +25 -0
  383. package/src/core/objects/type/enum/changes/enum.drop.ts +34 -0
  384. package/src/core/objects/type/enum/changes/enum.privilege.ts +175 -0
  385. package/src/core/objects/type/enum/changes/enum.types.ts +12 -0
  386. package/src/core/objects/type/enum/enum.diff.test.ts +191 -0
  387. package/src/core/objects/type/enum/enum.diff.ts +396 -0
  388. package/src/core/objects/type/enum/enum.model.ts +194 -0
  389. package/src/core/objects/type/range/changes/range.alter.test.ts +27 -0
  390. package/src/core/objects/type/range/changes/range.alter.ts +51 -0
  391. package/src/core/objects/type/range/changes/range.base.ts +20 -0
  392. package/src/core/objects/type/range/changes/range.comment.ts +64 -0
  393. package/src/core/objects/type/range/changes/range.create.test.ts +51 -0
  394. package/src/core/objects/type/range/changes/range.create.ts +151 -0
  395. package/src/core/objects/type/range/changes/range.drop.test.ts +26 -0
  396. package/src/core/objects/type/range/changes/range.drop.ts +34 -0
  397. package/src/core/objects/type/range/changes/range.privilege.ts +175 -0
  398. package/src/core/objects/type/range/changes/range.types.ts +12 -0
  399. package/src/core/objects/type/range/range.diff.test.ts +70 -0
  400. package/src/core/objects/type/range/range.diff.ts +259 -0
  401. package/src/core/objects/type/range/range.model.ts +187 -0
  402. package/src/core/objects/type/type.types.ts +5 -0
  403. package/src/core/objects/utils.ts +171 -0
  404. package/src/core/objects/view/changes/view.alter.test.ts +110 -0
  405. package/src/core/objects/view/changes/view.alter.ts +112 -0
  406. package/src/core/objects/view/changes/view.base.ts +20 -0
  407. package/src/core/objects/view/changes/view.comment.ts +59 -0
  408. package/src/core/objects/view/changes/view.create.test.ts +65 -0
  409. package/src/core/objects/view/changes/view.create.ts +73 -0
  410. package/src/core/objects/view/changes/view.drop.test.ts +34 -0
  411. package/src/core/objects/view/changes/view.drop.ts +40 -0
  412. package/src/core/objects/view/changes/view.privilege.ts +200 -0
  413. package/src/core/objects/view/changes/view.types.ts +12 -0
  414. package/src/core/objects/view/view.diff.test.ts +91 -0
  415. package/src/core/objects/view/view.diff.ts +365 -0
  416. package/src/core/objects/view/view.model.ts +276 -0
  417. package/src/core/plan/apply.ts +190 -0
  418. package/src/core/plan/create.ts +432 -0
  419. package/src/core/plan/hierarchy.ts +574 -0
  420. package/src/core/plan/index.ts +29 -0
  421. package/src/core/plan/io.ts +20 -0
  422. package/src/core/plan/risk.ts +48 -0
  423. package/src/core/plan/serialize.ts +195 -0
  424. package/src/core/plan/sql-format/constants.ts +13 -0
  425. package/src/core/plan/sql-format/fixtures.ts +2806 -0
  426. package/src/core/plan/sql-format/format-comment-literals.test.ts +96 -0
  427. package/src/core/plan/sql-format/format-functions.test.ts +127 -0
  428. package/src/core/plan/sql-format/format-lowercase-coverage.test.ts +67 -0
  429. package/src/core/plan/sql-format/format-off.test.ts +809 -0
  430. package/src/core/plan/sql-format/format-pretty-lower-leading.test.ts +1056 -0
  431. package/src/core/plan/sql-format/format-pretty-narrow.test.ts +1283 -0
  432. package/src/core/plan/sql-format/format-pretty-preserve.test.ts +1052 -0
  433. package/src/core/plan/sql-format/format-pretty-upper.test.ts +1045 -0
  434. package/src/core/plan/sql-format/format-stress.test.ts +616 -0
  435. package/src/core/plan/sql-format/format-utils.test.ts +91 -0
  436. package/src/core/plan/sql-format/format-utils.ts +391 -0
  437. package/src/core/plan/sql-format/formatters.ts +921 -0
  438. package/src/core/plan/sql-format/index.ts +149 -0
  439. package/src/core/plan/sql-format/keyword-case.test.ts +118 -0
  440. package/src/core/plan/sql-format/keyword-case.ts +1085 -0
  441. package/src/core/plan/sql-format/protect.test.ts +127 -0
  442. package/src/core/plan/sql-format/protect.ts +337 -0
  443. package/src/core/plan/sql-format/sql-scanner.test.ts +240 -0
  444. package/src/core/plan/sql-format/sql-scanner.ts +252 -0
  445. package/src/core/plan/sql-format/tokenizer.test.ts +68 -0
  446. package/src/core/plan/sql-format/tokenizer.ts +152 -0
  447. package/src/core/plan/sql-format/types.ts +31 -0
  448. package/src/core/plan/sql-format/wrap.test.ts +119 -0
  449. package/src/core/plan/sql-format/wrap.ts +196 -0
  450. package/src/core/plan/sql-format.ts +2 -0
  451. package/src/core/plan/statements.ts +22 -0
  452. package/src/core/plan/types.ts +165 -0
  453. package/src/core/postgres-config.ts +169 -0
  454. package/src/core/sort/custom-constraints.ts +161 -0
  455. package/src/core/sort/debug-visualization.ts +239 -0
  456. package/src/core/sort/dependency-filter.ts +224 -0
  457. package/src/core/sort/graph-builder.ts +223 -0
  458. package/src/core/sort/graph-utils.ts +51 -0
  459. package/src/core/sort/logical-sort.ts +590 -0
  460. package/src/core/sort/sort-changes.ts +234 -0
  461. package/src/core/sort/topological-sort.ts +184 -0
  462. package/src/core/sort/types.ts +112 -0
  463. package/src/core/sort/utils.ts +69 -0
  464. package/src/index.ts +14 -0
@@ -0,0 +1,276 @@
1
+ import { sql } from "@ts-safeql/sql-tag";
2
+ import type { Pool } from "pg";
3
+ import z from "zod";
4
+ import {
5
+ BasePgModel,
6
+ columnPropsSchema,
7
+ type TableLikeObject,
8
+ } from "../base.model.ts";
9
+ import {
10
+ type PrivilegeProps,
11
+ privilegePropsSchema,
12
+ } from "../base.privilege-diff.ts";
13
+ import { ReplicaIdentitySchema } from "../table/table.model.ts";
14
+
15
+ const viewPropsSchema = z.object({
16
+ schema: z.string(),
17
+ name: z.string(),
18
+ definition: z.string(),
19
+ row_security: z.boolean(),
20
+ force_row_security: z.boolean(),
21
+ has_indexes: z.boolean(),
22
+ has_rules: z.boolean(),
23
+ has_triggers: z.boolean(),
24
+ has_subclasses: z.boolean(),
25
+ is_populated: z.boolean(),
26
+ replica_identity: ReplicaIdentitySchema,
27
+ is_partition: z.boolean(),
28
+ options: z.array(z.string()).nullable(),
29
+ partition_bound: z.string().nullable(),
30
+ owner: z.string(),
31
+ comment: z.string().nullable(),
32
+ columns: z.array(columnPropsSchema),
33
+ privileges: z.array(privilegePropsSchema),
34
+ });
35
+
36
+ type ViewPrivilegeProps = PrivilegeProps;
37
+ export type ViewProps = z.infer<typeof viewPropsSchema>;
38
+
39
+ export class View extends BasePgModel implements TableLikeObject {
40
+ public readonly schema: ViewProps["schema"];
41
+ public readonly name: ViewProps["name"];
42
+ public readonly definition: ViewProps["definition"];
43
+ public readonly row_security: ViewProps["row_security"];
44
+ public readonly force_row_security: ViewProps["force_row_security"];
45
+ public readonly has_indexes: ViewProps["has_indexes"];
46
+ public readonly has_rules: ViewProps["has_rules"];
47
+ public readonly has_triggers: ViewProps["has_triggers"];
48
+ public readonly has_subclasses: ViewProps["has_subclasses"];
49
+ public readonly is_populated: ViewProps["is_populated"];
50
+ public readonly replica_identity: ViewProps["replica_identity"];
51
+ public readonly is_partition: ViewProps["is_partition"];
52
+ public readonly options: ViewProps["options"];
53
+ public readonly partition_bound: ViewProps["partition_bound"];
54
+ public readonly owner: ViewProps["owner"];
55
+ public readonly comment: ViewProps["comment"];
56
+ public readonly columns: ViewProps["columns"];
57
+ public readonly privileges: ViewPrivilegeProps[];
58
+
59
+ constructor(props: ViewProps) {
60
+ super();
61
+
62
+ // Identity fields
63
+ this.schema = props.schema;
64
+ this.name = props.name;
65
+
66
+ // Data fields
67
+ this.definition = props.definition;
68
+ this.row_security = props.row_security;
69
+ this.force_row_security = props.force_row_security;
70
+ this.has_indexes = props.has_indexes;
71
+ this.has_rules = props.has_rules;
72
+ this.has_triggers = props.has_triggers;
73
+ this.has_subclasses = props.has_subclasses;
74
+ this.is_populated = props.is_populated;
75
+ this.replica_identity = props.replica_identity;
76
+ this.is_partition = props.is_partition;
77
+ this.options = props.options;
78
+ this.partition_bound = props.partition_bound;
79
+ this.owner = props.owner;
80
+ this.comment = props.comment;
81
+ this.columns = props.columns;
82
+ this.privileges = props.privileges;
83
+ }
84
+
85
+ get stableId(): `view:${string}` {
86
+ return `view:${this.schema}.${this.name}`;
87
+ }
88
+
89
+ get identityFields() {
90
+ return {
91
+ schema: this.schema,
92
+ name: this.name,
93
+ };
94
+ }
95
+
96
+ get dataFields() {
97
+ return {
98
+ definition: this.definition,
99
+ row_security: this.row_security,
100
+ force_row_security: this.force_row_security,
101
+ has_indexes: this.has_indexes,
102
+ has_rules: this.has_rules,
103
+ has_triggers: this.has_triggers,
104
+ has_subclasses: this.has_subclasses,
105
+ is_populated: this.is_populated,
106
+ replica_identity: this.replica_identity,
107
+ is_partition: this.is_partition,
108
+ options: this.options,
109
+ partition_bound: this.partition_bound,
110
+ owner: this.owner,
111
+ comment: this.comment,
112
+ columns: this.columns,
113
+ privileges: this.privileges,
114
+ };
115
+ }
116
+
117
+ override stableSnapshot() {
118
+ const normalizeColumns = () =>
119
+ [...this.columns]
120
+ .map((col) => {
121
+ const { position: _pos, ...rest } = col as unknown as Record<
122
+ string,
123
+ unknown
124
+ >;
125
+ return rest;
126
+ })
127
+ .sort((a, b) => {
128
+ const nameA = (a.name as string | undefined) ?? "";
129
+ const nameB = (b.name as string | undefined) ?? "";
130
+ return nameA.localeCompare(nameB);
131
+ });
132
+
133
+ return {
134
+ identity: this.identityFields,
135
+ data: {
136
+ ...this.dataFields,
137
+ columns: normalizeColumns(),
138
+ },
139
+ };
140
+ }
141
+ }
142
+
143
+ export async function extractViews(pool: Pool): Promise<View[]> {
144
+ const { rows: viewRows } = await pool.query<ViewProps>(sql`
145
+ with extension_oids as (
146
+ select
147
+ objid
148
+ from
149
+ pg_depend d
150
+ where
151
+ d.refclassid = 'pg_extension'::regclass
152
+ and d.classid = 'pg_class'::regclass
153
+ ), views as (
154
+ select
155
+ c.relnamespace::regnamespace::text as schema,
156
+ quote_ident(c.relname) as name,
157
+ rtrim(pg_get_viewdef(c.oid), ';') as definition,
158
+ c.relrowsecurity as row_security,
159
+ c.relforcerowsecurity as force_row_security,
160
+ c.relhasindex as has_indexes,
161
+ c.relhasrules as has_rules,
162
+ c.relhastriggers as has_triggers,
163
+ c.relhassubclass as has_subclasses,
164
+ c.relispopulated as is_populated,
165
+ c.relreplident as replica_identity,
166
+ c.relispartition as is_partition,
167
+ c.reloptions as options,
168
+ pg_get_expr(c.relpartbound, c.oid) as partition_bound,
169
+ c.relowner::regrole::text as owner,
170
+ obj_description(c.oid, 'pg_class') as comment,
171
+ c.oid as oid
172
+ from
173
+ pg_catalog.pg_class c
174
+ left outer join extension_oids e on c.oid = e.objid
175
+ where not c.relnamespace::regnamespace::text like any(array['pg\\_%', 'information\\_schema'])
176
+ and e.objid is null
177
+ and c.relkind = 'v'
178
+ )
179
+ select
180
+ v.schema,
181
+ v.name,
182
+ v.definition,
183
+ v.row_security,
184
+ v.force_row_security,
185
+ v.has_indexes,
186
+ v.has_rules,
187
+ v.has_triggers,
188
+ v.has_subclasses,
189
+ v.is_populated,
190
+ v.replica_identity,
191
+ v.is_partition,
192
+ v.options,
193
+ v.partition_bound,
194
+ v.owner,
195
+ v.comment,
196
+ coalesce(json_agg(
197
+ case when a.attname is not null then
198
+ json_build_object(
199
+ 'name', quote_ident(a.attname),
200
+ 'position', a.attnum,
201
+ 'data_type', a.atttypid::regtype::text,
202
+ 'data_type_str', format_type(a.atttypid, a.atttypmod),
203
+ 'is_custom_type', ty.typnamespace::regnamespace::text not in ('pg_catalog', 'information_schema'),
204
+ 'custom_type_type', case when ty.typnamespace::regnamespace::text not in ('pg_catalog', 'information_schema') then ty.typtype else null end,
205
+ 'custom_type_category', case when ty.typnamespace::regnamespace::text not in ('pg_catalog', 'information_schema') then ty.typcategory else null end,
206
+ 'custom_type_schema', case when ty.typnamespace::regnamespace::text not in ('pg_catalog', 'information_schema') then ty.typnamespace::regnamespace else null end,
207
+ 'custom_type_name', case when ty.typnamespace::regnamespace::text not in ('pg_catalog', 'information_schema') then quote_ident(ty.typname) else null end,
208
+ 'not_null', a.attnotnull,
209
+ 'is_identity', a.attidentity != '',
210
+ 'is_identity_always', a.attidentity = 'a',
211
+ 'is_generated', a.attgenerated != '',
212
+ 'collation', (
213
+ select quote_ident(c2.collname)
214
+ from pg_collation c2, pg_type t2
215
+ where c2.oid = a.attcollation
216
+ and t2.oid = a.atttypid
217
+ and a.attcollation <> t2.typcollation
218
+ ),
219
+ 'default', pg_get_expr(ad.adbin, ad.adrelid),
220
+ 'comment', col_description(a.attrelid, a.attnum)
221
+ )
222
+ end
223
+ order by a.attnum
224
+ ) filter (where a.attname is not null), '[]') as columns,
225
+ coalesce((
226
+ select json_agg(
227
+ json_build_object(
228
+ 'grantee', case when grp.grantee = 0 then 'PUBLIC' else grp.grantee::regrole::text end,
229
+ 'privilege', grp.privilege_type,
230
+ 'grantable', grp.is_grantable,
231
+ 'columns', case when grp.cols is not null and array_length(grp.cols,1) > 0
232
+ then grp.cols
233
+ else null end
234
+ )
235
+ order by grp.grantee, grp.privilege_type
236
+ )
237
+ from (
238
+ select
239
+ x.grantee,
240
+ x.privilege_type,
241
+ bool_or(x.is_grantable) as is_grantable,
242
+ array_agg(quote_ident(src.attname) order by src.attname)
243
+ filter (where src.attname is not null) as cols
244
+ from (
245
+ -- one row for object ACL + one row per column ACL
246
+ select null::name as attname, v.oid as relacl_oid, (
247
+ select c_rel.relacl from pg_class c_rel where c_rel.oid = v.oid
248
+ ) as acl
249
+ union all
250
+ select a2.attname, v.oid as relacl_oid, a2.attacl
251
+ from pg_attribute a2
252
+ where a2.attrelid = v.oid
253
+ and a2.attnum > 0
254
+ and not a2.attisdropped
255
+ and a2.attacl is not null
256
+ ) as src
257
+ join lateral aclexplode(src.acl) as x(grantor, grantee, privilege_type, is_grantable) on true
258
+ group by x.grantee, x.privilege_type
259
+ ) as grp
260
+ ), '[]') as privileges
261
+ from
262
+ views v
263
+ left join pg_attribute a on a.attrelid = v.oid and a.attnum > 0 and not a.attisdropped
264
+ left join pg_attrdef ad on a.attrelid = ad.adrelid and a.attnum = ad.adnum
265
+ left join pg_type ty on ty.oid = a.atttypid
266
+ group by
267
+ v.oid, v.schema, v.name, v.definition, v.row_security, v.force_row_security, v.has_indexes, v.has_rules, v.has_triggers, v.has_subclasses, v.is_populated, v.replica_identity, v.is_partition, v.options, v.partition_bound, v.owner, v.comment
268
+ order by
269
+ v.schema, v.name
270
+ `);
271
+ // Validate and parse each row using the Zod schema
272
+ const validatedRows = viewRows.map((row: unknown) =>
273
+ viewPropsSchema.parse(row),
274
+ );
275
+ return validatedRows.map((row: ViewProps) => new View(row));
276
+ }
@@ -0,0 +1,190 @@
1
+ /**
2
+ * Plan application - execute migration plans against target databases.
3
+ */
4
+
5
+ import type { Pool } from "pg";
6
+ import { escapeIdentifier } from "pg";
7
+ import { diffCatalogs } from "../catalog.diff.ts";
8
+ import { extractCatalog } from "../catalog.model.ts";
9
+ import type { DiffContext } from "../context.ts";
10
+ import { buildPlanScopeFingerprint, hashStableIds } from "../fingerprint.ts";
11
+ import { compileFilterDSL } from "../integrations/filter/dsl.ts";
12
+ import { createPool, endPool } from "../postgres-config.ts";
13
+ import { sortChanges } from "../sort/sort-changes.ts";
14
+ import type { Plan } from "./types.ts";
15
+
16
+ type ApplyPlanResult =
17
+ | { status: "invalid_plan"; message: string }
18
+ | { status: "fingerprint_mismatch"; current: string; expected: string }
19
+ | { status: "already_applied" }
20
+ | { status: "applied"; statements: number; warnings?: string[] }
21
+ | { status: "failed"; error: unknown; script: string };
22
+
23
+ interface ApplyPlanOptions {
24
+ verifyPostApply?: boolean;
25
+ }
26
+
27
+ type ConnectionInput = string | Pool;
28
+
29
+ /**
30
+ * Check if a statement is a session configuration statement (standalone SET statements).
31
+ * These statements should not be counted as changes.
32
+ */
33
+ function isSessionStatement(statement: string): boolean {
34
+ return statement.trim().startsWith("SET ");
35
+ }
36
+
37
+ /**
38
+ * Apply a plan's SQL statements to a target database with integrity checks.
39
+ * Validates fingerprints before and after application to ensure plan integrity.
40
+ */
41
+
42
+ export async function applyPlan(
43
+ plan: Plan,
44
+ source: ConnectionInput,
45
+ target: ConnectionInput,
46
+ options: ApplyPlanOptions = {},
47
+ ): Promise<ApplyPlanResult> {
48
+ if (!plan.statements || plan.statements.length === 0) {
49
+ return {
50
+ status: "invalid_plan",
51
+ message: "Plan contains no SQL statements to execute.",
52
+ };
53
+ }
54
+
55
+ let currentPool: Pool;
56
+ let desiredPool: Pool;
57
+ let shouldCloseCurrent = false;
58
+ let shouldCloseDesired = false;
59
+
60
+ // Suppress expected shutdown errors from idle pool connections (57P01 = admin_shutdown)
61
+ const onError = (err: Error & { code?: string }) => {
62
+ if (err.code !== "57P01") {
63
+ console.error("Pool error:", err);
64
+ }
65
+ };
66
+
67
+ if (typeof source === "string") {
68
+ currentPool = createPool(source, {
69
+ onError,
70
+ onConnect: async (client) => {
71
+ // Force fully qualified names in catalog queries for fingerprint verification
72
+ await client.query("SET search_path = ''");
73
+ if (plan.role) {
74
+ await client.query(`SET ROLE ${escapeIdentifier(plan.role)}`);
75
+ }
76
+ },
77
+ });
78
+ shouldCloseCurrent = true;
79
+ } else {
80
+ currentPool = source;
81
+ }
82
+
83
+ if (typeof target === "string") {
84
+ desiredPool = createPool(target, {
85
+ onError,
86
+ onConnect: async (client) => {
87
+ // Force fully qualified names in catalog queries for fingerprint verification
88
+ await client.query("SET search_path = ''");
89
+ if (plan.role) {
90
+ await client.query(`SET ROLE ${escapeIdentifier(plan.role)}`);
91
+ }
92
+ },
93
+ });
94
+ shouldCloseDesired = true;
95
+ } else {
96
+ desiredPool = target;
97
+ }
98
+
99
+ try {
100
+ // Recompute stableIds and fingerprints from current and desired catalogs
101
+ const [currentCatalog, desiredCatalog] = await Promise.all([
102
+ extractCatalog(currentPool),
103
+ extractCatalog(desiredPool),
104
+ ]);
105
+
106
+ const changes = diffCatalogs(currentCatalog, desiredCatalog);
107
+ const ctx: DiffContext = {
108
+ mainCatalog: currentCatalog,
109
+ branchCatalog: desiredCatalog,
110
+ };
111
+
112
+ // Apply the same filter that was used to create the plan (if any)
113
+ let filteredChanges = changes;
114
+ if (plan.filter) {
115
+ const filterFn = compileFilterDSL(plan.filter);
116
+ filteredChanges = filteredChanges.filter((change) => filterFn(change));
117
+ }
118
+
119
+ const sortedChanges = sortChanges(ctx, filteredChanges);
120
+ const { hash: fingerprintFrom, stableIds } = buildPlanScopeFingerprint(
121
+ ctx.mainCatalog,
122
+ sortedChanges,
123
+ );
124
+ // We intentionally recompute target fingerprint only after applying.
125
+
126
+ // Pre-apply fingerprint validation
127
+ if (fingerprintFrom === plan.target.fingerprint) {
128
+ return { status: "already_applied" };
129
+ }
130
+
131
+ if (fingerprintFrom !== plan.source.fingerprint) {
132
+ return {
133
+ status: "fingerprint_mismatch",
134
+ current: fingerprintFrom,
135
+ expected: plan.source.fingerprint,
136
+ };
137
+ }
138
+
139
+ // Execute the SQL script
140
+ // TODO: mark statements that can't be run within a transaction
141
+ const statements = plan.statements;
142
+
143
+ const script = (() => {
144
+ const joined = statements.join(";\n");
145
+ return joined.endsWith(";") ? joined : `${joined};`;
146
+ })();
147
+
148
+ try {
149
+ await currentPool.query(script);
150
+ } catch (error) {
151
+ return { status: "failed", error, script };
152
+ }
153
+
154
+ const warnings: string[] = [];
155
+
156
+ if (options.verifyPostApply !== false) {
157
+ try {
158
+ const updatedCatalog = await extractCatalog(currentPool);
159
+ const updatedFingerprint = hashStableIds(updatedCatalog, stableIds);
160
+ if (updatedFingerprint !== plan.target.fingerprint) {
161
+ warnings.push(
162
+ "Post-apply fingerprint does not match the plan target fingerprint.",
163
+ );
164
+ }
165
+ } catch (error) {
166
+ warnings.push(
167
+ `Could not verify post-apply fingerprint: ${error instanceof Error ? error.message : String(error)}`,
168
+ );
169
+ }
170
+ }
171
+
172
+ // Count only actual changes, excluding session configuration statements
173
+ const changeStatements = statements.filter(
174
+ (stmt) => !isSessionStatement(stmt),
175
+ );
176
+
177
+ return {
178
+ status: "applied",
179
+ statements: changeStatements.length,
180
+ warnings: warnings.length ? warnings : undefined,
181
+ };
182
+ } finally {
183
+ const closers: Promise<unknown>[] = [];
184
+ if (shouldCloseCurrent) closers.push(endPool(currentPool));
185
+ if (shouldCloseDesired) closers.push(endPool(desiredPool));
186
+ if (closers.length) {
187
+ await Promise.all(closers);
188
+ }
189
+ }
190
+ }