@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,175 @@
1
+ import {
2
+ formatObjectPrivilegeList,
3
+ getObjectKindPrefix,
4
+ } from "../../../base.privilege.ts";
5
+ import { stableId } from "../../../utils.ts";
6
+ import type { Range } from "../range.model.ts";
7
+ import { AlterRangeChange } from "./range.base.ts";
8
+
9
+ export type RangePrivilege =
10
+ | GrantRangePrivileges
11
+ | RevokeRangePrivileges
12
+ | RevokeGrantOptionRangePrivileges;
13
+
14
+ /**
15
+ * Grant privileges on a range type.
16
+ *
17
+ * @see https://www.postgresql.org/docs/17/sql-grant.html
18
+ *
19
+ * Synopsis
20
+ * ```sql
21
+ * GRANT { USAGE | ALL [ PRIVILEGES ] }
22
+ * ON TYPE type_name [, ...]
23
+ * TO role_specification [, ...] [ WITH GRANT OPTION ]
24
+ * [ GRANTED BY role_specification ]
25
+ * ```
26
+ */
27
+ export class GrantRangePrivileges extends AlterRangeChange {
28
+ public readonly range: Range;
29
+ public readonly grantee: string;
30
+ public readonly privileges: { privilege: string; grantable: boolean }[];
31
+ public readonly version: number | undefined;
32
+ public readonly scope = "privilege" as const;
33
+
34
+ constructor(props: {
35
+ range: Range;
36
+ grantee: string;
37
+ privileges: { privilege: string; grantable: boolean }[];
38
+ version?: number;
39
+ }) {
40
+ super();
41
+ this.range = props.range;
42
+ this.grantee = props.grantee;
43
+ this.privileges = props.privileges;
44
+ this.version = props.version;
45
+ }
46
+
47
+ get creates() {
48
+ return [stableId.acl(this.range.stableId, this.grantee)];
49
+ }
50
+
51
+ get requires() {
52
+ return [this.range.stableId, stableId.role(this.grantee)];
53
+ }
54
+
55
+ serialize(): string {
56
+ const hasGrantable = this.privileges.some((p) => p.grantable);
57
+ const hasBase = this.privileges.some((p) => !p.grantable);
58
+ if (hasGrantable && hasBase) {
59
+ throw new Error(
60
+ "GrantRangePrivileges expects privileges with uniform grantable flag",
61
+ );
62
+ }
63
+ const withGrant = hasGrantable ? " WITH GRANT OPTION" : "";
64
+ const kindPrefix = getObjectKindPrefix("TYPE");
65
+ const list = this.privileges.map((p) => p.privilege);
66
+ const privSql = formatObjectPrivilegeList("TYPE", list, this.version);
67
+ const typeName = `${this.range.schema}.${this.range.name}`;
68
+ return `GRANT ${privSql} ${kindPrefix} ${typeName} TO ${this.grantee}${withGrant}`;
69
+ }
70
+ }
71
+
72
+ /**
73
+ * Revoke privileges on a range type.
74
+ *
75
+ * @see https://www.postgresql.org/docs/17/sql-revoke.html
76
+ *
77
+ * Synopsis
78
+ * ```sql
79
+ * REVOKE [ GRANT OPTION FOR ]
80
+ * { USAGE | ALL [ PRIVILEGES ] }
81
+ * ON TYPE type_name [, ...]
82
+ * FROM role_specification [, ...]
83
+ * [ GRANTED BY role_specification ]
84
+ * [ CASCADE | RESTRICT ]
85
+ * ```
86
+ */
87
+ export class RevokeRangePrivileges extends AlterRangeChange {
88
+ public readonly range: Range;
89
+ public readonly grantee: string;
90
+ public readonly privileges: { privilege: string; grantable: boolean }[];
91
+ public readonly version: number | undefined;
92
+ public readonly scope = "privilege" as const;
93
+
94
+ constructor(props: {
95
+ range: Range;
96
+ grantee: string;
97
+ privileges: { privilege: string; grantable: boolean }[];
98
+ version?: number;
99
+ }) {
100
+ super();
101
+ this.range = props.range;
102
+ this.grantee = props.grantee;
103
+ this.privileges = props.privileges;
104
+ this.version = props.version;
105
+ }
106
+
107
+ get drops() {
108
+ // Return ACL ID for dependency tracking, even though this is an ALTER operation
109
+ // Phase assignment now uses operation type, so this won't affect phase placement
110
+ return [stableId.acl(this.range.stableId, this.grantee)];
111
+ }
112
+
113
+ get requires() {
114
+ return [
115
+ stableId.acl(this.range.stableId, this.grantee),
116
+ this.range.stableId,
117
+ stableId.role(this.grantee),
118
+ ];
119
+ }
120
+
121
+ serialize(): string {
122
+ const kindPrefix = getObjectKindPrefix("TYPE");
123
+ const list = this.privileges.map((p) => p.privilege);
124
+ const privSql = formatObjectPrivilegeList("TYPE", list, this.version);
125
+ const typeName = `${this.range.schema}.${this.range.name}`;
126
+ return `REVOKE ${privSql} ${kindPrefix} ${typeName} FROM ${this.grantee}`;
127
+ }
128
+ }
129
+
130
+ /**
131
+ * Revoke grant option for privileges on a range type.
132
+ *
133
+ * This removes the ability to grant the privilege to others, but keeps the privilege itself.
134
+ *
135
+ * @see https://www.postgresql.org/docs/17/sql-revoke.html
136
+ */
137
+ export class RevokeGrantOptionRangePrivileges extends AlterRangeChange {
138
+ public readonly range: Range;
139
+ public readonly grantee: string;
140
+ public readonly privilegeNames: string[];
141
+ public readonly version: number | undefined;
142
+ public readonly scope = "privilege" as const;
143
+
144
+ constructor(props: {
145
+ range: Range;
146
+ grantee: string;
147
+ privilegeNames: string[];
148
+ version?: number;
149
+ }) {
150
+ super();
151
+ this.range = props.range;
152
+ this.grantee = props.grantee;
153
+ this.privilegeNames = [...new Set(props.privilegeNames)].sort();
154
+ this.version = props.version;
155
+ }
156
+
157
+ get requires() {
158
+ return [
159
+ stableId.acl(this.range.stableId, this.grantee),
160
+ this.range.stableId,
161
+ stableId.role(this.grantee),
162
+ ];
163
+ }
164
+
165
+ serialize(): string {
166
+ const kindPrefix = getObjectKindPrefix("TYPE");
167
+ const privSql = formatObjectPrivilegeList(
168
+ "TYPE",
169
+ this.privilegeNames,
170
+ this.version,
171
+ );
172
+ const typeName = `${this.range.schema}.${this.range.name}`;
173
+ return `REVOKE GRANT OPTION FOR ${privSql} ${kindPrefix} ${typeName} FROM ${this.grantee}`;
174
+ }
175
+ }
@@ -0,0 +1,12 @@
1
+ import type { AlterRange } from "./range.alter.ts";
2
+ import type { CommentRange } from "./range.comment.ts";
3
+ import type { CreateRange } from "./range.create.ts";
4
+ import type { DropRange } from "./range.drop.ts";
5
+ import type { RangePrivilege } from "./range.privilege.ts";
6
+
7
+ export type RangeChange =
8
+ | AlterRange
9
+ | CommentRange
10
+ | CreateRange
11
+ | DropRange
12
+ | RangePrivilege;
@@ -0,0 +1,70 @@
1
+ import { describe, expect, test } from "bun:test";
2
+ import { DefaultPrivilegeState } from "../../base.default-privileges.ts";
3
+ import { AlterRangeChangeOwner } from "./changes/range.alter.ts";
4
+ import { CreateRange } from "./changes/range.create.ts";
5
+ import { DropRange } from "./changes/range.drop.ts";
6
+ import { diffRanges } from "./range.diff.ts";
7
+ import { Range, type RangeProps } from "./range.model.ts";
8
+
9
+ const base: RangeProps = {
10
+ schema: "public",
11
+ name: "ts_custom",
12
+ owner: "o1",
13
+ subtype_schema: "pg_catalog",
14
+ subtype_str: "int4",
15
+ collation: null,
16
+ canonical_function_schema: null,
17
+ canonical_function_name: null,
18
+ subtype_diff_schema: null,
19
+ subtype_diff_name: null,
20
+ subtype_opclass_schema: null,
21
+ subtype_opclass_name: null,
22
+ comment: null,
23
+ privileges: [],
24
+ };
25
+
26
+ const testContext = {
27
+ version: 170000,
28
+ currentUser: "postgres",
29
+ defaultPrivilegeState: new DefaultPrivilegeState({}),
30
+ mainRoles: {},
31
+ };
32
+
33
+ describe.concurrent("range.diff", () => {
34
+ test("create and drop", () => {
35
+ const r = new Range(base);
36
+ const created = diffRanges(testContext, {}, { [r.stableId]: r });
37
+ expect(created[0]).toBeInstanceOf(CreateRange);
38
+ const dropped = diffRanges(testContext, { [r.stableId]: r }, {});
39
+ expect(dropped[0]).toBeInstanceOf(DropRange);
40
+ });
41
+
42
+ test("alter owner", () => {
43
+ const main = new Range(base);
44
+ const branch = new Range({ ...base, owner: "o2" });
45
+ const changes = diffRanges(
46
+ testContext,
47
+ { [main.stableId]: main },
48
+ { [branch.stableId]: branch },
49
+ );
50
+ expect(changes[0]).toBeInstanceOf(AlterRangeChangeOwner);
51
+ });
52
+
53
+ test("drop and create when non-alterable property changes", () => {
54
+ const main = new Range(base);
55
+ const branch = new Range({
56
+ ...base,
57
+ subtype_schema: "pg_catalog",
58
+ subtype_str: "text",
59
+ collation: "en_US",
60
+ });
61
+ const changes = diffRanges(
62
+ testContext,
63
+ { [main.stableId]: main },
64
+ { [branch.stableId]: branch },
65
+ );
66
+ expect(changes).toHaveLength(2);
67
+ expect(changes[0]).toBeInstanceOf(DropRange);
68
+ expect(changes[1]).toBeInstanceOf(CreateRange);
69
+ });
70
+ });
@@ -0,0 +1,259 @@
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 { hasNonAlterableChanges } from "../../utils.ts";
10
+ import { AlterRangeChangeOwner } from "./changes/range.alter.ts";
11
+ import {
12
+ CreateCommentOnRange,
13
+ DropCommentOnRange,
14
+ } from "./changes/range.comment.ts";
15
+ import { CreateRange } from "./changes/range.create.ts";
16
+ import { DropRange } from "./changes/range.drop.ts";
17
+ import {
18
+ GrantRangePrivileges,
19
+ RevokeGrantOptionRangePrivileges,
20
+ RevokeRangePrivileges,
21
+ } from "./changes/range.privilege.ts";
22
+ import type { RangeChange } from "./changes/range.types.ts";
23
+ import type { Range } from "./range.model.ts";
24
+
25
+ /**
26
+ * Diff two sets of range types from main and branch catalogs.
27
+ *
28
+ * @param ctx - Context containing version, currentUser, and defaultPrivilegeState
29
+ * @param main - The ranges in the main catalog.
30
+ * @param branch - The ranges in the branch catalog.
31
+ * @returns A list of changes to apply to main to make it match branch.
32
+ */
33
+ export function diffRanges(
34
+ ctx: {
35
+ version: number;
36
+ currentUser: string;
37
+ defaultPrivilegeState: DefaultPrivilegeState;
38
+ mainRoles: Record<string, Role>;
39
+ },
40
+ main: Record<string, Range>,
41
+ branch: Record<string, Range>,
42
+ ): RangeChange[] {
43
+ const { created, dropped, altered } = diffObjects(main, branch);
44
+
45
+ const changes: RangeChange[] = [];
46
+
47
+ for (const id of created) {
48
+ const createdRange = branch[id];
49
+ changes.push(new CreateRange({ range: createdRange }));
50
+
51
+ // OWNER: If the range type should be owned by someone other than the current user,
52
+ // emit ALTER TYPE ... OWNER TO after creation
53
+ if (createdRange.owner !== ctx.currentUser) {
54
+ changes.push(
55
+ new AlterRangeChangeOwner({
56
+ range: createdRange,
57
+ owner: createdRange.owner,
58
+ }),
59
+ );
60
+ }
61
+
62
+ if (createdRange.comment !== null) {
63
+ changes.push(new CreateCommentOnRange({ range: createdRange }));
64
+ }
65
+
66
+ // PRIVILEGES: For created objects, compare against default privileges state
67
+ // The migration script will run ALTER DEFAULT PRIVILEGES before CREATE (via constraint spec),
68
+ // so objects are created with the default privileges state in effect.
69
+ // We compare default privileges against desired privileges to generate REVOKE/GRANT statements
70
+ // needed to reach the final desired state.
71
+ const effectiveDefaults = ctx.defaultPrivilegeState.getEffectiveDefaults(
72
+ ctx.currentUser,
73
+ "range",
74
+ createdRange.schema ?? "",
75
+ );
76
+ // Filter out PUBLIC's built-in default USAGE privilege (PostgreSQL grants it automatically)
77
+ // Reference: https://www.postgresql.org/docs/17/ddl-priv.html Table 5.2
78
+ // This prevents generating unnecessary "GRANT USAGE TO PUBLIC" statements
79
+ const desiredPrivileges = filterPublicBuiltInDefaults(
80
+ "range",
81
+ createdRange.privileges,
82
+ );
83
+ // Filter out owner privileges - owner always has ALL privileges implicitly
84
+ // and shouldn't be compared. Use the range owner as the reference.
85
+ const privilegeResults = diffPrivileges(
86
+ effectiveDefaults,
87
+ desiredPrivileges,
88
+ createdRange.owner,
89
+ );
90
+
91
+ // Generate grant changes
92
+ for (const [grantee, result] of privilegeResults) {
93
+ if (result.grants.length > 0) {
94
+ const grantGroups = groupPrivilegesByGrantable(result.grants);
95
+ for (const [grantable, list] of grantGroups) {
96
+ void grantable;
97
+ changes.push(
98
+ new GrantRangePrivileges({
99
+ range: createdRange,
100
+ grantee,
101
+ privileges: list,
102
+ version: ctx.version,
103
+ }),
104
+ );
105
+ }
106
+ }
107
+
108
+ // Generate revoke changes
109
+ if (result.revokes.length > 0) {
110
+ const revokeGroups = groupPrivilegesByGrantable(result.revokes);
111
+ for (const [grantable, list] of revokeGroups) {
112
+ void grantable;
113
+ changes.push(
114
+ new RevokeRangePrivileges({
115
+ range: createdRange,
116
+ grantee,
117
+ privileges: list,
118
+ version: ctx.version,
119
+ }),
120
+ );
121
+ }
122
+ }
123
+
124
+ // Generate revoke grant option changes
125
+ if (result.revokeGrantOption.length > 0) {
126
+ changes.push(
127
+ new RevokeGrantOptionRangePrivileges({
128
+ range: createdRange,
129
+ grantee,
130
+ privilegeNames: result.revokeGrantOption,
131
+ version: ctx.version,
132
+ }),
133
+ );
134
+ }
135
+ }
136
+ }
137
+
138
+ for (const id of dropped) {
139
+ changes.push(new DropRange({ range: main[id] }));
140
+ }
141
+
142
+ for (const id of altered) {
143
+ const mainRange = main[id];
144
+ const branchRange = branch[id];
145
+
146
+ const NON_ALTERABLE_FIELDS: Array<keyof Range> = [
147
+ // Changes to these require DROP + CREATE
148
+ "subtype_schema",
149
+ "subtype_str",
150
+ "collation",
151
+ "canonical_function_schema",
152
+ "canonical_function_name",
153
+ "subtype_diff_schema",
154
+ "subtype_diff_name",
155
+ "subtype_opclass_schema",
156
+ "subtype_opclass_name",
157
+ ];
158
+
159
+ const nonAlterablePropsChanged = hasNonAlterableChanges(
160
+ mainRange,
161
+ branchRange,
162
+ NON_ALTERABLE_FIELDS,
163
+ );
164
+
165
+ if (nonAlterablePropsChanged) {
166
+ changes.push(
167
+ new DropRange({ range: mainRange }),
168
+ new CreateRange({ range: branchRange }),
169
+ );
170
+ } else {
171
+ if (mainRange.owner !== branchRange.owner) {
172
+ changes.push(
173
+ new AlterRangeChangeOwner({
174
+ range: mainRange,
175
+ owner: branchRange.owner,
176
+ }),
177
+ );
178
+ }
179
+
180
+ // COMMENT
181
+ if (mainRange.comment !== branchRange.comment) {
182
+ if (branchRange.comment === null) {
183
+ changes.push(new DropCommentOnRange({ range: mainRange }));
184
+ } else {
185
+ changes.push(new CreateCommentOnRange({ range: branchRange }));
186
+ }
187
+ }
188
+
189
+ // PRIVILEGES
190
+ // Filter out PUBLIC's built-in default USAGE privilege from main catalog
191
+ // (PostgreSQL grants it automatically, so we shouldn't compare it)
192
+ const mainPrivilegesFiltered = filterPublicBuiltInDefaults(
193
+ "range",
194
+ mainRange.privileges,
195
+ );
196
+ // Filter out PUBLIC's built-in default USAGE privilege from branch catalog
197
+ const branchPrivilegesFiltered = filterPublicBuiltInDefaults(
198
+ "range",
199
+ branchRange.privileges,
200
+ );
201
+ // Filter out owner privileges - owner always has ALL privileges implicitly
202
+ // and shouldn't be compared. Use branch owner as the reference.
203
+ const privilegeResults = diffPrivileges(
204
+ mainPrivilegesFiltered,
205
+ branchPrivilegesFiltered,
206
+ branchRange.owner,
207
+ ctx.mainRoles,
208
+ );
209
+
210
+ for (const [grantee, result] of privilegeResults) {
211
+ // Generate grant changes
212
+ if (result.grants.length > 0) {
213
+ const grantGroups = groupPrivilegesByGrantable(result.grants);
214
+ for (const [grantable, list] of grantGroups) {
215
+ void grantable;
216
+ changes.push(
217
+ new GrantRangePrivileges({
218
+ range: branchRange,
219
+ grantee,
220
+ privileges: list,
221
+ version: ctx.version,
222
+ }),
223
+ );
224
+ }
225
+ }
226
+
227
+ // Generate revoke changes
228
+ if (result.revokes.length > 0) {
229
+ const revokeGroups = groupPrivilegesByGrantable(result.revokes);
230
+ for (const [grantable, list] of revokeGroups) {
231
+ void grantable;
232
+ changes.push(
233
+ new RevokeRangePrivileges({
234
+ range: mainRange,
235
+ grantee,
236
+ privileges: list,
237
+ version: ctx.version,
238
+ }),
239
+ );
240
+ }
241
+ }
242
+
243
+ // Generate revoke grant option changes
244
+ if (result.revokeGrantOption.length > 0) {
245
+ changes.push(
246
+ new RevokeGrantOptionRangePrivileges({
247
+ range: mainRange,
248
+ grantee,
249
+ privilegeNames: result.revokeGrantOption,
250
+ version: ctx.version,
251
+ }),
252
+ );
253
+ }
254
+ }
255
+ }
256
+ }
257
+
258
+ return changes;
259
+ }
@@ -0,0 +1,187 @@
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 rangePropsSchema = z.object({
11
+ schema: z.string(),
12
+ name: z.string(),
13
+ owner: z.string(),
14
+ comment: z.string().nullable(),
15
+
16
+ // Subtype information
17
+ subtype_schema: z.string(),
18
+ subtype_str: z.string(),
19
+
20
+ // Optional, only present when non-default relative to subtype
21
+ collation: z.string().nullable(),
22
+
23
+ // Canonical and diff functions when present (non-default)
24
+ canonical_function_schema: z.string().nullable(),
25
+ canonical_function_name: z.string().nullable(),
26
+ subtype_diff_schema: z.string().nullable(),
27
+ subtype_diff_name: z.string().nullable(),
28
+
29
+ // Optional: print only when non-default (see extractor logic)
30
+ subtype_opclass_schema: z.string().nullable(),
31
+ subtype_opclass_name: z.string().nullable(),
32
+ privileges: z.array(privilegePropsSchema),
33
+ });
34
+
35
+ type RangePrivilegeProps = PrivilegeProps;
36
+ export type RangeProps = z.infer<typeof rangePropsSchema>;
37
+
38
+ export class Range extends BasePgModel {
39
+ public readonly schema: RangeProps["schema"];
40
+ public readonly name: RangeProps["name"];
41
+ public readonly owner: RangeProps["owner"];
42
+ public readonly comment: RangeProps["comment"];
43
+
44
+ public readonly subtype_schema: RangeProps["subtype_schema"];
45
+ public readonly subtype_str: RangeProps["subtype_str"];
46
+
47
+ public readonly collation: RangeProps["collation"];
48
+
49
+ public readonly canonical_function_schema: RangeProps["canonical_function_schema"];
50
+ public readonly canonical_function_name: RangeProps["canonical_function_name"];
51
+ public readonly subtype_diff_schema: RangeProps["subtype_diff_schema"];
52
+ public readonly subtype_diff_name: RangeProps["subtype_diff_name"];
53
+
54
+ public readonly subtype_opclass_schema: RangeProps["subtype_opclass_schema"];
55
+ public readonly subtype_opclass_name: RangeProps["subtype_opclass_name"];
56
+ public readonly privileges: RangePrivilegeProps[];
57
+
58
+ constructor(props: RangeProps) {
59
+ super();
60
+
61
+ // Identity fields
62
+ this.schema = props.schema;
63
+ this.name = props.name;
64
+
65
+ // Data fields
66
+ this.owner = props.owner;
67
+ this.comment = props.comment;
68
+ this.subtype_schema = props.subtype_schema;
69
+ this.subtype_str = props.subtype_str;
70
+ this.collation = props.collation;
71
+ this.canonical_function_schema = props.canonical_function_schema;
72
+ this.canonical_function_name = props.canonical_function_name;
73
+ this.subtype_diff_schema = props.subtype_diff_schema;
74
+ this.subtype_diff_name = props.subtype_diff_name;
75
+ this.subtype_opclass_schema = props.subtype_opclass_schema;
76
+ this.subtype_opclass_name = props.subtype_opclass_name;
77
+ this.privileges = props.privileges;
78
+ }
79
+
80
+ get stableId(): `type:${string}` {
81
+ return `type:${this.schema}.${this.name}`;
82
+ }
83
+
84
+ get identityFields() {
85
+ return {
86
+ schema: this.schema,
87
+ name: this.name,
88
+ };
89
+ }
90
+
91
+ get dataFields() {
92
+ return {
93
+ owner: this.owner,
94
+ subtype_schema: this.subtype_schema,
95
+ subtype_str: this.subtype_str,
96
+ collation: this.collation,
97
+ canonical_function_schema: this.canonical_function_schema,
98
+ canonical_function_name: this.canonical_function_name,
99
+ subtype_diff_schema: this.subtype_diff_schema,
100
+ subtype_diff_name: this.subtype_diff_name,
101
+ subtype_opclass_schema: this.subtype_opclass_schema,
102
+ subtype_opclass_name: this.subtype_opclass_name,
103
+ comment: this.comment,
104
+ privileges: this.privileges,
105
+ };
106
+ }
107
+ }
108
+
109
+ /**
110
+ * Extract all range types from the database.
111
+ *
112
+ * We intentionally capture only non-default options for CREATE TYPE AS RANGE:
113
+ * - SUBTYPE is required and always present
114
+ * - SUBTYPE_OPCLASS is included only when it differs from the default btree opclass
115
+ * - COLLATION is included only when it differs from the subtype's typcollation
116
+ * - CANONICAL and SUBTYPE_DIFF are included only when set
117
+ * - MULTIRANGE_TYPE_NAME is not included (we currently do not attempt to infer
118
+ * whether it differs from the default auto-generated name)
119
+ */
120
+ export async function extractRanges(pool: Pool): Promise<Range[]> {
121
+ const { rows } = await pool.query<RangeProps>(sql`
122
+ with extension_oids as (
123
+ select objid from pg_depend d
124
+ where d.refclassid = 'pg_extension'::regclass and d.classid = 'pg_type'::regclass
125
+ ), default_btree_opclass as (
126
+ -- For each input type, find its default btree operator class
127
+ select oc2.opcintype as type_oid, oc2.oid as opclass_oid
128
+ from pg_opclass oc2
129
+ join pg_am am on am.oid = oc2.opcmethod and am.amname = 'btree'
130
+ where oc2.opcdefault
131
+ )
132
+ select
133
+ -- range type identity
134
+ t.typnamespace::regnamespace::text as schema,
135
+ quote_ident(t.typname) as name,
136
+ t.typowner::regrole::text as owner,
137
+ obj_description(t.oid, 'pg_type') as comment,
138
+
139
+ -- subtype info
140
+ subt.typnamespace::regnamespace::text as subtype_schema,
141
+ format_type(r.rngsubtype, 0) as subtype_str,
142
+
143
+ -- include collation only if not default
144
+ case when r.rngcollation is not null and r.rngcollation <> 0 and r.rngcollation <> subt.typcollation then quote_ident(c.collname) else null end as collation,
145
+
146
+ -- include canonical/subtype_diff when set
147
+ case when r.rngcanonical <> 0 then pn_subcanon.nspname::regnamespace::text else null end as canonical_function_schema,
148
+ case when r.rngcanonical <> 0 then quote_ident(p_subcanon.proname) else null end as canonical_function_name,
149
+ case when r.rngsubdiff <> 0 then pn_subdiff.nspname::regnamespace::text else null end as subtype_diff_schema,
150
+ case when r.rngsubdiff <> 0 then quote_ident(p_subdiff.proname) else null end as subtype_diff_name,
151
+
152
+ -- include opclass only when not default for btree
153
+ case when r.rngsubopc is not null and r.rngsubopc <> 0 and r.rngsubopc <> dbo.opclass_oid then opc.opcnamespace::regnamespace::text else null end as subtype_opclass_schema,
154
+ case when r.rngsubopc is not null and r.rngsubopc <> 0 and r.rngsubopc <> dbo.opclass_oid then quote_ident(opc.opcname) else null end as subtype_opclass_name,
155
+
156
+ -- privileges
157
+ coalesce(
158
+ (
159
+ select json_agg(
160
+ json_build_object(
161
+ 'grantee', case when x.grantee = 0 then 'PUBLIC' else x.grantee::regrole::text end,
162
+ 'privilege', x.privilege_type,
163
+ 'grantable', x.is_grantable
164
+ )
165
+ order by x.grantee, x.privilege_type
166
+ )
167
+ from lateral aclexplode(t.typacl) as x(grantor, grantee, privilege_type, is_grantable)
168
+ ), '[]'
169
+ ) as privileges
170
+ from pg_catalog.pg_range r
171
+ join pg_catalog.pg_type t on t.oid = r.rngtypid
172
+ join pg_catalog.pg_type subt on subt.oid = r.rngsubtype
173
+ left join default_btree_opclass dbo on dbo.type_oid = r.rngsubtype
174
+ left join pg_catalog.pg_opclass opc on opc.oid = r.rngsubopc
175
+ left join pg_catalog.pg_collation c on c.oid = r.rngcollation
176
+ left join pg_catalog.pg_proc p_subcanon on p_subcanon.oid = r.rngcanonical
177
+ left join pg_catalog.pg_namespace pn_subcanon on pn_subcanon.oid = p_subcanon.pronamespace
178
+ left join pg_catalog.pg_proc p_subdiff on p_subdiff.oid = r.rngsubdiff
179
+ left join pg_catalog.pg_namespace pn_subdiff on pn_subdiff.oid = p_subdiff.pronamespace
180
+ left outer join extension_oids e on t.oid = e.objid
181
+ where not t.typnamespace::regnamespace::text like any(array['pg\_%', 'information\_schema'])
182
+ and e.objid is null
183
+ order by 1, 2
184
+ `);
185
+ const validated = rows.map((row: unknown) => rangePropsSchema.parse(row));
186
+ return validated.map((row: RangeProps) => new Range(row));
187
+ }