@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,133 @@
1
+ import { sql } from "@ts-safeql/sql-tag";
2
+ import type { Pool } from "pg";
3
+ import z from "zod";
4
+ import { BasePgModel } from "../../base.model.ts";
5
+ import {
6
+ type PrivilegeProps,
7
+ privilegePropsSchema,
8
+ } from "../../base.privilege-diff.ts";
9
+
10
+ /**
11
+ * All properties exposed by CREATE SERVER statement are included in diff output.
12
+ * https://www.postgresql.org/docs/17/sql-createserver.html
13
+ *
14
+ * ALTER SERVER statement can be generated for changes to the following properties:
15
+ * - owner, type, version, options
16
+ * https://www.postgresql.org/docs/17/sql-alterserver.html
17
+ *
18
+ * Servers are not schema-qualified (no schema property).
19
+ */
20
+ const serverPropsSchema = z.object({
21
+ name: z.string(),
22
+ owner: z.string(),
23
+ foreign_data_wrapper: z.string(),
24
+ type: z.string().nullable(),
25
+ version: z.string().nullable(),
26
+ options: z.array(z.string()).nullable(),
27
+ comment: z.string().nullable(),
28
+ privileges: z.array(privilegePropsSchema),
29
+ });
30
+
31
+ type ServerPrivilegeProps = PrivilegeProps;
32
+ export type ServerProps = z.infer<typeof serverPropsSchema>;
33
+
34
+ export class Server extends BasePgModel {
35
+ public readonly name: ServerProps["name"];
36
+ public readonly owner: ServerProps["owner"];
37
+ public readonly foreign_data_wrapper: ServerProps["foreign_data_wrapper"];
38
+ public readonly type: ServerProps["type"];
39
+ public readonly version: ServerProps["version"];
40
+ public readonly options: ServerProps["options"];
41
+ public readonly comment: ServerProps["comment"];
42
+ public readonly privileges: ServerPrivilegeProps[];
43
+
44
+ constructor(props: ServerProps) {
45
+ super();
46
+
47
+ // Identity fields
48
+ this.name = props.name;
49
+
50
+ // Data fields
51
+ this.owner = props.owner;
52
+ this.foreign_data_wrapper = props.foreign_data_wrapper;
53
+ this.type = props.type;
54
+ this.version = props.version;
55
+ this.options = props.options;
56
+ this.comment = props.comment;
57
+ this.privileges = props.privileges;
58
+ }
59
+
60
+ get stableId(): `server:${string}` {
61
+ return `server:${this.name}`;
62
+ }
63
+
64
+ get identityFields() {
65
+ return {
66
+ name: this.name,
67
+ };
68
+ }
69
+
70
+ get dataFields() {
71
+ return {
72
+ owner: this.owner,
73
+ foreign_data_wrapper: this.foreign_data_wrapper,
74
+ type: this.type,
75
+ version: this.version,
76
+ options: this.options,
77
+ comment: this.comment,
78
+ privileges: this.privileges,
79
+ };
80
+ }
81
+ }
82
+
83
+ export async function extractServers(pool: Pool): Promise<Server[]> {
84
+ const { rows: serverRows } = await pool.query<ServerProps>(sql`
85
+ select
86
+ quote_ident(srv.srvname) as name,
87
+ srv.srvowner::regrole::text as owner,
88
+ quote_ident(fdw.fdwname) as foreign_data_wrapper,
89
+ srv.srvtype as type,
90
+ srv.srvversion as version,
91
+ coalesce(srv.srvoptions, array[]::text[]) as options,
92
+ obj_description(srv.oid, 'pg_foreign_server') as comment,
93
+ coalesce(
94
+ (
95
+ select json_agg(
96
+ json_build_object(
97
+ 'grantee', case when x.grantee = 0 then 'PUBLIC' else x.grantee::regrole::text end,
98
+ 'privilege', x.privilege_type,
99
+ 'grantable', x.is_grantable
100
+ )
101
+ order by x.grantee, x.privilege_type
102
+ )
103
+ from lateral aclexplode(srv.srvacl) as x(grantor, grantee, privilege_type, is_grantable)
104
+ ), '[]'
105
+ ) as privileges
106
+ from
107
+ pg_catalog.pg_foreign_server srv
108
+ inner join pg_catalog.pg_foreign_data_wrapper fdw on fdw.oid = srv.srvfdw
109
+ where
110
+ not fdw.fdwname like any(array['pg\\_%'])
111
+ order by
112
+ srv.srvname
113
+ `);
114
+
115
+ // Validate and parse each row using the Zod schema
116
+ const validatedRows = serverRows.map((row: unknown) => {
117
+ const parsed = serverPropsSchema.parse(row);
118
+ // Parse options from PostgreSQL format ['key=value'] to ['key', 'value']
119
+ if (parsed.options && parsed.options.length > 0) {
120
+ const parsedOptions: string[] = [];
121
+ for (const opt of parsed.options) {
122
+ const eqIndex = opt.indexOf("=");
123
+ if (eqIndex > 0) {
124
+ parsedOptions.push(opt.substring(0, eqIndex));
125
+ parsedOptions.push(opt.substring(eqIndex + 1));
126
+ }
127
+ }
128
+ parsed.options = parsedOptions.length > 0 ? parsedOptions : null;
129
+ }
130
+ return parsed;
131
+ });
132
+ return validatedRows.map((row: ServerProps) => new Server(row));
133
+ }
@@ -0,0 +1,82 @@
1
+ import { describe, expect, test } from "bun:test";
2
+ import { UserMapping, type UserMappingProps } from "../user-mapping.model.ts";
3
+ import { AlterUserMappingSetOptions } from "./user-mapping.alter.ts";
4
+
5
+ describe.concurrent("user-mapping", () => {
6
+ describe("alter", () => {
7
+ test("set options ADD", () => {
8
+ const props: UserMappingProps = {
9
+ user: "test_user",
10
+ server: "test_server",
11
+ options: null,
12
+ };
13
+ const userMapping = new UserMapping(props);
14
+ const change = new AlterUserMappingSetOptions({
15
+ userMapping,
16
+ options: [
17
+ { action: "ADD", option: "user", value: "remote_user" },
18
+ { action: "ADD", option: "password", value: "secret" },
19
+ ],
20
+ });
21
+
22
+ expect(change.serialize()).toBe(
23
+ "ALTER USER MAPPING FOR test_user SERVER test_server OPTIONS (ADD user 'remote_user', ADD password 'secret')",
24
+ );
25
+ });
26
+
27
+ test("set options SET", () => {
28
+ const props: UserMappingProps = {
29
+ user: "test_user",
30
+ server: "test_server",
31
+ options: null,
32
+ };
33
+ const userMapping = new UserMapping(props);
34
+ const change = new AlterUserMappingSetOptions({
35
+ userMapping,
36
+ options: [{ action: "SET", option: "password", value: "new_secret" }],
37
+ });
38
+
39
+ expect(change.serialize()).toBe(
40
+ "ALTER USER MAPPING FOR test_user SERVER test_server OPTIONS (SET password 'new_secret')",
41
+ );
42
+ });
43
+
44
+ test("set options DROP", () => {
45
+ const props: UserMappingProps = {
46
+ user: "test_user",
47
+ server: "test_server",
48
+ options: null,
49
+ };
50
+ const userMapping = new UserMapping(props);
51
+ const change = new AlterUserMappingSetOptions({
52
+ userMapping,
53
+ options: [{ action: "DROP", option: "password" }],
54
+ });
55
+
56
+ expect(change.serialize()).toBe(
57
+ "ALTER USER MAPPING FOR test_user SERVER test_server OPTIONS (DROP password)",
58
+ );
59
+ });
60
+
61
+ test("set options mixed ADD/SET/DROP", () => {
62
+ const props: UserMappingProps = {
63
+ user: "PUBLIC",
64
+ server: "test_server",
65
+ options: null,
66
+ };
67
+ const userMapping = new UserMapping(props);
68
+ const change = new AlterUserMappingSetOptions({
69
+ userMapping,
70
+ options: [
71
+ { action: "ADD", option: "new_option", value: "new_value" },
72
+ { action: "SET", option: "existing_option", value: "updated_value" },
73
+ { action: "DROP", option: "old_option" },
74
+ ],
75
+ });
76
+
77
+ expect(change.serialize()).toBe(
78
+ "ALTER USER MAPPING FOR PUBLIC SERVER test_server OPTIONS (ADD new_option 'new_value', SET existing_option 'updated_value', DROP old_option)",
79
+ );
80
+ });
81
+ });
82
+ });
@@ -0,0 +1,69 @@
1
+ import { quoteLiteral } from "../../../base.change.ts";
2
+ import type { UserMapping } from "../user-mapping.model.ts";
3
+ import { AlterUserMappingChange } from "./user-mapping.base.ts";
4
+
5
+ /**
6
+ * Alter a user mapping.
7
+ *
8
+ * @see https://www.postgresql.org/docs/17/sql-alterusermapping.html
9
+ *
10
+ * Synopsis
11
+ * ```sql
12
+ * ALTER USER MAPPING FOR { user_name | USER | CURRENT_ROLE | CURRENT_USER | PUBLIC | SESSION_USER }
13
+ * SERVER server_name
14
+ * OPTIONS ( [ ADD | SET | DROP ] option ['value'] [, ... ] )
15
+ * ```
16
+ */
17
+
18
+ export type AlterUserMapping = AlterUserMappingSetOptions;
19
+
20
+ /**
21
+ * ALTER USER MAPPING ... OPTIONS ( ADD | SET | DROP ... )
22
+ */
23
+ export class AlterUserMappingSetOptions extends AlterUserMappingChange {
24
+ public readonly userMapping: UserMapping;
25
+ public readonly options: Array<{
26
+ action: "ADD" | "SET" | "DROP";
27
+ option: string;
28
+ value?: string;
29
+ }>;
30
+ public readonly scope = "object" as const;
31
+
32
+ constructor(props: {
33
+ userMapping: UserMapping;
34
+ options: Array<{
35
+ action: "ADD" | "SET" | "DROP";
36
+ option: string;
37
+ value?: string;
38
+ }>;
39
+ }) {
40
+ super();
41
+ this.userMapping = props.userMapping;
42
+ this.options = props.options;
43
+ }
44
+
45
+ get requires() {
46
+ return [this.userMapping.stableId];
47
+ }
48
+
49
+ serialize(): string {
50
+ const optionParts: string[] = [];
51
+ for (const opt of this.options) {
52
+ if (opt.action === "DROP") {
53
+ optionParts.push(`DROP ${opt.option}`);
54
+ } else {
55
+ const value = opt.value !== undefined ? quoteLiteral(opt.value) : "''";
56
+ optionParts.push(`${opt.action} ${opt.option} ${value}`);
57
+ }
58
+ }
59
+
60
+ return [
61
+ "ALTER USER MAPPING FOR",
62
+ this.userMapping.user,
63
+ "SERVER",
64
+ this.userMapping.server,
65
+ "OPTIONS",
66
+ `(${optionParts.join(", ")})`,
67
+ ].join(" ");
68
+ }
69
+ }
@@ -0,0 +1,20 @@
1
+ import { BaseChange } from "../../../base.change.ts";
2
+ import type { UserMapping } from "../user-mapping.model.ts";
3
+
4
+ abstract class BaseUserMappingChange extends BaseChange {
5
+ abstract readonly userMapping: UserMapping;
6
+ abstract readonly scope: "object";
7
+ readonly objectType: "user_mapping" = "user_mapping";
8
+ }
9
+
10
+ export abstract class CreateUserMappingChange extends BaseUserMappingChange {
11
+ readonly operation = "create" as const;
12
+ }
13
+
14
+ export abstract class AlterUserMappingChange extends BaseUserMappingChange {
15
+ readonly operation = "alter" as const;
16
+ }
17
+
18
+ export abstract class DropUserMappingChange extends BaseUserMappingChange {
19
+ readonly operation = "drop" as const;
20
+ }
@@ -0,0 +1,85 @@
1
+ import { describe, expect, test } from "bun:test";
2
+ import { UserMapping } from "../user-mapping.model.ts";
3
+ import { CreateUserMapping } from "./user-mapping.create.ts";
4
+
5
+ describe("user-mapping", () => {
6
+ test("create basic", () => {
7
+ const userMapping = new UserMapping({
8
+ user: "test_user",
9
+ server: "test_server",
10
+ options: null,
11
+ });
12
+
13
+ const change = new CreateUserMapping({
14
+ userMapping,
15
+ });
16
+
17
+ expect(change.serialize()).toBe(
18
+ "CREATE USER MAPPING FOR test_user SERVER test_server",
19
+ );
20
+ });
21
+
22
+ test("create with PUBLIC user", () => {
23
+ const userMapping = new UserMapping({
24
+ user: "PUBLIC",
25
+ server: "test_server",
26
+ options: null,
27
+ });
28
+
29
+ const change = new CreateUserMapping({
30
+ userMapping,
31
+ });
32
+
33
+ expect(change.serialize()).toBe(
34
+ "CREATE USER MAPPING FOR PUBLIC SERVER test_server",
35
+ );
36
+ });
37
+
38
+ test("create with CURRENT_USER", () => {
39
+ const userMapping = new UserMapping({
40
+ user: "CURRENT_USER",
41
+ server: "test_server",
42
+ options: null,
43
+ });
44
+
45
+ const change = new CreateUserMapping({
46
+ userMapping,
47
+ });
48
+
49
+ expect(change.serialize()).toBe(
50
+ "CREATE USER MAPPING FOR CURRENT_USER SERVER test_server",
51
+ );
52
+ });
53
+
54
+ test("create with options", () => {
55
+ const userMapping = new UserMapping({
56
+ user: "test_user",
57
+ server: "test_server",
58
+ options: ["user", "remote_user", "password", "secret"],
59
+ });
60
+
61
+ const change = new CreateUserMapping({
62
+ userMapping,
63
+ });
64
+
65
+ expect(change.serialize()).toBe(
66
+ "CREATE USER MAPPING FOR test_user SERVER test_server OPTIONS (user 'remote_user', password 'secret')",
67
+ );
68
+ });
69
+
70
+ test("create with all properties", () => {
71
+ const userMapping = new UserMapping({
72
+ user: "PUBLIC",
73
+ server: "test_server",
74
+ options: ["user", "remote_user", "password", "secret"],
75
+ });
76
+
77
+ const change = new CreateUserMapping({
78
+ userMapping,
79
+ });
80
+
81
+ expect(change.serialize()).toBe(
82
+ "CREATE USER MAPPING FOR PUBLIC SERVER test_server OPTIONS (user 'remote_user', password 'secret')",
83
+ );
84
+ });
85
+ });
@@ -0,0 +1,66 @@
1
+ import { quoteLiteral } from "../../../base.change.ts";
2
+ import { stableId } from "../../../utils.ts";
3
+ import type { UserMapping } from "../user-mapping.model.ts";
4
+ import { CreateUserMappingChange } from "./user-mapping.base.ts";
5
+
6
+ /**
7
+ * Create a user mapping.
8
+ *
9
+ * @see https://www.postgresql.org/docs/17/sql-createusermapping.html
10
+ *
11
+ * Synopsis
12
+ * ```sql
13
+ * CREATE USER MAPPING [ IF NOT EXISTS ] FOR { user_name | USER | CURRENT_ROLE | CURRENT_USER | PUBLIC | SESSION_USER }
14
+ * SERVER server_name
15
+ * [ OPTIONS ( option 'value' [, ... ] ) ]
16
+ * ```
17
+ */
18
+ export class CreateUserMapping extends CreateUserMappingChange {
19
+ public readonly userMapping: UserMapping;
20
+ public readonly scope = "object" as const;
21
+
22
+ constructor(props: { userMapping: UserMapping }) {
23
+ super();
24
+ this.userMapping = props.userMapping;
25
+ }
26
+
27
+ get creates() {
28
+ return [this.userMapping.stableId];
29
+ }
30
+
31
+ get requires() {
32
+ const dependencies = new Set<string>();
33
+
34
+ // Server dependency
35
+ dependencies.add(stableId.server(this.userMapping.server));
36
+
37
+ return Array.from(dependencies);
38
+ }
39
+
40
+ serialize(): string {
41
+ const parts: string[] = ["CREATE USER MAPPING FOR"];
42
+
43
+ // Add user (can be CURRENT_USER, PUBLIC, etc.)
44
+ parts.push(this.userMapping.user);
45
+
46
+ // Add SERVER clause
47
+ parts.push("SERVER", this.userMapping.server);
48
+
49
+ // Add OPTIONS clause
50
+ if (this.userMapping.options && this.userMapping.options.length > 0) {
51
+ const optionPairs: string[] = [];
52
+ for (let i = 0; i < this.userMapping.options.length; i += 2) {
53
+ if (i + 1 < this.userMapping.options.length) {
54
+ optionPairs.push(
55
+ `${this.userMapping.options[i]} ${quoteLiteral(this.userMapping.options[i + 1])}`,
56
+ );
57
+ }
58
+ }
59
+ if (optionPairs.length > 0) {
60
+ parts.push(`OPTIONS (${optionPairs.join(", ")})`);
61
+ }
62
+ }
63
+
64
+ return parts.join(" ");
65
+ }
66
+ }
@@ -0,0 +1,53 @@
1
+ import { describe, expect, test } from "bun:test";
2
+ import { UserMapping } from "../user-mapping.model.ts";
3
+ import { DropUserMapping } from "./user-mapping.drop.ts";
4
+
5
+ describe("user-mapping", () => {
6
+ test("drop", () => {
7
+ const userMapping = new UserMapping({
8
+ user: "test_user",
9
+ server: "test_server",
10
+ options: null,
11
+ });
12
+
13
+ const change = new DropUserMapping({
14
+ userMapping,
15
+ });
16
+
17
+ expect(change.serialize()).toBe(
18
+ "DROP USER MAPPING FOR test_user SERVER test_server",
19
+ );
20
+ });
21
+
22
+ test("drop PUBLIC user mapping", () => {
23
+ const userMapping = new UserMapping({
24
+ user: "PUBLIC",
25
+ server: "test_server",
26
+ options: null,
27
+ });
28
+
29
+ const change = new DropUserMapping({
30
+ userMapping,
31
+ });
32
+
33
+ expect(change.serialize()).toBe(
34
+ "DROP USER MAPPING FOR PUBLIC SERVER test_server",
35
+ );
36
+ });
37
+
38
+ test("drop CURRENT_USER mapping", () => {
39
+ const userMapping = new UserMapping({
40
+ user: "CURRENT_USER",
41
+ server: "test_server",
42
+ options: null,
43
+ });
44
+
45
+ const change = new DropUserMapping({
46
+ userMapping,
47
+ });
48
+
49
+ expect(change.serialize()).toBe(
50
+ "DROP USER MAPPING FOR CURRENT_USER SERVER test_server",
51
+ );
52
+ });
53
+ });
@@ -0,0 +1,40 @@
1
+ import type { UserMapping } from "../user-mapping.model.ts";
2
+ import { DropUserMappingChange } from "./user-mapping.base.ts";
3
+
4
+ /**
5
+ * Drop a user mapping.
6
+ *
7
+ * @see https://www.postgresql.org/docs/17/sql-dropusermapping.html
8
+ *
9
+ * Synopsis
10
+ * ```sql
11
+ * DROP USER MAPPING [ IF EXISTS ] FOR { user_name | USER | CURRENT_ROLE | CURRENT_USER | PUBLIC | SESSION_USER }
12
+ * SERVER server_name
13
+ * ```
14
+ */
15
+ export class DropUserMapping extends DropUserMappingChange {
16
+ public readonly userMapping: UserMapping;
17
+ public readonly scope = "object" as const;
18
+
19
+ constructor(props: { userMapping: UserMapping }) {
20
+ super();
21
+ this.userMapping = props.userMapping;
22
+ }
23
+
24
+ get drops() {
25
+ return [this.userMapping.stableId];
26
+ }
27
+
28
+ get requires() {
29
+ return [this.userMapping.stableId];
30
+ }
31
+
32
+ serialize(): string {
33
+ return [
34
+ "DROP USER MAPPING FOR",
35
+ this.userMapping.user,
36
+ "SERVER",
37
+ this.userMapping.server,
38
+ ].join(" ");
39
+ }
40
+ }
@@ -0,0 +1,8 @@
1
+ import type { AlterUserMapping } from "./user-mapping.alter.ts";
2
+ import type { CreateUserMapping } from "./user-mapping.create.ts";
3
+ import type { DropUserMapping } from "./user-mapping.drop.ts";
4
+
5
+ export type UserMappingChange =
6
+ | AlterUserMapping
7
+ | CreateUserMapping
8
+ | DropUserMapping;
@@ -0,0 +1,77 @@
1
+ import { describe, expect, test } from "bun:test";
2
+ import { AlterUserMappingSetOptions } from "./changes/user-mapping.alter.ts";
3
+ import { CreateUserMapping } from "./changes/user-mapping.create.ts";
4
+ import { DropUserMapping } from "./changes/user-mapping.drop.ts";
5
+ import { diffUserMappings } from "./user-mapping.diff.ts";
6
+ import { UserMapping, type UserMappingProps } from "./user-mapping.model.ts";
7
+
8
+ describe.concurrent("user-mapping.diff", () => {
9
+ test("create and drop", () => {
10
+ const props: UserMappingProps = {
11
+ user: "u1",
12
+ server: "srv1",
13
+ options: null,
14
+ };
15
+ const mapping = new UserMapping(props);
16
+
17
+ const created = diffUserMappings({}, { [mapping.stableId]: mapping });
18
+ expect(created[0]).toBeInstanceOf(CreateUserMapping);
19
+
20
+ const dropped = diffUserMappings({ [mapping.stableId]: mapping }, {});
21
+ expect(dropped[0]).toBeInstanceOf(DropUserMapping);
22
+ });
23
+
24
+ test("alter: options changes", () => {
25
+ // With the simplified approach, SET actions are filtered out, but ADD actions are not.
26
+ // Adding a new option (password) should generate an ALTER statement.
27
+ const main = new UserMapping({
28
+ user: "u1",
29
+ server: "srv1",
30
+ options: ["user", "remote_user"],
31
+ });
32
+ const branch = new UserMapping({
33
+ user: "u1",
34
+ server: "srv1",
35
+ options: ["user", "remote_user", "password", "secret"],
36
+ });
37
+
38
+ const changes = diffUserMappings(
39
+ { [main.stableId]: main },
40
+ { [branch.stableId]: branch },
41
+ );
42
+ // ADD actions are not filtered, so ALTER should be generated
43
+ const optionsChange = changes.find(
44
+ (c) => c instanceof AlterUserMappingSetOptions,
45
+ ) as AlterUserMappingSetOptions | undefined;
46
+ expect(optionsChange).toBeDefined();
47
+ expect(optionsChange?.options).toEqual([
48
+ { action: "ADD", option: "password", value: "secret" },
49
+ ]);
50
+ });
51
+
52
+ test("create with PUBLIC user", () => {
53
+ const mapping = new UserMapping({
54
+ user: "PUBLIC",
55
+ server: "srv1",
56
+ options: null,
57
+ });
58
+
59
+ const created = diffUserMappings({}, { [mapping.stableId]: mapping });
60
+ expect(created[0]).toBeInstanceOf(CreateUserMapping);
61
+ expect((created[0] as CreateUserMapping).userMapping.user).toBe("PUBLIC");
62
+ });
63
+
64
+ test("create with CURRENT_USER", () => {
65
+ const mapping = new UserMapping({
66
+ user: "CURRENT_USER",
67
+ server: "srv1",
68
+ options: null,
69
+ });
70
+
71
+ const created = diffUserMappings({}, { [mapping.stableId]: mapping });
72
+ expect(created[0]).toBeInstanceOf(CreateUserMapping);
73
+ expect((created[0] as CreateUserMapping).userMapping.user).toBe(
74
+ "CURRENT_USER",
75
+ );
76
+ });
77
+ });