@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
@@ -1,7 +1,6 @@
1
1
  import z from "zod";
2
2
  import type { Change } from "../change.types.ts";
3
- import type { Role } from "./role/role.model.ts";
4
- import { stableId } from "./utils.ts";
3
+ import type { BaseChange } from "./base.change.ts";
5
4
 
6
5
  /**
7
6
  * Privilege properties that all privilege objects share.
@@ -118,7 +117,7 @@ function checkStillHasBase<T extends PrivilegeProps>(
118
117
  /**
119
118
  * Groups privileges by grantable flag for efficient SQL generation
120
119
  */
121
- export function groupPrivilegesByGrantable<T extends PrivilegeProps>(
120
+ function groupPrivilegesByGrantable<T extends PrivilegeProps>(
122
121
  privileges: T[],
123
122
  ): Map<boolean, T[]> {
124
123
  const groups = new Map<boolean, T[]>();
@@ -135,7 +134,7 @@ export function groupPrivilegesByGrantable<T extends PrivilegeProps>(
135
134
  /**
136
135
  * Groups privileges by columns and grantable flag
137
136
  */
138
- export function groupPrivilegesByColumns<T extends PrivilegeProps>(
137
+ function groupPrivilegesByColumns<T extends PrivilegeProps>(
139
138
  privileges: T[],
140
139
  ): Map<string, { columns?: string[]; byGrant: Map<boolean, Set<string>> }> {
141
140
  const groups = new Map<
@@ -236,22 +235,6 @@ function filterOwnerPrivileges<T extends PrivilegeProps>(
236
235
  return privileges.filter((p) => p.grantee !== owner);
237
236
  }
238
237
 
239
- /**
240
- * Filter out privileges for superuser roles, as PostgreSQL doesn't store
241
- * GRANTs to superusers in relacl (they already have all privileges implicitly).
242
- * Reference: https://www.postgresql.org/docs/current/role-attributes.html
243
- */
244
- function filterSuperuserPrivileges<T extends PrivilegeProps>(
245
- privileges: T[],
246
- mainRoles?: Record<string, Role>,
247
- ): T[] {
248
- if (!mainRoles) return privileges;
249
- return privileges.filter((priv) => {
250
- const role = mainRoles[stableId.role(priv.grantee)];
251
- return !role?.is_superuser;
252
- });
253
- }
254
-
255
238
  /**
256
239
  * Generic privilege diffing function that works for any object type
257
240
  */
@@ -259,22 +242,14 @@ export function diffPrivileges<T extends PrivilegeProps>(
259
242
  mainPrivileges: T[],
260
243
  branchPrivileges: T[],
261
244
  owner?: string,
262
- mainRoles?: Record<string, Role>,
263
245
  ): Map<string, PrivilegeDiffResult<T>> {
264
- // Filter out superuser privileges from branch - PostgreSQL doesn't store GRANTs
265
- // to superusers in relacl because they already have all privileges implicitly
266
- const branchPrivilegesFiltered = filterSuperuserPrivileges(
267
- branchPrivileges,
268
- mainRoles,
269
- );
270
-
271
246
  // Filter out owner privileges if owner is provided
272
247
  const mainFiltered = owner
273
248
  ? filterOwnerPrivileges(mainPrivileges, owner)
274
249
  : mainPrivileges;
275
250
  const branchFiltered = owner
276
- ? filterOwnerPrivileges(branchPrivilegesFiltered, owner)
277
- : branchPrivilegesFiltered;
251
+ ? filterOwnerPrivileges(branchPrivileges, owner)
252
+ : branchPrivileges;
278
253
 
279
254
  const mainByGrantee = groupPrivilegesByGrantee(mainFiltered);
280
255
  const branchByGrantee = groupPrivilegesByGrantee(branchFiltered);
@@ -297,3 +272,176 @@ export function diffPrivileges<T extends PrivilegeProps>(
297
272
 
298
273
  return results;
299
274
  }
275
+
276
+ // ==== Privilege Change Emission Helpers ====
277
+ //
278
+ // These helpers convert the output of `diffPrivileges` (per-grantee grant /
279
+ // revoke / revoke-grant-option lists) into concrete Change instances so that
280
+ // individual object diffs don't have to repeat the same iteration and grouping
281
+ // logic.
282
+ //
283
+ // Callers pass a `PrivilegeChangeFactories` bag containing the three class
284
+ // constructors (Grant, Revoke, RevokeGrantOption) for their object type. The
285
+ // helpers instantiate them with a common props shape: an object reference keyed
286
+ // by `objectKey`, a `grantee`, `privileges` or `privilegeNames`, an optional
287
+ // `version`, and (for column-level privileges) optional `columns`.
288
+
289
+ /**
290
+ * Factory constructors for Grant / Revoke / RevokeGrantOption change classes.
291
+ * Every object type provides its own concrete classes. The `any` props type
292
+ * is intentional: the helpers build props with a computed `[objectKey]` key
293
+ * whose name varies per object type, so no single concrete type can unify
294
+ * all call sites without an unsafe cast elsewhere.
295
+ */
296
+ interface PrivilegeChangeFactories {
297
+ Grant: new (
298
+ // biome-ignore lint/suspicious/noExplicitAny: factory accepts heterogeneous prop bags keyed by object type
299
+ props: any,
300
+ ) => BaseChange;
301
+ Revoke: new (
302
+ // biome-ignore lint/suspicious/noExplicitAny: factory accepts heterogeneous prop bags keyed by object type
303
+ props: any,
304
+ ) => BaseChange;
305
+ RevokeGrantOption: new (
306
+ // biome-ignore lint/suspicious/noExplicitAny: factory accepts heterogeneous prop bags keyed by object type
307
+ props: any,
308
+ ) => BaseChange;
309
+ }
310
+
311
+ /**
312
+ * Emit privilege changes for object-level privileges (schema, sequence,
313
+ * procedure, etc.).
314
+ *
315
+ * For each grantee in `privilegeResults` the function groups grants and revokes
316
+ * by the `grantable` flag and pushes one change per group. Revoke-grant-option
317
+ * entries produce a single change carrying `privilegeNames`.
318
+ *
319
+ * `grantTarget` is the *branch* object (the desired state) while `revokeTarget`
320
+ * is the *main* object (the current state), so that GRANTs reference the
321
+ * newly-created/altered object and REVOKEs reference the existing one.
322
+ */
323
+ export function emitObjectPrivilegeChanges(
324
+ privilegeResults: Map<string, PrivilegeDiffResult<PrivilegeProps>>,
325
+ grantTarget: unknown,
326
+ revokeTarget: unknown,
327
+ objectKey: string,
328
+ factories: PrivilegeChangeFactories,
329
+ version?: number,
330
+ ): BaseChange[] {
331
+ const changes: BaseChange[] = [];
332
+
333
+ for (const [grantee, result] of privilegeResults) {
334
+ for (const [, revokes] of groupPrivilegesByGrantable(result.revokes)) {
335
+ changes.push(
336
+ new factories.Revoke({
337
+ [objectKey]: revokeTarget,
338
+ privileges: revokes,
339
+ grantee,
340
+ version,
341
+ }),
342
+ );
343
+ }
344
+ if (result.revokeGrantOption.length > 0) {
345
+ changes.push(
346
+ new factories.RevokeGrantOption({
347
+ [objectKey]: revokeTarget,
348
+ privilegeNames: result.revokeGrantOption,
349
+ grantee,
350
+ version,
351
+ }),
352
+ );
353
+ }
354
+ for (const [, grants] of groupPrivilegesByGrantable(result.grants)) {
355
+ changes.push(
356
+ new factories.Grant({
357
+ [objectKey]: grantTarget,
358
+ privileges: grants,
359
+ grantee,
360
+ version,
361
+ }),
362
+ );
363
+ }
364
+ }
365
+
366
+ return changes;
367
+ }
368
+
369
+ /**
370
+ * Emit privilege changes for column-level privileges (table, view,
371
+ * materialized view).
372
+ *
373
+ * Like {@link emitObjectPrivilegeChanges} but groups by column set (via
374
+ * `groupPrivilegesByColumns`) instead of only by grantable. For
375
+ * revoke-grant-option the column sets come from `sourcePrivileges` so that
376
+ * `REVOKE GRANT OPTION FOR` is emitted per column set that originally carried
377
+ * the privilege.
378
+ */
379
+ export function emitColumnPrivilegeChanges(
380
+ privilegeResults: Map<string, PrivilegeDiffResult<PrivilegeProps>>,
381
+ grantTarget: unknown,
382
+ revokeTarget: unknown,
383
+ objectKey: string,
384
+ factories: PrivilegeChangeFactories,
385
+ sourcePrivileges: PrivilegeProps[],
386
+ version?: number,
387
+ ): BaseChange[] {
388
+ const changes: BaseChange[] = [];
389
+
390
+ for (const [grantee, result] of privilegeResults) {
391
+ for (const [, group] of groupPrivilegesByColumns(result.revokes)) {
392
+ const allPrivileges = new Set<string>();
393
+ for (const [, privSet] of group.byGrant) {
394
+ for (const priv of privSet) {
395
+ allPrivileges.add(priv);
396
+ }
397
+ }
398
+ changes.push(
399
+ new factories.Revoke({
400
+ [objectKey]: revokeTarget,
401
+ privileges: [...allPrivileges].map((p) => ({
402
+ privilege: p,
403
+ grantable: false,
404
+ })),
405
+ grantee,
406
+ columns: group.columns,
407
+ version,
408
+ }),
409
+ );
410
+ }
411
+ if (result.revokeGrantOption.length > 0) {
412
+ const sourcePrivsForGrantee = sourcePrivileges.filter(
413
+ (p) => p.grantee === grantee,
414
+ );
415
+ for (const [, group] of groupPrivilegesByColumns(
416
+ sourcePrivsForGrantee.filter((p) =>
417
+ result.revokeGrantOption.includes(p.privilege),
418
+ ),
419
+ )) {
420
+ changes.push(
421
+ new factories.RevokeGrantOption({
422
+ [objectKey]: revokeTarget,
423
+ privilegeNames: result.revokeGrantOption,
424
+ grantee,
425
+ columns: group.columns,
426
+ version,
427
+ }),
428
+ );
429
+ }
430
+ }
431
+ for (const [, group] of groupPrivilegesByColumns(result.grants)) {
432
+ for (const [grantable, privSet] of group.byGrant) {
433
+ changes.push(
434
+ new factories.Grant({
435
+ [objectKey]: grantTarget,
436
+ privileges: [...privSet].map((p) => ({ privilege: p, grantable })),
437
+ grantee,
438
+ columns: group.columns,
439
+ version,
440
+ }),
441
+ );
442
+ }
443
+ }
444
+ }
445
+
446
+ return changes;
447
+ }
@@ -164,7 +164,7 @@ export function getObjectKindPrefix(objectKind: string): string {
164
164
  case "TYPE":
165
165
  return "ON TYPE";
166
166
  case "FOREIGN TABLE":
167
- return "ON FOREIGN TABLE";
167
+ return "ON TABLE";
168
168
  default:
169
169
  return "ON";
170
170
  }
@@ -176,9 +176,16 @@ export function normalizePrivileges(privileges: PrivilegeProps[]) {
176
176
  grantee: privilege.grantee,
177
177
  privilege: privilege.privilege,
178
178
  grantable: privilege.grantable,
179
+ columns: privilege.columns
180
+ ? [...privilege.columns].sort()
181
+ : privilege.columns,
179
182
  }))
180
183
  .sort((a, b) => {
181
184
  if (a.grantee !== b.grantee) return a.grantee.localeCompare(b.grantee);
182
- return a.privilege.localeCompare(b.privilege);
185
+ if (a.privilege !== b.privilege)
186
+ return a.privilege.localeCompare(b.privilege);
187
+ const colA = a.columns?.join(",") ?? "";
188
+ const colB = b.columns?.join(",") ?? "";
189
+ return colA.localeCompare(colB);
183
190
  });
184
191
  }
@@ -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 { Collation } from "../collation.model.ts";
3
4
  import {
4
5
  AlterCollationChangeOwner,
@@ -7,7 +8,7 @@ import {
7
8
 
8
9
  describe.concurrent("collation", () => {
9
10
  describe("alter", () => {
10
- test("change owner", () => {
11
+ test("change owner", async () => {
11
12
  const collation = new Collation({
12
13
  schema: "public",
13
14
  name: "test",
@@ -28,12 +29,14 @@ describe.concurrent("collation", () => {
28
29
  owner: "new_owner",
29
30
  });
30
31
 
32
+ await assertValidSql(change.serialize());
33
+
31
34
  expect(change.serialize()).toBe(
32
35
  "ALTER COLLATION public.test OWNER TO new_owner",
33
36
  );
34
37
  });
35
38
 
36
- test("refresh version", () => {
39
+ test("refresh version", async () => {
37
40
  const collation = new Collation({
38
41
  schema: "public",
39
42
  name: "test",
@@ -53,6 +56,8 @@ describe.concurrent("collation", () => {
53
56
  collation,
54
57
  });
55
58
 
59
+ await assertValidSql(change.serialize());
60
+
56
61
  expect(change.serialize()).toBe(
57
62
  "ALTER COLLATION public.test REFRESH VERSION",
58
63
  );
@@ -1,9 +1,10 @@
1
1
  import { describe, expect, test } from "bun:test";
2
+ import { assertValidSql } from "../../../test-utils/assert-valid-sql.ts";
2
3
  import { Collation } from "../collation.model.ts";
3
4
  import { CreateCollation } from "./collation.create.ts";
4
5
 
5
6
  describe("collation", () => {
6
- test("create minimal", () => {
7
+ test("create minimal", async () => {
7
8
  const collation = new Collation({
8
9
  schema: "public",
9
10
  name: "test",
@@ -21,12 +22,14 @@ describe("collation", () => {
21
22
 
22
23
  const change = new CreateCollation({ collation });
23
24
 
25
+ await assertValidSql(change.serialize());
26
+
24
27
  expect(change.serialize()).toBe(
25
28
  `CREATE COLLATION public.test (LC_COLLATE = 'C', LC_CTYPE = 'C')`,
26
29
  );
27
30
  });
28
31
 
29
- test("create with all options", () => {
32
+ test("create with all options", async () => {
30
33
  const collation = new Collation({
31
34
  schema: "public",
32
35
  name: "test",
@@ -44,6 +47,8 @@ describe("collation", () => {
44
47
 
45
48
  const change = new CreateCollation({ collation });
46
49
 
50
+ await assertValidSql(change.serialize());
51
+
47
52
  expect(change.serialize()).toBe(
48
53
  `CREATE COLLATION public.test (LOCALE = 'en_US', LC_COLLATE = 'en_US', LC_CTYPE = 'en_US', PROVIDER = icu, DETERMINISTIC = false, RULES = '& A < a <<< à', VERSION = '1.0')`,
49
54
  );
@@ -1,9 +1,10 @@
1
1
  import { describe, expect, test } from "bun:test";
2
+ import { assertValidSql } from "../../../test-utils/assert-valid-sql.ts";
2
3
  import { Collation } from "../collation.model.ts";
3
4
  import { DropCollation } from "./collation.drop.ts";
4
5
 
5
6
  describe("collation", () => {
6
- test("drop", () => {
7
+ test("drop", async () => {
7
8
  const collation = new Collation({
8
9
  schema: "public",
9
10
  name: "test",
@@ -23,6 +24,8 @@ describe("collation", () => {
23
24
  collation,
24
25
  });
25
26
 
27
+ await assertValidSql(change.serialize());
28
+
26
29
  expect(change.serialize()).toBe("DROP COLLATION public.test");
27
30
  });
28
31
  });
@@ -1,4 +1,5 @@
1
1
  import { describe, expect, test } from "bun:test";
2
+ import type { ObjectDiffContext } from "../diff-context.ts";
2
3
  import {
3
4
  AlterCollationChangeOwner,
4
5
  AlterCollationRefreshVersion,
@@ -8,6 +9,10 @@ import { DropCollation } from "./changes/collation.drop.ts";
8
9
  import { diffCollations } from "./collation.diff.ts";
9
10
  import { Collation, type CollationProps } from "./collation.model.ts";
10
11
 
12
+ const ctx: Pick<ObjectDiffContext, "currentUser"> = {
13
+ currentUser: "postgres",
14
+ };
15
+
11
16
  describe.concurrent("collation.diff", () => {
12
17
  test("create and drop", () => {
13
18
  const props: CollationProps = {
@@ -26,19 +31,11 @@ describe.concurrent("collation.diff", () => {
26
31
  };
27
32
  const c = new Collation(props);
28
33
 
29
- const created = diffCollations(
30
- { currentUser: "postgres" },
31
- {},
32
- { [c.stableId]: c },
33
- );
34
+ const created = diffCollations(ctx, {}, { [c.stableId]: c });
34
35
  expect(created).toHaveLength(1);
35
36
  expect(created[0]).toBeInstanceOf(CreateCollation);
36
37
 
37
- const dropped = diffCollations(
38
- { currentUser: "postgres" },
39
- { [c.stableId]: c },
40
- {},
41
- );
38
+ const dropped = diffCollations(ctx, { [c.stableId]: c }, {});
42
39
  expect(dropped).toHaveLength(1);
43
40
  expect(dropped[0]).toBeInstanceOf(DropCollation);
44
41
  });
@@ -60,7 +57,7 @@ describe.concurrent("collation.diff", () => {
60
57
  const branch = new Collation({ ...base, version: "2.0", owner: "o2" });
61
58
 
62
59
  const changes = diffCollations(
63
- { currentUser: "postgres" },
60
+ ctx,
64
61
  { [main.stableId]: main },
65
62
  { [branch.stableId]: branch },
66
63
  );
@@ -89,7 +86,7 @@ describe.concurrent("collation.diff", () => {
89
86
  const main = new Collation({ ...base, provider: "c" });
90
87
  const branch = new Collation({ ...base, provider: "i" });
91
88
  const changes = diffCollations(
92
- { currentUser: "postgres" },
89
+ ctx,
93
90
  { [main.stableId]: main },
94
91
  { [branch.stableId]: branch },
95
92
  );
@@ -1,4 +1,5 @@
1
1
  import { diffObjects } from "../base.diff.ts";
2
+ import type { ObjectDiffContext } from "../diff-context.ts";
2
3
  import { hasNonAlterableChanges } from "../utils.ts";
3
4
  import {
4
5
  AlterCollationChangeOwner,
@@ -22,7 +23,7 @@ import type { Collation } from "./collation.model.ts";
22
23
  * @returns A list of changes to apply to main to make it match branch.
23
24
  */
24
25
  export function diffCollations(
25
- ctx: { currentUser: string },
26
+ ctx: Pick<ObjectDiffContext, "currentUser">,
26
27
  main: Record<string, Collation>,
27
28
  branch: Record<string, Collation>,
28
29
  ): CollationChange[] {
@@ -0,0 +1,16 @@
1
+ import type { DefaultPrivilegeState } from "./base.default-privileges.ts";
2
+ import type { Role } from "./role/role.model.ts";
3
+
4
+ /**
5
+ * Unified context built by `diffCatalogs` and passed to per-object diff
6
+ * functions. Each diff declares only the keys it reads via
7
+ * `Pick<ObjectDiffContext, …>`, so every signature documents its actual
8
+ * requirements. The full object is always assignable to every narrower Pick.
9
+ */
10
+ export interface ObjectDiffContext {
11
+ version: number;
12
+ currentUser: string;
13
+ defaultPrivilegeState: DefaultPrivilegeState;
14
+ mainRoles: Record<string, Role>;
15
+ skipDefaultPrivilegeSubtraction?: boolean;
16
+ }
@@ -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 { Domain, type DomainProps } from "../domain.model.ts";
3
4
  import {
4
5
  AlterDomainAddConstraint,
@@ -13,7 +14,7 @@ import {
13
14
 
14
15
  describe.concurrent("domain", () => {
15
16
  describe("alter", () => {
16
- test("set default", () => {
17
+ test("set default", async () => {
17
18
  const props: Omit<DomainProps, "default_value"> = {
18
19
  schema: "public",
19
20
  name: "test_domain",
@@ -39,12 +40,14 @@ describe.concurrent("domain", () => {
39
40
  defaultValue: "42",
40
41
  });
41
42
 
43
+ await assertValidSql(change.serialize());
44
+
42
45
  expect(change.serialize()).toBe(
43
46
  "ALTER DOMAIN public.test_domain SET DEFAULT 42",
44
47
  );
45
48
  });
46
49
 
47
- test("drop default", () => {
50
+ test("drop default", async () => {
48
51
  const props: Omit<DomainProps, "default_value"> = {
49
52
  schema: "public",
50
53
  name: "test_domain",
@@ -70,12 +73,14 @@ describe.concurrent("domain", () => {
70
73
  domain,
71
74
  });
72
75
 
76
+ await assertValidSql(change.serialize());
77
+
73
78
  expect(change.serialize()).toBe(
74
79
  "ALTER DOMAIN public.test_domain DROP DEFAULT",
75
80
  );
76
81
  });
77
82
 
78
- test("set not null", () => {
83
+ test("set not null", async () => {
79
84
  const props: Omit<DomainProps, "not_null"> = {
80
85
  schema: "public",
81
86
  name: "test_domain",
@@ -101,12 +106,14 @@ describe.concurrent("domain", () => {
101
106
  domain,
102
107
  });
103
108
 
109
+ await assertValidSql(change.serialize());
110
+
104
111
  expect(change.serialize()).toBe(
105
112
  "ALTER DOMAIN public.test_domain SET NOT NULL",
106
113
  );
107
114
  });
108
115
 
109
- test("drop not null", () => {
116
+ test("drop not null", async () => {
110
117
  const props: Omit<DomainProps, "not_null"> = {
111
118
  schema: "public",
112
119
  name: "test_domain",
@@ -132,12 +139,14 @@ describe.concurrent("domain", () => {
132
139
  domain,
133
140
  });
134
141
 
142
+ await assertValidSql(change.serialize());
143
+
135
144
  expect(change.serialize()).toBe(
136
145
  "ALTER DOMAIN public.test_domain DROP NOT NULL",
137
146
  );
138
147
  });
139
148
 
140
- test("change owner", () => {
149
+ test("change owner", async () => {
141
150
  const props: Omit<DomainProps, "owner"> = {
142
151
  schema: "public",
143
152
  name: "test_domain",
@@ -164,12 +173,14 @@ describe.concurrent("domain", () => {
164
173
  owner: "new_owner",
165
174
  });
166
175
 
176
+ await assertValidSql(change.serialize());
177
+
167
178
  expect(change.serialize()).toBe(
168
179
  "ALTER DOMAIN public.test_domain OWNER TO new_owner",
169
180
  );
170
181
  });
171
182
 
172
- test("add constraint", () => {
183
+ test("add constraint", async () => {
173
184
  const props: DomainProps = {
174
185
  schema: "public",
175
186
  name: "test_domain",
@@ -200,12 +211,14 @@ describe.concurrent("domain", () => {
200
211
  },
201
212
  });
202
213
 
214
+ await assertValidSql(change.serialize());
215
+
203
216
  expect(change.serialize()).toBe(
204
217
  "ALTER DOMAIN public.test_domain ADD CONSTRAINT test_check CHECK (VALUE > 0)",
205
218
  );
206
219
  });
207
220
 
208
- test("add constraint not valid", () => {
221
+ test("add constraint not valid", async () => {
209
222
  const props: DomainProps = {
210
223
  schema: "public",
211
224
  name: "test_domain",
@@ -236,12 +249,14 @@ describe.concurrent("domain", () => {
236
249
  },
237
250
  });
238
251
 
252
+ await assertValidSql(change.serialize());
253
+
239
254
  expect(change.serialize()).toBe(
240
255
  "ALTER DOMAIN public.test_domain ADD CONSTRAINT test_check CHECK (VALUE > 0) NOT VALID",
241
256
  );
242
257
  });
243
258
 
244
- test("drop constraint", () => {
259
+ test("drop constraint", async () => {
245
260
  const props: DomainProps = {
246
261
  schema: "public",
247
262
  name: "test_domain",
@@ -272,12 +287,14 @@ describe.concurrent("domain", () => {
272
287
  },
273
288
  });
274
289
 
290
+ await assertValidSql(change.serialize());
291
+
275
292
  expect(change.serialize()).toBe(
276
293
  "ALTER DOMAIN public.test_domain DROP CONSTRAINT test_check",
277
294
  );
278
295
  });
279
296
 
280
- test("validate constraint", () => {
297
+ test("validate constraint", async () => {
281
298
  const props: DomainProps = {
282
299
  schema: "public",
283
300
  name: "test_domain",
@@ -308,6 +325,8 @@ describe.concurrent("domain", () => {
308
325
  },
309
326
  });
310
327
 
328
+ await assertValidSql(change.serialize());
329
+
311
330
  expect(change.serialize()).toBe(
312
331
  "ALTER DOMAIN public.test_domain VALIDATE CONSTRAINT test_check",
313
332
  );
@@ -1,9 +1,10 @@
1
1
  import { describe, expect, test } from "bun:test";
2
+ import { assertValidSql } from "../../../test-utils/assert-valid-sql.ts";
2
3
  import { Domain } from "../domain.model.ts";
3
4
  import { CreateDomain } from "./domain.create.ts";
4
5
 
5
6
  describe("domain", () => {
6
- test("create minimal", () => {
7
+ test("create minimal", async () => {
7
8
  const domain = new Domain({
8
9
  schema: "public",
9
10
  name: "test_domain",
@@ -24,12 +25,14 @@ describe("domain", () => {
24
25
 
25
26
  const change = new CreateDomain({ domain });
26
27
 
28
+ await assertValidSql(change.serialize());
29
+
27
30
  expect(change.serialize()).toBe(
28
31
  "CREATE DOMAIN public.test_domain AS integer",
29
32
  );
30
33
  });
31
34
 
32
- test("create with all options", () => {
35
+ test("create with all options", async () => {
33
36
  const domain = new Domain({
34
37
  schema: "public",
35
38
  name: "test_domain_all",
@@ -58,8 +61,35 @@ describe("domain", () => {
58
61
 
59
62
  const change = new CreateDomain({ domain });
60
63
 
64
+ await assertValidSql(change.serialize());
65
+
61
66
  expect(change.serialize()).toBe(
62
67
  `CREATE DOMAIN public.test_domain_all AS custom.text[][] COLLATE mycoll DEFAULT 'hello' NOT NULL CHECK (VALUE <> '')`,
63
68
  );
64
69
  });
70
+
71
+ test("create with already schema-qualified base type (format_type)", async () => {
72
+ const domain = new Domain({
73
+ schema: "app",
74
+ name: "email_address",
75
+ base_type: "citext",
76
+ base_type_schema: "extensions",
77
+ base_type_str: "extensions.citext",
78
+ not_null: false,
79
+ type_modifier: null,
80
+ array_dimensions: null,
81
+ collation: null,
82
+ default_bin: null,
83
+ default_value: null,
84
+ owner: "test",
85
+ comment: null,
86
+ constraints: [],
87
+ privileges: [],
88
+ });
89
+ const change = new CreateDomain({ domain });
90
+ await assertValidSql(change.serialize());
91
+ expect(change.serialize()).toBe(
92
+ "CREATE DOMAIN app.email_address AS extensions.citext",
93
+ );
94
+ });
65
95
  });