@supabase/pg-delta 1.0.0-alpha.3 → 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 (463) 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/objects/table/table.model.d.ts +4 -2
  7. package/dist/core/objects/table/table.model.js +3 -0
  8. package/dist/core/objects/trigger/changes/trigger.alter.js +23 -0
  9. package/dist/core/objects/trigger/changes/trigger.create.js +2 -1
  10. package/dist/core/objects/trigger/trigger.model.d.ts +1 -0
  11. package/dist/core/objects/trigger/trigger.model.js +3 -0
  12. package/dist/core/plan/apply.js +3 -3
  13. package/dist/core/plan/create.js +34 -15
  14. package/dist/core/plan/sql-format/constants.d.ts +2 -0
  15. package/dist/core/plan/sql-format/constants.js +11 -0
  16. package/dist/core/plan/sql-format/fixtures.d.ts +2 -0
  17. package/dist/core/plan/sql-format/fixtures.js +2449 -0
  18. package/dist/core/plan/sql-format/format-utils.d.ts +37 -0
  19. package/dist/core/plan/sql-format/format-utils.js +274 -0
  20. package/dist/core/plan/sql-format/formatters.d.ts +20 -0
  21. package/dist/core/plan/sql-format/formatters.js +737 -0
  22. package/dist/core/plan/sql-format/index.d.ts +2 -0
  23. package/dist/core/plan/sql-format/index.js +98 -0
  24. package/dist/core/plan/sql-format/keyword-case.d.ts +2 -0
  25. package/dist/core/plan/sql-format/keyword-case.js +868 -0
  26. package/dist/core/plan/sql-format/protect.d.ts +3 -0
  27. package/dist/core/plan/sql-format/protect.js +269 -0
  28. package/dist/core/plan/sql-format/sql-scanner.d.ts +59 -0
  29. package/dist/core/plan/sql-format/sql-scanner.js +202 -0
  30. package/dist/core/plan/sql-format/tokenizer.d.ts +22 -0
  31. package/dist/core/plan/sql-format/tokenizer.js +118 -0
  32. package/dist/core/plan/sql-format/types.d.ts +28 -0
  33. package/dist/core/plan/sql-format/types.js +1 -0
  34. package/dist/core/plan/sql-format/wrap.d.ts +2 -0
  35. package/dist/core/plan/sql-format/wrap.js +165 -0
  36. package/dist/core/plan/sql-format.d.ts +2 -0
  37. package/dist/core/plan/sql-format.js +1 -0
  38. package/dist/core/plan/statements.d.ts +2 -1
  39. package/dist/core/plan/statements.js +6 -2
  40. package/dist/core/postgres-config.d.ts +15 -0
  41. package/dist/core/postgres-config.js +30 -0
  42. package/dist/index.d.ts +2 -0
  43. package/dist/index.js +1 -0
  44. package/package.json +37 -22
  45. package/src/cli/app.ts +28 -0
  46. package/src/cli/bin/cli.ts +9 -0
  47. package/src/cli/commands/apply.ts +101 -0
  48. package/src/cli/commands/plan.ts +195 -0
  49. package/src/cli/commands/sync.ts +185 -0
  50. package/src/cli/formatters/index.ts +5 -0
  51. package/src/cli/formatters/tree/tree-builder.ts +380 -0
  52. package/src/cli/formatters/tree/tree-renderer.ts +372 -0
  53. package/src/cli/formatters/tree/tree.ts +237 -0
  54. package/src/cli/utils/integrations.ts +42 -0
  55. package/src/cli/utils.ts +231 -0
  56. package/src/core/catalog.diff.ts +246 -0
  57. package/src/core/catalog.model.ts +384 -0
  58. package/src/core/change.types.ts +44 -0
  59. package/src/core/context.ts +26 -0
  60. package/src/core/depend.ts +1870 -0
  61. package/src/core/expand-replace-dependencies.ts +380 -0
  62. package/src/core/fingerprint.ts +204 -0
  63. package/src/core/integrations/filter/dsl.ts +204 -0
  64. package/src/core/integrations/filter/extractors.ts +145 -0
  65. package/src/core/integrations/filter/filter.types.ts +3 -0
  66. package/src/core/integrations/integration-dsl.ts +24 -0
  67. package/src/core/integrations/integration.types.ts +7 -0
  68. package/src/core/integrations/serialize/dsl.ts +77 -0
  69. package/src/core/integrations/serialize/serialize.types.ts +3 -0
  70. package/src/core/integrations/supabase.ts +121 -0
  71. package/src/core/objects/aggregate/aggregate.diff.test.ts +215 -0
  72. package/src/core/objects/aggregate/aggregate.diff.ts +278 -0
  73. package/src/core/objects/aggregate/aggregate.model.ts +317 -0
  74. package/src/core/objects/aggregate/changes/aggregate.alter.test.ts +64 -0
  75. package/src/core/objects/aggregate/changes/aggregate.alter.ts +32 -0
  76. package/src/core/objects/aggregate/changes/aggregate.base.ts +20 -0
  77. package/src/core/objects/aggregate/changes/aggregate.comment.test.ts +86 -0
  78. package/src/core/objects/aggregate/changes/aggregate.comment.ts +62 -0
  79. package/src/core/objects/aggregate/changes/aggregate.create.test.ts +101 -0
  80. package/src/core/objects/aggregate/changes/aggregate.create.ts +329 -0
  81. package/src/core/objects/aggregate/changes/aggregate.drop.test.ts +78 -0
  82. package/src/core/objects/aggregate/changes/aggregate.drop.ts +32 -0
  83. package/src/core/objects/aggregate/changes/aggregate.privilege.test.ts +130 -0
  84. package/src/core/objects/aggregate/changes/aggregate.privilege.ts +146 -0
  85. package/src/core/objects/aggregate/changes/aggregate.types.ts +12 -0
  86. package/src/core/objects/base.change.ts +62 -0
  87. package/src/core/objects/base.default-privileges.ts +204 -0
  88. package/src/core/objects/base.diff.ts +20 -0
  89. package/src/core/objects/base.model.ts +82 -0
  90. package/src/core/objects/base.privilege-diff.ts +299 -0
  91. package/src/core/objects/base.privilege.ts +184 -0
  92. package/src/core/objects/collation/changes/collation.alter.test.ts +63 -0
  93. package/src/core/objects/collation/changes/collation.alter.ts +79 -0
  94. package/src/core/objects/collation/changes/collation.base.ts +20 -0
  95. package/src/core/objects/collation/changes/collation.comment.ts +68 -0
  96. package/src/core/objects/collation/changes/collation.create.test.ts +51 -0
  97. package/src/core/objects/collation/changes/collation.create.ts +106 -0
  98. package/src/core/objects/collation/changes/collation.drop.test.ts +28 -0
  99. package/src/core/objects/collation/changes/collation.drop.ts +37 -0
  100. package/src/core/objects/collation/changes/collation.types.ts +10 -0
  101. package/src/core/objects/collation/collation.diff.test.ts +100 -0
  102. package/src/core/objects/collation/collation.diff.ts +126 -0
  103. package/src/core/objects/collation/collation.model.ts +224 -0
  104. package/src/core/objects/domain/changes/domain.alter.test.ts +316 -0
  105. package/src/core/objects/domain/changes/domain.alter.ts +286 -0
  106. package/src/core/objects/domain/changes/domain.base.ts +20 -0
  107. package/src/core/objects/domain/changes/domain.comment.ts +59 -0
  108. package/src/core/objects/domain/changes/domain.create.test.ts +65 -0
  109. package/src/core/objects/domain/changes/domain.create.ts +118 -0
  110. package/src/core/objects/domain/changes/domain.drop.test.ts +30 -0
  111. package/src/core/objects/domain/changes/domain.drop.ts +34 -0
  112. package/src/core/objects/domain/changes/domain.privilege.ts +171 -0
  113. package/src/core/objects/domain/changes/domain.types.ts +12 -0
  114. package/src/core/objects/domain/domain.diff.test.ts +284 -0
  115. package/src/core/objects/domain/domain.diff.ts +358 -0
  116. package/src/core/objects/domain/domain.model.ts +190 -0
  117. package/src/core/objects/event-trigger/changes/event-trigger.alter.test.ts +50 -0
  118. package/src/core/objects/event-trigger/changes/event-trigger.alter.ts +82 -0
  119. package/src/core/objects/event-trigger/changes/event-trigger.base.ts +20 -0
  120. package/src/core/objects/event-trigger/changes/event-trigger.comment.ts +66 -0
  121. package/src/core/objects/event-trigger/changes/event-trigger.create.test.ts +24 -0
  122. package/src/core/objects/event-trigger/changes/event-trigger.create.ts +72 -0
  123. package/src/core/objects/event-trigger/changes/event-trigger.drop.test.ts +22 -0
  124. package/src/core/objects/event-trigger/changes/event-trigger.drop.ts +34 -0
  125. package/src/core/objects/event-trigger/changes/event-trigger.types.ts +10 -0
  126. package/src/core/objects/event-trigger/event-trigger.diff.test.ts +126 -0
  127. package/src/core/objects/event-trigger/event-trigger.diff.ts +126 -0
  128. package/src/core/objects/event-trigger/event-trigger.model.ts +106 -0
  129. package/src/core/objects/extension/changes/extension.alter.test.ts +58 -0
  130. package/src/core/objects/extension/changes/extension.alter.ts +78 -0
  131. package/src/core/objects/extension/changes/extension.base.ts +20 -0
  132. package/src/core/objects/extension/changes/extension.comment.ts +64 -0
  133. package/src/core/objects/extension/changes/extension.create.test.ts +25 -0
  134. package/src/core/objects/extension/changes/extension.create.ts +63 -0
  135. package/src/core/objects/extension/changes/extension.drop.test.ts +23 -0
  136. package/src/core/objects/extension/changes/extension.drop.ts +34 -0
  137. package/src/core/objects/extension/changes/extension.types.ts +10 -0
  138. package/src/core/objects/extension/extension.diff.test.ts +42 -0
  139. package/src/core/objects/extension/extension.diff.ts +90 -0
  140. package/src/core/objects/extension/extension.model.ts +280 -0
  141. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.alter.test.ts +125 -0
  142. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.alter.ts +101 -0
  143. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.base.ts +20 -0
  144. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.comment.ts +72 -0
  145. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.create.test.ts +125 -0
  146. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.create.ts +95 -0
  147. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.drop.test.ts +23 -0
  148. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.drop.ts +36 -0
  149. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.privilege.ts +172 -0
  150. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.types.ts +12 -0
  151. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/foreign-data-wrapper.diff.test.ts +179 -0
  152. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/foreign-data-wrapper.diff.ts +341 -0
  153. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/foreign-data-wrapper.model.ts +149 -0
  154. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper.types.ts +10 -0
  155. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.alter.test.ts +309 -0
  156. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.alter.ts +341 -0
  157. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.base.ts +20 -0
  158. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.comment.ts +72 -0
  159. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.create.test.ts +201 -0
  160. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.create.ts +81 -0
  161. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.drop.test.ts +43 -0
  162. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.drop.ts +37 -0
  163. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.privilege.ts +181 -0
  164. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.types.ts +12 -0
  165. package/src/core/objects/foreign-data-wrapper/foreign-table/foreign-table.diff.test.ts +813 -0
  166. package/src/core/objects/foreign-data-wrapper/foreign-table/foreign-table.diff.ts +406 -0
  167. package/src/core/objects/foreign-data-wrapper/foreign-table/foreign-table.model.ts +242 -0
  168. package/src/core/objects/foreign-data-wrapper/server/changes/server.alter.test.ts +168 -0
  169. package/src/core/objects/foreign-data-wrapper/server/changes/server.alter.ts +126 -0
  170. package/src/core/objects/foreign-data-wrapper/server/changes/server.base.ts +20 -0
  171. package/src/core/objects/foreign-data-wrapper/server/changes/server.comment.ts +60 -0
  172. package/src/core/objects/foreign-data-wrapper/server/changes/server.create.test.ts +131 -0
  173. package/src/core/objects/foreign-data-wrapper/server/changes/server.create.ts +81 -0
  174. package/src/core/objects/foreign-data-wrapper/server/changes/server.drop.test.ts +24 -0
  175. package/src/core/objects/foreign-data-wrapper/server/changes/server.drop.ts +34 -0
  176. package/src/core/objects/foreign-data-wrapper/server/changes/server.privilege.ts +164 -0
  177. package/src/core/objects/foreign-data-wrapper/server/changes/server.types.ts +12 -0
  178. package/src/core/objects/foreign-data-wrapper/server/server.diff.test.ts +167 -0
  179. package/src/core/objects/foreign-data-wrapper/server/server.diff.ts +317 -0
  180. package/src/core/objects/foreign-data-wrapper/server/server.model.ts +133 -0
  181. package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.alter.test.ts +82 -0
  182. package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.alter.ts +69 -0
  183. package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.base.ts +20 -0
  184. package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.create.test.ts +85 -0
  185. package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.create.ts +66 -0
  186. package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.drop.test.ts +53 -0
  187. package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.drop.ts +40 -0
  188. package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.types.ts +8 -0
  189. package/src/core/objects/foreign-data-wrapper/user-mapping/user-mapping.diff.test.ts +77 -0
  190. package/src/core/objects/foreign-data-wrapper/user-mapping/user-mapping.diff.ts +107 -0
  191. package/src/core/objects/foreign-data-wrapper/user-mapping/user-mapping.model.ts +96 -0
  192. package/src/core/objects/index/changes/index.alter.test.ts +200 -0
  193. package/src/core/objects/index/changes/index.alter.ts +144 -0
  194. package/src/core/objects/index/changes/index.base.ts +20 -0
  195. package/src/core/objects/index/changes/index.comment.ts +63 -0
  196. package/src/core/objects/index/changes/index.create.test.ts +66 -0
  197. package/src/core/objects/index/changes/index.create.ts +68 -0
  198. package/src/core/objects/index/changes/index.drop.test.ts +44 -0
  199. package/src/core/objects/index/changes/index.drop.ts +34 -0
  200. package/src/core/objects/index/changes/index.types.ts +6 -0
  201. package/src/core/objects/index/changes/utils.ts +16 -0
  202. package/src/core/objects/index/index.diff.test.ts +153 -0
  203. package/src/core/objects/index/index.diff.ts +243 -0
  204. package/src/core/objects/index/index.model.ts +370 -0
  205. package/src/core/objects/language/changes/language.alter.test.ts +33 -0
  206. package/src/core/objects/language/changes/language.alter.ts +53 -0
  207. package/src/core/objects/language/changes/language.base.ts +20 -0
  208. package/src/core/objects/language/changes/language.comment.ts +58 -0
  209. package/src/core/objects/language/changes/language.create.test.ts +27 -0
  210. package/src/core/objects/language/changes/language.create.ts +104 -0
  211. package/src/core/objects/language/changes/language.drop.test.ts +25 -0
  212. package/src/core/objects/language/changes/language.drop.ts +39 -0
  213. package/src/core/objects/language/changes/language.privilege.ts +172 -0
  214. package/src/core/objects/language/changes/language.types.ts +12 -0
  215. package/src/core/objects/language/language.diff.test.ts +53 -0
  216. package/src/core/objects/language/language.diff.ts +176 -0
  217. package/src/core/objects/language/language.model.ts +150 -0
  218. package/src/core/objects/materialized-view/changes/materialized-view.alter.test.ts +123 -0
  219. package/src/core/objects/materialized-view/changes/materialized-view.alter.ts +113 -0
  220. package/src/core/objects/materialized-view/changes/materialized-view.base.ts +20 -0
  221. package/src/core/objects/materialized-view/changes/materialized-view.comment.ts +176 -0
  222. package/src/core/objects/materialized-view/changes/materialized-view.create.test.ts +64 -0
  223. package/src/core/objects/materialized-view/changes/materialized-view.create.ts +93 -0
  224. package/src/core/objects/materialized-view/changes/materialized-view.drop.test.ts +34 -0
  225. package/src/core/objects/materialized-view/changes/materialized-view.drop.ts +60 -0
  226. package/src/core/objects/materialized-view/changes/materialized-view.privilege.ts +212 -0
  227. package/src/core/objects/materialized-view/changes/materialized-view.types.ts +12 -0
  228. package/src/core/objects/materialized-view/materialized-view.diff.test.ts +102 -0
  229. package/src/core/objects/materialized-view/materialized-view.diff.ts +451 -0
  230. package/src/core/objects/materialized-view/materialized-view.model.ts +258 -0
  231. package/src/core/objects/procedure/changes/procedure.alter.test.ts +1005 -0
  232. package/src/core/objects/procedure/changes/procedure.alter.ts +287 -0
  233. package/src/core/objects/procedure/changes/procedure.base.ts +20 -0
  234. package/src/core/objects/procedure/changes/procedure.comment.ts +70 -0
  235. package/src/core/objects/procedure/changes/procedure.create.test.ts +48 -0
  236. package/src/core/objects/procedure/changes/procedure.create.ts +92 -0
  237. package/src/core/objects/procedure/changes/procedure.drop.test.ts +85 -0
  238. package/src/core/objects/procedure/changes/procedure.drop.ts +49 -0
  239. package/src/core/objects/procedure/changes/procedure.privilege.ts +188 -0
  240. package/src/core/objects/procedure/changes/procedure.types.ts +12 -0
  241. package/src/core/objects/procedure/procedure.diff.test.ts +161 -0
  242. package/src/core/objects/procedure/procedure.diff.ts +404 -0
  243. package/src/core/objects/procedure/procedure.model.ts +264 -0
  244. package/src/core/objects/procedure/utils.ts +58 -0
  245. package/src/core/objects/publication/changes/publication.alter.test.ts +223 -0
  246. package/src/core/objects/publication/changes/publication.alter.ts +243 -0
  247. package/src/core/objects/publication/changes/publication.base.ts +20 -0
  248. package/src/core/objects/publication/changes/publication.comment.test.ts +70 -0
  249. package/src/core/objects/publication/changes/publication.comment.ts +64 -0
  250. package/src/core/objects/publication/changes/publication.create.test.ts +87 -0
  251. package/src/core/objects/publication/changes/publication.create.ts +82 -0
  252. package/src/core/objects/publication/changes/publication.drop.test.ts +46 -0
  253. package/src/core/objects/publication/changes/publication.drop.ts +29 -0
  254. package/src/core/objects/publication/changes/publication.types.ts +26 -0
  255. package/src/core/objects/publication/publication.diff.test.ts +292 -0
  256. package/src/core/objects/publication/publication.diff.ts +253 -0
  257. package/src/core/objects/publication/publication.model.ts +206 -0
  258. package/src/core/objects/publication/utils.ts +55 -0
  259. package/src/core/objects/rls-policy/changes/rls-policy.alter.test.ts +250 -0
  260. package/src/core/objects/rls-policy/changes/rls-policy.alter.ts +128 -0
  261. package/src/core/objects/rls-policy/changes/rls-policy.base.ts +20 -0
  262. package/src/core/objects/rls-policy/changes/rls-policy.comment.ts +69 -0
  263. package/src/core/objects/rls-policy/changes/rls-policy.create.test.ts +74 -0
  264. package/src/core/objects/rls-policy/changes/rls-policy.create.ts +100 -0
  265. package/src/core/objects/rls-policy/changes/rls-policy.drop.test.ts +28 -0
  266. package/src/core/objects/rls-policy/changes/rls-policy.drop.ts +39 -0
  267. package/src/core/objects/rls-policy/changes/rls-policy.types.ts +10 -0
  268. package/src/core/objects/rls-policy/rls-policy.diff.test.ts +79 -0
  269. package/src/core/objects/rls-policy/rls-policy.diff.ts +121 -0
  270. package/src/core/objects/rls-policy/rls-policy.model.ts +140 -0
  271. package/src/core/objects/role/changes/role.alter.test.ts +346 -0
  272. package/src/core/objects/role/changes/role.alter.ts +110 -0
  273. package/src/core/objects/role/changes/role.base.ts +24 -0
  274. package/src/core/objects/role/changes/role.comment.ts +55 -0
  275. package/src/core/objects/role/changes/role.create.test.ts +52 -0
  276. package/src/core/objects/role/changes/role.create.ts +102 -0
  277. package/src/core/objects/role/changes/role.drop.test.ts +29 -0
  278. package/src/core/objects/role/changes/role.drop.ts +34 -0
  279. package/src/core/objects/role/changes/role.privilege.ts +376 -0
  280. package/src/core/objects/role/changes/role.types.ts +12 -0
  281. package/src/core/objects/role/role.diff.test.ts +44 -0
  282. package/src/core/objects/role/role.diff.ts +479 -0
  283. package/src/core/objects/role/role.model.ts +344 -0
  284. package/src/core/objects/rule/changes/rule.alter.test.ts +78 -0
  285. package/src/core/objects/rule/changes/rule.alter.ts +72 -0
  286. package/src/core/objects/rule/changes/rule.base.ts +20 -0
  287. package/src/core/objects/rule/changes/rule.comment.test.ts +55 -0
  288. package/src/core/objects/rule/changes/rule.comment.ts +62 -0
  289. package/src/core/objects/rule/changes/rule.create.test.ts +59 -0
  290. package/src/core/objects/rule/changes/rule.create.ts +42 -0
  291. package/src/core/objects/rule/changes/rule.drop.test.ts +38 -0
  292. package/src/core/objects/rule/changes/rule.drop.ts +29 -0
  293. package/src/core/objects/rule/changes/rule.types.ts +12 -0
  294. package/src/core/objects/rule/rule.diff.test.ts +132 -0
  295. package/src/core/objects/rule/rule.diff.ts +79 -0
  296. package/src/core/objects/rule/rule.model.ts +173 -0
  297. package/src/core/objects/schema/changes/schema.alter.test.ts +28 -0
  298. package/src/core/objects/schema/changes/schema.alter.ts +45 -0
  299. package/src/core/objects/schema/changes/schema.base.ts +20 -0
  300. package/src/core/objects/schema/changes/schema.comment.ts +56 -0
  301. package/src/core/objects/schema/changes/schema.create.test.ts +22 -0
  302. package/src/core/objects/schema/changes/schema.create.ts +47 -0
  303. package/src/core/objects/schema/changes/schema.drop.test.ts +20 -0
  304. package/src/core/objects/schema/changes/schema.drop.ts +34 -0
  305. package/src/core/objects/schema/changes/schema.privilege.ts +175 -0
  306. package/src/core/objects/schema/changes/schema.types.ts +12 -0
  307. package/src/core/objects/schema/schema.diff.test.ts +42 -0
  308. package/src/core/objects/schema/schema.diff.ts +209 -0
  309. package/src/core/objects/schema/schema.model.ts +107 -0
  310. package/src/core/objects/sequence/changes/sequence.alter.test.ts +151 -0
  311. package/src/core/objects/sequence/changes/sequence.alter.ts +115 -0
  312. package/src/core/objects/sequence/changes/sequence.base.ts +20 -0
  313. package/src/core/objects/sequence/changes/sequence.comment.ts +60 -0
  314. package/src/core/objects/sequence/changes/sequence.create.test.ts +84 -0
  315. package/src/core/objects/sequence/changes/sequence.create.ts +111 -0
  316. package/src/core/objects/sequence/changes/sequence.drop.test.ts +32 -0
  317. package/src/core/objects/sequence/changes/sequence.drop.ts +37 -0
  318. package/src/core/objects/sequence/changes/sequence.privilege.ts +179 -0
  319. package/src/core/objects/sequence/changes/sequence.types.ts +12 -0
  320. package/src/core/objects/sequence/sequence.diff.test.ts +141 -0
  321. package/src/core/objects/sequence/sequence.diff.ts +359 -0
  322. package/src/core/objects/sequence/sequence.model.ts +185 -0
  323. package/src/core/objects/subscription/changes/subscription.alter.test.ts +124 -0
  324. package/src/core/objects/subscription/changes/subscription.alter.ts +110 -0
  325. package/src/core/objects/subscription/changes/subscription.base.ts +20 -0
  326. package/src/core/objects/subscription/changes/subscription.comment.test.ts +67 -0
  327. package/src/core/objects/subscription/changes/subscription.comment.ts +64 -0
  328. package/src/core/objects/subscription/changes/subscription.create.test.ts +77 -0
  329. package/src/core/objects/subscription/changes/subscription.create.ts +69 -0
  330. package/src/core/objects/subscription/changes/subscription.drop.test.ts +46 -0
  331. package/src/core/objects/subscription/changes/subscription.drop.ts +20 -0
  332. package/src/core/objects/subscription/changes/subscription.types.ts +22 -0
  333. package/src/core/objects/subscription/subscription.diff.test.ts +232 -0
  334. package/src/core/objects/subscription/subscription.diff.ts +241 -0
  335. package/src/core/objects/subscription/subscription.model.ts +190 -0
  336. package/src/core/objects/subscription/utils.ts +156 -0
  337. package/src/core/objects/table/changes/table.alter.test.ts +823 -0
  338. package/src/core/objects/table/changes/table.alter.ts +806 -0
  339. package/src/core/objects/table/changes/table.base.ts +20 -0
  340. package/src/core/objects/table/changes/table.comment.ts +266 -0
  341. package/src/core/objects/table/changes/table.create.test.ts +150 -0
  342. package/src/core/objects/table/changes/table.create.ts +188 -0
  343. package/src/core/objects/table/changes/table.drop.test.ts +34 -0
  344. package/src/core/objects/table/changes/table.drop.ts +45 -0
  345. package/src/core/objects/table/changes/table.privilege.ts +200 -0
  346. package/src/core/objects/table/changes/table.types.ts +12 -0
  347. package/src/core/objects/table/table.diff.test.ts +711 -0
  348. package/src/core/objects/table/table.diff.ts +953 -0
  349. package/src/core/objects/table/table.model.ts +460 -0
  350. package/src/core/objects/trigger/changes/trigger.alter.test.ts +46 -0
  351. package/src/core/objects/trigger/changes/trigger.alter.ts +76 -0
  352. package/src/core/objects/trigger/changes/trigger.base.ts +20 -0
  353. package/src/core/objects/trigger/changes/trigger.comment.ts +64 -0
  354. package/src/core/objects/trigger/changes/trigger.create.test.ts +43 -0
  355. package/src/core/objects/trigger/changes/trigger.create.ts +85 -0
  356. package/src/core/objects/trigger/changes/trigger.drop.test.ts +43 -0
  357. package/src/core/objects/trigger/changes/trigger.drop.ts +39 -0
  358. package/src/core/objects/trigger/changes/trigger.types.ts +10 -0
  359. package/src/core/objects/trigger/trigger.diff.test.ts +83 -0
  360. package/src/core/objects/trigger/trigger.diff.ts +116 -0
  361. package/src/core/objects/trigger/trigger.model.ts +252 -0
  362. package/src/core/objects/type/composite-type/changes/composite-type.alter.test.ts +202 -0
  363. package/src/core/objects/type/composite-type/changes/composite-type.alter.ts +174 -0
  364. package/src/core/objects/type/composite-type/changes/composite-type.base.ts +20 -0
  365. package/src/core/objects/type/composite-type/changes/composite-type.comment.ts +145 -0
  366. package/src/core/objects/type/composite-type/changes/composite-type.create.test.ts +101 -0
  367. package/src/core/objects/type/composite-type/changes/composite-type.create.ts +95 -0
  368. package/src/core/objects/type/composite-type/changes/composite-type.drop.test.ts +33 -0
  369. package/src/core/objects/type/composite-type/changes/composite-type.drop.ts +37 -0
  370. package/src/core/objects/type/composite-type/changes/composite-type.privilege.ts +175 -0
  371. package/src/core/objects/type/composite-type/changes/composite-type.types.ts +12 -0
  372. package/src/core/objects/type/composite-type/composite-type.diff.test.ts +191 -0
  373. package/src/core/objects/type/composite-type/composite-type.diff.ts +372 -0
  374. package/src/core/objects/type/composite-type/composite-type.model.ts +252 -0
  375. package/src/core/objects/type/enum/changes/enum.alter.test.ts +104 -0
  376. package/src/core/objects/type/enum/changes/enum.alter.ts +91 -0
  377. package/src/core/objects/type/enum/changes/enum.base.ts +20 -0
  378. package/src/core/objects/type/enum/changes/enum.comment.ts +64 -0
  379. package/src/core/objects/type/enum/changes/enum.create.test.ts +28 -0
  380. package/src/core/objects/type/enum/changes/enum.create.ts +56 -0
  381. package/src/core/objects/type/enum/changes/enum.drop.test.ts +25 -0
  382. package/src/core/objects/type/enum/changes/enum.drop.ts +34 -0
  383. package/src/core/objects/type/enum/changes/enum.privilege.ts +175 -0
  384. package/src/core/objects/type/enum/changes/enum.types.ts +12 -0
  385. package/src/core/objects/type/enum/enum.diff.test.ts +191 -0
  386. package/src/core/objects/type/enum/enum.diff.ts +396 -0
  387. package/src/core/objects/type/enum/enum.model.ts +194 -0
  388. package/src/core/objects/type/range/changes/range.alter.test.ts +27 -0
  389. package/src/core/objects/type/range/changes/range.alter.ts +51 -0
  390. package/src/core/objects/type/range/changes/range.base.ts +20 -0
  391. package/src/core/objects/type/range/changes/range.comment.ts +64 -0
  392. package/src/core/objects/type/range/changes/range.create.test.ts +51 -0
  393. package/src/core/objects/type/range/changes/range.create.ts +151 -0
  394. package/src/core/objects/type/range/changes/range.drop.test.ts +26 -0
  395. package/src/core/objects/type/range/changes/range.drop.ts +34 -0
  396. package/src/core/objects/type/range/changes/range.privilege.ts +175 -0
  397. package/src/core/objects/type/range/changes/range.types.ts +12 -0
  398. package/src/core/objects/type/range/range.diff.test.ts +70 -0
  399. package/src/core/objects/type/range/range.diff.ts +259 -0
  400. package/src/core/objects/type/range/range.model.ts +187 -0
  401. package/src/core/objects/type/type.types.ts +5 -0
  402. package/src/core/objects/utils.ts +171 -0
  403. package/src/core/objects/view/changes/view.alter.test.ts +110 -0
  404. package/src/core/objects/view/changes/view.alter.ts +112 -0
  405. package/src/core/objects/view/changes/view.base.ts +20 -0
  406. package/src/core/objects/view/changes/view.comment.ts +59 -0
  407. package/src/core/objects/view/changes/view.create.test.ts +65 -0
  408. package/src/core/objects/view/changes/view.create.ts +73 -0
  409. package/src/core/objects/view/changes/view.drop.test.ts +34 -0
  410. package/src/core/objects/view/changes/view.drop.ts +40 -0
  411. package/src/core/objects/view/changes/view.privilege.ts +200 -0
  412. package/src/core/objects/view/changes/view.types.ts +12 -0
  413. package/src/core/objects/view/view.diff.test.ts +91 -0
  414. package/src/core/objects/view/view.diff.ts +365 -0
  415. package/src/core/objects/view/view.model.ts +276 -0
  416. package/src/core/plan/apply.ts +190 -0
  417. package/src/core/plan/create.ts +432 -0
  418. package/src/core/plan/hierarchy.ts +574 -0
  419. package/src/core/plan/index.ts +29 -0
  420. package/src/core/plan/io.ts +20 -0
  421. package/src/core/plan/risk.ts +48 -0
  422. package/src/core/plan/serialize.ts +195 -0
  423. package/src/core/plan/sql-format/constants.ts +13 -0
  424. package/src/core/plan/sql-format/fixtures.ts +2806 -0
  425. package/src/core/plan/sql-format/format-comment-literals.test.ts +96 -0
  426. package/src/core/plan/sql-format/format-functions.test.ts +127 -0
  427. package/src/core/plan/sql-format/format-lowercase-coverage.test.ts +67 -0
  428. package/src/core/plan/sql-format/format-off.test.ts +809 -0
  429. package/src/core/plan/sql-format/format-pretty-lower-leading.test.ts +1056 -0
  430. package/src/core/plan/sql-format/format-pretty-narrow.test.ts +1283 -0
  431. package/src/core/plan/sql-format/format-pretty-preserve.test.ts +1052 -0
  432. package/src/core/plan/sql-format/format-pretty-upper.test.ts +1045 -0
  433. package/src/core/plan/sql-format/format-stress.test.ts +616 -0
  434. package/src/core/plan/sql-format/format-utils.test.ts +91 -0
  435. package/src/core/plan/sql-format/format-utils.ts +391 -0
  436. package/src/core/plan/sql-format/formatters.ts +921 -0
  437. package/src/core/plan/sql-format/index.ts +149 -0
  438. package/src/core/plan/sql-format/keyword-case.test.ts +118 -0
  439. package/src/core/plan/sql-format/keyword-case.ts +1085 -0
  440. package/src/core/plan/sql-format/protect.test.ts +127 -0
  441. package/src/core/plan/sql-format/protect.ts +337 -0
  442. package/src/core/plan/sql-format/sql-scanner.test.ts +240 -0
  443. package/src/core/plan/sql-format/sql-scanner.ts +252 -0
  444. package/src/core/plan/sql-format/tokenizer.test.ts +68 -0
  445. package/src/core/plan/sql-format/tokenizer.ts +152 -0
  446. package/src/core/plan/sql-format/types.ts +31 -0
  447. package/src/core/plan/sql-format/wrap.test.ts +119 -0
  448. package/src/core/plan/sql-format/wrap.ts +196 -0
  449. package/src/core/plan/sql-format.ts +2 -0
  450. package/src/core/plan/statements.ts +22 -0
  451. package/src/core/plan/types.ts +165 -0
  452. package/src/core/postgres-config.ts +169 -0
  453. package/src/core/sort/custom-constraints.ts +161 -0
  454. package/src/core/sort/debug-visualization.ts +239 -0
  455. package/src/core/sort/dependency-filter.ts +224 -0
  456. package/src/core/sort/graph-builder.ts +223 -0
  457. package/src/core/sort/graph-utils.ts +51 -0
  458. package/src/core/sort/logical-sort.ts +590 -0
  459. package/src/core/sort/sort-changes.ts +234 -0
  460. package/src/core/sort/topological-sort.ts +184 -0
  461. package/src/core/sort/types.ts +112 -0
  462. package/src/core/sort/utils.ts +69 -0
  463. package/src/index.ts +14 -0
@@ -0,0 +1,953 @@
1
+ import type { DefaultPrivilegeState } from "../base.default-privileges.ts";
2
+ import { diffObjects } from "../base.diff.ts";
3
+ import {
4
+ diffPrivileges,
5
+ groupPrivilegesByColumns,
6
+ } from "../base.privilege-diff.ts";
7
+ import type { Role } from "../role/role.model.ts";
8
+ import { deepEqual } from "../utils.ts";
9
+ import {
10
+ AlterTableAddColumn,
11
+ AlterTableAddConstraint,
12
+ AlterTableAlterColumnDropDefault,
13
+ AlterTableAlterColumnDropNotNull,
14
+ AlterTableAlterColumnSetDefault,
15
+ AlterTableAlterColumnSetNotNull,
16
+ AlterTableAlterColumnType,
17
+ AlterTableAttachPartition,
18
+ AlterTableChangeOwner,
19
+ AlterTableDetachPartition,
20
+ AlterTableDisableRowLevelSecurity,
21
+ AlterTableDropColumn,
22
+ AlterTableDropConstraint,
23
+ AlterTableEnableRowLevelSecurity,
24
+ AlterTableForceRowLevelSecurity,
25
+ AlterTableNoForceRowLevelSecurity,
26
+ AlterTableResetStorageParams,
27
+ AlterTableSetLogged,
28
+ AlterTableSetReplicaIdentity,
29
+ AlterTableSetStorageParams,
30
+ AlterTableSetUnlogged,
31
+ AlterTableValidateConstraint,
32
+ } from "./changes/table.alter.ts";
33
+ import {
34
+ CreateCommentOnColumn,
35
+ CreateCommentOnConstraint,
36
+ CreateCommentOnTable,
37
+ DropCommentOnColumn,
38
+ DropCommentOnConstraint,
39
+ DropCommentOnTable,
40
+ } from "./changes/table.comment.ts";
41
+ import { CreateTable } from "./changes/table.create.ts";
42
+ import { DropTable } from "./changes/table.drop.ts";
43
+ import {
44
+ GrantTablePrivileges,
45
+ RevokeGrantOptionTablePrivileges,
46
+ RevokeTablePrivileges,
47
+ } from "./changes/table.privilege.ts";
48
+ import type { TableChange } from "./changes/table.types.ts";
49
+ import { Table } from "./table.model.ts";
50
+
51
+ function createAlterConstraintChange(mainTable: Table, branchTable: Table) {
52
+ const changes: TableChange[] = [];
53
+
54
+ // Note: Table renaming would also use ALTER TABLE ... RENAME TO ...
55
+ // But since our Table model uses 'name' as the identity field,
56
+ // a name change would be handled as drop + create by diffObjects()
57
+
58
+ // TABLE CONSTRAINTS
59
+ const mainByName = new Map(
60
+ (mainTable.constraints ?? []).map((c) => [c.name, c]),
61
+ );
62
+ const branchByName = new Map(
63
+ (branchTable.constraints ?? []).map((c) => [c.name, c]),
64
+ );
65
+
66
+ // Created constraints
67
+ for (const [name, c] of branchByName) {
68
+ // Skip constraint clones on partitions - they are automatically created when the parent constraint is created
69
+ if (c.is_partition_clone) {
70
+ continue;
71
+ }
72
+
73
+ if (!mainByName.has(name)) {
74
+ changes.push(
75
+ new AlterTableAddConstraint({
76
+ table: branchTable,
77
+ constraint: c,
78
+ }),
79
+ );
80
+ if (!c.validated) {
81
+ changes.push(
82
+ new AlterTableValidateConstraint({
83
+ table: branchTable,
84
+ constraint: c,
85
+ }),
86
+ );
87
+ }
88
+ // Add comment for newly created constraint
89
+ if (c.comment !== null) {
90
+ changes.push(
91
+ new CreateCommentOnConstraint({
92
+ table: branchTable,
93
+ constraint: c,
94
+ }),
95
+ );
96
+ }
97
+ }
98
+ }
99
+
100
+ // Dropped constraints
101
+ for (const [name, c] of mainByName) {
102
+ // Skip constraint clones on partitions - they are automatically dropped when the parent constraint is dropped
103
+ if (c.is_partition_clone) {
104
+ continue;
105
+ }
106
+
107
+ if (!branchByName.has(name)) {
108
+ changes.push(
109
+ new AlterTableDropConstraint({ table: mainTable, constraint: c }),
110
+ );
111
+ }
112
+ }
113
+
114
+ // Altered constraints -> drop + add
115
+ for (const [name, mainC] of mainByName) {
116
+ const branchC = branchByName.get(name);
117
+ if (!branchC) continue;
118
+
119
+ // Skip constraint clones on partitions - they are automatically updated when the parent constraint is updated
120
+ if (mainC.is_partition_clone || branchC.is_partition_clone) {
121
+ continue;
122
+ }
123
+
124
+ const changed =
125
+ mainC.constraint_type !== branchC.constraint_type ||
126
+ mainC.deferrable !== branchC.deferrable ||
127
+ mainC.initially_deferred !== branchC.initially_deferred ||
128
+ mainC.validated !== branchC.validated ||
129
+ mainC.is_local !== branchC.is_local ||
130
+ mainC.no_inherit !== branchC.no_inherit ||
131
+ JSON.stringify(mainC.key_columns) !==
132
+ JSON.stringify(branchC.key_columns) ||
133
+ JSON.stringify(mainC.foreign_key_columns) !==
134
+ JSON.stringify(branchC.foreign_key_columns) ||
135
+ mainC.foreign_key_table !== branchC.foreign_key_table ||
136
+ mainC.foreign_key_schema !== branchC.foreign_key_schema ||
137
+ mainC.on_update !== branchC.on_update ||
138
+ mainC.on_delete !== branchC.on_delete ||
139
+ mainC.match_type !== branchC.match_type ||
140
+ mainC.check_expression !== branchC.check_expression;
141
+ if (changed) {
142
+ changes.push(
143
+ new AlterTableDropConstraint({
144
+ table: mainTable,
145
+ constraint: mainC,
146
+ }),
147
+ );
148
+ changes.push(
149
+ new AlterTableAddConstraint({
150
+ table: branchTable,
151
+ constraint: branchC,
152
+ }),
153
+ );
154
+ if (!branchC.validated) {
155
+ changes.push(
156
+ new AlterTableValidateConstraint({
157
+ table: branchTable,
158
+ constraint: branchC,
159
+ }),
160
+ );
161
+ }
162
+ // Ensure constraint comment is applied after re-creation
163
+ if (branchC.comment !== null) {
164
+ changes.push(
165
+ new CreateCommentOnConstraint({
166
+ table: branchTable,
167
+ constraint: branchC,
168
+ }),
169
+ );
170
+ }
171
+ } else {
172
+ // Comment-only change on constraint
173
+ if (mainC.comment !== branchC.comment) {
174
+ if (branchC.comment === null) {
175
+ changes.push(
176
+ new DropCommentOnConstraint({
177
+ table: mainTable,
178
+ constraint: mainC,
179
+ }),
180
+ );
181
+ } else {
182
+ changes.push(
183
+ new CreateCommentOnConstraint({
184
+ table: branchTable,
185
+ constraint: branchC,
186
+ }),
187
+ );
188
+ }
189
+ }
190
+ }
191
+ }
192
+
193
+ return changes;
194
+ }
195
+
196
+ /**
197
+ * Diff two sets of tables from main and branch catalogs.
198
+ *
199
+ * @param ctx - Context containing version, currentUser, and defaultPrivilegeState
200
+ * @param main - The tables in the main catalog.
201
+ * @param branch - The tables in the branch catalog.
202
+ * @returns A list of changes to apply to main to make it match branch.
203
+ */
204
+ export function diffTables(
205
+ ctx: {
206
+ version: number;
207
+ currentUser: string;
208
+ defaultPrivilegeState: DefaultPrivilegeState;
209
+ mainRoles: Record<string, Role>;
210
+ },
211
+ main: Record<string, Table>,
212
+ branch: Record<string, Table>,
213
+ ): TableChange[] {
214
+ const { created, dropped, altered } = diffObjects(main, branch);
215
+
216
+ const changes: TableChange[] = [];
217
+
218
+ for (const tableId of created) {
219
+ changes.push(new CreateTable({ table: branch[tableId] }));
220
+ const branchTable = branch[tableId];
221
+
222
+ // OWNER: If the table should be owned by someone other than the current user,
223
+ // emit ALTER TABLE ... OWNER TO after creation
224
+ if (branchTable.owner !== ctx.currentUser) {
225
+ changes.push(
226
+ new AlterTableChangeOwner({
227
+ table: branchTable,
228
+ owner: branchTable.owner,
229
+ }),
230
+ );
231
+ }
232
+
233
+ // ROW LEVEL SECURITY: If RLS should be enabled, emit ALTER TABLE ... ENABLE ROW LEVEL SECURITY
234
+ if (branchTable.row_security) {
235
+ changes.push(
236
+ new AlterTableEnableRowLevelSecurity({ table: branchTable }),
237
+ );
238
+ }
239
+
240
+ // FORCE ROW LEVEL SECURITY: If force RLS should be enabled, emit ALTER TABLE ... FORCE ROW LEVEL SECURITY
241
+ if (branchTable.force_row_security) {
242
+ changes.push(new AlterTableForceRowLevelSecurity({ table: branchTable }));
243
+ }
244
+
245
+ changes.push(
246
+ ...createAlterConstraintChange(
247
+ // Create a dummy table with no constraints do diff constraints against
248
+ new Table({
249
+ ...branchTable,
250
+ constraints: [],
251
+ }),
252
+ branchTable,
253
+ ),
254
+ );
255
+
256
+ // Table comment on creation
257
+ if (branchTable.comment !== null && branchTable.comment !== undefined) {
258
+ changes.push(new CreateCommentOnTable({ table: branchTable }));
259
+ }
260
+
261
+ // Column comments on creation
262
+ for (const col of branchTable.columns) {
263
+ if (col.comment !== null && col.comment !== undefined) {
264
+ changes.push(
265
+ new CreateCommentOnColumn({ table: branchTable, column: col }),
266
+ );
267
+ }
268
+ }
269
+
270
+ // PRIVILEGES: For created objects, compare against default privileges state
271
+ // The migration script will run ALTER DEFAULT PRIVILEGES before CREATE (via constraint spec),
272
+ // so objects are created with the default privileges state in effect.
273
+ // We compare default privileges against desired privileges to generate REVOKE/GRANT statements
274
+ // needed to reach the final desired state.
275
+ const effectiveDefaults = ctx.defaultPrivilegeState.getEffectiveDefaults(
276
+ ctx.currentUser,
277
+ "table",
278
+ branchTable.schema ?? "",
279
+ );
280
+ const desiredPrivileges = branchTable.privileges;
281
+ // Filter out owner privileges - owner always has ALL privileges implicitly
282
+ // and shouldn't be compared. Use the table owner as the reference.
283
+ const privilegeResults = diffPrivileges(
284
+ effectiveDefaults,
285
+ desiredPrivileges,
286
+ branchTable.owner,
287
+ ctx.mainRoles,
288
+ );
289
+
290
+ // Generate grant changes
291
+ for (const [grantee, result] of privilegeResults) {
292
+ if (result.grants.length > 0) {
293
+ const grantGroups = groupPrivilegesByColumns(result.grants);
294
+ for (const [, group] of grantGroups) {
295
+ for (const [grantable, privSet] of group.byGrant) {
296
+ const privileges = Array.from(privSet).map((priv) => ({
297
+ privilege: priv,
298
+ grantable,
299
+ }));
300
+ changes.push(
301
+ new GrantTablePrivileges({
302
+ table: branchTable,
303
+ grantee,
304
+ privileges,
305
+ columns: group.columns,
306
+ version: ctx.version,
307
+ }),
308
+ );
309
+ }
310
+ }
311
+ }
312
+
313
+ // Generate revoke changes
314
+ if (result.revokes.length > 0) {
315
+ const revokeGroups = groupPrivilegesByColumns(result.revokes);
316
+ for (const [, group] of revokeGroups) {
317
+ const allPrivileges = new Set<string>();
318
+ for (const [, privSet] of group.byGrant) {
319
+ for (const priv of privSet) {
320
+ allPrivileges.add(priv);
321
+ }
322
+ }
323
+ const privileges = Array.from(allPrivileges).map((priv) => ({
324
+ privilege: priv,
325
+ grantable: false,
326
+ }));
327
+ changes.push(
328
+ new RevokeTablePrivileges({
329
+ table: branchTable,
330
+ grantee,
331
+ privileges,
332
+ columns: group.columns,
333
+ version: ctx.version,
334
+ }),
335
+ );
336
+ }
337
+ }
338
+
339
+ // Generate revoke grant option changes
340
+ if (result.revokeGrantOption.length > 0) {
341
+ const revokeGrantGroups = new Map<
342
+ string,
343
+ { columns?: string[]; privileges: Set<string> }
344
+ >();
345
+ for (const r of result.revokeGrantOption) {
346
+ const originalPriv = effectiveDefaults.find(
347
+ (p) => p.grantee === grantee && p.privilege === r,
348
+ );
349
+ const key = originalPriv?.columns
350
+ ? originalPriv.columns.sort().join(",")
351
+ : "";
352
+ if (!revokeGrantGroups.has(key)) {
353
+ revokeGrantGroups.set(key, {
354
+ columns: originalPriv?.columns
355
+ ? [...originalPriv.columns]
356
+ : undefined,
357
+ privileges: new Set(),
358
+ });
359
+ }
360
+ const group = revokeGrantGroups.get(key);
361
+ if (!group) continue;
362
+ group.privileges.add(r);
363
+ }
364
+ for (const [, group] of revokeGrantGroups) {
365
+ const privilegeNames = Array.from(group.privileges);
366
+ changes.push(
367
+ new RevokeGrantOptionTablePrivileges({
368
+ table: branchTable,
369
+ grantee,
370
+ privilegeNames,
371
+ columns: group.columns,
372
+ version: ctx.version,
373
+ }),
374
+ );
375
+ }
376
+ }
377
+ }
378
+ }
379
+
380
+ for (const tableId of dropped) {
381
+ changes.push(new DropTable({ table: main[tableId] }));
382
+ }
383
+
384
+ for (const tableId of altered) {
385
+ const mainTable = main[tableId];
386
+ const branchTable = branch[tableId];
387
+
388
+ // Dangerous operations (drop+create) are not performed by this tool.
389
+ // Only emit safe ALTER statements below.
390
+ // Only alterable properties changed - check each one
391
+
392
+ // PERSISTENCE (LOGGED/UNLOGGED)
393
+ if (mainTable.persistence !== branchTable.persistence) {
394
+ if (branchTable.persistence === "u" && mainTable.persistence === "p") {
395
+ changes.push(new AlterTableSetUnlogged({ table: mainTable }));
396
+ } else if (
397
+ branchTable.persistence === "p" &&
398
+ mainTable.persistence === "u"
399
+ ) {
400
+ changes.push(new AlterTableSetLogged({ table: mainTable }));
401
+ }
402
+ }
403
+
404
+ // ROW LEVEL SECURITY
405
+ if (mainTable.row_security !== branchTable.row_security) {
406
+ if (branchTable.row_security) {
407
+ changes.push(
408
+ new AlterTableEnableRowLevelSecurity({ table: mainTable }),
409
+ );
410
+ } else {
411
+ changes.push(
412
+ new AlterTableDisableRowLevelSecurity({ table: mainTable }),
413
+ );
414
+ }
415
+ }
416
+
417
+ // FORCE ROW LEVEL SECURITY
418
+ if (mainTable.force_row_security !== branchTable.force_row_security) {
419
+ if (branchTable.force_row_security) {
420
+ changes.push(new AlterTableForceRowLevelSecurity({ table: mainTable }));
421
+ } else {
422
+ changes.push(
423
+ new AlterTableNoForceRowLevelSecurity({ table: mainTable }),
424
+ );
425
+ }
426
+ }
427
+
428
+ // STORAGE PARAMS (WITH (...))
429
+ if (!deepEqual(mainTable.options, branchTable.options)) {
430
+ const mainOpts = mainTable.options ?? [];
431
+ const branchOpts = branchTable.options ?? [];
432
+
433
+ // Always set branch options when provided
434
+ if (branchOpts.length > 0) {
435
+ changes.push(
436
+ new AlterTableSetStorageParams({
437
+ table: mainTable,
438
+ options: branchOpts,
439
+ }),
440
+ );
441
+ }
442
+
443
+ // Reset any params that are present in main but absent in branch
444
+ if (mainOpts.length > 0) {
445
+ const mainNames = new Set(mainOpts.map((opt) => opt.split("=")[0]));
446
+ const branchNames = new Set(branchOpts.map((opt) => opt.split("=")[0]));
447
+ const removed: string[] = [];
448
+ for (const name of mainNames) {
449
+ if (!branchNames.has(name)) removed.push(name);
450
+ }
451
+ if (removed.length > 0) {
452
+ changes.push(
453
+ new AlterTableResetStorageParams({
454
+ table: mainTable,
455
+ params: removed,
456
+ }),
457
+ );
458
+ }
459
+ }
460
+ }
461
+
462
+ // REPLICA IDENTITY
463
+ if (mainTable.replica_identity !== branchTable.replica_identity) {
464
+ // Skip when target is 'i' (USING INDEX) — handled by index changes
465
+ if (branchTable.replica_identity !== "i") {
466
+ changes.push(
467
+ new AlterTableSetReplicaIdentity({
468
+ table: mainTable,
469
+ mode: branchTable.replica_identity,
470
+ }),
471
+ );
472
+ }
473
+ }
474
+
475
+ // OWNER
476
+ if (mainTable.owner !== branchTable.owner) {
477
+ changes.push(
478
+ new AlterTableChangeOwner({
479
+ table: mainTable,
480
+ owner: branchTable.owner,
481
+ }),
482
+ );
483
+ }
484
+
485
+ // TABLE COMMENT (create/drop when comment changes)
486
+ if (mainTable.comment !== branchTable.comment) {
487
+ if (branchTable.comment === null) {
488
+ changes.push(new DropCommentOnTable({ table: mainTable }));
489
+ } else {
490
+ changes.push(new CreateCommentOnTable({ table: branchTable }));
491
+ }
492
+ }
493
+
494
+ // PARTITION ATTACH/DETACH
495
+ const mainIsPartition = Boolean(
496
+ mainTable.parent_schema && mainTable.parent_name,
497
+ );
498
+ const branchIsPartition = Boolean(
499
+ branchTable.parent_schema && branchTable.parent_name,
500
+ );
501
+
502
+ // Helper to resolve parent table from catalogs
503
+ const resolveParent = (
504
+ catalog: Record<string, Table>,
505
+ schema: string,
506
+ name: string,
507
+ ): Table | undefined => catalog[`table:${schema}.${name}`];
508
+
509
+ if (!mainIsPartition && branchIsPartition) {
510
+ const table = resolveParent(
511
+ branch,
512
+ branchTable.parent_schema as string,
513
+ branchTable.parent_name as string,
514
+ );
515
+ if (table) {
516
+ changes.push(
517
+ new AlterTableAttachPartition({ table, partition: branchTable }),
518
+ );
519
+ }
520
+ } else if (mainIsPartition && !branchIsPartition) {
521
+ const table = resolveParent(
522
+ main,
523
+ mainTable.parent_schema as string,
524
+ mainTable.parent_name as string,
525
+ );
526
+ if (table) {
527
+ changes.push(
528
+ new AlterTableDetachPartition({ table, partition: mainTable }),
529
+ );
530
+ }
531
+ } else if (mainIsPartition && branchIsPartition) {
532
+ const parentChanged =
533
+ mainTable.parent_schema !== branchTable.parent_schema ||
534
+ mainTable.parent_name !== branchTable.parent_name;
535
+ const boundChanged =
536
+ mainTable.partition_bound !== branchTable.partition_bound;
537
+ if (parentChanged || boundChanged) {
538
+ const oldParent = resolveParent(
539
+ main,
540
+ mainTable.parent_schema as string,
541
+ mainTable.parent_name as string,
542
+ );
543
+ if (oldParent) {
544
+ changes.push(
545
+ new AlterTableDetachPartition({
546
+ table: oldParent,
547
+ partition: mainTable,
548
+ }),
549
+ );
550
+ }
551
+ const newParent = resolveParent(
552
+ branch,
553
+ branchTable.parent_schema as string,
554
+ branchTable.parent_name as string,
555
+ );
556
+ if (newParent) {
557
+ changes.push(
558
+ new AlterTableAttachPartition({
559
+ table: newParent,
560
+ partition: branchTable,
561
+ }),
562
+ );
563
+ }
564
+ }
565
+ }
566
+
567
+ changes.push(...createAlterConstraintChange(mainTable, branchTable));
568
+
569
+ // COLUMNS
570
+ const mainCols = new Map(mainTable.columns.map((c) => [c.name, c]));
571
+ const branchCols = new Map(branchTable.columns.map((c) => [c.name, c]));
572
+
573
+ // Helper to get parent tables if this is a partition
574
+ // PostgreSQL automatically propagates column changes from parent to partitions,
575
+ // so we should skip changes on partitions when the parent has the same change
576
+ const getParentTables = (): {
577
+ parentMain: Table | null;
578
+ parentBranch: Table | null;
579
+ } => {
580
+ if (
581
+ !branchIsPartition ||
582
+ !branchTable.parent_schema ||
583
+ !branchTable.parent_name
584
+ ) {
585
+ return { parentMain: null, parentBranch: null };
586
+ }
587
+
588
+ const parentBranch = resolveParent(
589
+ branch,
590
+ branchTable.parent_schema,
591
+ branchTable.parent_name,
592
+ );
593
+ const parentMain = resolveParent(
594
+ main,
595
+ branchTable.parent_schema,
596
+ branchTable.parent_name,
597
+ );
598
+
599
+ return {
600
+ parentMain: parentMain ?? null,
601
+ parentBranch: parentBranch ?? null,
602
+ };
603
+ };
604
+
605
+ // Helper to check if parent has the same column property change
606
+ const parentHasSameColumnPropertyChange = (
607
+ columnName: string,
608
+ property: "type" | "default" | "not_null",
609
+ ): boolean => {
610
+ const { parentMain, parentBranch } = getParentTables();
611
+ if (!parentMain || !parentBranch) {
612
+ return false;
613
+ }
614
+
615
+ const parentMainCol = parentMain.columns.find(
616
+ (c) => c.name === columnName,
617
+ );
618
+ const parentBranchCol = parentBranch.columns.find(
619
+ (c) => c.name === columnName,
620
+ );
621
+ const branchCol = branchCols.get(columnName);
622
+ const mainCol = mainCols.get(columnName);
623
+
624
+ if (!parentMainCol || !parentBranchCol || !branchCol || !mainCol) {
625
+ return false;
626
+ }
627
+
628
+ switch (property) {
629
+ case "type": {
630
+ const parentTypeChanged =
631
+ parentMainCol.data_type_str !== parentBranchCol.data_type_str ||
632
+ parentMainCol.collation !== parentBranchCol.collation;
633
+ const partitionTypeChanged =
634
+ mainCol.data_type_str !== branchCol.data_type_str ||
635
+ mainCol.collation !== branchCol.collation;
636
+ return (
637
+ parentTypeChanged &&
638
+ partitionTypeChanged &&
639
+ parentBranchCol.data_type_str === branchCol.data_type_str &&
640
+ parentBranchCol.collation === branchCol.collation
641
+ );
642
+ }
643
+ case "default": {
644
+ const parentDefaultChanged =
645
+ parentMainCol.default !== parentBranchCol.default;
646
+ const partitionDefaultChanged = mainCol.default !== branchCol.default;
647
+ return (
648
+ parentDefaultChanged &&
649
+ partitionDefaultChanged &&
650
+ parentBranchCol.default === branchCol.default
651
+ );
652
+ }
653
+ case "not_null": {
654
+ const parentNotNullChanged =
655
+ parentMainCol.not_null !== parentBranchCol.not_null;
656
+ const partitionNotNullChanged =
657
+ mainCol.not_null !== branchCol.not_null;
658
+ return (
659
+ parentNotNullChanged &&
660
+ partitionNotNullChanged &&
661
+ parentBranchCol.not_null === branchCol.not_null
662
+ );
663
+ }
664
+ }
665
+ };
666
+
667
+ // Helper to check if parent has the same column add/drop
668
+ const shouldSkipColumnAddDropOnPartition = (
669
+ columnName: string,
670
+ changeType: "add" | "drop",
671
+ ): boolean => {
672
+ const { parentMain, parentBranch } = getParentTables();
673
+ if (!parentMain || !parentBranch) {
674
+ return false;
675
+ }
676
+
677
+ const parentMainHasCol = parentMain.columns.some(
678
+ (c) => c.name === columnName,
679
+ );
680
+ const parentBranchHasCol = parentBranch.columns.some(
681
+ (c) => c.name === columnName,
682
+ );
683
+
684
+ if (changeType === "add") {
685
+ // Check if parent also has this column added and final states match
686
+ if (!parentMainHasCol && parentBranchHasCol) {
687
+ const parentBranchCol = parentBranch.columns.find(
688
+ (c) => c.name === columnName,
689
+ );
690
+ const branchCol = branchCols.get(columnName);
691
+ return (
692
+ parentBranchCol !== undefined &&
693
+ branchCol !== undefined &&
694
+ parentBranchCol.data_type_str === branchCol.data_type_str &&
695
+ parentBranchCol.collation === branchCol.collation &&
696
+ parentBranchCol.default === branchCol.default &&
697
+ parentBranchCol.not_null === branchCol.not_null
698
+ );
699
+ }
700
+ } else {
701
+ // changeType === "drop"
702
+ // If parent is dropping the column, skip on partition
703
+ return parentMainHasCol && !parentBranchHasCol;
704
+ }
705
+
706
+ return false;
707
+ };
708
+
709
+ // Added columns
710
+ for (const [name, col] of branchCols) {
711
+ if (!mainCols.has(name)) {
712
+ // Skip if this is a partition and parent has the same column added
713
+ if (shouldSkipColumnAddDropOnPartition(name, "add")) {
714
+ continue;
715
+ }
716
+ changes.push(
717
+ new AlterTableAddColumn({ table: branchTable, column: col }),
718
+ );
719
+ if (col.comment !== null && col.comment !== undefined) {
720
+ changes.push(
721
+ new CreateCommentOnColumn({ table: branchTable, column: col }),
722
+ );
723
+ }
724
+ }
725
+ }
726
+
727
+ // Dropped columns
728
+ for (const [name, col] of mainCols) {
729
+ if (!branchCols.has(name)) {
730
+ // Skip if this is a partition and parent has the same column dropped
731
+ if (shouldSkipColumnAddDropOnPartition(name, "drop")) {
732
+ continue;
733
+ }
734
+ changes.push(
735
+ new AlterTableDropColumn({ table: mainTable, column: col }),
736
+ );
737
+ }
738
+ }
739
+
740
+ // Altered columns
741
+ for (const [name, mainCol] of mainCols) {
742
+ const branchCol = branchCols.get(name);
743
+ if (!branchCol) continue;
744
+
745
+ // TYPE or COLLATION change
746
+ if (
747
+ mainCol.data_type_str !== branchCol.data_type_str ||
748
+ mainCol.collation !== branchCol.collation
749
+ ) {
750
+ // Skip if parent has the same type/collation change
751
+ if (!parentHasSameColumnPropertyChange(name, "type")) {
752
+ changes.push(
753
+ new AlterTableAlterColumnType({
754
+ table: branchTable,
755
+ column: branchCol,
756
+ }),
757
+ );
758
+ }
759
+ }
760
+
761
+ // DEFAULT change
762
+ if (mainCol.default !== branchCol.default) {
763
+ // Skip if parent has the same default change
764
+ if (!parentHasSameColumnPropertyChange(name, "default")) {
765
+ if (branchCol.default === null) {
766
+ // Drop default value
767
+ changes.push(
768
+ new AlterTableAlterColumnDropDefault({
769
+ table: branchTable,
770
+ column: branchCol,
771
+ }),
772
+ );
773
+ } else {
774
+ // Set new default value
775
+ const isGeneratedColumn = branchCol.is_generated;
776
+ const isPostgresLowerThan17 = ctx.version < 170000;
777
+
778
+ if (isGeneratedColumn && isPostgresLowerThan17) {
779
+ // For generated columns in < PostgreSQL 17, we need to drop and recreate
780
+ // instead of using SET EXPRESSION AS for computed columns
781
+ // cf: https://git.postgresql.org/gitweb/?p=postgresql.git;a=commitdiff;h=5d06e99a3
782
+ // cf: https://www.postgresql.org/docs/release/17.0/
783
+ // > Allow ALTER TABLE to change a column's generation expression
784
+ changes.push(
785
+ new AlterTableDropColumn({
786
+ table: mainTable,
787
+ column: mainCol,
788
+ }),
789
+ );
790
+ changes.push(
791
+ new AlterTableAddColumn({
792
+ table: branchTable,
793
+ column: branchCol,
794
+ }),
795
+ );
796
+ } else {
797
+ // Use standard SET DEFAULT or SET EXPRESSION AS for newer PostgreSQL versions
798
+ changes.push(
799
+ new AlterTableAlterColumnSetDefault({
800
+ table: branchTable,
801
+ column: branchCol,
802
+ }),
803
+ );
804
+ }
805
+ }
806
+ }
807
+ }
808
+
809
+ // NOT NULL change
810
+ if (mainCol.not_null !== branchCol.not_null) {
811
+ // Skip if parent has the same NOT NULL change
812
+ if (!parentHasSameColumnPropertyChange(name, "not_null")) {
813
+ if (branchCol.not_null) {
814
+ changes.push(
815
+ new AlterTableAlterColumnSetNotNull({
816
+ table: branchTable,
817
+ column: branchCol,
818
+ }),
819
+ );
820
+ } else {
821
+ changes.push(
822
+ new AlterTableAlterColumnDropNotNull({
823
+ table: branchTable,
824
+ column: branchCol,
825
+ }),
826
+ );
827
+ }
828
+ }
829
+ }
830
+
831
+ // COMMENT change on column
832
+ // Note: Comments are NOT automatically propagated from parent to partitions,
833
+ // so we should NOT skip comment changes even if parent has the same change
834
+ if (mainCol.comment !== branchCol.comment) {
835
+ if (branchCol.comment === null) {
836
+ changes.push(
837
+ new DropCommentOnColumn({ table: mainTable, column: mainCol }),
838
+ );
839
+ } else {
840
+ changes.push(
841
+ new CreateCommentOnColumn({
842
+ table: branchTable,
843
+ column: branchCol,
844
+ }),
845
+ );
846
+ }
847
+ }
848
+ }
849
+
850
+ // PRIVILEGES (unified object and column privileges)
851
+ // Filter out owner privileges - owner always has ALL privileges implicitly
852
+ // and shouldn't be compared. Use branch owner as the reference.
853
+ const privilegeResults = diffPrivileges(
854
+ mainTable.privileges,
855
+ branchTable.privileges,
856
+ branchTable.owner,
857
+ ctx.mainRoles,
858
+ );
859
+
860
+ for (const [grantee, result] of privilegeResults) {
861
+ // Generate grant changes
862
+ if (result.grants.length > 0) {
863
+ const grantGroups = groupPrivilegesByColumns(result.grants);
864
+ for (const [, group] of grantGroups) {
865
+ for (const [grantable, privSet] of group.byGrant) {
866
+ const privileges = Array.from(privSet).map((priv) => ({
867
+ privilege: priv,
868
+ grantable,
869
+ }));
870
+ changes.push(
871
+ new GrantTablePrivileges({
872
+ table: branchTable,
873
+ grantee,
874
+ privileges,
875
+ columns: group.columns,
876
+ version: ctx.version,
877
+ }),
878
+ );
879
+ }
880
+ }
881
+ }
882
+
883
+ // Generate revoke changes
884
+ if (result.revokes.length > 0) {
885
+ const revokeGroups = groupPrivilegesByColumns(result.revokes);
886
+ for (const [, group] of revokeGroups) {
887
+ // Collapse all grantable groups into a single revoke (grantable: false)
888
+ const allPrivileges = new Set<string>();
889
+ for (const [, privSet] of group.byGrant) {
890
+ for (const priv of privSet) {
891
+ allPrivileges.add(priv);
892
+ }
893
+ }
894
+ const privileges = Array.from(allPrivileges).map((priv) => ({
895
+ privilege: priv,
896
+ grantable: false,
897
+ }));
898
+ changes.push(
899
+ new RevokeTablePrivileges({
900
+ table: mainTable,
901
+ grantee,
902
+ privileges,
903
+ columns: group.columns,
904
+ version: ctx.version,
905
+ }),
906
+ );
907
+ }
908
+ }
909
+
910
+ // Generate revoke grant option changes
911
+ if (result.revokeGrantOption.length > 0) {
912
+ const revokeGrantGroups = new Map<
913
+ string,
914
+ { columns?: string[]; privileges: Set<string> }
915
+ >();
916
+ for (const r of result.revokeGrantOption) {
917
+ // For revoke grant option, we need to find the columns from the original privilege
918
+ const originalPriv = mainTable.privileges.find(
919
+ (p) => p.grantee === grantee && p.privilege === r,
920
+ );
921
+ const key = originalPriv?.columns
922
+ ? originalPriv.columns.sort().join(",")
923
+ : "";
924
+ if (!revokeGrantGroups.has(key)) {
925
+ revokeGrantGroups.set(key, {
926
+ columns: originalPriv?.columns
927
+ ? [...originalPriv.columns]
928
+ : undefined,
929
+ privileges: new Set(),
930
+ });
931
+ }
932
+ const group = revokeGrantGroups.get(key);
933
+ if (!group) continue;
934
+ group.privileges.add(r);
935
+ }
936
+ for (const [, group] of revokeGrantGroups) {
937
+ const privilegeNames = Array.from(group.privileges);
938
+ changes.push(
939
+ new RevokeGrantOptionTablePrivileges({
940
+ table: mainTable,
941
+ grantee,
942
+ privilegeNames,
943
+ columns: group.columns,
944
+ version: ctx.version,
945
+ }),
946
+ );
947
+ }
948
+ }
949
+ }
950
+ }
951
+
952
+ return changes;
953
+ }