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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (463) hide show
  1. package/README.md +22 -0
  2. package/dist/cli/bin/cli.js +0 -0
  3. package/dist/cli/commands/plan.js +21 -0
  4. package/dist/cli/utils.d.ts +2 -0
  5. package/dist/cli/utils.js +1 -1
  6. package/dist/core/objects/table/table.model.d.ts +4 -2
  7. package/dist/core/objects/table/table.model.js +3 -0
  8. package/dist/core/objects/trigger/changes/trigger.alter.js +23 -0
  9. package/dist/core/objects/trigger/changes/trigger.create.js +2 -1
  10. package/dist/core/objects/trigger/trigger.model.d.ts +1 -0
  11. package/dist/core/objects/trigger/trigger.model.js +3 -0
  12. package/dist/core/plan/apply.js +3 -3
  13. package/dist/core/plan/create.js +34 -15
  14. package/dist/core/plan/sql-format/constants.d.ts +2 -0
  15. package/dist/core/plan/sql-format/constants.js +11 -0
  16. package/dist/core/plan/sql-format/fixtures.d.ts +2 -0
  17. package/dist/core/plan/sql-format/fixtures.js +2449 -0
  18. package/dist/core/plan/sql-format/format-utils.d.ts +37 -0
  19. package/dist/core/plan/sql-format/format-utils.js +274 -0
  20. package/dist/core/plan/sql-format/formatters.d.ts +20 -0
  21. package/dist/core/plan/sql-format/formatters.js +737 -0
  22. package/dist/core/plan/sql-format/index.d.ts +2 -0
  23. package/dist/core/plan/sql-format/index.js +98 -0
  24. package/dist/core/plan/sql-format/keyword-case.d.ts +2 -0
  25. package/dist/core/plan/sql-format/keyword-case.js +868 -0
  26. package/dist/core/plan/sql-format/protect.d.ts +3 -0
  27. package/dist/core/plan/sql-format/protect.js +269 -0
  28. package/dist/core/plan/sql-format/sql-scanner.d.ts +59 -0
  29. package/dist/core/plan/sql-format/sql-scanner.js +202 -0
  30. package/dist/core/plan/sql-format/tokenizer.d.ts +22 -0
  31. package/dist/core/plan/sql-format/tokenizer.js +118 -0
  32. package/dist/core/plan/sql-format/types.d.ts +28 -0
  33. package/dist/core/plan/sql-format/types.js +1 -0
  34. package/dist/core/plan/sql-format/wrap.d.ts +2 -0
  35. package/dist/core/plan/sql-format/wrap.js +165 -0
  36. package/dist/core/plan/sql-format.d.ts +2 -0
  37. package/dist/core/plan/sql-format.js +1 -0
  38. package/dist/core/plan/statements.d.ts +2 -1
  39. package/dist/core/plan/statements.js +6 -2
  40. package/dist/core/postgres-config.d.ts +15 -0
  41. package/dist/core/postgres-config.js +30 -0
  42. package/dist/index.d.ts +2 -0
  43. package/dist/index.js +1 -0
  44. package/package.json +37 -22
  45. package/src/cli/app.ts +28 -0
  46. package/src/cli/bin/cli.ts +9 -0
  47. package/src/cli/commands/apply.ts +101 -0
  48. package/src/cli/commands/plan.ts +195 -0
  49. package/src/cli/commands/sync.ts +185 -0
  50. package/src/cli/formatters/index.ts +5 -0
  51. package/src/cli/formatters/tree/tree-builder.ts +380 -0
  52. package/src/cli/formatters/tree/tree-renderer.ts +372 -0
  53. package/src/cli/formatters/tree/tree.ts +237 -0
  54. package/src/cli/utils/integrations.ts +42 -0
  55. package/src/cli/utils.ts +231 -0
  56. package/src/core/catalog.diff.ts +246 -0
  57. package/src/core/catalog.model.ts +384 -0
  58. package/src/core/change.types.ts +44 -0
  59. package/src/core/context.ts +26 -0
  60. package/src/core/depend.ts +1870 -0
  61. package/src/core/expand-replace-dependencies.ts +380 -0
  62. package/src/core/fingerprint.ts +204 -0
  63. package/src/core/integrations/filter/dsl.ts +204 -0
  64. package/src/core/integrations/filter/extractors.ts +145 -0
  65. package/src/core/integrations/filter/filter.types.ts +3 -0
  66. package/src/core/integrations/integration-dsl.ts +24 -0
  67. package/src/core/integrations/integration.types.ts +7 -0
  68. package/src/core/integrations/serialize/dsl.ts +77 -0
  69. package/src/core/integrations/serialize/serialize.types.ts +3 -0
  70. package/src/core/integrations/supabase.ts +121 -0
  71. package/src/core/objects/aggregate/aggregate.diff.test.ts +215 -0
  72. package/src/core/objects/aggregate/aggregate.diff.ts +278 -0
  73. package/src/core/objects/aggregate/aggregate.model.ts +317 -0
  74. package/src/core/objects/aggregate/changes/aggregate.alter.test.ts +64 -0
  75. package/src/core/objects/aggregate/changes/aggregate.alter.ts +32 -0
  76. package/src/core/objects/aggregate/changes/aggregate.base.ts +20 -0
  77. package/src/core/objects/aggregate/changes/aggregate.comment.test.ts +86 -0
  78. package/src/core/objects/aggregate/changes/aggregate.comment.ts +62 -0
  79. package/src/core/objects/aggregate/changes/aggregate.create.test.ts +101 -0
  80. package/src/core/objects/aggregate/changes/aggregate.create.ts +329 -0
  81. package/src/core/objects/aggregate/changes/aggregate.drop.test.ts +78 -0
  82. package/src/core/objects/aggregate/changes/aggregate.drop.ts +32 -0
  83. package/src/core/objects/aggregate/changes/aggregate.privilege.test.ts +130 -0
  84. package/src/core/objects/aggregate/changes/aggregate.privilege.ts +146 -0
  85. package/src/core/objects/aggregate/changes/aggregate.types.ts +12 -0
  86. package/src/core/objects/base.change.ts +62 -0
  87. package/src/core/objects/base.default-privileges.ts +204 -0
  88. package/src/core/objects/base.diff.ts +20 -0
  89. package/src/core/objects/base.model.ts +82 -0
  90. package/src/core/objects/base.privilege-diff.ts +299 -0
  91. package/src/core/objects/base.privilege.ts +184 -0
  92. package/src/core/objects/collation/changes/collation.alter.test.ts +63 -0
  93. package/src/core/objects/collation/changes/collation.alter.ts +79 -0
  94. package/src/core/objects/collation/changes/collation.base.ts +20 -0
  95. package/src/core/objects/collation/changes/collation.comment.ts +68 -0
  96. package/src/core/objects/collation/changes/collation.create.test.ts +51 -0
  97. package/src/core/objects/collation/changes/collation.create.ts +106 -0
  98. package/src/core/objects/collation/changes/collation.drop.test.ts +28 -0
  99. package/src/core/objects/collation/changes/collation.drop.ts +37 -0
  100. package/src/core/objects/collation/changes/collation.types.ts +10 -0
  101. package/src/core/objects/collation/collation.diff.test.ts +100 -0
  102. package/src/core/objects/collation/collation.diff.ts +126 -0
  103. package/src/core/objects/collation/collation.model.ts +224 -0
  104. package/src/core/objects/domain/changes/domain.alter.test.ts +316 -0
  105. package/src/core/objects/domain/changes/domain.alter.ts +286 -0
  106. package/src/core/objects/domain/changes/domain.base.ts +20 -0
  107. package/src/core/objects/domain/changes/domain.comment.ts +59 -0
  108. package/src/core/objects/domain/changes/domain.create.test.ts +65 -0
  109. package/src/core/objects/domain/changes/domain.create.ts +118 -0
  110. package/src/core/objects/domain/changes/domain.drop.test.ts +30 -0
  111. package/src/core/objects/domain/changes/domain.drop.ts +34 -0
  112. package/src/core/objects/domain/changes/domain.privilege.ts +171 -0
  113. package/src/core/objects/domain/changes/domain.types.ts +12 -0
  114. package/src/core/objects/domain/domain.diff.test.ts +284 -0
  115. package/src/core/objects/domain/domain.diff.ts +358 -0
  116. package/src/core/objects/domain/domain.model.ts +190 -0
  117. package/src/core/objects/event-trigger/changes/event-trigger.alter.test.ts +50 -0
  118. package/src/core/objects/event-trigger/changes/event-trigger.alter.ts +82 -0
  119. package/src/core/objects/event-trigger/changes/event-trigger.base.ts +20 -0
  120. package/src/core/objects/event-trigger/changes/event-trigger.comment.ts +66 -0
  121. package/src/core/objects/event-trigger/changes/event-trigger.create.test.ts +24 -0
  122. package/src/core/objects/event-trigger/changes/event-trigger.create.ts +72 -0
  123. package/src/core/objects/event-trigger/changes/event-trigger.drop.test.ts +22 -0
  124. package/src/core/objects/event-trigger/changes/event-trigger.drop.ts +34 -0
  125. package/src/core/objects/event-trigger/changes/event-trigger.types.ts +10 -0
  126. package/src/core/objects/event-trigger/event-trigger.diff.test.ts +126 -0
  127. package/src/core/objects/event-trigger/event-trigger.diff.ts +126 -0
  128. package/src/core/objects/event-trigger/event-trigger.model.ts +106 -0
  129. package/src/core/objects/extension/changes/extension.alter.test.ts +58 -0
  130. package/src/core/objects/extension/changes/extension.alter.ts +78 -0
  131. package/src/core/objects/extension/changes/extension.base.ts +20 -0
  132. package/src/core/objects/extension/changes/extension.comment.ts +64 -0
  133. package/src/core/objects/extension/changes/extension.create.test.ts +25 -0
  134. package/src/core/objects/extension/changes/extension.create.ts +63 -0
  135. package/src/core/objects/extension/changes/extension.drop.test.ts +23 -0
  136. package/src/core/objects/extension/changes/extension.drop.ts +34 -0
  137. package/src/core/objects/extension/changes/extension.types.ts +10 -0
  138. package/src/core/objects/extension/extension.diff.test.ts +42 -0
  139. package/src/core/objects/extension/extension.diff.ts +90 -0
  140. package/src/core/objects/extension/extension.model.ts +280 -0
  141. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.alter.test.ts +125 -0
  142. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.alter.ts +101 -0
  143. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.base.ts +20 -0
  144. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.comment.ts +72 -0
  145. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.create.test.ts +125 -0
  146. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.create.ts +95 -0
  147. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.drop.test.ts +23 -0
  148. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.drop.ts +36 -0
  149. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.privilege.ts +172 -0
  150. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.types.ts +12 -0
  151. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/foreign-data-wrapper.diff.test.ts +179 -0
  152. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/foreign-data-wrapper.diff.ts +341 -0
  153. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/foreign-data-wrapper.model.ts +149 -0
  154. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper.types.ts +10 -0
  155. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.alter.test.ts +309 -0
  156. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.alter.ts +341 -0
  157. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.base.ts +20 -0
  158. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.comment.ts +72 -0
  159. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.create.test.ts +201 -0
  160. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.create.ts +81 -0
  161. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.drop.test.ts +43 -0
  162. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.drop.ts +37 -0
  163. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.privilege.ts +181 -0
  164. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.types.ts +12 -0
  165. package/src/core/objects/foreign-data-wrapper/foreign-table/foreign-table.diff.test.ts +813 -0
  166. package/src/core/objects/foreign-data-wrapper/foreign-table/foreign-table.diff.ts +406 -0
  167. package/src/core/objects/foreign-data-wrapper/foreign-table/foreign-table.model.ts +242 -0
  168. package/src/core/objects/foreign-data-wrapper/server/changes/server.alter.test.ts +168 -0
  169. package/src/core/objects/foreign-data-wrapper/server/changes/server.alter.ts +126 -0
  170. package/src/core/objects/foreign-data-wrapper/server/changes/server.base.ts +20 -0
  171. package/src/core/objects/foreign-data-wrapper/server/changes/server.comment.ts +60 -0
  172. package/src/core/objects/foreign-data-wrapper/server/changes/server.create.test.ts +131 -0
  173. package/src/core/objects/foreign-data-wrapper/server/changes/server.create.ts +81 -0
  174. package/src/core/objects/foreign-data-wrapper/server/changes/server.drop.test.ts +24 -0
  175. package/src/core/objects/foreign-data-wrapper/server/changes/server.drop.ts +34 -0
  176. package/src/core/objects/foreign-data-wrapper/server/changes/server.privilege.ts +164 -0
  177. package/src/core/objects/foreign-data-wrapper/server/changes/server.types.ts +12 -0
  178. package/src/core/objects/foreign-data-wrapper/server/server.diff.test.ts +167 -0
  179. package/src/core/objects/foreign-data-wrapper/server/server.diff.ts +317 -0
  180. package/src/core/objects/foreign-data-wrapper/server/server.model.ts +133 -0
  181. package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.alter.test.ts +82 -0
  182. package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.alter.ts +69 -0
  183. package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.base.ts +20 -0
  184. package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.create.test.ts +85 -0
  185. package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.create.ts +66 -0
  186. package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.drop.test.ts +53 -0
  187. package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.drop.ts +40 -0
  188. package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.types.ts +8 -0
  189. package/src/core/objects/foreign-data-wrapper/user-mapping/user-mapping.diff.test.ts +77 -0
  190. package/src/core/objects/foreign-data-wrapper/user-mapping/user-mapping.diff.ts +107 -0
  191. package/src/core/objects/foreign-data-wrapper/user-mapping/user-mapping.model.ts +96 -0
  192. package/src/core/objects/index/changes/index.alter.test.ts +200 -0
  193. package/src/core/objects/index/changes/index.alter.ts +144 -0
  194. package/src/core/objects/index/changes/index.base.ts +20 -0
  195. package/src/core/objects/index/changes/index.comment.ts +63 -0
  196. package/src/core/objects/index/changes/index.create.test.ts +66 -0
  197. package/src/core/objects/index/changes/index.create.ts +68 -0
  198. package/src/core/objects/index/changes/index.drop.test.ts +44 -0
  199. package/src/core/objects/index/changes/index.drop.ts +34 -0
  200. package/src/core/objects/index/changes/index.types.ts +6 -0
  201. package/src/core/objects/index/changes/utils.ts +16 -0
  202. package/src/core/objects/index/index.diff.test.ts +153 -0
  203. package/src/core/objects/index/index.diff.ts +243 -0
  204. package/src/core/objects/index/index.model.ts +370 -0
  205. package/src/core/objects/language/changes/language.alter.test.ts +33 -0
  206. package/src/core/objects/language/changes/language.alter.ts +53 -0
  207. package/src/core/objects/language/changes/language.base.ts +20 -0
  208. package/src/core/objects/language/changes/language.comment.ts +58 -0
  209. package/src/core/objects/language/changes/language.create.test.ts +27 -0
  210. package/src/core/objects/language/changes/language.create.ts +104 -0
  211. package/src/core/objects/language/changes/language.drop.test.ts +25 -0
  212. package/src/core/objects/language/changes/language.drop.ts +39 -0
  213. package/src/core/objects/language/changes/language.privilege.ts +172 -0
  214. package/src/core/objects/language/changes/language.types.ts +12 -0
  215. package/src/core/objects/language/language.diff.test.ts +53 -0
  216. package/src/core/objects/language/language.diff.ts +176 -0
  217. package/src/core/objects/language/language.model.ts +150 -0
  218. package/src/core/objects/materialized-view/changes/materialized-view.alter.test.ts +123 -0
  219. package/src/core/objects/materialized-view/changes/materialized-view.alter.ts +113 -0
  220. package/src/core/objects/materialized-view/changes/materialized-view.base.ts +20 -0
  221. package/src/core/objects/materialized-view/changes/materialized-view.comment.ts +176 -0
  222. package/src/core/objects/materialized-view/changes/materialized-view.create.test.ts +64 -0
  223. package/src/core/objects/materialized-view/changes/materialized-view.create.ts +93 -0
  224. package/src/core/objects/materialized-view/changes/materialized-view.drop.test.ts +34 -0
  225. package/src/core/objects/materialized-view/changes/materialized-view.drop.ts +60 -0
  226. package/src/core/objects/materialized-view/changes/materialized-view.privilege.ts +212 -0
  227. package/src/core/objects/materialized-view/changes/materialized-view.types.ts +12 -0
  228. package/src/core/objects/materialized-view/materialized-view.diff.test.ts +102 -0
  229. package/src/core/objects/materialized-view/materialized-view.diff.ts +451 -0
  230. package/src/core/objects/materialized-view/materialized-view.model.ts +258 -0
  231. package/src/core/objects/procedure/changes/procedure.alter.test.ts +1005 -0
  232. package/src/core/objects/procedure/changes/procedure.alter.ts +287 -0
  233. package/src/core/objects/procedure/changes/procedure.base.ts +20 -0
  234. package/src/core/objects/procedure/changes/procedure.comment.ts +70 -0
  235. package/src/core/objects/procedure/changes/procedure.create.test.ts +48 -0
  236. package/src/core/objects/procedure/changes/procedure.create.ts +92 -0
  237. package/src/core/objects/procedure/changes/procedure.drop.test.ts +85 -0
  238. package/src/core/objects/procedure/changes/procedure.drop.ts +49 -0
  239. package/src/core/objects/procedure/changes/procedure.privilege.ts +188 -0
  240. package/src/core/objects/procedure/changes/procedure.types.ts +12 -0
  241. package/src/core/objects/procedure/procedure.diff.test.ts +161 -0
  242. package/src/core/objects/procedure/procedure.diff.ts +404 -0
  243. package/src/core/objects/procedure/procedure.model.ts +264 -0
  244. package/src/core/objects/procedure/utils.ts +58 -0
  245. package/src/core/objects/publication/changes/publication.alter.test.ts +223 -0
  246. package/src/core/objects/publication/changes/publication.alter.ts +243 -0
  247. package/src/core/objects/publication/changes/publication.base.ts +20 -0
  248. package/src/core/objects/publication/changes/publication.comment.test.ts +70 -0
  249. package/src/core/objects/publication/changes/publication.comment.ts +64 -0
  250. package/src/core/objects/publication/changes/publication.create.test.ts +87 -0
  251. package/src/core/objects/publication/changes/publication.create.ts +82 -0
  252. package/src/core/objects/publication/changes/publication.drop.test.ts +46 -0
  253. package/src/core/objects/publication/changes/publication.drop.ts +29 -0
  254. package/src/core/objects/publication/changes/publication.types.ts +26 -0
  255. package/src/core/objects/publication/publication.diff.test.ts +292 -0
  256. package/src/core/objects/publication/publication.diff.ts +253 -0
  257. package/src/core/objects/publication/publication.model.ts +206 -0
  258. package/src/core/objects/publication/utils.ts +55 -0
  259. package/src/core/objects/rls-policy/changes/rls-policy.alter.test.ts +250 -0
  260. package/src/core/objects/rls-policy/changes/rls-policy.alter.ts +128 -0
  261. package/src/core/objects/rls-policy/changes/rls-policy.base.ts +20 -0
  262. package/src/core/objects/rls-policy/changes/rls-policy.comment.ts +69 -0
  263. package/src/core/objects/rls-policy/changes/rls-policy.create.test.ts +74 -0
  264. package/src/core/objects/rls-policy/changes/rls-policy.create.ts +100 -0
  265. package/src/core/objects/rls-policy/changes/rls-policy.drop.test.ts +28 -0
  266. package/src/core/objects/rls-policy/changes/rls-policy.drop.ts +39 -0
  267. package/src/core/objects/rls-policy/changes/rls-policy.types.ts +10 -0
  268. package/src/core/objects/rls-policy/rls-policy.diff.test.ts +79 -0
  269. package/src/core/objects/rls-policy/rls-policy.diff.ts +121 -0
  270. package/src/core/objects/rls-policy/rls-policy.model.ts +140 -0
  271. package/src/core/objects/role/changes/role.alter.test.ts +346 -0
  272. package/src/core/objects/role/changes/role.alter.ts +110 -0
  273. package/src/core/objects/role/changes/role.base.ts +24 -0
  274. package/src/core/objects/role/changes/role.comment.ts +55 -0
  275. package/src/core/objects/role/changes/role.create.test.ts +52 -0
  276. package/src/core/objects/role/changes/role.create.ts +102 -0
  277. package/src/core/objects/role/changes/role.drop.test.ts +29 -0
  278. package/src/core/objects/role/changes/role.drop.ts +34 -0
  279. package/src/core/objects/role/changes/role.privilege.ts +376 -0
  280. package/src/core/objects/role/changes/role.types.ts +12 -0
  281. package/src/core/objects/role/role.diff.test.ts +44 -0
  282. package/src/core/objects/role/role.diff.ts +479 -0
  283. package/src/core/objects/role/role.model.ts +344 -0
  284. package/src/core/objects/rule/changes/rule.alter.test.ts +78 -0
  285. package/src/core/objects/rule/changes/rule.alter.ts +72 -0
  286. package/src/core/objects/rule/changes/rule.base.ts +20 -0
  287. package/src/core/objects/rule/changes/rule.comment.test.ts +55 -0
  288. package/src/core/objects/rule/changes/rule.comment.ts +62 -0
  289. package/src/core/objects/rule/changes/rule.create.test.ts +59 -0
  290. package/src/core/objects/rule/changes/rule.create.ts +42 -0
  291. package/src/core/objects/rule/changes/rule.drop.test.ts +38 -0
  292. package/src/core/objects/rule/changes/rule.drop.ts +29 -0
  293. package/src/core/objects/rule/changes/rule.types.ts +12 -0
  294. package/src/core/objects/rule/rule.diff.test.ts +132 -0
  295. package/src/core/objects/rule/rule.diff.ts +79 -0
  296. package/src/core/objects/rule/rule.model.ts +173 -0
  297. package/src/core/objects/schema/changes/schema.alter.test.ts +28 -0
  298. package/src/core/objects/schema/changes/schema.alter.ts +45 -0
  299. package/src/core/objects/schema/changes/schema.base.ts +20 -0
  300. package/src/core/objects/schema/changes/schema.comment.ts +56 -0
  301. package/src/core/objects/schema/changes/schema.create.test.ts +22 -0
  302. package/src/core/objects/schema/changes/schema.create.ts +47 -0
  303. package/src/core/objects/schema/changes/schema.drop.test.ts +20 -0
  304. package/src/core/objects/schema/changes/schema.drop.ts +34 -0
  305. package/src/core/objects/schema/changes/schema.privilege.ts +175 -0
  306. package/src/core/objects/schema/changes/schema.types.ts +12 -0
  307. package/src/core/objects/schema/schema.diff.test.ts +42 -0
  308. package/src/core/objects/schema/schema.diff.ts +209 -0
  309. package/src/core/objects/schema/schema.model.ts +107 -0
  310. package/src/core/objects/sequence/changes/sequence.alter.test.ts +151 -0
  311. package/src/core/objects/sequence/changes/sequence.alter.ts +115 -0
  312. package/src/core/objects/sequence/changes/sequence.base.ts +20 -0
  313. package/src/core/objects/sequence/changes/sequence.comment.ts +60 -0
  314. package/src/core/objects/sequence/changes/sequence.create.test.ts +84 -0
  315. package/src/core/objects/sequence/changes/sequence.create.ts +111 -0
  316. package/src/core/objects/sequence/changes/sequence.drop.test.ts +32 -0
  317. package/src/core/objects/sequence/changes/sequence.drop.ts +37 -0
  318. package/src/core/objects/sequence/changes/sequence.privilege.ts +179 -0
  319. package/src/core/objects/sequence/changes/sequence.types.ts +12 -0
  320. package/src/core/objects/sequence/sequence.diff.test.ts +141 -0
  321. package/src/core/objects/sequence/sequence.diff.ts +359 -0
  322. package/src/core/objects/sequence/sequence.model.ts +185 -0
  323. package/src/core/objects/subscription/changes/subscription.alter.test.ts +124 -0
  324. package/src/core/objects/subscription/changes/subscription.alter.ts +110 -0
  325. package/src/core/objects/subscription/changes/subscription.base.ts +20 -0
  326. package/src/core/objects/subscription/changes/subscription.comment.test.ts +67 -0
  327. package/src/core/objects/subscription/changes/subscription.comment.ts +64 -0
  328. package/src/core/objects/subscription/changes/subscription.create.test.ts +77 -0
  329. package/src/core/objects/subscription/changes/subscription.create.ts +69 -0
  330. package/src/core/objects/subscription/changes/subscription.drop.test.ts +46 -0
  331. package/src/core/objects/subscription/changes/subscription.drop.ts +20 -0
  332. package/src/core/objects/subscription/changes/subscription.types.ts +22 -0
  333. package/src/core/objects/subscription/subscription.diff.test.ts +232 -0
  334. package/src/core/objects/subscription/subscription.diff.ts +241 -0
  335. package/src/core/objects/subscription/subscription.model.ts +190 -0
  336. package/src/core/objects/subscription/utils.ts +156 -0
  337. package/src/core/objects/table/changes/table.alter.test.ts +823 -0
  338. package/src/core/objects/table/changes/table.alter.ts +806 -0
  339. package/src/core/objects/table/changes/table.base.ts +20 -0
  340. package/src/core/objects/table/changes/table.comment.ts +266 -0
  341. package/src/core/objects/table/changes/table.create.test.ts +150 -0
  342. package/src/core/objects/table/changes/table.create.ts +188 -0
  343. package/src/core/objects/table/changes/table.drop.test.ts +34 -0
  344. package/src/core/objects/table/changes/table.drop.ts +45 -0
  345. package/src/core/objects/table/changes/table.privilege.ts +200 -0
  346. package/src/core/objects/table/changes/table.types.ts +12 -0
  347. package/src/core/objects/table/table.diff.test.ts +711 -0
  348. package/src/core/objects/table/table.diff.ts +953 -0
  349. package/src/core/objects/table/table.model.ts +460 -0
  350. package/src/core/objects/trigger/changes/trigger.alter.test.ts +46 -0
  351. package/src/core/objects/trigger/changes/trigger.alter.ts +76 -0
  352. package/src/core/objects/trigger/changes/trigger.base.ts +20 -0
  353. package/src/core/objects/trigger/changes/trigger.comment.ts +64 -0
  354. package/src/core/objects/trigger/changes/trigger.create.test.ts +43 -0
  355. package/src/core/objects/trigger/changes/trigger.create.ts +85 -0
  356. package/src/core/objects/trigger/changes/trigger.drop.test.ts +43 -0
  357. package/src/core/objects/trigger/changes/trigger.drop.ts +39 -0
  358. package/src/core/objects/trigger/changes/trigger.types.ts +10 -0
  359. package/src/core/objects/trigger/trigger.diff.test.ts +83 -0
  360. package/src/core/objects/trigger/trigger.diff.ts +116 -0
  361. package/src/core/objects/trigger/trigger.model.ts +252 -0
  362. package/src/core/objects/type/composite-type/changes/composite-type.alter.test.ts +202 -0
  363. package/src/core/objects/type/composite-type/changes/composite-type.alter.ts +174 -0
  364. package/src/core/objects/type/composite-type/changes/composite-type.base.ts +20 -0
  365. package/src/core/objects/type/composite-type/changes/composite-type.comment.ts +145 -0
  366. package/src/core/objects/type/composite-type/changes/composite-type.create.test.ts +101 -0
  367. package/src/core/objects/type/composite-type/changes/composite-type.create.ts +95 -0
  368. package/src/core/objects/type/composite-type/changes/composite-type.drop.test.ts +33 -0
  369. package/src/core/objects/type/composite-type/changes/composite-type.drop.ts +37 -0
  370. package/src/core/objects/type/composite-type/changes/composite-type.privilege.ts +175 -0
  371. package/src/core/objects/type/composite-type/changes/composite-type.types.ts +12 -0
  372. package/src/core/objects/type/composite-type/composite-type.diff.test.ts +191 -0
  373. package/src/core/objects/type/composite-type/composite-type.diff.ts +372 -0
  374. package/src/core/objects/type/composite-type/composite-type.model.ts +252 -0
  375. package/src/core/objects/type/enum/changes/enum.alter.test.ts +104 -0
  376. package/src/core/objects/type/enum/changes/enum.alter.ts +91 -0
  377. package/src/core/objects/type/enum/changes/enum.base.ts +20 -0
  378. package/src/core/objects/type/enum/changes/enum.comment.ts +64 -0
  379. package/src/core/objects/type/enum/changes/enum.create.test.ts +28 -0
  380. package/src/core/objects/type/enum/changes/enum.create.ts +56 -0
  381. package/src/core/objects/type/enum/changes/enum.drop.test.ts +25 -0
  382. package/src/core/objects/type/enum/changes/enum.drop.ts +34 -0
  383. package/src/core/objects/type/enum/changes/enum.privilege.ts +175 -0
  384. package/src/core/objects/type/enum/changes/enum.types.ts +12 -0
  385. package/src/core/objects/type/enum/enum.diff.test.ts +191 -0
  386. package/src/core/objects/type/enum/enum.diff.ts +396 -0
  387. package/src/core/objects/type/enum/enum.model.ts +194 -0
  388. package/src/core/objects/type/range/changes/range.alter.test.ts +27 -0
  389. package/src/core/objects/type/range/changes/range.alter.ts +51 -0
  390. package/src/core/objects/type/range/changes/range.base.ts +20 -0
  391. package/src/core/objects/type/range/changes/range.comment.ts +64 -0
  392. package/src/core/objects/type/range/changes/range.create.test.ts +51 -0
  393. package/src/core/objects/type/range/changes/range.create.ts +151 -0
  394. package/src/core/objects/type/range/changes/range.drop.test.ts +26 -0
  395. package/src/core/objects/type/range/changes/range.drop.ts +34 -0
  396. package/src/core/objects/type/range/changes/range.privilege.ts +175 -0
  397. package/src/core/objects/type/range/changes/range.types.ts +12 -0
  398. package/src/core/objects/type/range/range.diff.test.ts +70 -0
  399. package/src/core/objects/type/range/range.diff.ts +259 -0
  400. package/src/core/objects/type/range/range.model.ts +187 -0
  401. package/src/core/objects/type/type.types.ts +5 -0
  402. package/src/core/objects/utils.ts +171 -0
  403. package/src/core/objects/view/changes/view.alter.test.ts +110 -0
  404. package/src/core/objects/view/changes/view.alter.ts +112 -0
  405. package/src/core/objects/view/changes/view.base.ts +20 -0
  406. package/src/core/objects/view/changes/view.comment.ts +59 -0
  407. package/src/core/objects/view/changes/view.create.test.ts +65 -0
  408. package/src/core/objects/view/changes/view.create.ts +73 -0
  409. package/src/core/objects/view/changes/view.drop.test.ts +34 -0
  410. package/src/core/objects/view/changes/view.drop.ts +40 -0
  411. package/src/core/objects/view/changes/view.privilege.ts +200 -0
  412. package/src/core/objects/view/changes/view.types.ts +12 -0
  413. package/src/core/objects/view/view.diff.test.ts +91 -0
  414. package/src/core/objects/view/view.diff.ts +365 -0
  415. package/src/core/objects/view/view.model.ts +276 -0
  416. package/src/core/plan/apply.ts +190 -0
  417. package/src/core/plan/create.ts +432 -0
  418. package/src/core/plan/hierarchy.ts +574 -0
  419. package/src/core/plan/index.ts +29 -0
  420. package/src/core/plan/io.ts +20 -0
  421. package/src/core/plan/risk.ts +48 -0
  422. package/src/core/plan/serialize.ts +195 -0
  423. package/src/core/plan/sql-format/constants.ts +13 -0
  424. package/src/core/plan/sql-format/fixtures.ts +2806 -0
  425. package/src/core/plan/sql-format/format-comment-literals.test.ts +96 -0
  426. package/src/core/plan/sql-format/format-functions.test.ts +127 -0
  427. package/src/core/plan/sql-format/format-lowercase-coverage.test.ts +67 -0
  428. package/src/core/plan/sql-format/format-off.test.ts +809 -0
  429. package/src/core/plan/sql-format/format-pretty-lower-leading.test.ts +1056 -0
  430. package/src/core/plan/sql-format/format-pretty-narrow.test.ts +1283 -0
  431. package/src/core/plan/sql-format/format-pretty-preserve.test.ts +1052 -0
  432. package/src/core/plan/sql-format/format-pretty-upper.test.ts +1045 -0
  433. package/src/core/plan/sql-format/format-stress.test.ts +616 -0
  434. package/src/core/plan/sql-format/format-utils.test.ts +91 -0
  435. package/src/core/plan/sql-format/format-utils.ts +391 -0
  436. package/src/core/plan/sql-format/formatters.ts +921 -0
  437. package/src/core/plan/sql-format/index.ts +149 -0
  438. package/src/core/plan/sql-format/keyword-case.test.ts +118 -0
  439. package/src/core/plan/sql-format/keyword-case.ts +1085 -0
  440. package/src/core/plan/sql-format/protect.test.ts +127 -0
  441. package/src/core/plan/sql-format/protect.ts +337 -0
  442. package/src/core/plan/sql-format/sql-scanner.test.ts +240 -0
  443. package/src/core/plan/sql-format/sql-scanner.ts +252 -0
  444. package/src/core/plan/sql-format/tokenizer.test.ts +68 -0
  445. package/src/core/plan/sql-format/tokenizer.ts +152 -0
  446. package/src/core/plan/sql-format/types.ts +31 -0
  447. package/src/core/plan/sql-format/wrap.test.ts +119 -0
  448. package/src/core/plan/sql-format/wrap.ts +196 -0
  449. package/src/core/plan/sql-format.ts +2 -0
  450. package/src/core/plan/statements.ts +22 -0
  451. package/src/core/plan/types.ts +165 -0
  452. package/src/core/postgres-config.ts +169 -0
  453. package/src/core/sort/custom-constraints.ts +161 -0
  454. package/src/core/sort/debug-visualization.ts +239 -0
  455. package/src/core/sort/dependency-filter.ts +224 -0
  456. package/src/core/sort/graph-builder.ts +223 -0
  457. package/src/core/sort/graph-utils.ts +51 -0
  458. package/src/core/sort/logical-sort.ts +590 -0
  459. package/src/core/sort/sort-changes.ts +234 -0
  460. package/src/core/sort/topological-sort.ts +184 -0
  461. package/src/core/sort/types.ts +112 -0
  462. package/src/core/sort/utils.ts +69 -0
  463. package/src/index.ts +14 -0
@@ -0,0 +1,344 @@
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
+
6
+ const membershipInfoSchema = z.object({
7
+ member: z.string(),
8
+ grantor: z.string(),
9
+ admin_option: z.boolean(),
10
+ inherit_option: z.boolean().nullish(),
11
+ set_option: z.boolean().nullish(),
12
+ });
13
+
14
+ const defaultPrivilegeSchema = z.object({
15
+ in_schema: z.string().nullable(),
16
+ objtype: z.enum(["r", "S", "f", "T", "n"]),
17
+ grantee: z.string(),
18
+ privileges: z.array(
19
+ z.object({ privilege: z.string(), grantable: z.boolean() }),
20
+ ),
21
+ });
22
+
23
+ const rolePropsSchema = z.object({
24
+ name: z.string(),
25
+ is_superuser: z.boolean(),
26
+ can_inherit: z.boolean(),
27
+ can_create_roles: z.boolean(),
28
+ can_create_databases: z.boolean(),
29
+ can_login: z.boolean(),
30
+ can_replicate: z.boolean(),
31
+ connection_limit: z.number().nullable(),
32
+ can_bypass_rls: z.boolean(),
33
+ config: z.array(z.string()).nullable(),
34
+ comment: z.string().nullable(),
35
+ members: z.array(membershipInfoSchema),
36
+ default_privileges: z.array(defaultPrivilegeSchema),
37
+ });
38
+
39
+ export type RoleProps = z.infer<typeof rolePropsSchema>;
40
+
41
+ export class Role extends BasePgModel {
42
+ public readonly name: RoleProps["name"];
43
+ public readonly is_superuser: RoleProps["is_superuser"];
44
+ public readonly can_inherit: RoleProps["can_inherit"];
45
+ public readonly can_create_roles: RoleProps["can_create_roles"];
46
+ public readonly can_create_databases: RoleProps["can_create_databases"];
47
+ public readonly can_login: RoleProps["can_login"];
48
+ public readonly can_replicate: RoleProps["can_replicate"];
49
+ public readonly connection_limit: RoleProps["connection_limit"];
50
+ public readonly can_bypass_rls: RoleProps["can_bypass_rls"];
51
+ public readonly config: RoleProps["config"];
52
+ public readonly comment: RoleProps["comment"];
53
+ public readonly members: RoleProps["members"];
54
+ public readonly default_privileges: RoleProps["default_privileges"];
55
+
56
+ constructor(props: RoleProps) {
57
+ super();
58
+
59
+ // Identity fields
60
+ this.name = props.name;
61
+
62
+ // Data fields
63
+ this.is_superuser = props.is_superuser;
64
+ this.can_inherit = props.can_inherit;
65
+ this.can_create_roles = props.can_create_roles;
66
+ this.can_create_databases = props.can_create_databases;
67
+ this.can_login = props.can_login;
68
+ this.can_replicate = props.can_replicate;
69
+ this.connection_limit = props.connection_limit;
70
+ this.can_bypass_rls = props.can_bypass_rls;
71
+ this.config = props.config;
72
+ this.comment = props.comment;
73
+ this.members = props.members;
74
+ this.default_privileges = props.default_privileges;
75
+ }
76
+
77
+ get stableId(): `role:${string}` {
78
+ return `role:${this.name}`;
79
+ }
80
+
81
+ get identityFields() {
82
+ return {
83
+ name: this.name,
84
+ };
85
+ }
86
+
87
+ get dataFields() {
88
+ const sortedMembers = [...this.members].sort((a, b) => {
89
+ return (
90
+ a.member.localeCompare(b.member) ||
91
+ a.grantor.localeCompare(b.grantor) ||
92
+ Number(a.admin_option) - Number(b.admin_option) ||
93
+ Number(a.inherit_option ?? false) - Number(b.inherit_option ?? false) ||
94
+ Number(a.set_option ?? false) - Number(b.set_option ?? false)
95
+ );
96
+ });
97
+
98
+ const sortedDefaultPrivs = [...this.default_privileges].map((dp) => ({
99
+ ...dp,
100
+ privileges: [...dp.privileges].sort((a, b) => {
101
+ return (
102
+ a.privilege.localeCompare(b.privilege) ||
103
+ Number(a.grantable) - Number(b.grantable)
104
+ );
105
+ }),
106
+ }));
107
+ sortedDefaultPrivs.sort((a, b) => {
108
+ return (
109
+ (a.in_schema ?? "").localeCompare(b.in_schema ?? "") ||
110
+ a.objtype.localeCompare(b.objtype) ||
111
+ a.grantee.localeCompare(b.grantee)
112
+ );
113
+ });
114
+
115
+ return {
116
+ is_superuser: this.is_superuser,
117
+ can_inherit: this.can_inherit,
118
+ can_create_roles: this.can_create_roles,
119
+ can_create_databases: this.can_create_databases,
120
+ can_login: this.can_login,
121
+ can_replicate: this.can_replicate,
122
+ connection_limit: this.connection_limit,
123
+ can_bypass_rls: this.can_bypass_rls,
124
+ config: this.config,
125
+ comment: this.comment,
126
+ members: sortedMembers,
127
+ default_privileges: sortedDefaultPrivs,
128
+ };
129
+ }
130
+ }
131
+
132
+ export async function extractRoles(pool: Pool): Promise<Role[]> {
133
+ // Check PostgreSQL version capabilities for membership options
134
+ const { rows: capabilitiesRows } = await pool.query<{
135
+ has_inherit: boolean;
136
+ has_set: boolean;
137
+ }>(sql`
138
+ select
139
+ exists (
140
+ select 1
141
+ from pg_attribute
142
+ where attrelid = 'pg_auth_members'::regclass
143
+ and attname = 'inherit_option'
144
+ ) as has_inherit,
145
+ exists (
146
+ select 1
147
+ from pg_attribute
148
+ where attrelid = 'pg_auth_members'::regclass
149
+ and attname = 'set_option'
150
+ ) as has_set
151
+ `);
152
+
153
+ const capabilities = capabilitiesRows[0];
154
+
155
+ let roleRows: RoleProps[];
156
+
157
+ if (capabilities?.has_inherit && capabilities?.has_set) {
158
+ const result = await pool.query<RoleProps>(sql`
159
+ WITH role_memberships AS (
160
+ SELECT
161
+ r.rolname AS role_name,
162
+ json_agg(
163
+ json_build_object(
164
+ 'member', m.rolname,
165
+ 'grantor', g.rolname,
166
+ 'admin_option', am.admin_option,
167
+ 'inherit_option', am.inherit_option,
168
+ 'set_option', am.set_option
169
+ )
170
+ ) FILTER (WHERE m.rolname IS NOT NULL) AS members
171
+ FROM pg_catalog.pg_roles r
172
+ LEFT JOIN pg_auth_members am ON am.roleid = r.oid
173
+ LEFT JOIN pg_roles m ON m.oid = am.member
174
+ LEFT JOIN pg_roles g ON g.oid = am.grantor
175
+ GROUP BY r.rolname
176
+ )
177
+ SELECT
178
+ quote_ident(r.rolname) AS name,
179
+ r.rolsuper AS is_superuser,
180
+ r.rolinherit AS can_inherit,
181
+ r.rolcreaterole AS can_create_roles,
182
+ r.rolcreatedb AS can_create_databases,
183
+ r.rolcanlogin AS can_login,
184
+ r.rolreplication AS can_replicate,
185
+ r.rolconnlimit AS connection_limit,
186
+ r.rolbypassrls AS can_bypass_rls,
187
+ r.rolconfig AS config,
188
+ obj_description(r.oid, 'pg_authid') AS comment,
189
+ COALESCE(rm.members, '[]') AS members,
190
+ COALESCE(
191
+ (
192
+ SELECT json_agg(
193
+ json_build_object(
194
+ 'in_schema',
195
+ CASE WHEN s.defaclnamespace = 0
196
+ THEN NULL
197
+ ELSE s.defaclnamespace::regnamespace::text
198
+ END,
199
+ 'objtype', s.defaclobjtype,
200
+ 'grantee',
201
+ CASE WHEN s.grantee = 0
202
+ THEN 'PUBLIC'
203
+ ELSE s.grantee::regrole::text
204
+ END,
205
+ 'privileges', s.privileges
206
+ )
207
+ ORDER BY s.defaclnamespace NULLS FIRST,
208
+ s.defaclobjtype,
209
+ s.grantee
210
+ )
211
+ FROM (
212
+ SELECT
213
+ d.defaclnamespace,
214
+ d.defaclobjtype,
215
+ x.grantee,
216
+ json_agg(
217
+ json_build_object(
218
+ 'privilege', x.privilege_type,
219
+ 'grantable', x.is_grantable
220
+ )
221
+ ORDER BY x.privilege_type, x.is_grantable
222
+ ) AS privileges
223
+ FROM pg_default_acl d
224
+ CROSS JOIN LATERAL aclexplode(COALESCE(d.defaclacl, ARRAY[]::aclitem[]))
225
+ AS x(grantor, grantee, privilege_type, is_grantable)
226
+ WHERE d.defaclrole = r.oid
227
+ GROUP BY d.defaclnamespace, d.defaclobjtype, x.grantee
228
+ ) AS s
229
+ ),
230
+ '[]'
231
+ ) AS default_privileges
232
+ FROM pg_catalog.pg_roles r
233
+ LEFT JOIN role_memberships rm ON rm.role_name = r.rolname
234
+ WHERE
235
+ r.rolname !~ '^pg_'
236
+ AND NOT EXISTS (
237
+ SELECT 1
238
+ FROM pg_catalog.pg_shdepend d
239
+ WHERE d.classid = 'pg_authid'::regclass
240
+ AND d.objid = r.oid
241
+ AND d.refclassid = 'pg_extension'::regclass
242
+ AND d.deptype IN ('e','x')
243
+ )
244
+ ORDER BY 1
245
+ `);
246
+ roleRows = result.rows;
247
+ } else {
248
+ const result = await pool.query<RoleProps>(sql`
249
+ WITH role_memberships AS (
250
+ SELECT
251
+ r.rolname AS role_name,
252
+ json_agg(
253
+ json_build_object(
254
+ 'member', m.rolname,
255
+ 'grantor', g.rolname,
256
+ 'admin_option', am.admin_option,
257
+ 'inherit_option', NULL,
258
+ 'set_option', NULL
259
+ )
260
+ ) FILTER (WHERE m.rolname IS NOT NULL) AS members
261
+ FROM pg_catalog.pg_roles r
262
+ LEFT JOIN pg_auth_members am ON am.roleid = r.oid
263
+ LEFT JOIN pg_roles m ON m.oid = am.member
264
+ LEFT JOIN pg_roles g ON g.oid = am.grantor
265
+ GROUP BY r.rolname
266
+ )
267
+ SELECT
268
+ quote_ident(r.rolname) AS name,
269
+ r.rolsuper AS is_superuser,
270
+ r.rolinherit AS can_inherit,
271
+ r.rolcreaterole AS can_create_roles,
272
+ r.rolcreatedb AS can_create_databases,
273
+ r.rolcanlogin AS can_login,
274
+ r.rolreplication AS can_replicate,
275
+ r.rolconnlimit AS connection_limit,
276
+ r.rolbypassrls AS can_bypass_rls,
277
+ r.rolconfig AS config,
278
+ obj_description(r.oid, 'pg_authid') AS comment,
279
+ COALESCE(rm.members, '[]') AS members,
280
+ COALESCE(
281
+ (
282
+ SELECT json_agg(
283
+ json_build_object(
284
+ 'in_schema',
285
+ CASE WHEN s.defaclnamespace = 0
286
+ THEN NULL
287
+ ELSE s.defaclnamespace::regnamespace::text
288
+ END,
289
+ 'objtype', s.defaclobjtype,
290
+ 'grantee',
291
+ CASE WHEN s.grantee = 0
292
+ THEN 'PUBLIC'
293
+ ELSE s.grantee::regrole::text
294
+ END,
295
+ 'privileges', s.privileges
296
+ )
297
+ ORDER BY s.defaclnamespace NULLS FIRST,
298
+ s.defaclobjtype,
299
+ s.grantee
300
+ )
301
+ FROM (
302
+ SELECT
303
+ d.defaclnamespace,
304
+ d.defaclobjtype,
305
+ x.grantee,
306
+ json_agg(
307
+ json_build_object(
308
+ 'privilege', x.privilege_type,
309
+ 'grantable', x.is_grantable
310
+ )
311
+ ORDER BY x.privilege_type, x.is_grantable
312
+ ) AS privileges
313
+ FROM pg_default_acl d
314
+ CROSS JOIN LATERAL aclexplode(COALESCE(d.defaclacl, ARRAY[]::aclitem[]))
315
+ AS x(grantor, grantee, privilege_type, is_grantable)
316
+ WHERE d.defaclrole = r.oid
317
+ GROUP BY d.defaclnamespace, d.defaclobjtype, x.grantee
318
+ ) AS s
319
+ ),
320
+ '[]'
321
+ ) AS default_privileges
322
+ FROM pg_catalog.pg_roles r
323
+ LEFT JOIN role_memberships rm ON rm.role_name = r.rolname
324
+ WHERE
325
+ r.rolname !~ '^pg_'
326
+ AND NOT EXISTS (
327
+ SELECT 1
328
+ FROM pg_catalog.pg_shdepend d
329
+ WHERE d.classid = 'pg_authid'::regclass
330
+ AND d.objid = r.oid
331
+ AND d.refclassid = 'pg_extension'::regclass
332
+ AND d.deptype IN ('e','x')
333
+ )
334
+ ORDER BY 1
335
+ `);
336
+ roleRows = result.rows;
337
+ }
338
+
339
+ // Validate and parse each row using the Zod schema
340
+ const validatedRows = roleRows.map((row: unknown) =>
341
+ rolePropsSchema.parse(row),
342
+ );
343
+ return validatedRows.map((row: RoleProps) => new Role(row));
344
+ }
@@ -0,0 +1,78 @@
1
+ import { describe, expect, test } from "bun:test";
2
+ import { stableId } from "../../utils.ts";
3
+ import { Rule } from "../rule.model.ts";
4
+ import { ReplaceRule, SetRuleEnabledState } from "./rule.alter.ts";
5
+
6
+ type RuleProps = ConstructorParameters<typeof Rule>[0];
7
+
8
+ const base: RuleProps = {
9
+ schema: "public",
10
+ name: '"my_rule"',
11
+ table_name: '"my_table"',
12
+ relation_kind: "r",
13
+ event: "INSERT",
14
+ enabled: "O",
15
+ is_instead: true,
16
+ owner: "owner1",
17
+ definition:
18
+ 'CREATE RULE "my_rule" AS ON INSERT TO public."my_table" DO INSTEAD NOTHING',
19
+ comment: null,
20
+ columns: ["id"],
21
+ };
22
+
23
+ const makeRule = (override: Partial<RuleProps> = {}) =>
24
+ new Rule({
25
+ ...base,
26
+ ...override,
27
+ columns: override.columns ? [...override.columns] : [...base.columns],
28
+ });
29
+
30
+ describe("rule.alter", () => {
31
+ test("replace rule serializes using create or replace and tracks dependencies", () => {
32
+ const rule = makeRule({ columns: ["id", "amount"] });
33
+ const change = new ReplaceRule({ rule });
34
+
35
+ expect(change.requires).toEqual([
36
+ rule.stableId,
37
+ rule.relationStableId,
38
+ ...rule.columns.map((column) =>
39
+ stableId.column(rule.schema, rule.table_name, column),
40
+ ),
41
+ ]);
42
+ expect(change.serialize()).toBe(
43
+ 'CREATE OR REPLACE RULE "my_rule" AS ON INSERT TO public."my_table" DO INSTEAD NOTHING',
44
+ );
45
+ });
46
+
47
+ test("set rule enabled state serializes appropriate clause", () => {
48
+ const rule = makeRule({ columns: ["id", "amount"] });
49
+ const change = new SetRuleEnabledState({ rule, enabled: "D" });
50
+
51
+ expect(change.requires).toEqual([
52
+ rule.stableId,
53
+ rule.relationStableId,
54
+ ...rule.columns.map((column) =>
55
+ stableId.column(rule.schema, rule.table_name, column),
56
+ ),
57
+ ]);
58
+ expect(change.serialize()).toBe(
59
+ 'ALTER TABLE public."my_table" DISABLE RULE "my_rule"',
60
+ );
61
+ });
62
+
63
+ test("set rule enabled state defaults to rule value and supports views", () => {
64
+ const rule = makeRule({
65
+ table_name: '"my_view"',
66
+ relation_kind: "v",
67
+ enabled: "R",
68
+ columns: [],
69
+ });
70
+
71
+ const change = new SetRuleEnabledState({ rule });
72
+
73
+ expect(change.requires).toEqual([rule.stableId, rule.relationStableId]);
74
+ expect(change.serialize()).toBe(
75
+ 'ALTER TABLE public."my_view" ENABLE REPLICA RULE "my_rule"',
76
+ );
77
+ });
78
+ });
@@ -0,0 +1,72 @@
1
+ import { stableId } from "../../utils.ts";
2
+ import type { Rule, RuleEnabledState } from "../rule.model.ts";
3
+ import { AlterRuleChange } from "./rule.base.ts";
4
+ import { CreateRule } from "./rule.create.ts";
5
+
6
+ export class ReplaceRule extends AlterRuleChange {
7
+ public readonly rule: Rule;
8
+ public readonly scope = "object" as const;
9
+
10
+ constructor(props: { rule: Rule }) {
11
+ super();
12
+ this.rule = props.rule;
13
+ }
14
+
15
+ get requires() {
16
+ return [
17
+ this.rule.stableId,
18
+ this.rule.relationStableId,
19
+ ...this.rule.columns.map((column) =>
20
+ stableId.column(this.rule.schema, this.rule.table_name, column),
21
+ ),
22
+ ];
23
+ }
24
+
25
+ serialize(): string {
26
+ return new CreateRule({ rule: this.rule, orReplace: true }).serialize();
27
+ }
28
+ }
29
+
30
+ export class SetRuleEnabledState extends AlterRuleChange {
31
+ public readonly rule: Rule;
32
+ public readonly scope = "object" as const;
33
+ public readonly enabled: RuleEnabledState;
34
+
35
+ constructor(props: { rule: Rule; enabled?: RuleEnabledState }) {
36
+ super();
37
+ this.rule = props.rule;
38
+ this.enabled = props.enabled ?? props.rule.enabled;
39
+ }
40
+
41
+ get requires() {
42
+ return [
43
+ this.rule.stableId,
44
+ this.rule.relationStableId,
45
+ ...this.rule.columns.map((column) =>
46
+ stableId.column(this.rule.schema, this.rule.table_name, column),
47
+ ),
48
+ ];
49
+ }
50
+
51
+ serialize(): string {
52
+ const clause = clauseForState(this.enabled);
53
+ return `ALTER TABLE ${this.rule.schema}.${this.rule.table_name} ${clause} ${this.rule.name}`;
54
+ }
55
+ }
56
+
57
+ function clauseForState(state: RuleEnabledState) {
58
+ switch (state) {
59
+ case "O":
60
+ return "ENABLE RULE";
61
+ case "D":
62
+ return "DISABLE RULE";
63
+ case "R":
64
+ return "ENABLE REPLICA RULE";
65
+ case "A":
66
+ return "ENABLE ALWAYS RULE";
67
+ default: {
68
+ const _exhaustive: never = state;
69
+ return _exhaustive;
70
+ }
71
+ }
72
+ }
@@ -0,0 +1,20 @@
1
+ import { BaseChange } from "../../base.change.ts";
2
+ import type { Rule } from "../rule.model.ts";
3
+
4
+ abstract class BaseRuleChange extends BaseChange {
5
+ abstract readonly rule: Rule;
6
+ abstract readonly scope: "object" | "comment";
7
+ readonly objectType = "rule" as const;
8
+ }
9
+
10
+ export abstract class CreateRuleChange extends BaseRuleChange {
11
+ readonly operation = "create" as const;
12
+ }
13
+
14
+ export abstract class AlterRuleChange extends BaseRuleChange {
15
+ readonly operation = "alter" as const;
16
+ }
17
+
18
+ export abstract class DropRuleChange extends BaseRuleChange {
19
+ readonly operation = "drop" as const;
20
+ }
@@ -0,0 +1,55 @@
1
+ import { describe, expect, test } from "bun:test";
2
+ import { stableId } from "../../utils.ts";
3
+ import { Rule } from "../rule.model.ts";
4
+ import { CreateCommentOnRule, DropCommentOnRule } from "./rule.comment.ts";
5
+
6
+ type RuleProps = ConstructorParameters<typeof Rule>[0];
7
+
8
+ const base: RuleProps = {
9
+ schema: "public",
10
+ name: '"my_rule"',
11
+ table_name: '"my_table"',
12
+ relation_kind: "r",
13
+ event: "INSERT",
14
+ enabled: "O",
15
+ is_instead: true,
16
+ owner: "owner1",
17
+ definition:
18
+ 'CREATE RULE "my_rule" AS ON INSERT TO public."my_table" DO INSTEAD NOTHING',
19
+ comment: null,
20
+ columns: ["id"],
21
+ };
22
+
23
+ const makeRule = (override: Partial<RuleProps> = {}) =>
24
+ new Rule({
25
+ ...base,
26
+ ...override,
27
+ columns: override.columns ? [...override.columns] : [...base.columns],
28
+ });
29
+
30
+ describe("rule.comment", () => {
31
+ test("create comment serializes and tracks dependencies", () => {
32
+ const rule = makeRule({ comment: "rule's description" });
33
+ const change = new CreateCommentOnRule({ rule });
34
+
35
+ expect(change.creates).toEqual([stableId.comment(rule.stableId)]);
36
+ expect(change.requires).toEqual([rule.stableId]);
37
+ expect(change.serialize()).toBe(
38
+ "COMMENT ON RULE \"my_rule\" ON public.\"my_table\" IS 'rule''s description'",
39
+ );
40
+ });
41
+
42
+ test("drop comment serializes and tracks dependencies", () => {
43
+ const rule = makeRule({ comment: "temporary comment" });
44
+ const change = new DropCommentOnRule({ rule });
45
+
46
+ expect(change.drops).toEqual([stableId.comment(rule.stableId)]);
47
+ expect(change.requires).toEqual([
48
+ stableId.comment(rule.stableId),
49
+ rule.stableId,
50
+ ]);
51
+ expect(change.serialize()).toBe(
52
+ 'COMMENT ON RULE "my_rule" ON public."my_table" IS NULL',
53
+ );
54
+ });
55
+ });
@@ -0,0 +1,62 @@
1
+ import { quoteLiteral } from "../../base.change.ts";
2
+ import { stableId } from "../../utils.ts";
3
+ import type { Rule } from "../rule.model.ts";
4
+ import { CreateRuleChange, DropRuleChange } from "./rule.base.ts";
5
+
6
+ export class CreateCommentOnRule extends CreateRuleChange {
7
+ public readonly rule: Rule;
8
+ public readonly scope = "comment" as const;
9
+
10
+ constructor(props: { rule: Rule }) {
11
+ super();
12
+ this.rule = props.rule;
13
+ }
14
+
15
+ get creates() {
16
+ return [stableId.comment(this.rule.stableId)];
17
+ }
18
+
19
+ get requires() {
20
+ return [this.rule.stableId];
21
+ }
22
+
23
+ serialize(): string {
24
+ return [
25
+ "COMMENT ON RULE",
26
+ this.rule.name,
27
+ "ON",
28
+ `${this.rule.schema}.${this.rule.table_name}`,
29
+ "IS",
30
+ // biome-ignore lint/style/noNonNullAssertion: rule comment is not nullable in this case
31
+ quoteLiteral(this.rule.comment!),
32
+ ].join(" ");
33
+ }
34
+ }
35
+
36
+ export class DropCommentOnRule extends DropRuleChange {
37
+ public readonly rule: Rule;
38
+ public readonly scope = "comment" as const;
39
+
40
+ constructor(props: { rule: Rule }) {
41
+ super();
42
+ this.rule = props.rule;
43
+ }
44
+
45
+ get drops() {
46
+ return [stableId.comment(this.rule.stableId)];
47
+ }
48
+
49
+ get requires() {
50
+ return [stableId.comment(this.rule.stableId), this.rule.stableId];
51
+ }
52
+
53
+ serialize(): string {
54
+ return [
55
+ "COMMENT ON RULE",
56
+ this.rule.name,
57
+ "ON",
58
+ `${this.rule.schema}.${this.rule.table_name}`,
59
+ "IS NULL",
60
+ ].join(" ");
61
+ }
62
+ }
@@ -0,0 +1,59 @@
1
+ import { describe, expect, test } from "bun:test";
2
+ import { stableId } from "../../utils.ts";
3
+ import { Rule } from "../rule.model.ts";
4
+ import { CreateRule } from "./rule.create.ts";
5
+
6
+ type RuleProps = ConstructorParameters<typeof Rule>[0];
7
+
8
+ const base: RuleProps = {
9
+ schema: "public",
10
+ name: '"my_rule"',
11
+ table_name: '"my_table"',
12
+ relation_kind: "r",
13
+ event: "INSERT",
14
+ enabled: "O",
15
+ is_instead: true,
16
+ owner: "owner1",
17
+ definition:
18
+ 'CREATE RULE "my_rule" AS ON INSERT TO public."my_table" DO INSTEAD NOTHING',
19
+ comment: null,
20
+ columns: ["id"],
21
+ };
22
+
23
+ const makeRule = (override: Partial<RuleProps> = {}) =>
24
+ new Rule({
25
+ ...base,
26
+ ...override,
27
+ columns: override.columns ? [...override.columns] : [...base.columns],
28
+ });
29
+
30
+ describe("rule.create", () => {
31
+ test("serialize rule definition and track dependencies", () => {
32
+ const rule = makeRule();
33
+ const change = new CreateRule({ rule });
34
+
35
+ expect(change.creates).toEqual([rule.stableId]);
36
+ expect(change.requires).toEqual([
37
+ rule.relationStableId,
38
+ ...rule.columns.map((column) =>
39
+ stableId.column(rule.schema, rule.table_name, column),
40
+ ),
41
+ ]);
42
+ expect(change.serialize()).toBe(
43
+ 'CREATE RULE "my_rule" AS ON INSERT TO public."my_table" DO INSTEAD NOTHING',
44
+ );
45
+ });
46
+
47
+ test("serialize rule definition with or replace override", () => {
48
+ const rule = makeRule({
49
+ definition:
50
+ ' CREATE RULE "my_rule" AS ON INSERT TO public."my_table" DO INSTEAD NOTHING ',
51
+ });
52
+
53
+ const change = new CreateRule({ rule, orReplace: true });
54
+
55
+ expect(change.serialize()).toBe(
56
+ 'CREATE OR REPLACE RULE "my_rule" AS ON INSERT TO public."my_table" DO INSTEAD NOTHING',
57
+ );
58
+ });
59
+ });