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

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 (359) hide show
  1. package/README.md +40 -23
  2. package/dist/cli/app.js +26 -3
  3. package/dist/cli/bin/cli.js +5 -0
  4. package/dist/cli/commands/catalog-export.d.ts +5 -0
  5. package/dist/cli/commands/catalog-export.js +64 -0
  6. package/dist/cli/commands/declarative-apply.d.ts +6 -0
  7. package/dist/cli/commands/declarative-apply.js +288 -0
  8. package/dist/cli/commands/declarative-export.d.ts +5 -0
  9. package/dist/cli/commands/declarative-export.js +245 -0
  10. package/dist/cli/commands/plan.js +19 -6
  11. package/dist/cli/exit-code.d.ts +2 -0
  12. package/dist/cli/exit-code.js +7 -0
  13. package/dist/cli/formatters/tree/tree.js +3 -2
  14. package/dist/cli/utils/apply-display.d.ts +52 -0
  15. package/dist/cli/utils/apply-display.js +183 -0
  16. package/dist/cli/utils/export-display.d.ts +43 -0
  17. package/dist/cli/utils/export-display.js +202 -0
  18. package/dist/cli/utils/resolve-input.d.ts +7 -0
  19. package/dist/cli/utils/resolve-input.js +13 -0
  20. package/dist/core/catalog-export/index.d.ts +11 -0
  21. package/dist/core/catalog-export/index.js +10 -0
  22. package/dist/core/catalog.diff.d.ts +1 -0
  23. package/dist/core/catalog.diff.js +64 -48
  24. package/dist/core/catalog.model.d.ts +14 -1
  25. package/dist/core/catalog.model.js +103 -1
  26. package/dist/core/catalog.snapshot.d.ts +66 -0
  27. package/dist/core/catalog.snapshot.js +206 -0
  28. package/dist/core/declarative-apply/discover-sql.d.ts +18 -0
  29. package/dist/core/declarative-apply/discover-sql.js +86 -0
  30. package/dist/core/declarative-apply/extract-catalog-providers.d.ts +23 -0
  31. package/dist/core/declarative-apply/extract-catalog-providers.js +159 -0
  32. package/dist/core/declarative-apply/index.d.ts +49 -0
  33. package/dist/core/declarative-apply/index.js +134 -0
  34. package/dist/core/declarative-apply/round-apply.d.ts +100 -0
  35. package/dist/core/declarative-apply/round-apply.js +378 -0
  36. package/dist/core/export/file-mapper.d.ts +71 -0
  37. package/dist/core/export/file-mapper.js +474 -0
  38. package/dist/core/export/grouper.d.ts +13 -0
  39. package/dist/core/export/grouper.js +76 -0
  40. package/dist/core/export/index.d.ts +45 -0
  41. package/dist/core/export/index.js +63 -0
  42. package/dist/core/export/types.d.ts +84 -0
  43. package/dist/core/export/types.js +25 -0
  44. package/dist/core/fixtures/empty-catalogs/postgres-15-16-baseline.json +287 -0
  45. package/dist/core/integrations/filter/dsl.d.ts +38 -1
  46. package/dist/core/integrations/filter/dsl.js +20 -2
  47. package/dist/core/integrations/filter/extractors.js +42 -0
  48. package/dist/core/integrations/integration-dsl.d.ts +10 -0
  49. package/dist/core/integrations/supabase.d.ts +8 -0
  50. package/dist/core/integrations/supabase.js +9 -0
  51. package/dist/core/objects/aggregate/aggregate.diff.d.ts +2 -8
  52. package/dist/core/objects/aggregate/aggregate.diff.js +16 -70
  53. package/dist/core/objects/aggregate/aggregate.model.d.ts +8 -8
  54. package/dist/core/objects/aggregate/aggregate.model.js +1 -1
  55. package/dist/core/objects/aggregate/changes/aggregate.create.js +1 -1
  56. package/dist/core/objects/aggregate/changes/aggregate.drop.js +1 -1
  57. package/dist/core/objects/base.privilege-diff.d.ts +38 -13
  58. package/dist/core/objects/base.privilege-diff.js +104 -22
  59. package/dist/core/objects/base.privilege.d.ts +1 -0
  60. package/dist/core/objects/base.privilege.js +9 -2
  61. package/dist/core/objects/collation/collation.diff.d.ts +2 -3
  62. package/dist/core/objects/diff-context.d.ts +15 -0
  63. package/dist/core/objects/diff-context.js +1 -0
  64. package/dist/core/objects/domain/changes/domain.create.js +4 -2
  65. package/dist/core/objects/domain/domain.diff.d.ts +2 -8
  66. package/dist/core/objects/domain/domain.diff.js +16 -77
  67. package/dist/core/objects/domain/domain.model.js +1 -1
  68. package/dist/core/objects/event-trigger/event-trigger.diff.d.ts +2 -3
  69. package/dist/core/objects/foreign-data-wrapper/foreign-data-wrapper/foreign-data-wrapper.diff.d.ts +2 -8
  70. package/dist/core/objects/foreign-data-wrapper/foreign-data-wrapper/foreign-data-wrapper.diff.js +13 -77
  71. package/dist/core/objects/foreign-data-wrapper/foreign-data-wrapper/foreign-data-wrapper.model.js +2 -2
  72. package/dist/core/objects/foreign-data-wrapper/foreign-table/foreign-table.diff.d.ts +2 -8
  73. package/dist/core/objects/foreign-data-wrapper/foreign-table/foreign-table.diff.js +16 -77
  74. package/dist/core/objects/foreign-data-wrapper/foreign-table/foreign-table.model.js +1 -1
  75. package/dist/core/objects/foreign-data-wrapper/server/server.diff.d.ts +2 -8
  76. package/dist/core/objects/foreign-data-wrapper/server/server.diff.js +13 -77
  77. package/dist/core/objects/language/language.diff.d.ts +2 -5
  78. package/dist/core/objects/language/language.diff.js +7 -39
  79. package/dist/core/objects/materialized-view/materialized-view.diff.d.ts +2 -8
  80. package/dist/core/objects/materialized-view/materialized-view.diff.js +16 -158
  81. package/dist/core/objects/materialized-view/materialized-view.model.d.ts +3 -3
  82. package/dist/core/objects/materialized-view/materialized-view.model.js +1 -1
  83. package/dist/core/objects/procedure/changes/procedure.alter.js +12 -12
  84. package/dist/core/objects/procedure/procedure.diff.d.ts +2 -8
  85. package/dist/core/objects/procedure/procedure.diff.js +16 -77
  86. package/dist/core/objects/procedure/procedure.model.d.ts +9 -9
  87. package/dist/core/objects/procedure/procedure.model.js +1 -1
  88. package/dist/core/objects/publication/changes/publication.alter.d.ts +0 -9
  89. package/dist/core/objects/publication/changes/publication.alter.js +0 -14
  90. package/dist/core/objects/publication/changes/publication.types.d.ts +2 -2
  91. package/dist/core/objects/publication/publication.diff.d.ts +2 -3
  92. package/dist/core/objects/publication/publication.diff.js +8 -13
  93. package/dist/core/objects/rls-policy/changes/rls-policy.alter.js +3 -3
  94. package/dist/core/objects/rls-policy/rls-policy.model.d.ts +2 -2
  95. package/dist/core/objects/role/role.diff.js +22 -1
  96. package/dist/core/objects/role/role.model.d.ts +4 -3
  97. package/dist/core/objects/role/role.model.js +118 -12
  98. package/dist/core/objects/rule/rule.model.d.ts +1 -1
  99. package/dist/core/objects/schema/schema.diff.d.ts +2 -8
  100. package/dist/core/objects/schema/schema.diff.js +16 -77
  101. package/dist/core/objects/schema/schema.model.js +1 -1
  102. package/dist/core/objects/sequence/sequence.diff.d.ts +2 -8
  103. package/dist/core/objects/sequence/sequence.diff.js +16 -79
  104. package/dist/core/objects/sequence/sequence.model.js +1 -1
  105. package/dist/core/objects/subscription/subscription.diff.d.ts +2 -3
  106. package/dist/core/objects/table/changes/table.create.js +3 -0
  107. package/dist/core/objects/table/table.diff.d.ts +2 -8
  108. package/dist/core/objects/table/table.diff.js +26 -157
  109. package/dist/core/objects/table/table.model.d.ts +23 -22
  110. package/dist/core/objects/table/table.model.js +1 -1
  111. package/dist/core/objects/trigger/changes/trigger.create.js +2 -4
  112. package/dist/core/objects/trigger/trigger.model.d.ts +8 -0
  113. package/dist/core/objects/trigger/trigger.model.js +11 -0
  114. package/dist/core/objects/type/composite-type/composite-type.diff.d.ts +2 -8
  115. package/dist/core/objects/type/composite-type/composite-type.diff.js +16 -77
  116. package/dist/core/objects/type/composite-type/composite-type.model.d.ts +3 -3
  117. package/dist/core/objects/type/composite-type/composite-type.model.js +2 -1
  118. package/dist/core/objects/type/enum/enum.diff.d.ts +2 -8
  119. package/dist/core/objects/type/enum/enum.diff.js +25 -112
  120. package/dist/core/objects/type/enum/enum.model.js +1 -1
  121. package/dist/core/objects/type/range/changes/range.create.js +6 -3
  122. package/dist/core/objects/type/range/range.diff.d.ts +2 -8
  123. package/dist/core/objects/type/range/range.diff.js +16 -77
  124. package/dist/core/objects/type/range/range.model.js +1 -1
  125. package/dist/core/objects/view/view.diff.d.ts +2 -8
  126. package/dist/core/objects/view/view.diff.js +16 -158
  127. package/dist/core/objects/view/view.model.d.ts +18 -4
  128. package/dist/core/objects/view/view.model.js +3 -13
  129. package/dist/core/plan/apply.js +9 -26
  130. package/dist/core/plan/create.d.ts +19 -6
  131. package/dist/core/plan/create.js +134 -174
  132. package/dist/core/plan/serialize.js +16 -4
  133. package/dist/core/plan/sql-format/fixtures.js +3 -5
  134. package/dist/core/plan/sql-format/keyword-case.js +26 -1
  135. package/dist/core/plan/ssl-config.d.ts +32 -0
  136. package/dist/core/plan/ssl-config.js +115 -0
  137. package/dist/core/plan/types.d.ts +6 -0
  138. package/dist/core/postgres-config.d.ts +14 -0
  139. package/dist/core/postgres-config.js +53 -2
  140. package/dist/core/sort/graph-builder.js +10 -0
  141. package/dist/core/sort/logical-sort.js +31 -23
  142. package/dist/core/test-utils/assert-valid-sql.d.ts +10 -0
  143. package/dist/core/test-utils/assert-valid-sql.js +19 -0
  144. package/dist/index.d.ts +6 -0
  145. package/dist/index.js +6 -1
  146. package/package.json +21 -4
  147. package/src/cli/app.ts +27 -3
  148. package/src/cli/bin/cli.ts +6 -0
  149. package/src/cli/commands/catalog-export.ts +78 -0
  150. package/src/cli/commands/declarative-apply.diagnostics.test.ts +77 -0
  151. package/src/cli/commands/declarative-apply.ts +380 -0
  152. package/src/cli/commands/declarative-export.ts +330 -0
  153. package/src/cli/commands/plan.ts +28 -7
  154. package/src/cli/exit-code.test.ts +19 -0
  155. package/src/cli/exit-code.ts +7 -0
  156. package/src/cli/formatters/tree/tree.ts +3 -2
  157. package/src/cli/utils/apply-display.test.ts +348 -0
  158. package/src/cli/utils/apply-display.ts +238 -0
  159. package/src/cli/utils/export-display.test.ts +103 -0
  160. package/src/cli/utils/export-display.ts +275 -0
  161. package/src/cli/utils/integrations.test.ts +44 -0
  162. package/src/cli/utils/resolve-input.test.ts +38 -0
  163. package/src/cli/utils/resolve-input.ts +17 -0
  164. package/src/core/catalog-export/index.ts +20 -0
  165. package/src/core/catalog.diff.ts +79 -78
  166. package/src/core/catalog.model.test.ts +122 -0
  167. package/src/core/catalog.model.ts +127 -1
  168. package/src/core/catalog.snapshot.test.ts +464 -0
  169. package/src/core/catalog.snapshot.ts +289 -0
  170. package/src/core/declarative-apply/discover-sql.test.ts +103 -0
  171. package/src/core/declarative-apply/discover-sql.ts +107 -0
  172. package/src/core/declarative-apply/extract-catalog-providers.ts +220 -0
  173. package/src/core/declarative-apply/index.test.ts +67 -0
  174. package/src/core/declarative-apply/index.ts +205 -0
  175. package/src/core/declarative-apply/round-apply.test.ts +504 -0
  176. package/src/core/declarative-apply/round-apply.ts +562 -0
  177. package/src/core/expand-replace-dependencies.test.ts +70 -0
  178. package/src/core/export/file-mapper.test.ts +816 -0
  179. package/src/core/export/file-mapper.ts +574 -0
  180. package/src/core/export/grouper.ts +108 -0
  181. package/src/core/export/index.ts +129 -0
  182. package/src/core/export/types.ts +104 -0
  183. package/src/core/fixtures/empty-catalogs/postgres-15-16-baseline.json +287 -0
  184. package/src/core/integrations/filter/dsl.test.ts +211 -0
  185. package/src/core/integrations/filter/dsl.ts +65 -3
  186. package/src/core/integrations/filter/extractors.test.ts +244 -0
  187. package/src/core/integrations/filter/extractors.ts +42 -0
  188. package/src/core/integrations/integration-dsl.ts +10 -0
  189. package/src/core/integrations/serialize/dsl.test.ts +91 -0
  190. package/src/core/integrations/supabase.ts +9 -0
  191. package/src/core/objects/aggregate/aggregate.diff.ts +39 -95
  192. package/src/core/objects/aggregate/aggregate.model.ts +1 -1
  193. package/src/core/objects/aggregate/changes/aggregate.alter.test.ts +3 -1
  194. package/src/core/objects/aggregate/changes/aggregate.comment.test.ts +5 -2
  195. package/src/core/objects/aggregate/changes/aggregate.create.test.ts +6 -3
  196. package/src/core/objects/aggregate/changes/aggregate.create.ts +1 -1
  197. package/src/core/objects/aggregate/changes/aggregate.drop.test.ts +7 -3
  198. package/src/core/objects/aggregate/changes/aggregate.drop.ts +1 -1
  199. package/src/core/objects/aggregate/changes/aggregate.privilege.test.ts +9 -3
  200. package/src/core/objects/base.privilege-diff.ts +178 -30
  201. package/src/core/objects/base.privilege.ts +9 -2
  202. package/src/core/objects/collation/changes/collation.alter.test.ts +7 -2
  203. package/src/core/objects/collation/changes/collation.create.test.ts +7 -2
  204. package/src/core/objects/collation/changes/collation.drop.test.ts +4 -1
  205. package/src/core/objects/collation/collation.diff.test.ts +9 -12
  206. package/src/core/objects/collation/collation.diff.ts +2 -1
  207. package/src/core/objects/diff-context.ts +16 -0
  208. package/src/core/objects/domain/changes/domain.alter.test.ts +28 -9
  209. package/src/core/objects/domain/changes/domain.create.test.ts +32 -2
  210. package/src/core/objects/domain/changes/domain.create.ts +7 -1
  211. package/src/core/objects/domain/changes/domain.drop.test.ts +4 -1
  212. package/src/core/objects/domain/domain.diff.ts +39 -102
  213. package/src/core/objects/domain/domain.model.ts +1 -1
  214. package/src/core/objects/event-trigger/changes/event-trigger.alter.test.ts +10 -3
  215. package/src/core/objects/event-trigger/changes/event-trigger.create.test.ts +4 -1
  216. package/src/core/objects/event-trigger/changes/event-trigger.drop.test.ts +4 -1
  217. package/src/core/objects/event-trigger/event-trigger.diff.test.ts +12 -7
  218. package/src/core/objects/event-trigger/event-trigger.diff.ts +2 -1
  219. package/src/core/objects/extension/changes/extension.alter.test.ts +7 -2
  220. package/src/core/objects/extension/changes/extension.create.test.ts +4 -1
  221. package/src/core/objects/extension/changes/extension.drop.test.ts +4 -1
  222. package/src/core/objects/extension/extension.model.test.ts +98 -0
  223. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.alter.test.ts +16 -5
  224. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.create.test.ts +51 -16
  225. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.drop.test.ts +4 -1
  226. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/foreign-data-wrapper.diff.test.ts +111 -4
  227. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/foreign-data-wrapper.diff.ts +31 -101
  228. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/foreign-data-wrapper.model.ts +2 -2
  229. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.alter.test.ts +46 -15
  230. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.create.test.ts +13 -4
  231. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.drop.test.ts +4 -1
  232. package/src/core/objects/foreign-data-wrapper/foreign-table/foreign-table.diff.ts +39 -102
  233. package/src/core/objects/foreign-data-wrapper/foreign-table/foreign-table.model.ts +1 -1
  234. package/src/core/objects/foreign-data-wrapper/server/changes/server.alter.test.ts +22 -7
  235. package/src/core/objects/foreign-data-wrapper/server/changes/server.create.test.ts +19 -6
  236. package/src/core/objects/foreign-data-wrapper/server/changes/server.drop.test.ts +4 -1
  237. package/src/core/objects/foreign-data-wrapper/server/server.diff.test.ts +95 -0
  238. package/src/core/objects/foreign-data-wrapper/server/server.diff.ts +31 -101
  239. package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.alter.test.ts +13 -4
  240. package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.create.test.ts +16 -5
  241. package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.drop.test.ts +10 -3
  242. package/src/core/objects/index/changes/index.alter.test.ts +13 -4
  243. package/src/core/objects/index/changes/index.create.test.ts +4 -1
  244. package/src/core/objects/index/changes/index.drop.test.ts +4 -1
  245. package/src/core/objects/language/changes/language.alter.test.ts +4 -1
  246. package/src/core/objects/language/changes/language.create.test.ts +4 -1
  247. package/src/core/objects/language/changes/language.drop.test.ts +4 -1
  248. package/src/core/objects/language/language.diff.test.ts +86 -4
  249. package/src/core/objects/language/language.diff.ts +17 -49
  250. package/src/core/objects/materialized-view/changes/materialized-view.alter.test.ts +10 -3
  251. package/src/core/objects/materialized-view/changes/materialized-view.create.test.ts +7 -2
  252. package/src/core/objects/materialized-view/changes/materialized-view.drop.test.ts +4 -1
  253. package/src/core/objects/materialized-view/materialized-view.diff.test.ts +162 -0
  254. package/src/core/objects/materialized-view/materialized-view.diff.ts +41 -191
  255. package/src/core/objects/materialized-view/materialized-view.model.ts +1 -1
  256. package/src/core/objects/procedure/changes/procedure.alter.test.ts +121 -49
  257. package/src/core/objects/procedure/changes/procedure.alter.ts +15 -12
  258. package/src/core/objects/procedure/changes/procedure.create.test.ts +4 -1
  259. package/src/core/objects/procedure/changes/procedure.drop.test.ts +7 -2
  260. package/src/core/objects/procedure/procedure.diff.ts +39 -102
  261. package/src/core/objects/procedure/procedure.model.ts +1 -1
  262. package/src/core/objects/publication/changes/publication.alter.test.ts +15 -21
  263. package/src/core/objects/publication/changes/publication.alter.ts +0 -18
  264. package/src/core/objects/publication/changes/publication.comment.test.ts +5 -2
  265. package/src/core/objects/publication/changes/publication.create.test.ts +5 -2
  266. package/src/core/objects/publication/changes/publication.drop.test.ts +3 -1
  267. package/src/core/objects/publication/changes/publication.types.ts +0 -2
  268. package/src/core/objects/publication/publication.diff.test.ts +24 -19
  269. package/src/core/objects/publication/publication.diff.ts +9 -15
  270. package/src/core/objects/rls-policy/changes/rls-policy.alter.test.ts +31 -14
  271. package/src/core/objects/rls-policy/changes/rls-policy.alter.ts +3 -3
  272. package/src/core/objects/rls-policy/changes/rls-policy.create.test.ts +10 -3
  273. package/src/core/objects/rls-policy/changes/rls-policy.drop.test.ts +4 -1
  274. package/src/core/objects/role/changes/role.alter.test.ts +31 -15
  275. package/src/core/objects/role/changes/role.create.test.ts +6 -2
  276. package/src/core/objects/role/changes/role.drop.test.ts +4 -1
  277. package/src/core/objects/role/role.diff.test.ts +235 -0
  278. package/src/core/objects/role/role.diff.ts +21 -1
  279. package/src/core/objects/role/role.model.ts +122 -14
  280. package/src/core/objects/rule/changes/rule.alter.test.ts +7 -3
  281. package/src/core/objects/rule/changes/rule.comment.test.ts +5 -2
  282. package/src/core/objects/rule/changes/rule.create.test.ts +6 -2
  283. package/src/core/objects/rule/changes/rule.drop.test.ts +3 -1
  284. package/src/core/objects/schema/changes/schema.alter.test.ts +4 -1
  285. package/src/core/objects/schema/changes/schema.create.test.ts +4 -1
  286. package/src/core/objects/schema/changes/schema.drop.test.ts +4 -1
  287. package/src/core/objects/schema/schema.diff.ts +39 -102
  288. package/src/core/objects/schema/schema.model.ts +1 -1
  289. package/src/core/objects/sequence/changes/sequence.alter.test.ts +11 -5
  290. package/src/core/objects/sequence/changes/sequence.create.test.ts +8 -3
  291. package/src/core/objects/sequence/changes/sequence.drop.test.ts +4 -1
  292. package/src/core/objects/sequence/sequence.diff.test.ts +114 -0
  293. package/src/core/objects/sequence/sequence.diff.ts +39 -104
  294. package/src/core/objects/sequence/sequence.model.ts +1 -1
  295. package/src/core/objects/subscription/changes/subscription.alter.test.ts +15 -5
  296. package/src/core/objects/subscription/changes/subscription.comment.test.ts +5 -2
  297. package/src/core/objects/subscription/changes/subscription.create.test.ts +5 -2
  298. package/src/core/objects/subscription/changes/subscription.drop.test.ts +3 -1
  299. package/src/core/objects/subscription/subscription.diff.test.ts +16 -11
  300. package/src/core/objects/subscription/subscription.diff.ts +2 -1
  301. package/src/core/objects/table/changes/table.alter.test.ts +38 -15
  302. package/src/core/objects/table/changes/table.create.test.ts +41 -3
  303. package/src/core/objects/table/changes/table.create.ts +4 -0
  304. package/src/core/objects/table/changes/table.drop.test.ts +3 -1
  305. package/src/core/objects/table/table.diff.test.ts +157 -0
  306. package/src/core/objects/table/table.diff.ts +54 -190
  307. package/src/core/objects/table/table.model.ts +1 -1
  308. package/src/core/objects/trigger/changes/trigger.alter.test.ts +8 -4
  309. package/src/core/objects/trigger/changes/trigger.create.test.ts +5 -1
  310. package/src/core/objects/trigger/changes/trigger.create.ts +7 -4
  311. package/src/core/objects/trigger/changes/trigger.drop.test.ts +5 -1
  312. package/src/core/objects/trigger/trigger.diff.test.ts +1 -0
  313. package/src/core/objects/trigger/trigger.model.ts +12 -0
  314. package/src/core/objects/type/composite-type/changes/composite-type.alter.test.ts +10 -4
  315. package/src/core/objects/type/composite-type/changes/composite-type.create.test.ts +7 -2
  316. package/src/core/objects/type/composite-type/changes/composite-type.drop.test.ts +4 -1
  317. package/src/core/objects/type/composite-type/composite-type.diff.test.ts +78 -0
  318. package/src/core/objects/type/composite-type/composite-type.diff.ts +39 -101
  319. package/src/core/objects/type/composite-type/composite-type.model.ts +2 -1
  320. package/src/core/objects/type/enum/changes/enum.alter.test.ts +14 -5
  321. package/src/core/objects/type/enum/changes/enum.create.test.ts +4 -1
  322. package/src/core/objects/type/enum/changes/enum.drop.test.ts +4 -1
  323. package/src/core/objects/type/enum/enum.diff.test.ts +181 -0
  324. package/src/core/objects/type/enum/enum.diff.ts +58 -146
  325. package/src/core/objects/type/enum/enum.model.ts +1 -1
  326. package/src/core/objects/type/range/changes/range.alter.test.ts +3 -1
  327. package/src/core/objects/type/range/changes/range.create.test.ts +5 -2
  328. package/src/core/objects/type/range/changes/range.create.ts +6 -2
  329. package/src/core/objects/type/range/changes/range.drop.test.ts +3 -1
  330. package/src/core/objects/type/range/range.diff.test.ts +77 -0
  331. package/src/core/objects/type/range/range.diff.ts +39 -101
  332. package/src/core/objects/type/range/range.model.ts +1 -1
  333. package/src/core/objects/view/changes/view.alter.test.ts +8 -3
  334. package/src/core/objects/view/changes/view.create.test.ts +7 -2
  335. package/src/core/objects/view/changes/view.drop.test.ts +4 -1
  336. package/src/core/objects/view/view.diff.test.ts +82 -0
  337. package/src/core/objects/view/view.diff.ts +41 -191
  338. package/src/core/objects/view/view.model.ts +3 -17
  339. package/src/core/plan/apply.ts +9 -27
  340. package/src/core/plan/create.ts +173 -237
  341. package/src/core/plan/serialize.test.ts +317 -0
  342. package/src/core/plan/serialize.ts +18 -4
  343. package/src/core/plan/sql-format/fixtures.ts +2 -5
  344. package/src/core/plan/sql-format/format-lowercase-coverage.test.ts +52 -0
  345. package/src/core/plan/sql-format/format-off.test.ts +14 -17
  346. package/src/core/plan/sql-format/format-pretty-lower-leading.test.ts +27 -22
  347. package/src/core/plan/sql-format/format-pretty-narrow.test.ts +17 -21
  348. package/src/core/plan/sql-format/format-pretty-preserve.test.ts +25 -20
  349. package/src/core/plan/sql-format/format-pretty-upper.test.ts +23 -20
  350. package/src/core/plan/sql-format/keyword-case.ts +36 -1
  351. package/src/core/plan/ssl-config.ts +172 -0
  352. package/src/core/plan/types.ts +6 -0
  353. package/src/core/postgres-config.ts +71 -2
  354. package/src/core/sort/graph-builder.ts +12 -0
  355. package/src/core/sort/logical-sort.test.ts +371 -0
  356. package/src/core/sort/logical-sort.ts +32 -25
  357. package/src/core/sort/topological-sort.test.ts +275 -0
  358. package/src/core/test-utils/assert-valid-sql.ts +20 -0
  359. package/src/index.ts +26 -2
@@ -13,10 +13,10 @@ declare const compositeTypePropsSchema: z.ZodObject<{
13
13
  has_subclasses: z.ZodBoolean;
14
14
  is_populated: z.ZodBoolean;
15
15
  replica_identity: z.ZodEnum<{
16
- f: "f";
17
16
  n: "n";
18
17
  i: "i";
19
18
  d: "d";
19
+ f: "f";
20
20
  }>;
21
21
  is_partition: z.ZodBoolean;
22
22
  options: z.ZodNullable<z.ZodArray<z.ZodString>>;
@@ -82,7 +82,7 @@ export declare class CompositeType extends BasePgModel implements TableLikeObjec
82
82
  has_triggers: boolean;
83
83
  has_subclasses: boolean;
84
84
  is_populated: boolean;
85
- replica_identity: "f" | "n" | "i" | "d";
85
+ replica_identity: "n" | "i" | "d" | "f";
86
86
  is_partition: boolean;
87
87
  options: string[] | null;
88
88
  partition_bound: string | null;
@@ -129,7 +129,7 @@ export declare class CompositeType extends BasePgModel implements TableLikeObjec
129
129
  has_triggers: boolean;
130
130
  has_subclasses: boolean;
131
131
  is_populated: boolean;
132
- replica_identity: "f" | "n" | "i" | "d";
132
+ replica_identity: "n" | "i" | "d" | "f";
133
133
  is_partition: boolean;
134
134
  options: string[] | null;
135
135
  partition_bound: string | null;
@@ -136,6 +136,7 @@ export async function extractCompositeTypes(pool) {
136
136
  c.relowner::regrole::text AS owner,
137
137
  obj_description(c.reltype, 'pg_type') AS comment,
138
138
  c.relacl AS relacl, -- used by privileges LATERAL
139
+ c.relowner AS relowner,
139
140
  c.oid AS oid
140
141
  FROM pg_catalog.pg_class c
141
142
  LEFT JOIN extension_oids e ON c.reltype = e.objid
@@ -173,7 +174,7 @@ export async function extractCompositeTypes(pool) {
173
174
  )
174
175
  ORDER BY x.grantee, x.privilege_type
175
176
  ) AS privileges
176
- FROM LATERAL aclexplode(ct.relacl) AS x(grantor, grantee, privilege_type, is_grantable)
177
+ FROM LATERAL aclexplode(COALESCE(ct.relacl, acldefault('T', ct.relowner))) AS x(grantor, grantee, privilege_type, is_grantable)
177
178
  ) priv ON TRUE
178
179
 
179
180
  -- columns as a per-row LATERAL subquery (so no GROUP BY needed)
@@ -1,5 +1,4 @@
1
- import type { DefaultPrivilegeState } from "../../base.default-privileges.ts";
2
- import type { Role } from "../../role/role.model.ts";
1
+ import type { ObjectDiffContext } from "../../diff-context.ts";
3
2
  import type { EnumChange } from "./changes/enum.types.ts";
4
3
  import type { Enum } from "./enum.model.ts";
5
4
  /**
@@ -10,9 +9,4 @@ import type { Enum } from "./enum.model.ts";
10
9
  * @param branch - The enums in the branch catalog.
11
10
  * @returns A list of changes to apply to main to make it match branch.
12
11
  */
13
- export declare function diffEnums(ctx: {
14
- version: number;
15
- currentUser: string;
16
- defaultPrivilegeState: DefaultPrivilegeState;
17
- mainRoles: Record<string, Role>;
18
- }, main: Record<string, Enum>, branch: Record<string, Enum>): EnumChange[];
12
+ export declare function diffEnums(ctx: Pick<ObjectDiffContext, "version" | "currentUser" | "defaultPrivilegeState">, main: Record<string, Enum>, branch: Record<string, Enum>): EnumChange[];
@@ -1,5 +1,5 @@
1
1
  import { diffObjects } from "../../base.diff.js";
2
- import { diffPrivileges, filterPublicBuiltInDefaults, groupPrivilegesByGrantable, } from "../../base.privilege-diff.js";
2
+ import { diffPrivileges, emitObjectPrivilegeChanges, filterPublicBuiltInDefaults, } from "../../base.privilege-diff.js";
3
3
  import { AlterEnumAddValue, AlterEnumChangeOwner, } from "./changes/enum.alter.js";
4
4
  import { CreateCommentOnEnum, DropCommentOnEnum, } from "./changes/enum.comment.js";
5
5
  import { CreateEnum } from "./changes/enum.create.js";
@@ -36,50 +36,21 @@ export function diffEnums(ctx, main, branch) {
36
36
  // We compare default privileges against desired privileges to generate REVOKE/GRANT statements
37
37
  // needed to reach the final desired state.
38
38
  const effectiveDefaults = ctx.defaultPrivilegeState.getEffectiveDefaults(ctx.currentUser, "enum", createdEnum.schema ?? "");
39
+ const creatorFilteredDefaults = createdEnum.owner !== ctx.currentUser
40
+ ? effectiveDefaults.filter((p) => p.grantee !== ctx.currentUser)
41
+ : effectiveDefaults;
39
42
  // Filter out PUBLIC's built-in default USAGE privilege (PostgreSQL grants it automatically)
40
43
  // Reference: https://www.postgresql.org/docs/17/ddl-priv.html Table 5.2
41
44
  // This prevents generating unnecessary "GRANT USAGE TO PUBLIC" statements
42
45
  const desiredPrivileges = filterPublicBuiltInDefaults("enum", createdEnum.privileges);
43
46
  // Filter out owner privileges - owner always has ALL privileges implicitly
44
47
  // and shouldn't be compared. Use the enum owner as the reference.
45
- const privilegeResults = diffPrivileges(effectiveDefaults, desiredPrivileges, createdEnum.owner, ctx.mainRoles);
46
- // Generate grant changes
47
- for (const [grantee, result] of privilegeResults) {
48
- if (result.grants.length > 0) {
49
- const grantGroups = groupPrivilegesByGrantable(result.grants);
50
- for (const [grantable, list] of grantGroups) {
51
- void grantable;
52
- changes.push(new GrantEnumPrivileges({
53
- enum: createdEnum,
54
- grantee,
55
- privileges: list,
56
- version: ctx.version,
57
- }));
58
- }
59
- }
60
- // Generate revoke changes
61
- if (result.revokes.length > 0) {
62
- const revokeGroups = groupPrivilegesByGrantable(result.revokes);
63
- for (const [grantable, list] of revokeGroups) {
64
- void grantable;
65
- changes.push(new RevokeEnumPrivileges({
66
- enum: createdEnum,
67
- grantee,
68
- privileges: list,
69
- version: ctx.version,
70
- }));
71
- }
72
- }
73
- // Generate revoke grant option changes
74
- if (result.revokeGrantOption.length > 0) {
75
- changes.push(new RevokeGrantOptionEnumPrivileges({
76
- enum: createdEnum,
77
- grantee,
78
- privilegeNames: result.revokeGrantOption,
79
- version: ctx.version,
80
- }));
81
- }
82
- }
48
+ const privilegeResults = diffPrivileges(filterPublicBuiltInDefaults("enum", creatorFilteredDefaults), desiredPrivileges, createdEnum.owner);
49
+ changes.push(...emitObjectPrivilegeChanges(privilegeResults, createdEnum, createdEnum, "enum", {
50
+ Grant: GrantEnumPrivileges,
51
+ Revoke: RevokeEnumPrivileges,
52
+ RevokeGrantOption: RevokeGrantOptionEnumPrivileges,
53
+ }, ctx.version));
83
54
  }
84
55
  for (const enumId of dropped) {
85
56
  changes.push(new DropEnum({ enum: main[enumId] }));
@@ -105,42 +76,16 @@ export function diffEnums(ctx, main, branch) {
105
76
  changes.push(new CreateCommentOnEnum({ enum: branchEnum }));
106
77
  }
107
78
  const effectiveDefaults = ctx.defaultPrivilegeState.getEffectiveDefaults(ctx.currentUser, "enum", branchEnum.schema ?? "");
79
+ const creatorFilteredDefaults = branchEnum.owner !== ctx.currentUser
80
+ ? effectiveDefaults.filter((p) => p.grantee !== ctx.currentUser)
81
+ : effectiveDefaults;
108
82
  const desiredPrivileges = filterPublicBuiltInDefaults("enum", branchEnum.privileges);
109
- const privilegeResults = diffPrivileges(effectiveDefaults, desiredPrivileges, branchEnum.owner, ctx.mainRoles);
110
- for (const [grantee, result] of privilegeResults) {
111
- if (result.grants.length > 0) {
112
- const grantGroups = groupPrivilegesByGrantable(result.grants);
113
- for (const [grantable, list] of grantGroups) {
114
- void grantable;
115
- changes.push(new GrantEnumPrivileges({
116
- enum: branchEnum,
117
- grantee,
118
- privileges: list,
119
- version: ctx.version,
120
- }));
121
- }
122
- }
123
- if (result.revokes.length > 0) {
124
- const revokeGroups = groupPrivilegesByGrantable(result.revokes);
125
- for (const [grantable, list] of revokeGroups) {
126
- void grantable;
127
- changes.push(new RevokeEnumPrivileges({
128
- enum: branchEnum,
129
- grantee,
130
- privileges: list,
131
- version: ctx.version,
132
- }));
133
- }
134
- }
135
- if (result.revokeGrantOption.length > 0) {
136
- changes.push(new RevokeGrantOptionEnumPrivileges({
137
- enum: branchEnum,
138
- grantee,
139
- privilegeNames: result.revokeGrantOption,
140
- version: ctx.version,
141
- }));
142
- }
143
- }
83
+ const privilegeResults = diffPrivileges(filterPublicBuiltInDefaults("enum", creatorFilteredDefaults), desiredPrivileges, branchEnum.owner);
84
+ changes.push(...emitObjectPrivilegeChanges(privilegeResults, branchEnum, branchEnum, "enum", {
85
+ Grant: GrantEnumPrivileges,
86
+ Revoke: RevokeEnumPrivileges,
87
+ RevokeGrantOption: RevokeGrantOptionEnumPrivileges,
88
+ }, ctx.version));
144
89
  continue;
145
90
  }
146
91
  // OWNER
@@ -169,44 +114,12 @@ export function diffEnums(ctx, main, branch) {
169
114
  const branchPrivilegesFiltered = filterPublicBuiltInDefaults("enum", branchEnum.privileges);
170
115
  // Filter out owner privileges - owner always has ALL privileges implicitly
171
116
  // and shouldn't be compared. Use branch owner as the reference.
172
- const privilegeResults = diffPrivileges(mainPrivilegesFiltered, branchPrivilegesFiltered, branchEnum.owner, ctx.mainRoles);
173
- for (const [grantee, result] of privilegeResults) {
174
- // Generate grant changes
175
- if (result.grants.length > 0) {
176
- const grantGroups = groupPrivilegesByGrantable(result.grants);
177
- for (const [grantable, list] of grantGroups) {
178
- void grantable;
179
- changes.push(new GrantEnumPrivileges({
180
- enum: branchEnum,
181
- grantee,
182
- privileges: list,
183
- version: ctx.version,
184
- }));
185
- }
186
- }
187
- // Generate revoke changes
188
- if (result.revokes.length > 0) {
189
- const revokeGroups = groupPrivilegesByGrantable(result.revokes);
190
- for (const [grantable, list] of revokeGroups) {
191
- void grantable;
192
- changes.push(new RevokeEnumPrivileges({
193
- enum: mainEnum,
194
- grantee,
195
- privileges: list,
196
- version: ctx.version,
197
- }));
198
- }
199
- }
200
- // Generate revoke grant option changes
201
- if (result.revokeGrantOption.length > 0) {
202
- changes.push(new RevokeGrantOptionEnumPrivileges({
203
- enum: mainEnum,
204
- grantee,
205
- privilegeNames: result.revokeGrantOption,
206
- version: ctx.version,
207
- }));
208
- }
209
- }
117
+ const privilegeResults = diffPrivileges(mainPrivilegesFiltered, branchPrivilegesFiltered, branchEnum.owner);
118
+ changes.push(...emitObjectPrivilegeChanges(privilegeResults, branchEnum, mainEnum, "enum", {
119
+ Grant: GrantEnumPrivileges,
120
+ Revoke: RevokeEnumPrivileges,
121
+ RevokeGrantOption: RevokeGrantOptionEnumPrivileges,
122
+ }, ctx.version));
210
123
  // Note: Enum renaming would also use ALTER TYPE ... RENAME TO ...
211
124
  // But since our Enum model uses 'name' as the identity field,
212
125
  // a name change would be handled as drop + create by diffObjects()
@@ -119,7 +119,7 @@ select
119
119
  )
120
120
  order by x.grantee, x.privilege_type
121
121
  )
122
- from lateral aclexplode(t.typacl) as x(grantor, grantee, privilege_type, is_grantable)
122
+ from lateral aclexplode(COALESCE(t.typacl, acldefault('T', t.typowner))) as x(grantor, grantee, privilege_type, is_grantable)
123
123
  ), '[]'
124
124
  ) as privileges
125
125
  from
@@ -1,4 +1,4 @@
1
- import { isUserDefinedTypeSchema, parseProcedureReference, stableId, } from "../../../utils.js";
1
+ import { isUserDefinedTypeSchema, parseProcedureReference, parseTypeString, stableId, } from "../../../utils.js";
2
2
  import { CreateRangeChange } from "./range.base.js";
3
3
  /**
4
4
  * Create a range type.
@@ -74,8 +74,11 @@ export class CreateRange extends CreateRangeChange {
74
74
  const name = `${this.range.schema}.${this.range.name}`;
75
75
  const prefix = ["CREATE TYPE", name, "AS RANGE"].join(" ");
76
76
  const opts = [];
77
- // Required subtype
78
- const subtypeQualified = this.range.subtype_schema && this.range.subtype_schema !== "pg_catalog"
77
+ // Required subtype (format_type may already return schema-qualified name)
78
+ const alreadyQualified = parseTypeString(this.range.subtype_str);
79
+ const subtypeQualified = !alreadyQualified &&
80
+ this.range.subtype_schema &&
81
+ this.range.subtype_schema !== "pg_catalog"
79
82
  ? `${this.range.subtype_schema}.${this.range.subtype_str}`
80
83
  : this.range.subtype_str;
81
84
  opts.push(`SUBTYPE = ${subtypeQualified}`);
@@ -1,5 +1,4 @@
1
- import type { DefaultPrivilegeState } from "../../base.default-privileges.ts";
2
- import type { Role } from "../../role/role.model.ts";
1
+ import type { ObjectDiffContext } from "../../diff-context.ts";
3
2
  import type { RangeChange } from "./changes/range.types.ts";
4
3
  import type { Range } from "./range.model.ts";
5
4
  /**
@@ -10,9 +9,4 @@ import type { Range } from "./range.model.ts";
10
9
  * @param branch - The ranges in the branch catalog.
11
10
  * @returns A list of changes to apply to main to make it match branch.
12
11
  */
13
- export declare function diffRanges(ctx: {
14
- version: number;
15
- currentUser: string;
16
- defaultPrivilegeState: DefaultPrivilegeState;
17
- mainRoles: Record<string, Role>;
18
- }, main: Record<string, Range>, branch: Record<string, Range>): RangeChange[];
12
+ export declare function diffRanges(ctx: Pick<ObjectDiffContext, "version" | "currentUser" | "defaultPrivilegeState">, main: Record<string, Range>, branch: Record<string, Range>): RangeChange[];
@@ -1,5 +1,5 @@
1
1
  import { diffObjects } from "../../base.diff.js";
2
- import { diffPrivileges, filterPublicBuiltInDefaults, groupPrivilegesByGrantable, } from "../../base.privilege-diff.js";
2
+ import { diffPrivileges, emitObjectPrivilegeChanges, filterPublicBuiltInDefaults, } from "../../base.privilege-diff.js";
3
3
  import { hasNonAlterableChanges } from "../../utils.js";
4
4
  import { AlterRangeChangeOwner } from "./changes/range.alter.js";
5
5
  import { CreateCommentOnRange, DropCommentOnRange, } from "./changes/range.comment.js";
@@ -37,50 +37,21 @@ export function diffRanges(ctx, main, branch) {
37
37
  // We compare default privileges against desired privileges to generate REVOKE/GRANT statements
38
38
  // needed to reach the final desired state.
39
39
  const effectiveDefaults = ctx.defaultPrivilegeState.getEffectiveDefaults(ctx.currentUser, "range", createdRange.schema ?? "");
40
+ const creatorFilteredDefaults = createdRange.owner !== ctx.currentUser
41
+ ? effectiveDefaults.filter((p) => p.grantee !== ctx.currentUser)
42
+ : effectiveDefaults;
40
43
  // Filter out PUBLIC's built-in default USAGE privilege (PostgreSQL grants it automatically)
41
44
  // Reference: https://www.postgresql.org/docs/17/ddl-priv.html Table 5.2
42
45
  // This prevents generating unnecessary "GRANT USAGE TO PUBLIC" statements
43
46
  const desiredPrivileges = filterPublicBuiltInDefaults("range", createdRange.privileges);
44
47
  // Filter out owner privileges - owner always has ALL privileges implicitly
45
48
  // and shouldn't be compared. Use the range owner as the reference.
46
- const privilegeResults = diffPrivileges(effectiveDefaults, desiredPrivileges, createdRange.owner);
47
- // Generate grant changes
48
- for (const [grantee, result] of privilegeResults) {
49
- if (result.grants.length > 0) {
50
- const grantGroups = groupPrivilegesByGrantable(result.grants);
51
- for (const [grantable, list] of grantGroups) {
52
- void grantable;
53
- changes.push(new GrantRangePrivileges({
54
- range: createdRange,
55
- grantee,
56
- privileges: list,
57
- version: ctx.version,
58
- }));
59
- }
60
- }
61
- // Generate revoke changes
62
- if (result.revokes.length > 0) {
63
- const revokeGroups = groupPrivilegesByGrantable(result.revokes);
64
- for (const [grantable, list] of revokeGroups) {
65
- void grantable;
66
- changes.push(new RevokeRangePrivileges({
67
- range: createdRange,
68
- grantee,
69
- privileges: list,
70
- version: ctx.version,
71
- }));
72
- }
73
- }
74
- // Generate revoke grant option changes
75
- if (result.revokeGrantOption.length > 0) {
76
- changes.push(new RevokeGrantOptionRangePrivileges({
77
- range: createdRange,
78
- grantee,
79
- privilegeNames: result.revokeGrantOption,
80
- version: ctx.version,
81
- }));
82
- }
83
- }
49
+ const privilegeResults = diffPrivileges(filterPublicBuiltInDefaults("range", creatorFilteredDefaults), desiredPrivileges, createdRange.owner);
50
+ changes.push(...emitObjectPrivilegeChanges(privilegeResults, createdRange, createdRange, "range", {
51
+ Grant: GrantRangePrivileges,
52
+ Revoke: RevokeRangePrivileges,
53
+ RevokeGrantOption: RevokeGrantOptionRangePrivileges,
54
+ }, ctx.version));
84
55
  }
85
56
  for (const id of dropped) {
86
57
  changes.push(new DropRange({ range: main[id] }));
@@ -128,44 +99,12 @@ export function diffRanges(ctx, main, branch) {
128
99
  const branchPrivilegesFiltered = filterPublicBuiltInDefaults("range", branchRange.privileges);
129
100
  // Filter out owner privileges - owner always has ALL privileges implicitly
130
101
  // and shouldn't be compared. Use branch owner as the reference.
131
- const privilegeResults = diffPrivileges(mainPrivilegesFiltered, branchPrivilegesFiltered, branchRange.owner, ctx.mainRoles);
132
- for (const [grantee, result] of privilegeResults) {
133
- // Generate grant changes
134
- if (result.grants.length > 0) {
135
- const grantGroups = groupPrivilegesByGrantable(result.grants);
136
- for (const [grantable, list] of grantGroups) {
137
- void grantable;
138
- changes.push(new GrantRangePrivileges({
139
- range: branchRange,
140
- grantee,
141
- privileges: list,
142
- version: ctx.version,
143
- }));
144
- }
145
- }
146
- // Generate revoke changes
147
- if (result.revokes.length > 0) {
148
- const revokeGroups = groupPrivilegesByGrantable(result.revokes);
149
- for (const [grantable, list] of revokeGroups) {
150
- void grantable;
151
- changes.push(new RevokeRangePrivileges({
152
- range: mainRange,
153
- grantee,
154
- privileges: list,
155
- version: ctx.version,
156
- }));
157
- }
158
- }
159
- // Generate revoke grant option changes
160
- if (result.revokeGrantOption.length > 0) {
161
- changes.push(new RevokeGrantOptionRangePrivileges({
162
- range: mainRange,
163
- grantee,
164
- privilegeNames: result.revokeGrantOption,
165
- version: ctx.version,
166
- }));
167
- }
168
- }
102
+ const privilegeResults = diffPrivileges(mainPrivilegesFiltered, branchPrivilegesFiltered, branchRange.owner);
103
+ changes.push(...emitObjectPrivilegeChanges(privilegeResults, branchRange, mainRange, "range", {
104
+ Grant: GrantRangePrivileges,
105
+ Revoke: RevokeRangePrivileges,
106
+ RevokeGrantOption: RevokeGrantOptionRangePrivileges,
107
+ }, ctx.version));
169
108
  }
170
109
  }
171
110
  return changes;
@@ -140,7 +140,7 @@ select
140
140
  )
141
141
  order by x.grantee, x.privilege_type
142
142
  )
143
- from lateral aclexplode(t.typacl) as x(grantor, grantee, privilege_type, is_grantable)
143
+ from lateral aclexplode(COALESCE(t.typacl, acldefault('T', t.typowner))) as x(grantor, grantee, privilege_type, is_grantable)
144
144
  ), '[]'
145
145
  ) as privileges
146
146
  from pg_catalog.pg_range r
@@ -1,5 +1,4 @@
1
- import type { DefaultPrivilegeState } from "../base.default-privileges.ts";
2
- import type { Role } from "../role/role.model.ts";
1
+ import type { ObjectDiffContext } from "../diff-context.ts";
3
2
  import type { ViewChange } from "./changes/view.types.ts";
4
3
  import type { View } from "./view.model.ts";
5
4
  /**
@@ -10,9 +9,4 @@ import type { View } from "./view.model.ts";
10
9
  * @param branch - The views in the branch catalog.
11
10
  * @returns A list of changes to apply to main to make it match branch.
12
11
  */
13
- export declare function diffViews(ctx: {
14
- version: number;
15
- currentUser: string;
16
- defaultPrivilegeState: DefaultPrivilegeState;
17
- mainRoles: Record<string, Role>;
18
- }, main: Record<string, View>, branch: Record<string, View>): ViewChange[];
12
+ export declare function diffViews(ctx: Pick<ObjectDiffContext, "version" | "currentUser" | "defaultPrivilegeState">, main: Record<string, View>, branch: Record<string, View>): ViewChange[];
@@ -1,5 +1,5 @@
1
1
  import { diffObjects } from "../base.diff.js";
2
- import { diffPrivileges, groupPrivilegesByColumns, } from "../base.privilege-diff.js";
2
+ import { diffPrivileges, emitColumnPrivilegeChanges, } from "../base.privilege-diff.js";
3
3
  import { deepEqual, hasNonAlterableChanges } from "../utils.js";
4
4
  import { AlterViewChangeOwner, AlterViewResetOptions, AlterViewSetOptions, } from "./changes/view.alter.js";
5
5
  import { CreateCommentOnView, DropCommentOnView, } from "./changes/view.comment.js";
@@ -34,87 +34,18 @@ export function diffViews(ctx, main, branch) {
34
34
  // We compare default privileges against desired privileges to generate REVOKE/GRANT statements
35
35
  // needed to reach the final desired state.
36
36
  const effectiveDefaults = ctx.defaultPrivilegeState.getEffectiveDefaults(ctx.currentUser, "view", v.schema ?? "");
37
+ const creatorFilteredDefaults = v.owner !== ctx.currentUser
38
+ ? effectiveDefaults.filter((p) => p.grantee !== ctx.currentUser)
39
+ : effectiveDefaults;
37
40
  const desiredPrivileges = v.privileges;
38
41
  // Filter out owner privileges - owner always has ALL privileges implicitly
39
42
  // and shouldn't be compared. Use the view owner as the reference.
40
- const privilegeResults = diffPrivileges(effectiveDefaults, desiredPrivileges, v.owner, ctx.mainRoles);
41
- // Generate grant changes
42
- for (const [grantee, result] of privilegeResults) {
43
- if (result.grants.length > 0) {
44
- const grantGroups = groupPrivilegesByColumns(result.grants);
45
- for (const [, group] of grantGroups) {
46
- for (const [grantable, privSet] of group.byGrant) {
47
- const privileges = Array.from(privSet).map((priv) => ({
48
- privilege: priv,
49
- grantable,
50
- }));
51
- changes.push(new GrantViewPrivileges({
52
- view: v,
53
- grantee,
54
- privileges,
55
- columns: group.columns,
56
- version: ctx.version,
57
- }));
58
- }
59
- }
60
- }
61
- // Generate revoke changes
62
- if (result.revokes.length > 0) {
63
- const revokeGroups = groupPrivilegesByColumns(result.revokes);
64
- for (const [, group] of revokeGroups) {
65
- const allPrivileges = new Set();
66
- for (const [, privSet] of group.byGrant) {
67
- for (const priv of privSet) {
68
- allPrivileges.add(priv);
69
- }
70
- }
71
- const privileges = Array.from(allPrivileges).map((priv) => ({
72
- privilege: priv,
73
- grantable: false,
74
- }));
75
- changes.push(new RevokeViewPrivileges({
76
- view: v,
77
- grantee,
78
- privileges,
79
- columns: group.columns,
80
- version: ctx.version,
81
- }));
82
- }
83
- }
84
- // Generate revoke grant option changes
85
- if (result.revokeGrantOption.length > 0) {
86
- const revokeGrantGroups = new Map();
87
- for (const r of result.revokeGrantOption) {
88
- // For revoke grant option, we need to find the columns from the effective defaults
89
- const originalPriv = effectiveDefaults.find((p) => p.grantee === grantee && p.privilege === r);
90
- const key = originalPriv?.columns
91
- ? originalPriv.columns.sort().join(",")
92
- : "";
93
- if (!revokeGrantGroups.has(key)) {
94
- revokeGrantGroups.set(key, {
95
- columns: originalPriv?.columns
96
- ? [...originalPriv.columns]
97
- : undefined,
98
- privileges: new Set(),
99
- });
100
- }
101
- const group = revokeGrantGroups.get(key);
102
- if (!group)
103
- continue;
104
- group.privileges.add(r);
105
- }
106
- for (const [, group] of revokeGrantGroups) {
107
- const privilegeNames = Array.from(group.privileges);
108
- changes.push(new RevokeGrantOptionViewPrivileges({
109
- view: v,
110
- grantee,
111
- privilegeNames,
112
- columns: group.columns,
113
- version: ctx.version,
114
- }));
115
- }
116
- }
117
- }
43
+ const privilegeResults = diffPrivileges(creatorFilteredDefaults, desiredPrivileges, v.owner);
44
+ changes.push(...emitColumnPrivilegeChanges(privilegeResults, v, v, "view", {
45
+ Grant: GrantViewPrivileges,
46
+ Revoke: RevokeViewPrivileges,
47
+ RevokeGrantOption: RevokeGrantOptionViewPrivileges,
48
+ }, effectiveDefaults, ctx.version));
118
49
  }
119
50
  for (const viewId of dropped) {
120
51
  changes.push(new DropView({ view: main[viewId] }));
@@ -185,85 +116,12 @@ export function diffViews(ctx, main, branch) {
185
116
  // PRIVILEGES (unified object and column privileges)
186
117
  // Filter out owner privileges - owner always has ALL privileges implicitly
187
118
  // and shouldn't be compared. Use branch owner as the reference.
188
- const privilegeResults = diffPrivileges(mainView.privileges, branchView.privileges, branchView.owner, ctx.mainRoles);
189
- for (const [grantee, result] of privilegeResults) {
190
- // Generate grant changes
191
- if (result.grants.length > 0) {
192
- const grantGroups = groupPrivilegesByColumns(result.grants);
193
- for (const [, group] of grantGroups) {
194
- for (const [grantable, privSet] of group.byGrant) {
195
- const privileges = Array.from(privSet).map((priv) => ({
196
- privilege: priv,
197
- grantable,
198
- }));
199
- changes.push(new GrantViewPrivileges({
200
- view: branchView,
201
- grantee,
202
- privileges,
203
- columns: group.columns,
204
- version: ctx.version,
205
- }));
206
- }
207
- }
208
- }
209
- // Generate revoke changes
210
- if (result.revokes.length > 0) {
211
- const revokeGroups = groupPrivilegesByColumns(result.revokes);
212
- for (const [, group] of revokeGroups) {
213
- // Collapse all grantable groups into a single revoke (grantable: false)
214
- const allPrivileges = new Set();
215
- for (const [, privSet] of group.byGrant) {
216
- for (const priv of privSet) {
217
- allPrivileges.add(priv);
218
- }
219
- }
220
- const privileges = Array.from(allPrivileges).map((priv) => ({
221
- privilege: priv,
222
- grantable: false,
223
- }));
224
- changes.push(new RevokeViewPrivileges({
225
- view: mainView,
226
- grantee,
227
- privileges,
228
- columns: group.columns,
229
- version: ctx.version,
230
- }));
231
- }
232
- }
233
- // Generate revoke grant option changes
234
- if (result.revokeGrantOption.length > 0) {
235
- const revokeGrantGroups = new Map();
236
- for (const r of result.revokeGrantOption) {
237
- // For revoke grant option, we need to find the columns from the original privilege
238
- const originalPriv = mainView.privileges.find((p) => p.grantee === grantee && p.privilege === r);
239
- const key = originalPriv?.columns
240
- ? originalPriv.columns.sort().join(",")
241
- : "";
242
- if (!revokeGrantGroups.has(key)) {
243
- revokeGrantGroups.set(key, {
244
- columns: originalPriv?.columns
245
- ? [...originalPriv.columns]
246
- : undefined,
247
- privileges: new Set(),
248
- });
249
- }
250
- const group = revokeGrantGroups.get(key);
251
- if (!group)
252
- continue;
253
- group.privileges.add(r);
254
- }
255
- for (const [, group] of revokeGrantGroups) {
256
- const privilegeNames = Array.from(group.privileges);
257
- changes.push(new RevokeGrantOptionViewPrivileges({
258
- view: mainView,
259
- grantee,
260
- privilegeNames,
261
- columns: group.columns,
262
- version: ctx.version,
263
- }));
264
- }
265
- }
266
- }
119
+ const privilegeResults = diffPrivileges(mainView.privileges, branchView.privileges, branchView.owner);
120
+ changes.push(...emitColumnPrivilegeChanges(privilegeResults, branchView, mainView, "view", {
121
+ Grant: GrantViewPrivileges,
122
+ Revoke: RevokeViewPrivileges,
123
+ RevokeGrantOption: RevokeGrantOptionViewPrivileges,
124
+ }, mainView.privileges, ctx.version));
267
125
  }
268
126
  }
269
127
  return changes;