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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (464) hide show
  1. package/README.md +22 -0
  2. package/dist/cli/bin/cli.js +0 -0
  3. package/dist/cli/commands/plan.js +21 -0
  4. package/dist/cli/utils.d.ts +2 -0
  5. package/dist/cli/utils.js +1 -1
  6. package/dist/core/integrations/supabase.js +2 -0
  7. package/dist/core/objects/table/table.model.d.ts +4 -2
  8. package/dist/core/objects/table/table.model.js +3 -0
  9. package/dist/core/objects/trigger/changes/trigger.alter.js +23 -0
  10. package/dist/core/objects/trigger/changes/trigger.create.js +2 -1
  11. package/dist/core/objects/trigger/trigger.model.d.ts +1 -0
  12. package/dist/core/objects/trigger/trigger.model.js +3 -0
  13. package/dist/core/plan/apply.js +3 -3
  14. package/dist/core/plan/create.js +34 -15
  15. package/dist/core/plan/sql-format/constants.d.ts +2 -0
  16. package/dist/core/plan/sql-format/constants.js +11 -0
  17. package/dist/core/plan/sql-format/fixtures.d.ts +2 -0
  18. package/dist/core/plan/sql-format/fixtures.js +2449 -0
  19. package/dist/core/plan/sql-format/format-utils.d.ts +37 -0
  20. package/dist/core/plan/sql-format/format-utils.js +274 -0
  21. package/dist/core/plan/sql-format/formatters.d.ts +20 -0
  22. package/dist/core/plan/sql-format/formatters.js +737 -0
  23. package/dist/core/plan/sql-format/index.d.ts +2 -0
  24. package/dist/core/plan/sql-format/index.js +98 -0
  25. package/dist/core/plan/sql-format/keyword-case.d.ts +2 -0
  26. package/dist/core/plan/sql-format/keyword-case.js +868 -0
  27. package/dist/core/plan/sql-format/protect.d.ts +3 -0
  28. package/dist/core/plan/sql-format/protect.js +269 -0
  29. package/dist/core/plan/sql-format/sql-scanner.d.ts +59 -0
  30. package/dist/core/plan/sql-format/sql-scanner.js +202 -0
  31. package/dist/core/plan/sql-format/tokenizer.d.ts +22 -0
  32. package/dist/core/plan/sql-format/tokenizer.js +118 -0
  33. package/dist/core/plan/sql-format/types.d.ts +28 -0
  34. package/dist/core/plan/sql-format/types.js +1 -0
  35. package/dist/core/plan/sql-format/wrap.d.ts +2 -0
  36. package/dist/core/plan/sql-format/wrap.js +165 -0
  37. package/dist/core/plan/sql-format.d.ts +2 -0
  38. package/dist/core/plan/sql-format.js +1 -0
  39. package/dist/core/plan/statements.d.ts +2 -1
  40. package/dist/core/plan/statements.js +6 -2
  41. package/dist/core/postgres-config.d.ts +15 -0
  42. package/dist/core/postgres-config.js +30 -0
  43. package/dist/index.d.ts +2 -0
  44. package/dist/index.js +1 -0
  45. package/package.json +37 -22
  46. package/src/cli/app.ts +28 -0
  47. package/src/cli/bin/cli.ts +9 -0
  48. package/src/cli/commands/apply.ts +101 -0
  49. package/src/cli/commands/plan.ts +195 -0
  50. package/src/cli/commands/sync.ts +185 -0
  51. package/src/cli/formatters/index.ts +5 -0
  52. package/src/cli/formatters/tree/tree-builder.ts +380 -0
  53. package/src/cli/formatters/tree/tree-renderer.ts +372 -0
  54. package/src/cli/formatters/tree/tree.ts +237 -0
  55. package/src/cli/utils/integrations.ts +42 -0
  56. package/src/cli/utils.ts +231 -0
  57. package/src/core/catalog.diff.ts +246 -0
  58. package/src/core/catalog.model.ts +384 -0
  59. package/src/core/change.types.ts +44 -0
  60. package/src/core/context.ts +26 -0
  61. package/src/core/depend.ts +1870 -0
  62. package/src/core/expand-replace-dependencies.ts +380 -0
  63. package/src/core/fingerprint.ts +204 -0
  64. package/src/core/integrations/filter/dsl.ts +204 -0
  65. package/src/core/integrations/filter/extractors.ts +145 -0
  66. package/src/core/integrations/filter/filter.types.ts +3 -0
  67. package/src/core/integrations/integration-dsl.ts +24 -0
  68. package/src/core/integrations/integration.types.ts +7 -0
  69. package/src/core/integrations/serialize/dsl.ts +77 -0
  70. package/src/core/integrations/serialize/serialize.types.ts +3 -0
  71. package/src/core/integrations/supabase.ts +121 -0
  72. package/src/core/objects/aggregate/aggregate.diff.test.ts +215 -0
  73. package/src/core/objects/aggregate/aggregate.diff.ts +278 -0
  74. package/src/core/objects/aggregate/aggregate.model.ts +317 -0
  75. package/src/core/objects/aggregate/changes/aggregate.alter.test.ts +64 -0
  76. package/src/core/objects/aggregate/changes/aggregate.alter.ts +32 -0
  77. package/src/core/objects/aggregate/changes/aggregate.base.ts +20 -0
  78. package/src/core/objects/aggregate/changes/aggregate.comment.test.ts +86 -0
  79. package/src/core/objects/aggregate/changes/aggregate.comment.ts +62 -0
  80. package/src/core/objects/aggregate/changes/aggregate.create.test.ts +101 -0
  81. package/src/core/objects/aggregate/changes/aggregate.create.ts +329 -0
  82. package/src/core/objects/aggregate/changes/aggregate.drop.test.ts +78 -0
  83. package/src/core/objects/aggregate/changes/aggregate.drop.ts +32 -0
  84. package/src/core/objects/aggregate/changes/aggregate.privilege.test.ts +130 -0
  85. package/src/core/objects/aggregate/changes/aggregate.privilege.ts +146 -0
  86. package/src/core/objects/aggregate/changes/aggregate.types.ts +12 -0
  87. package/src/core/objects/base.change.ts +62 -0
  88. package/src/core/objects/base.default-privileges.ts +204 -0
  89. package/src/core/objects/base.diff.ts +20 -0
  90. package/src/core/objects/base.model.ts +82 -0
  91. package/src/core/objects/base.privilege-diff.ts +299 -0
  92. package/src/core/objects/base.privilege.ts +184 -0
  93. package/src/core/objects/collation/changes/collation.alter.test.ts +63 -0
  94. package/src/core/objects/collation/changes/collation.alter.ts +79 -0
  95. package/src/core/objects/collation/changes/collation.base.ts +20 -0
  96. package/src/core/objects/collation/changes/collation.comment.ts +68 -0
  97. package/src/core/objects/collation/changes/collation.create.test.ts +51 -0
  98. package/src/core/objects/collation/changes/collation.create.ts +106 -0
  99. package/src/core/objects/collation/changes/collation.drop.test.ts +28 -0
  100. package/src/core/objects/collation/changes/collation.drop.ts +37 -0
  101. package/src/core/objects/collation/changes/collation.types.ts +10 -0
  102. package/src/core/objects/collation/collation.diff.test.ts +100 -0
  103. package/src/core/objects/collation/collation.diff.ts +126 -0
  104. package/src/core/objects/collation/collation.model.ts +224 -0
  105. package/src/core/objects/domain/changes/domain.alter.test.ts +316 -0
  106. package/src/core/objects/domain/changes/domain.alter.ts +286 -0
  107. package/src/core/objects/domain/changes/domain.base.ts +20 -0
  108. package/src/core/objects/domain/changes/domain.comment.ts +59 -0
  109. package/src/core/objects/domain/changes/domain.create.test.ts +65 -0
  110. package/src/core/objects/domain/changes/domain.create.ts +118 -0
  111. package/src/core/objects/domain/changes/domain.drop.test.ts +30 -0
  112. package/src/core/objects/domain/changes/domain.drop.ts +34 -0
  113. package/src/core/objects/domain/changes/domain.privilege.ts +171 -0
  114. package/src/core/objects/domain/changes/domain.types.ts +12 -0
  115. package/src/core/objects/domain/domain.diff.test.ts +284 -0
  116. package/src/core/objects/domain/domain.diff.ts +358 -0
  117. package/src/core/objects/domain/domain.model.ts +190 -0
  118. package/src/core/objects/event-trigger/changes/event-trigger.alter.test.ts +50 -0
  119. package/src/core/objects/event-trigger/changes/event-trigger.alter.ts +82 -0
  120. package/src/core/objects/event-trigger/changes/event-trigger.base.ts +20 -0
  121. package/src/core/objects/event-trigger/changes/event-trigger.comment.ts +66 -0
  122. package/src/core/objects/event-trigger/changes/event-trigger.create.test.ts +24 -0
  123. package/src/core/objects/event-trigger/changes/event-trigger.create.ts +72 -0
  124. package/src/core/objects/event-trigger/changes/event-trigger.drop.test.ts +22 -0
  125. package/src/core/objects/event-trigger/changes/event-trigger.drop.ts +34 -0
  126. package/src/core/objects/event-trigger/changes/event-trigger.types.ts +10 -0
  127. package/src/core/objects/event-trigger/event-trigger.diff.test.ts +126 -0
  128. package/src/core/objects/event-trigger/event-trigger.diff.ts +126 -0
  129. package/src/core/objects/event-trigger/event-trigger.model.ts +106 -0
  130. package/src/core/objects/extension/changes/extension.alter.test.ts +58 -0
  131. package/src/core/objects/extension/changes/extension.alter.ts +78 -0
  132. package/src/core/objects/extension/changes/extension.base.ts +20 -0
  133. package/src/core/objects/extension/changes/extension.comment.ts +64 -0
  134. package/src/core/objects/extension/changes/extension.create.test.ts +25 -0
  135. package/src/core/objects/extension/changes/extension.create.ts +63 -0
  136. package/src/core/objects/extension/changes/extension.drop.test.ts +23 -0
  137. package/src/core/objects/extension/changes/extension.drop.ts +34 -0
  138. package/src/core/objects/extension/changes/extension.types.ts +10 -0
  139. package/src/core/objects/extension/extension.diff.test.ts +42 -0
  140. package/src/core/objects/extension/extension.diff.ts +90 -0
  141. package/src/core/objects/extension/extension.model.ts +280 -0
  142. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.alter.test.ts +125 -0
  143. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.alter.ts +101 -0
  144. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.base.ts +20 -0
  145. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.comment.ts +72 -0
  146. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.create.test.ts +125 -0
  147. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.create.ts +95 -0
  148. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.drop.test.ts +23 -0
  149. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.drop.ts +36 -0
  150. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.privilege.ts +172 -0
  151. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.types.ts +12 -0
  152. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/foreign-data-wrapper.diff.test.ts +179 -0
  153. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/foreign-data-wrapper.diff.ts +341 -0
  154. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/foreign-data-wrapper.model.ts +149 -0
  155. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper.types.ts +10 -0
  156. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.alter.test.ts +309 -0
  157. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.alter.ts +341 -0
  158. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.base.ts +20 -0
  159. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.comment.ts +72 -0
  160. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.create.test.ts +201 -0
  161. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.create.ts +81 -0
  162. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.drop.test.ts +43 -0
  163. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.drop.ts +37 -0
  164. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.privilege.ts +181 -0
  165. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.types.ts +12 -0
  166. package/src/core/objects/foreign-data-wrapper/foreign-table/foreign-table.diff.test.ts +813 -0
  167. package/src/core/objects/foreign-data-wrapper/foreign-table/foreign-table.diff.ts +406 -0
  168. package/src/core/objects/foreign-data-wrapper/foreign-table/foreign-table.model.ts +242 -0
  169. package/src/core/objects/foreign-data-wrapper/server/changes/server.alter.test.ts +168 -0
  170. package/src/core/objects/foreign-data-wrapper/server/changes/server.alter.ts +126 -0
  171. package/src/core/objects/foreign-data-wrapper/server/changes/server.base.ts +20 -0
  172. package/src/core/objects/foreign-data-wrapper/server/changes/server.comment.ts +60 -0
  173. package/src/core/objects/foreign-data-wrapper/server/changes/server.create.test.ts +131 -0
  174. package/src/core/objects/foreign-data-wrapper/server/changes/server.create.ts +81 -0
  175. package/src/core/objects/foreign-data-wrapper/server/changes/server.drop.test.ts +24 -0
  176. package/src/core/objects/foreign-data-wrapper/server/changes/server.drop.ts +34 -0
  177. package/src/core/objects/foreign-data-wrapper/server/changes/server.privilege.ts +164 -0
  178. package/src/core/objects/foreign-data-wrapper/server/changes/server.types.ts +12 -0
  179. package/src/core/objects/foreign-data-wrapper/server/server.diff.test.ts +167 -0
  180. package/src/core/objects/foreign-data-wrapper/server/server.diff.ts +317 -0
  181. package/src/core/objects/foreign-data-wrapper/server/server.model.ts +133 -0
  182. package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.alter.test.ts +82 -0
  183. package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.alter.ts +69 -0
  184. package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.base.ts +20 -0
  185. package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.create.test.ts +85 -0
  186. package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.create.ts +66 -0
  187. package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.drop.test.ts +53 -0
  188. package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.drop.ts +40 -0
  189. package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.types.ts +8 -0
  190. package/src/core/objects/foreign-data-wrapper/user-mapping/user-mapping.diff.test.ts +77 -0
  191. package/src/core/objects/foreign-data-wrapper/user-mapping/user-mapping.diff.ts +107 -0
  192. package/src/core/objects/foreign-data-wrapper/user-mapping/user-mapping.model.ts +96 -0
  193. package/src/core/objects/index/changes/index.alter.test.ts +200 -0
  194. package/src/core/objects/index/changes/index.alter.ts +144 -0
  195. package/src/core/objects/index/changes/index.base.ts +20 -0
  196. package/src/core/objects/index/changes/index.comment.ts +63 -0
  197. package/src/core/objects/index/changes/index.create.test.ts +66 -0
  198. package/src/core/objects/index/changes/index.create.ts +68 -0
  199. package/src/core/objects/index/changes/index.drop.test.ts +44 -0
  200. package/src/core/objects/index/changes/index.drop.ts +34 -0
  201. package/src/core/objects/index/changes/index.types.ts +6 -0
  202. package/src/core/objects/index/changes/utils.ts +16 -0
  203. package/src/core/objects/index/index.diff.test.ts +153 -0
  204. package/src/core/objects/index/index.diff.ts +243 -0
  205. package/src/core/objects/index/index.model.ts +370 -0
  206. package/src/core/objects/language/changes/language.alter.test.ts +33 -0
  207. package/src/core/objects/language/changes/language.alter.ts +53 -0
  208. package/src/core/objects/language/changes/language.base.ts +20 -0
  209. package/src/core/objects/language/changes/language.comment.ts +58 -0
  210. package/src/core/objects/language/changes/language.create.test.ts +27 -0
  211. package/src/core/objects/language/changes/language.create.ts +104 -0
  212. package/src/core/objects/language/changes/language.drop.test.ts +25 -0
  213. package/src/core/objects/language/changes/language.drop.ts +39 -0
  214. package/src/core/objects/language/changes/language.privilege.ts +172 -0
  215. package/src/core/objects/language/changes/language.types.ts +12 -0
  216. package/src/core/objects/language/language.diff.test.ts +53 -0
  217. package/src/core/objects/language/language.diff.ts +176 -0
  218. package/src/core/objects/language/language.model.ts +150 -0
  219. package/src/core/objects/materialized-view/changes/materialized-view.alter.test.ts +123 -0
  220. package/src/core/objects/materialized-view/changes/materialized-view.alter.ts +113 -0
  221. package/src/core/objects/materialized-view/changes/materialized-view.base.ts +20 -0
  222. package/src/core/objects/materialized-view/changes/materialized-view.comment.ts +176 -0
  223. package/src/core/objects/materialized-view/changes/materialized-view.create.test.ts +64 -0
  224. package/src/core/objects/materialized-view/changes/materialized-view.create.ts +93 -0
  225. package/src/core/objects/materialized-view/changes/materialized-view.drop.test.ts +34 -0
  226. package/src/core/objects/materialized-view/changes/materialized-view.drop.ts +60 -0
  227. package/src/core/objects/materialized-view/changes/materialized-view.privilege.ts +212 -0
  228. package/src/core/objects/materialized-view/changes/materialized-view.types.ts +12 -0
  229. package/src/core/objects/materialized-view/materialized-view.diff.test.ts +102 -0
  230. package/src/core/objects/materialized-view/materialized-view.diff.ts +451 -0
  231. package/src/core/objects/materialized-view/materialized-view.model.ts +258 -0
  232. package/src/core/objects/procedure/changes/procedure.alter.test.ts +1005 -0
  233. package/src/core/objects/procedure/changes/procedure.alter.ts +287 -0
  234. package/src/core/objects/procedure/changes/procedure.base.ts +20 -0
  235. package/src/core/objects/procedure/changes/procedure.comment.ts +70 -0
  236. package/src/core/objects/procedure/changes/procedure.create.test.ts +48 -0
  237. package/src/core/objects/procedure/changes/procedure.create.ts +92 -0
  238. package/src/core/objects/procedure/changes/procedure.drop.test.ts +85 -0
  239. package/src/core/objects/procedure/changes/procedure.drop.ts +49 -0
  240. package/src/core/objects/procedure/changes/procedure.privilege.ts +188 -0
  241. package/src/core/objects/procedure/changes/procedure.types.ts +12 -0
  242. package/src/core/objects/procedure/procedure.diff.test.ts +161 -0
  243. package/src/core/objects/procedure/procedure.diff.ts +404 -0
  244. package/src/core/objects/procedure/procedure.model.ts +264 -0
  245. package/src/core/objects/procedure/utils.ts +58 -0
  246. package/src/core/objects/publication/changes/publication.alter.test.ts +223 -0
  247. package/src/core/objects/publication/changes/publication.alter.ts +243 -0
  248. package/src/core/objects/publication/changes/publication.base.ts +20 -0
  249. package/src/core/objects/publication/changes/publication.comment.test.ts +70 -0
  250. package/src/core/objects/publication/changes/publication.comment.ts +64 -0
  251. package/src/core/objects/publication/changes/publication.create.test.ts +87 -0
  252. package/src/core/objects/publication/changes/publication.create.ts +82 -0
  253. package/src/core/objects/publication/changes/publication.drop.test.ts +46 -0
  254. package/src/core/objects/publication/changes/publication.drop.ts +29 -0
  255. package/src/core/objects/publication/changes/publication.types.ts +26 -0
  256. package/src/core/objects/publication/publication.diff.test.ts +292 -0
  257. package/src/core/objects/publication/publication.diff.ts +253 -0
  258. package/src/core/objects/publication/publication.model.ts +206 -0
  259. package/src/core/objects/publication/utils.ts +55 -0
  260. package/src/core/objects/rls-policy/changes/rls-policy.alter.test.ts +250 -0
  261. package/src/core/objects/rls-policy/changes/rls-policy.alter.ts +128 -0
  262. package/src/core/objects/rls-policy/changes/rls-policy.base.ts +20 -0
  263. package/src/core/objects/rls-policy/changes/rls-policy.comment.ts +69 -0
  264. package/src/core/objects/rls-policy/changes/rls-policy.create.test.ts +74 -0
  265. package/src/core/objects/rls-policy/changes/rls-policy.create.ts +100 -0
  266. package/src/core/objects/rls-policy/changes/rls-policy.drop.test.ts +28 -0
  267. package/src/core/objects/rls-policy/changes/rls-policy.drop.ts +39 -0
  268. package/src/core/objects/rls-policy/changes/rls-policy.types.ts +10 -0
  269. package/src/core/objects/rls-policy/rls-policy.diff.test.ts +79 -0
  270. package/src/core/objects/rls-policy/rls-policy.diff.ts +121 -0
  271. package/src/core/objects/rls-policy/rls-policy.model.ts +140 -0
  272. package/src/core/objects/role/changes/role.alter.test.ts +346 -0
  273. package/src/core/objects/role/changes/role.alter.ts +110 -0
  274. package/src/core/objects/role/changes/role.base.ts +24 -0
  275. package/src/core/objects/role/changes/role.comment.ts +55 -0
  276. package/src/core/objects/role/changes/role.create.test.ts +52 -0
  277. package/src/core/objects/role/changes/role.create.ts +102 -0
  278. package/src/core/objects/role/changes/role.drop.test.ts +29 -0
  279. package/src/core/objects/role/changes/role.drop.ts +34 -0
  280. package/src/core/objects/role/changes/role.privilege.ts +376 -0
  281. package/src/core/objects/role/changes/role.types.ts +12 -0
  282. package/src/core/objects/role/role.diff.test.ts +44 -0
  283. package/src/core/objects/role/role.diff.ts +479 -0
  284. package/src/core/objects/role/role.model.ts +344 -0
  285. package/src/core/objects/rule/changes/rule.alter.test.ts +78 -0
  286. package/src/core/objects/rule/changes/rule.alter.ts +72 -0
  287. package/src/core/objects/rule/changes/rule.base.ts +20 -0
  288. package/src/core/objects/rule/changes/rule.comment.test.ts +55 -0
  289. package/src/core/objects/rule/changes/rule.comment.ts +62 -0
  290. package/src/core/objects/rule/changes/rule.create.test.ts +59 -0
  291. package/src/core/objects/rule/changes/rule.create.ts +42 -0
  292. package/src/core/objects/rule/changes/rule.drop.test.ts +38 -0
  293. package/src/core/objects/rule/changes/rule.drop.ts +29 -0
  294. package/src/core/objects/rule/changes/rule.types.ts +12 -0
  295. package/src/core/objects/rule/rule.diff.test.ts +132 -0
  296. package/src/core/objects/rule/rule.diff.ts +79 -0
  297. package/src/core/objects/rule/rule.model.ts +173 -0
  298. package/src/core/objects/schema/changes/schema.alter.test.ts +28 -0
  299. package/src/core/objects/schema/changes/schema.alter.ts +45 -0
  300. package/src/core/objects/schema/changes/schema.base.ts +20 -0
  301. package/src/core/objects/schema/changes/schema.comment.ts +56 -0
  302. package/src/core/objects/schema/changes/schema.create.test.ts +22 -0
  303. package/src/core/objects/schema/changes/schema.create.ts +47 -0
  304. package/src/core/objects/schema/changes/schema.drop.test.ts +20 -0
  305. package/src/core/objects/schema/changes/schema.drop.ts +34 -0
  306. package/src/core/objects/schema/changes/schema.privilege.ts +175 -0
  307. package/src/core/objects/schema/changes/schema.types.ts +12 -0
  308. package/src/core/objects/schema/schema.diff.test.ts +42 -0
  309. package/src/core/objects/schema/schema.diff.ts +209 -0
  310. package/src/core/objects/schema/schema.model.ts +107 -0
  311. package/src/core/objects/sequence/changes/sequence.alter.test.ts +151 -0
  312. package/src/core/objects/sequence/changes/sequence.alter.ts +115 -0
  313. package/src/core/objects/sequence/changes/sequence.base.ts +20 -0
  314. package/src/core/objects/sequence/changes/sequence.comment.ts +60 -0
  315. package/src/core/objects/sequence/changes/sequence.create.test.ts +84 -0
  316. package/src/core/objects/sequence/changes/sequence.create.ts +111 -0
  317. package/src/core/objects/sequence/changes/sequence.drop.test.ts +32 -0
  318. package/src/core/objects/sequence/changes/sequence.drop.ts +37 -0
  319. package/src/core/objects/sequence/changes/sequence.privilege.ts +179 -0
  320. package/src/core/objects/sequence/changes/sequence.types.ts +12 -0
  321. package/src/core/objects/sequence/sequence.diff.test.ts +141 -0
  322. package/src/core/objects/sequence/sequence.diff.ts +359 -0
  323. package/src/core/objects/sequence/sequence.model.ts +185 -0
  324. package/src/core/objects/subscription/changes/subscription.alter.test.ts +124 -0
  325. package/src/core/objects/subscription/changes/subscription.alter.ts +110 -0
  326. package/src/core/objects/subscription/changes/subscription.base.ts +20 -0
  327. package/src/core/objects/subscription/changes/subscription.comment.test.ts +67 -0
  328. package/src/core/objects/subscription/changes/subscription.comment.ts +64 -0
  329. package/src/core/objects/subscription/changes/subscription.create.test.ts +77 -0
  330. package/src/core/objects/subscription/changes/subscription.create.ts +69 -0
  331. package/src/core/objects/subscription/changes/subscription.drop.test.ts +46 -0
  332. package/src/core/objects/subscription/changes/subscription.drop.ts +20 -0
  333. package/src/core/objects/subscription/changes/subscription.types.ts +22 -0
  334. package/src/core/objects/subscription/subscription.diff.test.ts +232 -0
  335. package/src/core/objects/subscription/subscription.diff.ts +241 -0
  336. package/src/core/objects/subscription/subscription.model.ts +190 -0
  337. package/src/core/objects/subscription/utils.ts +156 -0
  338. package/src/core/objects/table/changes/table.alter.test.ts +823 -0
  339. package/src/core/objects/table/changes/table.alter.ts +806 -0
  340. package/src/core/objects/table/changes/table.base.ts +20 -0
  341. package/src/core/objects/table/changes/table.comment.ts +266 -0
  342. package/src/core/objects/table/changes/table.create.test.ts +150 -0
  343. package/src/core/objects/table/changes/table.create.ts +188 -0
  344. package/src/core/objects/table/changes/table.drop.test.ts +34 -0
  345. package/src/core/objects/table/changes/table.drop.ts +45 -0
  346. package/src/core/objects/table/changes/table.privilege.ts +200 -0
  347. package/src/core/objects/table/changes/table.types.ts +12 -0
  348. package/src/core/objects/table/table.diff.test.ts +711 -0
  349. package/src/core/objects/table/table.diff.ts +953 -0
  350. package/src/core/objects/table/table.model.ts +460 -0
  351. package/src/core/objects/trigger/changes/trigger.alter.test.ts +46 -0
  352. package/src/core/objects/trigger/changes/trigger.alter.ts +76 -0
  353. package/src/core/objects/trigger/changes/trigger.base.ts +20 -0
  354. package/src/core/objects/trigger/changes/trigger.comment.ts +64 -0
  355. package/src/core/objects/trigger/changes/trigger.create.test.ts +43 -0
  356. package/src/core/objects/trigger/changes/trigger.create.ts +85 -0
  357. package/src/core/objects/trigger/changes/trigger.drop.test.ts +43 -0
  358. package/src/core/objects/trigger/changes/trigger.drop.ts +39 -0
  359. package/src/core/objects/trigger/changes/trigger.types.ts +10 -0
  360. package/src/core/objects/trigger/trigger.diff.test.ts +83 -0
  361. package/src/core/objects/trigger/trigger.diff.ts +116 -0
  362. package/src/core/objects/trigger/trigger.model.ts +252 -0
  363. package/src/core/objects/type/composite-type/changes/composite-type.alter.test.ts +202 -0
  364. package/src/core/objects/type/composite-type/changes/composite-type.alter.ts +174 -0
  365. package/src/core/objects/type/composite-type/changes/composite-type.base.ts +20 -0
  366. package/src/core/objects/type/composite-type/changes/composite-type.comment.ts +145 -0
  367. package/src/core/objects/type/composite-type/changes/composite-type.create.test.ts +101 -0
  368. package/src/core/objects/type/composite-type/changes/composite-type.create.ts +95 -0
  369. package/src/core/objects/type/composite-type/changes/composite-type.drop.test.ts +33 -0
  370. package/src/core/objects/type/composite-type/changes/composite-type.drop.ts +37 -0
  371. package/src/core/objects/type/composite-type/changes/composite-type.privilege.ts +175 -0
  372. package/src/core/objects/type/composite-type/changes/composite-type.types.ts +12 -0
  373. package/src/core/objects/type/composite-type/composite-type.diff.test.ts +191 -0
  374. package/src/core/objects/type/composite-type/composite-type.diff.ts +372 -0
  375. package/src/core/objects/type/composite-type/composite-type.model.ts +252 -0
  376. package/src/core/objects/type/enum/changes/enum.alter.test.ts +104 -0
  377. package/src/core/objects/type/enum/changes/enum.alter.ts +91 -0
  378. package/src/core/objects/type/enum/changes/enum.base.ts +20 -0
  379. package/src/core/objects/type/enum/changes/enum.comment.ts +64 -0
  380. package/src/core/objects/type/enum/changes/enum.create.test.ts +28 -0
  381. package/src/core/objects/type/enum/changes/enum.create.ts +56 -0
  382. package/src/core/objects/type/enum/changes/enum.drop.test.ts +25 -0
  383. package/src/core/objects/type/enum/changes/enum.drop.ts +34 -0
  384. package/src/core/objects/type/enum/changes/enum.privilege.ts +175 -0
  385. package/src/core/objects/type/enum/changes/enum.types.ts +12 -0
  386. package/src/core/objects/type/enum/enum.diff.test.ts +191 -0
  387. package/src/core/objects/type/enum/enum.diff.ts +396 -0
  388. package/src/core/objects/type/enum/enum.model.ts +194 -0
  389. package/src/core/objects/type/range/changes/range.alter.test.ts +27 -0
  390. package/src/core/objects/type/range/changes/range.alter.ts +51 -0
  391. package/src/core/objects/type/range/changes/range.base.ts +20 -0
  392. package/src/core/objects/type/range/changes/range.comment.ts +64 -0
  393. package/src/core/objects/type/range/changes/range.create.test.ts +51 -0
  394. package/src/core/objects/type/range/changes/range.create.ts +151 -0
  395. package/src/core/objects/type/range/changes/range.drop.test.ts +26 -0
  396. package/src/core/objects/type/range/changes/range.drop.ts +34 -0
  397. package/src/core/objects/type/range/changes/range.privilege.ts +175 -0
  398. package/src/core/objects/type/range/changes/range.types.ts +12 -0
  399. package/src/core/objects/type/range/range.diff.test.ts +70 -0
  400. package/src/core/objects/type/range/range.diff.ts +259 -0
  401. package/src/core/objects/type/range/range.model.ts +187 -0
  402. package/src/core/objects/type/type.types.ts +5 -0
  403. package/src/core/objects/utils.ts +171 -0
  404. package/src/core/objects/view/changes/view.alter.test.ts +110 -0
  405. package/src/core/objects/view/changes/view.alter.ts +112 -0
  406. package/src/core/objects/view/changes/view.base.ts +20 -0
  407. package/src/core/objects/view/changes/view.comment.ts +59 -0
  408. package/src/core/objects/view/changes/view.create.test.ts +65 -0
  409. package/src/core/objects/view/changes/view.create.ts +73 -0
  410. package/src/core/objects/view/changes/view.drop.test.ts +34 -0
  411. package/src/core/objects/view/changes/view.drop.ts +40 -0
  412. package/src/core/objects/view/changes/view.privilege.ts +200 -0
  413. package/src/core/objects/view/changes/view.types.ts +12 -0
  414. package/src/core/objects/view/view.diff.test.ts +91 -0
  415. package/src/core/objects/view/view.diff.ts +365 -0
  416. package/src/core/objects/view/view.model.ts +276 -0
  417. package/src/core/plan/apply.ts +190 -0
  418. package/src/core/plan/create.ts +432 -0
  419. package/src/core/plan/hierarchy.ts +574 -0
  420. package/src/core/plan/index.ts +29 -0
  421. package/src/core/plan/io.ts +20 -0
  422. package/src/core/plan/risk.ts +48 -0
  423. package/src/core/plan/serialize.ts +195 -0
  424. package/src/core/plan/sql-format/constants.ts +13 -0
  425. package/src/core/plan/sql-format/fixtures.ts +2806 -0
  426. package/src/core/plan/sql-format/format-comment-literals.test.ts +96 -0
  427. package/src/core/plan/sql-format/format-functions.test.ts +127 -0
  428. package/src/core/plan/sql-format/format-lowercase-coverage.test.ts +67 -0
  429. package/src/core/plan/sql-format/format-off.test.ts +809 -0
  430. package/src/core/plan/sql-format/format-pretty-lower-leading.test.ts +1056 -0
  431. package/src/core/plan/sql-format/format-pretty-narrow.test.ts +1283 -0
  432. package/src/core/plan/sql-format/format-pretty-preserve.test.ts +1052 -0
  433. package/src/core/plan/sql-format/format-pretty-upper.test.ts +1045 -0
  434. package/src/core/plan/sql-format/format-stress.test.ts +616 -0
  435. package/src/core/plan/sql-format/format-utils.test.ts +91 -0
  436. package/src/core/plan/sql-format/format-utils.ts +391 -0
  437. package/src/core/plan/sql-format/formatters.ts +921 -0
  438. package/src/core/plan/sql-format/index.ts +149 -0
  439. package/src/core/plan/sql-format/keyword-case.test.ts +118 -0
  440. package/src/core/plan/sql-format/keyword-case.ts +1085 -0
  441. package/src/core/plan/sql-format/protect.test.ts +127 -0
  442. package/src/core/plan/sql-format/protect.ts +337 -0
  443. package/src/core/plan/sql-format/sql-scanner.test.ts +240 -0
  444. package/src/core/plan/sql-format/sql-scanner.ts +252 -0
  445. package/src/core/plan/sql-format/tokenizer.test.ts +68 -0
  446. package/src/core/plan/sql-format/tokenizer.ts +152 -0
  447. package/src/core/plan/sql-format/types.ts +31 -0
  448. package/src/core/plan/sql-format/wrap.test.ts +119 -0
  449. package/src/core/plan/sql-format/wrap.ts +196 -0
  450. package/src/core/plan/sql-format.ts +2 -0
  451. package/src/core/plan/statements.ts +22 -0
  452. package/src/core/plan/types.ts +165 -0
  453. package/src/core/postgres-config.ts +169 -0
  454. package/src/core/sort/custom-constraints.ts +161 -0
  455. package/src/core/sort/debug-visualization.ts +239 -0
  456. package/src/core/sort/dependency-filter.ts +224 -0
  457. package/src/core/sort/graph-builder.ts +223 -0
  458. package/src/core/sort/graph-utils.ts +51 -0
  459. package/src/core/sort/logical-sort.ts +590 -0
  460. package/src/core/sort/sort-changes.ts +234 -0
  461. package/src/core/sort/topological-sort.ts +184 -0
  462. package/src/core/sort/types.ts +112 -0
  463. package/src/core/sort/utils.ts +69 -0
  464. package/src/index.ts +14 -0
@@ -0,0 +1,161 @@
1
+ import type { Change } from "../change.types.ts";
2
+ import { getSchema } from "../integrations/filter/extractors.ts";
3
+ import {
4
+ GrantRoleDefaultPrivileges,
5
+ RevokeRoleDefaultPrivileges,
6
+ } from "../objects/role/changes/role.privilege.ts";
7
+ import type { Constraint } from "./types.ts";
8
+
9
+ /**
10
+ * Maps object type names to PostgreSQL default privilege objtype codes.
11
+ * This mirrors the mapping in base.default-privileges.ts.
12
+ */
13
+ function objectTypeToObjtype(objectType: string): string | null {
14
+ switch (objectType) {
15
+ case "table":
16
+ case "view":
17
+ case "materialized_view":
18
+ return "r"; // Relations
19
+ case "sequence":
20
+ return "S"; // Sequences
21
+ case "procedure":
22
+ case "function":
23
+ case "aggregate":
24
+ return "f"; // Functions/routines
25
+ case "type":
26
+ case "domain":
27
+ case "enum":
28
+ case "range":
29
+ case "composite_type":
30
+ return "T"; // Types
31
+ case "schema":
32
+ return "n"; // Schemas
33
+ default:
34
+ return null;
35
+ }
36
+ }
37
+
38
+ /**
39
+ * A function that generates constraints for a list of changes.
40
+ * Should be optimized to avoid O(N²) complexity by using lookups/indexing.
41
+ */
42
+ type ConstraintGenerator = (changes: Change[]) => Constraint[];
43
+
44
+ /**
45
+ * Generate constraints to ensure ALTER DEFAULT PRIVILEGES comes before CREATE statements.
46
+ *
47
+ * Rules:
48
+ * - Only applies when the default privilege's schema matches the CREATE statement's schema
49
+ * (or if the default privilege is global, applies to all schemas)
50
+ * - Only applies when the default privilege's objtype matches the CREATE statement's object type
51
+ * - Excludes CREATE ROLE and CREATE SCHEMA since they are dependencies
52
+ * of ALTER DEFAULT PRIVILEGES and must come before it
53
+ *
54
+ * implementation: O(N) using schema/objtype indexing.
55
+ */
56
+ function generateDefaultPrivilegeConstraints(changes: Change[]): Constraint[] {
57
+ const constraints: Constraint[] = [];
58
+ const defaultPrivilegeIndices: number[] = [];
59
+ // Map<objtype_code, Map<schema_name, index[]>>
60
+ const createsByObjTypeAndSchema = new Map<string, Map<string, number[]>>();
61
+
62
+ // Pass 1: Index changes
63
+ for (let i = 0; i < changes.length; i++) {
64
+ const change = changes[i];
65
+
66
+ // Identify default privilege changes
67
+ if (
68
+ change instanceof GrantRoleDefaultPrivileges ||
69
+ change instanceof RevokeRoleDefaultPrivileges
70
+ ) {
71
+ defaultPrivilegeIndices.push(i);
72
+ continue;
73
+ }
74
+
75
+ // Identify CREATE object changes (excluding role/schema)
76
+ if (
77
+ change.operation === "create" &&
78
+ change.scope === "object" &&
79
+ change.objectType !== "role" &&
80
+ change.objectType !== "schema"
81
+ ) {
82
+ const objTypeCode = objectTypeToObjtype(change.objectType);
83
+ if (!objTypeCode) continue;
84
+
85
+ const schema = getSchema(change);
86
+ // Default privileges only apply to schema-contained objects.
87
+ if (schema) {
88
+ let schemaMap = createsByObjTypeAndSchema.get(objTypeCode);
89
+ if (!schemaMap) {
90
+ schemaMap = new Map();
91
+ createsByObjTypeAndSchema.set(objTypeCode, schemaMap);
92
+ }
93
+
94
+ let indices = schemaMap.get(schema);
95
+ if (!indices) {
96
+ indices = [];
97
+ schemaMap.set(schema, indices);
98
+ }
99
+ indices.push(i);
100
+ }
101
+ }
102
+ }
103
+
104
+ // Pass 2: Generate constraints
105
+ for (const privIndex of defaultPrivilegeIndices) {
106
+ const privChange = changes[privIndex] as {
107
+ inSchema: string | null;
108
+ objtype: string;
109
+ };
110
+ const privSchema = privChange.inSchema;
111
+ const privObjType = privChange.objtype;
112
+
113
+ const schemaMap = createsByObjTypeAndSchema.get(privObjType);
114
+ if (!schemaMap) continue;
115
+
116
+ if (privSchema === null) {
117
+ // Global default privilege: applies to ALL schemas
118
+ for (const indices of schemaMap.values()) {
119
+ for (const createIndex of indices) {
120
+ // (No self-check needed as types differ)
121
+ constraints.push({
122
+ sourceChangeIndex: privIndex,
123
+ targetChangeIndex: createIndex,
124
+ source: "custom",
125
+ });
126
+ }
127
+ }
128
+ } else {
129
+ // Specific schema: applies only to that schema
130
+ const indices = schemaMap.get(privSchema);
131
+ if (indices) {
132
+ for (const createIndex of indices) {
133
+ constraints.push({
134
+ sourceChangeIndex: privIndex,
135
+ targetChangeIndex: createIndex,
136
+ source: "custom",
137
+ });
138
+ }
139
+ }
140
+ }
141
+ }
142
+
143
+ return constraints;
144
+ }
145
+
146
+ /**
147
+ * All custom constraint generators.
148
+ */
149
+ const customConstraintGenerators: ConstraintGenerator[] = [
150
+ generateDefaultPrivilegeConstraints,
151
+ ];
152
+
153
+ /**
154
+ * Generate Constraints from custom constraint generators.
155
+ *
156
+ * Iterates through registered generators to produce constraints.
157
+ * Generators should be optimized (e.g. using indexing) to avoid O(N²) complexity.
158
+ */
159
+ export function generateCustomConstraints(changes: Change[]): Constraint[] {
160
+ return customConstraintGenerators.flatMap((generate) => generate(changes));
161
+ }
@@ -0,0 +1,239 @@
1
+ import debug from "debug";
2
+ import type { Change } from "../change.types.ts";
3
+ import { findCycle } from "./topological-sort.ts";
4
+ import type { Constraint, GraphData, PgDependRow } from "./types.ts";
5
+
6
+ const debugGraph = debug("pg-delta:graph");
7
+
8
+ /**
9
+ * Generate a Mermaid diagram representation of the dependency graph for debugging.
10
+ */
11
+ function generateMermaidDiagram(
12
+ phaseChanges: Change[],
13
+ graphData: GraphData,
14
+ edges: Array<[number, number]>,
15
+ requirementSets: Array<Set<string>>,
16
+ dependenciesByReferencedId: Map<string, Set<string>>,
17
+ ): string {
18
+ const cycleNodeIndexes = findCycle(phaseChanges.length, edges) ?? [];
19
+ const mermaidLines: string[] = [];
20
+ mermaidLines.push("flowchart TD");
21
+
22
+ // Add nodes
23
+ for (let changeIndex = 0; changeIndex < phaseChanges.length; changeIndex++) {
24
+ const changeInstance = phaseChanges[changeIndex];
25
+ const changeClassName = changeInstance?.constructor?.name ?? "Change";
26
+ const truncatedCreates = Array.isArray(changeInstance.creates)
27
+ ? changeInstance.creates.slice(0, 3)
28
+ : [];
29
+ const nodeLabel = `${changeIndex}: ${changeClassName} ${
30
+ truncatedCreates.length > 0 ? `[${truncatedCreates.join(",")}]` : ""
31
+ }`.replaceAll('"', "'");
32
+ mermaidLines.push(` n${changeIndex}["${nodeLabel}"]`);
33
+ }
34
+
35
+ // Add edges with descriptions
36
+ for (const [sourceIndex, targetIndex] of edges) {
37
+ const edgeDescription = describeEdge(
38
+ sourceIndex,
39
+ targetIndex,
40
+ graphData,
41
+ requirementSets,
42
+ dependenciesByReferencedId,
43
+ ).replaceAll('"', "'");
44
+ if (edgeDescription.length > 0) {
45
+ mermaidLines.push(
46
+ ` n${sourceIndex} -- "${edgeDescription}" --> n${targetIndex}`,
47
+ );
48
+ } else {
49
+ mermaidLines.push(` n${sourceIndex} --> n${targetIndex}`);
50
+ }
51
+ }
52
+
53
+ // Highlight cycles if any
54
+ if (cycleNodeIndexes.length > 0) {
55
+ mermaidLines.push(
56
+ " classDef cycleNode fill:#ffe6e6,stroke:#ff4d4f,stroke-width:2px;",
57
+ );
58
+ for (const nodeIndex of cycleNodeIndexes) {
59
+ mermaidLines.push(` class n${nodeIndex} cycleNode;`);
60
+ }
61
+
62
+ const cycleEdges: Array<[number, number]> = [];
63
+ for (
64
+ let cycleIndex = 0;
65
+ cycleIndex < cycleNodeIndexes.length;
66
+ cycleIndex++
67
+ ) {
68
+ const sourceIndex = cycleNodeIndexes[cycleIndex];
69
+ const targetIndex =
70
+ cycleNodeIndexes[(cycleIndex + 1) % cycleNodeIndexes.length];
71
+ cycleEdges.push([sourceIndex, targetIndex]);
72
+ }
73
+
74
+ let edgeIndex = 0;
75
+ for (const [sourceIndex, targetIndex] of edges) {
76
+ const edgeBelongsToCycle = cycleEdges.some(
77
+ ([cycleSourceIndex, cycleTargetIndex]) =>
78
+ cycleSourceIndex === sourceIndex && cycleTargetIndex === targetIndex,
79
+ );
80
+ if (edgeBelongsToCycle) {
81
+ mermaidLines.push(
82
+ ` linkStyle ${edgeIndex} stroke:#ff4d4f,stroke-width:2px;`,
83
+ );
84
+ }
85
+ edgeIndex++;
86
+ }
87
+ }
88
+
89
+ return mermaidLines.join("\n");
90
+ }
91
+
92
+ /**
93
+ * Build requirementSets from explicit requirements and constraints (for debug visualization).
94
+ *
95
+ * This reconstructs what requirements were inferred from constraints by looking at
96
+ * the constraints that were processed. Only processes catalog/explicit constraints,
97
+ * as custom constraints don't affect requirement sets.
98
+ */
99
+ function buildRequirementSets(
100
+ explicitRequirementSets: Array<Set<string>>,
101
+ constraints: Constraint[],
102
+ changeIndexesByCreatedId: Map<string, Set<number>>,
103
+ _changeIndexesByExplicitRequirementId: Map<string, Set<number>>,
104
+ ): Array<Set<string>> {
105
+ // Start with explicit requirements
106
+ const requirementSets: Array<Set<string>> = explicitRequirementSets.map(
107
+ (explicitRequirements) => new Set<string>(explicitRequirements),
108
+ );
109
+
110
+ // Add requirements inferred from catalog/explicit constraints
111
+ // For each constraint with a reason, if the referenced ID is created by some change,
112
+ // then the target change requires the referenced ID
113
+ for (const constraint of constraints) {
114
+ // Only process catalog/explicit constraints (custom constraints don't affect requirements)
115
+ if (constraint.source === "custom" || !constraint.reason) continue;
116
+
117
+ const referencedProducers = changeIndexesByCreatedId.get(
118
+ constraint.reason.referencedStableId,
119
+ );
120
+ if (!referencedProducers || referencedProducers.size === 0) continue;
121
+
122
+ // The target change requires the referenced stable ID
123
+ requirementSets[constraint.targetChangeIndex].add(
124
+ constraint.reason.referencedStableId,
125
+ );
126
+ }
127
+
128
+ return requirementSets;
129
+ }
130
+
131
+ /**
132
+ * Build dependenciesByReferencedId from dependency rows (for debug visualization).
133
+ */
134
+ function buildDependenciesByReferencedId(
135
+ dependencyRows: PgDependRow[],
136
+ ): Map<string, Set<string>> {
137
+ const dependenciesByReferencedId = new Map<string, Set<string>>();
138
+ for (const dependencyRow of dependencyRows) {
139
+ // Filter out unknown dependencies
140
+ if (
141
+ dependencyRow.referenced_stable_id.startsWith("unknown:") ||
142
+ dependencyRow.dependent_stable_id.startsWith("unknown:")
143
+ ) {
144
+ continue;
145
+ }
146
+
147
+ let dependentIds = dependenciesByReferencedId.get(
148
+ dependencyRow.referenced_stable_id,
149
+ );
150
+ if (!dependentIds) {
151
+ dependentIds = new Set<string>();
152
+ dependenciesByReferencedId.set(
153
+ dependencyRow.referenced_stable_id,
154
+ dependentIds,
155
+ );
156
+ }
157
+ dependentIds.add(dependencyRow.dependent_stable_id);
158
+ }
159
+ return dependenciesByReferencedId;
160
+ }
161
+
162
+ /**
163
+ * Describe an edge in the dependency graph for visualization.
164
+ */
165
+ function describeEdge(
166
+ sourceIndex: number,
167
+ targetIndex: number,
168
+ graphData: GraphData,
169
+ requirementSets: Array<Set<string>>,
170
+ dependenciesByReferencedId: Map<string, Set<string>>,
171
+ ): string {
172
+ // Check if target explicitly requires something created by source
173
+ for (const createdId of graphData.createdStableIdSets[sourceIndex]) {
174
+ if (requirementSets[targetIndex].has(createdId)) {
175
+ return `${createdId} -> (requires)`;
176
+ }
177
+ }
178
+
179
+ // Check pg_depend relationships
180
+ for (const createdId of graphData.createdStableIdSets[sourceIndex]) {
181
+ const outgoingDependencies = dependenciesByReferencedId.get(createdId);
182
+ if (!outgoingDependencies) continue;
183
+
184
+ // Check if target requires this ID
185
+ for (const requiredId of requirementSets[targetIndex]) {
186
+ if (outgoingDependencies.has(requiredId)) {
187
+ return `${createdId} -> ${requiredId}`;
188
+ }
189
+ }
190
+
191
+ // Check if target creates something that depends on this ID
192
+ for (const targetCreatedId of graphData.createdStableIdSets[targetIndex]) {
193
+ if (outgoingDependencies.has(targetCreatedId)) {
194
+ return `${createdId} -> ${targetCreatedId}`;
195
+ }
196
+ }
197
+ }
198
+
199
+ return "";
200
+ }
201
+
202
+ /**
203
+ * Print debug information about the dependency graph.
204
+ *
205
+ * Builds debug-only data structures (requirementSets, dependenciesByReferencedId) just-in-time.
206
+ */
207
+ export function printDebugGraph(
208
+ phaseChanges: Change[],
209
+ graphData: GraphData,
210
+ edges: Array<[number, number]>,
211
+ dependencyRows: PgDependRow[],
212
+ constraints: Constraint[],
213
+ ): void {
214
+ try {
215
+ // Build debug-only data structures just-in-time
216
+ const requirementSets = buildRequirementSets(
217
+ graphData.explicitRequirementSets,
218
+ constraints,
219
+ graphData.changeIndexesByCreatedId,
220
+ graphData.changeIndexesByExplicitRequirementId,
221
+ );
222
+ const dependenciesByReferencedId =
223
+ buildDependenciesByReferencedId(dependencyRows);
224
+
225
+ const mermaidDiagram = generateMermaidDiagram(
226
+ phaseChanges,
227
+ graphData,
228
+ edges,
229
+ requirementSets,
230
+ dependenciesByReferencedId,
231
+ );
232
+ debugGraph(
233
+ "\n==== Mermaid (cycle detected) ====\n%s\n==== end ====",
234
+ mermaidDiagram,
235
+ );
236
+ } catch (_error) {
237
+ // ignore debug printing errors
238
+ }
239
+ }
@@ -0,0 +1,224 @@
1
+ import type { Change } from "../change.types.ts";
2
+ import { CreateSequence } from "../objects/sequence/changes/sequence.create.ts";
3
+ import { stableId } from "../objects/utils.ts";
4
+ import { findConsumerIndexes } from "./graph-utils.ts";
5
+ import type { Edge, GraphData } from "./types.ts";
6
+
7
+ /**
8
+ * Check if a sequence is owned by a given column.
9
+ *
10
+ * @param sequence - The sequence object with ownership information
11
+ * @param referencedStableId - The column stable ID to check against
12
+ * @returns true if the sequence is owned by the referenced column
13
+ */
14
+ function isSequenceOwnedBy(
15
+ sequence: {
16
+ owned_by_schema: string | null;
17
+ owned_by_table: string | null;
18
+ owned_by_column: string | null;
19
+ },
20
+ referencedStableId: string,
21
+ ): boolean {
22
+ if (
23
+ !sequence.owned_by_schema ||
24
+ !sequence.owned_by_table ||
25
+ !sequence.owned_by_column
26
+ ) {
27
+ return false;
28
+ }
29
+
30
+ const ownedByColumnId = stableId.column(
31
+ sequence.owned_by_schema,
32
+ sequence.owned_by_table,
33
+ sequence.owned_by_column,
34
+ );
35
+
36
+ return referencedStableId === ownedByColumnId;
37
+ }
38
+
39
+ /**
40
+ * Check if a sequence ownership dependency should be filtered to prevent cycles.
41
+ *
42
+ * CYCLE SCENARIO:
43
+ * When a sequence is owned by a table column that also uses the sequence (via DEFAULT),
44
+ * PostgreSQL's pg_depend creates a bidirectional dependency cycle:
45
+ * 1. column → sequence (column default depends on sequence)
46
+ * 2. sequence → column (sequence ownership depends on column)
47
+ *
48
+ * This creates: sequence → column → sequence (cycle!)
49
+ *
50
+ * HOW WE BREAK THE CYCLE:
51
+ * We filter out the ownership dependency edge (sequence → column) because:
52
+ * - CREATE phase: Sequences should be created before tables. Ownership is set later
53
+ * via ALTER SEQUENCE OWNED BY after both the sequence and table exist.
54
+ * - DROP phase: Prevents cycles when dropping sequences owned by tables that
55
+ * aren't being dropped.
56
+ *
57
+ * PARAMETERS:
58
+ * @param dependentStableId - The sequence stable ID (e.g., "sequence:schema.seq_name")
59
+ * @param referencedStableId - The column stable ID (e.g., "column:schema.table.col")
60
+ * Note: PostgreSQL's pg_depend creates sequence ownership dependencies on columns (not tables)
61
+ * when refobjsubid > 0, so we only check for column dependencies
62
+ * @param phaseChanges - All changes in the current phase
63
+ * @param graphData - Graph data structures for looking up changes
64
+ * @returns true if this ownership dependency should be filtered (removed) to break the cycle
65
+ */
66
+ function shouldFilterSequenceOwnershipDependency(
67
+ dependentStableId: string,
68
+ referencedStableId: string,
69
+ phaseChanges: Change[],
70
+ graphData: GraphData,
71
+ ): boolean {
72
+ // Early exit: only filter edges FROM sequences TO columns
73
+ // Note: PostgreSQL's pg_depend creates sequence ownership dependencies on columns (not tables)
74
+ // when refobjsubid > 0, so we only need to check for column dependencies
75
+ if (
76
+ !dependentStableId.startsWith("sequence:") ||
77
+ !referencedStableId.startsWith("column:")
78
+ ) {
79
+ return false;
80
+ }
81
+
82
+ // Find all changes that create or consume this sequence
83
+ // (includes the CreateSequence change that creates it)
84
+ const changesInvolvingSequence = findConsumerIndexes(
85
+ dependentStableId,
86
+ graphData.changeIndexesByCreatedId,
87
+ graphData.changeIndexesByExplicitRequirementId,
88
+ );
89
+
90
+ // Check if any CreateSequence change creates a sequence that is owned by
91
+ // the referenced table/column. If so, filter this ownership dependency edge.
92
+ for (const changeIndex of changesInvolvingSequence) {
93
+ const change = phaseChanges[changeIndex];
94
+
95
+ // Only filter edges from CreateSequence changes, not AlterSequenceSetOwnedBy.
96
+ // AlterSequenceSetOwnedBy is a separate change that sets ownership after
97
+ // both the sequence and table exist, so it doesn't create the cycle.
98
+ if (!(change instanceof CreateSequence)) {
99
+ continue;
100
+ }
101
+
102
+ // Check if this CreateSequence creates a sequence owned by the referenced table/column
103
+ if (isSequenceOwnedBy(change.sequence, referencedStableId)) {
104
+ return true; // Filter this edge to break the cycle
105
+ }
106
+ }
107
+
108
+ return false; // Don't filter - this is not a cycle-causing ownership dependency
109
+ }
110
+
111
+ /**
112
+ * Cycle-breaking filters for stable ID dependencies.
113
+ *
114
+ * Prevents cycles that would occur due to special PostgreSQL behaviors.
115
+ * Delegates to specific filter functions for each type of cycle.
116
+ *
117
+ * @param dependentStableId - The dependent object's stable ID
118
+ * @param referencedStableId - The referenced object's stable ID
119
+ * @param phaseChanges - All changes in the current phase
120
+ * @param graphData - Graph data structures for looking up changes
121
+ * @returns true if this dependency edge should be filtered (removed) to break a cycle
122
+ */
123
+ function shouldFilterStableIdDependencyForCycleBreaking(
124
+ dependentStableId: string,
125
+ referencedStableId: string,
126
+ phaseChanges: Change[],
127
+ graphData: GraphData,
128
+ ): boolean {
129
+ // Filter sequence ownership dependencies that create cycles with column defaults
130
+ if (
131
+ shouldFilterSequenceOwnershipDependency(
132
+ dependentStableId,
133
+ referencedStableId,
134
+ phaseChanges,
135
+ graphData,
136
+ )
137
+ ) {
138
+ return true;
139
+ }
140
+
141
+ return false;
142
+ }
143
+
144
+ /**
145
+ * Identify edges that are part of a cycle.
146
+ *
147
+ * Given cycle node indices, returns edges where both source and target are in the cycle
148
+ * and form consecutive nodes in the cycle path.
149
+ */
150
+ export function getEdgesInCycle(
151
+ cycleNodeIndexes: number[],
152
+ edges: Edge[],
153
+ ): Edge[] {
154
+ const cycleEdges: Edge[] = [];
155
+
156
+ // Create a map of edges for quick lookup
157
+ const edgeMap = new Map<string, Edge>();
158
+ for (const edge of edges) {
159
+ const key = `${edge.sourceIndex}->${edge.targetIndex}`;
160
+ edgeMap.set(key, edge);
161
+ }
162
+
163
+ // Find edges that connect consecutive nodes in the cycle
164
+ for (let i = 0; i < cycleNodeIndexes.length; i++) {
165
+ const sourceIndex = cycleNodeIndexes[i];
166
+ const targetIndex = cycleNodeIndexes[(i + 1) % cycleNodeIndexes.length];
167
+ const key = `${sourceIndex}->${targetIndex}`;
168
+ const edge = edgeMap.get(key);
169
+ if (edge) {
170
+ cycleEdges.push(edge);
171
+ }
172
+ }
173
+
174
+ return cycleEdges;
175
+ }
176
+
177
+ /**
178
+ * Filter edges involved in cycles based on their constraint's cycle-breaking rules.
179
+ *
180
+ * This is applied when cycles are detected to break them by removing problematic edges.
181
+ * Only filters edges that:
182
+ * 1. Are part of the detected cycle(s)
183
+ * 2. Have a reason (stable ID dependency) - custom constraints are never filtered
184
+ * 3. Match the cycle-breaking filter criteria
185
+ */
186
+ export function filterEdgesForCycleBreaking(
187
+ edges: Edge[],
188
+ cycleNodeIndexes: number[],
189
+ phaseChanges: Change[],
190
+ graphData: GraphData,
191
+ ): Edge[] {
192
+ // Get edges that are part of the cycle
193
+ const cycleEdges = getEdgesInCycle(cycleNodeIndexes, edges);
194
+ // Use string keys for comparison since Set.has() uses reference equality
195
+ const cycleEdgeKeys = new Set(
196
+ cycleEdges.map((e) => `${e.sourceIndex}->${e.targetIndex}`),
197
+ );
198
+
199
+ return edges.filter((edge) => {
200
+ const edgeKey = `${edge.sourceIndex}->${edge.targetIndex}`;
201
+ // If edge is not in the cycle, keep it
202
+ if (!cycleEdgeKeys.has(edgeKey)) {
203
+ return true;
204
+ }
205
+
206
+ // Edge is in cycle - check if it should be filtered
207
+ const constraint = edge.constraint;
208
+
209
+ // Custom constraints are never filtered
210
+ if (constraint.source === "custom") return true;
211
+
212
+ const { dependentStableId, referencedStableId } = constraint.reason;
213
+ // Skip if dependentStableId is undefined (explicit requirement without created IDs)
214
+ if (!dependentStableId) return true;
215
+
216
+ // Apply cycle-breaking filters - return false to filter out this edge
217
+ return !shouldFilterStableIdDependencyForCycleBreaking(
218
+ dependentStableId,
219
+ referencedStableId,
220
+ phaseChanges,
221
+ graphData,
222
+ );
223
+ });
224
+ }