@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,299 @@
1
+ import z from "zod";
2
+ import type { Change } from "../change.types.ts";
3
+ import type { Role } from "./role/role.model.ts";
4
+ import { stableId } from "./utils.ts";
5
+
6
+ /**
7
+ * Privilege properties that all privilege objects share.
8
+ */
9
+ export const privilegePropsSchema = z.object({
10
+ grantee: z.string(),
11
+ privilege: z.string(),
12
+ grantable: z.boolean(),
13
+ columns: z.array(z.string()).nullable().optional(),
14
+ });
15
+
16
+ export type PrivilegeProps = z.infer<typeof privilegePropsSchema>;
17
+
18
+ /**
19
+ * Result of privilege diffing for a single grantee
20
+ */
21
+ interface PrivilegeDiffResult<T extends PrivilegeProps> {
22
+ grants: T[];
23
+ revokes: T[];
24
+ revokeGrantOption: string[];
25
+ }
26
+
27
+ /**
28
+ * Groups privileges by grantee for efficient diffing
29
+ */
30
+ function groupPrivilegesByGrantee<T extends PrivilegeProps>(
31
+ privileges: T[],
32
+ ): Map<string, T[]> {
33
+ const byGrantee = new Map<string, T[]>();
34
+
35
+ for (const privilege of privileges) {
36
+ const existing = byGrantee.get(privilege.grantee) || [];
37
+ existing.push(privilege);
38
+ byGrantee.set(privilege.grantee, existing);
39
+ }
40
+
41
+ return byGrantee;
42
+ }
43
+
44
+ /**
45
+ * Diffs privileges for a single grantee between main and branch
46
+ */
47
+ function diffPrivilegesForGrantee<T extends PrivilegeProps>(
48
+ mainPrivs: T[],
49
+ branchPrivs: T[],
50
+ ): PrivilegeDiffResult<T> {
51
+ // Create comparison key - always include columns (null for object-level privileges)
52
+ const toKey = (p: T) => {
53
+ const cols = p.columns || [];
54
+ return `${p.privilege}:${p.grantable}:${cols.sort().join(",")}`;
55
+ };
56
+
57
+ // Create key-to-object mappings to retain original data structures
58
+ const mainKeyToObj = new Map(mainPrivs.map((p) => [toKey(p), p]));
59
+ const branchKeyToObj = new Map(branchPrivs.map((p) => [toKey(p), p]));
60
+
61
+ const aSet = new Set(mainPrivs.map(toKey));
62
+ const bSet = new Set(branchPrivs.map(toKey));
63
+
64
+ const grants: T[] = [];
65
+ const revokes: T[] = [];
66
+ const revokeGrantOption: string[] = [];
67
+
68
+ // Find privileges to grant
69
+ for (const key of bSet) {
70
+ if (!aSet.has(key)) {
71
+ const obj = branchKeyToObj.get(key);
72
+ if (obj) grants.push(obj);
73
+ }
74
+ }
75
+
76
+ // Find privileges to revoke
77
+ for (const key of aSet) {
78
+ if (!bSet.has(key)) {
79
+ const obj = mainKeyToObj.get(key);
80
+ if (!obj) continue;
81
+
82
+ const wasGrantable = obj.grantable;
83
+
84
+ // Upgrade: base -> with grant option (no base revoke)
85
+ const upgradedKey = key.replace(":false", ":true");
86
+ const upgraded = !wasGrantable && bSet.has(upgradedKey);
87
+ if (upgraded) continue;
88
+
89
+ // If only grantable flipped from true to false, emit REVOKE GRANT OPTION FOR
90
+ const stillHasBase = checkStillHasBase(branchPrivs, obj.privilege, key);
91
+ if (wasGrantable && stillHasBase) {
92
+ revokeGrantOption.push(obj.privilege);
93
+ } else {
94
+ revokes.push(obj);
95
+ }
96
+ }
97
+ }
98
+
99
+ return { grants, revokes, revokeGrantOption };
100
+ }
101
+
102
+ /**
103
+ * Check if a privilege still exists in the target set
104
+ */
105
+ function checkStillHasBase<T extends PrivilegeProps>(
106
+ targetPrivs: T[],
107
+ privilege: string,
108
+ key: string,
109
+ ): boolean {
110
+ const [, , columnsStr] = key.split(":");
111
+ return targetPrivs.some(
112
+ (p) =>
113
+ p.privilege === privilege &&
114
+ (p.columns || []).sort().join(",") === columnsStr,
115
+ );
116
+ }
117
+
118
+ /**
119
+ * Groups privileges by grantable flag for efficient SQL generation
120
+ */
121
+ export function groupPrivilegesByGrantable<T extends PrivilegeProps>(
122
+ privileges: T[],
123
+ ): Map<boolean, T[]> {
124
+ const groups = new Map<boolean, T[]>();
125
+
126
+ for (const privilege of privileges) {
127
+ const arr = groups.get(privilege.grantable) ?? [];
128
+ arr.push(privilege);
129
+ groups.set(privilege.grantable, arr);
130
+ }
131
+
132
+ return groups;
133
+ }
134
+
135
+ /**
136
+ * Groups privileges by columns and grantable flag
137
+ */
138
+ export function groupPrivilegesByColumns<T extends PrivilegeProps>(
139
+ privileges: T[],
140
+ ): Map<string, { columns?: string[]; byGrant: Map<boolean, Set<string>> }> {
141
+ const groups = new Map<
142
+ string,
143
+ { columns?: string[]; byGrant: Map<boolean, Set<string>> }
144
+ >();
145
+
146
+ for (const privilege of privileges) {
147
+ const key = privilege.columns ? privilege.columns.sort().join(",") : "";
148
+
149
+ if (!groups.has(key)) {
150
+ groups.set(key, {
151
+ columns: privilege.columns ? [...privilege.columns] : undefined,
152
+ byGrant: new Map(),
153
+ });
154
+ }
155
+
156
+ const group = groups.get(key);
157
+ if (!group) continue;
158
+
159
+ if (!group.byGrant.has(privilege.grantable)) {
160
+ group.byGrant.set(privilege.grantable, new Set());
161
+ }
162
+
163
+ const privSet = group.byGrant.get(privilege.grantable);
164
+ if (!privSet) continue;
165
+
166
+ privSet.add(privilege.privilege);
167
+ }
168
+
169
+ return groups;
170
+ }
171
+
172
+ /**
173
+ * Filters out PUBLIC's built-in default privileges that PostgreSQL automatically grants
174
+ * when creating certain object types. This prevents generating unnecessary GRANT statements
175
+ * for privileges that PostgreSQL grants automatically.
176
+ *
177
+ * Reference: PostgreSQL 17 Documentation, Table 5.2 "Summary of Access Privileges"
178
+ * https://www.postgresql.org/docs/17/ddl-priv.html
179
+ *
180
+ * Objects with default PUBLIC privileges:
181
+ * - Functions/Procedures/Aggregates: EXECUTE
182
+ * - Types/Domains/Enums/Ranges/Composite Types: USAGE
183
+ * - Languages: USAGE
184
+ *
185
+ * Objects WITHOUT default PUBLIC privileges (so we should generate GRANT statements):
186
+ * - Tables, Views, Materialized Views, Sequences, Schemas, etc.
187
+ */
188
+ export function filterPublicBuiltInDefaults<T extends PrivilegeProps>(
189
+ objectType: Change["objectType"],
190
+ privileges: T[],
191
+ ): T[] {
192
+ // Only filter PUBLIC privileges
193
+ return privileges.filter((priv) => {
194
+ if (priv.grantee !== "PUBLIC") {
195
+ return true; // Keep all non-PUBLIC privileges
196
+ }
197
+
198
+ // Check if this is a built-in default privilege for this object type
199
+ switch (objectType) {
200
+ case "procedure":
201
+ case "aggregate":
202
+ // Functions/Procedures/Aggregates: EXECUTE is granted to PUBLIC by default
203
+ // Filter it out so we don't generate unnecessary GRANT EXECUTE TO PUBLIC
204
+ return priv.privilege !== "EXECUTE";
205
+
206
+ case "domain":
207
+ case "enum":
208
+ case "range":
209
+ case "composite_type":
210
+ // Types/Domains/Enums/Ranges/Composite Types: USAGE is granted to PUBLIC by default
211
+ // Filter it out so we don't generate unnecessary GRANT USAGE TO PUBLIC
212
+ return priv.privilege !== "USAGE";
213
+
214
+ case "language":
215
+ // Languages: USAGE is granted to PUBLIC by default
216
+ // Filter it out so we don't generate unnecessary GRANT USAGE TO PUBLIC
217
+ return priv.privilege !== "USAGE";
218
+
219
+ default:
220
+ // For other object types (tables, views, sequences, schemas, etc.),
221
+ // PUBLIC has NO default privileges, so we should keep all PUBLIC privileges
222
+ // and generate GRANT statements for them
223
+ return true;
224
+ }
225
+ });
226
+ }
227
+
228
+ /**
229
+ * Filter out owner privileges from a privilege list.
230
+ * Owner privileges are implicit (owner always has ALL) and shouldn't be compared.
231
+ */
232
+ function filterOwnerPrivileges<T extends PrivilegeProps>(
233
+ privileges: T[],
234
+ owner: string,
235
+ ): T[] {
236
+ return privileges.filter((p) => p.grantee !== owner);
237
+ }
238
+
239
+ /**
240
+ * Filter out privileges for superuser roles, as PostgreSQL doesn't store
241
+ * GRANTs to superusers in relacl (they already have all privileges implicitly).
242
+ * Reference: https://www.postgresql.org/docs/current/role-attributes.html
243
+ */
244
+ function filterSuperuserPrivileges<T extends PrivilegeProps>(
245
+ privileges: T[],
246
+ mainRoles?: Record<string, Role>,
247
+ ): T[] {
248
+ if (!mainRoles) return privileges;
249
+ return privileges.filter((priv) => {
250
+ const role = mainRoles[stableId.role(priv.grantee)];
251
+ return !role?.is_superuser;
252
+ });
253
+ }
254
+
255
+ /**
256
+ * Generic privilege diffing function that works for any object type
257
+ */
258
+ export function diffPrivileges<T extends PrivilegeProps>(
259
+ mainPrivileges: T[],
260
+ branchPrivileges: T[],
261
+ owner?: string,
262
+ mainRoles?: Record<string, Role>,
263
+ ): Map<string, PrivilegeDiffResult<T>> {
264
+ // Filter out superuser privileges from branch - PostgreSQL doesn't store GRANTs
265
+ // to superusers in relacl because they already have all privileges implicitly
266
+ const branchPrivilegesFiltered = filterSuperuserPrivileges(
267
+ branchPrivileges,
268
+ mainRoles,
269
+ );
270
+
271
+ // Filter out owner privileges if owner is provided
272
+ const mainFiltered = owner
273
+ ? filterOwnerPrivileges(mainPrivileges, owner)
274
+ : mainPrivileges;
275
+ const branchFiltered = owner
276
+ ? filterOwnerPrivileges(branchPrivilegesFiltered, owner)
277
+ : branchPrivilegesFiltered;
278
+
279
+ const mainByGrantee = groupPrivilegesByGrantee(mainFiltered);
280
+ const branchByGrantee = groupPrivilegesByGrantee(branchFiltered);
281
+
282
+ // Get all grantees
283
+ const allGrantees = new Set([
284
+ ...mainByGrantee.keys(),
285
+ ...branchByGrantee.keys(),
286
+ ]);
287
+
288
+ const results = new Map<string, PrivilegeDiffResult<T>>();
289
+
290
+ for (const grantee of allGrantees) {
291
+ const mainPrivs = mainByGrantee.get(grantee) || [];
292
+ const branchPrivs = branchByGrantee.get(grantee) || [];
293
+
294
+ const result = diffPrivilegesForGrantee(mainPrivs, branchPrivs);
295
+ results.set(grantee, result);
296
+ }
297
+
298
+ return results;
299
+ }
@@ -0,0 +1,184 @@
1
+ /**
2
+ * Base utilities and helpers for object privilege changes.
3
+ * These functions support GRANT/REVOKE operations across different database objects.
4
+ */
5
+
6
+ import type { PrivilegeProps } from "./base.privilege-diff.ts";
7
+
8
+ /**
9
+ * Returns the complete set of available privileges for a given object kind.
10
+ * This is used to determine whether a privilege list represents "ALL PRIVILEGES".
11
+ *
12
+ * @param kind - The PostgreSQL object kind (TABLE, VIEW, SEQUENCE, etc.)
13
+ * @param version - The PostgreSQL version number (e.g., 170000 for 17.0.0)
14
+ * @returns An array of privilege names available for this object kind
15
+ */
16
+ function objectPrivilegeUniverse(
17
+ kind: string,
18
+ version: number | undefined,
19
+ ): string[] {
20
+ switch (kind) {
21
+ case "TABLE": {
22
+ const includesMaintain = (version ?? 170000) >= 170000;
23
+ return [
24
+ "DELETE",
25
+ "INSERT",
26
+ ...(includesMaintain ? (["MAINTAIN"] as const) : []),
27
+ "REFERENCES",
28
+ "SELECT",
29
+ "TRIGGER",
30
+ "TRUNCATE",
31
+ "UPDATE",
32
+ ];
33
+ }
34
+ case "VIEW": {
35
+ // Per PostgreSQL docs, views are table-like and share the table privilege set
36
+ // for GRANT/REVOKE purposes. MAINTAIN exists on PostgreSQL >= 17
37
+ const includesMaintain = (version ?? 170000) >= 170000;
38
+ return [
39
+ "DELETE",
40
+ "INSERT",
41
+ ...(includesMaintain ? (["MAINTAIN"] as const) : []),
42
+ "REFERENCES",
43
+ "SELECT",
44
+ "TRIGGER",
45
+ "TRUNCATE",
46
+ "UPDATE",
47
+ ];
48
+ }
49
+ case "MATERIALIZED VIEW": {
50
+ // Materialized views support the same table-like privileges as tables/views
51
+ // Per PostgreSQL docs, materialized views are table-like for GRANT/REVOKE purposes
52
+ const includesMaintain = (version ?? 170000) >= 170000;
53
+ return [
54
+ "DELETE",
55
+ "INSERT",
56
+ ...(includesMaintain ? (["MAINTAIN"] as const) : []),
57
+ "REFERENCES",
58
+ "SELECT",
59
+ "TRIGGER",
60
+ "TRUNCATE",
61
+ "UPDATE",
62
+ ];
63
+ }
64
+ case "SEQUENCE":
65
+ return ["SELECT", "UPDATE", "USAGE"].sort();
66
+ case "SCHEMA":
67
+ return ["CREATE", "USAGE"].sort();
68
+ case "LANGUAGE":
69
+ return ["USAGE"];
70
+ case "FUNCTION":
71
+ case "PROCEDURE":
72
+ case "ROUTINE":
73
+ return ["EXECUTE"];
74
+ case "TYPE":
75
+ case "DOMAIN":
76
+ return ["USAGE"];
77
+ case "FOREIGN DATA WRAPPER":
78
+ return ["USAGE"];
79
+ case "SERVER":
80
+ return ["USAGE"];
81
+ case "FOREIGN TABLE": {
82
+ const includesMaintain = (version ?? 170000) >= 170000;
83
+ return [
84
+ "DELETE",
85
+ "INSERT",
86
+ ...(includesMaintain ? (["MAINTAIN"] as const) : []),
87
+ "REFERENCES",
88
+ "SELECT",
89
+ "TRIGGER",
90
+ "TRUNCATE",
91
+ "UPDATE",
92
+ ];
93
+ }
94
+ default:
95
+ return [];
96
+ }
97
+ }
98
+
99
+ /**
100
+ * Checks if a privilege list represents the full set of privileges for an object kind.
101
+ * This determines whether we can use "ALL PRIVILEGES" shorthand in SQL.
102
+ *
103
+ * @param kind - The PostgreSQL object kind
104
+ * @param list - Array of privilege names to check
105
+ * @param version - The PostgreSQL version number
106
+ * @returns true if the list contains all available privileges for this object kind
107
+ */
108
+ function isFullObjectPrivilegeSet(
109
+ kind: string,
110
+ list: string[],
111
+ version: number | undefined,
112
+ ): boolean {
113
+ const uniqSorted = [...new Set(list)].sort();
114
+ const fullSorted = [...objectPrivilegeUniverse(kind, version)].sort();
115
+ if (uniqSorted.length !== fullSorted.length) return false;
116
+ for (let i = 0; i < uniqSorted.length; i++) {
117
+ if (uniqSorted[i] !== fullSorted[i]) return false;
118
+ }
119
+ return true;
120
+ }
121
+
122
+ /**
123
+ * Formats a list of privileges for use in GRANT/REVOKE statements.
124
+ * If the list represents all privileges, returns "ALL", otherwise returns a comma-separated list.
125
+ *
126
+ * @param kind - The PostgreSQL object kind
127
+ * @param list - Array of privilege names to format
128
+ * @param version - The PostgreSQL version number
129
+ * @returns A SQL-formatted privilege list (either "ALL" or "PRIV1, PRIV2, ...")
130
+ */
131
+ export function formatObjectPrivilegeList(
132
+ kind: string,
133
+ list: string[],
134
+ version: number | undefined,
135
+ ): string {
136
+ const uniqSorted = [...new Set(list)].sort();
137
+ return isFullObjectPrivilegeSet(kind, uniqSorted, version)
138
+ ? "ALL"
139
+ : uniqSorted.join(", ");
140
+ }
141
+
142
+ /**
143
+ * Gets the SQL keyword prefix for a given object kind in GRANT/REVOKE statements.
144
+ *
145
+ * @param objectKind - The PostgreSQL object kind
146
+ * @returns The SQL prefix (e.g., "ON SCHEMA", "ON DOMAIN", "ON")
147
+ */
148
+ export function getObjectKindPrefix(objectKind: string): string {
149
+ switch (objectKind) {
150
+ case "FUNCTION":
151
+ return "ON FUNCTION";
152
+ case "PROCEDURE":
153
+ return "ON PROCEDURE";
154
+ case "ROUTINE":
155
+ return "ON ROUTINE";
156
+ case "LANGUAGE":
157
+ return "ON LANGUAGE";
158
+ case "SCHEMA":
159
+ return "ON SCHEMA";
160
+ case "SEQUENCE":
161
+ return "ON SEQUENCE";
162
+ case "DOMAIN":
163
+ return "ON DOMAIN";
164
+ case "TYPE":
165
+ return "ON TYPE";
166
+ case "FOREIGN TABLE":
167
+ return "ON FOREIGN TABLE";
168
+ default:
169
+ return "ON";
170
+ }
171
+ }
172
+
173
+ export function normalizePrivileges(privileges: PrivilegeProps[]) {
174
+ return privileges
175
+ .map((privilege) => ({
176
+ grantee: privilege.grantee,
177
+ privilege: privilege.privilege,
178
+ grantable: privilege.grantable,
179
+ }))
180
+ .sort((a, b) => {
181
+ if (a.grantee !== b.grantee) return a.grantee.localeCompare(b.grantee);
182
+ return a.privilege.localeCompare(b.privilege);
183
+ });
184
+ }
@@ -0,0 +1,63 @@
1
+ import { describe, expect, test } from "bun:test";
2
+ import { Collation } from "../collation.model.ts";
3
+ import {
4
+ AlterCollationChangeOwner,
5
+ AlterCollationRefreshVersion,
6
+ } from "./collation.alter.ts";
7
+
8
+ describe.concurrent("collation", () => {
9
+ describe("alter", () => {
10
+ test("change owner", () => {
11
+ const collation = new Collation({
12
+ schema: "public",
13
+ name: "test",
14
+ provider: "c",
15
+ is_deterministic: true,
16
+ encoding: 1,
17
+ collate: "en_US",
18
+ locale: "en_US",
19
+ version: "1.0",
20
+ ctype: "test",
21
+ icu_rules: "test",
22
+ comment: null,
23
+ owner: "old_owner",
24
+ });
25
+
26
+ const change = new AlterCollationChangeOwner({
27
+ collation,
28
+ owner: "new_owner",
29
+ });
30
+
31
+ expect(change.serialize()).toBe(
32
+ "ALTER COLLATION public.test OWNER TO new_owner",
33
+ );
34
+ });
35
+
36
+ test("refresh version", () => {
37
+ const collation = new Collation({
38
+ schema: "public",
39
+ name: "test",
40
+ provider: "c",
41
+ is_deterministic: true,
42
+ encoding: 1,
43
+ collate: "en_US",
44
+ locale: "en_US",
45
+ ctype: "test",
46
+ icu_rules: "test",
47
+ comment: null,
48
+ owner: "test",
49
+ version: "1.0",
50
+ });
51
+
52
+ const change = new AlterCollationRefreshVersion({
53
+ collation,
54
+ });
55
+
56
+ expect(change.serialize()).toBe(
57
+ "ALTER COLLATION public.test REFRESH VERSION",
58
+ );
59
+ });
60
+
61
+ // replace behavior moved into collation.diff.ts as separate Drop + Create
62
+ });
63
+ });
@@ -0,0 +1,79 @@
1
+ import type { Collation } from "../collation.model.ts";
2
+ import { AlterCollationChange } from "./collation.base.ts";
3
+
4
+ /**
5
+ * Alter a collation.
6
+ *
7
+ * @see https://www.postgresql.org/docs/17/sql-altercollation.html
8
+ *
9
+ * Synopsis
10
+ * ```sql
11
+ * ALTER COLLATION name REFRESH VERSION
12
+ * ALTER COLLATION name OWNER TO { new_owner | CURRENT_ROLE | CURRENT_USER | SESSION_USER }
13
+ * ALTER COLLATION name RENAME TO new_name
14
+ * ```
15
+ */
16
+
17
+ export type AlterCollation =
18
+ | AlterCollationChangeOwner
19
+ | AlterCollationRefreshVersion;
20
+
21
+ /**
22
+ * ALTER COLLATION ... OWNER TO ...
23
+ */
24
+ export class AlterCollationChangeOwner extends AlterCollationChange {
25
+ public readonly collation: Collation;
26
+ public readonly owner: string;
27
+ public readonly scope = "object" as const;
28
+
29
+ constructor(props: { collation: Collation; owner: string }) {
30
+ super();
31
+ this.collation = props.collation;
32
+ this.owner = props.owner;
33
+ }
34
+
35
+ get requires() {
36
+ return [this.collation.stableId];
37
+ }
38
+
39
+ serialize(): string {
40
+ return [
41
+ "ALTER COLLATION",
42
+ `${this.collation.schema}.${this.collation.name}`,
43
+ "OWNER TO",
44
+ this.owner,
45
+ ].join(" ");
46
+ }
47
+ }
48
+
49
+ /**
50
+ * ALTER COLLATION ... REFRESH VERSION
51
+ */
52
+ export class AlterCollationRefreshVersion extends AlterCollationChange {
53
+ public readonly collation: Collation;
54
+ public readonly scope = "object" as const;
55
+
56
+ constructor(props: { collation: Collation }) {
57
+ super();
58
+ this.collation = props.collation;
59
+ }
60
+
61
+ get requires() {
62
+ return [this.collation.stableId];
63
+ }
64
+
65
+ serialize(): string {
66
+ return [
67
+ "ALTER COLLATION",
68
+ `${this.collation.schema}.${this.collation.name}`,
69
+ "REFRESH VERSION",
70
+ ].join(" ");
71
+ }
72
+ }
73
+
74
+ /**
75
+ * Replace a collation by dropping and recreating it.
76
+ * This is used when properties that cannot be altered via ALTER COLLATION change.
77
+ */
78
+ // NOTE: ReplaceCollation has been removed. Non-alterable property changes
79
+ // are modeled as separate DropCollation + CreateCollation changes in collation.diff.ts.
@@ -0,0 +1,20 @@
1
+ import { BaseChange } from "../../base.change.ts";
2
+ import type { Collation } from "../collation.model.ts";
3
+
4
+ abstract class BaseCollationChange extends BaseChange {
5
+ abstract readonly collation: Collation;
6
+ abstract readonly scope: "object" | "comment";
7
+ readonly objectType: "collation" = "collation";
8
+ }
9
+
10
+ export abstract class CreateCollationChange extends BaseCollationChange {
11
+ readonly operation = "create" as const;
12
+ }
13
+
14
+ export abstract class AlterCollationChange extends BaseCollationChange {
15
+ readonly operation = "alter" as const;
16
+ }
17
+
18
+ export abstract class DropCollationChange extends BaseCollationChange {
19
+ readonly operation = "drop" as const;
20
+ }