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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (464) hide show
  1. package/README.md +22 -0
  2. package/dist/cli/bin/cli.js +0 -0
  3. package/dist/cli/commands/plan.js +21 -0
  4. package/dist/cli/utils.d.ts +2 -0
  5. package/dist/cli/utils.js +1 -1
  6. package/dist/core/integrations/supabase.js +2 -0
  7. package/dist/core/objects/table/table.model.d.ts +4 -2
  8. package/dist/core/objects/table/table.model.js +3 -0
  9. package/dist/core/objects/trigger/changes/trigger.alter.js +23 -0
  10. package/dist/core/objects/trigger/changes/trigger.create.js +2 -1
  11. package/dist/core/objects/trigger/trigger.model.d.ts +1 -0
  12. package/dist/core/objects/trigger/trigger.model.js +3 -0
  13. package/dist/core/plan/apply.js +3 -3
  14. package/dist/core/plan/create.js +34 -15
  15. package/dist/core/plan/sql-format/constants.d.ts +2 -0
  16. package/dist/core/plan/sql-format/constants.js +11 -0
  17. package/dist/core/plan/sql-format/fixtures.d.ts +2 -0
  18. package/dist/core/plan/sql-format/fixtures.js +2449 -0
  19. package/dist/core/plan/sql-format/format-utils.d.ts +37 -0
  20. package/dist/core/plan/sql-format/format-utils.js +274 -0
  21. package/dist/core/plan/sql-format/formatters.d.ts +20 -0
  22. package/dist/core/plan/sql-format/formatters.js +737 -0
  23. package/dist/core/plan/sql-format/index.d.ts +2 -0
  24. package/dist/core/plan/sql-format/index.js +98 -0
  25. package/dist/core/plan/sql-format/keyword-case.d.ts +2 -0
  26. package/dist/core/plan/sql-format/keyword-case.js +868 -0
  27. package/dist/core/plan/sql-format/protect.d.ts +3 -0
  28. package/dist/core/plan/sql-format/protect.js +269 -0
  29. package/dist/core/plan/sql-format/sql-scanner.d.ts +59 -0
  30. package/dist/core/plan/sql-format/sql-scanner.js +202 -0
  31. package/dist/core/plan/sql-format/tokenizer.d.ts +22 -0
  32. package/dist/core/plan/sql-format/tokenizer.js +118 -0
  33. package/dist/core/plan/sql-format/types.d.ts +28 -0
  34. package/dist/core/plan/sql-format/types.js +1 -0
  35. package/dist/core/plan/sql-format/wrap.d.ts +2 -0
  36. package/dist/core/plan/sql-format/wrap.js +165 -0
  37. package/dist/core/plan/sql-format.d.ts +2 -0
  38. package/dist/core/plan/sql-format.js +1 -0
  39. package/dist/core/plan/statements.d.ts +2 -1
  40. package/dist/core/plan/statements.js +6 -2
  41. package/dist/core/postgres-config.d.ts +15 -0
  42. package/dist/core/postgres-config.js +30 -0
  43. package/dist/index.d.ts +2 -0
  44. package/dist/index.js +1 -0
  45. package/package.json +37 -22
  46. package/src/cli/app.ts +28 -0
  47. package/src/cli/bin/cli.ts +9 -0
  48. package/src/cli/commands/apply.ts +101 -0
  49. package/src/cli/commands/plan.ts +195 -0
  50. package/src/cli/commands/sync.ts +185 -0
  51. package/src/cli/formatters/index.ts +5 -0
  52. package/src/cli/formatters/tree/tree-builder.ts +380 -0
  53. package/src/cli/formatters/tree/tree-renderer.ts +372 -0
  54. package/src/cli/formatters/tree/tree.ts +237 -0
  55. package/src/cli/utils/integrations.ts +42 -0
  56. package/src/cli/utils.ts +231 -0
  57. package/src/core/catalog.diff.ts +246 -0
  58. package/src/core/catalog.model.ts +384 -0
  59. package/src/core/change.types.ts +44 -0
  60. package/src/core/context.ts +26 -0
  61. package/src/core/depend.ts +1870 -0
  62. package/src/core/expand-replace-dependencies.ts +380 -0
  63. package/src/core/fingerprint.ts +204 -0
  64. package/src/core/integrations/filter/dsl.ts +204 -0
  65. package/src/core/integrations/filter/extractors.ts +145 -0
  66. package/src/core/integrations/filter/filter.types.ts +3 -0
  67. package/src/core/integrations/integration-dsl.ts +24 -0
  68. package/src/core/integrations/integration.types.ts +7 -0
  69. package/src/core/integrations/serialize/dsl.ts +77 -0
  70. package/src/core/integrations/serialize/serialize.types.ts +3 -0
  71. package/src/core/integrations/supabase.ts +121 -0
  72. package/src/core/objects/aggregate/aggregate.diff.test.ts +215 -0
  73. package/src/core/objects/aggregate/aggregate.diff.ts +278 -0
  74. package/src/core/objects/aggregate/aggregate.model.ts +317 -0
  75. package/src/core/objects/aggregate/changes/aggregate.alter.test.ts +64 -0
  76. package/src/core/objects/aggregate/changes/aggregate.alter.ts +32 -0
  77. package/src/core/objects/aggregate/changes/aggregate.base.ts +20 -0
  78. package/src/core/objects/aggregate/changes/aggregate.comment.test.ts +86 -0
  79. package/src/core/objects/aggregate/changes/aggregate.comment.ts +62 -0
  80. package/src/core/objects/aggregate/changes/aggregate.create.test.ts +101 -0
  81. package/src/core/objects/aggregate/changes/aggregate.create.ts +329 -0
  82. package/src/core/objects/aggregate/changes/aggregate.drop.test.ts +78 -0
  83. package/src/core/objects/aggregate/changes/aggregate.drop.ts +32 -0
  84. package/src/core/objects/aggregate/changes/aggregate.privilege.test.ts +130 -0
  85. package/src/core/objects/aggregate/changes/aggregate.privilege.ts +146 -0
  86. package/src/core/objects/aggregate/changes/aggregate.types.ts +12 -0
  87. package/src/core/objects/base.change.ts +62 -0
  88. package/src/core/objects/base.default-privileges.ts +204 -0
  89. package/src/core/objects/base.diff.ts +20 -0
  90. package/src/core/objects/base.model.ts +82 -0
  91. package/src/core/objects/base.privilege-diff.ts +299 -0
  92. package/src/core/objects/base.privilege.ts +184 -0
  93. package/src/core/objects/collation/changes/collation.alter.test.ts +63 -0
  94. package/src/core/objects/collation/changes/collation.alter.ts +79 -0
  95. package/src/core/objects/collation/changes/collation.base.ts +20 -0
  96. package/src/core/objects/collation/changes/collation.comment.ts +68 -0
  97. package/src/core/objects/collation/changes/collation.create.test.ts +51 -0
  98. package/src/core/objects/collation/changes/collation.create.ts +106 -0
  99. package/src/core/objects/collation/changes/collation.drop.test.ts +28 -0
  100. package/src/core/objects/collation/changes/collation.drop.ts +37 -0
  101. package/src/core/objects/collation/changes/collation.types.ts +10 -0
  102. package/src/core/objects/collation/collation.diff.test.ts +100 -0
  103. package/src/core/objects/collation/collation.diff.ts +126 -0
  104. package/src/core/objects/collation/collation.model.ts +224 -0
  105. package/src/core/objects/domain/changes/domain.alter.test.ts +316 -0
  106. package/src/core/objects/domain/changes/domain.alter.ts +286 -0
  107. package/src/core/objects/domain/changes/domain.base.ts +20 -0
  108. package/src/core/objects/domain/changes/domain.comment.ts +59 -0
  109. package/src/core/objects/domain/changes/domain.create.test.ts +65 -0
  110. package/src/core/objects/domain/changes/domain.create.ts +118 -0
  111. package/src/core/objects/domain/changes/domain.drop.test.ts +30 -0
  112. package/src/core/objects/domain/changes/domain.drop.ts +34 -0
  113. package/src/core/objects/domain/changes/domain.privilege.ts +171 -0
  114. package/src/core/objects/domain/changes/domain.types.ts +12 -0
  115. package/src/core/objects/domain/domain.diff.test.ts +284 -0
  116. package/src/core/objects/domain/domain.diff.ts +358 -0
  117. package/src/core/objects/domain/domain.model.ts +190 -0
  118. package/src/core/objects/event-trigger/changes/event-trigger.alter.test.ts +50 -0
  119. package/src/core/objects/event-trigger/changes/event-trigger.alter.ts +82 -0
  120. package/src/core/objects/event-trigger/changes/event-trigger.base.ts +20 -0
  121. package/src/core/objects/event-trigger/changes/event-trigger.comment.ts +66 -0
  122. package/src/core/objects/event-trigger/changes/event-trigger.create.test.ts +24 -0
  123. package/src/core/objects/event-trigger/changes/event-trigger.create.ts +72 -0
  124. package/src/core/objects/event-trigger/changes/event-trigger.drop.test.ts +22 -0
  125. package/src/core/objects/event-trigger/changes/event-trigger.drop.ts +34 -0
  126. package/src/core/objects/event-trigger/changes/event-trigger.types.ts +10 -0
  127. package/src/core/objects/event-trigger/event-trigger.diff.test.ts +126 -0
  128. package/src/core/objects/event-trigger/event-trigger.diff.ts +126 -0
  129. package/src/core/objects/event-trigger/event-trigger.model.ts +106 -0
  130. package/src/core/objects/extension/changes/extension.alter.test.ts +58 -0
  131. package/src/core/objects/extension/changes/extension.alter.ts +78 -0
  132. package/src/core/objects/extension/changes/extension.base.ts +20 -0
  133. package/src/core/objects/extension/changes/extension.comment.ts +64 -0
  134. package/src/core/objects/extension/changes/extension.create.test.ts +25 -0
  135. package/src/core/objects/extension/changes/extension.create.ts +63 -0
  136. package/src/core/objects/extension/changes/extension.drop.test.ts +23 -0
  137. package/src/core/objects/extension/changes/extension.drop.ts +34 -0
  138. package/src/core/objects/extension/changes/extension.types.ts +10 -0
  139. package/src/core/objects/extension/extension.diff.test.ts +42 -0
  140. package/src/core/objects/extension/extension.diff.ts +90 -0
  141. package/src/core/objects/extension/extension.model.ts +280 -0
  142. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.alter.test.ts +125 -0
  143. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.alter.ts +101 -0
  144. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.base.ts +20 -0
  145. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.comment.ts +72 -0
  146. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.create.test.ts +125 -0
  147. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.create.ts +95 -0
  148. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.drop.test.ts +23 -0
  149. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.drop.ts +36 -0
  150. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.privilege.ts +172 -0
  151. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.types.ts +12 -0
  152. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/foreign-data-wrapper.diff.test.ts +179 -0
  153. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/foreign-data-wrapper.diff.ts +341 -0
  154. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/foreign-data-wrapper.model.ts +149 -0
  155. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper.types.ts +10 -0
  156. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.alter.test.ts +309 -0
  157. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.alter.ts +341 -0
  158. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.base.ts +20 -0
  159. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.comment.ts +72 -0
  160. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.create.test.ts +201 -0
  161. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.create.ts +81 -0
  162. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.drop.test.ts +43 -0
  163. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.drop.ts +37 -0
  164. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.privilege.ts +181 -0
  165. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.types.ts +12 -0
  166. package/src/core/objects/foreign-data-wrapper/foreign-table/foreign-table.diff.test.ts +813 -0
  167. package/src/core/objects/foreign-data-wrapper/foreign-table/foreign-table.diff.ts +406 -0
  168. package/src/core/objects/foreign-data-wrapper/foreign-table/foreign-table.model.ts +242 -0
  169. package/src/core/objects/foreign-data-wrapper/server/changes/server.alter.test.ts +168 -0
  170. package/src/core/objects/foreign-data-wrapper/server/changes/server.alter.ts +126 -0
  171. package/src/core/objects/foreign-data-wrapper/server/changes/server.base.ts +20 -0
  172. package/src/core/objects/foreign-data-wrapper/server/changes/server.comment.ts +60 -0
  173. package/src/core/objects/foreign-data-wrapper/server/changes/server.create.test.ts +131 -0
  174. package/src/core/objects/foreign-data-wrapper/server/changes/server.create.ts +81 -0
  175. package/src/core/objects/foreign-data-wrapper/server/changes/server.drop.test.ts +24 -0
  176. package/src/core/objects/foreign-data-wrapper/server/changes/server.drop.ts +34 -0
  177. package/src/core/objects/foreign-data-wrapper/server/changes/server.privilege.ts +164 -0
  178. package/src/core/objects/foreign-data-wrapper/server/changes/server.types.ts +12 -0
  179. package/src/core/objects/foreign-data-wrapper/server/server.diff.test.ts +167 -0
  180. package/src/core/objects/foreign-data-wrapper/server/server.diff.ts +317 -0
  181. package/src/core/objects/foreign-data-wrapper/server/server.model.ts +133 -0
  182. package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.alter.test.ts +82 -0
  183. package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.alter.ts +69 -0
  184. package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.base.ts +20 -0
  185. package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.create.test.ts +85 -0
  186. package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.create.ts +66 -0
  187. package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.drop.test.ts +53 -0
  188. package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.drop.ts +40 -0
  189. package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.types.ts +8 -0
  190. package/src/core/objects/foreign-data-wrapper/user-mapping/user-mapping.diff.test.ts +77 -0
  191. package/src/core/objects/foreign-data-wrapper/user-mapping/user-mapping.diff.ts +107 -0
  192. package/src/core/objects/foreign-data-wrapper/user-mapping/user-mapping.model.ts +96 -0
  193. package/src/core/objects/index/changes/index.alter.test.ts +200 -0
  194. package/src/core/objects/index/changes/index.alter.ts +144 -0
  195. package/src/core/objects/index/changes/index.base.ts +20 -0
  196. package/src/core/objects/index/changes/index.comment.ts +63 -0
  197. package/src/core/objects/index/changes/index.create.test.ts +66 -0
  198. package/src/core/objects/index/changes/index.create.ts +68 -0
  199. package/src/core/objects/index/changes/index.drop.test.ts +44 -0
  200. package/src/core/objects/index/changes/index.drop.ts +34 -0
  201. package/src/core/objects/index/changes/index.types.ts +6 -0
  202. package/src/core/objects/index/changes/utils.ts +16 -0
  203. package/src/core/objects/index/index.diff.test.ts +153 -0
  204. package/src/core/objects/index/index.diff.ts +243 -0
  205. package/src/core/objects/index/index.model.ts +370 -0
  206. package/src/core/objects/language/changes/language.alter.test.ts +33 -0
  207. package/src/core/objects/language/changes/language.alter.ts +53 -0
  208. package/src/core/objects/language/changes/language.base.ts +20 -0
  209. package/src/core/objects/language/changes/language.comment.ts +58 -0
  210. package/src/core/objects/language/changes/language.create.test.ts +27 -0
  211. package/src/core/objects/language/changes/language.create.ts +104 -0
  212. package/src/core/objects/language/changes/language.drop.test.ts +25 -0
  213. package/src/core/objects/language/changes/language.drop.ts +39 -0
  214. package/src/core/objects/language/changes/language.privilege.ts +172 -0
  215. package/src/core/objects/language/changes/language.types.ts +12 -0
  216. package/src/core/objects/language/language.diff.test.ts +53 -0
  217. package/src/core/objects/language/language.diff.ts +176 -0
  218. package/src/core/objects/language/language.model.ts +150 -0
  219. package/src/core/objects/materialized-view/changes/materialized-view.alter.test.ts +123 -0
  220. package/src/core/objects/materialized-view/changes/materialized-view.alter.ts +113 -0
  221. package/src/core/objects/materialized-view/changes/materialized-view.base.ts +20 -0
  222. package/src/core/objects/materialized-view/changes/materialized-view.comment.ts +176 -0
  223. package/src/core/objects/materialized-view/changes/materialized-view.create.test.ts +64 -0
  224. package/src/core/objects/materialized-view/changes/materialized-view.create.ts +93 -0
  225. package/src/core/objects/materialized-view/changes/materialized-view.drop.test.ts +34 -0
  226. package/src/core/objects/materialized-view/changes/materialized-view.drop.ts +60 -0
  227. package/src/core/objects/materialized-view/changes/materialized-view.privilege.ts +212 -0
  228. package/src/core/objects/materialized-view/changes/materialized-view.types.ts +12 -0
  229. package/src/core/objects/materialized-view/materialized-view.diff.test.ts +102 -0
  230. package/src/core/objects/materialized-view/materialized-view.diff.ts +451 -0
  231. package/src/core/objects/materialized-view/materialized-view.model.ts +258 -0
  232. package/src/core/objects/procedure/changes/procedure.alter.test.ts +1005 -0
  233. package/src/core/objects/procedure/changes/procedure.alter.ts +287 -0
  234. package/src/core/objects/procedure/changes/procedure.base.ts +20 -0
  235. package/src/core/objects/procedure/changes/procedure.comment.ts +70 -0
  236. package/src/core/objects/procedure/changes/procedure.create.test.ts +48 -0
  237. package/src/core/objects/procedure/changes/procedure.create.ts +92 -0
  238. package/src/core/objects/procedure/changes/procedure.drop.test.ts +85 -0
  239. package/src/core/objects/procedure/changes/procedure.drop.ts +49 -0
  240. package/src/core/objects/procedure/changes/procedure.privilege.ts +188 -0
  241. package/src/core/objects/procedure/changes/procedure.types.ts +12 -0
  242. package/src/core/objects/procedure/procedure.diff.test.ts +161 -0
  243. package/src/core/objects/procedure/procedure.diff.ts +404 -0
  244. package/src/core/objects/procedure/procedure.model.ts +264 -0
  245. package/src/core/objects/procedure/utils.ts +58 -0
  246. package/src/core/objects/publication/changes/publication.alter.test.ts +223 -0
  247. package/src/core/objects/publication/changes/publication.alter.ts +243 -0
  248. package/src/core/objects/publication/changes/publication.base.ts +20 -0
  249. package/src/core/objects/publication/changes/publication.comment.test.ts +70 -0
  250. package/src/core/objects/publication/changes/publication.comment.ts +64 -0
  251. package/src/core/objects/publication/changes/publication.create.test.ts +87 -0
  252. package/src/core/objects/publication/changes/publication.create.ts +82 -0
  253. package/src/core/objects/publication/changes/publication.drop.test.ts +46 -0
  254. package/src/core/objects/publication/changes/publication.drop.ts +29 -0
  255. package/src/core/objects/publication/changes/publication.types.ts +26 -0
  256. package/src/core/objects/publication/publication.diff.test.ts +292 -0
  257. package/src/core/objects/publication/publication.diff.ts +253 -0
  258. package/src/core/objects/publication/publication.model.ts +206 -0
  259. package/src/core/objects/publication/utils.ts +55 -0
  260. package/src/core/objects/rls-policy/changes/rls-policy.alter.test.ts +250 -0
  261. package/src/core/objects/rls-policy/changes/rls-policy.alter.ts +128 -0
  262. package/src/core/objects/rls-policy/changes/rls-policy.base.ts +20 -0
  263. package/src/core/objects/rls-policy/changes/rls-policy.comment.ts +69 -0
  264. package/src/core/objects/rls-policy/changes/rls-policy.create.test.ts +74 -0
  265. package/src/core/objects/rls-policy/changes/rls-policy.create.ts +100 -0
  266. package/src/core/objects/rls-policy/changes/rls-policy.drop.test.ts +28 -0
  267. package/src/core/objects/rls-policy/changes/rls-policy.drop.ts +39 -0
  268. package/src/core/objects/rls-policy/changes/rls-policy.types.ts +10 -0
  269. package/src/core/objects/rls-policy/rls-policy.diff.test.ts +79 -0
  270. package/src/core/objects/rls-policy/rls-policy.diff.ts +121 -0
  271. package/src/core/objects/rls-policy/rls-policy.model.ts +140 -0
  272. package/src/core/objects/role/changes/role.alter.test.ts +346 -0
  273. package/src/core/objects/role/changes/role.alter.ts +110 -0
  274. package/src/core/objects/role/changes/role.base.ts +24 -0
  275. package/src/core/objects/role/changes/role.comment.ts +55 -0
  276. package/src/core/objects/role/changes/role.create.test.ts +52 -0
  277. package/src/core/objects/role/changes/role.create.ts +102 -0
  278. package/src/core/objects/role/changes/role.drop.test.ts +29 -0
  279. package/src/core/objects/role/changes/role.drop.ts +34 -0
  280. package/src/core/objects/role/changes/role.privilege.ts +376 -0
  281. package/src/core/objects/role/changes/role.types.ts +12 -0
  282. package/src/core/objects/role/role.diff.test.ts +44 -0
  283. package/src/core/objects/role/role.diff.ts +479 -0
  284. package/src/core/objects/role/role.model.ts +344 -0
  285. package/src/core/objects/rule/changes/rule.alter.test.ts +78 -0
  286. package/src/core/objects/rule/changes/rule.alter.ts +72 -0
  287. package/src/core/objects/rule/changes/rule.base.ts +20 -0
  288. package/src/core/objects/rule/changes/rule.comment.test.ts +55 -0
  289. package/src/core/objects/rule/changes/rule.comment.ts +62 -0
  290. package/src/core/objects/rule/changes/rule.create.test.ts +59 -0
  291. package/src/core/objects/rule/changes/rule.create.ts +42 -0
  292. package/src/core/objects/rule/changes/rule.drop.test.ts +38 -0
  293. package/src/core/objects/rule/changes/rule.drop.ts +29 -0
  294. package/src/core/objects/rule/changes/rule.types.ts +12 -0
  295. package/src/core/objects/rule/rule.diff.test.ts +132 -0
  296. package/src/core/objects/rule/rule.diff.ts +79 -0
  297. package/src/core/objects/rule/rule.model.ts +173 -0
  298. package/src/core/objects/schema/changes/schema.alter.test.ts +28 -0
  299. package/src/core/objects/schema/changes/schema.alter.ts +45 -0
  300. package/src/core/objects/schema/changes/schema.base.ts +20 -0
  301. package/src/core/objects/schema/changes/schema.comment.ts +56 -0
  302. package/src/core/objects/schema/changes/schema.create.test.ts +22 -0
  303. package/src/core/objects/schema/changes/schema.create.ts +47 -0
  304. package/src/core/objects/schema/changes/schema.drop.test.ts +20 -0
  305. package/src/core/objects/schema/changes/schema.drop.ts +34 -0
  306. package/src/core/objects/schema/changes/schema.privilege.ts +175 -0
  307. package/src/core/objects/schema/changes/schema.types.ts +12 -0
  308. package/src/core/objects/schema/schema.diff.test.ts +42 -0
  309. package/src/core/objects/schema/schema.diff.ts +209 -0
  310. package/src/core/objects/schema/schema.model.ts +107 -0
  311. package/src/core/objects/sequence/changes/sequence.alter.test.ts +151 -0
  312. package/src/core/objects/sequence/changes/sequence.alter.ts +115 -0
  313. package/src/core/objects/sequence/changes/sequence.base.ts +20 -0
  314. package/src/core/objects/sequence/changes/sequence.comment.ts +60 -0
  315. package/src/core/objects/sequence/changes/sequence.create.test.ts +84 -0
  316. package/src/core/objects/sequence/changes/sequence.create.ts +111 -0
  317. package/src/core/objects/sequence/changes/sequence.drop.test.ts +32 -0
  318. package/src/core/objects/sequence/changes/sequence.drop.ts +37 -0
  319. package/src/core/objects/sequence/changes/sequence.privilege.ts +179 -0
  320. package/src/core/objects/sequence/changes/sequence.types.ts +12 -0
  321. package/src/core/objects/sequence/sequence.diff.test.ts +141 -0
  322. package/src/core/objects/sequence/sequence.diff.ts +359 -0
  323. package/src/core/objects/sequence/sequence.model.ts +185 -0
  324. package/src/core/objects/subscription/changes/subscription.alter.test.ts +124 -0
  325. package/src/core/objects/subscription/changes/subscription.alter.ts +110 -0
  326. package/src/core/objects/subscription/changes/subscription.base.ts +20 -0
  327. package/src/core/objects/subscription/changes/subscription.comment.test.ts +67 -0
  328. package/src/core/objects/subscription/changes/subscription.comment.ts +64 -0
  329. package/src/core/objects/subscription/changes/subscription.create.test.ts +77 -0
  330. package/src/core/objects/subscription/changes/subscription.create.ts +69 -0
  331. package/src/core/objects/subscription/changes/subscription.drop.test.ts +46 -0
  332. package/src/core/objects/subscription/changes/subscription.drop.ts +20 -0
  333. package/src/core/objects/subscription/changes/subscription.types.ts +22 -0
  334. package/src/core/objects/subscription/subscription.diff.test.ts +232 -0
  335. package/src/core/objects/subscription/subscription.diff.ts +241 -0
  336. package/src/core/objects/subscription/subscription.model.ts +190 -0
  337. package/src/core/objects/subscription/utils.ts +156 -0
  338. package/src/core/objects/table/changes/table.alter.test.ts +823 -0
  339. package/src/core/objects/table/changes/table.alter.ts +806 -0
  340. package/src/core/objects/table/changes/table.base.ts +20 -0
  341. package/src/core/objects/table/changes/table.comment.ts +266 -0
  342. package/src/core/objects/table/changes/table.create.test.ts +150 -0
  343. package/src/core/objects/table/changes/table.create.ts +188 -0
  344. package/src/core/objects/table/changes/table.drop.test.ts +34 -0
  345. package/src/core/objects/table/changes/table.drop.ts +45 -0
  346. package/src/core/objects/table/changes/table.privilege.ts +200 -0
  347. package/src/core/objects/table/changes/table.types.ts +12 -0
  348. package/src/core/objects/table/table.diff.test.ts +711 -0
  349. package/src/core/objects/table/table.diff.ts +953 -0
  350. package/src/core/objects/table/table.model.ts +460 -0
  351. package/src/core/objects/trigger/changes/trigger.alter.test.ts +46 -0
  352. package/src/core/objects/trigger/changes/trigger.alter.ts +76 -0
  353. package/src/core/objects/trigger/changes/trigger.base.ts +20 -0
  354. package/src/core/objects/trigger/changes/trigger.comment.ts +64 -0
  355. package/src/core/objects/trigger/changes/trigger.create.test.ts +43 -0
  356. package/src/core/objects/trigger/changes/trigger.create.ts +85 -0
  357. package/src/core/objects/trigger/changes/trigger.drop.test.ts +43 -0
  358. package/src/core/objects/trigger/changes/trigger.drop.ts +39 -0
  359. package/src/core/objects/trigger/changes/trigger.types.ts +10 -0
  360. package/src/core/objects/trigger/trigger.diff.test.ts +83 -0
  361. package/src/core/objects/trigger/trigger.diff.ts +116 -0
  362. package/src/core/objects/trigger/trigger.model.ts +252 -0
  363. package/src/core/objects/type/composite-type/changes/composite-type.alter.test.ts +202 -0
  364. package/src/core/objects/type/composite-type/changes/composite-type.alter.ts +174 -0
  365. package/src/core/objects/type/composite-type/changes/composite-type.base.ts +20 -0
  366. package/src/core/objects/type/composite-type/changes/composite-type.comment.ts +145 -0
  367. package/src/core/objects/type/composite-type/changes/composite-type.create.test.ts +101 -0
  368. package/src/core/objects/type/composite-type/changes/composite-type.create.ts +95 -0
  369. package/src/core/objects/type/composite-type/changes/composite-type.drop.test.ts +33 -0
  370. package/src/core/objects/type/composite-type/changes/composite-type.drop.ts +37 -0
  371. package/src/core/objects/type/composite-type/changes/composite-type.privilege.ts +175 -0
  372. package/src/core/objects/type/composite-type/changes/composite-type.types.ts +12 -0
  373. package/src/core/objects/type/composite-type/composite-type.diff.test.ts +191 -0
  374. package/src/core/objects/type/composite-type/composite-type.diff.ts +372 -0
  375. package/src/core/objects/type/composite-type/composite-type.model.ts +252 -0
  376. package/src/core/objects/type/enum/changes/enum.alter.test.ts +104 -0
  377. package/src/core/objects/type/enum/changes/enum.alter.ts +91 -0
  378. package/src/core/objects/type/enum/changes/enum.base.ts +20 -0
  379. package/src/core/objects/type/enum/changes/enum.comment.ts +64 -0
  380. package/src/core/objects/type/enum/changes/enum.create.test.ts +28 -0
  381. package/src/core/objects/type/enum/changes/enum.create.ts +56 -0
  382. package/src/core/objects/type/enum/changes/enum.drop.test.ts +25 -0
  383. package/src/core/objects/type/enum/changes/enum.drop.ts +34 -0
  384. package/src/core/objects/type/enum/changes/enum.privilege.ts +175 -0
  385. package/src/core/objects/type/enum/changes/enum.types.ts +12 -0
  386. package/src/core/objects/type/enum/enum.diff.test.ts +191 -0
  387. package/src/core/objects/type/enum/enum.diff.ts +396 -0
  388. package/src/core/objects/type/enum/enum.model.ts +194 -0
  389. package/src/core/objects/type/range/changes/range.alter.test.ts +27 -0
  390. package/src/core/objects/type/range/changes/range.alter.ts +51 -0
  391. package/src/core/objects/type/range/changes/range.base.ts +20 -0
  392. package/src/core/objects/type/range/changes/range.comment.ts +64 -0
  393. package/src/core/objects/type/range/changes/range.create.test.ts +51 -0
  394. package/src/core/objects/type/range/changes/range.create.ts +151 -0
  395. package/src/core/objects/type/range/changes/range.drop.test.ts +26 -0
  396. package/src/core/objects/type/range/changes/range.drop.ts +34 -0
  397. package/src/core/objects/type/range/changes/range.privilege.ts +175 -0
  398. package/src/core/objects/type/range/changes/range.types.ts +12 -0
  399. package/src/core/objects/type/range/range.diff.test.ts +70 -0
  400. package/src/core/objects/type/range/range.diff.ts +259 -0
  401. package/src/core/objects/type/range/range.model.ts +187 -0
  402. package/src/core/objects/type/type.types.ts +5 -0
  403. package/src/core/objects/utils.ts +171 -0
  404. package/src/core/objects/view/changes/view.alter.test.ts +110 -0
  405. package/src/core/objects/view/changes/view.alter.ts +112 -0
  406. package/src/core/objects/view/changes/view.base.ts +20 -0
  407. package/src/core/objects/view/changes/view.comment.ts +59 -0
  408. package/src/core/objects/view/changes/view.create.test.ts +65 -0
  409. package/src/core/objects/view/changes/view.create.ts +73 -0
  410. package/src/core/objects/view/changes/view.drop.test.ts +34 -0
  411. package/src/core/objects/view/changes/view.drop.ts +40 -0
  412. package/src/core/objects/view/changes/view.privilege.ts +200 -0
  413. package/src/core/objects/view/changes/view.types.ts +12 -0
  414. package/src/core/objects/view/view.diff.test.ts +91 -0
  415. package/src/core/objects/view/view.diff.ts +365 -0
  416. package/src/core/objects/view/view.model.ts +276 -0
  417. package/src/core/plan/apply.ts +190 -0
  418. package/src/core/plan/create.ts +432 -0
  419. package/src/core/plan/hierarchy.ts +574 -0
  420. package/src/core/plan/index.ts +29 -0
  421. package/src/core/plan/io.ts +20 -0
  422. package/src/core/plan/risk.ts +48 -0
  423. package/src/core/plan/serialize.ts +195 -0
  424. package/src/core/plan/sql-format/constants.ts +13 -0
  425. package/src/core/plan/sql-format/fixtures.ts +2806 -0
  426. package/src/core/plan/sql-format/format-comment-literals.test.ts +96 -0
  427. package/src/core/plan/sql-format/format-functions.test.ts +127 -0
  428. package/src/core/plan/sql-format/format-lowercase-coverage.test.ts +67 -0
  429. package/src/core/plan/sql-format/format-off.test.ts +809 -0
  430. package/src/core/plan/sql-format/format-pretty-lower-leading.test.ts +1056 -0
  431. package/src/core/plan/sql-format/format-pretty-narrow.test.ts +1283 -0
  432. package/src/core/plan/sql-format/format-pretty-preserve.test.ts +1052 -0
  433. package/src/core/plan/sql-format/format-pretty-upper.test.ts +1045 -0
  434. package/src/core/plan/sql-format/format-stress.test.ts +616 -0
  435. package/src/core/plan/sql-format/format-utils.test.ts +91 -0
  436. package/src/core/plan/sql-format/format-utils.ts +391 -0
  437. package/src/core/plan/sql-format/formatters.ts +921 -0
  438. package/src/core/plan/sql-format/index.ts +149 -0
  439. package/src/core/plan/sql-format/keyword-case.test.ts +118 -0
  440. package/src/core/plan/sql-format/keyword-case.ts +1085 -0
  441. package/src/core/plan/sql-format/protect.test.ts +127 -0
  442. package/src/core/plan/sql-format/protect.ts +337 -0
  443. package/src/core/plan/sql-format/sql-scanner.test.ts +240 -0
  444. package/src/core/plan/sql-format/sql-scanner.ts +252 -0
  445. package/src/core/plan/sql-format/tokenizer.test.ts +68 -0
  446. package/src/core/plan/sql-format/tokenizer.ts +152 -0
  447. package/src/core/plan/sql-format/types.ts +31 -0
  448. package/src/core/plan/sql-format/wrap.test.ts +119 -0
  449. package/src/core/plan/sql-format/wrap.ts +196 -0
  450. package/src/core/plan/sql-format.ts +2 -0
  451. package/src/core/plan/statements.ts +22 -0
  452. package/src/core/plan/types.ts +165 -0
  453. package/src/core/postgres-config.ts +169 -0
  454. package/src/core/sort/custom-constraints.ts +161 -0
  455. package/src/core/sort/debug-visualization.ts +239 -0
  456. package/src/core/sort/dependency-filter.ts +224 -0
  457. package/src/core/sort/graph-builder.ts +223 -0
  458. package/src/core/sort/graph-utils.ts +51 -0
  459. package/src/core/sort/logical-sort.ts +590 -0
  460. package/src/core/sort/sort-changes.ts +234 -0
  461. package/src/core/sort/topological-sort.ts +184 -0
  462. package/src/core/sort/types.ts +112 -0
  463. package/src/core/sort/utils.ts +69 -0
  464. package/src/index.ts +14 -0
@@ -0,0 +1,42 @@
1
+ import { stableId } from "../../utils.ts";
2
+ import type { Rule } from "../rule.model.ts";
3
+ import { CreateRuleChange } from "./rule.base.ts";
4
+
5
+ export class CreateRule extends CreateRuleChange {
6
+ public readonly rule: Rule;
7
+ public readonly scope = "object" as const;
8
+ public readonly orReplace?: boolean;
9
+
10
+ constructor(props: { rule: Rule; orReplace?: boolean }) {
11
+ super();
12
+ this.rule = props.rule;
13
+ this.orReplace = props.orReplace;
14
+ }
15
+
16
+ get creates() {
17
+ return [this.rule.stableId];
18
+ }
19
+
20
+ get requires() {
21
+ return [
22
+ this.rule.relationStableId,
23
+ ...this.rule.columns.map((column) =>
24
+ stableId.column(this.rule.schema, this.rule.table_name, column),
25
+ ),
26
+ ];
27
+ }
28
+
29
+ serialize(): string {
30
+ let definition = this.rule.definition.trim();
31
+
32
+ definition = definition.replace(
33
+ /^CREATE\s+(?:OR\s+REPLACE\s+)?/i,
34
+ `CREATE ${this.orReplace ? "OR REPLACE " : ""}`,
35
+ );
36
+
37
+ // Remove trailing semicolons (pg_get_ruledef includes them, but we add our own)
38
+ definition = definition.replace(/;+\s*$/, "");
39
+
40
+ return definition;
41
+ }
42
+ }
@@ -0,0 +1,38 @@
1
+ import { describe, expect, test } from "bun:test";
2
+ import { Rule } from "../rule.model.ts";
3
+ import { DropRule } from "./rule.drop.ts";
4
+
5
+ type RuleProps = ConstructorParameters<typeof Rule>[0];
6
+
7
+ const base: RuleProps = {
8
+ schema: "public",
9
+ name: '"my_rule"',
10
+ table_name: '"my_table"',
11
+ relation_kind: "r",
12
+ event: "INSERT",
13
+ enabled: "O",
14
+ is_instead: true,
15
+ owner: "owner1",
16
+ definition:
17
+ 'CREATE RULE "my_rule" AS ON INSERT TO public."my_table" DO INSTEAD NOTHING',
18
+ comment: null,
19
+ columns: ["id"],
20
+ };
21
+
22
+ const makeRule = (override: Partial<RuleProps> = {}) =>
23
+ new Rule({
24
+ ...base,
25
+ ...override,
26
+ columns: override.columns ? [...override.columns] : [...base.columns],
27
+ });
28
+
29
+ describe("rule.drop", () => {
30
+ test("serialize rule drop and track dependencies", () => {
31
+ const rule = makeRule();
32
+ const change = new DropRule({ rule });
33
+
34
+ expect(change.drops).toEqual([rule.stableId]);
35
+ expect(change.requires).toEqual([rule.stableId, rule.relationStableId]);
36
+ expect(change.serialize()).toBe('DROP RULE "my_rule" ON public."my_table"');
37
+ });
38
+ });
@@ -0,0 +1,29 @@
1
+ import type { Rule } from "../rule.model.ts";
2
+ import { DropRuleChange } from "./rule.base.ts";
3
+
4
+ export class DropRule extends DropRuleChange {
5
+ public readonly rule: Rule;
6
+ public readonly scope = "object" as const;
7
+
8
+ constructor(props: { rule: Rule }) {
9
+ super();
10
+ this.rule = props.rule;
11
+ }
12
+
13
+ get drops() {
14
+ return [this.rule.stableId];
15
+ }
16
+
17
+ get requires() {
18
+ return [this.rule.stableId, this.rule.relationStableId];
19
+ }
20
+
21
+ serialize(): string {
22
+ return [
23
+ "DROP RULE",
24
+ this.rule.name,
25
+ "ON",
26
+ `${this.rule.schema}.${this.rule.table_name}`,
27
+ ].join(" ");
28
+ }
29
+ }
@@ -0,0 +1,12 @@
1
+ import type { ReplaceRule, SetRuleEnabledState } from "./rule.alter.ts";
2
+ import type { CreateCommentOnRule, DropCommentOnRule } from "./rule.comment.ts";
3
+ import type { CreateRule } from "./rule.create.ts";
4
+ import type { DropRule } from "./rule.drop.ts";
5
+
6
+ export type RuleChange =
7
+ | CreateRule
8
+ | DropRule
9
+ | ReplaceRule
10
+ | SetRuleEnabledState
11
+ | CreateCommentOnRule
12
+ | DropCommentOnRule;
@@ -0,0 +1,132 @@
1
+ import { describe, expect, test } from "bun:test";
2
+ import { ReplaceRule, SetRuleEnabledState } from "./changes/rule.alter.ts";
3
+ import {
4
+ CreateCommentOnRule,
5
+ DropCommentOnRule,
6
+ } from "./changes/rule.comment.ts";
7
+ import { CreateRule } from "./changes/rule.create.ts";
8
+ import { DropRule } from "./changes/rule.drop.ts";
9
+ import { diffRules } from "./rule.diff.ts";
10
+ import { Rule, type RuleProps } from "./rule.model.ts";
11
+
12
+ const baseRule: RuleProps = {
13
+ schema: "public",
14
+ name: '"my_rule"',
15
+ table_name: '"my_table"',
16
+ relation_kind: "r",
17
+ event: "INSERT",
18
+ enabled: "O",
19
+ is_instead: true,
20
+ definition:
21
+ 'CREATE RULE "my_rule" AS ON INSERT TO public."my_table" DO INSTEAD NOTHING',
22
+ comment: null,
23
+ columns: ["id"],
24
+ owner: "o1",
25
+ };
26
+
27
+ describe.concurrent("rule.diff", () => {
28
+ test("create rule", () => {
29
+ const rule = new Rule(baseRule);
30
+ const changes = diffRules({}, { [rule.stableId]: rule });
31
+ expect(changes[0]).toBeInstanceOf(CreateRule);
32
+ });
33
+
34
+ test("drop rule", () => {
35
+ const rule = new Rule(baseRule);
36
+ const changes = diffRules({ [rule.stableId]: rule }, {});
37
+ expect(changes[0]).toBeInstanceOf(DropRule);
38
+ });
39
+
40
+ test("replace when definition changes", () => {
41
+ const main = new Rule(baseRule);
42
+ const branch = new Rule({
43
+ ...baseRule,
44
+ definition:
45
+ 'CREATE RULE "my_rule" AS ON INSERT TO public."my_table" DO ALSO NOTHING',
46
+ is_instead: false,
47
+ columns: ["id", "amount"],
48
+ });
49
+ const changes = diffRules(
50
+ { [main.stableId]: main },
51
+ { [branch.stableId]: branch },
52
+ );
53
+ expect(changes.some((change) => change instanceof ReplaceRule)).toBe(true);
54
+ });
55
+
56
+ test("handle comment changes", () => {
57
+ const main = new Rule({ ...baseRule, comment: "old comment" });
58
+ const branch = new Rule({ ...baseRule, comment: "new comment" });
59
+ const changes = diffRules(
60
+ { [main.stableId]: main },
61
+ { [branch.stableId]: branch },
62
+ );
63
+ expect(
64
+ changes.some((change) => change instanceof CreateCommentOnRule),
65
+ ).toBe(true);
66
+ expect(changes.some((change) => change instanceof DropCommentOnRule)).toBe(
67
+ false,
68
+ );
69
+ });
70
+
71
+ test("handle comment removal", () => {
72
+ const main = new Rule({ ...baseRule, comment: "old comment" });
73
+ const branch = new Rule(baseRule);
74
+ const changes = diffRules(
75
+ { [main.stableId]: main },
76
+ { [branch.stableId]: branch },
77
+ );
78
+ expect(changes[0]).toBeInstanceOf(DropCommentOnRule);
79
+ });
80
+
81
+ test("handle enabled state changes", () => {
82
+ const main = new Rule(baseRule);
83
+ const branch = new Rule({ ...baseRule, enabled: "D" });
84
+ const changes = diffRules(
85
+ { [main.stableId]: main },
86
+ { [branch.stableId]: branch },
87
+ );
88
+ expect(
89
+ changes.some((change) => change instanceof SetRuleEnabledState),
90
+ ).toBe(true);
91
+ });
92
+
93
+ test("reapply comment when replacing rule", () => {
94
+ const main = new Rule({ ...baseRule, comment: "my comment" });
95
+ const branch = new Rule({
96
+ ...baseRule,
97
+ definition:
98
+ 'CREATE RULE "my_rule" AS ON INSERT TO public."my_table" DO ALSO NOTHING',
99
+ is_instead: false,
100
+ comment: "my comment",
101
+ columns: ["id", "balance"],
102
+ });
103
+ const changes = diffRules(
104
+ { [main.stableId]: main },
105
+ { [branch.stableId]: branch },
106
+ );
107
+ expect(changes.some((change) => change instanceof ReplaceRule)).toBe(true);
108
+ expect(
109
+ changes.some((change) => change instanceof CreateCommentOnRule),
110
+ ).toBe(true);
111
+ });
112
+
113
+ test("reapply enabled state when replacing rule", () => {
114
+ const main = new Rule({ ...baseRule, enabled: "D" });
115
+ const branch = new Rule({
116
+ ...baseRule,
117
+ definition:
118
+ 'CREATE RULE "my_rule" AS ON INSERT TO public."my_table" DO ALSO NOTHING',
119
+ is_instead: false,
120
+ enabled: "D",
121
+ columns: ["id", "balance"],
122
+ });
123
+ const changes = diffRules(
124
+ { [main.stableId]: main },
125
+ { [branch.stableId]: branch },
126
+ );
127
+ expect(changes.some((change) => change instanceof ReplaceRule)).toBe(true);
128
+ expect(
129
+ changes.some((change) => change instanceof SetRuleEnabledState),
130
+ ).toBe(true);
131
+ });
132
+ });
@@ -0,0 +1,79 @@
1
+ import { diffObjects } from "../base.diff.ts";
2
+ import { deepEqual, hasNonAlterableChanges } from "../utils.ts";
3
+ import { ReplaceRule, SetRuleEnabledState } from "./changes/rule.alter.ts";
4
+ import {
5
+ CreateCommentOnRule,
6
+ DropCommentOnRule,
7
+ } from "./changes/rule.comment.ts";
8
+ import { CreateRule } from "./changes/rule.create.ts";
9
+ import { DropRule } from "./changes/rule.drop.ts";
10
+ import type { RuleChange } from "./changes/rule.types.ts";
11
+ import type { Rule } from "./rule.model.ts";
12
+
13
+ export function diffRules(
14
+ main: Record<string, Rule>,
15
+ branch: Record<string, Rule>,
16
+ ): RuleChange[] {
17
+ const { created, dropped, altered } = diffObjects(main, branch);
18
+ const changes: RuleChange[] = [];
19
+
20
+ for (const id of created) {
21
+ const rule = branch[id];
22
+ changes.push(new CreateRule({ rule }));
23
+
24
+ if (rule.comment !== null) {
25
+ changes.push(new CreateCommentOnRule({ rule }));
26
+ }
27
+
28
+ if (rule.enabled !== "O") {
29
+ changes.push(new SetRuleEnabledState({ rule }));
30
+ }
31
+ }
32
+
33
+ for (const id of dropped) {
34
+ changes.push(new DropRule({ rule: main[id] }));
35
+ }
36
+
37
+ for (const id of altered) {
38
+ const mainRule = main[id];
39
+ const branchRule = branch[id];
40
+
41
+ const NON_ALTERABLE_FIELDS: Array<keyof Rule> = [
42
+ "definition",
43
+ "event",
44
+ "is_instead",
45
+ ];
46
+
47
+ const shouldReplace = hasNonAlterableChanges(
48
+ mainRule,
49
+ branchRule,
50
+ NON_ALTERABLE_FIELDS,
51
+ { columns: deepEqual },
52
+ );
53
+
54
+ const replaced = shouldReplace;
55
+
56
+ if (shouldReplace) {
57
+ changes.push(new ReplaceRule({ rule: branchRule }));
58
+ }
59
+
60
+ if (mainRule.comment !== branchRule.comment) {
61
+ if (branchRule.comment === null) {
62
+ changes.push(new DropCommentOnRule({ rule: mainRule }));
63
+ } else {
64
+ changes.push(new CreateCommentOnRule({ rule: branchRule }));
65
+ }
66
+ } else if (replaced && branchRule.comment !== null) {
67
+ changes.push(new CreateCommentOnRule({ rule: branchRule }));
68
+ }
69
+
70
+ if (
71
+ mainRule.enabled !== branchRule.enabled ||
72
+ (replaced && branchRule.enabled !== "O")
73
+ ) {
74
+ changes.push(new SetRuleEnabledState({ rule: branchRule }));
75
+ }
76
+ }
77
+
78
+ return changes;
79
+ }
@@ -0,0 +1,173 @@
1
+ import { sql } from "@ts-safeql/sql-tag";
2
+ import type { Pool } from "pg";
3
+ import z from "zod";
4
+ import { BasePgModel } from "../base.model.ts";
5
+ import { stableId } from "../utils.ts";
6
+
7
+ const RuleEventSchema = z.enum(["SELECT", "INSERT", "UPDATE", "DELETE"]);
8
+ const RuleEnabledStateSchema = z.enum(["O", "D", "R", "A"]);
9
+
10
+ const RuleRelationKindSchema = z.enum([
11
+ "r", // ordinary table
12
+ "p", // partitioned table
13
+ "f", // foreign table
14
+ "v", // view
15
+ "m", // materialized view
16
+ ]);
17
+
18
+ const rulePropsSchema = z.object({
19
+ schema: z.string(),
20
+ name: z.string(),
21
+ table_name: z.string(),
22
+ relation_kind: RuleRelationKindSchema,
23
+ event: RuleEventSchema,
24
+ enabled: RuleEnabledStateSchema,
25
+ is_instead: z.boolean(),
26
+ owner: z.string(),
27
+ definition: z.string(),
28
+ comment: z.string().nullable(),
29
+ columns: z.array(z.string()),
30
+ });
31
+
32
+ export type RuleEnabledState = z.infer<typeof RuleEnabledStateSchema>;
33
+ export type RuleProps = z.infer<typeof rulePropsSchema>;
34
+
35
+ export class Rule extends BasePgModel {
36
+ public readonly schema: RuleProps["schema"];
37
+ public readonly name: RuleProps["name"];
38
+ public readonly table_name: RuleProps["table_name"];
39
+ public readonly relation_kind: RuleProps["relation_kind"];
40
+ public readonly event: RuleProps["event"];
41
+ public readonly enabled: RuleProps["enabled"];
42
+ public readonly is_instead: RuleProps["is_instead"];
43
+ public readonly owner: RuleProps["owner"];
44
+ public readonly definition: RuleProps["definition"];
45
+ public readonly comment: RuleProps["comment"];
46
+ public readonly columns: RuleProps["columns"];
47
+
48
+ constructor(props: RuleProps) {
49
+ super();
50
+
51
+ this.schema = props.schema;
52
+ this.name = props.name;
53
+ this.table_name = props.table_name;
54
+ this.relation_kind = props.relation_kind;
55
+ this.event = props.event;
56
+ this.enabled = props.enabled;
57
+ this.is_instead = props.is_instead;
58
+ this.owner = props.owner;
59
+ this.definition = props.definition;
60
+ this.comment = props.comment;
61
+ this.columns = props.columns;
62
+ }
63
+
64
+ get stableId(): `rule:${string}` {
65
+ return `rule:${this.schema}.${this.table_name}.${this.name}`;
66
+ }
67
+
68
+ get identityFields() {
69
+ return {
70
+ schema: this.schema,
71
+ name: this.name,
72
+ table_name: this.table_name,
73
+ };
74
+ }
75
+
76
+ get dataFields() {
77
+ return {
78
+ event: this.event,
79
+ enabled: this.enabled,
80
+ is_instead: this.is_instead,
81
+ owner: this.owner,
82
+ definition: this.definition,
83
+ comment: this.comment,
84
+ columns: this.columns,
85
+ };
86
+ }
87
+
88
+ get relationStableId(): string {
89
+ switch (this.relation_kind) {
90
+ case "v":
91
+ return stableId.view(this.schema, this.table_name);
92
+ case "m":
93
+ return stableId.materializedView(this.schema, this.table_name);
94
+ default:
95
+ return stableId.table(this.schema, this.table_name);
96
+ }
97
+ }
98
+ }
99
+
100
+ export async function extractRules(pool: Pool): Promise<Rule[]> {
101
+ const { rows: ruleRows } = await pool.query<RuleProps>(sql`
102
+ WITH extension_rule_oids AS (
103
+ SELECT
104
+ objid
105
+ FROM
106
+ pg_depend d
107
+ WHERE
108
+ d.refclassid = 'pg_extension'::regclass
109
+ AND d.classid = 'pg_rewrite'::regclass
110
+ ),
111
+ extension_relation_oids AS (
112
+ SELECT
113
+ objid
114
+ FROM
115
+ pg_depend d
116
+ WHERE
117
+ d.refclassid = 'pg_extension'::regclass
118
+ AND d.classid = 'pg_class'::regclass
119
+ AND d.deptype = 'e'
120
+ )
121
+ SELECT
122
+ c.relnamespace::regnamespace::text AS schema,
123
+ quote_ident(r.rulename) AS name,
124
+ quote_ident(c.relname) AS table_name,
125
+ c.relkind AS relation_kind,
126
+ CASE r.ev_type
127
+ WHEN '1' THEN 'SELECT'
128
+ WHEN '2' THEN 'UPDATE'
129
+ WHEN '3' THEN 'INSERT'
130
+ WHEN '4' THEN 'DELETE'
131
+ ELSE NULL
132
+ END AS event,
133
+ r.ev_enabled AS enabled,
134
+ r.is_instead,
135
+ c.relowner::regrole::text AS owner,
136
+ pg_get_ruledef(r.oid, true) AS definition,
137
+ obj_description(r.oid, 'pg_rewrite') AS comment,
138
+ COALESCE(
139
+ (
140
+ SELECT json_agg(quote_ident(att.attname) ORDER BY dep.refobjsubid)
141
+ FROM pg_depend dep
142
+ JOIN pg_attribute att
143
+ ON att.attrelid = dep.refobjid
144
+ AND att.attnum = dep.refobjsubid
145
+ AND att.attnum > 0
146
+ AND NOT att.attisdropped
147
+ WHERE dep.classid = 'pg_rewrite'::regclass
148
+ AND dep.objid = r.oid
149
+ AND dep.refclassid = 'pg_class'::regclass
150
+ AND dep.refobjid = c.oid
151
+ AND dep.refobjsubid > 0
152
+ ), '[]'
153
+ ) AS columns
154
+ FROM
155
+ pg_catalog.pg_rewrite r
156
+ JOIN pg_catalog.pg_class c ON c.oid = r.ev_class
157
+ LEFT JOIN extension_rule_oids e_rule ON r.oid = e_rule.objid
158
+ LEFT JOIN extension_relation_oids e_rel ON c.oid = e_rel.objid
159
+ WHERE
160
+ NOT c.relnamespace::regnamespace::text LIKE ANY (ARRAY['pg\\_%', 'information\\_schema'])
161
+ AND e_rule.objid IS NULL
162
+ AND e_rel.objid IS NULL
163
+ AND r.rulename <> '_RETURN'
164
+ ORDER BY
165
+ 1, 3, 2
166
+ `);
167
+
168
+ const validatedRows = ruleRows.map((row: unknown) =>
169
+ rulePropsSchema.parse(row),
170
+ );
171
+
172
+ return validatedRows.map((row) => new Rule(row));
173
+ }
@@ -0,0 +1,28 @@
1
+ import { describe, expect, test } from "bun:test";
2
+ import { Schema, type SchemaProps } from "../schema.model.ts";
3
+ import { AlterSchemaChangeOwner } from "./schema.alter.ts";
4
+
5
+ describe.concurrent("schema", () => {
6
+ describe("alter", () => {
7
+ test("change owner", () => {
8
+ const props: Omit<SchemaProps, "owner"> = {
9
+ name: "test_schema",
10
+ comment: null,
11
+ privileges: [],
12
+ };
13
+ const schemaObj = new Schema({
14
+ ...props,
15
+ owner: "old_owner",
16
+ });
17
+
18
+ const change = new AlterSchemaChangeOwner({
19
+ schema: schemaObj,
20
+ owner: "new_owner",
21
+ });
22
+
23
+ expect(change.serialize()).toBe(
24
+ "ALTER SCHEMA test_schema OWNER TO new_owner",
25
+ );
26
+ });
27
+ });
28
+ });
@@ -0,0 +1,45 @@
1
+ import type { Schema } from "../schema.model.ts";
2
+ import { AlterSchemaChange } from "./schema.base.ts";
3
+
4
+ /**
5
+ * Alter a schema.
6
+ *
7
+ * @see https://www.postgresql.org/docs/17/sql-alterschema.html
8
+ *
9
+ * Synopsis
10
+ * ```sql
11
+ * ALTER SCHEMA name RENAME TO new_name
12
+ * ALTER SCHEMA name OWNER TO { new_owner | CURRENT_ROLE | CURRENT_USER | SESSION_USER }
13
+ * ```
14
+ */
15
+
16
+ export type AlterSchema = AlterSchemaChangeOwner;
17
+
18
+ /**
19
+ * ALTER SCHEMA ... OWNER TO ...
20
+ */
21
+ export class AlterSchemaChangeOwner extends AlterSchemaChange {
22
+ public readonly schema: Schema;
23
+ public readonly owner: string;
24
+ public readonly scope = "object" as const;
25
+
26
+ constructor(props: { schema: Schema; owner: string }) {
27
+ super();
28
+ this.schema = props.schema;
29
+ this.owner = props.owner;
30
+ }
31
+
32
+ get requires() {
33
+ return [this.schema.stableId];
34
+ }
35
+
36
+ serialize(): string {
37
+ return ["ALTER SCHEMA", this.schema.name, "OWNER TO", this.owner].join(" ");
38
+ }
39
+ }
40
+
41
+ /**
42
+ * Replace a schema by dropping and recreating it.
43
+ * This is used when properties that cannot be altered via ALTER SCHEMA change.
44
+ */
45
+ // NOTE: ReplaceSchema removed. Non-alterable changes would be emitted via Drop + Create in schema.diff.ts if needed.
@@ -0,0 +1,20 @@
1
+ import { BaseChange } from "../../base.change.ts";
2
+ import type { Schema } from "../schema.model.ts";
3
+
4
+ abstract class BaseSchemaChange extends BaseChange {
5
+ abstract readonly schema: Schema;
6
+ abstract readonly scope: "object" | "comment" | "privilege";
7
+ readonly objectType: "schema" = "schema";
8
+ }
9
+
10
+ export abstract class CreateSchemaChange extends BaseSchemaChange {
11
+ readonly operation = "create" as const;
12
+ }
13
+
14
+ export abstract class AlterSchemaChange extends BaseSchemaChange {
15
+ readonly operation = "alter" as const;
16
+ }
17
+
18
+ export abstract class DropSchemaChange extends BaseSchemaChange {
19
+ readonly operation = "drop" as const;
20
+ }
@@ -0,0 +1,56 @@
1
+ import { quoteLiteral } from "../../base.change.ts";
2
+ import { stableId } from "../../utils.ts";
3
+ import type { Schema } from "../schema.model.ts";
4
+ import { CreateSchemaChange, DropSchemaChange } from "./schema.base.ts";
5
+
6
+ export type CommentSchema = CreateCommentOnSchema | DropCommentOnSchema;
7
+
8
+ export class CreateCommentOnSchema extends CreateSchemaChange {
9
+ public readonly schema: Schema;
10
+ public readonly scope = "comment" as const;
11
+
12
+ constructor(props: { schema: Schema }) {
13
+ super();
14
+ this.schema = props.schema;
15
+ }
16
+
17
+ get creates() {
18
+ return [stableId.comment(this.schema.stableId)];
19
+ }
20
+
21
+ get requires() {
22
+ return [this.schema.stableId];
23
+ }
24
+
25
+ serialize(): string {
26
+ return [
27
+ "COMMENT ON SCHEMA",
28
+ this.schema.name,
29
+ "IS",
30
+ // biome-ignore lint/style/noNonNullAssertion: schema comment is not nullable in this case
31
+ quoteLiteral(this.schema.comment!),
32
+ ].join(" ");
33
+ }
34
+ }
35
+
36
+ export class DropCommentOnSchema extends DropSchemaChange {
37
+ public readonly schema: Schema;
38
+ public readonly scope = "comment" as const;
39
+
40
+ constructor(props: { schema: Schema }) {
41
+ super();
42
+ this.schema = props.schema;
43
+ }
44
+
45
+ get drops() {
46
+ return [stableId.comment(this.schema.stableId)];
47
+ }
48
+
49
+ get requires() {
50
+ return [stableId.comment(this.schema.stableId), this.schema.stableId];
51
+ }
52
+
53
+ serialize(): string {
54
+ return ["COMMENT ON SCHEMA", this.schema.name, "IS NULL"].join(" ");
55
+ }
56
+ }
@@ -0,0 +1,22 @@
1
+ import { describe, expect, test } from "bun:test";
2
+ import { Schema } from "../schema.model.ts";
3
+ import { CreateSchema } from "./schema.create.ts";
4
+
5
+ describe("schema", () => {
6
+ test("create", () => {
7
+ const schema = new Schema({
8
+ name: "test_schema",
9
+ owner: "test",
10
+ comment: null,
11
+ privileges: [],
12
+ });
13
+
14
+ const change = new CreateSchema({
15
+ schema,
16
+ });
17
+
18
+ expect(change.serialize()).toBe(
19
+ "CREATE SCHEMA test_schema AUTHORIZATION test",
20
+ );
21
+ });
22
+ });