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

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
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Catalog export command - extract a database catalog and save as a snapshot JSON file.
3
+ */
4
+
5
+ import { writeFile } from "node:fs/promises";
6
+ import { buildCommand, type CommandContext } from "@stricli/core";
7
+ import { extractCatalog } from "../../core/catalog.model.ts";
8
+ import {
9
+ serializeCatalog,
10
+ stringifyCatalogSnapshot,
11
+ } from "../../core/catalog.snapshot.ts";
12
+ import { createManagedPool } from "../../core/postgres-config.ts";
13
+
14
+ export const catalogExportCommand = buildCommand({
15
+ parameters: {
16
+ flags: {
17
+ target: {
18
+ kind: "parsed",
19
+ brief: "Target database connection URL to extract the catalog from",
20
+ parse: String,
21
+ },
22
+ output: {
23
+ kind: "parsed",
24
+ brief: "Output file path for the catalog snapshot JSON",
25
+ parse: String,
26
+ },
27
+ role: {
28
+ kind: "parsed",
29
+ brief: "Role to use when extracting the catalog (SET ROLE)",
30
+ parse: String,
31
+ optional: true,
32
+ },
33
+ },
34
+ aliases: {
35
+ t: "target",
36
+ o: "output",
37
+ },
38
+ },
39
+ docs: {
40
+ brief: "Export a database catalog as a snapshot JSON file",
41
+ fullDescription: `
42
+ Extract the full catalog from a live PostgreSQL database and save it
43
+ as a JSON snapshot file. The snapshot can later be used as --source or
44
+ --target for the plan and declarative export commands, enabling
45
+ offline diffing without a live database connection.
46
+
47
+ Use cases:
48
+ - Snapshot template1 for use as an empty-database baseline
49
+ - Snapshot a production database to generate revert migrations
50
+ - Snapshot any state for reproducible offline diffs
51
+ `.trim(),
52
+ },
53
+ async func(
54
+ this: CommandContext,
55
+ flags: {
56
+ target: string;
57
+ output: string;
58
+ role?: string;
59
+ },
60
+ ) {
61
+ const { pool, close } = await createManagedPool(flags.target, {
62
+ role: flags.role,
63
+ label: "target",
64
+ });
65
+
66
+ try {
67
+ const catalog = await extractCatalog(pool);
68
+ const snapshot = serializeCatalog(catalog);
69
+ const json = stringifyCatalogSnapshot(snapshot);
70
+ await writeFile(flags.output, json, "utf-8");
71
+ this.process.stdout.write(
72
+ `Catalog snapshot written to ${flags.output}\n`,
73
+ );
74
+ } finally {
75
+ await close();
76
+ }
77
+ },
78
+ });
@@ -0,0 +1,77 @@
1
+ import { describe, expect, test } from "bun:test";
2
+ import type { Diagnostic } from "@supabase/pg-topo";
3
+ import {
4
+ buildDiagnosticDisplayItems,
5
+ type DiagnosticDisplayEntry,
6
+ } from "../utils/apply-display.ts";
7
+
8
+ const unresolvedDiagnostic = (message: string): Diagnostic => ({
9
+ code: "UNRESOLVED_DEPENDENCY",
10
+ message,
11
+ details: {
12
+ requiredObjectKey: "function:public:json_build_object:(unknown,unknown)",
13
+ },
14
+ suggestedFix: "Add the missing statement.",
15
+ });
16
+
17
+ describe("declarative apply diagnostic display grouping", () => {
18
+ test("grouped mode collapses repeated unresolved diagnostics", () => {
19
+ const entries: DiagnosticDisplayEntry[] = [
20
+ {
21
+ diagnostic: unresolvedDiagnostic(
22
+ "No producer found for 'function:public:json_build_object:(unknown,unknown)'.",
23
+ ),
24
+ location: "schemas/public/tables/user.sql:38:1",
25
+ requiredObjectKey:
26
+ "function:public:json_build_object:(unknown,unknown)",
27
+ },
28
+ {
29
+ diagnostic: unresolvedDiagnostic(
30
+ "No producer found for 'function:public:json_build_object:(unknown,unknown)'.",
31
+ ),
32
+ location: "schemas/public/tables/user.sql:45:1",
33
+ requiredObjectKey:
34
+ "function:public:json_build_object:(unknown,unknown)",
35
+ },
36
+ ];
37
+
38
+ const displayItems = buildDiagnosticDisplayItems(entries, true);
39
+
40
+ expect(displayItems).toHaveLength(1);
41
+ expect(displayItems[0]?.locations).toEqual([
42
+ "schemas/public/tables/user.sql:38:1",
43
+ "schemas/public/tables/user.sql:45:1",
44
+ ]);
45
+ });
46
+
47
+ test("ungrouped mode keeps full per-diagnostic detail", () => {
48
+ const entries: DiagnosticDisplayEntry[] = [
49
+ {
50
+ diagnostic: unresolvedDiagnostic(
51
+ "No producer found for 'function:public:json_build_object:(unknown,unknown)'.",
52
+ ),
53
+ location: "schemas/public/tables/user.sql:38:1",
54
+ requiredObjectKey:
55
+ "function:public:json_build_object:(unknown,unknown)",
56
+ },
57
+ {
58
+ diagnostic: unresolvedDiagnostic(
59
+ "No producer found for 'function:public:json_build_object:(unknown,unknown)'.",
60
+ ),
61
+ location: "schemas/public/tables/user.sql:45:1",
62
+ requiredObjectKey:
63
+ "function:public:json_build_object:(unknown,unknown)",
64
+ },
65
+ ];
66
+
67
+ const displayItems = buildDiagnosticDisplayItems(entries, false);
68
+
69
+ expect(displayItems).toHaveLength(2);
70
+ expect(displayItems[0]?.locations).toEqual([
71
+ "schemas/public/tables/user.sql:38:1",
72
+ ]);
73
+ expect(displayItems[1]?.locations).toEqual([
74
+ "schemas/public/tables/user.sql:45:1",
75
+ ]);
76
+ });
77
+ });
@@ -0,0 +1,380 @@
1
+ /**
2
+ * Declarative-apply command - apply a declarative SQL schema to a database
3
+ * using pg-topo static analysis + round-based execution.
4
+ */
5
+
6
+ import { readFile } from "node:fs/promises";
7
+ import { buildCommand, type CommandContext } from "@stricli/core";
8
+ import chalk from "chalk";
9
+ import { loadDeclarativeSchema } from "../../core/declarative-apply/discover-sql.ts";
10
+ import {
11
+ applyDeclarativeSchema,
12
+ type DeclarativeApplyResult,
13
+ type RoundResult,
14
+ } from "../../core/declarative-apply/index.ts";
15
+ import {
16
+ buildDiagnosticDisplayItems,
17
+ type DiagnosticDisplayEntry,
18
+ formatStatementError,
19
+ positionToLineColumn,
20
+ requiredObjectKeyFromDiagnostic,
21
+ resolveSqlFilePath,
22
+ } from "../utils/apply-display.ts";
23
+
24
+ export const declarativeApplyCommand = buildCommand({
25
+ parameters: {
26
+ flags: {
27
+ path: {
28
+ kind: "parsed",
29
+ brief:
30
+ "Path to the declarative schema directory (containing .sql files) or a single .sql file",
31
+ parse: String,
32
+ },
33
+ target: {
34
+ kind: "parsed",
35
+ brief: "Target database connection URL to apply the schema to",
36
+ parse: String,
37
+ },
38
+ "max-rounds": {
39
+ kind: "parsed",
40
+ brief:
41
+ "Maximum number of application rounds before giving up (default: 100)",
42
+ parse: Number,
43
+ optional: true,
44
+ },
45
+ "no-validate-functions": {
46
+ kind: "boolean",
47
+ brief: "Skip final function body validation pass",
48
+ optional: true,
49
+ },
50
+ verbose: {
51
+ kind: "boolean",
52
+ brief: "Show detailed per-round progress",
53
+ optional: true,
54
+ },
55
+ "ungroup-diagnostics": {
56
+ kind: "boolean",
57
+ brief:
58
+ "Show full per-diagnostic detail instead of grouped summary output",
59
+ optional: true,
60
+ },
61
+ },
62
+ aliases: {
63
+ p: "path",
64
+ t: "target",
65
+ v: "verbose",
66
+ },
67
+ },
68
+ docs: {
69
+ brief: "Apply a declarative SQL schema to a database",
70
+ fullDescription: `
71
+ Apply SQL files from a declarative schema directory to a target database.
72
+
73
+ Uses pg-topo for static dependency analysis and topological ordering,
74
+ then applies statements round-by-round to handle any remaining
75
+ dependency gaps. Statements that fail with dependency errors are
76
+ deferred to subsequent rounds until all succeed or no progress is made.
77
+
78
+ Function body checks are disabled during rounds to avoid false failures
79
+ from functions referencing not-yet-created objects. A final validation
80
+ pass re-runs all function/procedure definitions with body checks enabled.
81
+
82
+ Exit codes:
83
+ 0 - Success (all statements applied)
84
+ 1 - Error (hard failures or validation errors)
85
+ 2 - Stuck (dependency cycle or unresolvable ordering)
86
+
87
+ Tip: Use DEBUG=pg-delta:declarative-apply for detailed defer/skip/fail logs (which statements are deferred and why).
88
+ `.trim(),
89
+ },
90
+ async func(
91
+ this: CommandContext,
92
+ flags: {
93
+ path: string;
94
+ target: string;
95
+ "max-rounds"?: number;
96
+ "no-validate-functions"?: boolean;
97
+ verbose?: boolean;
98
+ "ungroup-diagnostics"?: boolean;
99
+ },
100
+ ) {
101
+ const verbose = !!flags.verbose;
102
+ const ungroupDiagnostics = !!flags["ungroup-diagnostics"];
103
+
104
+ const onRoundComplete = verbose
105
+ ? (round: RoundResult) => {
106
+ const parts = [
107
+ `Round ${round.round}:`,
108
+ chalk.green(`${round.applied} applied`),
109
+ ];
110
+ if (round.deferred > 0) {
111
+ parts.push(chalk.yellow(`${round.deferred} deferred`));
112
+ }
113
+ if (round.failed > 0) {
114
+ parts.push(chalk.red(`${round.failed} failed`));
115
+ }
116
+ this.process.stdout.write(`${parts.join(" ")}\n`);
117
+ }
118
+ : undefined;
119
+
120
+ this.process.stdout.write(`Analyzing SQL files in ${flags.path}...\n`);
121
+
122
+ let content: Array<{ filePath: string; sql: string }>;
123
+ try {
124
+ content = await loadDeclarativeSchema(flags.path);
125
+ } catch (error) {
126
+ this.process.stderr.write(
127
+ `Error: ${error instanceof Error ? error.message : String(error)}\n`,
128
+ );
129
+ process.exitCode = 1;
130
+ return;
131
+ }
132
+
133
+ if (content.length === 0) {
134
+ this.process.stderr.write(
135
+ `No .sql files found in '${flags.path}'. Pass a directory containing .sql files or a single .sql file.\n`,
136
+ );
137
+ process.exitCode = 1;
138
+ return;
139
+ }
140
+
141
+ let result: DeclarativeApplyResult;
142
+ try {
143
+ result = await applyDeclarativeSchema({
144
+ content,
145
+ targetUrl: flags.target,
146
+ maxRounds: flags["max-rounds"],
147
+ validateFunctionBodies: !flags["no-validate-functions"],
148
+ onRoundComplete,
149
+ });
150
+ } catch (error) {
151
+ this.process.stderr.write(
152
+ `Error: ${error instanceof Error ? error.message : String(error)}\n`,
153
+ );
154
+ process.exitCode = 1;
155
+ return;
156
+ }
157
+
158
+ // Report pg-topo diagnostics grouped by severity (least noisy first).
159
+ // UNKNOWN_STATEMENT_CLASS is always hidden; DUPLICATE_PRODUCER,
160
+ // CYCLE_EDGE_SKIPPED, and UNRESOLVED_DEPENDENCY are verbose-only.
161
+ const diagnosticDisplayOrder: Record<string, number> = {
162
+ UNKNOWN_STATEMENT_CLASS: 0,
163
+ DUPLICATE_PRODUCER: 1,
164
+ CYCLE_EDGE_SKIPPED: 2,
165
+ UNRESOLVED_DEPENDENCY: 3,
166
+ };
167
+ const diagnosticColor: Record<string, (s: string) => string> = {
168
+ DUPLICATE_PRODUCER: chalk.yellow,
169
+ CYCLE_EDGE_SKIPPED: chalk.red,
170
+ UNRESOLVED_DEPENDENCY: chalk.dim,
171
+ };
172
+ const verboseOnlyCodes = new Set([
173
+ "UNRESOLVED_DEPENDENCY",
174
+ "DUPLICATE_PRODUCER",
175
+ "CYCLE_EDGE_SKIPPED",
176
+ ]);
177
+ const warnings = result.diagnostics
178
+ .filter(
179
+ (d) =>
180
+ d.code !== "UNKNOWN_STATEMENT_CLASS" &&
181
+ (verbose || !verboseOnlyCodes.has(d.code)),
182
+ )
183
+ .sort(
184
+ (a, b) =>
185
+ (diagnosticDisplayOrder[a.code] ?? 99) -
186
+ (diagnosticDisplayOrder[b.code] ?? 99),
187
+ );
188
+ if (warnings.length > 0 && verbose) {
189
+ const fileContentCache = new Map<string, string>();
190
+ for (const diag of warnings) {
191
+ const id = diag.statementId;
192
+ if (
193
+ id &&
194
+ id.sourceOffset != null &&
195
+ id.filePath &&
196
+ !fileContentCache.has(id.filePath)
197
+ ) {
198
+ // Try to resolve the exact file path of the statement to get the exact location of the error
199
+ try {
200
+ const fullPath = await resolveSqlFilePath(flags.path, id.filePath);
201
+ const content = await readFile(fullPath, "utf-8");
202
+ fileContentCache.set(id.filePath, content);
203
+ } catch {
204
+ // Fall back to statementIndex display
205
+ }
206
+ }
207
+ }
208
+
209
+ this.process.stderr.write(
210
+ chalk.yellow(
211
+ `\n${warnings.length} diagnostic(s) from static analysis:\n`,
212
+ ),
213
+ );
214
+ const entries: DiagnosticDisplayEntry[] = warnings.map((diag) => {
215
+ let location: string | undefined;
216
+ if (diag.statementId) {
217
+ const id = diag.statementId;
218
+ const offset = id.sourceOffset;
219
+ const content =
220
+ offset != null ? fileContentCache.get(id.filePath) : undefined;
221
+ if (content != null && offset != null) {
222
+ const { line, column } = positionToLineColumn(content, offset + 1);
223
+ location = `${id.filePath}:${line}:${column}`;
224
+ } else {
225
+ location = `${id.filePath}:${id.statementIndex}`;
226
+ }
227
+ }
228
+ return {
229
+ diagnostic: diag,
230
+ location,
231
+ requiredObjectKey: requiredObjectKeyFromDiagnostic(diag),
232
+ };
233
+ });
234
+ const displayItems = buildDiagnosticDisplayItems(
235
+ entries,
236
+ !ungroupDiagnostics,
237
+ );
238
+
239
+ let lastCode = "";
240
+ const previewLimit = 5;
241
+ for (const item of displayItems) {
242
+ if (item.code !== lastCode) {
243
+ if (lastCode !== "") {
244
+ this.process.stderr.write("\n");
245
+ }
246
+ lastCode = item.code;
247
+ }
248
+ const colorFn = diagnosticColor[item.code] ?? chalk.yellow;
249
+ const location =
250
+ item.locations.length > 0 ? ` (${item.locations[0]})` : "";
251
+ const occurrences =
252
+ !ungroupDiagnostics && item.locations.length > 1
253
+ ? ` x${item.locations.length}`
254
+ : "";
255
+ this.process.stderr.write(
256
+ colorFn(
257
+ ` [${item.code}]${location}${occurrences} ${item.message}\n`,
258
+ ),
259
+ );
260
+ if (!ungroupDiagnostics && item.requiredObjectKey) {
261
+ this.process.stderr.write(
262
+ colorFn(` -> Object: ${item.requiredObjectKey}\n`),
263
+ );
264
+ }
265
+ if (!ungroupDiagnostics && item.locations.length > 1) {
266
+ for (const locationEntry of item.locations.slice(0, previewLimit)) {
267
+ this.process.stderr.write(colorFn(` at ${locationEntry}\n`));
268
+ }
269
+ const remaining = item.locations.length - previewLimit;
270
+ if (remaining > 0) {
271
+ this.process.stderr.write(
272
+ colorFn(` ... and ${remaining} more location(s)\n`),
273
+ );
274
+ }
275
+ }
276
+ if (item.suggestedFix) {
277
+ this.process.stderr.write(
278
+ colorFn(` -> Fix: ${item.suggestedFix}\n`),
279
+ );
280
+ }
281
+ }
282
+ this.process.stderr.write("\n");
283
+ }
284
+
285
+ const { apply } = result;
286
+
287
+ // Summary
288
+ this.process.stdout.write("\n");
289
+ this.process.stdout.write(
290
+ `Statements: ${result.totalStatements} total, ${apply.totalApplied} applied`,
291
+ );
292
+ if (apply.totalSkipped > 0) {
293
+ this.process.stdout.write(`, ${apply.totalSkipped} skipped`);
294
+ }
295
+ this.process.stdout.write("\n");
296
+ this.process.stdout.write(`Rounds: ${apply.totalRounds}\n`);
297
+
298
+ switch (apply.status) {
299
+ case "success": {
300
+ this.process.stdout.write(
301
+ chalk.green("All statements applied successfully.\n"),
302
+ );
303
+ if (apply.validationErrors && apply.validationErrors.length > 0) {
304
+ this.process.stderr.write(
305
+ chalk.yellow(
306
+ `\n${apply.validationErrors.length} function body validation error(s):\n`,
307
+ ),
308
+ );
309
+ for (const err of apply.validationErrors) {
310
+ const formatted = await formatStatementError(err, flags.path);
311
+ this.process.stderr.write(chalk.yellow(formatted));
312
+ this.process.stderr.write("\n\n");
313
+ }
314
+ process.exitCode = 1;
315
+ } else {
316
+ process.exitCode = 0;
317
+ }
318
+ break;
319
+ }
320
+
321
+ case "stuck": {
322
+ this.process.stderr.write(
323
+ chalk.red(
324
+ `\nStuck after ${apply.totalRounds} round(s). ${apply.stuckStatements?.length ?? 0} statement(s) could not be applied:\n`,
325
+ ),
326
+ );
327
+ if (apply.stuckStatements) {
328
+ for (const stuck of apply.stuckStatements) {
329
+ const formatted = await formatStatementError(stuck, flags.path);
330
+ this.process.stderr.write(chalk.red(formatted));
331
+ this.process.stderr.write("\n\n");
332
+ }
333
+ }
334
+ if (apply.errors && apply.errors.length > 0) {
335
+ this.process.stderr.write(
336
+ chalk.red(
337
+ `\nAdditionally, ${apply.errors.length} statement(s) had non-dependency errors:\n`,
338
+ ),
339
+ );
340
+ for (const err of apply.errors) {
341
+ const formatted = await formatStatementError(err, flags.path);
342
+ this.process.stderr.write(chalk.red(formatted));
343
+ this.process.stderr.write("\n\n");
344
+ }
345
+ }
346
+ process.exitCode = 2;
347
+ break;
348
+ }
349
+
350
+ case "error": {
351
+ this.process.stderr.write(
352
+ chalk.red(
353
+ `\nCompleted with errors. ${apply.errors?.length ?? 0} statement(s) failed:\n`,
354
+ ),
355
+ );
356
+ if (apply.errors) {
357
+ for (const err of apply.errors) {
358
+ const formatted = await formatStatementError(err, flags.path);
359
+ this.process.stderr.write(chalk.red(formatted));
360
+ this.process.stderr.write("\n\n");
361
+ }
362
+ }
363
+ if (apply.validationErrors && apply.validationErrors.length > 0) {
364
+ this.process.stderr.write(
365
+ chalk.yellow(
366
+ `\n${apply.validationErrors.length} function body validation error(s):\n`,
367
+ ),
368
+ );
369
+ for (const err of apply.validationErrors) {
370
+ const formatted = await formatStatementError(err, flags.path);
371
+ this.process.stderr.write(chalk.yellow(formatted));
372
+ this.process.stderr.write("\n\n");
373
+ }
374
+ }
375
+ process.exitCode = 1;
376
+ break;
377
+ }
378
+ }
379
+ },
380
+ });