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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (464) hide show
  1. package/README.md +22 -0
  2. package/dist/cli/bin/cli.js +0 -0
  3. package/dist/cli/commands/plan.js +21 -0
  4. package/dist/cli/utils.d.ts +2 -0
  5. package/dist/cli/utils.js +1 -1
  6. package/dist/core/integrations/supabase.js +2 -0
  7. package/dist/core/objects/table/table.model.d.ts +4 -2
  8. package/dist/core/objects/table/table.model.js +3 -0
  9. package/dist/core/objects/trigger/changes/trigger.alter.js +23 -0
  10. package/dist/core/objects/trigger/changes/trigger.create.js +2 -1
  11. package/dist/core/objects/trigger/trigger.model.d.ts +1 -0
  12. package/dist/core/objects/trigger/trigger.model.js +3 -0
  13. package/dist/core/plan/apply.js +3 -3
  14. package/dist/core/plan/create.js +34 -15
  15. package/dist/core/plan/sql-format/constants.d.ts +2 -0
  16. package/dist/core/plan/sql-format/constants.js +11 -0
  17. package/dist/core/plan/sql-format/fixtures.d.ts +2 -0
  18. package/dist/core/plan/sql-format/fixtures.js +2449 -0
  19. package/dist/core/plan/sql-format/format-utils.d.ts +37 -0
  20. package/dist/core/plan/sql-format/format-utils.js +274 -0
  21. package/dist/core/plan/sql-format/formatters.d.ts +20 -0
  22. package/dist/core/plan/sql-format/formatters.js +737 -0
  23. package/dist/core/plan/sql-format/index.d.ts +2 -0
  24. package/dist/core/plan/sql-format/index.js +98 -0
  25. package/dist/core/plan/sql-format/keyword-case.d.ts +2 -0
  26. package/dist/core/plan/sql-format/keyword-case.js +868 -0
  27. package/dist/core/plan/sql-format/protect.d.ts +3 -0
  28. package/dist/core/plan/sql-format/protect.js +269 -0
  29. package/dist/core/plan/sql-format/sql-scanner.d.ts +59 -0
  30. package/dist/core/plan/sql-format/sql-scanner.js +202 -0
  31. package/dist/core/plan/sql-format/tokenizer.d.ts +22 -0
  32. package/dist/core/plan/sql-format/tokenizer.js +118 -0
  33. package/dist/core/plan/sql-format/types.d.ts +28 -0
  34. package/dist/core/plan/sql-format/types.js +1 -0
  35. package/dist/core/plan/sql-format/wrap.d.ts +2 -0
  36. package/dist/core/plan/sql-format/wrap.js +165 -0
  37. package/dist/core/plan/sql-format.d.ts +2 -0
  38. package/dist/core/plan/sql-format.js +1 -0
  39. package/dist/core/plan/statements.d.ts +2 -1
  40. package/dist/core/plan/statements.js +6 -2
  41. package/dist/core/postgres-config.d.ts +15 -0
  42. package/dist/core/postgres-config.js +30 -0
  43. package/dist/index.d.ts +2 -0
  44. package/dist/index.js +1 -0
  45. package/package.json +37 -22
  46. package/src/cli/app.ts +28 -0
  47. package/src/cli/bin/cli.ts +9 -0
  48. package/src/cli/commands/apply.ts +101 -0
  49. package/src/cli/commands/plan.ts +195 -0
  50. package/src/cli/commands/sync.ts +185 -0
  51. package/src/cli/formatters/index.ts +5 -0
  52. package/src/cli/formatters/tree/tree-builder.ts +380 -0
  53. package/src/cli/formatters/tree/tree-renderer.ts +372 -0
  54. package/src/cli/formatters/tree/tree.ts +237 -0
  55. package/src/cli/utils/integrations.ts +42 -0
  56. package/src/cli/utils.ts +231 -0
  57. package/src/core/catalog.diff.ts +246 -0
  58. package/src/core/catalog.model.ts +384 -0
  59. package/src/core/change.types.ts +44 -0
  60. package/src/core/context.ts +26 -0
  61. package/src/core/depend.ts +1870 -0
  62. package/src/core/expand-replace-dependencies.ts +380 -0
  63. package/src/core/fingerprint.ts +204 -0
  64. package/src/core/integrations/filter/dsl.ts +204 -0
  65. package/src/core/integrations/filter/extractors.ts +145 -0
  66. package/src/core/integrations/filter/filter.types.ts +3 -0
  67. package/src/core/integrations/integration-dsl.ts +24 -0
  68. package/src/core/integrations/integration.types.ts +7 -0
  69. package/src/core/integrations/serialize/dsl.ts +77 -0
  70. package/src/core/integrations/serialize/serialize.types.ts +3 -0
  71. package/src/core/integrations/supabase.ts +121 -0
  72. package/src/core/objects/aggregate/aggregate.diff.test.ts +215 -0
  73. package/src/core/objects/aggregate/aggregate.diff.ts +278 -0
  74. package/src/core/objects/aggregate/aggregate.model.ts +317 -0
  75. package/src/core/objects/aggregate/changes/aggregate.alter.test.ts +64 -0
  76. package/src/core/objects/aggregate/changes/aggregate.alter.ts +32 -0
  77. package/src/core/objects/aggregate/changes/aggregate.base.ts +20 -0
  78. package/src/core/objects/aggregate/changes/aggregate.comment.test.ts +86 -0
  79. package/src/core/objects/aggregate/changes/aggregate.comment.ts +62 -0
  80. package/src/core/objects/aggregate/changes/aggregate.create.test.ts +101 -0
  81. package/src/core/objects/aggregate/changes/aggregate.create.ts +329 -0
  82. package/src/core/objects/aggregate/changes/aggregate.drop.test.ts +78 -0
  83. package/src/core/objects/aggregate/changes/aggregate.drop.ts +32 -0
  84. package/src/core/objects/aggregate/changes/aggregate.privilege.test.ts +130 -0
  85. package/src/core/objects/aggregate/changes/aggregate.privilege.ts +146 -0
  86. package/src/core/objects/aggregate/changes/aggregate.types.ts +12 -0
  87. package/src/core/objects/base.change.ts +62 -0
  88. package/src/core/objects/base.default-privileges.ts +204 -0
  89. package/src/core/objects/base.diff.ts +20 -0
  90. package/src/core/objects/base.model.ts +82 -0
  91. package/src/core/objects/base.privilege-diff.ts +299 -0
  92. package/src/core/objects/base.privilege.ts +184 -0
  93. package/src/core/objects/collation/changes/collation.alter.test.ts +63 -0
  94. package/src/core/objects/collation/changes/collation.alter.ts +79 -0
  95. package/src/core/objects/collation/changes/collation.base.ts +20 -0
  96. package/src/core/objects/collation/changes/collation.comment.ts +68 -0
  97. package/src/core/objects/collation/changes/collation.create.test.ts +51 -0
  98. package/src/core/objects/collation/changes/collation.create.ts +106 -0
  99. package/src/core/objects/collation/changes/collation.drop.test.ts +28 -0
  100. package/src/core/objects/collation/changes/collation.drop.ts +37 -0
  101. package/src/core/objects/collation/changes/collation.types.ts +10 -0
  102. package/src/core/objects/collation/collation.diff.test.ts +100 -0
  103. package/src/core/objects/collation/collation.diff.ts +126 -0
  104. package/src/core/objects/collation/collation.model.ts +224 -0
  105. package/src/core/objects/domain/changes/domain.alter.test.ts +316 -0
  106. package/src/core/objects/domain/changes/domain.alter.ts +286 -0
  107. package/src/core/objects/domain/changes/domain.base.ts +20 -0
  108. package/src/core/objects/domain/changes/domain.comment.ts +59 -0
  109. package/src/core/objects/domain/changes/domain.create.test.ts +65 -0
  110. package/src/core/objects/domain/changes/domain.create.ts +118 -0
  111. package/src/core/objects/domain/changes/domain.drop.test.ts +30 -0
  112. package/src/core/objects/domain/changes/domain.drop.ts +34 -0
  113. package/src/core/objects/domain/changes/domain.privilege.ts +171 -0
  114. package/src/core/objects/domain/changes/domain.types.ts +12 -0
  115. package/src/core/objects/domain/domain.diff.test.ts +284 -0
  116. package/src/core/objects/domain/domain.diff.ts +358 -0
  117. package/src/core/objects/domain/domain.model.ts +190 -0
  118. package/src/core/objects/event-trigger/changes/event-trigger.alter.test.ts +50 -0
  119. package/src/core/objects/event-trigger/changes/event-trigger.alter.ts +82 -0
  120. package/src/core/objects/event-trigger/changes/event-trigger.base.ts +20 -0
  121. package/src/core/objects/event-trigger/changes/event-trigger.comment.ts +66 -0
  122. package/src/core/objects/event-trigger/changes/event-trigger.create.test.ts +24 -0
  123. package/src/core/objects/event-trigger/changes/event-trigger.create.ts +72 -0
  124. package/src/core/objects/event-trigger/changes/event-trigger.drop.test.ts +22 -0
  125. package/src/core/objects/event-trigger/changes/event-trigger.drop.ts +34 -0
  126. package/src/core/objects/event-trigger/changes/event-trigger.types.ts +10 -0
  127. package/src/core/objects/event-trigger/event-trigger.diff.test.ts +126 -0
  128. package/src/core/objects/event-trigger/event-trigger.diff.ts +126 -0
  129. package/src/core/objects/event-trigger/event-trigger.model.ts +106 -0
  130. package/src/core/objects/extension/changes/extension.alter.test.ts +58 -0
  131. package/src/core/objects/extension/changes/extension.alter.ts +78 -0
  132. package/src/core/objects/extension/changes/extension.base.ts +20 -0
  133. package/src/core/objects/extension/changes/extension.comment.ts +64 -0
  134. package/src/core/objects/extension/changes/extension.create.test.ts +25 -0
  135. package/src/core/objects/extension/changes/extension.create.ts +63 -0
  136. package/src/core/objects/extension/changes/extension.drop.test.ts +23 -0
  137. package/src/core/objects/extension/changes/extension.drop.ts +34 -0
  138. package/src/core/objects/extension/changes/extension.types.ts +10 -0
  139. package/src/core/objects/extension/extension.diff.test.ts +42 -0
  140. package/src/core/objects/extension/extension.diff.ts +90 -0
  141. package/src/core/objects/extension/extension.model.ts +280 -0
  142. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.alter.test.ts +125 -0
  143. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.alter.ts +101 -0
  144. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.base.ts +20 -0
  145. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.comment.ts +72 -0
  146. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.create.test.ts +125 -0
  147. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.create.ts +95 -0
  148. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.drop.test.ts +23 -0
  149. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.drop.ts +36 -0
  150. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.privilege.ts +172 -0
  151. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.types.ts +12 -0
  152. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/foreign-data-wrapper.diff.test.ts +179 -0
  153. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/foreign-data-wrapper.diff.ts +341 -0
  154. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/foreign-data-wrapper.model.ts +149 -0
  155. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper.types.ts +10 -0
  156. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.alter.test.ts +309 -0
  157. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.alter.ts +341 -0
  158. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.base.ts +20 -0
  159. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.comment.ts +72 -0
  160. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.create.test.ts +201 -0
  161. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.create.ts +81 -0
  162. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.drop.test.ts +43 -0
  163. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.drop.ts +37 -0
  164. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.privilege.ts +181 -0
  165. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.types.ts +12 -0
  166. package/src/core/objects/foreign-data-wrapper/foreign-table/foreign-table.diff.test.ts +813 -0
  167. package/src/core/objects/foreign-data-wrapper/foreign-table/foreign-table.diff.ts +406 -0
  168. package/src/core/objects/foreign-data-wrapper/foreign-table/foreign-table.model.ts +242 -0
  169. package/src/core/objects/foreign-data-wrapper/server/changes/server.alter.test.ts +168 -0
  170. package/src/core/objects/foreign-data-wrapper/server/changes/server.alter.ts +126 -0
  171. package/src/core/objects/foreign-data-wrapper/server/changes/server.base.ts +20 -0
  172. package/src/core/objects/foreign-data-wrapper/server/changes/server.comment.ts +60 -0
  173. package/src/core/objects/foreign-data-wrapper/server/changes/server.create.test.ts +131 -0
  174. package/src/core/objects/foreign-data-wrapper/server/changes/server.create.ts +81 -0
  175. package/src/core/objects/foreign-data-wrapper/server/changes/server.drop.test.ts +24 -0
  176. package/src/core/objects/foreign-data-wrapper/server/changes/server.drop.ts +34 -0
  177. package/src/core/objects/foreign-data-wrapper/server/changes/server.privilege.ts +164 -0
  178. package/src/core/objects/foreign-data-wrapper/server/changes/server.types.ts +12 -0
  179. package/src/core/objects/foreign-data-wrapper/server/server.diff.test.ts +167 -0
  180. package/src/core/objects/foreign-data-wrapper/server/server.diff.ts +317 -0
  181. package/src/core/objects/foreign-data-wrapper/server/server.model.ts +133 -0
  182. package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.alter.test.ts +82 -0
  183. package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.alter.ts +69 -0
  184. package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.base.ts +20 -0
  185. package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.create.test.ts +85 -0
  186. package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.create.ts +66 -0
  187. package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.drop.test.ts +53 -0
  188. package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.drop.ts +40 -0
  189. package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.types.ts +8 -0
  190. package/src/core/objects/foreign-data-wrapper/user-mapping/user-mapping.diff.test.ts +77 -0
  191. package/src/core/objects/foreign-data-wrapper/user-mapping/user-mapping.diff.ts +107 -0
  192. package/src/core/objects/foreign-data-wrapper/user-mapping/user-mapping.model.ts +96 -0
  193. package/src/core/objects/index/changes/index.alter.test.ts +200 -0
  194. package/src/core/objects/index/changes/index.alter.ts +144 -0
  195. package/src/core/objects/index/changes/index.base.ts +20 -0
  196. package/src/core/objects/index/changes/index.comment.ts +63 -0
  197. package/src/core/objects/index/changes/index.create.test.ts +66 -0
  198. package/src/core/objects/index/changes/index.create.ts +68 -0
  199. package/src/core/objects/index/changes/index.drop.test.ts +44 -0
  200. package/src/core/objects/index/changes/index.drop.ts +34 -0
  201. package/src/core/objects/index/changes/index.types.ts +6 -0
  202. package/src/core/objects/index/changes/utils.ts +16 -0
  203. package/src/core/objects/index/index.diff.test.ts +153 -0
  204. package/src/core/objects/index/index.diff.ts +243 -0
  205. package/src/core/objects/index/index.model.ts +370 -0
  206. package/src/core/objects/language/changes/language.alter.test.ts +33 -0
  207. package/src/core/objects/language/changes/language.alter.ts +53 -0
  208. package/src/core/objects/language/changes/language.base.ts +20 -0
  209. package/src/core/objects/language/changes/language.comment.ts +58 -0
  210. package/src/core/objects/language/changes/language.create.test.ts +27 -0
  211. package/src/core/objects/language/changes/language.create.ts +104 -0
  212. package/src/core/objects/language/changes/language.drop.test.ts +25 -0
  213. package/src/core/objects/language/changes/language.drop.ts +39 -0
  214. package/src/core/objects/language/changes/language.privilege.ts +172 -0
  215. package/src/core/objects/language/changes/language.types.ts +12 -0
  216. package/src/core/objects/language/language.diff.test.ts +53 -0
  217. package/src/core/objects/language/language.diff.ts +176 -0
  218. package/src/core/objects/language/language.model.ts +150 -0
  219. package/src/core/objects/materialized-view/changes/materialized-view.alter.test.ts +123 -0
  220. package/src/core/objects/materialized-view/changes/materialized-view.alter.ts +113 -0
  221. package/src/core/objects/materialized-view/changes/materialized-view.base.ts +20 -0
  222. package/src/core/objects/materialized-view/changes/materialized-view.comment.ts +176 -0
  223. package/src/core/objects/materialized-view/changes/materialized-view.create.test.ts +64 -0
  224. package/src/core/objects/materialized-view/changes/materialized-view.create.ts +93 -0
  225. package/src/core/objects/materialized-view/changes/materialized-view.drop.test.ts +34 -0
  226. package/src/core/objects/materialized-view/changes/materialized-view.drop.ts +60 -0
  227. package/src/core/objects/materialized-view/changes/materialized-view.privilege.ts +212 -0
  228. package/src/core/objects/materialized-view/changes/materialized-view.types.ts +12 -0
  229. package/src/core/objects/materialized-view/materialized-view.diff.test.ts +102 -0
  230. package/src/core/objects/materialized-view/materialized-view.diff.ts +451 -0
  231. package/src/core/objects/materialized-view/materialized-view.model.ts +258 -0
  232. package/src/core/objects/procedure/changes/procedure.alter.test.ts +1005 -0
  233. package/src/core/objects/procedure/changes/procedure.alter.ts +287 -0
  234. package/src/core/objects/procedure/changes/procedure.base.ts +20 -0
  235. package/src/core/objects/procedure/changes/procedure.comment.ts +70 -0
  236. package/src/core/objects/procedure/changes/procedure.create.test.ts +48 -0
  237. package/src/core/objects/procedure/changes/procedure.create.ts +92 -0
  238. package/src/core/objects/procedure/changes/procedure.drop.test.ts +85 -0
  239. package/src/core/objects/procedure/changes/procedure.drop.ts +49 -0
  240. package/src/core/objects/procedure/changes/procedure.privilege.ts +188 -0
  241. package/src/core/objects/procedure/changes/procedure.types.ts +12 -0
  242. package/src/core/objects/procedure/procedure.diff.test.ts +161 -0
  243. package/src/core/objects/procedure/procedure.diff.ts +404 -0
  244. package/src/core/objects/procedure/procedure.model.ts +264 -0
  245. package/src/core/objects/procedure/utils.ts +58 -0
  246. package/src/core/objects/publication/changes/publication.alter.test.ts +223 -0
  247. package/src/core/objects/publication/changes/publication.alter.ts +243 -0
  248. package/src/core/objects/publication/changes/publication.base.ts +20 -0
  249. package/src/core/objects/publication/changes/publication.comment.test.ts +70 -0
  250. package/src/core/objects/publication/changes/publication.comment.ts +64 -0
  251. package/src/core/objects/publication/changes/publication.create.test.ts +87 -0
  252. package/src/core/objects/publication/changes/publication.create.ts +82 -0
  253. package/src/core/objects/publication/changes/publication.drop.test.ts +46 -0
  254. package/src/core/objects/publication/changes/publication.drop.ts +29 -0
  255. package/src/core/objects/publication/changes/publication.types.ts +26 -0
  256. package/src/core/objects/publication/publication.diff.test.ts +292 -0
  257. package/src/core/objects/publication/publication.diff.ts +253 -0
  258. package/src/core/objects/publication/publication.model.ts +206 -0
  259. package/src/core/objects/publication/utils.ts +55 -0
  260. package/src/core/objects/rls-policy/changes/rls-policy.alter.test.ts +250 -0
  261. package/src/core/objects/rls-policy/changes/rls-policy.alter.ts +128 -0
  262. package/src/core/objects/rls-policy/changes/rls-policy.base.ts +20 -0
  263. package/src/core/objects/rls-policy/changes/rls-policy.comment.ts +69 -0
  264. package/src/core/objects/rls-policy/changes/rls-policy.create.test.ts +74 -0
  265. package/src/core/objects/rls-policy/changes/rls-policy.create.ts +100 -0
  266. package/src/core/objects/rls-policy/changes/rls-policy.drop.test.ts +28 -0
  267. package/src/core/objects/rls-policy/changes/rls-policy.drop.ts +39 -0
  268. package/src/core/objects/rls-policy/changes/rls-policy.types.ts +10 -0
  269. package/src/core/objects/rls-policy/rls-policy.diff.test.ts +79 -0
  270. package/src/core/objects/rls-policy/rls-policy.diff.ts +121 -0
  271. package/src/core/objects/rls-policy/rls-policy.model.ts +140 -0
  272. package/src/core/objects/role/changes/role.alter.test.ts +346 -0
  273. package/src/core/objects/role/changes/role.alter.ts +110 -0
  274. package/src/core/objects/role/changes/role.base.ts +24 -0
  275. package/src/core/objects/role/changes/role.comment.ts +55 -0
  276. package/src/core/objects/role/changes/role.create.test.ts +52 -0
  277. package/src/core/objects/role/changes/role.create.ts +102 -0
  278. package/src/core/objects/role/changes/role.drop.test.ts +29 -0
  279. package/src/core/objects/role/changes/role.drop.ts +34 -0
  280. package/src/core/objects/role/changes/role.privilege.ts +376 -0
  281. package/src/core/objects/role/changes/role.types.ts +12 -0
  282. package/src/core/objects/role/role.diff.test.ts +44 -0
  283. package/src/core/objects/role/role.diff.ts +479 -0
  284. package/src/core/objects/role/role.model.ts +344 -0
  285. package/src/core/objects/rule/changes/rule.alter.test.ts +78 -0
  286. package/src/core/objects/rule/changes/rule.alter.ts +72 -0
  287. package/src/core/objects/rule/changes/rule.base.ts +20 -0
  288. package/src/core/objects/rule/changes/rule.comment.test.ts +55 -0
  289. package/src/core/objects/rule/changes/rule.comment.ts +62 -0
  290. package/src/core/objects/rule/changes/rule.create.test.ts +59 -0
  291. package/src/core/objects/rule/changes/rule.create.ts +42 -0
  292. package/src/core/objects/rule/changes/rule.drop.test.ts +38 -0
  293. package/src/core/objects/rule/changes/rule.drop.ts +29 -0
  294. package/src/core/objects/rule/changes/rule.types.ts +12 -0
  295. package/src/core/objects/rule/rule.diff.test.ts +132 -0
  296. package/src/core/objects/rule/rule.diff.ts +79 -0
  297. package/src/core/objects/rule/rule.model.ts +173 -0
  298. package/src/core/objects/schema/changes/schema.alter.test.ts +28 -0
  299. package/src/core/objects/schema/changes/schema.alter.ts +45 -0
  300. package/src/core/objects/schema/changes/schema.base.ts +20 -0
  301. package/src/core/objects/schema/changes/schema.comment.ts +56 -0
  302. package/src/core/objects/schema/changes/schema.create.test.ts +22 -0
  303. package/src/core/objects/schema/changes/schema.create.ts +47 -0
  304. package/src/core/objects/schema/changes/schema.drop.test.ts +20 -0
  305. package/src/core/objects/schema/changes/schema.drop.ts +34 -0
  306. package/src/core/objects/schema/changes/schema.privilege.ts +175 -0
  307. package/src/core/objects/schema/changes/schema.types.ts +12 -0
  308. package/src/core/objects/schema/schema.diff.test.ts +42 -0
  309. package/src/core/objects/schema/schema.diff.ts +209 -0
  310. package/src/core/objects/schema/schema.model.ts +107 -0
  311. package/src/core/objects/sequence/changes/sequence.alter.test.ts +151 -0
  312. package/src/core/objects/sequence/changes/sequence.alter.ts +115 -0
  313. package/src/core/objects/sequence/changes/sequence.base.ts +20 -0
  314. package/src/core/objects/sequence/changes/sequence.comment.ts +60 -0
  315. package/src/core/objects/sequence/changes/sequence.create.test.ts +84 -0
  316. package/src/core/objects/sequence/changes/sequence.create.ts +111 -0
  317. package/src/core/objects/sequence/changes/sequence.drop.test.ts +32 -0
  318. package/src/core/objects/sequence/changes/sequence.drop.ts +37 -0
  319. package/src/core/objects/sequence/changes/sequence.privilege.ts +179 -0
  320. package/src/core/objects/sequence/changes/sequence.types.ts +12 -0
  321. package/src/core/objects/sequence/sequence.diff.test.ts +141 -0
  322. package/src/core/objects/sequence/sequence.diff.ts +359 -0
  323. package/src/core/objects/sequence/sequence.model.ts +185 -0
  324. package/src/core/objects/subscription/changes/subscription.alter.test.ts +124 -0
  325. package/src/core/objects/subscription/changes/subscription.alter.ts +110 -0
  326. package/src/core/objects/subscription/changes/subscription.base.ts +20 -0
  327. package/src/core/objects/subscription/changes/subscription.comment.test.ts +67 -0
  328. package/src/core/objects/subscription/changes/subscription.comment.ts +64 -0
  329. package/src/core/objects/subscription/changes/subscription.create.test.ts +77 -0
  330. package/src/core/objects/subscription/changes/subscription.create.ts +69 -0
  331. package/src/core/objects/subscription/changes/subscription.drop.test.ts +46 -0
  332. package/src/core/objects/subscription/changes/subscription.drop.ts +20 -0
  333. package/src/core/objects/subscription/changes/subscription.types.ts +22 -0
  334. package/src/core/objects/subscription/subscription.diff.test.ts +232 -0
  335. package/src/core/objects/subscription/subscription.diff.ts +241 -0
  336. package/src/core/objects/subscription/subscription.model.ts +190 -0
  337. package/src/core/objects/subscription/utils.ts +156 -0
  338. package/src/core/objects/table/changes/table.alter.test.ts +823 -0
  339. package/src/core/objects/table/changes/table.alter.ts +806 -0
  340. package/src/core/objects/table/changes/table.base.ts +20 -0
  341. package/src/core/objects/table/changes/table.comment.ts +266 -0
  342. package/src/core/objects/table/changes/table.create.test.ts +150 -0
  343. package/src/core/objects/table/changes/table.create.ts +188 -0
  344. package/src/core/objects/table/changes/table.drop.test.ts +34 -0
  345. package/src/core/objects/table/changes/table.drop.ts +45 -0
  346. package/src/core/objects/table/changes/table.privilege.ts +200 -0
  347. package/src/core/objects/table/changes/table.types.ts +12 -0
  348. package/src/core/objects/table/table.diff.test.ts +711 -0
  349. package/src/core/objects/table/table.diff.ts +953 -0
  350. package/src/core/objects/table/table.model.ts +460 -0
  351. package/src/core/objects/trigger/changes/trigger.alter.test.ts +46 -0
  352. package/src/core/objects/trigger/changes/trigger.alter.ts +76 -0
  353. package/src/core/objects/trigger/changes/trigger.base.ts +20 -0
  354. package/src/core/objects/trigger/changes/trigger.comment.ts +64 -0
  355. package/src/core/objects/trigger/changes/trigger.create.test.ts +43 -0
  356. package/src/core/objects/trigger/changes/trigger.create.ts +85 -0
  357. package/src/core/objects/trigger/changes/trigger.drop.test.ts +43 -0
  358. package/src/core/objects/trigger/changes/trigger.drop.ts +39 -0
  359. package/src/core/objects/trigger/changes/trigger.types.ts +10 -0
  360. package/src/core/objects/trigger/trigger.diff.test.ts +83 -0
  361. package/src/core/objects/trigger/trigger.diff.ts +116 -0
  362. package/src/core/objects/trigger/trigger.model.ts +252 -0
  363. package/src/core/objects/type/composite-type/changes/composite-type.alter.test.ts +202 -0
  364. package/src/core/objects/type/composite-type/changes/composite-type.alter.ts +174 -0
  365. package/src/core/objects/type/composite-type/changes/composite-type.base.ts +20 -0
  366. package/src/core/objects/type/composite-type/changes/composite-type.comment.ts +145 -0
  367. package/src/core/objects/type/composite-type/changes/composite-type.create.test.ts +101 -0
  368. package/src/core/objects/type/composite-type/changes/composite-type.create.ts +95 -0
  369. package/src/core/objects/type/composite-type/changes/composite-type.drop.test.ts +33 -0
  370. package/src/core/objects/type/composite-type/changes/composite-type.drop.ts +37 -0
  371. package/src/core/objects/type/composite-type/changes/composite-type.privilege.ts +175 -0
  372. package/src/core/objects/type/composite-type/changes/composite-type.types.ts +12 -0
  373. package/src/core/objects/type/composite-type/composite-type.diff.test.ts +191 -0
  374. package/src/core/objects/type/composite-type/composite-type.diff.ts +372 -0
  375. package/src/core/objects/type/composite-type/composite-type.model.ts +252 -0
  376. package/src/core/objects/type/enum/changes/enum.alter.test.ts +104 -0
  377. package/src/core/objects/type/enum/changes/enum.alter.ts +91 -0
  378. package/src/core/objects/type/enum/changes/enum.base.ts +20 -0
  379. package/src/core/objects/type/enum/changes/enum.comment.ts +64 -0
  380. package/src/core/objects/type/enum/changes/enum.create.test.ts +28 -0
  381. package/src/core/objects/type/enum/changes/enum.create.ts +56 -0
  382. package/src/core/objects/type/enum/changes/enum.drop.test.ts +25 -0
  383. package/src/core/objects/type/enum/changes/enum.drop.ts +34 -0
  384. package/src/core/objects/type/enum/changes/enum.privilege.ts +175 -0
  385. package/src/core/objects/type/enum/changes/enum.types.ts +12 -0
  386. package/src/core/objects/type/enum/enum.diff.test.ts +191 -0
  387. package/src/core/objects/type/enum/enum.diff.ts +396 -0
  388. package/src/core/objects/type/enum/enum.model.ts +194 -0
  389. package/src/core/objects/type/range/changes/range.alter.test.ts +27 -0
  390. package/src/core/objects/type/range/changes/range.alter.ts +51 -0
  391. package/src/core/objects/type/range/changes/range.base.ts +20 -0
  392. package/src/core/objects/type/range/changes/range.comment.ts +64 -0
  393. package/src/core/objects/type/range/changes/range.create.test.ts +51 -0
  394. package/src/core/objects/type/range/changes/range.create.ts +151 -0
  395. package/src/core/objects/type/range/changes/range.drop.test.ts +26 -0
  396. package/src/core/objects/type/range/changes/range.drop.ts +34 -0
  397. package/src/core/objects/type/range/changes/range.privilege.ts +175 -0
  398. package/src/core/objects/type/range/changes/range.types.ts +12 -0
  399. package/src/core/objects/type/range/range.diff.test.ts +70 -0
  400. package/src/core/objects/type/range/range.diff.ts +259 -0
  401. package/src/core/objects/type/range/range.model.ts +187 -0
  402. package/src/core/objects/type/type.types.ts +5 -0
  403. package/src/core/objects/utils.ts +171 -0
  404. package/src/core/objects/view/changes/view.alter.test.ts +110 -0
  405. package/src/core/objects/view/changes/view.alter.ts +112 -0
  406. package/src/core/objects/view/changes/view.base.ts +20 -0
  407. package/src/core/objects/view/changes/view.comment.ts +59 -0
  408. package/src/core/objects/view/changes/view.create.test.ts +65 -0
  409. package/src/core/objects/view/changes/view.create.ts +73 -0
  410. package/src/core/objects/view/changes/view.drop.test.ts +34 -0
  411. package/src/core/objects/view/changes/view.drop.ts +40 -0
  412. package/src/core/objects/view/changes/view.privilege.ts +200 -0
  413. package/src/core/objects/view/changes/view.types.ts +12 -0
  414. package/src/core/objects/view/view.diff.test.ts +91 -0
  415. package/src/core/objects/view/view.diff.ts +365 -0
  416. package/src/core/objects/view/view.model.ts +276 -0
  417. package/src/core/plan/apply.ts +190 -0
  418. package/src/core/plan/create.ts +432 -0
  419. package/src/core/plan/hierarchy.ts +574 -0
  420. package/src/core/plan/index.ts +29 -0
  421. package/src/core/plan/io.ts +20 -0
  422. package/src/core/plan/risk.ts +48 -0
  423. package/src/core/plan/serialize.ts +195 -0
  424. package/src/core/plan/sql-format/constants.ts +13 -0
  425. package/src/core/plan/sql-format/fixtures.ts +2806 -0
  426. package/src/core/plan/sql-format/format-comment-literals.test.ts +96 -0
  427. package/src/core/plan/sql-format/format-functions.test.ts +127 -0
  428. package/src/core/plan/sql-format/format-lowercase-coverage.test.ts +67 -0
  429. package/src/core/plan/sql-format/format-off.test.ts +809 -0
  430. package/src/core/plan/sql-format/format-pretty-lower-leading.test.ts +1056 -0
  431. package/src/core/plan/sql-format/format-pretty-narrow.test.ts +1283 -0
  432. package/src/core/plan/sql-format/format-pretty-preserve.test.ts +1052 -0
  433. package/src/core/plan/sql-format/format-pretty-upper.test.ts +1045 -0
  434. package/src/core/plan/sql-format/format-stress.test.ts +616 -0
  435. package/src/core/plan/sql-format/format-utils.test.ts +91 -0
  436. package/src/core/plan/sql-format/format-utils.ts +391 -0
  437. package/src/core/plan/sql-format/formatters.ts +921 -0
  438. package/src/core/plan/sql-format/index.ts +149 -0
  439. package/src/core/plan/sql-format/keyword-case.test.ts +118 -0
  440. package/src/core/plan/sql-format/keyword-case.ts +1085 -0
  441. package/src/core/plan/sql-format/protect.test.ts +127 -0
  442. package/src/core/plan/sql-format/protect.ts +337 -0
  443. package/src/core/plan/sql-format/sql-scanner.test.ts +240 -0
  444. package/src/core/plan/sql-format/sql-scanner.ts +252 -0
  445. package/src/core/plan/sql-format/tokenizer.test.ts +68 -0
  446. package/src/core/plan/sql-format/tokenizer.ts +152 -0
  447. package/src/core/plan/sql-format/types.ts +31 -0
  448. package/src/core/plan/sql-format/wrap.test.ts +119 -0
  449. package/src/core/plan/sql-format/wrap.ts +196 -0
  450. package/src/core/plan/sql-format.ts +2 -0
  451. package/src/core/plan/statements.ts +22 -0
  452. package/src/core/plan/types.ts +165 -0
  453. package/src/core/postgres-config.ts +169 -0
  454. package/src/core/sort/custom-constraints.ts +161 -0
  455. package/src/core/sort/debug-visualization.ts +239 -0
  456. package/src/core/sort/dependency-filter.ts +224 -0
  457. package/src/core/sort/graph-builder.ts +223 -0
  458. package/src/core/sort/graph-utils.ts +51 -0
  459. package/src/core/sort/logical-sort.ts +590 -0
  460. package/src/core/sort/sort-changes.ts +234 -0
  461. package/src/core/sort/topological-sort.ts +184 -0
  462. package/src/core/sort/types.ts +112 -0
  463. package/src/core/sort/utils.ts +69 -0
  464. package/src/index.ts +14 -0
@@ -0,0 +1,370 @@
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
+
6
+ const TableRelkindSchema = z.enum([
7
+ "r", // table (regular relation)
8
+ "m", // materialized view
9
+ "p", // partitioned table
10
+ ]);
11
+
12
+ const indexPropsSchema = z.object({
13
+ schema: z.string(),
14
+ table_name: z.string(),
15
+ name: z.string(),
16
+ storage_params: z.array(z.string()),
17
+ statistics_target: z.array(z.number()),
18
+ index_type: z.string(),
19
+ tablespace: z.string().nullable(),
20
+ is_unique: z.boolean(),
21
+ is_primary: z.boolean(),
22
+ is_exclusion: z.boolean(),
23
+ nulls_not_distinct: z.boolean(),
24
+ immediate: z.boolean(),
25
+ is_clustered: z.boolean(),
26
+ is_replica_identity: z.boolean(),
27
+ key_columns: z.array(z.number()),
28
+ column_collations: z.array(z.string().nullable()),
29
+ operator_classes: z.array(z.string()),
30
+ column_options: z.array(z.number()),
31
+ index_expressions: z.string().nullable(),
32
+ partial_predicate: z.string().nullable(),
33
+ is_owned_by_constraint: z.boolean(),
34
+ table_relkind: TableRelkindSchema, // 'r' for table, 'm' for materialized view
35
+ is_partitioned_index: z.boolean(),
36
+ is_index_partition: z.boolean(),
37
+ parent_index_name: z.string().nullable(),
38
+ definition: z.string(),
39
+ comment: z.string().nullable(),
40
+ owner: z.string(),
41
+ });
42
+
43
+ /**
44
+ * All properties exposed by CREATE INDEX statement are included in diff output.
45
+ * https://www.postgresql.org/docs/current/sql-createindex.html
46
+ *
47
+ * ALTER INDEX statement can only be generated for a subset of properties:
48
+ * - name, storage param, statistics, tablespace, attach partition
49
+ * https://www.postgresql.org/docs/current/sql-alterindex.html
50
+ *
51
+ * Unsupported alter properties include
52
+ * - depends on extension (all extension dependencies are excluded)
53
+ *
54
+ * Other properties require dropping and creating a new index.
55
+ */
56
+ export type IndexProps = z.infer<typeof indexPropsSchema>;
57
+
58
+ export class Index extends BasePgModel {
59
+ public readonly schema: IndexProps["schema"];
60
+ public readonly table_name: IndexProps["table_name"];
61
+ public readonly name: IndexProps["name"];
62
+ public readonly storage_params: IndexProps["storage_params"];
63
+ public readonly statistics_target: IndexProps["statistics_target"];
64
+ public readonly index_type: IndexProps["index_type"];
65
+ public readonly tablespace: IndexProps["tablespace"];
66
+ public readonly is_unique: IndexProps["is_unique"];
67
+ public readonly is_primary: IndexProps["is_primary"];
68
+ public readonly is_exclusion: IndexProps["is_exclusion"];
69
+ public readonly nulls_not_distinct: IndexProps["nulls_not_distinct"];
70
+ public readonly immediate: IndexProps["immediate"];
71
+ public readonly is_clustered: IndexProps["is_clustered"];
72
+ public readonly is_replica_identity: IndexProps["is_replica_identity"];
73
+ public readonly key_columns: IndexProps["key_columns"];
74
+ public readonly column_collations: IndexProps["column_collations"];
75
+ public readonly operator_classes: IndexProps["operator_classes"];
76
+ public readonly column_options: IndexProps["column_options"];
77
+ public readonly index_expressions: IndexProps["index_expressions"];
78
+ public readonly partial_predicate: IndexProps["partial_predicate"];
79
+ public readonly table_relkind: IndexProps["table_relkind"];
80
+ public readonly is_owned_by_constraint: IndexProps["is_owned_by_constraint"];
81
+ public readonly is_partitioned_index: IndexProps["is_partitioned_index"];
82
+ public readonly is_index_partition: IndexProps["is_index_partition"];
83
+ public readonly parent_index_name: IndexProps["parent_index_name"];
84
+ public readonly definition: IndexProps["definition"];
85
+ public readonly comment: IndexProps["comment"];
86
+ public readonly owner: IndexProps["owner"];
87
+
88
+ constructor(props: IndexProps) {
89
+ super();
90
+
91
+ // Identity fields
92
+ this.schema = props.schema;
93
+ this.table_name = props.table_name;
94
+ this.name = props.name;
95
+
96
+ // Data fields
97
+ this.storage_params = props.storage_params;
98
+ this.statistics_target = props.statistics_target;
99
+ this.index_type = props.index_type;
100
+ this.tablespace = props.tablespace;
101
+ this.is_unique = props.is_unique;
102
+ this.is_primary = props.is_primary;
103
+ this.is_exclusion = props.is_exclusion;
104
+ this.nulls_not_distinct = props.nulls_not_distinct;
105
+ this.immediate = props.immediate;
106
+ this.is_clustered = props.is_clustered;
107
+ this.is_replica_identity = props.is_replica_identity;
108
+ this.key_columns = props.key_columns;
109
+ this.column_collations = props.column_collations;
110
+ this.operator_classes = props.operator_classes;
111
+ this.column_options = props.column_options;
112
+ this.index_expressions = props.index_expressions;
113
+ this.partial_predicate = props.partial_predicate;
114
+ this.table_relkind = props.table_relkind;
115
+ this.is_owned_by_constraint = props.is_owned_by_constraint;
116
+ this.is_partitioned_index = props.is_partitioned_index;
117
+ this.is_index_partition = props.is_index_partition;
118
+ this.parent_index_name = props.parent_index_name;
119
+ this.definition = props.definition;
120
+ this.comment = props.comment;
121
+ this.owner = props.owner;
122
+ }
123
+
124
+ get stableId(): `index:${string}` {
125
+ return `index:${this.schema}.${this.table_name}.${this.name}`;
126
+ }
127
+
128
+ get tableStableId(): `table:${string}` | `materializedView:${string}` {
129
+ // Materialized views use a different stableId prefix
130
+ if (this.table_relkind === "m") {
131
+ return `materializedView:${this.schema}.${this.table_name}`;
132
+ }
133
+ return `table:${this.schema}.${this.table_name}`;
134
+ }
135
+
136
+ get identityFields() {
137
+ return {
138
+ schema: this.schema,
139
+ table_name: this.table_name,
140
+ name: this.name,
141
+ };
142
+ }
143
+
144
+ get dataFields() {
145
+ return {
146
+ storage_params: this.storage_params,
147
+ statistics_target: this.statistics_target,
148
+ index_type: this.index_type,
149
+ tablespace: this.tablespace,
150
+ is_unique: this.is_unique,
151
+ is_primary: this.is_primary,
152
+ is_exclusion: this.is_exclusion,
153
+ nulls_not_distinct: this.nulls_not_distinct,
154
+ immediate: this.immediate,
155
+ is_clustered: this.is_clustered,
156
+ is_replica_identity: this.is_replica_identity,
157
+ // key_columns excluded: contains attribute numbers that can differ between databases
158
+ // even when indexes are logically identical. The definition field already captures
159
+ // the logical structure using column names, so we compare by definition instead.
160
+ column_collations: this.column_collations,
161
+ operator_classes: this.operator_classes,
162
+ column_options: this.column_options,
163
+ index_expressions: this.index_expressions,
164
+ partial_predicate: this.partial_predicate,
165
+ table_relkind: this.table_relkind,
166
+ is_owned_by_constraint: this.is_owned_by_constraint,
167
+ is_partitioned_index: this.is_partitioned_index,
168
+ is_index_partition: this.is_index_partition,
169
+ parent_index_name: this.parent_index_name,
170
+ definition: this.definition,
171
+ comment: this.comment,
172
+ owner: this.owner,
173
+ };
174
+ }
175
+
176
+ override stableSnapshot() {
177
+ const normalizeArray = (arr: unknown) => {
178
+ if (!Array.isArray(arr)) return arr;
179
+ return [...arr].map((v) => normalizeValue(v));
180
+ };
181
+
182
+ const normalizeValue = (v: unknown): unknown => {
183
+ if (Array.isArray(v)) return normalizeArray(v);
184
+ if (v && typeof v === "object") {
185
+ return Object.fromEntries(
186
+ Object.entries(v as Record<string, unknown>).map(([k, val]) => [
187
+ k,
188
+ normalizeValue(val),
189
+ ]),
190
+ );
191
+ }
192
+ return v;
193
+ };
194
+
195
+ return {
196
+ identity: this.identityFields,
197
+ data: {
198
+ ...this.dataFields,
199
+ statistics_target: normalizeArray(this.statistics_target),
200
+ column_options: normalizeArray(this.column_options),
201
+ column_collations: normalizeArray(this.column_collations),
202
+ operator_classes: normalizeArray(this.operator_classes),
203
+ },
204
+ };
205
+ }
206
+ }
207
+
208
+ export async function extractIndexes(pool: Pool): Promise<Index[]> {
209
+ const { rows: indexRows } = await pool.query<IndexProps>(sql`
210
+ with extension_oids as (
211
+ select objid
212
+ from pg_depend d
213
+ where d.refclassid = 'pg_extension'::regclass
214
+ and d.classid = 'pg_class'::regclass
215
+ ),
216
+ -- align every per-column array by ordinality (1..indnatts)
217
+ -- this is used to ensure that key_columns, column_collations, operator_classes, and column_options are aligned
218
+ idx_cols as (
219
+ select
220
+ i.indexrelid,
221
+ i.indrelid,
222
+ k.ord,
223
+ k.attnum,
224
+ -- collation: only for key cols; 0 for none/default
225
+ case when k.ord <= i.indnkeyatts then coalesce(coll.oid, 0) else 0 end as coll_oid,
226
+ -- opclass: one per column
227
+ coalesce(cls.oid, 0) as cls_oid,
228
+ -- options: only for key cols; 0 for include cols
229
+ case when k.ord <= i.indnkeyatts then coalesce(opt.val, 0) else 0 end::int2 as indopt
230
+ from pg_index i
231
+ join lateral unnest(i.indkey) with ordinality as k(attnum, ord) on true
232
+ left join lateral unnest(i.indcollation) with ordinality as coll(oid, ordc) on ordc = k.ord
233
+ left join lateral unnest(i.indclass) with ordinality as cls(oid, ordo) on ordo = k.ord
234
+ left join lateral unnest(i.indoption) with ordinality as opt(val, ordi) on ordi = k.ord
235
+ )
236
+ select
237
+ c.relnamespace::regnamespace::text as schema,
238
+ quote_ident(tc.relname) as table_name,
239
+ tc.relkind as table_relkind,
240
+ quote_ident(c.relname) as name,
241
+ coalesce(c.reloptions, array[]::text[]) as storage_params,
242
+ am.amname as index_type,
243
+ quote_ident(ts.spcname) as tablespace,
244
+ i.indisunique as is_unique,
245
+ i.indisprimary as is_primary,
246
+ i.indisexclusion as is_exclusion,
247
+ i.indnullsnotdistinct as nulls_not_distinct,
248
+ i.indimmediate as immediate,
249
+ i.indisclustered as is_clustered,
250
+ i.indisreplident as is_replica_identity,
251
+ i.indkey as key_columns,
252
+
253
+ -- NEW: partitioned-index / index-partition tagging
254
+ (c.relkind = 'I') as is_partitioned_index,
255
+ (parent_idx.oid is not null) as is_index_partition,
256
+ case
257
+ when parent_idx.oid is not null then
258
+ quote_ident(parent_idx_ns.nspname) || '.' || quote_ident(parent_idx.relname)
259
+ end as parent_index_name,
260
+
261
+ -- Foreign keys don’t create/own an index; their conindid points to the referenced PK/UNIQUE index.
262
+ -- Mark as is_owned_by_constraint only when the owning constraint is PK/UNIQUE/EXCLUSION.
263
+ exists (
264
+ select 1
265
+ from pg_depend d
266
+ join pg_constraint pc on pc.oid = d.refobjid
267
+ where d.classid = 'pg_class'::regclass
268
+ and d.objid = i.indexrelid
269
+ and d.refclassid = 'pg_constraint'::regclass
270
+ and d.deptype = 'i'
271
+ and pc.contype in ('p','u','x')
272
+ ) as is_owned_by_constraint,
273
+
274
+ -- per-column arrays from one pass over idx_cols
275
+ coalesce(agg.column_collations, array[]::text[]) as column_collations,
276
+ coalesce(agg.operator_classes, array[]::text[]) as operator_classes,
277
+ coalesce(agg.column_options, array[]::int2[]) as column_options,
278
+
279
+ -- always an array (possibly empty), ordered by index attnum
280
+ coalesce(st.statistics_target, array[]::int4[]) as statistics_target,
281
+
282
+ pg_get_expr(i.indexprs, i.indrelid) as index_expressions,
283
+ pg_get_expr(i.indpred, i.indrelid) as partial_predicate,
284
+ pg_get_indexdef(i.indexrelid, 0, true) as definition,
285
+ obj_description(c.oid, 'pg_class') as comment,
286
+ c.relowner::regrole::text as owner
287
+
288
+ from pg_index i
289
+ join pg_class c on c.oid = i.indexrelid
290
+ join pg_class tc on tc.oid = i.indrelid
291
+ join pg_am am on am.oid = c.relam
292
+ left join pg_tablespace ts on ts.oid = c.reltablespace
293
+ left join extension_oids e on c.oid = e.objid
294
+ left join extension_oids e_table on tc.oid = e_table.objid
295
+
296
+ -- NEW: detect whether this index is an attached partition of a partitioned index
297
+ left join pg_inherits inh_idx
298
+ on inh_idx.inhrelid = c.oid
299
+ left join pg_class parent_idx
300
+ on parent_idx.oid = inh_idx.inhparent
301
+ left join pg_namespace parent_idx_ns
302
+ on parent_idx_ns.oid = parent_idx.relnamespace
303
+
304
+ -- single lateral aggregate keeps order by ic2.ord
305
+ left join lateral (
306
+ select
307
+ array_agg(
308
+ case
309
+ when ic2.coll_oid = 0 then null
310
+ when col.collname = 'default'
311
+ and col.collnamespace = 'pg_catalog'::regnamespace then null
312
+ else quote_ident(ns_coll.nspname) || '.' || quote_ident(col.collname)
313
+ end
314
+ order by ic2.ord
315
+ ) as column_collations,
316
+
317
+ -- 'default' when the AM's default opclass applies to the column's base type
318
+ array_agg(
319
+ case
320
+ when oc.oid is null then 'default'
321
+ when ic2.attnum = 0 then oc.opcnamespace::regnamespace::text || '.' || quote_ident(oc.opcname) -- expression key: no column type
322
+ -- in the case where the opclass is the default for the column's base type
323
+ when oc.opcdefault and (
324
+ (case when t.typtype = 'd' then t.typbasetype else a.atttypid end) = oc.opcintype
325
+ or exists (
326
+ select 1
327
+ from pg_catalog.pg_cast pc
328
+ where pc.castsource = (case when t.typtype = 'd' then t.typbasetype else a.atttypid end)
329
+ and pc.casttarget = oc.opcintype
330
+ and pc.castcontext = 'i' -- implicit
331
+ )
332
+ )
333
+ then 'default'
334
+ else oc.opcnamespace::regnamespace::text || '.' || quote_ident(oc.opcname)
335
+ end
336
+ order by ic2.ord
337
+ ) as operator_classes,
338
+
339
+ array_agg(coalesce(ic2.indopt, 0)::int2 order by ic2.ord) as column_options
340
+
341
+ from idx_cols ic2
342
+ left join pg_collation col on col.oid = ic2.coll_oid
343
+ left join pg_namespace ns_coll on ns_coll.oid = col.collnamespace
344
+ left join pg_opclass oc on oc.oid = ic2.cls_oid
345
+ -- base type for the underlying column (domain -> base); NULL for expressions
346
+ left join pg_attribute a on a.attrelid = ic2.indrelid and a.attnum = ic2.attnum
347
+ left join pg_type t on t.oid = a.atttypid
348
+ where ic2.indexrelid = i.indexrelid
349
+ ) as agg on true
350
+
351
+ left join lateral (
352
+ select array_agg(coalesce(a2.attstattarget, -1) order by a2.attnum) as statistics_target
353
+ from pg_attribute a2
354
+ where a2.attrelid = i.indexrelid
355
+ and a2.attnum > 0
356
+ ) as st on true
357
+
358
+ where not c.relnamespace::regnamespace::text like any(array['pg\\_%', 'information\\_schema'])
359
+ and i.indislive is true
360
+ and e.objid is null
361
+ and e_table.objid is null
362
+
363
+ order by 1, 2
364
+ `);
365
+ // Validate and parse each row using the Zod schema
366
+ const validatedRows = indexRows.map((row: unknown) =>
367
+ indexPropsSchema.parse(row),
368
+ );
369
+ return validatedRows.map((row: IndexProps) => new Index(row));
370
+ }
@@ -0,0 +1,33 @@
1
+ import { describe, expect, test } from "bun:test";
2
+ import { Language, type LanguageProps } from "../language.model.ts";
3
+ import { AlterLanguageChangeOwner } from "./language.alter.ts";
4
+
5
+ describe.concurrent("language", () => {
6
+ describe("alter", () => {
7
+ test("change owner", () => {
8
+ const props: Omit<LanguageProps, "owner"> = {
9
+ name: "plpgsql",
10
+ is_trusted: true,
11
+ is_procedural: true,
12
+ call_handler: "plpgsql_call_handler",
13
+ inline_handler: "plpgsql_inline_handler",
14
+ validator: "plpgsql_validator",
15
+ comment: null,
16
+ privileges: [],
17
+ };
18
+ const language = new Language({
19
+ ...props,
20
+ owner: "old_owner",
21
+ });
22
+
23
+ const change = new AlterLanguageChangeOwner({
24
+ language,
25
+ owner: "new_owner",
26
+ });
27
+
28
+ expect(change.serialize()).toBe(
29
+ "ALTER LANGUAGE plpgsql OWNER TO new_owner",
30
+ );
31
+ });
32
+ });
33
+ });
@@ -0,0 +1,53 @@
1
+ import type { Language } from "../language.model.ts";
2
+ import { AlterLanguageChange } from "./language.base.ts";
3
+
4
+ /**
5
+ * Alter a language.
6
+ *
7
+ * @see https://www.postgresql.org/docs/17/sql-alterlanguage.html
8
+ *
9
+ * Synopsis
10
+ * ```sql
11
+ * ALTER [ PROCEDURAL ] LANGUAGE name OWNER TO { new_owner | CURRENT_ROLE | CURRENT_USER | SESSION_USER }
12
+ * ALTER [ PROCEDURAL ] LANGUAGE name RENAME TO new_name
13
+ * ```
14
+ */
15
+
16
+ export type AlterLanguage = AlterLanguageChangeOwner;
17
+
18
+ /**
19
+ * ALTER LANGUAGE ... OWNER TO ...
20
+ */
21
+ export class AlterLanguageChangeOwner extends AlterLanguageChange {
22
+ public readonly language: Language;
23
+ public readonly owner: string;
24
+ public readonly scope = "object" as const;
25
+
26
+ constructor(props: { language: Language; owner: string }) {
27
+ super();
28
+ this.language = props.language;
29
+ this.owner = props.owner;
30
+ }
31
+
32
+ get requires() {
33
+ return [this.language.stableId];
34
+ }
35
+
36
+ serialize(): string {
37
+ const parts: string[] = ["ALTER"];
38
+
39
+ // Do not print the optional PROCEDURAL keyword.
40
+ // It is syntactic noise and the default for procedural languages,
41
+ // so we purposely omit it to avoid emitting defaults.
42
+
43
+ parts.push("LANGUAGE", this.language.name, "OWNER TO", this.owner);
44
+
45
+ return parts.join(" ");
46
+ }
47
+ }
48
+
49
+ /**
50
+ * Replace a language.
51
+ * This is used when properties that cannot be altered via ALTER LANGUAGE change.
52
+ */
53
+ // NOTE: ReplaceLanguage removed. Non-alterable changes are emitted as Drop + Create in language.diff.ts.
@@ -0,0 +1,20 @@
1
+ import { BaseChange } from "../../base.change.ts";
2
+ import type { Language } from "../language.model.ts";
3
+
4
+ abstract class BaseLanguageChange extends BaseChange {
5
+ abstract readonly language: Language;
6
+ abstract readonly scope: "object" | "comment" | "privilege";
7
+ readonly objectType: "language" = "language";
8
+ }
9
+
10
+ export abstract class CreateLanguageChange extends BaseLanguageChange {
11
+ readonly operation = "create" as const;
12
+ }
13
+
14
+ export abstract class AlterLanguageChange extends BaseLanguageChange {
15
+ readonly operation = "alter" as const;
16
+ }
17
+
18
+ export abstract class DropLanguageChange extends BaseLanguageChange {
19
+ readonly operation = "drop" as const;
20
+ }
@@ -0,0 +1,58 @@
1
+ import { quoteLiteral } from "../../base.change.ts";
2
+ import { stableId } from "../../utils.ts";
3
+ import type { Language } from "../language.model.ts";
4
+ import { CreateLanguageChange, DropLanguageChange } from "./language.base.ts";
5
+
6
+ export type CommentLanguage = CreateCommentOnLanguage | DropCommentOnLanguage;
7
+
8
+ /**
9
+ * Create/drop comments on languages.
10
+ */
11
+ export class CreateCommentOnLanguage extends CreateLanguageChange {
12
+ public readonly language: Language;
13
+ public readonly scope = "comment" as const;
14
+
15
+ constructor(props: { language: Language }) {
16
+ super();
17
+ this.language = props.language;
18
+ }
19
+
20
+ get creates() {
21
+ return [stableId.comment(this.language.stableId)];
22
+ }
23
+
24
+ get requires() {
25
+ return [this.language.stableId];
26
+ }
27
+
28
+ serialize(): string {
29
+ return [
30
+ "COMMENT ON LANGUAGE",
31
+ this.language.name,
32
+ "IS",
33
+ quoteLiteral(this.language.comment as string),
34
+ ].join(" ");
35
+ }
36
+ }
37
+
38
+ export class DropCommentOnLanguage extends DropLanguageChange {
39
+ public readonly language: Language;
40
+ public readonly scope = "comment" as const;
41
+
42
+ constructor(props: { language: Language }) {
43
+ super();
44
+ this.language = props.language;
45
+ }
46
+
47
+ get drops() {
48
+ return [stableId.comment(this.language.stableId)];
49
+ }
50
+
51
+ get requires() {
52
+ return [stableId.comment(this.language.stableId), this.language.stableId];
53
+ }
54
+
55
+ serialize(): string {
56
+ return ["COMMENT ON LANGUAGE", this.language.name, "IS NULL"].join(" ");
57
+ }
58
+ }
@@ -0,0 +1,27 @@
1
+ import { describe, expect, test } from "bun:test";
2
+ import { Language } from "../language.model.ts";
3
+ import { CreateLanguage } from "./language.create.ts";
4
+
5
+ describe("language", () => {
6
+ test("create", () => {
7
+ const language = new Language({
8
+ name: "plpgsql",
9
+ is_trusted: true,
10
+ is_procedural: true,
11
+ call_handler: "plpgsql_call_handler",
12
+ inline_handler: "plpgsql_inline_handler",
13
+ validator: "plpgsql_validator",
14
+ owner: "test",
15
+ comment: null,
16
+ privileges: [],
17
+ });
18
+
19
+ const change = new CreateLanguage({
20
+ language,
21
+ });
22
+
23
+ expect(change.serialize()).toBe(
24
+ "CREATE TRUSTED LANGUAGE plpgsql HANDLER plpgsql_call_handler INLINE plpgsql_inline_handler VALIDATOR plpgsql_validator",
25
+ );
26
+ });
27
+ });
@@ -0,0 +1,104 @@
1
+ import { parseProcedureReference, stableId } from "../../utils.ts";
2
+ import type { Language } from "../language.model.ts";
3
+ import { CreateLanguageChange } from "./language.base.ts";
4
+
5
+ /**
6
+ * Create a language.
7
+ *
8
+ * @see https://www.postgresql.org/docs/17/sql-createlanguage.html
9
+ *
10
+ * Synopsis
11
+ * ```sql
12
+ * CREATE [ OR REPLACE ] [ TRUSTED ] [ PROCEDURAL ] LANGUAGE name
13
+ * [ HANDLER call_handler [ INLINE inline_handler ] [ VALIDATOR valfunction ] ]
14
+ * ```
15
+ */
16
+ export class CreateLanguage extends CreateLanguageChange {
17
+ public readonly language: Language;
18
+ public readonly orReplace?: boolean;
19
+ public readonly scope = "object" as const;
20
+
21
+ constructor(props: { language: Language; orReplace?: boolean }) {
22
+ super();
23
+ this.language = props.language;
24
+ this.orReplace = props.orReplace;
25
+ }
26
+
27
+ get creates() {
28
+ return [this.language.stableId];
29
+ }
30
+
31
+ get requires() {
32
+ const dependencies = new Set<string>();
33
+
34
+ // Owner dependency
35
+ dependencies.add(stableId.role(this.language.owner));
36
+
37
+ // Call handler function dependency
38
+ if (this.language.call_handler) {
39
+ const callHandlerProc = parseProcedureReference(
40
+ this.language.call_handler,
41
+ );
42
+ if (callHandlerProc) {
43
+ dependencies.add(
44
+ stableId.procedure(callHandlerProc.schema, callHandlerProc.name),
45
+ );
46
+ }
47
+ }
48
+
49
+ // Inline handler function dependency
50
+ if (this.language.inline_handler) {
51
+ const inlineHandlerProc = parseProcedureReference(
52
+ this.language.inline_handler,
53
+ );
54
+ if (inlineHandlerProc) {
55
+ dependencies.add(
56
+ stableId.procedure(inlineHandlerProc.schema, inlineHandlerProc.name),
57
+ );
58
+ }
59
+ }
60
+
61
+ // Validator function dependency
62
+ if (this.language.validator) {
63
+ const validatorProc = parseProcedureReference(this.language.validator);
64
+ if (validatorProc) {
65
+ dependencies.add(
66
+ stableId.procedure(validatorProc.schema, validatorProc.name),
67
+ );
68
+ }
69
+ }
70
+
71
+ return Array.from(dependencies);
72
+ }
73
+
74
+ serialize(): string {
75
+ const parts: string[] = [`CREATE${this.orReplace ? " OR REPLACE" : ""}`];
76
+
77
+ // Only include non-default flags. We never print the optional
78
+ // PROCEDURAL keyword or any defaults.
79
+
80
+ // TRUSTED keyword (default is untrusted -> omitted unless true)
81
+ if (this.language.is_trusted) {
82
+ parts.push("TRUSTED");
83
+ }
84
+
85
+ parts.push("LANGUAGE", this.language.name);
86
+
87
+ // HANDLER (omit when null)
88
+ if (this.language.call_handler) {
89
+ parts.push("HANDLER", this.language.call_handler);
90
+ }
91
+
92
+ // INLINE (omit when null)
93
+ if (this.language.inline_handler) {
94
+ parts.push("INLINE", this.language.inline_handler);
95
+ }
96
+
97
+ // VALIDATOR (omit when null)
98
+ if (this.language.validator) {
99
+ parts.push("VALIDATOR", this.language.validator);
100
+ }
101
+
102
+ return parts.join(" ");
103
+ }
104
+ }
@@ -0,0 +1,25 @@
1
+ import { describe, expect, test } from "bun:test";
2
+ import { Language } from "../language.model.ts";
3
+ import { DropLanguage } from "./language.drop.ts";
4
+
5
+ describe("language", () => {
6
+ test("drop", () => {
7
+ const language = new Language({
8
+ name: "plpgsql",
9
+ is_trusted: true,
10
+ is_procedural: true,
11
+ call_handler: "plpgsql_call_handler",
12
+ inline_handler: "plpgsql_inline_handler",
13
+ validator: "plpgsql_validator",
14
+ owner: "test",
15
+ comment: null,
16
+ privileges: [],
17
+ });
18
+
19
+ const change = new DropLanguage({
20
+ language,
21
+ });
22
+
23
+ expect(change.serialize()).toBe("DROP LANGUAGE plpgsql");
24
+ });
25
+ });