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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (359) hide show
  1. package/README.md +40 -23
  2. package/dist/cli/app.js +26 -3
  3. package/dist/cli/bin/cli.js +5 -0
  4. package/dist/cli/commands/catalog-export.d.ts +5 -0
  5. package/dist/cli/commands/catalog-export.js +64 -0
  6. package/dist/cli/commands/declarative-apply.d.ts +6 -0
  7. package/dist/cli/commands/declarative-apply.js +288 -0
  8. package/dist/cli/commands/declarative-export.d.ts +5 -0
  9. package/dist/cli/commands/declarative-export.js +245 -0
  10. package/dist/cli/commands/plan.js +19 -6
  11. package/dist/cli/exit-code.d.ts +2 -0
  12. package/dist/cli/exit-code.js +7 -0
  13. package/dist/cli/formatters/tree/tree.js +3 -2
  14. package/dist/cli/utils/apply-display.d.ts +52 -0
  15. package/dist/cli/utils/apply-display.js +183 -0
  16. package/dist/cli/utils/export-display.d.ts +43 -0
  17. package/dist/cli/utils/export-display.js +202 -0
  18. package/dist/cli/utils/resolve-input.d.ts +7 -0
  19. package/dist/cli/utils/resolve-input.js +13 -0
  20. package/dist/core/catalog-export/index.d.ts +11 -0
  21. package/dist/core/catalog-export/index.js +10 -0
  22. package/dist/core/catalog.diff.d.ts +1 -0
  23. package/dist/core/catalog.diff.js +64 -48
  24. package/dist/core/catalog.model.d.ts +14 -1
  25. package/dist/core/catalog.model.js +103 -1
  26. package/dist/core/catalog.snapshot.d.ts +66 -0
  27. package/dist/core/catalog.snapshot.js +206 -0
  28. package/dist/core/declarative-apply/discover-sql.d.ts +18 -0
  29. package/dist/core/declarative-apply/discover-sql.js +86 -0
  30. package/dist/core/declarative-apply/extract-catalog-providers.d.ts +23 -0
  31. package/dist/core/declarative-apply/extract-catalog-providers.js +159 -0
  32. package/dist/core/declarative-apply/index.d.ts +49 -0
  33. package/dist/core/declarative-apply/index.js +134 -0
  34. package/dist/core/declarative-apply/round-apply.d.ts +100 -0
  35. package/dist/core/declarative-apply/round-apply.js +378 -0
  36. package/dist/core/export/file-mapper.d.ts +71 -0
  37. package/dist/core/export/file-mapper.js +474 -0
  38. package/dist/core/export/grouper.d.ts +13 -0
  39. package/dist/core/export/grouper.js +76 -0
  40. package/dist/core/export/index.d.ts +45 -0
  41. package/dist/core/export/index.js +63 -0
  42. package/dist/core/export/types.d.ts +84 -0
  43. package/dist/core/export/types.js +25 -0
  44. package/dist/core/fixtures/empty-catalogs/postgres-15-16-baseline.json +287 -0
  45. package/dist/core/integrations/filter/dsl.d.ts +38 -1
  46. package/dist/core/integrations/filter/dsl.js +20 -2
  47. package/dist/core/integrations/filter/extractors.js +42 -0
  48. package/dist/core/integrations/integration-dsl.d.ts +10 -0
  49. package/dist/core/integrations/supabase.d.ts +8 -0
  50. package/dist/core/integrations/supabase.js +9 -0
  51. package/dist/core/objects/aggregate/aggregate.diff.d.ts +2 -8
  52. package/dist/core/objects/aggregate/aggregate.diff.js +16 -70
  53. package/dist/core/objects/aggregate/aggregate.model.d.ts +8 -8
  54. package/dist/core/objects/aggregate/aggregate.model.js +1 -1
  55. package/dist/core/objects/aggregate/changes/aggregate.create.js +1 -1
  56. package/dist/core/objects/aggregate/changes/aggregate.drop.js +1 -1
  57. package/dist/core/objects/base.privilege-diff.d.ts +38 -13
  58. package/dist/core/objects/base.privilege-diff.js +104 -22
  59. package/dist/core/objects/base.privilege.d.ts +1 -0
  60. package/dist/core/objects/base.privilege.js +9 -2
  61. package/dist/core/objects/collation/collation.diff.d.ts +2 -3
  62. package/dist/core/objects/diff-context.d.ts +15 -0
  63. package/dist/core/objects/diff-context.js +1 -0
  64. package/dist/core/objects/domain/changes/domain.create.js +4 -2
  65. package/dist/core/objects/domain/domain.diff.d.ts +2 -8
  66. package/dist/core/objects/domain/domain.diff.js +16 -77
  67. package/dist/core/objects/domain/domain.model.js +1 -1
  68. package/dist/core/objects/event-trigger/event-trigger.diff.d.ts +2 -3
  69. package/dist/core/objects/foreign-data-wrapper/foreign-data-wrapper/foreign-data-wrapper.diff.d.ts +2 -8
  70. package/dist/core/objects/foreign-data-wrapper/foreign-data-wrapper/foreign-data-wrapper.diff.js +13 -77
  71. package/dist/core/objects/foreign-data-wrapper/foreign-data-wrapper/foreign-data-wrapper.model.js +2 -2
  72. package/dist/core/objects/foreign-data-wrapper/foreign-table/foreign-table.diff.d.ts +2 -8
  73. package/dist/core/objects/foreign-data-wrapper/foreign-table/foreign-table.diff.js +16 -77
  74. package/dist/core/objects/foreign-data-wrapper/foreign-table/foreign-table.model.js +1 -1
  75. package/dist/core/objects/foreign-data-wrapper/server/server.diff.d.ts +2 -8
  76. package/dist/core/objects/foreign-data-wrapper/server/server.diff.js +13 -77
  77. package/dist/core/objects/language/language.diff.d.ts +2 -5
  78. package/dist/core/objects/language/language.diff.js +7 -39
  79. package/dist/core/objects/materialized-view/materialized-view.diff.d.ts +2 -8
  80. package/dist/core/objects/materialized-view/materialized-view.diff.js +16 -158
  81. package/dist/core/objects/materialized-view/materialized-view.model.d.ts +3 -3
  82. package/dist/core/objects/materialized-view/materialized-view.model.js +1 -1
  83. package/dist/core/objects/procedure/changes/procedure.alter.js +12 -12
  84. package/dist/core/objects/procedure/procedure.diff.d.ts +2 -8
  85. package/dist/core/objects/procedure/procedure.diff.js +16 -77
  86. package/dist/core/objects/procedure/procedure.model.d.ts +9 -9
  87. package/dist/core/objects/procedure/procedure.model.js +1 -1
  88. package/dist/core/objects/publication/changes/publication.alter.d.ts +0 -9
  89. package/dist/core/objects/publication/changes/publication.alter.js +0 -14
  90. package/dist/core/objects/publication/changes/publication.types.d.ts +2 -2
  91. package/dist/core/objects/publication/publication.diff.d.ts +2 -3
  92. package/dist/core/objects/publication/publication.diff.js +8 -13
  93. package/dist/core/objects/rls-policy/changes/rls-policy.alter.js +3 -3
  94. package/dist/core/objects/rls-policy/rls-policy.model.d.ts +2 -2
  95. package/dist/core/objects/role/role.diff.js +22 -1
  96. package/dist/core/objects/role/role.model.d.ts +4 -3
  97. package/dist/core/objects/role/role.model.js +118 -12
  98. package/dist/core/objects/rule/rule.model.d.ts +1 -1
  99. package/dist/core/objects/schema/schema.diff.d.ts +2 -8
  100. package/dist/core/objects/schema/schema.diff.js +16 -77
  101. package/dist/core/objects/schema/schema.model.js +1 -1
  102. package/dist/core/objects/sequence/sequence.diff.d.ts +2 -8
  103. package/dist/core/objects/sequence/sequence.diff.js +16 -79
  104. package/dist/core/objects/sequence/sequence.model.js +1 -1
  105. package/dist/core/objects/subscription/subscription.diff.d.ts +2 -3
  106. package/dist/core/objects/table/changes/table.create.js +3 -0
  107. package/dist/core/objects/table/table.diff.d.ts +2 -8
  108. package/dist/core/objects/table/table.diff.js +26 -157
  109. package/dist/core/objects/table/table.model.d.ts +23 -22
  110. package/dist/core/objects/table/table.model.js +1 -1
  111. package/dist/core/objects/trigger/changes/trigger.create.js +2 -4
  112. package/dist/core/objects/trigger/trigger.model.d.ts +8 -0
  113. package/dist/core/objects/trigger/trigger.model.js +11 -0
  114. package/dist/core/objects/type/composite-type/composite-type.diff.d.ts +2 -8
  115. package/dist/core/objects/type/composite-type/composite-type.diff.js +16 -77
  116. package/dist/core/objects/type/composite-type/composite-type.model.d.ts +3 -3
  117. package/dist/core/objects/type/composite-type/composite-type.model.js +2 -1
  118. package/dist/core/objects/type/enum/enum.diff.d.ts +2 -8
  119. package/dist/core/objects/type/enum/enum.diff.js +25 -112
  120. package/dist/core/objects/type/enum/enum.model.js +1 -1
  121. package/dist/core/objects/type/range/changes/range.create.js +6 -3
  122. package/dist/core/objects/type/range/range.diff.d.ts +2 -8
  123. package/dist/core/objects/type/range/range.diff.js +16 -77
  124. package/dist/core/objects/type/range/range.model.js +1 -1
  125. package/dist/core/objects/view/view.diff.d.ts +2 -8
  126. package/dist/core/objects/view/view.diff.js +16 -158
  127. package/dist/core/objects/view/view.model.d.ts +18 -4
  128. package/dist/core/objects/view/view.model.js +3 -13
  129. package/dist/core/plan/apply.js +9 -26
  130. package/dist/core/plan/create.d.ts +19 -6
  131. package/dist/core/plan/create.js +134 -174
  132. package/dist/core/plan/serialize.js +16 -4
  133. package/dist/core/plan/sql-format/fixtures.js +3 -5
  134. package/dist/core/plan/sql-format/keyword-case.js +26 -1
  135. package/dist/core/plan/ssl-config.d.ts +32 -0
  136. package/dist/core/plan/ssl-config.js +115 -0
  137. package/dist/core/plan/types.d.ts +6 -0
  138. package/dist/core/postgres-config.d.ts +14 -0
  139. package/dist/core/postgres-config.js +53 -2
  140. package/dist/core/sort/graph-builder.js +10 -0
  141. package/dist/core/sort/logical-sort.js +31 -23
  142. package/dist/core/test-utils/assert-valid-sql.d.ts +10 -0
  143. package/dist/core/test-utils/assert-valid-sql.js +19 -0
  144. package/dist/index.d.ts +6 -0
  145. package/dist/index.js +6 -1
  146. package/package.json +21 -4
  147. package/src/cli/app.ts +27 -3
  148. package/src/cli/bin/cli.ts +6 -0
  149. package/src/cli/commands/catalog-export.ts +78 -0
  150. package/src/cli/commands/declarative-apply.diagnostics.test.ts +77 -0
  151. package/src/cli/commands/declarative-apply.ts +380 -0
  152. package/src/cli/commands/declarative-export.ts +330 -0
  153. package/src/cli/commands/plan.ts +28 -7
  154. package/src/cli/exit-code.test.ts +19 -0
  155. package/src/cli/exit-code.ts +7 -0
  156. package/src/cli/formatters/tree/tree.ts +3 -2
  157. package/src/cli/utils/apply-display.test.ts +348 -0
  158. package/src/cli/utils/apply-display.ts +238 -0
  159. package/src/cli/utils/export-display.test.ts +103 -0
  160. package/src/cli/utils/export-display.ts +275 -0
  161. package/src/cli/utils/integrations.test.ts +44 -0
  162. package/src/cli/utils/resolve-input.test.ts +38 -0
  163. package/src/cli/utils/resolve-input.ts +17 -0
  164. package/src/core/catalog-export/index.ts +20 -0
  165. package/src/core/catalog.diff.ts +79 -78
  166. package/src/core/catalog.model.test.ts +122 -0
  167. package/src/core/catalog.model.ts +127 -1
  168. package/src/core/catalog.snapshot.test.ts +464 -0
  169. package/src/core/catalog.snapshot.ts +289 -0
  170. package/src/core/declarative-apply/discover-sql.test.ts +103 -0
  171. package/src/core/declarative-apply/discover-sql.ts +107 -0
  172. package/src/core/declarative-apply/extract-catalog-providers.ts +220 -0
  173. package/src/core/declarative-apply/index.test.ts +67 -0
  174. package/src/core/declarative-apply/index.ts +205 -0
  175. package/src/core/declarative-apply/round-apply.test.ts +504 -0
  176. package/src/core/declarative-apply/round-apply.ts +562 -0
  177. package/src/core/expand-replace-dependencies.test.ts +70 -0
  178. package/src/core/export/file-mapper.test.ts +816 -0
  179. package/src/core/export/file-mapper.ts +574 -0
  180. package/src/core/export/grouper.ts +108 -0
  181. package/src/core/export/index.ts +129 -0
  182. package/src/core/export/types.ts +104 -0
  183. package/src/core/fixtures/empty-catalogs/postgres-15-16-baseline.json +287 -0
  184. package/src/core/integrations/filter/dsl.test.ts +211 -0
  185. package/src/core/integrations/filter/dsl.ts +65 -3
  186. package/src/core/integrations/filter/extractors.test.ts +244 -0
  187. package/src/core/integrations/filter/extractors.ts +42 -0
  188. package/src/core/integrations/integration-dsl.ts +10 -0
  189. package/src/core/integrations/serialize/dsl.test.ts +91 -0
  190. package/src/core/integrations/supabase.ts +9 -0
  191. package/src/core/objects/aggregate/aggregate.diff.ts +39 -95
  192. package/src/core/objects/aggregate/aggregate.model.ts +1 -1
  193. package/src/core/objects/aggregate/changes/aggregate.alter.test.ts +3 -1
  194. package/src/core/objects/aggregate/changes/aggregate.comment.test.ts +5 -2
  195. package/src/core/objects/aggregate/changes/aggregate.create.test.ts +6 -3
  196. package/src/core/objects/aggregate/changes/aggregate.create.ts +1 -1
  197. package/src/core/objects/aggregate/changes/aggregate.drop.test.ts +7 -3
  198. package/src/core/objects/aggregate/changes/aggregate.drop.ts +1 -1
  199. package/src/core/objects/aggregate/changes/aggregate.privilege.test.ts +9 -3
  200. package/src/core/objects/base.privilege-diff.ts +178 -30
  201. package/src/core/objects/base.privilege.ts +9 -2
  202. package/src/core/objects/collation/changes/collation.alter.test.ts +7 -2
  203. package/src/core/objects/collation/changes/collation.create.test.ts +7 -2
  204. package/src/core/objects/collation/changes/collation.drop.test.ts +4 -1
  205. package/src/core/objects/collation/collation.diff.test.ts +9 -12
  206. package/src/core/objects/collation/collation.diff.ts +2 -1
  207. package/src/core/objects/diff-context.ts +16 -0
  208. package/src/core/objects/domain/changes/domain.alter.test.ts +28 -9
  209. package/src/core/objects/domain/changes/domain.create.test.ts +32 -2
  210. package/src/core/objects/domain/changes/domain.create.ts +7 -1
  211. package/src/core/objects/domain/changes/domain.drop.test.ts +4 -1
  212. package/src/core/objects/domain/domain.diff.ts +39 -102
  213. package/src/core/objects/domain/domain.model.ts +1 -1
  214. package/src/core/objects/event-trigger/changes/event-trigger.alter.test.ts +10 -3
  215. package/src/core/objects/event-trigger/changes/event-trigger.create.test.ts +4 -1
  216. package/src/core/objects/event-trigger/changes/event-trigger.drop.test.ts +4 -1
  217. package/src/core/objects/event-trigger/event-trigger.diff.test.ts +12 -7
  218. package/src/core/objects/event-trigger/event-trigger.diff.ts +2 -1
  219. package/src/core/objects/extension/changes/extension.alter.test.ts +7 -2
  220. package/src/core/objects/extension/changes/extension.create.test.ts +4 -1
  221. package/src/core/objects/extension/changes/extension.drop.test.ts +4 -1
  222. package/src/core/objects/extension/extension.model.test.ts +98 -0
  223. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.alter.test.ts +16 -5
  224. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.create.test.ts +51 -16
  225. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.drop.test.ts +4 -1
  226. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/foreign-data-wrapper.diff.test.ts +111 -4
  227. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/foreign-data-wrapper.diff.ts +31 -101
  228. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/foreign-data-wrapper.model.ts +2 -2
  229. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.alter.test.ts +46 -15
  230. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.create.test.ts +13 -4
  231. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.drop.test.ts +4 -1
  232. package/src/core/objects/foreign-data-wrapper/foreign-table/foreign-table.diff.ts +39 -102
  233. package/src/core/objects/foreign-data-wrapper/foreign-table/foreign-table.model.ts +1 -1
  234. package/src/core/objects/foreign-data-wrapper/server/changes/server.alter.test.ts +22 -7
  235. package/src/core/objects/foreign-data-wrapper/server/changes/server.create.test.ts +19 -6
  236. package/src/core/objects/foreign-data-wrapper/server/changes/server.drop.test.ts +4 -1
  237. package/src/core/objects/foreign-data-wrapper/server/server.diff.test.ts +95 -0
  238. package/src/core/objects/foreign-data-wrapper/server/server.diff.ts +31 -101
  239. package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.alter.test.ts +13 -4
  240. package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.create.test.ts +16 -5
  241. package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.drop.test.ts +10 -3
  242. package/src/core/objects/index/changes/index.alter.test.ts +13 -4
  243. package/src/core/objects/index/changes/index.create.test.ts +4 -1
  244. package/src/core/objects/index/changes/index.drop.test.ts +4 -1
  245. package/src/core/objects/language/changes/language.alter.test.ts +4 -1
  246. package/src/core/objects/language/changes/language.create.test.ts +4 -1
  247. package/src/core/objects/language/changes/language.drop.test.ts +4 -1
  248. package/src/core/objects/language/language.diff.test.ts +86 -4
  249. package/src/core/objects/language/language.diff.ts +17 -49
  250. package/src/core/objects/materialized-view/changes/materialized-view.alter.test.ts +10 -3
  251. package/src/core/objects/materialized-view/changes/materialized-view.create.test.ts +7 -2
  252. package/src/core/objects/materialized-view/changes/materialized-view.drop.test.ts +4 -1
  253. package/src/core/objects/materialized-view/materialized-view.diff.test.ts +162 -0
  254. package/src/core/objects/materialized-view/materialized-view.diff.ts +41 -191
  255. package/src/core/objects/materialized-view/materialized-view.model.ts +1 -1
  256. package/src/core/objects/procedure/changes/procedure.alter.test.ts +121 -49
  257. package/src/core/objects/procedure/changes/procedure.alter.ts +15 -12
  258. package/src/core/objects/procedure/changes/procedure.create.test.ts +4 -1
  259. package/src/core/objects/procedure/changes/procedure.drop.test.ts +7 -2
  260. package/src/core/objects/procedure/procedure.diff.ts +39 -102
  261. package/src/core/objects/procedure/procedure.model.ts +1 -1
  262. package/src/core/objects/publication/changes/publication.alter.test.ts +15 -21
  263. package/src/core/objects/publication/changes/publication.alter.ts +0 -18
  264. package/src/core/objects/publication/changes/publication.comment.test.ts +5 -2
  265. package/src/core/objects/publication/changes/publication.create.test.ts +5 -2
  266. package/src/core/objects/publication/changes/publication.drop.test.ts +3 -1
  267. package/src/core/objects/publication/changes/publication.types.ts +0 -2
  268. package/src/core/objects/publication/publication.diff.test.ts +24 -19
  269. package/src/core/objects/publication/publication.diff.ts +9 -15
  270. package/src/core/objects/rls-policy/changes/rls-policy.alter.test.ts +31 -14
  271. package/src/core/objects/rls-policy/changes/rls-policy.alter.ts +3 -3
  272. package/src/core/objects/rls-policy/changes/rls-policy.create.test.ts +10 -3
  273. package/src/core/objects/rls-policy/changes/rls-policy.drop.test.ts +4 -1
  274. package/src/core/objects/role/changes/role.alter.test.ts +31 -15
  275. package/src/core/objects/role/changes/role.create.test.ts +6 -2
  276. package/src/core/objects/role/changes/role.drop.test.ts +4 -1
  277. package/src/core/objects/role/role.diff.test.ts +235 -0
  278. package/src/core/objects/role/role.diff.ts +21 -1
  279. package/src/core/objects/role/role.model.ts +122 -14
  280. package/src/core/objects/rule/changes/rule.alter.test.ts +7 -3
  281. package/src/core/objects/rule/changes/rule.comment.test.ts +5 -2
  282. package/src/core/objects/rule/changes/rule.create.test.ts +6 -2
  283. package/src/core/objects/rule/changes/rule.drop.test.ts +3 -1
  284. package/src/core/objects/schema/changes/schema.alter.test.ts +4 -1
  285. package/src/core/objects/schema/changes/schema.create.test.ts +4 -1
  286. package/src/core/objects/schema/changes/schema.drop.test.ts +4 -1
  287. package/src/core/objects/schema/schema.diff.ts +39 -102
  288. package/src/core/objects/schema/schema.model.ts +1 -1
  289. package/src/core/objects/sequence/changes/sequence.alter.test.ts +11 -5
  290. package/src/core/objects/sequence/changes/sequence.create.test.ts +8 -3
  291. package/src/core/objects/sequence/changes/sequence.drop.test.ts +4 -1
  292. package/src/core/objects/sequence/sequence.diff.test.ts +114 -0
  293. package/src/core/objects/sequence/sequence.diff.ts +39 -104
  294. package/src/core/objects/sequence/sequence.model.ts +1 -1
  295. package/src/core/objects/subscription/changes/subscription.alter.test.ts +15 -5
  296. package/src/core/objects/subscription/changes/subscription.comment.test.ts +5 -2
  297. package/src/core/objects/subscription/changes/subscription.create.test.ts +5 -2
  298. package/src/core/objects/subscription/changes/subscription.drop.test.ts +3 -1
  299. package/src/core/objects/subscription/subscription.diff.test.ts +16 -11
  300. package/src/core/objects/subscription/subscription.diff.ts +2 -1
  301. package/src/core/objects/table/changes/table.alter.test.ts +38 -15
  302. package/src/core/objects/table/changes/table.create.test.ts +41 -3
  303. package/src/core/objects/table/changes/table.create.ts +4 -0
  304. package/src/core/objects/table/changes/table.drop.test.ts +3 -1
  305. package/src/core/objects/table/table.diff.test.ts +157 -0
  306. package/src/core/objects/table/table.diff.ts +54 -190
  307. package/src/core/objects/table/table.model.ts +1 -1
  308. package/src/core/objects/trigger/changes/trigger.alter.test.ts +8 -4
  309. package/src/core/objects/trigger/changes/trigger.create.test.ts +5 -1
  310. package/src/core/objects/trigger/changes/trigger.create.ts +7 -4
  311. package/src/core/objects/trigger/changes/trigger.drop.test.ts +5 -1
  312. package/src/core/objects/trigger/trigger.diff.test.ts +1 -0
  313. package/src/core/objects/trigger/trigger.model.ts +12 -0
  314. package/src/core/objects/type/composite-type/changes/composite-type.alter.test.ts +10 -4
  315. package/src/core/objects/type/composite-type/changes/composite-type.create.test.ts +7 -2
  316. package/src/core/objects/type/composite-type/changes/composite-type.drop.test.ts +4 -1
  317. package/src/core/objects/type/composite-type/composite-type.diff.test.ts +78 -0
  318. package/src/core/objects/type/composite-type/composite-type.diff.ts +39 -101
  319. package/src/core/objects/type/composite-type/composite-type.model.ts +2 -1
  320. package/src/core/objects/type/enum/changes/enum.alter.test.ts +14 -5
  321. package/src/core/objects/type/enum/changes/enum.create.test.ts +4 -1
  322. package/src/core/objects/type/enum/changes/enum.drop.test.ts +4 -1
  323. package/src/core/objects/type/enum/enum.diff.test.ts +181 -0
  324. package/src/core/objects/type/enum/enum.diff.ts +58 -146
  325. package/src/core/objects/type/enum/enum.model.ts +1 -1
  326. package/src/core/objects/type/range/changes/range.alter.test.ts +3 -1
  327. package/src/core/objects/type/range/changes/range.create.test.ts +5 -2
  328. package/src/core/objects/type/range/changes/range.create.ts +6 -2
  329. package/src/core/objects/type/range/changes/range.drop.test.ts +3 -1
  330. package/src/core/objects/type/range/range.diff.test.ts +77 -0
  331. package/src/core/objects/type/range/range.diff.ts +39 -101
  332. package/src/core/objects/type/range/range.model.ts +1 -1
  333. package/src/core/objects/view/changes/view.alter.test.ts +8 -3
  334. package/src/core/objects/view/changes/view.create.test.ts +7 -2
  335. package/src/core/objects/view/changes/view.drop.test.ts +4 -1
  336. package/src/core/objects/view/view.diff.test.ts +82 -0
  337. package/src/core/objects/view/view.diff.ts +41 -191
  338. package/src/core/objects/view/view.model.ts +3 -17
  339. package/src/core/plan/apply.ts +9 -27
  340. package/src/core/plan/create.ts +173 -237
  341. package/src/core/plan/serialize.test.ts +317 -0
  342. package/src/core/plan/serialize.ts +18 -4
  343. package/src/core/plan/sql-format/fixtures.ts +2 -5
  344. package/src/core/plan/sql-format/format-lowercase-coverage.test.ts +52 -0
  345. package/src/core/plan/sql-format/format-off.test.ts +14 -17
  346. package/src/core/plan/sql-format/format-pretty-lower-leading.test.ts +27 -22
  347. package/src/core/plan/sql-format/format-pretty-narrow.test.ts +17 -21
  348. package/src/core/plan/sql-format/format-pretty-preserve.test.ts +25 -20
  349. package/src/core/plan/sql-format/format-pretty-upper.test.ts +23 -20
  350. package/src/core/plan/sql-format/keyword-case.ts +36 -1
  351. package/src/core/plan/ssl-config.ts +172 -0
  352. package/src/core/plan/types.ts +6 -0
  353. package/src/core/postgres-config.ts +71 -2
  354. package/src/core/sort/graph-builder.ts +12 -0
  355. package/src/core/sort/logical-sort.test.ts +371 -0
  356. package/src/core/sort/logical-sort.ts +32 -25
  357. package/src/core/sort/topological-sort.test.ts +275 -0
  358. package/src/core/test-utils/assert-valid-sql.ts +20 -0
  359. package/src/index.ts +26 -2
@@ -84,6 +84,10 @@ export class CreateTable extends CreateTableChange {
84
84
  }
85
85
  }
86
86
  }
87
+
88
+ // Function dependencies from DEFAULT expressions are handled by pg_depend
89
+ // catalog constraints in the sort pipeline, which provides exact argument
90
+ // types and covers all expression contexts (not just column defaults).
87
91
  }
88
92
 
89
93
  return Array.from(dependencies);
@@ -1,4 +1,5 @@
1
1
  import { describe, expect, test } from "bun:test";
2
+ import { assertValidSql } from "../../../test-utils/assert-valid-sql.ts";
2
3
  import { Table, type TableProps } from "../table.model.ts";
3
4
  import { DropTable } from "./table.drop.ts";
4
5
 
@@ -26,9 +27,10 @@ const base: TableProps = {
26
27
  };
27
28
 
28
29
  describe.concurrent("table.drop", () => {
29
- test("drop table basic", () => {
30
+ test("drop table basic", async () => {
30
31
  const t = new Table(base);
31
32
  const change = new DropTable({ table: t });
33
+ await assertValidSql(change.serialize());
32
34
  expect(change.serialize()).toBe("DROP TABLE public.t");
33
35
  });
34
36
  });
@@ -24,6 +24,11 @@ import {
24
24
  } from "./changes/table.alter.ts";
25
25
  import { CreateTable } from "./changes/table.create.ts";
26
26
  import { DropTable } from "./changes/table.drop.ts";
27
+ import {
28
+ GrantTablePrivileges,
29
+ RevokeGrantOptionTablePrivileges,
30
+ RevokeTablePrivileges,
31
+ } from "./changes/table.privilege.ts";
27
32
  import { diffTables } from "./table.diff.ts";
28
33
  import { Table, type TableProps } from "./table.model.ts";
29
34
 
@@ -708,4 +713,156 @@ describe.concurrent("table.diff", () => {
708
713
  notNullDropped.some((c) => c instanceof AlterTableAlterColumnDropNotNull),
709
714
  ).toBe(true);
710
715
  });
716
+
717
+ test("created table with privileges emits grant changes", () => {
718
+ const t = new Table({
719
+ ...base,
720
+ privileges: [
721
+ { grantee: "role_sel", privilege: "SELECT", grantable: false },
722
+ { grantee: "role_ins", privilege: "INSERT", grantable: true },
723
+ ],
724
+ });
725
+ const changes = diffTables(testContext, {}, { [t.stableId]: t });
726
+ expect(changes[0]).toBeInstanceOf(CreateTable);
727
+ expect(changes.some((c) => c instanceof GrantTablePrivileges)).toBe(true);
728
+ });
729
+
730
+ test("created table with default privilege revoke grant option", () => {
731
+ const defaultPrivilegeState = new DefaultPrivilegeState({});
732
+ defaultPrivilegeState.applyGrant("postgres", "r", "public", "role_a", [
733
+ { privilege: "SELECT", grantable: true },
734
+ ]);
735
+ const ctx = {
736
+ ...testContext,
737
+ defaultPrivilegeState,
738
+ };
739
+ const t = new Table({
740
+ ...base,
741
+ owner: "postgres",
742
+ privileges: [
743
+ { grantee: "role_a", privilege: "SELECT", grantable: false },
744
+ ],
745
+ });
746
+ const changes = diffTables(ctx, {}, { [t.stableId]: t });
747
+ expect(changes[0]).toBeInstanceOf(CreateTable);
748
+ expect(
749
+ changes.some((c) => c instanceof RevokeGrantOptionTablePrivileges),
750
+ ).toBe(true);
751
+ });
752
+
753
+ test("altered table privileges emit grant, revoke, and revoke grant option", () => {
754
+ const main = new Table({
755
+ ...base,
756
+ privileges: [
757
+ { grantee: "role_sel", privilege: "SELECT", grantable: false },
758
+ { grantee: "role_with_option", privilege: "SELECT", grantable: true },
759
+ { grantee: "role_removed", privilege: "SELECT", grantable: false },
760
+ ],
761
+ });
762
+ const branch = new Table({
763
+ ...base,
764
+ privileges: [
765
+ { grantee: "role_sel", privilege: "SELECT", grantable: true },
766
+ { grantee: "role_with_option", privilege: "SELECT", grantable: false },
767
+ { grantee: "role_new", privilege: "SELECT", grantable: false },
768
+ ],
769
+ });
770
+ const changes = diffTables(
771
+ testContext,
772
+ { [main.stableId]: main },
773
+ { [branch.stableId]: branch },
774
+ );
775
+ expect(changes.some((c) => c instanceof GrantTablePrivileges)).toBe(true);
776
+ expect(changes.some((c) => c instanceof RevokeTablePrivileges)).toBe(true);
777
+ expect(
778
+ changes.some((c) => c instanceof RevokeGrantOptionTablePrivileges),
779
+ ).toBe(true);
780
+ });
781
+
782
+ test("altered table privileges emit revokes before grants", () => {
783
+ const main = new Table({
784
+ ...base,
785
+ privileges: [
786
+ { grantee: "authenticated", privilege: "INSERT", grantable: false },
787
+ { grantee: "authenticated", privilege: "UPDATE", grantable: false },
788
+ ],
789
+ });
790
+ const branch = new Table({
791
+ ...base,
792
+ privileges: [
793
+ {
794
+ grantee: "authenticated",
795
+ privilege: "INSERT",
796
+ grantable: false,
797
+ columns: ["org_id", "name"],
798
+ },
799
+ {
800
+ grantee: "authenticated",
801
+ privilege: "UPDATE",
802
+ grantable: false,
803
+ columns: ["name"],
804
+ },
805
+ ],
806
+ });
807
+ const changes = diffTables(
808
+ testContext,
809
+ { [main.stableId]: main },
810
+ { [branch.stableId]: branch },
811
+ );
812
+ const privilegeChanges = changes.filter(
813
+ (c) =>
814
+ c instanceof GrantTablePrivileges ||
815
+ c instanceof RevokeTablePrivileges ||
816
+ c instanceof RevokeGrantOptionTablePrivileges,
817
+ );
818
+ expect(privilegeChanges.length).toBeGreaterThan(1);
819
+
820
+ const firstRevokeIndex = privilegeChanges.findIndex(
821
+ (c) => c instanceof RevokeTablePrivileges,
822
+ );
823
+ const firstGrantIndex = privilegeChanges.findIndex(
824
+ (c) => c instanceof GrantTablePrivileges,
825
+ );
826
+ expect(firstRevokeIndex).not.toBe(-1);
827
+ expect(firstGrantIndex).not.toBe(-1);
828
+ expect(firstRevokeIndex).toBeLessThan(firstGrantIndex);
829
+ });
830
+
831
+ test("storage params: set when added from null", () => {
832
+ const main = new Table(base);
833
+ const branch = new Table({
834
+ ...base,
835
+ options: ["autovacuum_enabled=false"],
836
+ });
837
+ const changes = diffTables(
838
+ testContext,
839
+ { [main.stableId]: main },
840
+ { [branch.stableId]: branch },
841
+ );
842
+ expect(changes.some((c) => c instanceof AlterTableSetStorageParams)).toBe(
843
+ true,
844
+ );
845
+ expect(changes.some((c) => c instanceof AlterTableResetStorageParams)).toBe(
846
+ false,
847
+ );
848
+ });
849
+
850
+ test("storage params: reset when removed to null", () => {
851
+ const main = new Table({
852
+ ...base,
853
+ options: ["fillfactor=90"],
854
+ });
855
+ const branch = new Table(base);
856
+ const changes = diffTables(
857
+ testContext,
858
+ { [main.stableId]: main },
859
+ { [branch.stableId]: branch },
860
+ );
861
+ expect(changes.some((c) => c instanceof AlterTableResetStorageParams)).toBe(
862
+ true,
863
+ );
864
+ expect(changes.some((c) => c instanceof AlterTableSetStorageParams)).toBe(
865
+ false,
866
+ );
867
+ });
711
868
  });
@@ -1,10 +1,9 @@
1
- import type { DefaultPrivilegeState } from "../base.default-privileges.ts";
2
1
  import { diffObjects } from "../base.diff.ts";
3
2
  import {
4
3
  diffPrivileges,
5
- groupPrivilegesByColumns,
4
+ emitColumnPrivilegeChanges,
6
5
  } from "../base.privilege-diff.ts";
7
- import type { Role } from "../role/role.model.ts";
6
+ import type { ObjectDiffContext } from "../diff-context.ts";
8
7
  import { deepEqual } from "../utils.ts";
9
8
  import {
10
9
  AlterTableAddColumn,
@@ -202,12 +201,10 @@ function createAlterConstraintChange(mainTable: Table, branchTable: Table) {
202
201
  * @returns A list of changes to apply to main to make it match branch.
203
202
  */
204
203
  export function diffTables(
205
- ctx: {
206
- version: number;
207
- currentUser: string;
208
- defaultPrivilegeState: DefaultPrivilegeState;
209
- mainRoles: Record<string, Role>;
210
- },
204
+ ctx: Pick<
205
+ ObjectDiffContext,
206
+ "version" | "currentUser" | "defaultPrivilegeState"
207
+ >,
211
208
  main: Record<string, Table>,
212
209
  branch: Record<string, Table>,
213
210
  ): TableChange[] {
@@ -242,6 +239,19 @@ export function diffTables(
242
239
  changes.push(new AlterTableForceRowLevelSecurity({ table: branchTable }));
243
240
  }
244
241
 
242
+ // REPLICA IDENTITY: If non-default, emit ALTER TABLE ... REPLICA IDENTITY
243
+ if (branchTable.replica_identity !== "d") {
244
+ // Skip 'i' (USING INDEX) — handled by index changes
245
+ if (branchTable.replica_identity !== "i") {
246
+ changes.push(
247
+ new AlterTableSetReplicaIdentity({
248
+ table: branchTable,
249
+ mode: branchTable.replica_identity,
250
+ }),
251
+ );
252
+ }
253
+ }
254
+
245
255
  changes.push(
246
256
  ...createAlterConstraintChange(
247
257
  // Create a dummy table with no constraints do diff constraints against
@@ -277,104 +287,34 @@ export function diffTables(
277
287
  "table",
278
288
  branchTable.schema ?? "",
279
289
  );
290
+ const creatorFilteredDefaults =
291
+ branchTable.owner !== ctx.currentUser
292
+ ? effectiveDefaults.filter((p) => p.grantee !== ctx.currentUser)
293
+ : effectiveDefaults;
280
294
  const desiredPrivileges = branchTable.privileges;
281
295
  // Filter out owner privileges - owner always has ALL privileges implicitly
282
296
  // and shouldn't be compared. Use the table owner as the reference.
283
297
  const privilegeResults = diffPrivileges(
284
- effectiveDefaults,
298
+ creatorFilteredDefaults,
285
299
  desiredPrivileges,
286
300
  branchTable.owner,
287
- ctx.mainRoles,
288
301
  );
289
302
 
290
- // Generate grant changes
291
- for (const [grantee, result] of privilegeResults) {
292
- if (result.grants.length > 0) {
293
- const grantGroups = groupPrivilegesByColumns(result.grants);
294
- for (const [, group] of grantGroups) {
295
- for (const [grantable, privSet] of group.byGrant) {
296
- const privileges = Array.from(privSet).map((priv) => ({
297
- privilege: priv,
298
- grantable,
299
- }));
300
- changes.push(
301
- new GrantTablePrivileges({
302
- table: branchTable,
303
- grantee,
304
- privileges,
305
- columns: group.columns,
306
- version: ctx.version,
307
- }),
308
- );
309
- }
310
- }
311
- }
312
-
313
- // Generate revoke changes
314
- if (result.revokes.length > 0) {
315
- const revokeGroups = groupPrivilegesByColumns(result.revokes);
316
- for (const [, group] of revokeGroups) {
317
- const allPrivileges = new Set<string>();
318
- for (const [, privSet] of group.byGrant) {
319
- for (const priv of privSet) {
320
- allPrivileges.add(priv);
321
- }
322
- }
323
- const privileges = Array.from(allPrivileges).map((priv) => ({
324
- privilege: priv,
325
- grantable: false,
326
- }));
327
- changes.push(
328
- new RevokeTablePrivileges({
329
- table: branchTable,
330
- grantee,
331
- privileges,
332
- columns: group.columns,
333
- version: ctx.version,
334
- }),
335
- );
336
- }
337
- }
338
-
339
- // Generate revoke grant option changes
340
- if (result.revokeGrantOption.length > 0) {
341
- const revokeGrantGroups = new Map<
342
- string,
343
- { columns?: string[]; privileges: Set<string> }
344
- >();
345
- for (const r of result.revokeGrantOption) {
346
- const originalPriv = effectiveDefaults.find(
347
- (p) => p.grantee === grantee && p.privilege === r,
348
- );
349
- const key = originalPriv?.columns
350
- ? originalPriv.columns.sort().join(",")
351
- : "";
352
- if (!revokeGrantGroups.has(key)) {
353
- revokeGrantGroups.set(key, {
354
- columns: originalPriv?.columns
355
- ? [...originalPriv.columns]
356
- : undefined,
357
- privileges: new Set(),
358
- });
359
- }
360
- const group = revokeGrantGroups.get(key);
361
- if (!group) continue;
362
- group.privileges.add(r);
363
- }
364
- for (const [, group] of revokeGrantGroups) {
365
- const privilegeNames = Array.from(group.privileges);
366
- changes.push(
367
- new RevokeGrantOptionTablePrivileges({
368
- table: branchTable,
369
- grantee,
370
- privilegeNames,
371
- columns: group.columns,
372
- version: ctx.version,
373
- }),
374
- );
375
- }
376
- }
377
- }
303
+ changes.push(
304
+ ...(emitColumnPrivilegeChanges(
305
+ privilegeResults,
306
+ branchTable,
307
+ branchTable,
308
+ "table",
309
+ {
310
+ Grant: GrantTablePrivileges,
311
+ Revoke: RevokeTablePrivileges,
312
+ RevokeGrantOption: RevokeGrantOptionTablePrivileges,
313
+ },
314
+ effectiveDefaults,
315
+ ctx.version,
316
+ ) as TableChange[]),
317
+ );
378
318
  }
379
319
 
380
320
  for (const tableId of dropped) {
@@ -854,99 +794,23 @@ export function diffTables(
854
794
  mainTable.privileges,
855
795
  branchTable.privileges,
856
796
  branchTable.owner,
857
- ctx.mainRoles,
858
797
  );
859
798
 
860
- for (const [grantee, result] of privilegeResults) {
861
- // Generate grant changes
862
- if (result.grants.length > 0) {
863
- const grantGroups = groupPrivilegesByColumns(result.grants);
864
- for (const [, group] of grantGroups) {
865
- for (const [grantable, privSet] of group.byGrant) {
866
- const privileges = Array.from(privSet).map((priv) => ({
867
- privilege: priv,
868
- grantable,
869
- }));
870
- changes.push(
871
- new GrantTablePrivileges({
872
- table: branchTable,
873
- grantee,
874
- privileges,
875
- columns: group.columns,
876
- version: ctx.version,
877
- }),
878
- );
879
- }
880
- }
881
- }
882
-
883
- // Generate revoke changes
884
- if (result.revokes.length > 0) {
885
- const revokeGroups = groupPrivilegesByColumns(result.revokes);
886
- for (const [, group] of revokeGroups) {
887
- // Collapse all grantable groups into a single revoke (grantable: false)
888
- const allPrivileges = new Set<string>();
889
- for (const [, privSet] of group.byGrant) {
890
- for (const priv of privSet) {
891
- allPrivileges.add(priv);
892
- }
893
- }
894
- const privileges = Array.from(allPrivileges).map((priv) => ({
895
- privilege: priv,
896
- grantable: false,
897
- }));
898
- changes.push(
899
- new RevokeTablePrivileges({
900
- table: mainTable,
901
- grantee,
902
- privileges,
903
- columns: group.columns,
904
- version: ctx.version,
905
- }),
906
- );
907
- }
908
- }
909
-
910
- // Generate revoke grant option changes
911
- if (result.revokeGrantOption.length > 0) {
912
- const revokeGrantGroups = new Map<
913
- string,
914
- { columns?: string[]; privileges: Set<string> }
915
- >();
916
- for (const r of result.revokeGrantOption) {
917
- // For revoke grant option, we need to find the columns from the original privilege
918
- const originalPriv = mainTable.privileges.find(
919
- (p) => p.grantee === grantee && p.privilege === r,
920
- );
921
- const key = originalPriv?.columns
922
- ? originalPriv.columns.sort().join(",")
923
- : "";
924
- if (!revokeGrantGroups.has(key)) {
925
- revokeGrantGroups.set(key, {
926
- columns: originalPriv?.columns
927
- ? [...originalPriv.columns]
928
- : undefined,
929
- privileges: new Set(),
930
- });
931
- }
932
- const group = revokeGrantGroups.get(key);
933
- if (!group) continue;
934
- group.privileges.add(r);
935
- }
936
- for (const [, group] of revokeGrantGroups) {
937
- const privilegeNames = Array.from(group.privileges);
938
- changes.push(
939
- new RevokeGrantOptionTablePrivileges({
940
- table: mainTable,
941
- grantee,
942
- privilegeNames,
943
- columns: group.columns,
944
- version: ctx.version,
945
- }),
946
- );
947
- }
948
- }
949
- }
799
+ changes.push(
800
+ ...(emitColumnPrivilegeChanges(
801
+ privilegeResults,
802
+ branchTable,
803
+ mainTable,
804
+ "table",
805
+ {
806
+ Grant: GrantTablePrivileges,
807
+ Revoke: RevokeTablePrivileges,
808
+ RevokeGrantOption: RevokeGrantOptionTablePrivileges,
809
+ },
810
+ mainTable.privileges,
811
+ ctx.version,
812
+ ) as TableChange[]),
813
+ );
950
814
  }
951
815
 
952
816
  return changes;
@@ -428,7 +428,7 @@ select
428
428
  from (
429
429
  -- one row for object ACL + one row per column ACL
430
430
  select null::name as attname, t.oid as relacl_oid, (
431
- select c_rel.relacl from pg_class c_rel where c_rel.oid = t.oid
431
+ select COALESCE(c_rel.relacl, acldefault('r', c_rel.relowner)) from pg_class c_rel where c_rel.oid = t.oid
432
432
  ) as acl
433
433
  union all
434
434
  select a2.attname, t.oid as relacl_oid, a2.attacl
@@ -1,19 +1,21 @@
1
1
  import { describe, expect, test } from "bun:test";
2
+ import { assertValidSql } from "../../../test-utils/assert-valid-sql.ts";
2
3
  import { Trigger, type TriggerProps } from "../trigger.model.ts";
3
4
  import { ReplaceTrigger } from "./trigger.alter.ts";
4
5
 
5
6
  describe.concurrent("trigger", () => {
6
7
  describe("alter", () => {
7
- test("replace trigger", () => {
8
+ test("replace trigger", async () => {
8
9
  const props: Omit<TriggerProps, "enabled"> = {
9
10
  schema: "public",
10
11
  name: "test_trigger",
11
12
  table_name: "test_table",
13
+ table_relkind: "r",
12
14
  function_schema: "public",
13
15
  function_name: "test_function",
14
16
  trigger_type: 1 << 4, // UPDATE (1<<4) = 16, AFTER is default (0), STATEMENT is default (0)
15
17
  is_internal: false,
16
- deferrable: true,
18
+ deferrable: false,
17
19
  initially_deferred: false,
18
20
  argument_count: 0,
19
21
  column_numbers: null,
@@ -28,7 +30,7 @@ describe.concurrent("trigger", () => {
28
30
  is_on_partitioned_table: false,
29
31
  owner: "test",
30
32
  definition:
31
- "CREATE TRIGGER test_trigger AFTER UPDATE ON public.test_table DEFERRABLE EXECUTE FUNCTION public.test_function()",
33
+ "CREATE TRIGGER test_trigger AFTER UPDATE ON public.test_table EXECUTE FUNCTION public.test_function()",
32
34
  comment: null,
33
35
  };
34
36
  const branch = new Trigger({
@@ -38,8 +40,10 @@ describe.concurrent("trigger", () => {
38
40
 
39
41
  const change = new ReplaceTrigger({ trigger: branch });
40
42
 
43
+ await assertValidSql(change.serialize());
44
+
41
45
  expect(change.serialize()).toBe(
42
- "CREATE OR REPLACE TRIGGER test_trigger AFTER UPDATE ON public.test_table DEFERRABLE EXECUTE FUNCTION public.test_function()",
46
+ "CREATE OR REPLACE TRIGGER test_trigger AFTER UPDATE ON public.test_table EXECUTE FUNCTION public.test_function()",
43
47
  );
44
48
  });
45
49
  });
@@ -1,13 +1,15 @@
1
1
  import { describe, expect, test } from "bun:test";
2
+ import { assertValidSql } from "../../../test-utils/assert-valid-sql.ts";
2
3
  import { Trigger } from "../trigger.model.ts";
3
4
  import { CreateTrigger } from "./trigger.create.ts";
4
5
 
5
6
  describe("trigger", () => {
6
- test("create", () => {
7
+ test("create", async () => {
7
8
  const trigger = new Trigger({
8
9
  schema: "public",
9
10
  name: "test_trigger",
10
11
  table_name: "test_table",
12
+ table_relkind: "r",
11
13
  function_schema: "public",
12
14
  function_name: "test_function",
13
15
  trigger_type: (1 << 1) | (1 << 2) | (1 << 0), // BEFORE (1<<1) | INSERT (1<<2) | ROW (1<<0) = 7
@@ -36,6 +38,8 @@ describe("trigger", () => {
36
38
  trigger,
37
39
  });
38
40
 
41
+ await assertValidSql(change.serialize());
42
+
39
43
  expect(change.serialize()).toBe(
40
44
  "CREATE TRIGGER test_trigger BEFORE INSERT ON public.test_table FOR EACH ROW EXECUTE FUNCTION public.test_function()",
41
45
  );
@@ -60,10 +60,13 @@ export class CreateTrigger extends CreateTriggerChange {
60
60
  );
61
61
 
62
62
  // Function dependency
63
- // Note: We can't build the exact procedure stableId without argument types.
64
- // The trigger definition contains the full function call, but parsing it would be complex.
65
- // For now, we rely on pg_depend extraction for procedure dependencies.
66
- // If needed, we could parse the trigger definition to extract the full function signature.
63
+ // Trigger functions always have signature () RETURNS trigger, so no arguments.
64
+ dependencies.add(
65
+ stableId.procedure(
66
+ this.trigger.function_schema,
67
+ this.trigger.function_name,
68
+ ),
69
+ );
67
70
 
68
71
  // Owner dependency
69
72
  dependencies.add(stableId.role(this.trigger.owner));
@@ -1,13 +1,15 @@
1
1
  import { describe, expect, test } from "bun:test";
2
+ import { assertValidSql } from "../../../test-utils/assert-valid-sql.ts";
2
3
  import { Trigger } from "../trigger.model.ts";
3
4
  import { DropTrigger } from "./trigger.drop.ts";
4
5
 
5
6
  describe("trigger", () => {
6
- test("drop", () => {
7
+ test("drop", async () => {
7
8
  const trigger = new Trigger({
8
9
  schema: "public",
9
10
  name: "test_trigger",
10
11
  table_name: "test_table",
12
+ table_relkind: "r",
11
13
  function_schema: "public",
12
14
  function_name: "test_function",
13
15
  trigger_type: 66,
@@ -36,6 +38,8 @@ describe("trigger", () => {
36
38
  trigger,
37
39
  });
38
40
 
41
+ await assertValidSql(change.serialize());
42
+
39
43
  expect(change.serialize()).toBe(
40
44
  "DROP TRIGGER test_trigger ON public.test_table",
41
45
  );
@@ -17,6 +17,7 @@ const base: Omit<
17
17
  schema: "public",
18
18
  name: "trg",
19
19
  table_name: "t",
20
+ table_relkind: "r",
20
21
  function_schema: "public",
21
22
  trigger_type: 1,
22
23
  enabled: "O",
@@ -10,10 +10,19 @@ const TriggerEnabledSchema = z.enum([
10
10
  "A", // ALWAYS - trigger fires regardless of replication mode
11
11
  ]);
12
12
 
13
+ const TriggerTableRelkindSchema = z.enum([
14
+ "r", // ordinary table
15
+ "p", // partitioned table
16
+ "f", // foreign table
17
+ "v", // view
18
+ "m", // materialized view
19
+ ]);
20
+
13
21
  const triggerPropsSchema = z.object({
14
22
  schema: z.string(),
15
23
  name: z.string(),
16
24
  table_name: z.string(),
25
+ table_relkind: TriggerTableRelkindSchema,
17
26
  function_schema: z.string(),
18
27
  function_name: z.string(),
19
28
  trigger_type: z.number(),
@@ -43,6 +52,7 @@ export class Trigger extends BasePgModel {
43
52
  public readonly schema: TriggerProps["schema"];
44
53
  public readonly name: TriggerProps["name"];
45
54
  public readonly table_name: TriggerProps["table_name"];
55
+ public readonly table_relkind: TriggerProps["table_relkind"];
46
56
  public readonly function_schema: TriggerProps["function_schema"];
47
57
  public readonly function_name: TriggerProps["function_name"];
48
58
  public readonly trigger_type: TriggerProps["trigger_type"];
@@ -72,6 +82,7 @@ export class Trigger extends BasePgModel {
72
82
  this.schema = props.schema;
73
83
  this.name = props.name;
74
84
  this.table_name = props.table_name;
85
+ this.table_relkind = props.table_relkind;
75
86
 
76
87
  // Data fields
77
88
  this.function_schema = props.function_schema;
@@ -164,6 +175,7 @@ export async function extractTriggers(pool: Pool): Promise<Trigger[]> {
164
175
  tc.relnamespace::regnamespace::text as schema,
165
176
  quote_ident(t.tgname) as name,
166
177
  quote_ident(tc.relname) as table_name,
178
+ tc.relkind as table_relkind,
167
179
 
168
180
  fc.pronamespace::regnamespace::text as function_schema,
169
181
  quote_ident(fc.proname) as function_name,