@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,372 @@
1
+ import type { DefaultPrivilegeState } from "../../base.default-privileges.ts";
2
+ import { diffObjects } from "../../base.diff.ts";
3
+ import {
4
+ diffPrivileges,
5
+ filterPublicBuiltInDefaults,
6
+ groupPrivilegesByGrantable,
7
+ } from "../../base.privilege-diff.ts";
8
+ import type { Role } from "../../role/role.model.ts";
9
+ import { deepEqual, hasNonAlterableChanges } from "../../utils.ts";
10
+ import {
11
+ AlterCompositeTypeAddAttribute,
12
+ AlterCompositeTypeAlterAttributeType,
13
+ AlterCompositeTypeChangeOwner,
14
+ AlterCompositeTypeDropAttribute,
15
+ } from "./changes/composite-type.alter.ts";
16
+ import {
17
+ CreateCommentOnCompositeType,
18
+ CreateCommentOnCompositeTypeAttribute,
19
+ DropCommentOnCompositeType,
20
+ DropCommentOnCompositeTypeAttribute,
21
+ } from "./changes/composite-type.comment.ts";
22
+ import { CreateCompositeType } from "./changes/composite-type.create.ts";
23
+ import { DropCompositeType } from "./changes/composite-type.drop.ts";
24
+ import {
25
+ GrantCompositeTypePrivileges,
26
+ RevokeCompositeTypePrivileges,
27
+ RevokeGrantOptionCompositeTypePrivileges,
28
+ } from "./changes/composite-type.privilege.ts";
29
+ import type { CompositeTypeChange } from "./changes/composite-type.types.ts";
30
+ import type { CompositeType } from "./composite-type.model.ts";
31
+
32
+ /**
33
+ * Diff two sets of composite types from main and branch catalogs.
34
+ *
35
+ * @param ctx - Context containing version, currentUser, and defaultPrivilegeState
36
+ * @param main - The composite types in the main catalog.
37
+ * @param branch - The composite types in the branch catalog.
38
+ * @returns A list of changes to apply to main to make it match branch.
39
+ */
40
+ export function diffCompositeTypes(
41
+ ctx: {
42
+ version: number;
43
+ currentUser: string;
44
+ defaultPrivilegeState: DefaultPrivilegeState;
45
+ mainRoles: Record<string, Role>;
46
+ },
47
+ main: Record<string, CompositeType>,
48
+ branch: Record<string, CompositeType>,
49
+ ): CompositeTypeChange[] {
50
+ const { created, dropped, altered } = diffObjects(main, branch);
51
+
52
+ const changes: CompositeTypeChange[] = [];
53
+
54
+ for (const compositeTypeId of created) {
55
+ const ct = branch[compositeTypeId];
56
+ changes.push(new CreateCompositeType({ compositeType: ct }));
57
+
58
+ // OWNER: If the composite type should be owned by someone other than the current user,
59
+ // emit ALTER TYPE ... OWNER TO after creation
60
+ if (ct.owner !== ctx.currentUser) {
61
+ changes.push(
62
+ new AlterCompositeTypeChangeOwner({
63
+ compositeType: ct,
64
+ owner: ct.owner,
65
+ }),
66
+ );
67
+ }
68
+
69
+ // Type comment on creation
70
+ if (ct.comment !== null) {
71
+ changes.push(new CreateCommentOnCompositeType({ compositeType: ct }));
72
+ }
73
+ // Attribute comments on creation
74
+ for (const attr of ct.columns) {
75
+ if (attr.comment !== null) {
76
+ changes.push(
77
+ new CreateCommentOnCompositeTypeAttribute({
78
+ compositeType: ct,
79
+ attribute: attr,
80
+ }),
81
+ );
82
+ }
83
+ }
84
+
85
+ // PRIVILEGES: For created objects, compare against default privileges state
86
+ // The migration script will run ALTER DEFAULT PRIVILEGES before CREATE (via constraint spec),
87
+ // so objects are created with the default privileges state in effect.
88
+ // We compare default privileges against desired privileges to generate REVOKE/GRANT statements
89
+ // needed to reach the final desired state.
90
+ const effectiveDefaults = ctx.defaultPrivilegeState.getEffectiveDefaults(
91
+ ctx.currentUser,
92
+ "composite_type",
93
+ ct.schema ?? "",
94
+ );
95
+ // Filter out PUBLIC's built-in default USAGE privilege (PostgreSQL grants it automatically)
96
+ // Reference: https://www.postgresql.org/docs/17/ddl-priv.html Table 5.2
97
+ // This prevents generating unnecessary "GRANT USAGE TO PUBLIC" statements
98
+ const desiredPrivileges = filterPublicBuiltInDefaults(
99
+ "composite_type",
100
+ ct.privileges,
101
+ );
102
+ // Filter out owner privileges - owner always has ALL privileges implicitly
103
+ // and shouldn't be compared. Use the composite type owner as the reference.
104
+ const privilegeResults = diffPrivileges(
105
+ effectiveDefaults,
106
+ desiredPrivileges,
107
+ ct.owner,
108
+ );
109
+
110
+ // Generate grant changes
111
+ for (const [grantee, result] of privilegeResults) {
112
+ if (result.grants.length > 0) {
113
+ const grantGroups = groupPrivilegesByGrantable(result.grants);
114
+ for (const [grantable, list] of grantGroups) {
115
+ void grantable;
116
+ changes.push(
117
+ new GrantCompositeTypePrivileges({
118
+ compositeType: ct,
119
+ grantee,
120
+ privileges: list,
121
+ version: ctx.version,
122
+ }),
123
+ );
124
+ }
125
+ }
126
+
127
+ // Generate revoke changes
128
+ if (result.revokes.length > 0) {
129
+ const revokeGroups = groupPrivilegesByGrantable(result.revokes);
130
+ for (const [grantable, list] of revokeGroups) {
131
+ void grantable;
132
+ changes.push(
133
+ new RevokeCompositeTypePrivileges({
134
+ compositeType: ct,
135
+ grantee,
136
+ privileges: list,
137
+ version: ctx.version,
138
+ }),
139
+ );
140
+ }
141
+ }
142
+
143
+ // Generate revoke grant option changes
144
+ if (result.revokeGrantOption.length > 0) {
145
+ changes.push(
146
+ new RevokeGrantOptionCompositeTypePrivileges({
147
+ compositeType: ct,
148
+ grantee,
149
+ privilegeNames: result.revokeGrantOption,
150
+ version: ctx.version,
151
+ }),
152
+ );
153
+ }
154
+ }
155
+ }
156
+
157
+ for (const compositeTypeId of dropped) {
158
+ changes.push(
159
+ new DropCompositeType({ compositeType: main[compositeTypeId] }),
160
+ );
161
+ }
162
+
163
+ for (const compositeTypeId of altered) {
164
+ const mainCompositeType = main[compositeTypeId];
165
+ const branchCompositeType = branch[compositeTypeId];
166
+
167
+ // Check if non-alterable properties have changed
168
+ // These require dropping and recreating the composite type
169
+ const NON_ALTERABLE_FIELDS: Array<keyof CompositeType> = [
170
+ "row_security",
171
+ "force_row_security",
172
+ "has_indexes",
173
+ "has_rules",
174
+ "has_triggers",
175
+ "has_subclasses",
176
+ "is_populated",
177
+ "replica_identity",
178
+ "is_partition",
179
+ "options",
180
+ "partition_bound",
181
+ ];
182
+ const nonAlterablePropsChanged = hasNonAlterableChanges(
183
+ mainCompositeType,
184
+ branchCompositeType,
185
+ NON_ALTERABLE_FIELDS,
186
+ { options: deepEqual },
187
+ );
188
+
189
+ if (nonAlterablePropsChanged) {
190
+ // Replacement is not performed automatically for composite types
191
+ // to avoid destructive operations; keep changes minimal.
192
+ } else {
193
+ // Only alterable properties changed - check each one
194
+
195
+ // OWNER
196
+ if (mainCompositeType.owner !== branchCompositeType.owner) {
197
+ changes.push(
198
+ new AlterCompositeTypeChangeOwner({
199
+ compositeType: mainCompositeType,
200
+ owner: branchCompositeType.owner,
201
+ }),
202
+ );
203
+ }
204
+
205
+ // TYPE COMMENT (create/drop when comment changes)
206
+ if (mainCompositeType.comment !== branchCompositeType.comment) {
207
+ if (branchCompositeType.comment === null) {
208
+ changes.push(
209
+ new DropCommentOnCompositeType({
210
+ compositeType: mainCompositeType,
211
+ }),
212
+ );
213
+ } else {
214
+ changes.push(
215
+ new CreateCommentOnCompositeType({
216
+ compositeType: branchCompositeType,
217
+ }),
218
+ );
219
+ }
220
+ }
221
+
222
+ // ATTRIBUTE diffs
223
+ const mainAttrs = new Map(
224
+ mainCompositeType.columns.map((c) => [c.name, c]),
225
+ );
226
+ const branchAttrs = new Map(
227
+ branchCompositeType.columns.map((c) => [c.name, c]),
228
+ );
229
+
230
+ // Added attributes
231
+ for (const [name, attr] of branchAttrs) {
232
+ if (!mainAttrs.has(name)) {
233
+ changes.push(
234
+ new AlterCompositeTypeAddAttribute({
235
+ compositeType: branchCompositeType,
236
+ attribute: attr,
237
+ }),
238
+ );
239
+ if (attr.comment !== null) {
240
+ changes.push(
241
+ new CreateCommentOnCompositeTypeAttribute({
242
+ compositeType: branchCompositeType,
243
+ attribute: attr,
244
+ }),
245
+ );
246
+ }
247
+ }
248
+ }
249
+
250
+ // Dropped attributes
251
+ for (const [name, attr] of mainAttrs) {
252
+ if (!branchAttrs.has(name)) {
253
+ changes.push(
254
+ new AlterCompositeTypeDropAttribute({
255
+ compositeType: mainCompositeType,
256
+ attribute: attr,
257
+ }),
258
+ );
259
+ }
260
+ }
261
+
262
+ // Altered attribute type/collation
263
+ for (const [name, mainAttr] of mainAttrs) {
264
+ const branchAttr = branchAttrs.get(name);
265
+ if (!branchAttr) continue;
266
+ if (
267
+ mainAttr.data_type_str !== branchAttr.data_type_str ||
268
+ mainAttr.collation !== branchAttr.collation
269
+ ) {
270
+ changes.push(
271
+ new AlterCompositeTypeAlterAttributeType({
272
+ compositeType: branchCompositeType,
273
+ attribute: branchAttr,
274
+ }),
275
+ );
276
+ }
277
+
278
+ // COMMENT change on attribute
279
+ if (mainAttr.comment !== branchAttr.comment) {
280
+ if (branchAttr.comment === null) {
281
+ changes.push(
282
+ new DropCommentOnCompositeTypeAttribute({
283
+ compositeType: mainCompositeType,
284
+ attribute: mainAttr,
285
+ }),
286
+ );
287
+ } else {
288
+ changes.push(
289
+ new CreateCommentOnCompositeTypeAttribute({
290
+ compositeType: branchCompositeType,
291
+ attribute: branchAttr,
292
+ }),
293
+ );
294
+ }
295
+ }
296
+ }
297
+
298
+ // PRIVILEGES
299
+ // Filter out PUBLIC's built-in default USAGE privilege from main catalog
300
+ // (PostgreSQL grants it automatically, so we shouldn't compare it)
301
+ const mainPrivilegesFiltered = filterPublicBuiltInDefaults(
302
+ "composite_type",
303
+ mainCompositeType.privileges,
304
+ );
305
+ // Filter out PUBLIC's built-in default USAGE privilege from branch catalog
306
+ const branchPrivilegesFiltered = filterPublicBuiltInDefaults(
307
+ "composite_type",
308
+ branchCompositeType.privileges,
309
+ );
310
+ // Filter out owner privileges - owner always has ALL privileges implicitly
311
+ // and shouldn't be compared. Use branch owner as the reference.
312
+ const privilegeResults = diffPrivileges(
313
+ mainPrivilegesFiltered,
314
+ branchPrivilegesFiltered,
315
+ branchCompositeType.owner,
316
+ ctx.mainRoles,
317
+ );
318
+
319
+ for (const [grantee, result] of privilegeResults) {
320
+ // Generate grant changes
321
+ if (result.grants.length > 0) {
322
+ const grantGroups = groupPrivilegesByGrantable(result.grants);
323
+ for (const [grantable, list] of grantGroups) {
324
+ void grantable;
325
+ changes.push(
326
+ new GrantCompositeTypePrivileges({
327
+ compositeType: branchCompositeType,
328
+ grantee,
329
+ privileges: list,
330
+ version: ctx.version,
331
+ }),
332
+ );
333
+ }
334
+ }
335
+
336
+ // Generate revoke changes
337
+ if (result.revokes.length > 0) {
338
+ const revokeGroups = groupPrivilegesByGrantable(result.revokes);
339
+ for (const [grantable, list] of revokeGroups) {
340
+ void grantable;
341
+ changes.push(
342
+ new RevokeCompositeTypePrivileges({
343
+ compositeType: mainCompositeType,
344
+ grantee,
345
+ privileges: list,
346
+ version: ctx.version,
347
+ }),
348
+ );
349
+ }
350
+ }
351
+
352
+ // Generate revoke grant option changes
353
+ if (result.revokeGrantOption.length > 0) {
354
+ changes.push(
355
+ new RevokeGrantOptionCompositeTypePrivileges({
356
+ compositeType: mainCompositeType,
357
+ grantee,
358
+ privilegeNames: result.revokeGrantOption,
359
+ version: ctx.version,
360
+ }),
361
+ );
362
+ }
363
+ }
364
+
365
+ // Note: Composite type renaming would also use ALTER TYPE ... RENAME TO ...
366
+ // But since our CompositeType model uses 'name' as the identity field,
367
+ // a name change would be handled as drop + create by diffObjects()
368
+ }
369
+ }
370
+
371
+ return changes;
372
+ }
@@ -0,0 +1,252 @@
1
+ import { sql } from "@ts-safeql/sql-tag";
2
+ import type { Pool } from "pg";
3
+ import z from "zod";
4
+ import {
5
+ BasePgModel,
6
+ columnPropsSchema,
7
+ type TableLikeObject,
8
+ } from "../../base.model.ts";
9
+ import {
10
+ type PrivilegeProps,
11
+ privilegePropsSchema,
12
+ } from "../../base.privilege-diff.ts";
13
+ import { ReplicaIdentitySchema } from "../../table/table.model.ts";
14
+
15
+ const compositeTypePropsSchema = z.object({
16
+ schema: z.string(),
17
+ name: z.string(),
18
+ row_security: z.boolean(),
19
+ force_row_security: z.boolean(),
20
+ has_indexes: z.boolean(),
21
+ has_rules: z.boolean(),
22
+ has_triggers: z.boolean(),
23
+ has_subclasses: z.boolean(),
24
+ is_populated: z.boolean(),
25
+ replica_identity: ReplicaIdentitySchema,
26
+ is_partition: z.boolean(),
27
+ options: z.array(z.string()).nullable(),
28
+ partition_bound: z.string().nullable(),
29
+ owner: z.string(),
30
+ comment: z.string().nullable(),
31
+ columns: z.array(columnPropsSchema),
32
+ privileges: z.array(privilegePropsSchema),
33
+ });
34
+
35
+ type CompositeTypePrivilegeProps = PrivilegeProps;
36
+ export type CompositeTypeProps = z.infer<typeof compositeTypePropsSchema>;
37
+
38
+ export class CompositeType extends BasePgModel implements TableLikeObject {
39
+ public readonly schema: CompositeTypeProps["schema"];
40
+ public readonly name: CompositeTypeProps["name"];
41
+ public readonly row_security: CompositeTypeProps["row_security"];
42
+ public readonly force_row_security: CompositeTypeProps["force_row_security"];
43
+ public readonly has_indexes: CompositeTypeProps["has_indexes"];
44
+ public readonly has_rules: CompositeTypeProps["has_rules"];
45
+ public readonly has_triggers: CompositeTypeProps["has_triggers"];
46
+ public readonly has_subclasses: CompositeTypeProps["has_subclasses"];
47
+ public readonly is_populated: CompositeTypeProps["is_populated"];
48
+ public readonly replica_identity: CompositeTypeProps["replica_identity"];
49
+ public readonly is_partition: CompositeTypeProps["is_partition"];
50
+ public readonly options: CompositeTypeProps["options"];
51
+ public readonly partition_bound: CompositeTypeProps["partition_bound"];
52
+ public readonly owner: CompositeTypeProps["owner"];
53
+ public readonly comment: CompositeTypeProps["comment"];
54
+ public readonly columns: CompositeTypeProps["columns"];
55
+ public readonly privileges: CompositeTypePrivilegeProps[];
56
+
57
+ constructor(props: CompositeTypeProps) {
58
+ super();
59
+
60
+ // Identity fields
61
+ this.schema = props.schema;
62
+ this.name = props.name;
63
+
64
+ // Data fields
65
+ this.row_security = props.row_security;
66
+ this.force_row_security = props.force_row_security;
67
+ this.has_indexes = props.has_indexes;
68
+ this.has_rules = props.has_rules;
69
+ this.has_triggers = props.has_triggers;
70
+ this.has_subclasses = props.has_subclasses;
71
+ this.is_populated = props.is_populated;
72
+ this.replica_identity = props.replica_identity;
73
+ this.is_partition = props.is_partition;
74
+ this.options = props.options;
75
+ this.partition_bound = props.partition_bound;
76
+ this.owner = props.owner;
77
+ this.comment = props.comment;
78
+ this.columns = props.columns;
79
+ this.privileges = props.privileges;
80
+ }
81
+
82
+ get stableId(): `type:${string}` {
83
+ return `type:${this.schema}.${this.name}`;
84
+ }
85
+
86
+ get identityFields() {
87
+ return {
88
+ schema: this.schema,
89
+ name: this.name,
90
+ };
91
+ }
92
+
93
+ get dataFields() {
94
+ return {
95
+ row_security: this.row_security,
96
+ force_row_security: this.force_row_security,
97
+ has_indexes: this.has_indexes,
98
+ has_rules: this.has_rules,
99
+ has_triggers: this.has_triggers,
100
+ has_subclasses: this.has_subclasses,
101
+ is_populated: this.is_populated,
102
+ replica_identity: this.replica_identity,
103
+ is_partition: this.is_partition,
104
+ options: this.options,
105
+ partition_bound: this.partition_bound,
106
+ owner: this.owner,
107
+ comment: this.comment,
108
+ columns: this.columns,
109
+ privileges: this.privileges,
110
+ };
111
+ }
112
+
113
+ override stableSnapshot() {
114
+ const normalizeColumns = () =>
115
+ [...this.columns]
116
+ .map((col) => {
117
+ const { position: _pos, ...rest } = col as unknown as Record<
118
+ string,
119
+ unknown
120
+ >;
121
+ return rest;
122
+ })
123
+ .sort((a, b) => {
124
+ const nameA = (a.name as string | undefined) ?? "";
125
+ const nameB = (b.name as string | undefined) ?? "";
126
+ return nameA.localeCompare(nameB);
127
+ });
128
+
129
+ return {
130
+ identity: this.identityFields,
131
+ data: {
132
+ ...this.dataFields,
133
+ columns: normalizeColumns(),
134
+ },
135
+ };
136
+ }
137
+ }
138
+
139
+ export async function extractCompositeTypes(
140
+ pool: Pool,
141
+ ): Promise<CompositeType[]> {
142
+ const { rows: compositeTypeRows } = await pool.query<CompositeTypeProps>(sql`
143
+ WITH extension_oids AS (
144
+ SELECT objid
145
+ FROM pg_depend d
146
+ WHERE d.refclassid = 'pg_extension'::regclass
147
+ AND d.classid = 'pg_type'::regclass
148
+ ),
149
+ composite_types AS (
150
+ SELECT
151
+ c.relnamespace::regnamespace::text AS schema,
152
+ quote_ident(c.relname) AS name,
153
+ c.relrowsecurity AS row_security,
154
+ c.relforcerowsecurity AS force_row_security,
155
+ c.relhasindex AS has_indexes,
156
+ c.relhasrules AS has_rules,
157
+ c.relhastriggers AS has_triggers,
158
+ c.relhassubclass AS has_subclasses,
159
+ c.relispopulated AS is_populated,
160
+ c.relreplident AS replica_identity,
161
+ c.relispartition AS is_partition,
162
+ c.reloptions AS options,
163
+ pg_get_expr(c.relpartbound, c.oid) AS partition_bound,
164
+ c.relowner::regrole::text AS owner,
165
+ obj_description(c.reltype, 'pg_type') AS comment,
166
+ c.relacl AS relacl, -- used by privileges LATERAL
167
+ c.oid AS oid
168
+ FROM pg_catalog.pg_class c
169
+ LEFT JOIN extension_oids e ON c.reltype = e.objid
170
+ WHERE NOT c.relnamespace::regnamespace::text LIKE ANY (ARRAY['pg\\_%', 'information\\_schema'])
171
+ AND e.objid IS NULL
172
+ AND c.relkind = 'c'
173
+ )
174
+ SELECT
175
+ ct.schema,
176
+ ct.name,
177
+ ct.row_security,
178
+ ct.force_row_security,
179
+ ct.has_indexes,
180
+ ct.has_rules,
181
+ ct.has_triggers,
182
+ ct.has_subclasses,
183
+ ct.is_populated,
184
+ ct.replica_identity,
185
+ ct.is_partition,
186
+ ct.options,
187
+ ct.partition_bound,
188
+ ct.owner,
189
+ ct.comment,
190
+ COALESCE(priv.privileges, '[]') AS privileges,
191
+ COALESCE(cols.columns, '[]') AS columns
192
+ FROM composite_types ct
193
+
194
+ -- privileges as a per-row LATERAL subquery
195
+ LEFT JOIN LATERAL (
196
+ SELECT json_agg(
197
+ json_build_object(
198
+ 'grantee', CASE WHEN x.grantee = 0 THEN 'PUBLIC' ELSE x.grantee::regrole::text END,
199
+ 'privilege', x.privilege_type,
200
+ 'grantable', x.is_grantable
201
+ )
202
+ ORDER BY x.grantee, x.privilege_type
203
+ ) AS privileges
204
+ FROM LATERAL aclexplode(ct.relacl) AS x(grantor, grantee, privilege_type, is_grantable)
205
+ ) priv ON TRUE
206
+
207
+ -- columns as a per-row LATERAL subquery (so no GROUP BY needed)
208
+ LEFT JOIN LATERAL (
209
+ SELECT json_agg(
210
+ json_build_object(
211
+ 'name', quote_ident(a.attname),
212
+ 'position', a.attnum,
213
+ 'data_type', a.atttypid::regtype::text,
214
+ 'data_type_str', format_type(a.atttypid, a.atttypmod),
215
+ 'is_custom_type', ty.typnamespace::regnamespace::text NOT IN ('pg_catalog','information_schema'),
216
+ 'custom_type_type', CASE WHEN ty.typnamespace::regnamespace::text NOT IN ('pg_catalog','information_schema') THEN ty.typtype ELSE NULL END,
217
+ 'custom_type_category', CASE WHEN ty.typnamespace::regnamespace::text NOT IN ('pg_catalog','information_schema') THEN ty.typcategory ELSE NULL END,
218
+ 'custom_type_schema', CASE WHEN ty.typnamespace::regnamespace::text NOT IN ('pg_catalog','information_schema') THEN ty.typnamespace::regnamespace ELSE NULL END,
219
+ 'custom_type_name', CASE WHEN ty.typnamespace::regnamespace::text NOT IN ('pg_catalog','information_schema') THEN quote_ident(ty.typname) ELSE NULL END,
220
+ 'not_null', a.attnotnull,
221
+ 'is_identity', a.attidentity <> '',
222
+ 'is_identity_always', a.attidentity = 'a',
223
+ 'is_generated', a.attgenerated <> '',
224
+ 'collation', (
225
+ SELECT quote_ident(c2.collname)
226
+ FROM pg_collation c2, pg_type t2
227
+ WHERE c2.oid = a.attcollation
228
+ AND t2.oid = a.atttypid
229
+ AND a.attcollation <> t2.typcollation
230
+ ),
231
+ 'default', pg_get_expr(ad.adbin, ad.adrelid),
232
+ 'comment', col_description(a.attrelid, a.attnum)
233
+ )
234
+ ORDER BY a.attnum
235
+ ) AS columns
236
+ FROM pg_attribute a
237
+ LEFT JOIN pg_attrdef ad ON a.attrelid = ad.adrelid AND a.attnum = ad.adnum
238
+ LEFT JOIN pg_type ty ON ty.oid = a.atttypid
239
+ WHERE a.attrelid = ct.oid
240
+ AND a.attnum > 0
241
+ AND NOT a.attisdropped
242
+ ) cols ON TRUE
243
+
244
+ ORDER BY ct.schema, ct.name
245
+ `);
246
+
247
+ // Validate and parse each row using the Zod schema
248
+ const validatedRows = compositeTypeRows.map((row: unknown) =>
249
+ compositeTypePropsSchema.parse(row),
250
+ );
251
+ return validatedRows.map((row: CompositeTypeProps) => new CompositeType(row));
252
+ }