@supabase/pg-delta 1.0.0-alpha.3 → 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 (463) 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/objects/table/table.model.d.ts +4 -2
  7. package/dist/core/objects/table/table.model.js +3 -0
  8. package/dist/core/objects/trigger/changes/trigger.alter.js +23 -0
  9. package/dist/core/objects/trigger/changes/trigger.create.js +2 -1
  10. package/dist/core/objects/trigger/trigger.model.d.ts +1 -0
  11. package/dist/core/objects/trigger/trigger.model.js +3 -0
  12. package/dist/core/plan/apply.js +3 -3
  13. package/dist/core/plan/create.js +34 -15
  14. package/dist/core/plan/sql-format/constants.d.ts +2 -0
  15. package/dist/core/plan/sql-format/constants.js +11 -0
  16. package/dist/core/plan/sql-format/fixtures.d.ts +2 -0
  17. package/dist/core/plan/sql-format/fixtures.js +2449 -0
  18. package/dist/core/plan/sql-format/format-utils.d.ts +37 -0
  19. package/dist/core/plan/sql-format/format-utils.js +274 -0
  20. package/dist/core/plan/sql-format/formatters.d.ts +20 -0
  21. package/dist/core/plan/sql-format/formatters.js +737 -0
  22. package/dist/core/plan/sql-format/index.d.ts +2 -0
  23. package/dist/core/plan/sql-format/index.js +98 -0
  24. package/dist/core/plan/sql-format/keyword-case.d.ts +2 -0
  25. package/dist/core/plan/sql-format/keyword-case.js +868 -0
  26. package/dist/core/plan/sql-format/protect.d.ts +3 -0
  27. package/dist/core/plan/sql-format/protect.js +269 -0
  28. package/dist/core/plan/sql-format/sql-scanner.d.ts +59 -0
  29. package/dist/core/plan/sql-format/sql-scanner.js +202 -0
  30. package/dist/core/plan/sql-format/tokenizer.d.ts +22 -0
  31. package/dist/core/plan/sql-format/tokenizer.js +118 -0
  32. package/dist/core/plan/sql-format/types.d.ts +28 -0
  33. package/dist/core/plan/sql-format/types.js +1 -0
  34. package/dist/core/plan/sql-format/wrap.d.ts +2 -0
  35. package/dist/core/plan/sql-format/wrap.js +165 -0
  36. package/dist/core/plan/sql-format.d.ts +2 -0
  37. package/dist/core/plan/sql-format.js +1 -0
  38. package/dist/core/plan/statements.d.ts +2 -1
  39. package/dist/core/plan/statements.js +6 -2
  40. package/dist/core/postgres-config.d.ts +15 -0
  41. package/dist/core/postgres-config.js +30 -0
  42. package/dist/index.d.ts +2 -0
  43. package/dist/index.js +1 -0
  44. package/package.json +37 -22
  45. package/src/cli/app.ts +28 -0
  46. package/src/cli/bin/cli.ts +9 -0
  47. package/src/cli/commands/apply.ts +101 -0
  48. package/src/cli/commands/plan.ts +195 -0
  49. package/src/cli/commands/sync.ts +185 -0
  50. package/src/cli/formatters/index.ts +5 -0
  51. package/src/cli/formatters/tree/tree-builder.ts +380 -0
  52. package/src/cli/formatters/tree/tree-renderer.ts +372 -0
  53. package/src/cli/formatters/tree/tree.ts +237 -0
  54. package/src/cli/utils/integrations.ts +42 -0
  55. package/src/cli/utils.ts +231 -0
  56. package/src/core/catalog.diff.ts +246 -0
  57. package/src/core/catalog.model.ts +384 -0
  58. package/src/core/change.types.ts +44 -0
  59. package/src/core/context.ts +26 -0
  60. package/src/core/depend.ts +1870 -0
  61. package/src/core/expand-replace-dependencies.ts +380 -0
  62. package/src/core/fingerprint.ts +204 -0
  63. package/src/core/integrations/filter/dsl.ts +204 -0
  64. package/src/core/integrations/filter/extractors.ts +145 -0
  65. package/src/core/integrations/filter/filter.types.ts +3 -0
  66. package/src/core/integrations/integration-dsl.ts +24 -0
  67. package/src/core/integrations/integration.types.ts +7 -0
  68. package/src/core/integrations/serialize/dsl.ts +77 -0
  69. package/src/core/integrations/serialize/serialize.types.ts +3 -0
  70. package/src/core/integrations/supabase.ts +121 -0
  71. package/src/core/objects/aggregate/aggregate.diff.test.ts +215 -0
  72. package/src/core/objects/aggregate/aggregate.diff.ts +278 -0
  73. package/src/core/objects/aggregate/aggregate.model.ts +317 -0
  74. package/src/core/objects/aggregate/changes/aggregate.alter.test.ts +64 -0
  75. package/src/core/objects/aggregate/changes/aggregate.alter.ts +32 -0
  76. package/src/core/objects/aggregate/changes/aggregate.base.ts +20 -0
  77. package/src/core/objects/aggregate/changes/aggregate.comment.test.ts +86 -0
  78. package/src/core/objects/aggregate/changes/aggregate.comment.ts +62 -0
  79. package/src/core/objects/aggregate/changes/aggregate.create.test.ts +101 -0
  80. package/src/core/objects/aggregate/changes/aggregate.create.ts +329 -0
  81. package/src/core/objects/aggregate/changes/aggregate.drop.test.ts +78 -0
  82. package/src/core/objects/aggregate/changes/aggregate.drop.ts +32 -0
  83. package/src/core/objects/aggregate/changes/aggregate.privilege.test.ts +130 -0
  84. package/src/core/objects/aggregate/changes/aggregate.privilege.ts +146 -0
  85. package/src/core/objects/aggregate/changes/aggregate.types.ts +12 -0
  86. package/src/core/objects/base.change.ts +62 -0
  87. package/src/core/objects/base.default-privileges.ts +204 -0
  88. package/src/core/objects/base.diff.ts +20 -0
  89. package/src/core/objects/base.model.ts +82 -0
  90. package/src/core/objects/base.privilege-diff.ts +299 -0
  91. package/src/core/objects/base.privilege.ts +184 -0
  92. package/src/core/objects/collation/changes/collation.alter.test.ts +63 -0
  93. package/src/core/objects/collation/changes/collation.alter.ts +79 -0
  94. package/src/core/objects/collation/changes/collation.base.ts +20 -0
  95. package/src/core/objects/collation/changes/collation.comment.ts +68 -0
  96. package/src/core/objects/collation/changes/collation.create.test.ts +51 -0
  97. package/src/core/objects/collation/changes/collation.create.ts +106 -0
  98. package/src/core/objects/collation/changes/collation.drop.test.ts +28 -0
  99. package/src/core/objects/collation/changes/collation.drop.ts +37 -0
  100. package/src/core/objects/collation/changes/collation.types.ts +10 -0
  101. package/src/core/objects/collation/collation.diff.test.ts +100 -0
  102. package/src/core/objects/collation/collation.diff.ts +126 -0
  103. package/src/core/objects/collation/collation.model.ts +224 -0
  104. package/src/core/objects/domain/changes/domain.alter.test.ts +316 -0
  105. package/src/core/objects/domain/changes/domain.alter.ts +286 -0
  106. package/src/core/objects/domain/changes/domain.base.ts +20 -0
  107. package/src/core/objects/domain/changes/domain.comment.ts +59 -0
  108. package/src/core/objects/domain/changes/domain.create.test.ts +65 -0
  109. package/src/core/objects/domain/changes/domain.create.ts +118 -0
  110. package/src/core/objects/domain/changes/domain.drop.test.ts +30 -0
  111. package/src/core/objects/domain/changes/domain.drop.ts +34 -0
  112. package/src/core/objects/domain/changes/domain.privilege.ts +171 -0
  113. package/src/core/objects/domain/changes/domain.types.ts +12 -0
  114. package/src/core/objects/domain/domain.diff.test.ts +284 -0
  115. package/src/core/objects/domain/domain.diff.ts +358 -0
  116. package/src/core/objects/domain/domain.model.ts +190 -0
  117. package/src/core/objects/event-trigger/changes/event-trigger.alter.test.ts +50 -0
  118. package/src/core/objects/event-trigger/changes/event-trigger.alter.ts +82 -0
  119. package/src/core/objects/event-trigger/changes/event-trigger.base.ts +20 -0
  120. package/src/core/objects/event-trigger/changes/event-trigger.comment.ts +66 -0
  121. package/src/core/objects/event-trigger/changes/event-trigger.create.test.ts +24 -0
  122. package/src/core/objects/event-trigger/changes/event-trigger.create.ts +72 -0
  123. package/src/core/objects/event-trigger/changes/event-trigger.drop.test.ts +22 -0
  124. package/src/core/objects/event-trigger/changes/event-trigger.drop.ts +34 -0
  125. package/src/core/objects/event-trigger/changes/event-trigger.types.ts +10 -0
  126. package/src/core/objects/event-trigger/event-trigger.diff.test.ts +126 -0
  127. package/src/core/objects/event-trigger/event-trigger.diff.ts +126 -0
  128. package/src/core/objects/event-trigger/event-trigger.model.ts +106 -0
  129. package/src/core/objects/extension/changes/extension.alter.test.ts +58 -0
  130. package/src/core/objects/extension/changes/extension.alter.ts +78 -0
  131. package/src/core/objects/extension/changes/extension.base.ts +20 -0
  132. package/src/core/objects/extension/changes/extension.comment.ts +64 -0
  133. package/src/core/objects/extension/changes/extension.create.test.ts +25 -0
  134. package/src/core/objects/extension/changes/extension.create.ts +63 -0
  135. package/src/core/objects/extension/changes/extension.drop.test.ts +23 -0
  136. package/src/core/objects/extension/changes/extension.drop.ts +34 -0
  137. package/src/core/objects/extension/changes/extension.types.ts +10 -0
  138. package/src/core/objects/extension/extension.diff.test.ts +42 -0
  139. package/src/core/objects/extension/extension.diff.ts +90 -0
  140. package/src/core/objects/extension/extension.model.ts +280 -0
  141. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.alter.test.ts +125 -0
  142. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.alter.ts +101 -0
  143. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.base.ts +20 -0
  144. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.comment.ts +72 -0
  145. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.create.test.ts +125 -0
  146. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.create.ts +95 -0
  147. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.drop.test.ts +23 -0
  148. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.drop.ts +36 -0
  149. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.privilege.ts +172 -0
  150. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.types.ts +12 -0
  151. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/foreign-data-wrapper.diff.test.ts +179 -0
  152. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/foreign-data-wrapper.diff.ts +341 -0
  153. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/foreign-data-wrapper.model.ts +149 -0
  154. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper.types.ts +10 -0
  155. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.alter.test.ts +309 -0
  156. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.alter.ts +341 -0
  157. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.base.ts +20 -0
  158. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.comment.ts +72 -0
  159. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.create.test.ts +201 -0
  160. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.create.ts +81 -0
  161. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.drop.test.ts +43 -0
  162. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.drop.ts +37 -0
  163. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.privilege.ts +181 -0
  164. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.types.ts +12 -0
  165. package/src/core/objects/foreign-data-wrapper/foreign-table/foreign-table.diff.test.ts +813 -0
  166. package/src/core/objects/foreign-data-wrapper/foreign-table/foreign-table.diff.ts +406 -0
  167. package/src/core/objects/foreign-data-wrapper/foreign-table/foreign-table.model.ts +242 -0
  168. package/src/core/objects/foreign-data-wrapper/server/changes/server.alter.test.ts +168 -0
  169. package/src/core/objects/foreign-data-wrapper/server/changes/server.alter.ts +126 -0
  170. package/src/core/objects/foreign-data-wrapper/server/changes/server.base.ts +20 -0
  171. package/src/core/objects/foreign-data-wrapper/server/changes/server.comment.ts +60 -0
  172. package/src/core/objects/foreign-data-wrapper/server/changes/server.create.test.ts +131 -0
  173. package/src/core/objects/foreign-data-wrapper/server/changes/server.create.ts +81 -0
  174. package/src/core/objects/foreign-data-wrapper/server/changes/server.drop.test.ts +24 -0
  175. package/src/core/objects/foreign-data-wrapper/server/changes/server.drop.ts +34 -0
  176. package/src/core/objects/foreign-data-wrapper/server/changes/server.privilege.ts +164 -0
  177. package/src/core/objects/foreign-data-wrapper/server/changes/server.types.ts +12 -0
  178. package/src/core/objects/foreign-data-wrapper/server/server.diff.test.ts +167 -0
  179. package/src/core/objects/foreign-data-wrapper/server/server.diff.ts +317 -0
  180. package/src/core/objects/foreign-data-wrapper/server/server.model.ts +133 -0
  181. package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.alter.test.ts +82 -0
  182. package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.alter.ts +69 -0
  183. package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.base.ts +20 -0
  184. package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.create.test.ts +85 -0
  185. package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.create.ts +66 -0
  186. package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.drop.test.ts +53 -0
  187. package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.drop.ts +40 -0
  188. package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.types.ts +8 -0
  189. package/src/core/objects/foreign-data-wrapper/user-mapping/user-mapping.diff.test.ts +77 -0
  190. package/src/core/objects/foreign-data-wrapper/user-mapping/user-mapping.diff.ts +107 -0
  191. package/src/core/objects/foreign-data-wrapper/user-mapping/user-mapping.model.ts +96 -0
  192. package/src/core/objects/index/changes/index.alter.test.ts +200 -0
  193. package/src/core/objects/index/changes/index.alter.ts +144 -0
  194. package/src/core/objects/index/changes/index.base.ts +20 -0
  195. package/src/core/objects/index/changes/index.comment.ts +63 -0
  196. package/src/core/objects/index/changes/index.create.test.ts +66 -0
  197. package/src/core/objects/index/changes/index.create.ts +68 -0
  198. package/src/core/objects/index/changes/index.drop.test.ts +44 -0
  199. package/src/core/objects/index/changes/index.drop.ts +34 -0
  200. package/src/core/objects/index/changes/index.types.ts +6 -0
  201. package/src/core/objects/index/changes/utils.ts +16 -0
  202. package/src/core/objects/index/index.diff.test.ts +153 -0
  203. package/src/core/objects/index/index.diff.ts +243 -0
  204. package/src/core/objects/index/index.model.ts +370 -0
  205. package/src/core/objects/language/changes/language.alter.test.ts +33 -0
  206. package/src/core/objects/language/changes/language.alter.ts +53 -0
  207. package/src/core/objects/language/changes/language.base.ts +20 -0
  208. package/src/core/objects/language/changes/language.comment.ts +58 -0
  209. package/src/core/objects/language/changes/language.create.test.ts +27 -0
  210. package/src/core/objects/language/changes/language.create.ts +104 -0
  211. package/src/core/objects/language/changes/language.drop.test.ts +25 -0
  212. package/src/core/objects/language/changes/language.drop.ts +39 -0
  213. package/src/core/objects/language/changes/language.privilege.ts +172 -0
  214. package/src/core/objects/language/changes/language.types.ts +12 -0
  215. package/src/core/objects/language/language.diff.test.ts +53 -0
  216. package/src/core/objects/language/language.diff.ts +176 -0
  217. package/src/core/objects/language/language.model.ts +150 -0
  218. package/src/core/objects/materialized-view/changes/materialized-view.alter.test.ts +123 -0
  219. package/src/core/objects/materialized-view/changes/materialized-view.alter.ts +113 -0
  220. package/src/core/objects/materialized-view/changes/materialized-view.base.ts +20 -0
  221. package/src/core/objects/materialized-view/changes/materialized-view.comment.ts +176 -0
  222. package/src/core/objects/materialized-view/changes/materialized-view.create.test.ts +64 -0
  223. package/src/core/objects/materialized-view/changes/materialized-view.create.ts +93 -0
  224. package/src/core/objects/materialized-view/changes/materialized-view.drop.test.ts +34 -0
  225. package/src/core/objects/materialized-view/changes/materialized-view.drop.ts +60 -0
  226. package/src/core/objects/materialized-view/changes/materialized-view.privilege.ts +212 -0
  227. package/src/core/objects/materialized-view/changes/materialized-view.types.ts +12 -0
  228. package/src/core/objects/materialized-view/materialized-view.diff.test.ts +102 -0
  229. package/src/core/objects/materialized-view/materialized-view.diff.ts +451 -0
  230. package/src/core/objects/materialized-view/materialized-view.model.ts +258 -0
  231. package/src/core/objects/procedure/changes/procedure.alter.test.ts +1005 -0
  232. package/src/core/objects/procedure/changes/procedure.alter.ts +287 -0
  233. package/src/core/objects/procedure/changes/procedure.base.ts +20 -0
  234. package/src/core/objects/procedure/changes/procedure.comment.ts +70 -0
  235. package/src/core/objects/procedure/changes/procedure.create.test.ts +48 -0
  236. package/src/core/objects/procedure/changes/procedure.create.ts +92 -0
  237. package/src/core/objects/procedure/changes/procedure.drop.test.ts +85 -0
  238. package/src/core/objects/procedure/changes/procedure.drop.ts +49 -0
  239. package/src/core/objects/procedure/changes/procedure.privilege.ts +188 -0
  240. package/src/core/objects/procedure/changes/procedure.types.ts +12 -0
  241. package/src/core/objects/procedure/procedure.diff.test.ts +161 -0
  242. package/src/core/objects/procedure/procedure.diff.ts +404 -0
  243. package/src/core/objects/procedure/procedure.model.ts +264 -0
  244. package/src/core/objects/procedure/utils.ts +58 -0
  245. package/src/core/objects/publication/changes/publication.alter.test.ts +223 -0
  246. package/src/core/objects/publication/changes/publication.alter.ts +243 -0
  247. package/src/core/objects/publication/changes/publication.base.ts +20 -0
  248. package/src/core/objects/publication/changes/publication.comment.test.ts +70 -0
  249. package/src/core/objects/publication/changes/publication.comment.ts +64 -0
  250. package/src/core/objects/publication/changes/publication.create.test.ts +87 -0
  251. package/src/core/objects/publication/changes/publication.create.ts +82 -0
  252. package/src/core/objects/publication/changes/publication.drop.test.ts +46 -0
  253. package/src/core/objects/publication/changes/publication.drop.ts +29 -0
  254. package/src/core/objects/publication/changes/publication.types.ts +26 -0
  255. package/src/core/objects/publication/publication.diff.test.ts +292 -0
  256. package/src/core/objects/publication/publication.diff.ts +253 -0
  257. package/src/core/objects/publication/publication.model.ts +206 -0
  258. package/src/core/objects/publication/utils.ts +55 -0
  259. package/src/core/objects/rls-policy/changes/rls-policy.alter.test.ts +250 -0
  260. package/src/core/objects/rls-policy/changes/rls-policy.alter.ts +128 -0
  261. package/src/core/objects/rls-policy/changes/rls-policy.base.ts +20 -0
  262. package/src/core/objects/rls-policy/changes/rls-policy.comment.ts +69 -0
  263. package/src/core/objects/rls-policy/changes/rls-policy.create.test.ts +74 -0
  264. package/src/core/objects/rls-policy/changes/rls-policy.create.ts +100 -0
  265. package/src/core/objects/rls-policy/changes/rls-policy.drop.test.ts +28 -0
  266. package/src/core/objects/rls-policy/changes/rls-policy.drop.ts +39 -0
  267. package/src/core/objects/rls-policy/changes/rls-policy.types.ts +10 -0
  268. package/src/core/objects/rls-policy/rls-policy.diff.test.ts +79 -0
  269. package/src/core/objects/rls-policy/rls-policy.diff.ts +121 -0
  270. package/src/core/objects/rls-policy/rls-policy.model.ts +140 -0
  271. package/src/core/objects/role/changes/role.alter.test.ts +346 -0
  272. package/src/core/objects/role/changes/role.alter.ts +110 -0
  273. package/src/core/objects/role/changes/role.base.ts +24 -0
  274. package/src/core/objects/role/changes/role.comment.ts +55 -0
  275. package/src/core/objects/role/changes/role.create.test.ts +52 -0
  276. package/src/core/objects/role/changes/role.create.ts +102 -0
  277. package/src/core/objects/role/changes/role.drop.test.ts +29 -0
  278. package/src/core/objects/role/changes/role.drop.ts +34 -0
  279. package/src/core/objects/role/changes/role.privilege.ts +376 -0
  280. package/src/core/objects/role/changes/role.types.ts +12 -0
  281. package/src/core/objects/role/role.diff.test.ts +44 -0
  282. package/src/core/objects/role/role.diff.ts +479 -0
  283. package/src/core/objects/role/role.model.ts +344 -0
  284. package/src/core/objects/rule/changes/rule.alter.test.ts +78 -0
  285. package/src/core/objects/rule/changes/rule.alter.ts +72 -0
  286. package/src/core/objects/rule/changes/rule.base.ts +20 -0
  287. package/src/core/objects/rule/changes/rule.comment.test.ts +55 -0
  288. package/src/core/objects/rule/changes/rule.comment.ts +62 -0
  289. package/src/core/objects/rule/changes/rule.create.test.ts +59 -0
  290. package/src/core/objects/rule/changes/rule.create.ts +42 -0
  291. package/src/core/objects/rule/changes/rule.drop.test.ts +38 -0
  292. package/src/core/objects/rule/changes/rule.drop.ts +29 -0
  293. package/src/core/objects/rule/changes/rule.types.ts +12 -0
  294. package/src/core/objects/rule/rule.diff.test.ts +132 -0
  295. package/src/core/objects/rule/rule.diff.ts +79 -0
  296. package/src/core/objects/rule/rule.model.ts +173 -0
  297. package/src/core/objects/schema/changes/schema.alter.test.ts +28 -0
  298. package/src/core/objects/schema/changes/schema.alter.ts +45 -0
  299. package/src/core/objects/schema/changes/schema.base.ts +20 -0
  300. package/src/core/objects/schema/changes/schema.comment.ts +56 -0
  301. package/src/core/objects/schema/changes/schema.create.test.ts +22 -0
  302. package/src/core/objects/schema/changes/schema.create.ts +47 -0
  303. package/src/core/objects/schema/changes/schema.drop.test.ts +20 -0
  304. package/src/core/objects/schema/changes/schema.drop.ts +34 -0
  305. package/src/core/objects/schema/changes/schema.privilege.ts +175 -0
  306. package/src/core/objects/schema/changes/schema.types.ts +12 -0
  307. package/src/core/objects/schema/schema.diff.test.ts +42 -0
  308. package/src/core/objects/schema/schema.diff.ts +209 -0
  309. package/src/core/objects/schema/schema.model.ts +107 -0
  310. package/src/core/objects/sequence/changes/sequence.alter.test.ts +151 -0
  311. package/src/core/objects/sequence/changes/sequence.alter.ts +115 -0
  312. package/src/core/objects/sequence/changes/sequence.base.ts +20 -0
  313. package/src/core/objects/sequence/changes/sequence.comment.ts +60 -0
  314. package/src/core/objects/sequence/changes/sequence.create.test.ts +84 -0
  315. package/src/core/objects/sequence/changes/sequence.create.ts +111 -0
  316. package/src/core/objects/sequence/changes/sequence.drop.test.ts +32 -0
  317. package/src/core/objects/sequence/changes/sequence.drop.ts +37 -0
  318. package/src/core/objects/sequence/changes/sequence.privilege.ts +179 -0
  319. package/src/core/objects/sequence/changes/sequence.types.ts +12 -0
  320. package/src/core/objects/sequence/sequence.diff.test.ts +141 -0
  321. package/src/core/objects/sequence/sequence.diff.ts +359 -0
  322. package/src/core/objects/sequence/sequence.model.ts +185 -0
  323. package/src/core/objects/subscription/changes/subscription.alter.test.ts +124 -0
  324. package/src/core/objects/subscription/changes/subscription.alter.ts +110 -0
  325. package/src/core/objects/subscription/changes/subscription.base.ts +20 -0
  326. package/src/core/objects/subscription/changes/subscription.comment.test.ts +67 -0
  327. package/src/core/objects/subscription/changes/subscription.comment.ts +64 -0
  328. package/src/core/objects/subscription/changes/subscription.create.test.ts +77 -0
  329. package/src/core/objects/subscription/changes/subscription.create.ts +69 -0
  330. package/src/core/objects/subscription/changes/subscription.drop.test.ts +46 -0
  331. package/src/core/objects/subscription/changes/subscription.drop.ts +20 -0
  332. package/src/core/objects/subscription/changes/subscription.types.ts +22 -0
  333. package/src/core/objects/subscription/subscription.diff.test.ts +232 -0
  334. package/src/core/objects/subscription/subscription.diff.ts +241 -0
  335. package/src/core/objects/subscription/subscription.model.ts +190 -0
  336. package/src/core/objects/subscription/utils.ts +156 -0
  337. package/src/core/objects/table/changes/table.alter.test.ts +823 -0
  338. package/src/core/objects/table/changes/table.alter.ts +806 -0
  339. package/src/core/objects/table/changes/table.base.ts +20 -0
  340. package/src/core/objects/table/changes/table.comment.ts +266 -0
  341. package/src/core/objects/table/changes/table.create.test.ts +150 -0
  342. package/src/core/objects/table/changes/table.create.ts +188 -0
  343. package/src/core/objects/table/changes/table.drop.test.ts +34 -0
  344. package/src/core/objects/table/changes/table.drop.ts +45 -0
  345. package/src/core/objects/table/changes/table.privilege.ts +200 -0
  346. package/src/core/objects/table/changes/table.types.ts +12 -0
  347. package/src/core/objects/table/table.diff.test.ts +711 -0
  348. package/src/core/objects/table/table.diff.ts +953 -0
  349. package/src/core/objects/table/table.model.ts +460 -0
  350. package/src/core/objects/trigger/changes/trigger.alter.test.ts +46 -0
  351. package/src/core/objects/trigger/changes/trigger.alter.ts +76 -0
  352. package/src/core/objects/trigger/changes/trigger.base.ts +20 -0
  353. package/src/core/objects/trigger/changes/trigger.comment.ts +64 -0
  354. package/src/core/objects/trigger/changes/trigger.create.test.ts +43 -0
  355. package/src/core/objects/trigger/changes/trigger.create.ts +85 -0
  356. package/src/core/objects/trigger/changes/trigger.drop.test.ts +43 -0
  357. package/src/core/objects/trigger/changes/trigger.drop.ts +39 -0
  358. package/src/core/objects/trigger/changes/trigger.types.ts +10 -0
  359. package/src/core/objects/trigger/trigger.diff.test.ts +83 -0
  360. package/src/core/objects/trigger/trigger.diff.ts +116 -0
  361. package/src/core/objects/trigger/trigger.model.ts +252 -0
  362. package/src/core/objects/type/composite-type/changes/composite-type.alter.test.ts +202 -0
  363. package/src/core/objects/type/composite-type/changes/composite-type.alter.ts +174 -0
  364. package/src/core/objects/type/composite-type/changes/composite-type.base.ts +20 -0
  365. package/src/core/objects/type/composite-type/changes/composite-type.comment.ts +145 -0
  366. package/src/core/objects/type/composite-type/changes/composite-type.create.test.ts +101 -0
  367. package/src/core/objects/type/composite-type/changes/composite-type.create.ts +95 -0
  368. package/src/core/objects/type/composite-type/changes/composite-type.drop.test.ts +33 -0
  369. package/src/core/objects/type/composite-type/changes/composite-type.drop.ts +37 -0
  370. package/src/core/objects/type/composite-type/changes/composite-type.privilege.ts +175 -0
  371. package/src/core/objects/type/composite-type/changes/composite-type.types.ts +12 -0
  372. package/src/core/objects/type/composite-type/composite-type.diff.test.ts +191 -0
  373. package/src/core/objects/type/composite-type/composite-type.diff.ts +372 -0
  374. package/src/core/objects/type/composite-type/composite-type.model.ts +252 -0
  375. package/src/core/objects/type/enum/changes/enum.alter.test.ts +104 -0
  376. package/src/core/objects/type/enum/changes/enum.alter.ts +91 -0
  377. package/src/core/objects/type/enum/changes/enum.base.ts +20 -0
  378. package/src/core/objects/type/enum/changes/enum.comment.ts +64 -0
  379. package/src/core/objects/type/enum/changes/enum.create.test.ts +28 -0
  380. package/src/core/objects/type/enum/changes/enum.create.ts +56 -0
  381. package/src/core/objects/type/enum/changes/enum.drop.test.ts +25 -0
  382. package/src/core/objects/type/enum/changes/enum.drop.ts +34 -0
  383. package/src/core/objects/type/enum/changes/enum.privilege.ts +175 -0
  384. package/src/core/objects/type/enum/changes/enum.types.ts +12 -0
  385. package/src/core/objects/type/enum/enum.diff.test.ts +191 -0
  386. package/src/core/objects/type/enum/enum.diff.ts +396 -0
  387. package/src/core/objects/type/enum/enum.model.ts +194 -0
  388. package/src/core/objects/type/range/changes/range.alter.test.ts +27 -0
  389. package/src/core/objects/type/range/changes/range.alter.ts +51 -0
  390. package/src/core/objects/type/range/changes/range.base.ts +20 -0
  391. package/src/core/objects/type/range/changes/range.comment.ts +64 -0
  392. package/src/core/objects/type/range/changes/range.create.test.ts +51 -0
  393. package/src/core/objects/type/range/changes/range.create.ts +151 -0
  394. package/src/core/objects/type/range/changes/range.drop.test.ts +26 -0
  395. package/src/core/objects/type/range/changes/range.drop.ts +34 -0
  396. package/src/core/objects/type/range/changes/range.privilege.ts +175 -0
  397. package/src/core/objects/type/range/changes/range.types.ts +12 -0
  398. package/src/core/objects/type/range/range.diff.test.ts +70 -0
  399. package/src/core/objects/type/range/range.diff.ts +259 -0
  400. package/src/core/objects/type/range/range.model.ts +187 -0
  401. package/src/core/objects/type/type.types.ts +5 -0
  402. package/src/core/objects/utils.ts +171 -0
  403. package/src/core/objects/view/changes/view.alter.test.ts +110 -0
  404. package/src/core/objects/view/changes/view.alter.ts +112 -0
  405. package/src/core/objects/view/changes/view.base.ts +20 -0
  406. package/src/core/objects/view/changes/view.comment.ts +59 -0
  407. package/src/core/objects/view/changes/view.create.test.ts +65 -0
  408. package/src/core/objects/view/changes/view.create.ts +73 -0
  409. package/src/core/objects/view/changes/view.drop.test.ts +34 -0
  410. package/src/core/objects/view/changes/view.drop.ts +40 -0
  411. package/src/core/objects/view/changes/view.privilege.ts +200 -0
  412. package/src/core/objects/view/changes/view.types.ts +12 -0
  413. package/src/core/objects/view/view.diff.test.ts +91 -0
  414. package/src/core/objects/view/view.diff.ts +365 -0
  415. package/src/core/objects/view/view.model.ts +276 -0
  416. package/src/core/plan/apply.ts +190 -0
  417. package/src/core/plan/create.ts +432 -0
  418. package/src/core/plan/hierarchy.ts +574 -0
  419. package/src/core/plan/index.ts +29 -0
  420. package/src/core/plan/io.ts +20 -0
  421. package/src/core/plan/risk.ts +48 -0
  422. package/src/core/plan/serialize.ts +195 -0
  423. package/src/core/plan/sql-format/constants.ts +13 -0
  424. package/src/core/plan/sql-format/fixtures.ts +2806 -0
  425. package/src/core/plan/sql-format/format-comment-literals.test.ts +96 -0
  426. package/src/core/plan/sql-format/format-functions.test.ts +127 -0
  427. package/src/core/plan/sql-format/format-lowercase-coverage.test.ts +67 -0
  428. package/src/core/plan/sql-format/format-off.test.ts +809 -0
  429. package/src/core/plan/sql-format/format-pretty-lower-leading.test.ts +1056 -0
  430. package/src/core/plan/sql-format/format-pretty-narrow.test.ts +1283 -0
  431. package/src/core/plan/sql-format/format-pretty-preserve.test.ts +1052 -0
  432. package/src/core/plan/sql-format/format-pretty-upper.test.ts +1045 -0
  433. package/src/core/plan/sql-format/format-stress.test.ts +616 -0
  434. package/src/core/plan/sql-format/format-utils.test.ts +91 -0
  435. package/src/core/plan/sql-format/format-utils.ts +391 -0
  436. package/src/core/plan/sql-format/formatters.ts +921 -0
  437. package/src/core/plan/sql-format/index.ts +149 -0
  438. package/src/core/plan/sql-format/keyword-case.test.ts +118 -0
  439. package/src/core/plan/sql-format/keyword-case.ts +1085 -0
  440. package/src/core/plan/sql-format/protect.test.ts +127 -0
  441. package/src/core/plan/sql-format/protect.ts +337 -0
  442. package/src/core/plan/sql-format/sql-scanner.test.ts +240 -0
  443. package/src/core/plan/sql-format/sql-scanner.ts +252 -0
  444. package/src/core/plan/sql-format/tokenizer.test.ts +68 -0
  445. package/src/core/plan/sql-format/tokenizer.ts +152 -0
  446. package/src/core/plan/sql-format/types.ts +31 -0
  447. package/src/core/plan/sql-format/wrap.test.ts +119 -0
  448. package/src/core/plan/sql-format/wrap.ts +196 -0
  449. package/src/core/plan/sql-format.ts +2 -0
  450. package/src/core/plan/statements.ts +22 -0
  451. package/src/core/plan/types.ts +165 -0
  452. package/src/core/postgres-config.ts +169 -0
  453. package/src/core/sort/custom-constraints.ts +161 -0
  454. package/src/core/sort/debug-visualization.ts +239 -0
  455. package/src/core/sort/dependency-filter.ts +224 -0
  456. package/src/core/sort/graph-builder.ts +223 -0
  457. package/src/core/sort/graph-utils.ts +51 -0
  458. package/src/core/sort/logical-sort.ts +590 -0
  459. package/src/core/sort/sort-changes.ts +234 -0
  460. package/src/core/sort/topological-sort.ts +184 -0
  461. package/src/core/sort/types.ts +112 -0
  462. package/src/core/sort/utils.ts +69 -0
  463. package/src/index.ts +14 -0
@@ -0,0 +1,196 @@
1
+ import { indentString } from "./format-utils.ts";
2
+ import { isWordChar, walkSql } from "./sql-scanner.ts";
3
+ import type { NormalizedOptions } from "./types.ts";
4
+
5
+ /**
6
+ * Keywords that are preferred break points when wrapping long lines.
7
+ * The wrapper will prefer to break just before one of these keywords
8
+ * rather than at an arbitrary whitespace position.
9
+ */
10
+ const WRAP_PREFERRED_KEYWORDS = new Set([
11
+ "ADD",
12
+ "CHECK",
13
+ "CONNECTION",
14
+ "CONSTRAINT",
15
+ "DEFERRABLE",
16
+ "FOREIGN",
17
+ "HANDLER",
18
+ "INCLUDE",
19
+ "INITIALLY",
20
+ "INLINE",
21
+ "MATCH",
22
+ "NOT",
23
+ "ON",
24
+ "OPTIONS",
25
+ "PUBLICATION",
26
+ "REFERENCES",
27
+ "REFERENCING",
28
+ "SET",
29
+ "USING",
30
+ "VALIDATOR",
31
+ "WHERE",
32
+ "WITH",
33
+ ]);
34
+
35
+ export function wrapStatement(
36
+ statement: string,
37
+ options: NormalizedOptions,
38
+ noWrapPlaceholders: Set<string>,
39
+ ): string {
40
+ const lines = statement.split(/\r?\n/);
41
+ const wrapped: string[] = [];
42
+
43
+ for (const line of lines) {
44
+ if (line.trim().startsWith("--")) {
45
+ wrapped.push(line);
46
+ continue;
47
+ }
48
+
49
+ if (hasNoWrapPlaceholder(line, noWrapPlaceholders)) {
50
+ wrapped.push(line);
51
+ continue;
52
+ }
53
+
54
+ wrapped.push(...wrapLine(line, options));
55
+ }
56
+
57
+ return wrapped.join("\n");
58
+ }
59
+
60
+ function hasNoWrapPlaceholder(
61
+ line: string,
62
+ placeholders: Set<string>,
63
+ ): boolean {
64
+ for (const token of placeholders) {
65
+ if (line.includes(token)) return true;
66
+ }
67
+ return false;
68
+ }
69
+
70
+ function wrapLine(line: string, options: NormalizedOptions): string[] {
71
+ const maxWidth = options.maxWidth;
72
+ if (maxWidth <= 0 || line.length <= maxWidth) {
73
+ return [line];
74
+ }
75
+
76
+ const indentMatch = line.match(/^\s*/);
77
+ const baseIndent = indentMatch ? indentMatch[0] : "";
78
+ const continuationIndent = `${baseIndent}${indentString(options.indent)}`;
79
+
80
+ let remaining = line;
81
+ const output: string[] = [];
82
+
83
+ while (remaining.length > maxWidth) {
84
+ const breakpoint = findWrapPosition(remaining, maxWidth);
85
+ if (breakpoint <= 0) break;
86
+
87
+ const head = remaining.slice(0, breakpoint).trimEnd();
88
+ const tail = remaining.slice(breakpoint).trimStart();
89
+ output.push(head);
90
+ const next = `${continuationIndent}${tail}`;
91
+ if (next.length >= remaining.length) {
92
+ remaining = next;
93
+ break;
94
+ }
95
+ remaining = next;
96
+ }
97
+
98
+ output.push(remaining);
99
+ return output;
100
+ }
101
+
102
+ /** Words that should not be separated from the previous word when wrapping (e.g. CREATE PUBLICATION, COMMENT ON). */
103
+ const KEEP_WITH_PREVIOUS = new Set([
104
+ "PUBLICATION",
105
+ "TABLE",
106
+ "VIEW",
107
+ "SCHEMA",
108
+ "INDEX",
109
+ "OR", // CREATE OR REPLACE
110
+ "ON", // COMMENT ON
111
+ ]);
112
+
113
+ function getPreviousWord(text: string, beforeIndex: number): string | null {
114
+ let end = beforeIndex - 1;
115
+ while (end >= 0 && (text[end] === " " || text[end] === "\t")) {
116
+ end -= 1;
117
+ }
118
+ if (end < 0 || !isWordChar(text[end])) return null;
119
+ let start = end;
120
+ while (start > 0 && isWordChar(text[start - 1])) {
121
+ start -= 1;
122
+ }
123
+ return text.slice(start, end + 1).toUpperCase();
124
+ }
125
+
126
+ function findWrapPosition(text: string, maxWidth: number): number {
127
+ /** Last whitespace at depth 0 (preferred — avoids splitting parenthesized expressions) */
128
+ let lastTopLevelWhitespace = -1;
129
+ /** Last whitespace at any depth (fallback when no depth-0 break exists) */
130
+ let lastAnyWhitespace = -1;
131
+ let lastKeywordBoundary = -1;
132
+ /** First (leftmost) top-level comma within maxWidth — break there so each clause gets its own line */
133
+ let firstComma = -1;
134
+
135
+ // Never break within the leading indent — that would produce an empty head line
136
+ const contentStart = text.search(/\S/);
137
+ if (contentStart < 0) return -1; // all whitespace
138
+
139
+ walkSql(
140
+ text,
141
+ (index, char, depth) => {
142
+ if (index > maxWidth) return false;
143
+
144
+ // Skip positions within leading indent
145
+ if (index < contentStart) return true;
146
+
147
+ // Prefer breaking after the first top-level comma so comma-separated clauses (e.g. publication tables) each get their own line
148
+ if (char === "," && depth === 0 && firstComma < 0) {
149
+ firstComma = index + 1; // position after the comma
150
+ }
151
+
152
+ if (char === " " || char === "\t") {
153
+ lastAnyWhitespace = index;
154
+ if (depth === 0) {
155
+ lastTopLevelWhitespace = index;
156
+ }
157
+
158
+ // Check if the next word is a preferred keyword
159
+ const nextWordStart = index + 1;
160
+ if (nextWordStart < text.length && isWordChar(text[nextWordStart])) {
161
+ let wordEnd = nextWordStart + 1;
162
+ while (wordEnd < text.length && isWordChar(text[wordEnd])) {
163
+ wordEnd += 1;
164
+ }
165
+ const word = text.slice(nextWordStart, wordEnd).toUpperCase();
166
+ if (WRAP_PREFERRED_KEYWORDS.has(word)) {
167
+ // Don't break between CREATE and object type, COMMENT and ON, or ALL and ON (GRANT/REVOKE ALL ON)
168
+ const prev = getPreviousWord(text, index);
169
+ if (
170
+ prev !== null &&
171
+ ((prev === "CREATE" && KEEP_WITH_PREVIOUS.has(word)) ||
172
+ ((prev === "COMMENT" || prev === "ALL") && word === "ON"))
173
+ ) {
174
+ return true;
175
+ }
176
+ lastKeywordBoundary = index;
177
+ }
178
+ }
179
+ }
180
+ return true;
181
+ },
182
+ { trackDepth: true },
183
+ );
184
+
185
+ // Prefer: 1) comma, 2) keyword boundary, 3) depth-0 whitespace, 4) any whitespace
186
+ if (firstComma > 0 && firstComma <= maxWidth) {
187
+ return firstComma;
188
+ }
189
+ if (lastKeywordBoundary > 0 && lastKeywordBoundary <= maxWidth) {
190
+ return lastKeywordBoundary;
191
+ }
192
+ if (lastTopLevelWhitespace > 0) {
193
+ return lastTopLevelWhitespace;
194
+ }
195
+ return lastAnyWhitespace;
196
+ }
@@ -0,0 +1,2 @@
1
+ export { formatSqlStatements } from "./sql-format/index.ts";
2
+ export type { SqlFormatOptions } from "./sql-format/types.ts";
@@ -0,0 +1,22 @@
1
+ /**
2
+ * SQL script formatting utilities.
3
+ */
4
+
5
+ import { formatSqlStatements, type SqlFormatOptions } from "./sql-format.ts";
6
+
7
+ const STATEMENT_DELIMITER = ";\n\n";
8
+
9
+ /**
10
+ * Format an array of SQL statements into a single script string.
11
+ * Statements are joined with double newlines and the script ends with a semicolon.
12
+ */
13
+ export function formatSqlScript(
14
+ statements: string[],
15
+ options?: SqlFormatOptions,
16
+ ): string {
17
+ if (statements.length === 0) return "";
18
+ const formatted = options
19
+ ? formatSqlStatements(statements, options)
20
+ : statements;
21
+ return `${formatted.join(STATEMENT_DELIMITER)};`;
22
+ }
@@ -0,0 +1,165 @@
1
+ /**
2
+ * Type definitions for the Plan module.
3
+ */
4
+
5
+ import z from "zod";
6
+ import type { Change } from "../change.types.ts";
7
+ import type { FilterDSL } from "../integrations/filter/dsl.ts";
8
+ import type { ChangeFilter } from "../integrations/filter/filter.types.ts";
9
+ import type { SerializeDSL } from "../integrations/serialize/dsl.ts";
10
+ import type { ChangeSerializer } from "../integrations/serialize/serialize.types.ts";
11
+
12
+ // ============================================================================
13
+ // Core Types
14
+ // ============================================================================
15
+
16
+ export type PlanRisk =
17
+ | { level: "safe" }
18
+ | { level: "data_loss"; statements: string[] };
19
+
20
+ /**
21
+ * All supported object types in the system.
22
+ * Derived from the Change union type's objectType discriminant.
23
+ */
24
+ type ObjectType = Change["objectType"];
25
+
26
+ /**
27
+ * Parent types for child objects.
28
+ */
29
+ export type ParentType = Extract<
30
+ ObjectType,
31
+ "table" | "view" | "materialized_view" | "foreign_table"
32
+ >;
33
+
34
+ /**
35
+ * A change entry storing both serialized and original change for instanceof checks.
36
+ */
37
+ export interface ChangeEntry {
38
+ original: Change;
39
+ }
40
+
41
+ /**
42
+ * A group of changes organized by operation.
43
+ */
44
+ export interface ChangeGroup {
45
+ create: ChangeEntry[];
46
+ alter: ChangeEntry[];
47
+ drop: ChangeEntry[];
48
+ }
49
+
50
+ /**
51
+ * Children objects of a table/view (indexes, triggers, policies, etc.)
52
+ */
53
+ export interface TableChildren {
54
+ changes: ChangeGroup;
55
+ columns: ChangeGroup;
56
+ indexes: ChangeGroup;
57
+ triggers: ChangeGroup;
58
+ rules: ChangeGroup;
59
+ policies: ChangeGroup;
60
+ /** Partition tables (only for partitioned tables) */
61
+ partitions: Record<string, TableChildren>;
62
+ }
63
+
64
+ /**
65
+ * Children objects of a materialized view
66
+ */
67
+ export interface MaterializedViewChildren {
68
+ changes: ChangeGroup;
69
+ indexes: ChangeGroup;
70
+ }
71
+
72
+ /**
73
+ * Type grouping within a schema
74
+ */
75
+ export interface TypeGroup {
76
+ enums: ChangeGroup;
77
+ composites: ChangeGroup;
78
+ ranges: ChangeGroup;
79
+ domains: ChangeGroup;
80
+ }
81
+
82
+ /**
83
+ * Schema-level grouping of objects
84
+ */
85
+ export interface SchemaGroup {
86
+ changes: ChangeGroup;
87
+ tables: Record<string, TableChildren>;
88
+ views: Record<string, TableChildren>;
89
+ materializedViews: Record<string, MaterializedViewChildren>;
90
+ functions: ChangeGroup;
91
+ procedures: ChangeGroup;
92
+ aggregates: ChangeGroup;
93
+ sequences: ChangeGroup;
94
+ types: TypeGroup;
95
+ collations: ChangeGroup;
96
+ foreignTables: Record<string, TableChildren>;
97
+ }
98
+
99
+ /**
100
+ * Cluster-wide objects (no schema)
101
+ */
102
+ export interface ClusterGroup {
103
+ roles: ChangeGroup;
104
+ extensions: ChangeGroup;
105
+ eventTriggers: ChangeGroup;
106
+ publications: ChangeGroup;
107
+ subscriptions: ChangeGroup;
108
+ foreignDataWrappers: ChangeGroup;
109
+ servers: ChangeGroup;
110
+ userMappings: ChangeGroup;
111
+ }
112
+
113
+ /**
114
+ * Fully hierarchical plan structure for tree display.
115
+ */
116
+ export interface HierarchicalPlan {
117
+ cluster: ClusterGroup;
118
+ schemas: Record<string, SchemaGroup>;
119
+ }
120
+
121
+ /**
122
+ * Plan schema for serialization/deserialization.
123
+ */
124
+ export const PlanSchema = z.object({
125
+ version: z.number(),
126
+ toolVersion: z.string().optional(),
127
+ source: z.object({
128
+ fingerprint: z.string(),
129
+ }),
130
+ target: z.object({
131
+ fingerprint: z.string(),
132
+ }),
133
+ statements: z.array(z.string()),
134
+ role: z.string().optional(),
135
+ filter: z.any().optional(), // FilterDSL - complex recursive type, validated at compile time
136
+ serialize: z.any().optional(), // SerializeDSL - complex recursive type, validated at compile time
137
+ risk: z
138
+ .discriminatedUnion("level", [
139
+ z.object({
140
+ level: z.literal("safe"),
141
+ }),
142
+ z.object({
143
+ level: z.literal("data_loss"),
144
+ statements: z.array(z.string()),
145
+ }),
146
+ ])
147
+ .optional(),
148
+ });
149
+
150
+ /**
151
+ * A migration plan containing all changes to transform one database schema into another.
152
+ */
153
+ export type Plan = z.infer<typeof PlanSchema>;
154
+
155
+ /**
156
+ * Options for creating a plan.
157
+ */
158
+ export interface CreatePlanOptions {
159
+ /** Filter - either FilterDSL (stored in plan) or ChangeFilter function (not stored) */
160
+ filter?: FilterDSL | ChangeFilter;
161
+ /** Serialize - either SerializeDSL (stored in plan) or ChangeSerializer function (not stored) */
162
+ serialize?: SerializeDSL | ChangeSerializer;
163
+ /** Role to use when executing the migration (SET ROLE will be added to statements) */
164
+ role?: string;
165
+ }
@@ -0,0 +1,169 @@
1
+ /**
2
+ * PostgreSQL connection configuration with custom type handlers.
3
+ */
4
+
5
+ import type { PoolClient, PoolConfig } from "pg";
6
+ import { Pool, types } from "pg";
7
+
8
+ // ============================================================================
9
+ // Array Parser
10
+ // ============================================================================
11
+
12
+ /**
13
+ * Parse PostgreSQL array string into JavaScript array.
14
+ * Handles: {val1,val2}, {NULL,val}, {"quoted,val"}, nested arrays.
15
+ */
16
+ function parseArray(
17
+ value: string,
18
+ parseElement: (val: string) => unknown = (v) => v,
19
+ ): unknown[] {
20
+ if (!value || value === "{}") return [];
21
+
22
+ // Remove outer braces
23
+ const inner = value.slice(1, -1);
24
+ if (inner === "") return [];
25
+
26
+ const result: unknown[] = [];
27
+ let current = "";
28
+ let inQuotes = false;
29
+ let depth = 0;
30
+
31
+ for (let i = 0; i < inner.length; i++) {
32
+ const char = inner[i];
33
+
34
+ if (char === '"' && inner[i - 1] !== "\\") {
35
+ inQuotes = !inQuotes;
36
+ current += char;
37
+ } else if (char === "{" && !inQuotes) {
38
+ depth++;
39
+ current += char;
40
+ } else if (char === "}" && !inQuotes) {
41
+ depth--;
42
+ current += char;
43
+ } else if (char === "," && !inQuotes && depth === 0) {
44
+ result.push(parseElement(current));
45
+ current = "";
46
+ } else {
47
+ current += char;
48
+ }
49
+ }
50
+
51
+ if (current !== "") {
52
+ result.push(parseElement(current));
53
+ }
54
+
55
+ return result;
56
+ }
57
+
58
+ /**
59
+ * Parse element, handling NULL, quoted strings, and unquoted values.
60
+ */
61
+ function parseStringElement(val: string): string | null {
62
+ if (val === "NULL") return null;
63
+ if (val.startsWith('"') && val.endsWith('"')) {
64
+ // Unescape quoted string
65
+ return val.slice(1, -1).replace(/\\(.)/g, "$1");
66
+ }
67
+ return val;
68
+ }
69
+
70
+ function parseIntElement(val: string): number | null {
71
+ if (val === "NULL") return null;
72
+ return Number.parseInt(val, 10);
73
+ }
74
+
75
+ // ============================================================================
76
+ // Type Parsers
77
+ // ============================================================================
78
+
79
+ // int2vector: "1 2 3" -> [1, 2, 3]
80
+ // @ts-expect-error - pg types expects TypeId but raw OID numbers work fine
81
+ types.setTypeParser(22, (val: string) => {
82
+ if (!val || val === "") return [];
83
+ return val
84
+ .split(" ")
85
+ .map(Number)
86
+ .filter((n: number) => !Number.isNaN(n));
87
+ });
88
+
89
+ // bigint: string -> BigInt
90
+ types.setTypeParser(20, (val: string) => BigInt(val));
91
+
92
+ // PostgreSQL array types
93
+ // @ts-expect-error - pg types expects TypeId but raw OID numbers work fine
94
+ types.setTypeParser(1002, (val: string) => parseArray(val, parseStringElement)); // "char"[]
95
+ // @ts-expect-error - pg types expects TypeId but raw OID numbers work fine
96
+ types.setTypeParser(1009, (val: string) => parseArray(val, parseStringElement)); // text[]
97
+ // @ts-expect-error - pg types expects TypeId but raw OID numbers work fine
98
+ types.setTypeParser(1015, (val: string) => parseArray(val, parseStringElement)); // varchar[]
99
+ // @ts-expect-error - pg types expects TypeId but raw OID numbers work fine
100
+ types.setTypeParser(1005, (val: string) => parseArray(val, parseIntElement)); // int2[]
101
+ // @ts-expect-error - pg types expects TypeId but raw OID numbers work fine
102
+ types.setTypeParser(1007, (val: string) => parseArray(val, parseIntElement)); // int4[]
103
+ // @ts-expect-error - pg types expects TypeId but raw OID numbers work fine
104
+ types.setTypeParser(1016, (val: string) => parseArray(val, parseIntElement)); // int8[]
105
+
106
+ /**
107
+ * Options for creating a Pool with event listeners.
108
+ */
109
+ interface CreatePoolOptions extends Partial<PoolConfig> {
110
+ /** Called when a new client connects to the pool */
111
+ onConnect?: (client: PoolClient) => void | Promise<void>;
112
+ /** Called when an idle client emits an error */
113
+ onError?: (err: Error, client: PoolClient) => void;
114
+ /** Called when a client is acquired from the pool */
115
+ onAcquire?: (client: PoolClient) => void;
116
+ /** Called when a client is removed from the pool */
117
+ onRemove?: (client: PoolClient) => void;
118
+ }
119
+
120
+ /**
121
+ * Create a Pool with custom type handlers and optional event listeners.
122
+ */
123
+ export function createPool(
124
+ connectionString: string,
125
+ options?: CreatePoolOptions,
126
+ ): Pool {
127
+ const { onConnect, onError, onAcquire, onRemove, ...config } = options ?? {};
128
+ const pool = new Pool({ connectionString, ...config });
129
+
130
+ if (onConnect) pool.on("connect", onConnect);
131
+ if (onError) pool.on("error", onError);
132
+ if (onAcquire) pool.on("acquire", onAcquire);
133
+ if (onRemove) pool.on("remove", onRemove);
134
+
135
+ return pool;
136
+ }
137
+
138
+ /**
139
+ * End a pool and wait for all client sockets to fully close.
140
+ *
141
+ * pg-pool's `pool.end()` resolves once clients are removed from its
142
+ * internal bookkeeping, but the underlying `client.end()` calls (which
143
+ * close the TCP/TLS sockets) are fired asynchronously *after* that.
144
+ * If the server (e.g. a test container) is stopped right after
145
+ * `pool.end()` resolves, the still-open sockets receive an unexpected
146
+ * RST and emit unhandled "Connection terminated unexpectedly" errors.
147
+ *
148
+ * This helper waits for every `remove` event — which pg-pool emits
149
+ * inside each `client.end()` callback — ensuring all sockets are
150
+ * truly closed before it resolves.
151
+ */
152
+ export function endPool(pool: Pool): Promise<void> {
153
+ const clientCount = pool.totalCount;
154
+
155
+ if (clientCount === 0) {
156
+ return pool.end();
157
+ }
158
+
159
+ return new Promise<void>((resolve, reject) => {
160
+ let removed = 0;
161
+ pool.on("remove", function onRemove() {
162
+ if (++removed >= clientCount) {
163
+ pool.removeListener("remove", onRemove);
164
+ resolve();
165
+ }
166
+ });
167
+ pool.end().catch(reject);
168
+ });
169
+ }