@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,404 @@
1
+ import type { DefaultPrivilegeState } from "../base.default-privileges.ts";
2
+ import { diffObjects } from "../base.diff.ts";
3
+ import {
4
+ diffPrivileges,
5
+ filterPublicBuiltInDefaults,
6
+ groupPrivilegesByGrantable,
7
+ } from "../base.privilege-diff.ts";
8
+ import type { Role } from "../role/role.model.ts";
9
+ import { deepEqual, hasNonAlterableChanges } from "../utils.ts";
10
+ import {
11
+ AlterProcedureChangeOwner,
12
+ AlterProcedureSetConfig,
13
+ AlterProcedureSetLeakproof,
14
+ AlterProcedureSetParallel,
15
+ AlterProcedureSetSecurity,
16
+ AlterProcedureSetStrictness,
17
+ AlterProcedureSetVolatility,
18
+ } from "./changes/procedure.alter.ts";
19
+ import {
20
+ CreateCommentOnProcedure,
21
+ DropCommentOnProcedure,
22
+ } from "./changes/procedure.comment.ts";
23
+ import { CreateProcedure } from "./changes/procedure.create.ts";
24
+ import { DropProcedure } from "./changes/procedure.drop.ts";
25
+ import {
26
+ GrantProcedurePrivileges,
27
+ RevokeGrantOptionProcedurePrivileges,
28
+ RevokeProcedurePrivileges,
29
+ } from "./changes/procedure.privilege.ts";
30
+ import type { ProcedureChange } from "./changes/procedure.types.ts";
31
+ import type { Procedure } from "./procedure.model.ts";
32
+
33
+ /**
34
+ * Diff two sets of procedures from main and branch catalogs.
35
+ *
36
+ * @param ctx - Context containing version, currentUser, and defaultPrivilegeState
37
+ * @param main - The procedures in the main catalog.
38
+ * @param branch - The procedures in the branch catalog.
39
+ * @returns A list of changes to apply to main to make it match branch.
40
+ */
41
+ export function diffProcedures(
42
+ ctx: {
43
+ version: number;
44
+ currentUser: string;
45
+ defaultPrivilegeState: DefaultPrivilegeState;
46
+ mainRoles: Record<string, Role>;
47
+ },
48
+ main: Record<string, Procedure>,
49
+ branch: Record<string, Procedure>,
50
+ ): ProcedureChange[] {
51
+ const { created, dropped, altered } = diffObjects(main, branch);
52
+
53
+ const changes: ProcedureChange[] = [];
54
+
55
+ for (const procedureId of created) {
56
+ const proc = branch[procedureId];
57
+ changes.push(new CreateProcedure({ procedure: proc }));
58
+
59
+ // OWNER: If the procedure should be owned by someone other than the current user,
60
+ // emit ALTER FUNCTION/PROCEDURE ... OWNER TO after creation
61
+ if (proc.owner !== ctx.currentUser) {
62
+ changes.push(
63
+ new AlterProcedureChangeOwner({
64
+ procedure: proc,
65
+ owner: proc.owner,
66
+ }),
67
+ );
68
+ }
69
+
70
+ if (proc.comment !== null) {
71
+ changes.push(new CreateCommentOnProcedure({ procedure: proc }));
72
+ }
73
+
74
+ // PRIVILEGES: For created objects, compare against default privileges state
75
+ // The migration script will run ALTER DEFAULT PRIVILEGES before CREATE (via constraint spec),
76
+ // so objects are created with the default privileges state in effect.
77
+ // We compare default privileges against desired privileges to generate REVOKE/GRANT statements
78
+ // needed to reach the final desired state.
79
+ const effectiveDefaults = ctx.defaultPrivilegeState.getEffectiveDefaults(
80
+ ctx.currentUser,
81
+ "procedure",
82
+ proc.schema ?? "",
83
+ );
84
+ // Filter out PUBLIC's built-in default EXECUTE privilege (PostgreSQL grants it automatically)
85
+ // Reference: https://www.postgresql.org/docs/17/ddl-priv.html Table 5.2
86
+ // This prevents generating unnecessary "GRANT EXECUTE TO PUBLIC" statements
87
+ const desiredPrivileges = filterPublicBuiltInDefaults(
88
+ "procedure",
89
+ proc.privileges,
90
+ );
91
+ // Filter out owner privileges - owner always has ALL privileges implicitly
92
+ // and shouldn't be compared. Note: we use the final owner (proc.owner), not the
93
+ // current user, because ownership change happens before privilege diffing.
94
+ const privilegeResults = diffPrivileges(
95
+ effectiveDefaults,
96
+ desiredPrivileges,
97
+ proc.owner,
98
+ ctx.mainRoles,
99
+ );
100
+
101
+ // Generate grant changes
102
+ for (const [grantee, result] of privilegeResults) {
103
+ if (result.grants.length > 0) {
104
+ const grantGroups = groupPrivilegesByGrantable(result.grants);
105
+ for (const [grantable, list] of grantGroups) {
106
+ void grantable;
107
+ changes.push(
108
+ new GrantProcedurePrivileges({
109
+ procedure: proc,
110
+ grantee,
111
+ privileges: list,
112
+ version: ctx.version,
113
+ }),
114
+ );
115
+ }
116
+ }
117
+
118
+ // Generate revoke changes
119
+ if (result.revokes.length > 0) {
120
+ const revokeGroups = groupPrivilegesByGrantable(result.revokes);
121
+ for (const [grantable, list] of revokeGroups) {
122
+ void grantable;
123
+ changes.push(
124
+ new RevokeProcedurePrivileges({
125
+ procedure: proc,
126
+ grantee,
127
+ privileges: list,
128
+ version: ctx.version,
129
+ }),
130
+ );
131
+ }
132
+ }
133
+
134
+ // Generate revoke grant option changes
135
+ if (result.revokeGrantOption.length > 0) {
136
+ changes.push(
137
+ new RevokeGrantOptionProcedurePrivileges({
138
+ procedure: proc,
139
+ grantee,
140
+ privilegeNames: result.revokeGrantOption,
141
+ version: ctx.version,
142
+ }),
143
+ );
144
+ }
145
+ }
146
+ }
147
+
148
+ for (const procedureId of dropped) {
149
+ changes.push(new DropProcedure({ procedure: main[procedureId] }));
150
+ }
151
+
152
+ for (const procedureId of altered) {
153
+ const mainProcedure = main[procedureId];
154
+ const branchProcedure = branch[procedureId];
155
+
156
+ // Check if non-alterable properties have changed
157
+ // These require dropping and recreating the procedure
158
+ const NON_ALTERABLE_FIELDS: Array<keyof Procedure> = [
159
+ "kind",
160
+ "return_type",
161
+ "return_type_schema",
162
+ "language",
163
+ // The following properties are alterable in SQL, but our generator may choose
164
+ // to replace on changes not covered by explicit ALTER actions. Keep them out here
165
+ // to allow ALTER for those we implement below.
166
+ // security_definer,
167
+ // volatility,
168
+ // parallel_safety,
169
+ // is_strict,
170
+ // leakproof,
171
+ // Returns-set is part of the signature and not alterable
172
+ "returns_set",
173
+ "argument_count",
174
+ "argument_default_count",
175
+ "argument_names",
176
+ "argument_types",
177
+ "all_argument_types",
178
+ "argument_modes",
179
+ "argument_defaults",
180
+ "source_code",
181
+ "binary_path",
182
+ "sql_body",
183
+ // config is alterable via SET/RESET
184
+ ];
185
+ const nonAlterablePropsChanged = hasNonAlterableChanges(
186
+ mainProcedure,
187
+ branchProcedure,
188
+ NON_ALTERABLE_FIELDS,
189
+ {
190
+ argument_names: deepEqual,
191
+ argument_types: deepEqual,
192
+ all_argument_types: deepEqual,
193
+ argument_modes: deepEqual,
194
+ config: deepEqual,
195
+ },
196
+ );
197
+
198
+ if (nonAlterablePropsChanged) {
199
+ // Replace the entire procedure
200
+ changes.push(
201
+ new CreateProcedure({ procedure: branchProcedure, orReplace: true }),
202
+ );
203
+ } else {
204
+ // Only alterable properties changed - check each one
205
+
206
+ // OWNER
207
+ if (mainProcedure.owner !== branchProcedure.owner) {
208
+ changes.push(
209
+ new AlterProcedureChangeOwner({
210
+ procedure: mainProcedure,
211
+ owner: branchProcedure.owner,
212
+ }),
213
+ );
214
+ }
215
+
216
+ // COMMENT
217
+ if (mainProcedure.comment !== branchProcedure.comment) {
218
+ if (branchProcedure.comment === null) {
219
+ changes.push(
220
+ new DropCommentOnProcedure({ procedure: mainProcedure }),
221
+ );
222
+ } else {
223
+ changes.push(
224
+ new CreateCommentOnProcedure({ procedure: branchProcedure }),
225
+ );
226
+ }
227
+ }
228
+
229
+ // SECURITY DEFINER/INVOKER
230
+ if (mainProcedure.security_definer !== branchProcedure.security_definer) {
231
+ changes.push(
232
+ new AlterProcedureSetSecurity({
233
+ procedure: mainProcedure,
234
+ securityDefiner: branchProcedure.security_definer,
235
+ }),
236
+ );
237
+ }
238
+
239
+ // CONFIG SET/RESET
240
+ const toMap = (opts?: string[] | null) => {
241
+ const map = new Map<string, string>();
242
+ for (const opt of opts ?? []) {
243
+ const eq = opt.indexOf("=");
244
+ const key = opt.slice(0, eq).trim();
245
+ const value = opt.slice(eq + 1).trim();
246
+ map.set(key, value);
247
+ }
248
+ return map;
249
+ };
250
+ const mainCfg = toMap(mainProcedure.config);
251
+ const branchCfg = toMap(branchProcedure.config);
252
+ if (branchCfg.size === 0 && mainCfg.size > 0) {
253
+ // Branch has no config at all -> prefer a single RESET ALL
254
+ changes.push(
255
+ new AlterProcedureSetConfig({
256
+ procedure: mainProcedure,
257
+ action: "reset_all",
258
+ }),
259
+ );
260
+ } else {
261
+ for (const [key, oldValue] of mainCfg.entries()) {
262
+ const hasInBranch = branchCfg.has(key);
263
+ const newValue = branchCfg.get(key);
264
+ const changed = hasInBranch ? oldValue !== newValue : true;
265
+ if (changed) {
266
+ changes.push(
267
+ new AlterProcedureSetConfig({
268
+ procedure: mainProcedure,
269
+ action: "reset",
270
+ key,
271
+ }),
272
+ );
273
+ }
274
+ }
275
+ for (const [key, newValue] of branchCfg.entries()) {
276
+ const oldValue = mainCfg.get(key);
277
+ if (oldValue !== newValue) {
278
+ changes.push(
279
+ new AlterProcedureSetConfig({
280
+ procedure: mainProcedure,
281
+ action: "set",
282
+ key,
283
+ value: newValue,
284
+ }),
285
+ );
286
+ }
287
+ }
288
+ }
289
+
290
+ // VOLATILITY
291
+ if (mainProcedure.volatility !== branchProcedure.volatility) {
292
+ changes.push(
293
+ new AlterProcedureSetVolatility({
294
+ procedure: mainProcedure,
295
+ volatility: branchProcedure.volatility,
296
+ }),
297
+ );
298
+ }
299
+
300
+ // STRICTNESS
301
+ if (mainProcedure.is_strict !== branchProcedure.is_strict) {
302
+ changes.push(
303
+ new AlterProcedureSetStrictness({
304
+ procedure: mainProcedure,
305
+ isStrict: branchProcedure.is_strict,
306
+ }),
307
+ );
308
+ }
309
+
310
+ // LEAKPROOF
311
+ if (mainProcedure.leakproof !== branchProcedure.leakproof) {
312
+ changes.push(
313
+ new AlterProcedureSetLeakproof({
314
+ procedure: mainProcedure,
315
+ leakproof: branchProcedure.leakproof,
316
+ }),
317
+ );
318
+ }
319
+
320
+ // PARALLEL
321
+ if (mainProcedure.parallel_safety !== branchProcedure.parallel_safety) {
322
+ changes.push(
323
+ new AlterProcedureSetParallel({
324
+ procedure: mainProcedure,
325
+ parallelSafety: branchProcedure.parallel_safety,
326
+ }),
327
+ );
328
+ }
329
+
330
+ // Note: Procedure renaming would also use ALTER FUNCTION/PROCEDURE ... RENAME TO ...
331
+ // But since our Procedure model uses 'name' as the identity field,
332
+ // a name change would be handled as drop + create by diffObjects()
333
+
334
+ // PRIVILEGES
335
+ // Filter out PUBLIC's built-in default EXECUTE privilege from main catalog
336
+ // (PostgreSQL grants it automatically, so we shouldn't compare it)
337
+ const mainPrivilegesFiltered = filterPublicBuiltInDefaults(
338
+ "procedure",
339
+ mainProcedure.privileges,
340
+ );
341
+ // Filter out PUBLIC's built-in default EXECUTE privilege from branch catalog
342
+ const branchPrivilegesFiltered = filterPublicBuiltInDefaults(
343
+ "procedure",
344
+ branchProcedure.privileges,
345
+ );
346
+ // Filter out owner privileges - owner always has ALL privileges implicitly
347
+ // and shouldn't be compared. Use branch owner as the reference.
348
+ const privilegeResults = diffPrivileges(
349
+ mainPrivilegesFiltered,
350
+ branchPrivilegesFiltered,
351
+ branchProcedure.owner,
352
+ ctx.mainRoles,
353
+ );
354
+
355
+ for (const [grantee, result] of privilegeResults) {
356
+ // Generate grant changes
357
+ if (result.grants.length > 0) {
358
+ const grantGroups = groupPrivilegesByGrantable(result.grants);
359
+ for (const [grantable, list] of grantGroups) {
360
+ void grantable;
361
+ changes.push(
362
+ new GrantProcedurePrivileges({
363
+ procedure: branchProcedure,
364
+ grantee,
365
+ privileges: list,
366
+ version: ctx.version,
367
+ }),
368
+ );
369
+ }
370
+ }
371
+
372
+ // Generate revoke changes
373
+ if (result.revokes.length > 0) {
374
+ const revokeGroups = groupPrivilegesByGrantable(result.revokes);
375
+ for (const [grantable, list] of revokeGroups) {
376
+ void grantable;
377
+ changes.push(
378
+ new RevokeProcedurePrivileges({
379
+ procedure: mainProcedure,
380
+ grantee,
381
+ privileges: list,
382
+ version: ctx.version,
383
+ }),
384
+ );
385
+ }
386
+ }
387
+
388
+ // Generate revoke grant option changes
389
+ if (result.revokeGrantOption.length > 0) {
390
+ changes.push(
391
+ new RevokeGrantOptionProcedurePrivileges({
392
+ procedure: mainProcedure,
393
+ grantee,
394
+ privilegeNames: result.revokeGrantOption,
395
+ version: ctx.version,
396
+ }),
397
+ );
398
+ }
399
+ }
400
+ }
401
+ }
402
+
403
+ return changes;
404
+ }
@@ -0,0 +1,264 @@
1
+ import { sql } from "@ts-safeql/sql-tag";
2
+ import type { Pool } from "pg";
3
+ import z from "zod";
4
+ import { BasePgModel } from "../base.model.ts";
5
+ import {
6
+ type PrivilegeProps,
7
+ privilegePropsSchema,
8
+ } from "../base.privilege-diff.ts";
9
+
10
+ const FunctionKindSchema = z.enum([
11
+ "f", // function
12
+ "p", // procedure
13
+ "a", // aggregate function
14
+ "w", // window function
15
+ ]);
16
+
17
+ const FunctionVolatilitySchema = z.enum([
18
+ "i", // IMMUTABLE
19
+ "s", // STABLE
20
+ "v", // VOLATILE
21
+ ]);
22
+
23
+ const FunctionParallelSafetySchema = z.enum([
24
+ "u", // UNSAFE (cannot run in parallel)
25
+ "s", // SAFE (can run in parallel)
26
+ "r", // RESTRICTED (can run in parallel with restrictions)
27
+ ]);
28
+
29
+ const FunctionArgumentModeSchema = z.enum([
30
+ "i", // IN parameter
31
+ "o", // OUT parameter
32
+ "b", // INOUT parameter
33
+ "v", // VARIADIC parameter
34
+ "t", // TABLE parameter
35
+ ]);
36
+
37
+ const procedurePropsSchema = z.object({
38
+ schema: z.string(),
39
+ name: z.string(),
40
+ kind: FunctionKindSchema,
41
+ return_type: z.string(),
42
+ return_type_schema: z.string(),
43
+ language: z.string(),
44
+ security_definer: z.boolean(),
45
+ volatility: FunctionVolatilitySchema,
46
+ parallel_safety: FunctionParallelSafetySchema,
47
+ execution_cost: z.number(),
48
+ result_rows: z.number(),
49
+ is_strict: z.boolean(),
50
+ leakproof: z.boolean(),
51
+ returns_set: z.boolean(),
52
+ argument_count: z.number(),
53
+ argument_default_count: z.number(),
54
+ argument_names: z.array(z.string()).nullable(),
55
+ argument_types: z.array(z.string()).nullable(),
56
+ all_argument_types: z.array(z.string()).nullable(),
57
+ argument_modes: z.array(FunctionArgumentModeSchema).nullable(),
58
+ argument_defaults: z.string().nullable(),
59
+ source_code: z.string().nullable(),
60
+ binary_path: z.string().nullable(),
61
+ sql_body: z.string().nullable(),
62
+ definition: z.string(),
63
+ config: z.array(z.string()).nullable(),
64
+ owner: z.string(),
65
+ comment: z.string().nullable(),
66
+ privileges: z.array(privilegePropsSchema),
67
+ });
68
+
69
+ type ProcedurePrivilegeProps = PrivilegeProps;
70
+ export type ProcedureProps = z.infer<typeof procedurePropsSchema>;
71
+
72
+ export class Procedure extends BasePgModel {
73
+ public readonly schema: ProcedureProps["schema"];
74
+ public readonly name: ProcedureProps["name"];
75
+ public readonly kind: ProcedureProps["kind"];
76
+ public readonly return_type: ProcedureProps["return_type"];
77
+ public readonly return_type_schema: ProcedureProps["return_type_schema"];
78
+ public readonly language: ProcedureProps["language"];
79
+ public readonly security_definer: ProcedureProps["security_definer"];
80
+ public readonly volatility: ProcedureProps["volatility"];
81
+ public readonly parallel_safety: ProcedureProps["parallel_safety"];
82
+ public readonly execution_cost: ProcedureProps["execution_cost"];
83
+ public readonly result_rows: ProcedureProps["result_rows"];
84
+ public readonly is_strict: ProcedureProps["is_strict"];
85
+ public readonly leakproof: ProcedureProps["leakproof"];
86
+ public readonly returns_set: ProcedureProps["returns_set"];
87
+ public readonly argument_count: ProcedureProps["argument_count"];
88
+ public readonly argument_default_count: ProcedureProps["argument_default_count"];
89
+ public readonly argument_names: ProcedureProps["argument_names"];
90
+ public readonly argument_types: ProcedureProps["argument_types"];
91
+ public readonly all_argument_types: ProcedureProps["all_argument_types"];
92
+ public readonly argument_modes: ProcedureProps["argument_modes"];
93
+ public readonly argument_defaults: ProcedureProps["argument_defaults"];
94
+ public readonly source_code: ProcedureProps["source_code"];
95
+ public readonly binary_path: ProcedureProps["binary_path"];
96
+ public readonly sql_body: ProcedureProps["sql_body"];
97
+ public readonly definition: ProcedureProps["definition"];
98
+ public readonly config: ProcedureProps["config"];
99
+ public readonly owner: ProcedureProps["owner"];
100
+ public readonly comment: ProcedureProps["comment"];
101
+ public readonly privileges: ProcedurePrivilegeProps[];
102
+
103
+ constructor(props: ProcedureProps) {
104
+ super();
105
+
106
+ // Identity fields
107
+ this.schema = props.schema;
108
+ this.name = props.name;
109
+
110
+ // Data fields
111
+ this.kind = props.kind;
112
+ this.return_type = props.return_type;
113
+ this.return_type_schema = props.return_type_schema;
114
+ this.language = props.language;
115
+ this.security_definer = props.security_definer;
116
+ this.volatility = props.volatility;
117
+ this.parallel_safety = props.parallel_safety;
118
+ this.execution_cost = props.execution_cost;
119
+ this.result_rows = props.result_rows;
120
+ this.is_strict = props.is_strict;
121
+ this.leakproof = props.leakproof;
122
+ this.returns_set = props.returns_set;
123
+ this.argument_count = props.argument_count;
124
+ this.argument_default_count = props.argument_default_count;
125
+ this.argument_names = props.argument_names;
126
+ this.argument_types = props.argument_types;
127
+ this.all_argument_types = props.all_argument_types;
128
+ this.argument_modes = props.argument_modes;
129
+ this.argument_defaults = props.argument_defaults;
130
+ this.source_code = props.source_code;
131
+ this.binary_path = props.binary_path;
132
+ this.sql_body = props.sql_body;
133
+ this.definition = props.definition;
134
+ this.config = props.config;
135
+ this.owner = props.owner;
136
+ this.comment = props.comment;
137
+ this.privileges = props.privileges;
138
+ }
139
+
140
+ get stableId(): `procedure:${string}` {
141
+ const args = this.argument_types?.join(",") ?? "";
142
+ return `procedure:${this.schema}.${this.name}(${args})`;
143
+ }
144
+
145
+ get identityFields() {
146
+ return {
147
+ schema: this.schema,
148
+ name: this.name,
149
+ };
150
+ }
151
+
152
+ get dataFields() {
153
+ return {
154
+ kind: this.kind,
155
+ return_type: this.return_type,
156
+ return_type_schema: this.return_type_schema,
157
+ language: this.language,
158
+ security_definer: this.security_definer,
159
+ volatility: this.volatility,
160
+ parallel_safety: this.parallel_safety,
161
+ // execution_cost and result_rows are planner hints. We intentionally
162
+ // exclude them from dataFields to avoid generating diffs solely due to
163
+ // changes in estimates. They are still used for CREATE serialization.
164
+ is_strict: this.is_strict,
165
+ leakproof: this.leakproof,
166
+ returns_set: this.returns_set,
167
+ argument_count: this.argument_count,
168
+ argument_default_count: this.argument_default_count,
169
+ argument_names: this.argument_names,
170
+ argument_types: this.argument_types,
171
+ all_argument_types: this.all_argument_types,
172
+ argument_modes: this.argument_modes,
173
+ argument_defaults: this.argument_defaults,
174
+ source_code: this.source_code,
175
+ binary_path: this.binary_path,
176
+ sql_body: this.sql_body,
177
+ definition: this.definition,
178
+ config: this.config,
179
+ owner: this.owner,
180
+ comment: this.comment,
181
+ privileges: this.privileges,
182
+ };
183
+ }
184
+ }
185
+
186
+ export async function extractProcedures(pool: Pool): Promise<Procedure[]> {
187
+ const { rows: procedureRows } = await pool.query<ProcedureProps>(sql`
188
+ with extension_oids as (
189
+ select
190
+ objid
191
+ from
192
+ pg_depend d
193
+ where
194
+ d.refclassid = 'pg_extension'::regclass
195
+ and d.classid = 'pg_proc'::regclass
196
+ )
197
+ select
198
+ p.pronamespace::regnamespace::text as schema,
199
+ quote_ident(p.proname) as name,
200
+ p.prokind as kind,
201
+ format_type(p.prorettype, null) as return_type,
202
+ rt.typnamespace::regnamespace::text as return_type_schema,
203
+ l.lanname as language,
204
+ p.prosecdef as security_definer,
205
+ p.provolatile as volatility,
206
+ p.proparallel as parallel_safety,
207
+ p.procost as execution_cost,
208
+ p.prorows as result_rows,
209
+ p.proisstrict as is_strict,
210
+ p.proleakproof as leakproof,
211
+ p.proretset as returns_set,
212
+ p.pronargs as argument_count,
213
+ p.pronargdefaults as argument_default_count,
214
+ -- quote argument names server-side for safe serialization
215
+ case when p.proargnames is null then null
216
+ else array(select quote_ident(n) from unnest(p.proargnames) as n)
217
+ end as argument_names,
218
+ array(
219
+ select format_type(oid, null)
220
+ from unnest(p.proargtypes) as oid
221
+ ) as argument_types,
222
+ array(
223
+ select format_type(oid, null)
224
+ from unnest(p.proallargtypes) as oid
225
+ ) as all_argument_types,
226
+ p.proargmodes as argument_modes,
227
+ pg_get_expr(p.proargdefaults, 0) as argument_defaults,
228
+ p.prosrc as source_code,
229
+ p.probin as binary_path,
230
+ pg_get_function_sqlbody(p.oid) as sql_body,
231
+ pg_get_functiondef(p.oid) as definition,
232
+ p.proconfig as config,
233
+ p.proowner::regrole::text as owner,
234
+ obj_description(p.oid, 'pg_proc') as comment,
235
+ coalesce(
236
+ (
237
+ select json_agg(
238
+ json_build_object(
239
+ 'grantee', case when x.grantee = 0 then 'PUBLIC' else x.grantee::regrole::text end,
240
+ 'privilege', x.privilege_type,
241
+ 'grantable', x.is_grantable
242
+ )
243
+ order by x.grantee, x.privilege_type
244
+ )
245
+ from lateral aclexplode(p.proacl) as x(grantor, grantee, privilege_type, is_grantable)
246
+ ), '[]'
247
+ ) as privileges
248
+ from
249
+ pg_catalog.pg_proc p
250
+ inner join pg_catalog.pg_language l on l.oid = p.prolang
251
+ left join pg_catalog.pg_type rt on rt.oid = p.prorettype
252
+ left outer join extension_oids e on p.oid = e.objid
253
+ where not p.pronamespace::regnamespace::text like any(array['pg\\_%', 'information\\_schema'])
254
+ and e.objid is null
255
+ and l.lanname not in ('c', 'internal')
256
+ order by
257
+ 1, 2
258
+ `);
259
+ // Validate and parse each row using the Zod schema
260
+ const validatedRows = procedureRows.map((row: unknown) =>
261
+ procedurePropsSchema.parse(row),
262
+ );
263
+ return validatedRows.map((row: ProcedureProps) => new Procedure(row));
264
+ }