@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,1870 @@
1
+ import { sql } from "@ts-safeql/sql-tag";
2
+ import type { Pool } from "pg";
3
+
4
+ /**
5
+ * Dependency type as defined in PostgreSQL's pg_depend.deptype.
6
+ * n: normal
7
+ * a: auto
8
+ * i: internal
9
+ */
10
+ type PgDependType = "n" | "a" | "i";
11
+
12
+ export interface PgDepend {
13
+ dependent_stable_id: string;
14
+ referenced_stable_id: string;
15
+ /**
16
+ * Dependency type as defined in PostgreSQL's pg_depend.deptype.
17
+ *
18
+ * - "n" (normal): Ordinary dependency — if the referenced object is dropped, the dependent object is also dropped automatically.
19
+ * Example: a table column depends on its table.
20
+ * - "a" (auto): Automatically created dependency — the dependent object was created as a result of creating the referenced object,
21
+ * and should be dropped automatically when the referenced object is dropped, but not otherwise treated as a strong link.
22
+ * - "i" (internal): Internal dependency — the dependent object is a low-level part of the referenced object and cannot be dropped
23
+ * without dropping the whole referenced object. Example: a table's toast table or an index that's part of a unique constraint.
24
+ */
25
+ deptype: PgDependType;
26
+ }
27
+
28
+ /**
29
+ * Extract dependencies for privileges and memberships so that GRANT/REVOKE
30
+ * operations are properly ordered with respect to their target objects/roles.
31
+ *
32
+ * Encodes edges like:
33
+ * - acl:<target>::grantee:<role> -> <target>
34
+ * - acl:<target>::grantee:<role> -> role:<role>
35
+ * - aclcol:table:<schema>.<name>::grantee:<role> -> table:<schema>.<name>
36
+ * - aclcol:... -> role:<role>
37
+ * - defacl:<grantor>:<objtype>:<scope>:grantee:<grantee> -> role:<grantor>
38
+ * - defacl:... -> role:<grantee>
39
+ * - defacl:... -> schema:<schema> (when scoped to a schema)
40
+ * - membership:<role>-><member> -> role:<role>
41
+ * - membership:<role>-><member> -> role:<member>
42
+ */
43
+ async function extractPrivilegeAndMembershipDepends(
44
+ pool: Pool,
45
+ ): Promise<PgDepend[]> {
46
+ const { rows } = await pool.query<PgDepend>(sql`
47
+ with
48
+ -- OBJECT PRIVILEGES (relations)
49
+ extension_rel_oids as (
50
+ select objid from pg_depend d
51
+ where d.refclassid = 'pg_extension'::regclass and d.classid = 'pg_class'::regclass
52
+ ),
53
+ rel_acls as (
54
+ select
55
+ c.relkind,
56
+ c.relnamespace::regnamespace::text as schema_name,
57
+ c.relname as relname,
58
+ case when x.grantee = 0 then 'PUBLIC' else x.grantee::regrole::text end as grantee
59
+ from pg_catalog.pg_class c
60
+ join lateral aclexplode(c.relacl) as x(grantor, grantee, privilege_type, is_grantable) on true
61
+ left join extension_rel_oids e on e.objid = c.oid
62
+ where c.relkind in ('r','p','v','m','S','f')
63
+ and not c.relnamespace::regnamespace::text like any(array['pg\\_%','information\\_schema'])
64
+ and e.objid is null
65
+ ),
66
+ rel_targets as (
67
+ select
68
+ case
69
+ when relkind in ('r','p') then format('table:%I.%I', schema_name, relname)
70
+ when relkind = 'v' then format('view:%I.%I', schema_name, relname)
71
+ when relkind = 'm' then format('materializedView:%I.%I', schema_name, relname)
72
+ when relkind = 'S' then format('sequence:%I.%I', schema_name, relname)
73
+ when relkind = 'f' then format('foreignTable:%I.%I', schema_name, relname)
74
+ else null
75
+ end as target_stable_id,
76
+ schema_name as target_schema,
77
+ grantee
78
+ from rel_acls
79
+ ),
80
+
81
+ -- OBJECT PRIVILEGES (schemas)
82
+ extension_ns_oids as (
83
+ select objid from pg_depend d
84
+ where d.refclassid = 'pg_extension'::regclass and d.classid = 'pg_namespace'::regclass
85
+ ),
86
+ ns_acls as (
87
+ select
88
+ format('schema:%I', n.nspname) as schema_stable_id,
89
+ n.nspname as schema_name,
90
+ case when x.grantee = 0 then 'PUBLIC' else x.grantee::regrole::text end as grantee
91
+ from pg_catalog.pg_namespace n
92
+ join lateral aclexplode(n.nspacl) as x(grantor, grantee, privilege_type, is_grantable) on true
93
+ left join extension_ns_oids e on e.objid = n.oid
94
+ where not n.nspname like any(array['pg\\_%','information\\_schema'])
95
+ and e.objid is null
96
+ ),
97
+
98
+ -- OBJECT PRIVILEGES (languages)
99
+ extension_lang_oids as (
100
+ select objid from pg_depend d
101
+ where d.refclassid = 'pg_extension'::regclass and d.classid = 'pg_language'::regclass
102
+ ),
103
+ lang_acls as (
104
+ select
105
+ format('language:%I', l.lanname) as language_stable_id,
106
+ NULL::text as language_schema,
107
+ case when x.grantee = 0 then 'PUBLIC' else x.grantee::regrole::text end as grantee
108
+ from pg_catalog.pg_language l
109
+ join lateral aclexplode(l.lanacl) as x(grantor, grantee, privilege_type, is_grantable) on true
110
+ left join extension_lang_oids e on e.objid = l.oid
111
+ where l.lanname not in ('internal','c')
112
+ ),
113
+
114
+ -- OBJECT PRIVILEGES (routines)
115
+ extension_proc_oids as (
116
+ select objid from pg_depend d
117
+ where d.refclassid = 'pg_extension'::regclass and d.classid = 'pg_proc'::regclass
118
+ ),
119
+ proc_acls as (
120
+ select
121
+ p.pronamespace::regnamespace::text as schema_name,
122
+ p.proname as procname,
123
+ p.prokind,
124
+ case when x.grantee = 0 then 'PUBLIC' else x.grantee::regrole::text end as grantee,
125
+ (select coalesce(string_agg(format_type(oid, null), ',' order by ord), '') from unnest(p.proargtypes) with ordinality as t(oid, ord)) as arg_types,
126
+ trim(pg_catalog.pg_get_function_identity_arguments(p.oid)) as identity_arguments
127
+ from pg_catalog.pg_proc p
128
+ join lateral aclexplode(p.proacl) as x(grantor, grantee, privilege_type, is_grantable) on true
129
+ left join extension_proc_oids e on e.objid = p.oid
130
+ join pg_language l on l.oid = p.prolang
131
+ where not p.pronamespace::regnamespace::text like any(array['pg\\_%','information\\_schema'])
132
+ and e.objid is null
133
+ and l.lanname not in ('c','internal')
134
+ ),
135
+ proc_targets as (
136
+ select
137
+ case
138
+ when prokind = 'a' then format('aggregate:%I.%I(%s)', schema_name, procname, identity_arguments)
139
+ else format('procedure:%I.%I(%s)', schema_name, procname, arg_types)
140
+ end as target_stable_id,
141
+ schema_name,
142
+ grantee
143
+ from proc_acls
144
+ ),
145
+
146
+ -- OBJECT PRIVILEGES (types/domains)
147
+ extension_type_oids as (
148
+ select objid from pg_depend d
149
+ where d.refclassid = 'pg_extension'::regclass and d.classid = 'pg_type'::regclass
150
+ ),
151
+ type_acls as (
152
+ select
153
+ t.typtype,
154
+ t.typnamespace::regnamespace::text as schema_name,
155
+ t.typname as type_name,
156
+ case when x.grantee = 0 then 'PUBLIC' else x.grantee::regrole::text end as grantee
157
+ from pg_catalog.pg_type t
158
+ join lateral aclexplode(t.typacl) as x(grantor, grantee, privilege_type, is_grantable) on true
159
+ left join extension_type_oids e on e.objid = t.oid
160
+ where not t.typnamespace::regnamespace::text like any(array['pg\\_%','information\\_schema'])
161
+ and e.objid is null
162
+ and t.typtype in ('d','e','r','c')
163
+ ),
164
+ type_targets as (
165
+ select
166
+ (case
167
+ when typtype = 'd' then format('domain:%I.%I', schema_name, type_name)
168
+ when typtype = 'e' then format('type:%I.%I', schema_name, type_name)
169
+ when typtype = 'r' then format('type:%I.%I', schema_name, type_name)
170
+ when typtype = 'c' then format('type:%I.%I', schema_name, type_name)
171
+ else null
172
+ end) as target_stable_id,
173
+ schema_name,
174
+ grantee
175
+ from type_acls
176
+ ),
177
+
178
+ -- COLUMN PRIVILEGES
179
+ rels as (
180
+ select c.oid,
181
+ c.relkind,
182
+ c.relnamespace::regnamespace::text as schema_name,
183
+ c.relname as relname
184
+ from pg_catalog.pg_class c
185
+ left join pg_depend de on de.classid='pg_class'::regclass and de.objid=c.oid and de.refclassid='pg_extension'::regclass
186
+ where c.relkind in ('r','p','v','m','f')
187
+ and not c.relnamespace::regnamespace::text like any(array['pg\\_%','information\\_schema'])
188
+ and de.objid is null
189
+ ),
190
+ col_acls as (
191
+ select
192
+ format('table:%I.%I', r.schema_name, r.relname) as table_stable_id,
193
+ r.schema_name as table_schema,
194
+ case when x.grantee = 0 then 'PUBLIC' else x.grantee::regrole::text end as grantee
195
+ from rels r
196
+ join pg_attribute a on a.attrelid = r.oid and a.attnum > 0 and not a.attisdropped
197
+ join lateral aclexplode(a.attacl) as x(grantor, grantee, privilege_type, is_grantable) on true
198
+ ),
199
+
200
+ -- DEFAULT PRIVILEGES
201
+ defacls as (
202
+ select
203
+ format(
204
+ 'defacl:%s:%s:%s:grantee:%s',
205
+ d.defaclrole::regrole::text,
206
+ d.defaclobjtype::text,
207
+ coalesce(format('schema:%s', d.defaclnamespace::regnamespace::text), 'global'),
208
+ case when x.grantee = 0 then 'PUBLIC' else x.grantee::regrole::text end
209
+ ) as defacl_stable_id,
210
+ format('role:%s', d.defaclrole::regrole::text) as grantor_role_stable_id,
211
+ format('role:%s', case when x.grantee = 0 then 'PUBLIC' else x.grantee::regrole::text end) as grantee_role_stable_id,
212
+ case
213
+ when d.defaclnamespace = 0 then null
214
+ else format('schema:%s', d.defaclnamespace::regnamespace::text)
215
+ end as schema_stable_id,
216
+ case
217
+ when d.defaclnamespace = 0 then null
218
+ else d.defaclnamespace::regnamespace::text
219
+ end as schema_name
220
+ from pg_default_acl d
221
+ cross join lateral aclexplode(coalesce(d.defaclacl, ARRAY[]::aclitem[])) as x(grantor, grantee, privilege_type, is_grantable)
222
+ ),
223
+
224
+ -- OBJECT PRIVILEGES (Foreign Data Wrappers)
225
+ fdw_acls as (
226
+ select
227
+ format('foreignDataWrapper:%I', fdw.fdwname) as fdw_stable_id,
228
+ case when x.grantee = 0 then 'PUBLIC' else x.grantee::regrole::text end as grantee
229
+ from pg_catalog.pg_foreign_data_wrapper fdw
230
+ join lateral aclexplode(fdw.fdwacl) as x(grantor, grantee, privilege_type, is_grantable) on true
231
+ where not fdw.fdwname like any(array['pg\\_%'])
232
+ ),
233
+
234
+ -- OBJECT PRIVILEGES (Servers)
235
+ server_acls as (
236
+ select
237
+ format('server:%I', srv.srvname) as server_stable_id,
238
+ case when x.grantee = 0 then 'PUBLIC' else x.grantee::regrole::text end as grantee
239
+ from pg_catalog.pg_foreign_server srv
240
+ join pg_catalog.pg_foreign_data_wrapper fdw on fdw.oid = srv.srvfdw
241
+ join lateral aclexplode(srv.srvacl) as x(grantor, grantee, privilege_type, is_grantable) on true
242
+ where not fdw.fdwname like any(array['pg\\_%'])
243
+ ),
244
+
245
+ -- OBJECT PRIVILEGES (Foreign Tables)
246
+ foreign_table_acls as (
247
+ select
248
+ c.relnamespace::regnamespace::text as schema_name,
249
+ c.relname as relname,
250
+ case when x.grantee = 0 then 'PUBLIC' else x.grantee::regrole::text end as grantee
251
+ from pg_catalog.pg_class c
252
+ join pg_foreign_table ft on ft.ftrelid = c.oid
253
+ join pg_foreign_server srv on srv.oid = ft.ftserver
254
+ join pg_foreign_data_wrapper fdw on fdw.oid = srv.srvfdw
255
+ join lateral aclexplode(c.relacl) as x(grantor, grantee, privilege_type, is_grantable) on true
256
+ left join extension_rel_oids e on e.objid = c.oid
257
+ where c.relkind = 'f'
258
+ and not c.relnamespace::regnamespace::text like any(array['pg\\_%','information\\_schema'])
259
+ and e.objid is null
260
+ and not fdw.fdwname like any(array['pg\\_%'])
261
+ ),
262
+ foreign_table_targets as (
263
+ select
264
+ format('foreignTable:%I.%I', schema_name, relname) as target_stable_id,
265
+ schema_name as target_schema,
266
+ grantee
267
+ from foreign_table_acls
268
+ ),
269
+
270
+ -- ROLE MEMBERSHIPS
271
+ memberships as (
272
+ select quote_ident(r.rolname) as role_name, m.rolname as member_name
273
+ from pg_auth_members am
274
+ join pg_roles r on r.oid = am.roleid
275
+ join pg_roles m on m.oid = am.member
276
+ )
277
+
278
+ select distinct
279
+ dependent_stable_id,
280
+ referenced_stable_id,
281
+ deptype
282
+ from (
283
+ select distinct
284
+ format('acl:%s::grantee:%s', target_stable_id, grantee) as dependent_stable_id,
285
+ target_stable_id as referenced_stable_id,
286
+ 'n'::char as deptype,
287
+ target_schema as dep_schema,
288
+ target_schema as ref_schema
289
+ from rel_targets
290
+ where target_stable_id is not null
291
+
292
+ union all
293
+ select distinct
294
+ format('acl:%s::grantee:%s', target_stable_id, grantee) as dependent_stable_id,
295
+ format('role:%s', grantee) as referenced_stable_id,
296
+ 'n'::char as deptype,
297
+ target_schema as dep_schema,
298
+ NULL::text as ref_schema
299
+ from rel_targets
300
+ where target_stable_id is not null
301
+
302
+ union all
303
+ select distinct
304
+ format('acl:%s::grantee:%s', schema_stable_id, grantee) as dependent_stable_id,
305
+ schema_stable_id as referenced_stable_id,
306
+ 'n'::char as deptype,
307
+ schema_name as dep_schema,
308
+ schema_name as ref_schema
309
+ from ns_acls
310
+
311
+ union all
312
+ select distinct
313
+ format('acl:%s::grantee:%s', schema_stable_id, grantee) as dependent_stable_id,
314
+ format('role:%s', grantee) as referenced_stable_id,
315
+ 'n'::char as deptype,
316
+ schema_name as dep_schema,
317
+ NULL::text as ref_schema
318
+ from ns_acls
319
+
320
+ union all
321
+ select distinct
322
+ format('acl:%s::grantee:%s', language_stable_id, grantee) as dependent_stable_id,
323
+ language_stable_id as referenced_stable_id,
324
+ 'n'::char as deptype,
325
+ NULL::text as dep_schema,
326
+ NULL::text as ref_schema
327
+ from lang_acls
328
+
329
+ union all
330
+ select distinct
331
+ format('acl:%s::grantee:%s', language_stable_id, grantee) as dependent_stable_id,
332
+ format('role:%s', grantee) as referenced_stable_id,
333
+ 'n'::char as deptype,
334
+ NULL::text as dep_schema,
335
+ NULL::text as ref_schema
336
+ from lang_acls
337
+
338
+ union all
339
+ select distinct
340
+ format('acl:%s::grantee:%s', target_stable_id, grantee) as dependent_stable_id,
341
+ target_stable_id as referenced_stable_id,
342
+ 'n'::char as deptype,
343
+ schema_name as dep_schema,
344
+ schema_name as ref_schema
345
+ from proc_targets
346
+
347
+ union all
348
+ select distinct
349
+ format('acl:%s::grantee:%s', target_stable_id, grantee) as dependent_stable_id,
350
+ format('role:%s', grantee) as referenced_stable_id,
351
+ 'n'::char as deptype,
352
+ schema_name as dep_schema,
353
+ NULL::text as ref_schema
354
+ from proc_targets
355
+
356
+ union all
357
+ select distinct
358
+ format('acl:%s::grantee:%s', target_stable_id, grantee) as dependent_stable_id,
359
+ target_stable_id as referenced_stable_id,
360
+ 'n'::char as deptype,
361
+ schema_name as dep_schema,
362
+ schema_name as ref_schema
363
+ from type_targets
364
+ where target_stable_id is not null
365
+
366
+ union all
367
+ select distinct
368
+ format('acl:%s::grantee:%s', target_stable_id, grantee) as dependent_stable_id,
369
+ format('role:%s', grantee) as referenced_stable_id,
370
+ 'n'::char as deptype,
371
+ schema_name as dep_schema,
372
+ NULL::text as ref_schema
373
+ from type_targets
374
+ where target_stable_id is not null
375
+
376
+ union all
377
+ select distinct
378
+ format('aclcol:%s::grantee:%s', table_stable_id, grantee) as dependent_stable_id,
379
+ table_stable_id as referenced_stable_id,
380
+ 'n'::char as deptype,
381
+ table_schema as dep_schema,
382
+ table_schema as ref_schema
383
+ from col_acls
384
+
385
+ union all
386
+ select distinct
387
+ format('aclcol:%s::grantee:%s', table_stable_id, grantee) as dependent_stable_id,
388
+ format('role:%s', grantee) as referenced_stable_id,
389
+ 'n'::char as deptype,
390
+ table_schema as dep_schema,
391
+ NULL::text as ref_schema
392
+ from col_acls
393
+
394
+ union all
395
+ select distinct
396
+ defacl_stable_id as dependent_stable_id,
397
+ grantor_role_stable_id as referenced_stable_id,
398
+ 'n'::char as deptype,
399
+ schema_name as dep_schema,
400
+ NULL::text as ref_schema
401
+ from defacls
402
+
403
+ union all
404
+ select distinct
405
+ defacl_stable_id as dependent_stable_id,
406
+ grantee_role_stable_id as referenced_stable_id,
407
+ 'n'::char as deptype,
408
+ schema_name as dep_schema,
409
+ NULL::text as ref_schema
410
+ from defacls
411
+
412
+ union all
413
+ select distinct
414
+ defacl_stable_id as dependent_stable_id,
415
+ schema_stable_id as referenced_stable_id,
416
+ 'n'::char as deptype,
417
+ schema_name as dep_schema,
418
+ schema_name as ref_schema
419
+ from defacls
420
+ where schema_stable_id is not null
421
+
422
+ union all
423
+ select distinct
424
+ format('membership:%s->%s', role_name, member_name) as dependent_stable_id,
425
+ format('role:%s', role_name) as referenced_stable_id,
426
+ 'n'::char as deptype,
427
+ NULL::text as dep_schema,
428
+ NULL::text as ref_schema
429
+ from memberships
430
+
431
+ union all
432
+ select distinct
433
+ format('membership:%s->%s', role_name, member_name) as dependent_stable_id,
434
+ format('role:%s', member_name) as referenced_stable_id,
435
+ 'n'::char as deptype,
436
+ NULL::text as dep_schema,
437
+ NULL::text as ref_schema
438
+ from memberships
439
+
440
+ union all
441
+ select distinct
442
+ format('acl:%s::grantee:%s', fdw_stable_id, grantee) as dependent_stable_id,
443
+ fdw_stable_id as referenced_stable_id,
444
+ 'n'::char as deptype,
445
+ NULL::text as dep_schema,
446
+ NULL::text as ref_schema
447
+ from fdw_acls
448
+
449
+ union all
450
+ select distinct
451
+ format('acl:%s::grantee:%s', fdw_stable_id, grantee) as dependent_stable_id,
452
+ format('role:%s', grantee) as referenced_stable_id,
453
+ 'n'::char as deptype,
454
+ NULL::text as dep_schema,
455
+ NULL::text as ref_schema
456
+ from fdw_acls
457
+
458
+ union all
459
+ select distinct
460
+ format('acl:%s::grantee:%s', server_stable_id, grantee) as dependent_stable_id,
461
+ server_stable_id as referenced_stable_id,
462
+ 'n'::char as deptype,
463
+ NULL::text as dep_schema,
464
+ NULL::text as ref_schema
465
+ from server_acls
466
+
467
+ union all
468
+ select distinct
469
+ format('acl:%s::grantee:%s', server_stable_id, grantee) as dependent_stable_id,
470
+ format('role:%s', grantee) as referenced_stable_id,
471
+ 'n'::char as deptype,
472
+ NULL::text as dep_schema,
473
+ NULL::text as ref_schema
474
+ from server_acls
475
+
476
+ union all
477
+ select distinct
478
+ format('acl:%s::grantee:%s', target_stable_id, grantee) as dependent_stable_id,
479
+ target_stable_id as referenced_stable_id,
480
+ 'n'::char as deptype,
481
+ target_schema as dep_schema,
482
+ target_schema as ref_schema
483
+ from foreign_table_targets
484
+ where target_stable_id is not null
485
+
486
+ union all
487
+ select distinct
488
+ format('acl:%s::grantee:%s', target_stable_id, grantee) as dependent_stable_id,
489
+ format('role:%s', grantee) as referenced_stable_id,
490
+ 'n'::char as deptype,
491
+ target_schema as dep_schema,
492
+ NULL::text as ref_schema
493
+ from foreign_table_targets
494
+ where target_stable_id is not null
495
+ ) all_rows
496
+ where dependent_stable_id <> referenced_stable_id
497
+ and NOT (
498
+ COALESCE(dep_schema, '') LIKE ANY (ARRAY['pg\\_%','information\\_schema'])
499
+ )
500
+ `);
501
+
502
+ return rows;
503
+ }
504
+
505
+ /**
506
+ * Extract all dependencies from pg_depend, joining with pg_class for class names and applying user object filters.
507
+ * @param sql - The SQL client.
508
+ * @param params - Object containing arrays of OIDs for filtering (user_oids, user_namespace_oids, etc.)
509
+ * @returns Array of dependency objects with class names.
510
+ */
511
+ export async function extractDepends(pool: Pool): Promise<PgDepend[]> {
512
+ const { rows: dependsRows } = await pool.query<PgDepend>(sql`
513
+ WITH ids AS (
514
+ -- only the objects that actually show up in dependencies (both sides)
515
+ SELECT DISTINCT classid, objid, objsubid FROM pg_depend WHERE deptype IN ('n','a')
516
+ UNION
517
+ SELECT DISTINCT refclassid, refobjid, refobjsubid FROM pg_depend WHERE deptype IN ('n','a')
518
+ ),
519
+ objects AS (
520
+ /* Schemas */
521
+ SELECT 'pg_namespace'::regclass AS classid, n.oid AS objid, 0::int2 AS objsubid,
522
+ n.nspname AS schema_name,
523
+ format('schema:%I', n.nspname) AS stable_id
524
+ FROM pg_namespace n
525
+ JOIN ids i ON i.classid = 'pg_namespace'::regclass AND i.objid = n.oid AND COALESCE(i.objsubid,0) = 0
526
+
527
+ UNION ALL
528
+ /* Tables / Views / MViews / Sequences / Indexes / Composite types (pg_class) */
529
+ SELECT 'pg_class'::regclass, c.oid, 0::int2,
530
+ ns.nspname,
531
+ CASE
532
+ WHEN ns.nspname IN ('information_schema','pg_catalog','pg_toast') THEN
533
+ CASE c.relkind
534
+ WHEN 'r' THEN format('systemTable:%I.%I', ns.nspname, c.relname)
535
+ WHEN 'v' THEN format('systemView:%I.%I', ns.nspname, c.relname)
536
+ WHEN 'S' THEN format('systemSequence:%I.%I', ns.nspname, c.relname)
537
+ WHEN 'i' THEN format('systemIndex:%I.%I.%I', ns.nspname, tbl.relname, c.relname)
538
+ ELSE format('systemObject:%I.%I:%s', ns.nspname, c.relname, c.relkind::text)
539
+ END
540
+ ELSE
541
+ CASE c.relkind
542
+ WHEN 'r' THEN format('table:%I.%I', ns.nspname, c.relname)
543
+ WHEN 'p' THEN format('table:%I.%I', ns.nspname, c.relname)
544
+ WHEN 'v' THEN format('view:%I.%I', ns.nspname, c.relname)
545
+ WHEN 'm' THEN format('materializedView:%I.%I', ns.nspname, c.relname)
546
+ WHEN 'S' THEN format('sequence:%I.%I', ns.nspname, c.relname)
547
+ WHEN 'f' THEN format('foreignTable:%I.%I', ns.nspname, c.relname)
548
+ WHEN 'i' THEN format('index:%I.%I.%I', ns.nspname, tbl.relname, c.relname)
549
+ WHEN 'c' THEN format('type:%I.%I', ns.nspname, c.relname)
550
+ ELSE format('unknown:%s.%s', 'pg_class', c.oid::text)
551
+ END
552
+ END AS stable_id
553
+ FROM pg_class c
554
+ JOIN pg_namespace ns ON ns.oid = c.relnamespace
555
+ LEFT JOIN pg_index idx ON idx.indexrelid = c.oid
556
+ LEFT JOIN pg_class tbl ON tbl.oid = idx.indrelid
557
+ JOIN ids i ON i.classid = 'pg_class'::regclass AND i.objid = c.oid AND COALESCE(i.objsubid,0) = 0
558
+
559
+ UNION ALL
560
+ /* Columns (so refobjsubid > 0 resolves to a column stable id) */
561
+ SELECT 'pg_class'::regclass, a.attrelid, a.attnum,
562
+ ns.nspname,
563
+ format('column:%I.%I.%I', ns.nspname, c.relname, a.attname)
564
+ FROM pg_attribute a
565
+ JOIN pg_class c ON c.oid = a.attrelid
566
+ JOIN pg_namespace ns ON ns.oid = c.relnamespace
567
+ JOIN ids i ON i.classid = 'pg_class'::regclass AND i.objid = a.attrelid AND i.objsubid = a.attnum
568
+ WHERE a.attnum > 0 AND NOT a.attisdropped
569
+
570
+ UNION ALL
571
+ /* Types (map row types back to their owning relation when applicable) */
572
+ SELECT 'pg_type'::regclass, t.oid, 0::int2,
573
+ COALESCE(rns.nspname, ns.nspname) AS schema_name, -- prefer owning rel's schema if present
574
+ CASE t.typtype
575
+ WHEN 'd' THEN format('domain:%I.%I', ns.nspname, t.typname)
576
+ WHEN 'e' THEN format('type:%I.%I', ns.nspname, t.typname)
577
+ WHEN 'r' THEN format('type:%I.%I', ns.nspname, t.typname)
578
+ WHEN 'm' THEN format('multirange:%I.%I', ns.nspname, t.typname)
579
+
580
+ WHEN 'c' THEN
581
+ CASE
582
+ /* Row type owned by a table / partitioned table / foreign table */
583
+ WHEN r.oid IS NOT NULL AND r.relkind IN ('r','p','f') THEN
584
+ CASE
585
+ WHEN rns.nspname IN ('information_schema','pg_catalog','pg_toast')
586
+ THEN format('systemTable:%I.%I', rns.nspname, r.relname)
587
+ ELSE format('table:%I.%I', rns.nspname, r.relname)
588
+ END
589
+
590
+ /* Row type owned by a view */
591
+ WHEN r.oid IS NOT NULL AND r.relkind = 'v' THEN
592
+ CASE
593
+ WHEN rns.nspname IN ('information_schema','pg_catalog','pg_toast')
594
+ THEN format('systemView:%I.%I', rns.nspname, r.relname)
595
+ ELSE format('view:%I.%I', rns.nspname, r.relname)
596
+ END
597
+
598
+ /* Row type owned by a materialized view */
599
+ WHEN r.oid IS NOT NULL AND r.relkind = 'm' THEN
600
+ CASE
601
+ /* your pg_class system-branch uses systemObject for relkind m */
602
+ WHEN rns.nspname IN ('information_schema','pg_catalog','pg_toast')
603
+ THEN format('systemObject:%I.%I:%s', rns.nspname, r.relname, 'm')
604
+ ELSE format('materializedView:%I.%I', rns.nspname, r.relname)
605
+ END
606
+
607
+ /* Standalone composite type */
608
+ ELSE format('type:%I.%I', ns.nspname, t.typname)
609
+ END
610
+
611
+ WHEN 'p' THEN format('pseudoType:%I.%I', ns.nspname, t.typname)
612
+ ELSE format('type:%I.%I', ns.nspname, t.typname)
613
+ END AS stable_id
614
+ FROM pg_type t
615
+ JOIN pg_namespace ns ON ns.oid = t.typnamespace
616
+ LEFT JOIN pg_class r ON r.oid = t.typrelid
617
+ LEFT JOIN pg_namespace rns ON rns.oid = r.relnamespace
618
+ JOIN ids i ON i.classid = 'pg_type'::regclass AND i.objid = t.oid AND COALESCE(i.objsubid,0) = 0
619
+
620
+ UNION ALL
621
+ /* Constraints on domain */
622
+ SELECT 'pg_constraint'::regclass, c.oid, 0::int2,
623
+ ns.nspname,
624
+ format('constraint:%I.%I.%I', ns.nspname, ty.typname, c.conname)
625
+ FROM pg_constraint c
626
+ JOIN pg_type ty ON ty.oid = c.contypid
627
+ JOIN pg_namespace ns ON ns.oid = ty.typnamespace
628
+ JOIN ids i ON i.classid = 'pg_constraint'::regclass AND i.objid = c.oid AND COALESCE(i.objsubid,0) = 0
629
+ WHERE c.contypid <> 0
630
+
631
+ UNION ALL
632
+ /* Constraints on table */
633
+ SELECT 'pg_constraint'::regclass, c.oid, 0::int2,
634
+ ns.nspname,
635
+ format('constraint:%I.%I.%I', ns.nspname, tbl.relname, c.conname)
636
+ FROM pg_constraint c
637
+ JOIN pg_class tbl ON tbl.oid = c.conrelid
638
+ JOIN pg_namespace ns ON ns.oid = tbl.relnamespace
639
+ JOIN ids i ON i.classid = 'pg_constraint'::regclass AND i.objid = c.oid AND COALESCE(i.objsubid,0) = 0
640
+ WHERE c.conrelid <> 0
641
+
642
+ UNION ALL
643
+ /* RLS policies */
644
+ SELECT 'pg_policy'::regclass, p.oid, 0::int2,
645
+ ns.nspname,
646
+ format('rlsPolicy:%I.%I.%I', ns.nspname, tbl.relname, p.polname)
647
+ FROM pg_policy p
648
+ JOIN pg_class tbl ON tbl.oid = p.polrelid
649
+ JOIN pg_namespace ns ON ns.oid = tbl.relnamespace
650
+ JOIN ids i ON i.classid = 'pg_policy'::regclass AND i.objid = p.oid AND COALESCE(i.objsubid,0) = 0
651
+
652
+ UNION ALL
653
+ /* Functions/Procedures/Aggregates: types-only signature */
654
+ SELECT 'pg_proc'::regclass, p.oid, 0::int2,
655
+ ns.nspname,
656
+ CASE
657
+ WHEN p.prokind = 'a' THEN format(
658
+ 'aggregate:%I.%I(%s)',
659
+ ns.nspname,
660
+ p.proname,
661
+ trim(pg_catalog.pg_get_function_identity_arguments(p.oid))
662
+ )
663
+ ELSE format(
664
+ 'procedure:%I.%I(%s)',
665
+ ns.nspname,
666
+ p.proname,
667
+ COALESCE((
668
+ SELECT string_agg(format_type(t.oid, NULL), ',' ORDER BY ord)
669
+ FROM unnest(p.proargtypes) WITH ORDINALITY AS t(oid, ord)
670
+ ), '')
671
+ )
672
+ END
673
+ FROM pg_proc p
674
+ JOIN pg_namespace ns ON ns.oid = p.pronamespace
675
+ JOIN ids i ON i.classid = 'pg_proc'::regclass AND i.objid = p.oid AND COALESCE(i.objsubid,0) = 0
676
+
677
+ UNION ALL
678
+ /* Triggers */
679
+ SELECT 'pg_trigger'::regclass, tg.oid, 0::int2,
680
+ ns.nspname,
681
+ format('trigger:%I.%I.%I', ns.nspname, tbl.relname, tg.tgname)
682
+ FROM pg_trigger tg
683
+ JOIN pg_class tbl ON tbl.oid = tg.tgrelid
684
+ JOIN pg_namespace ns ON ns.oid = tbl.relnamespace
685
+ JOIN ids i ON i.classid = 'pg_trigger'::regclass AND i.objid = tg.oid AND COALESCE(i.objsubid,0) = 0
686
+
687
+ UNION ALL
688
+ /* Rewrite rules */
689
+ SELECT 'pg_rewrite'::regclass, r.oid, 0::int2,
690
+ ns.nspname,
691
+ format('rule:%I.%I.%I', ns.nspname, tbl.relname, r.rulename)
692
+ FROM pg_rewrite r
693
+ JOIN pg_class tbl ON tbl.oid = r.ev_class
694
+ JOIN pg_namespace ns ON ns.oid = tbl.relnamespace
695
+ JOIN ids i ON i.classid = 'pg_rewrite'::regclass AND i.objid = r.oid AND COALESCE(i.objsubid,0) = 0
696
+
697
+ UNION ALL
698
+ /* Full-text search objects */
699
+ SELECT 'pg_ts_config'::regclass, c.oid, 0::int2, ns.nspname, format('tsConfig:%I.%I', ns.nspname, c.cfgname)
700
+ FROM pg_ts_config c
701
+ JOIN pg_namespace ns ON ns.oid = c.cfgnamespace
702
+ JOIN ids i ON i.classid = 'pg_ts_config'::regclass AND i.objid = c.oid AND COALESCE(i.objsubid,0) = 0
703
+
704
+ UNION ALL
705
+ SELECT 'pg_ts_dict'::regclass, d.oid, 0::int2, ns.nspname, format('tsDict:%I.%I', ns.nspname, d.dictname)
706
+ FROM pg_ts_dict d
707
+ JOIN pg_namespace ns ON ns.oid = d.dictnamespace
708
+ JOIN ids i ON i.classid = 'pg_ts_dict'::regclass AND i.objid = d.oid AND COALESCE(i.objsubid,0) = 0
709
+
710
+ UNION ALL
711
+ SELECT 'pg_ts_template'::regclass, t.oid, 0::int2, ns.nspname, format('tsTemplate:%I.%I', ns.nspname, t.tmplname)
712
+ FROM pg_ts_template t
713
+ JOIN pg_namespace ns ON ns.oid = t.tmplnamespace
714
+ JOIN ids i ON i.classid = 'pg_ts_template'::regclass AND i.objid = t.oid AND COALESCE(i.objsubid,0) = 0
715
+
716
+ UNION ALL
717
+ /* Column defaults (attrdef) → column stable id */
718
+ SELECT 'pg_attrdef'::regclass, ad.oid, 0::int2,
719
+ ns.nspname,
720
+ format('column:%I.%I.%I', ns.nspname, tbl.relname, col.attname)
721
+ FROM pg_attrdef ad
722
+ JOIN pg_class tbl ON tbl.oid = ad.adrelid
723
+ JOIN pg_namespace ns ON ns.oid = tbl.relnamespace
724
+ JOIN pg_attribute col
725
+ ON col.attrelid = ad.adrelid AND col.attnum = ad.adnum AND col.attnum > 0 AND NOT col.attisdropped
726
+ JOIN ids i ON i.classid = 'pg_attrdef'::regclass AND i.objid = ad.oid AND COALESCE(i.objsubid,0) = 0
727
+
728
+ UNION ALL
729
+ /* Default ACLs */
730
+ SELECT 'pg_default_acl'::regclass, da.oid, 0::int2,
731
+ ns.nspname,
732
+ format('defaultAcl:%I.%s', ns.nspname, da.defaclobjtype::text)
733
+ FROM pg_default_acl da
734
+ JOIN pg_namespace ns ON ns.oid = da.defaclnamespace
735
+ JOIN ids i ON i.classid = 'pg_default_acl'::regclass AND i.objid = da.oid AND COALESCE(i.objsubid,0) = 0
736
+
737
+ UNION ALL
738
+ /* Publications */
739
+ SELECT 'pg_publication'::regclass, p.oid, 0::int2,
740
+ NULL::text,
741
+ format('publication:%I', p.pubname)
742
+ FROM pg_publication p
743
+ JOIN ids i ON i.classid = 'pg_publication'::regclass AND i.objid = p.oid AND COALESCE(i.objsubid,0) = 0
744
+
745
+ UNION ALL
746
+ /* Publication–table membership rows (collapse to publication stable id) */
747
+ SELECT 'pg_publication_rel'::regclass, pr.oid, 0::int2,
748
+ NULL::text AS schema_name, -- publication isn’t really “in” a schema
749
+ format('publication:%I', pub.pubname) AS stable_id
750
+ FROM pg_publication_rel pr
751
+ JOIN pg_publication pub ON pub.oid = pr.prpubid
752
+ JOIN ids i ON i.classid = 'pg_publication_rel'::regclass
753
+ AND i.objid = pr.oid
754
+ AND COALESCE(i.objsubid,0) = 0
755
+
756
+ UNION ALL
757
+ /* Language (no schema), Event trigger, Extension */
758
+ SELECT 'pg_language'::regclass, l.oid, 0::int2, NULL::text, format('language:%I', l.lanname)
759
+ FROM pg_language l
760
+ JOIN ids i ON i.classid = 'pg_language'::regclass AND i.objid = l.oid AND COALESCE(i.objsubid,0) = 0
761
+
762
+ UNION ALL
763
+ SELECT 'pg_event_trigger'::regclass, et.oid, 0::int2, NULL::text, format('eventTrigger:%I', et.evtname)
764
+ FROM pg_event_trigger et
765
+ JOIN ids i ON i.classid = 'pg_event_trigger'::regclass AND i.objid = et.oid AND COALESCE(i.objsubid,0) = 0
766
+
767
+ UNION ALL
768
+ SELECT 'pg_extension'::regclass, e.oid, 0::int2, NULL::text, format('extension:%I', e.extname)
769
+ FROM pg_extension e
770
+ JOIN ids i ON i.classid = 'pg_extension'::regclass AND i.objid = e.oid AND COALESCE(i.objsubid,0) = 0
771
+
772
+ UNION ALL
773
+ /* Subscriptions (cluster-wide; scope to current database) */
774
+ SELECT 'pg_subscription'::regclass, s.oid, 0::int2,
775
+ NULL::text,
776
+ format('subscription:%I', s.subname)
777
+ FROM pg_subscription s
778
+ JOIN ids i
779
+ ON i.classid = 'pg_subscription'::regclass
780
+ AND i.objid = s.oid
781
+ AND COALESCE(i.objsubid,0) = 0
782
+ WHERE s.subdbid = (SELECT oid FROM pg_database WHERE datname = current_database())
783
+
784
+ UNION ALL
785
+ /* Foreign Data Wrappers */
786
+ SELECT 'pg_foreign_data_wrapper'::regclass, fdw.oid, 0::int2,
787
+ NULL::text,
788
+ format('foreignDataWrapper:%I', fdw.fdwname)
789
+ FROM pg_foreign_data_wrapper fdw
790
+ JOIN ids i ON i.classid = 'pg_foreign_data_wrapper'::regclass AND i.objid = fdw.oid AND COALESCE(i.objsubid,0) = 0
791
+ WHERE NOT fdw.fdwname LIKE ANY (ARRAY['pg\\_%'])
792
+
793
+ UNION ALL
794
+ /* Foreign Servers */
795
+ SELECT 'pg_foreign_server'::regclass, srv.oid, 0::int2,
796
+ NULL::text,
797
+ format('server:%I', srv.srvname)
798
+ FROM pg_foreign_server srv
799
+ JOIN pg_foreign_data_wrapper fdw ON fdw.oid = srv.srvfdw
800
+ JOIN ids i ON i.classid = 'pg_foreign_server'::regclass AND i.objid = srv.oid AND COALESCE(i.objsubid,0) = 0
801
+ WHERE NOT fdw.fdwname LIKE ANY (ARRAY['pg\\_%'])
802
+
803
+ UNION ALL
804
+ /* User Mappings */
805
+ SELECT 'pg_user_mapping'::regclass, um.oid, 0::int2,
806
+ NULL::text,
807
+ format('userMapping:%I:%s', srv.srvname, CASE WHEN um.umuser = 0 THEN 'PUBLIC' ELSE um.umuser::regrole::text END)
808
+ FROM pg_user_mapping um
809
+ JOIN pg_foreign_server srv ON srv.oid = um.umserver
810
+ JOIN pg_foreign_data_wrapper fdw ON fdw.oid = srv.srvfdw
811
+ JOIN ids i ON i.classid = 'pg_user_mapping'::regclass AND i.objid = um.oid AND COALESCE(i.objsubid,0) = 0
812
+ WHERE NOT fdw.fdwname LIKE ANY (ARRAY['pg\\_%'])
813
+ ),
814
+ base AS (
815
+ SELECT DISTINCT
816
+ COALESCE(dep.stable_id, format('unknown:%s.%s', (d.classid::regclass)::text, d.objid::text)) AS dependent_stable_id,
817
+ COALESCE(ref.stable_id, format('unknown:%s.%s', (d.refclassid::regclass)::text, d.refobjid::text)) AS referenced_stable_id,
818
+ d.deptype,
819
+ dep.schema_name AS dep_schema,
820
+ ref.schema_name AS ref_schema
821
+ FROM pg_depend d
822
+ LEFT JOIN objects dep
823
+ ON dep.classid = d.classid AND dep.objid = d.objid AND dep.objsubid = COALESCE(NULLIF(d.objsubid,0),0)
824
+ LEFT JOIN objects ref
825
+ ON ref.classid = d.refclassid AND ref.objid = d.refobjid AND ref.objsubid = COALESCE(NULLIF(d.refobjsubid,0),0)
826
+ WHERE d.deptype IN ('n','a')
827
+ ),
828
+ comment_deps AS (
829
+ -- Table comments
830
+ SELECT DISTINCT
831
+ format('comment:%s', format('table:%I.%I', n.nspname, c.relname)) AS dependent_stable_id,
832
+ format('table:%I.%I', n.nspname, c.relname) AS referenced_stable_id,
833
+ 'a'::"char" AS deptype,
834
+ n.nspname AS dep_schema,
835
+ n.nspname AS ref_schema
836
+ FROM pg_description d
837
+ JOIN pg_class c ON d.classoid = 'pg_class'::regclass AND d.objoid = c.oid AND d.objsubid = 0
838
+ JOIN pg_namespace n ON c.relnamespace = n.oid
839
+ WHERE c.relkind IN ('r','p')
840
+
841
+ UNION ALL
842
+
843
+ -- Foreign table comments
844
+ SELECT DISTINCT
845
+ format('comment:%s', format('foreignTable:%I.%I', n.nspname, c.relname)) AS dependent_stable_id,
846
+ format('foreignTable:%I.%I', n.nspname, c.relname) AS referenced_stable_id,
847
+ 'a'::"char" AS deptype,
848
+ n.nspname AS dep_schema,
849
+ n.nspname AS ref_schema
850
+ FROM pg_description d
851
+ JOIN pg_class c ON d.classoid = 'pg_class'::regclass AND d.objoid = c.oid AND d.objsubid = 0
852
+ JOIN pg_namespace n ON c.relnamespace = n.oid
853
+ JOIN pg_foreign_table ft ON ft.ftrelid = c.oid
854
+ JOIN pg_foreign_server srv ON srv.oid = ft.ftserver
855
+ JOIN pg_foreign_data_wrapper fdw ON fdw.oid = srv.srvfdw
856
+ WHERE c.relkind = 'f'
857
+ AND NOT n.nspname LIKE ANY (ARRAY['pg\\_%','information\\_schema'])
858
+ AND NOT fdw.fdwname LIKE ANY (ARRAY['pg\\_%'])
859
+
860
+ UNION ALL
861
+
862
+ -- Materialized view comments
863
+ SELECT DISTINCT
864
+ format(
865
+ 'comment:%s',
866
+ format('materializedView:%I.%I', n.nspname, c.relname)
867
+ ) AS dependent_stable_id,
868
+ format('materializedView:%I.%I', n.nspname, c.relname) AS referenced_stable_id,
869
+ 'a'::"char" AS deptype,
870
+ n.nspname AS dep_schema,
871
+ n.nspname AS ref_schema
872
+ FROM pg_description d
873
+ JOIN pg_class c ON d.classoid = 'pg_class'::regclass AND d.objoid = c.oid AND d.objsubid = 0
874
+ JOIN pg_namespace n ON c.relnamespace = n.oid
875
+ WHERE c.relkind = 'm'
876
+
877
+ UNION ALL
878
+
879
+ -- Composite type comments
880
+ SELECT DISTINCT
881
+ format(
882
+ 'comment:%s',
883
+ format('type:%I.%I', n.nspname, t.relname)
884
+ ) AS dependent_stable_id,
885
+ format('type:%I.%I', n.nspname, t.relname) AS referenced_stable_id,
886
+ 'a'::"char" AS deptype,
887
+ n.nspname AS dep_schema,
888
+ n.nspname AS ref_schema
889
+ FROM pg_description d
890
+ JOIN pg_type ty
891
+ ON d.classoid = 'pg_type'::regclass
892
+ AND d.objoid = ty.oid
893
+ AND d.objsubid = 0
894
+ JOIN pg_class t
895
+ ON t.reltype = ty.oid
896
+ JOIN pg_namespace n
897
+ ON n.oid = t.relnamespace
898
+ WHERE t.relkind = 'c'
899
+
900
+ UNION ALL
901
+
902
+ -- Domain comments
903
+ SELECT DISTINCT
904
+ format(
905
+ 'comment:%s',
906
+ format('domain:%I.%I', t.typnamespace::regnamespace::text, t.typname)
907
+ ) AS dependent_stable_id,
908
+ format('domain:%I.%I', t.typnamespace::regnamespace::text, t.typname) AS referenced_stable_id,
909
+ 'a'::"char" AS deptype,
910
+ t.typnamespace::regnamespace::text AS dep_schema,
911
+ t.typnamespace::regnamespace::text AS ref_schema
912
+ FROM pg_description d
913
+ JOIN pg_type t ON d.classoid = 'pg_type'::regclass AND d.objoid = t.oid AND t.typtype = 'd' AND d.objsubid = 0
914
+
915
+
916
+ UNION ALL
917
+
918
+ -- Collation comments
919
+ SELECT DISTINCT
920
+ format(
921
+ 'comment:%s',
922
+ format('collation:%I.%I', n.nspname, c.collname)
923
+ ) AS dependent_stable_id,
924
+ format('collation:%I.%I', n.nspname, c.collname) AS referenced_stable_id,
925
+ 'a'::"char" AS deptype,
926
+ n.nspname AS dep_schema,
927
+ n.nspname AS ref_schema
928
+ FROM pg_description d
929
+ JOIN pg_collation c ON d.classoid = 'pg_collation'::regclass AND d.objoid = c.oid AND d.objsubid = 0
930
+ JOIN pg_namespace n ON c.collnamespace = n.oid
931
+
932
+
933
+ UNION ALL
934
+
935
+ -- Enum type comments
936
+ SELECT DISTINCT
937
+ format(
938
+ 'comment:%s',
939
+ format('type:%I.%I', t.typnamespace::regnamespace::text, t.typname)
940
+ ) AS dependent_stable_id,
941
+ format('type:%I.%I', t.typnamespace::regnamespace::text, t.typname) AS referenced_stable_id,
942
+ 'a'::"char" AS deptype,
943
+ t.typnamespace::regnamespace::text AS dep_schema,
944
+ t.typnamespace::regnamespace::text AS ref_schema
945
+ FROM pg_description d
946
+ JOIN pg_type t ON d.classoid = 'pg_type'::regclass AND d.objoid = t.oid AND t.typtype = 'e' AND d.objsubid = 0
947
+
948
+
949
+ UNION ALL
950
+
951
+ -- Range type comments
952
+ SELECT DISTINCT
953
+ format(
954
+ 'comment:%s',
955
+ format('type:%I.%I', t.typnamespace::regnamespace::text, t.typname)
956
+ ) AS dependent_stable_id,
957
+ format('type:%I.%I', t.typnamespace::regnamespace::text, t.typname) AS referenced_stable_id,
958
+ 'a'::"char" AS deptype,
959
+ t.typnamespace::regnamespace::text AS dep_schema,
960
+ t.typnamespace::regnamespace::text AS ref_schema
961
+ FROM pg_description d
962
+ JOIN pg_type t ON d.classoid = 'pg_type'::regclass AND d.objoid = t.oid AND t.typtype = 'r' AND d.objsubid = 0
963
+
964
+
965
+ UNION ALL
966
+
967
+ -- Column comments (reference table as the owning object)
968
+ SELECT DISTINCT
969
+ format(
970
+ 'comment:%s',
971
+ format('column:%I.%I.%I', n.nspname, c.relname, a.attname)
972
+ ) AS dependent_stable_id,
973
+ format('column:%I.%I.%I', n.nspname, c.relname, a.attname) AS referenced_stable_id,
974
+ 'a'::"char" AS deptype,
975
+ n.nspname AS dep_schema,
976
+ n.nspname AS ref_schema
977
+ FROM pg_description d
978
+ JOIN pg_class c ON d.classoid = 'pg_class'::regclass AND d.objoid = c.oid AND d.objsubid > 0
979
+ JOIN pg_attribute a ON a.attrelid = c.oid AND a.attnum = d.objsubid AND a.attnum > 0 AND NOT a.attisdropped
980
+ JOIN pg_namespace n ON c.relnamespace = n.oid
981
+ WHERE c.relkind IN ('r','p')
982
+
983
+ UNION ALL
984
+
985
+ -- Index comments
986
+ SELECT DISTINCT
987
+ format(
988
+ 'comment:%s',
989
+ format('index:%I.%I.%I', n.nspname, tbl.relname, c.relname)
990
+ ) AS dependent_stable_id,
991
+ format('index:%I.%I.%I', n.nspname, tbl.relname, c.relname) AS referenced_stable_id,
992
+ 'a'::"char" AS deptype,
993
+ n.nspname AS dep_schema,
994
+ n.nspname AS ref_schema
995
+ FROM pg_description d
996
+ JOIN pg_class c ON d.classoid = 'pg_class'::regclass AND d.objoid = c.oid AND d.objsubid = 0
997
+ JOIN pg_namespace n ON c.relnamespace = n.oid
998
+ LEFT JOIN pg_index idx ON idx.indexrelid = c.oid
999
+ LEFT JOIN pg_class tbl ON tbl.oid = idx.indrelid
1000
+ WHERE c.relkind = 'i'
1001
+
1002
+ UNION ALL
1003
+
1004
+ -- Materialized view column comments (reference materialized view as the owning object)
1005
+ SELECT DISTINCT
1006
+ format(
1007
+ 'comment:%s',
1008
+ format('column:%I.%I.%I', n.nspname, c.relname, a.attname)
1009
+ ) AS dependent_stable_id,
1010
+ format('column:%I.%I.%I', n.nspname, c.relname, a.attname) AS referenced_stable_id,
1011
+ 'a'::"char" AS deptype,
1012
+ n.nspname AS dep_schema,
1013
+ n.nspname AS ref_schema
1014
+ FROM pg_description d
1015
+ JOIN pg_class c ON d.classoid = 'pg_class'::regclass AND d.objoid = c.oid AND d.objsubid > 0
1016
+ JOIN pg_attribute a ON a.attrelid = c.oid AND a.attnum = d.objsubid AND a.attnum > 0 AND NOT a.attisdropped
1017
+ JOIN pg_namespace n ON c.relnamespace = n.oid
1018
+ WHERE c.relkind = 'm'
1019
+
1020
+ UNION ALL
1021
+
1022
+ -- Composite type attribute comments
1023
+ SELECT DISTINCT
1024
+ format(
1025
+ 'comment:%s',
1026
+ format('%s:%s', format('type:%I.%I', n.nspname, t.relname), a.attname)
1027
+ ) AS dependent_stable_id,
1028
+ format('%s:%s', format('type:%I.%I', n.nspname, t.relname), a.attname) AS referenced_stable_id,
1029
+ 'a'::"char" AS deptype,
1030
+ n.nspname AS dep_schema,
1031
+ n.nspname AS ref_schema
1032
+ FROM pg_description d
1033
+ JOIN pg_class t ON d.classoid = 'pg_class'::regclass AND d.objoid = t.oid AND t.relkind = 'c'
1034
+ JOIN pg_attribute a ON a.attrelid = t.oid AND a.attnum = d.objsubid AND a.attnum > 0 AND NOT a.attisdropped
1035
+ JOIN pg_namespace n ON t.relnamespace = n.oid
1036
+
1037
+
1038
+ UNION ALL
1039
+
1040
+ -- Language comments
1041
+ SELECT DISTINCT
1042
+ format('comment:%s', format('language:%I', l.lanname)) AS dependent_stable_id,
1043
+ format('language:%I', l.lanname) AS referenced_stable_id,
1044
+ 'a'::"char" AS deptype,
1045
+ NULL::text AS dep_schema,
1046
+ NULL::text AS ref_schema
1047
+ FROM pg_description d
1048
+ JOIN pg_language l ON d.classoid = 'pg_language'::regclass AND d.objoid = l.oid AND d.objsubid = 0
1049
+ WHERE l.lanname NOT IN ('internal', 'c')
1050
+ UNION ALL
1051
+
1052
+ -- Event trigger comments
1053
+ SELECT DISTINCT
1054
+ format('comment:%s', format('eventTrigger:%I', et.evtname)) AS dependent_stable_id,
1055
+ format('eventTrigger:%I', et.evtname) AS referenced_stable_id,
1056
+ 'a'::"char" AS deptype,
1057
+ NULL::text AS dep_schema,
1058
+ NULL::text AS ref_schema
1059
+ FROM pg_description d
1060
+ JOIN pg_event_trigger et ON d.classoid = 'pg_event_trigger'::regclass AND d.objoid = et.oid AND d.objsubid = 0
1061
+
1062
+ UNION ALL
1063
+
1064
+ -- Publication comments
1065
+ SELECT DISTINCT
1066
+ format('comment:%s', format('publication:%I', p.pubname)) AS dependent_stable_id,
1067
+ format('publication:%I', p.pubname) AS referenced_stable_id,
1068
+ 'a'::"char" AS deptype,
1069
+ NULL::text AS dep_schema,
1070
+ NULL::text AS ref_schema
1071
+ FROM pg_description d
1072
+ JOIN pg_publication p
1073
+ ON d.classoid = 'pg_publication'::regclass
1074
+ AND d.objoid = p.oid
1075
+ AND d.objsubid = 0
1076
+
1077
+ UNION ALL
1078
+
1079
+ -- Subscription comments
1080
+ SELECT DISTINCT
1081
+ format('comment:%s', format('subscription:%I', s.subname)) AS dependent_stable_id,
1082
+ format('subscription:%I', s.subname) AS referenced_stable_id,
1083
+ 'a'::"char" AS deptype,
1084
+ NULL::text AS dep_schema,
1085
+ NULL::text AS ref_schema
1086
+ FROM pg_description d
1087
+ JOIN pg_subscription s
1088
+ ON d.classoid = 'pg_subscription'::regclass
1089
+ AND d.objoid = s.oid
1090
+ AND d.objsubid = 0
1091
+ WHERE s.subdbid = (SELECT oid FROM pg_database WHERE datname = current_database())
1092
+
1093
+ UNION ALL
1094
+
1095
+ -- Extension comments
1096
+ SELECT DISTINCT
1097
+ format('comment:%s', format('extension:%I', e.extname)) AS dependent_stable_id,
1098
+ format('extension:%I', e.extname) AS referenced_stable_id,
1099
+ 'a'::"char" AS deptype,
1100
+ NULL::text AS dep_schema,
1101
+ NULL::text AS ref_schema
1102
+ FROM pg_description d
1103
+ JOIN pg_extension e ON d.classoid = 'pg_extension'::regclass AND d.objoid = e.oid AND d.objsubid = 0
1104
+
1105
+ UNION ALL
1106
+
1107
+ -- Procedure/function/aggregate comments
1108
+ SELECT DISTINCT
1109
+ CASE
1110
+ WHEN p.prokind = 'a' THEN format(
1111
+ 'comment:%s',
1112
+ format(
1113
+ 'aggregate:%I.%I(%s)',
1114
+ p.pronamespace::regnamespace::text,
1115
+ p.proname,
1116
+ trim(pg_catalog.pg_get_function_identity_arguments(p.oid))
1117
+ )
1118
+ )
1119
+ ELSE format(
1120
+ 'comment:%s',
1121
+ format(
1122
+ 'procedure:%I.%I(%s)',
1123
+ p.pronamespace::regnamespace::text,
1124
+ p.proname,
1125
+ coalesce(
1126
+ (select string_agg(format_type(oid, null), ',' order by ord) from unnest(p.proargtypes) with ordinality as t(oid, ord)),
1127
+ ''
1128
+ )
1129
+ )
1130
+ )
1131
+ END AS dependent_stable_id,
1132
+ CASE
1133
+ WHEN p.prokind = 'a' THEN format(
1134
+ 'aggregate:%I.%I(%s)',
1135
+ p.pronamespace::regnamespace::text,
1136
+ p.proname,
1137
+ trim(pg_catalog.pg_get_function_identity_arguments(p.oid))
1138
+ )
1139
+ ELSE format(
1140
+ 'procedure:%I.%I(%s)',
1141
+ p.pronamespace::regnamespace::text,
1142
+ p.proname,
1143
+ coalesce(
1144
+ (select string_agg(format_type(oid, null), ',' order by ord) from unnest(p.proargtypes) with ordinality as t(oid, ord)),
1145
+ ''
1146
+ )
1147
+ )
1148
+ END AS referenced_stable_id,
1149
+ 'a'::"char" AS deptype,
1150
+ p.pronamespace::regnamespace::text AS dep_schema,
1151
+ p.pronamespace::regnamespace::text AS ref_schema
1152
+ FROM pg_description d
1153
+ JOIN pg_proc p ON d.classoid = 'pg_proc'::regclass AND d.objoid = p.oid AND d.objsubid = 0
1154
+
1155
+
1156
+ UNION ALL
1157
+
1158
+ -- RLS policy comments
1159
+ SELECT DISTINCT
1160
+ format(
1161
+ 'comment:%s',
1162
+ format('rlsPolicy:%I.%I.%I', ns.nspname, tc.relname, pol.polname)
1163
+ ) AS dependent_stable_id,
1164
+ format('rlsPolicy:%I.%I.%I', ns.nspname, tc.relname, pol.polname) AS referenced_stable_id,
1165
+ 'a'::"char" AS deptype,
1166
+ ns.nspname AS dep_schema,
1167
+ ns.nspname AS ref_schema
1168
+ FROM pg_description d
1169
+ JOIN pg_policy pol ON d.classoid = 'pg_policy'::regclass AND d.objoid = pol.oid AND d.objsubid = 0
1170
+ JOIN pg_class tc ON pol.polrelid = tc.oid
1171
+ JOIN pg_namespace ns ON tc.relnamespace = ns.oid
1172
+
1173
+
1174
+ UNION ALL
1175
+
1176
+ -- Role comments
1177
+ SELECT DISTINCT
1178
+ format('comment:%s', format('role:%I', r.rolname)) AS dependent_stable_id,
1179
+ format('role:%I', r.rolname) AS referenced_stable_id,
1180
+ 'a'::"char" AS deptype,
1181
+ NULL::text AS dep_schema,
1182
+ NULL::text AS ref_schema
1183
+ FROM pg_description d
1184
+ JOIN pg_roles r ON d.classoid = 'pg_authid'::regclass AND d.objoid = r.oid AND d.objsubid = 0
1185
+
1186
+ UNION ALL
1187
+
1188
+ -- Constraint comments
1189
+ SELECT DISTINCT
1190
+ format(
1191
+ 'comment:%s',
1192
+ format('constraint:%I.%I.%I', ns.nspname, tbl.relname, con.conname)
1193
+ ) AS dependent_stable_id,
1194
+ format('constraint:%I.%I.%I', ns.nspname, tbl.relname, con.conname) AS referenced_stable_id,
1195
+ 'a'::"char" AS deptype,
1196
+ ns.nspname AS dep_schema,
1197
+ ns.nspname AS ref_schema
1198
+ FROM pg_description d
1199
+ JOIN pg_constraint con ON d.classoid = 'pg_constraint'::regclass AND d.objoid = con.oid
1200
+ JOIN pg_class tbl ON con.conrelid = tbl.oid
1201
+ JOIN pg_namespace ns ON tbl.relnamespace = ns.oid
1202
+ WHERE con.conrelid <> 0
1203
+
1204
+ UNION ALL
1205
+
1206
+ -- Foreign Data Wrapper comments
1207
+ SELECT DISTINCT
1208
+ format('comment:%s', format('foreignDataWrapper:%I', fdw.fdwname)) AS dependent_stable_id,
1209
+ format('foreignDataWrapper:%I', fdw.fdwname) AS referenced_stable_id,
1210
+ 'a'::"char" AS deptype,
1211
+ NULL::text AS dep_schema,
1212
+ NULL::text AS ref_schema
1213
+ FROM pg_description d
1214
+ JOIN pg_foreign_data_wrapper fdw
1215
+ ON d.classoid = 'pg_foreign_data_wrapper'::regclass
1216
+ AND d.objoid = fdw.oid
1217
+ AND d.objsubid = 0
1218
+ WHERE NOT fdw.fdwname LIKE ANY (ARRAY['pg\\_%'])
1219
+
1220
+ UNION ALL
1221
+
1222
+ -- Server comments
1223
+ SELECT DISTINCT
1224
+ format('comment:%s', format('server:%I', srv.srvname)) AS dependent_stable_id,
1225
+ format('server:%I', srv.srvname) AS referenced_stable_id,
1226
+ 'a'::"char" AS deptype,
1227
+ NULL::text AS dep_schema,
1228
+ NULL::text AS ref_schema
1229
+ FROM pg_description d
1230
+ JOIN pg_foreign_server srv
1231
+ ON d.classoid = 'pg_foreign_server'::regclass
1232
+ AND d.objoid = srv.oid
1233
+ AND d.objsubid = 0
1234
+ JOIN pg_foreign_data_wrapper fdw ON fdw.oid = srv.srvfdw
1235
+ WHERE NOT fdw.fdwname LIKE ANY (ARRAY['pg\\_%'])
1236
+ ),
1237
+ type_usage_deps AS (
1238
+ -- Composite type attribute dependencies on user-defined types (domain/enum/range/multirange/composite)
1239
+ SELECT DISTINCT
1240
+ format('type:%I.%I', ns.nspname, comp.relname) AS dependent_stable_id,
1241
+ CASE ref_t.typtype
1242
+ WHEN 'd' THEN format('domain:%I.%I', refns.nspname, ref_t.typname)
1243
+ WHEN 'e' THEN format('type:%I.%I', refns.nspname, ref_t.typname)
1244
+ WHEN 'r' THEN format('type:%I.%I', refns.nspname, ref_t.typname)
1245
+ WHEN 'm' THEN format('multirange:%I.%I', refns.nspname, ref_t.typname)
1246
+ WHEN 'c' THEN format('type:%I.%I', refns.nspname, ref_comp.relname)
1247
+ ELSE NULL
1248
+ END AS referenced_stable_id,
1249
+ 'n'::"char" AS deptype,
1250
+ ns.nspname AS dep_schema,
1251
+ refns.nspname AS ref_schema
1252
+ FROM pg_class comp
1253
+ JOIN pg_namespace ns ON ns.oid = comp.relnamespace
1254
+ JOIN pg_attribute a ON a.attrelid = comp.oid AND a.attnum > 0 AND NOT a.attisdropped
1255
+ JOIN pg_type ref_t ON ref_t.oid = a.atttypid
1256
+ JOIN pg_namespace refns ON refns.oid = ref_t.typnamespace
1257
+ LEFT JOIN pg_class ref_comp ON ref_comp.oid = ref_t.typrelid
1258
+ WHERE comp.relkind = 'c'
1259
+ AND NOT refns.nspname LIKE ANY (ARRAY['pg\\_%','information\\_schema'])
1260
+ AND (
1261
+ ref_t.typtype IN ('d','e','r','m')
1262
+ OR (ref_t.typtype = 'c' AND ref_comp.relkind = 'c')
1263
+ )
1264
+ AND CASE ref_t.typtype
1265
+ WHEN 'c' THEN ref_comp.relname IS NOT NULL
1266
+ ELSE true
1267
+ END
1268
+ ),
1269
+ view_rewrite_rel_deps AS (
1270
+ SELECT DISTINCT
1271
+ COALESCE(
1272
+ dep_view.stable_id,
1273
+ CASE v.relkind
1274
+ WHEN 'v' THEN format('view:%I.%I', v_ns.nspname, v.relname)
1275
+ WHEN 'm' THEN format('materializedView:%I.%I', v_ns.nspname, v.relname)
1276
+ ELSE format('unknown:%s.%s', 'pg_class', v.oid::text)
1277
+ END
1278
+ ) AS dependent_stable_id,
1279
+ COALESCE(
1280
+ ref_obj.stable_id,
1281
+ CASE
1282
+ WHEN ref_attr.attnum IS NOT NULL THEN format('column:%I.%I.%I', ref_ns.nspname, ref_rel.relname, ref_attr.attname)
1283
+ WHEN ref_rel.relkind IN ('r','p','f') THEN format('table:%I.%I', ref_ns.nspname, ref_rel.relname)
1284
+ WHEN ref_rel.relkind = 'v' THEN format('view:%I.%I', ref_ns.nspname, ref_rel.relname)
1285
+ WHEN ref_rel.relkind = 'm' THEN format('materializedView:%I.%I', ref_ns.nspname, ref_rel.relname)
1286
+ ELSE format('unknown:%s.%s', 'pg_class', COALESCE(ref_rel.oid::text, d.refobjid::text))
1287
+ END
1288
+ ) AS referenced_stable_id,
1289
+ d.deptype,
1290
+ COALESCE(dep_view.schema_name, v_ns.nspname) AS dep_schema,
1291
+ COALESCE(ref_obj.schema_name, ref_ns.nspname) AS ref_schema
1292
+ FROM pg_depend d
1293
+ JOIN pg_rewrite r ON r.oid = d.objid
1294
+ JOIN pg_class v ON r.ev_class = v.oid
1295
+ JOIN pg_namespace v_ns ON v.relnamespace = v_ns.oid
1296
+ LEFT JOIN objects dep_view
1297
+ ON dep_view.classid = 'pg_class'::regclass
1298
+ AND dep_view.objid = v.oid
1299
+ AND dep_view.objsubid = 0
1300
+ LEFT JOIN pg_class ref_rel ON ref_rel.oid = d.refobjid
1301
+ LEFT JOIN pg_namespace ref_ns ON ref_rel.relnamespace = ref_ns.oid
1302
+ LEFT JOIN pg_attribute ref_attr
1303
+ ON ref_attr.attrelid = ref_rel.oid
1304
+ AND ref_attr.attnum = d.refobjsubid
1305
+ AND d.refobjsubid <> 0
1306
+ LEFT JOIN objects ref_obj
1307
+ ON ref_obj.classid = d.refclassid
1308
+ AND ref_obj.objid = d.refobjid
1309
+ AND ref_obj.objsubid = COALESCE(NULLIF(d.refobjsubid,0),0)
1310
+ WHERE d.classid = 'pg_rewrite'::regclass
1311
+ AND d.refclassid = 'pg_class'::regclass
1312
+ AND v.relkind IN ('v','m')
1313
+ AND d.deptype = 'n'
1314
+ AND (d.refobjsubid = 0 OR (ref_attr.attnum > 0 AND NOT ref_attr.attisdropped))
1315
+ AND ref_rel.oid IS NOT NULL
1316
+ AND (
1317
+ ref_attr.attnum IS NOT NULL
1318
+ OR ref_rel.relkind IN ('r','p','f','v','m')
1319
+ )
1320
+ ),
1321
+ view_rewrite_proc_deps AS (
1322
+ SELECT DISTINCT
1323
+ COALESCE(
1324
+ dep_view.stable_id,
1325
+ CASE v.relkind
1326
+ WHEN 'v' THEN format('view:%I.%I', v_ns.nspname, v.relname)
1327
+ WHEN 'm' THEN format('materializedView:%I.%I', v_ns.nspname, v.relname)
1328
+ ELSE format('unknown:%s.%s', 'pg_class', v.oid::text)
1329
+ END
1330
+ ) AS dependent_stable_id,
1331
+ COALESCE(
1332
+ ref_proc_obj.stable_id,
1333
+ CASE
1334
+ WHEN ref_proc.prokind = 'a' THEN format(
1335
+ 'aggregate:%I.%I(%s)',
1336
+ ref_proc_ns.nspname,
1337
+ ref_proc.proname,
1338
+ trim(pg_catalog.pg_get_function_identity_arguments(ref_proc.oid))
1339
+ )
1340
+ ELSE format(
1341
+ 'procedure:%I.%I(%s)',
1342
+ ref_proc_ns.nspname,
1343
+ ref_proc.proname,
1344
+ COALESCE(
1345
+ (
1346
+ SELECT string_agg(format_type(oid, NULL), ',' ORDER BY ord)
1347
+ FROM unnest(ref_proc.proargtypes) WITH ORDINALITY AS t(oid, ord)
1348
+ ),
1349
+ ''
1350
+ )
1351
+ )
1352
+ END
1353
+ ) AS referenced_stable_id,
1354
+ d.deptype,
1355
+ COALESCE(dep_view.schema_name, v_ns.nspname) AS dep_schema,
1356
+ COALESCE(ref_proc_obj.schema_name, ref_proc_ns.nspname) AS ref_schema
1357
+ FROM pg_depend d
1358
+ JOIN pg_rewrite r ON r.oid = d.objid
1359
+ JOIN pg_class v ON r.ev_class = v.oid
1360
+ JOIN pg_namespace v_ns ON v.relnamespace = v_ns.oid
1361
+ LEFT JOIN objects dep_view
1362
+ ON dep_view.classid = 'pg_class'::regclass
1363
+ AND dep_view.objid = v.oid
1364
+ AND dep_view.objsubid = 0
1365
+ JOIN pg_proc ref_proc ON ref_proc.oid = d.refobjid
1366
+ JOIN pg_namespace ref_proc_ns ON ref_proc_ns.oid = ref_proc.pronamespace
1367
+ LEFT JOIN objects ref_proc_obj
1368
+ ON ref_proc_obj.classid = 'pg_proc'::regclass
1369
+ AND ref_proc_obj.objid = ref_proc.oid
1370
+ AND ref_proc_obj.objsubid = 0
1371
+ WHERE d.classid = 'pg_rewrite'::regclass
1372
+ AND d.refclassid = 'pg_proc'::regclass
1373
+ AND v.relkind IN ('v','m')
1374
+ AND d.deptype = 'n'
1375
+ ),
1376
+ constraint_deps AS (
1377
+ SELECT DISTINCT
1378
+ format('constraint:%I.%I.%I', fk_ns.nspname, fk_table.relname, fk_con.conname) AS dependent_stable_id,
1379
+ format('constraint:%I.%I.%I', ref_ns.nspname, ref_table.relname, ref_con.conname) AS referenced_stable_id,
1380
+ 'n'::"char" AS deptype,
1381
+ fk_ns.nspname AS dep_schema,
1382
+ ref_ns.nspname AS ref_schema
1383
+ FROM pg_constraint fk_con
1384
+ JOIN pg_class fk_table ON fk_con.conrelid = fk_table.oid
1385
+ JOIN pg_namespace fk_ns ON fk_table.relnamespace = fk_ns.oid
1386
+ JOIN pg_class ref_table ON fk_con.confrelid = ref_table.oid
1387
+ JOIN pg_namespace ref_ns ON ref_table.relnamespace = ref_ns.oid
1388
+ JOIN pg_constraint ref_con ON (
1389
+ ref_con.conrelid = fk_con.confrelid
1390
+ AND ref_con.contype IN ('p', 'u')
1391
+ AND ref_con.conkey = fk_con.confkey
1392
+ )
1393
+ WHERE fk_con.contype = 'f'
1394
+ ),
1395
+ index_schema_deps AS (
1396
+ -- Indexes depend on their schema (ensure schema exists before indexes)
1397
+ SELECT DISTINCT
1398
+ format('index:%I.%I.%I', ns.nspname, tbl.relname, idx_rel.relname) AS dependent_stable_id,
1399
+ format('schema:%I', ns.nspname) AS referenced_stable_id,
1400
+ 'n'::"char" AS deptype,
1401
+ ns.nspname AS dep_schema,
1402
+ ns.nspname AS ref_schema
1403
+ FROM pg_class idx_rel
1404
+ JOIN pg_index idx ON idx.indexrelid = idx_rel.oid
1405
+ JOIN pg_class tbl ON tbl.oid = idx.indrelid
1406
+ JOIN pg_namespace ns ON ns.oid = idx_rel.relnamespace
1407
+ WHERE idx_rel.relkind = 'i'
1408
+ ),
1409
+ index_table_deps AS (
1410
+ -- Indexes depend on their owning table
1411
+ SELECT DISTINCT
1412
+ format('index:%I.%I.%I', ns.nspname, tbl.relname, idx_rel.relname) AS dependent_stable_id,
1413
+ format('table:%I.%I', ns.nspname, tbl.relname) AS referenced_stable_id,
1414
+ 'n'::"char" AS deptype,
1415
+ ns.nspname AS dep_schema,
1416
+ ns.nspname AS ref_schema
1417
+ FROM pg_class idx_rel
1418
+ JOIN pg_index idx ON idx.indexrelid = idx_rel.oid
1419
+ JOIN pg_class tbl ON tbl.oid = idx.indrelid
1420
+ JOIN pg_namespace ns ON ns.oid = idx_rel.relnamespace
1421
+ WHERE idx_rel.relkind = 'i'
1422
+ ),
1423
+ ownership_deps AS (
1424
+ -- Schema ownership dependencies
1425
+ SELECT DISTINCT
1426
+ format('schema:%I', n.nspname) AS dependent_stable_id,
1427
+ format('role:%s', n.nspowner::regrole::text) AS referenced_stable_id,
1428
+ 'n'::"char" AS deptype,
1429
+ n.nspname AS dep_schema,
1430
+ NULL::text AS ref_schema
1431
+ FROM pg_namespace n
1432
+
1433
+ UNION ALL
1434
+
1435
+ -- Table ownership dependencies
1436
+ SELECT DISTINCT
1437
+ format('table:%I.%I', n.nspname, c.relname) AS dependent_stable_id,
1438
+ format('role:%s', c.relowner::regrole::text) AS referenced_stable_id,
1439
+ 'n'::"char" AS deptype,
1440
+ n.nspname AS dep_schema,
1441
+ NULL::text AS ref_schema
1442
+ FROM pg_class c
1443
+ JOIN pg_namespace n ON c.relnamespace = n.oid
1444
+ WHERE c.relkind IN ('r','p')
1445
+
1446
+ UNION ALL
1447
+
1448
+ -- View ownership dependencies
1449
+ SELECT DISTINCT
1450
+ format('view:%I.%I', n.nspname, c.relname) AS dependent_stable_id,
1451
+ format('role:%s', c.relowner::regrole::text) AS referenced_stable_id,
1452
+ 'n'::"char" AS deptype,
1453
+ n.nspname AS dep_schema,
1454
+ NULL::text AS ref_schema
1455
+ FROM pg_class c
1456
+ JOIN pg_namespace n ON c.relnamespace = n.oid
1457
+ WHERE c.relkind = 'v'
1458
+
1459
+ UNION ALL
1460
+
1461
+ -- Materialized view ownership dependencies
1462
+ SELECT DISTINCT
1463
+ format('materializedView:%I.%I', n.nspname, c.relname) AS dependent_stable_id,
1464
+ format('role:%s', c.relowner::regrole::text) AS referenced_stable_id,
1465
+ 'n'::"char" AS deptype,
1466
+ n.nspname AS dep_schema,
1467
+ NULL::text AS ref_schema
1468
+ FROM pg_class c
1469
+ JOIN pg_namespace n ON c.relnamespace = n.oid
1470
+ WHERE c.relkind = 'm'
1471
+
1472
+ UNION ALL
1473
+
1474
+ -- Sequence ownership dependencies
1475
+ SELECT DISTINCT
1476
+ format('sequence:%I.%I', n.nspname, c.relname) AS dependent_stable_id,
1477
+ format('role:%s', c.relowner::regrole::text) AS referenced_stable_id,
1478
+ 'n'::"char" AS deptype,
1479
+ n.nspname AS dep_schema,
1480
+ NULL::text AS ref_schema
1481
+ FROM pg_class c
1482
+ JOIN pg_namespace n ON c.relnamespace = n.oid
1483
+ WHERE c.relkind = 'S'
1484
+
1485
+ UNION ALL
1486
+
1487
+ -- Composite type ownership dependencies
1488
+ SELECT DISTINCT
1489
+ format('type:%I.%I', n.nspname, c.relname) AS dependent_stable_id,
1490
+ format('role:%s', c.relowner::regrole::text) AS referenced_stable_id,
1491
+ 'n'::"char" AS deptype,
1492
+ n.nspname AS dep_schema,
1493
+ NULL::text AS ref_schema
1494
+ FROM pg_class c
1495
+ JOIN pg_namespace n ON c.relnamespace = n.oid
1496
+ WHERE c.relkind = 'c'
1497
+
1498
+ UNION ALL
1499
+
1500
+ -- Function/procedure/aggregate ownership dependencies
1501
+ SELECT DISTINCT
1502
+ CASE
1503
+ WHEN p.prokind = 'a' THEN format(
1504
+ 'aggregate:%I.%I(%s)',
1505
+ n.nspname,
1506
+ p.proname,
1507
+ trim(pg_catalog.pg_get_function_identity_arguments(p.oid))
1508
+ )
1509
+ ELSE format(
1510
+ 'procedure:%I.%I(%s)',
1511
+ n.nspname,
1512
+ p.proname,
1513
+ COALESCE(
1514
+ (
1515
+ SELECT string_agg(format_type(oid, NULL), ',' ORDER BY ord)
1516
+ FROM unnest(p.proargtypes) WITH ORDINALITY AS t(oid, ord)
1517
+ ),
1518
+ ''
1519
+ )
1520
+ )
1521
+ END AS dependent_stable_id,
1522
+ format('role:%s', p.proowner::regrole::text) AS referenced_stable_id,
1523
+ 'n'::"char" AS deptype,
1524
+ n.nspname AS dep_schema,
1525
+ NULL::text AS ref_schema
1526
+ FROM pg_proc p
1527
+ JOIN pg_namespace n ON p.pronamespace = n.oid
1528
+
1529
+ UNION ALL
1530
+
1531
+ -- Domain ownership dependencies
1532
+ SELECT DISTINCT
1533
+ format('domain:%I.%I', n.nspname, t.typname) AS dependent_stable_id,
1534
+ format('role:%s', t.typowner::regrole::text) AS referenced_stable_id,
1535
+ 'n'::"char" AS deptype,
1536
+ n.nspname AS dep_schema,
1537
+ NULL::text AS ref_schema
1538
+ FROM pg_type t
1539
+ JOIN pg_namespace n ON t.typnamespace = n.oid
1540
+ WHERE t.typtype = 'd'
1541
+
1542
+ UNION ALL
1543
+
1544
+ -- Enum ownership dependencies
1545
+ SELECT DISTINCT
1546
+ format('type:%I.%I', n.nspname, t.typname) AS dependent_stable_id,
1547
+ format('role:%s', t.typowner::regrole::text) AS referenced_stable_id,
1548
+ 'n'::"char" AS deptype,
1549
+ n.nspname AS dep_schema,
1550
+ NULL::text AS ref_schema
1551
+ FROM pg_type t
1552
+ JOIN pg_namespace n ON t.typnamespace = n.oid
1553
+ WHERE t.typtype = 'e'
1554
+
1555
+ UNION ALL
1556
+
1557
+ -- Range type ownership dependencies
1558
+ SELECT DISTINCT
1559
+ format('type:%I.%I', n.nspname, t.typname) AS dependent_stable_id,
1560
+ format('role:%s', t.typowner::regrole::text) AS referenced_stable_id,
1561
+ 'n'::"char" AS deptype,
1562
+ n.nspname AS dep_schema,
1563
+ NULL::text AS ref_schema
1564
+ FROM pg_type t
1565
+ JOIN pg_namespace n ON t.typnamespace = n.oid
1566
+ WHERE t.typtype = 'r'
1567
+
1568
+ UNION ALL
1569
+
1570
+ -- Multirange type ownership dependencies
1571
+ SELECT DISTINCT
1572
+ format('multirange:%I.%I', n.nspname, t.typname) AS dependent_stable_id,
1573
+ format('role:%s', t.typowner::regrole::text) AS referenced_stable_id,
1574
+ 'n'::"char" AS deptype,
1575
+ n.nspname AS dep_schema,
1576
+ NULL::text AS ref_schema
1577
+ FROM pg_type t
1578
+ JOIN pg_namespace n ON t.typnamespace = n.oid
1579
+ WHERE t.typtype = 'm'
1580
+
1581
+ UNION ALL
1582
+
1583
+ -- Base type ownership dependencies
1584
+ SELECT DISTINCT
1585
+ format('type:%I.%I', n.nspname, t.typname) AS dependent_stable_id,
1586
+ format('role:%s', t.typowner::regrole::text) AS referenced_stable_id,
1587
+ 'n'::"char" AS deptype,
1588
+ n.nspname AS dep_schema,
1589
+ NULL::text AS ref_schema
1590
+ FROM pg_type t
1591
+ JOIN pg_namespace n ON t.typnamespace = n.oid
1592
+ WHERE t.typtype = 'b'
1593
+
1594
+ UNION ALL
1595
+
1596
+ -- Trigger ownership dependencies (triggers inherit owner from their table)
1597
+ SELECT DISTINCT
1598
+ format('trigger:%I.%I.%I', tn.nspname, tc.relname, tg.tgname) AS dependent_stable_id,
1599
+ format('role:%s', tc.relowner::regrole::text) AS referenced_stable_id,
1600
+ 'n'::"char" AS deptype,
1601
+ tn.nspname AS dep_schema,
1602
+ NULL::text AS ref_schema
1603
+ FROM pg_trigger tg
1604
+ JOIN pg_class tc ON tg.tgrelid = tc.oid
1605
+ JOIN pg_namespace tn ON tc.relnamespace = tn.oid
1606
+ WHERE NOT tg.tgisinternal
1607
+
1608
+ UNION ALL
1609
+
1610
+ -- RLS Policy ownership dependencies (policies inherit owner from their table)
1611
+ SELECT DISTINCT
1612
+ format('rlsPolicy:%I.%I.%I', tn.nspname, tc.relname, pol.polname) AS dependent_stable_id,
1613
+ format('role:%s', tc.relowner::regrole::text) AS referenced_stable_id,
1614
+ 'n'::"char" AS deptype,
1615
+ tn.nspname AS dep_schema,
1616
+ NULL::text AS ref_schema
1617
+ FROM pg_policy pol
1618
+ JOIN pg_class tc ON pol.polrelid = tc.oid
1619
+ JOIN pg_namespace tn ON tc.relnamespace = tn.oid
1620
+
1621
+
1622
+ UNION ALL
1623
+
1624
+ -- Language ownership dependencies
1625
+ SELECT DISTINCT
1626
+ format('language:%I', l.lanname) AS dependent_stable_id,
1627
+ format('role:%s', l.lanowner::regrole::text) AS referenced_stable_id,
1628
+ 'n'::"char" AS deptype,
1629
+ NULL::text AS dep_schema,
1630
+ NULL::text AS ref_schema
1631
+ FROM pg_language l
1632
+ WHERE l.lanname NOT IN ('internal', 'c', 'sql')
1633
+
1634
+ UNION ALL
1635
+
1636
+ -- Event trigger ownership dependencies
1637
+ SELECT DISTINCT
1638
+ format('eventTrigger:%I', et.evtname) AS dependent_stable_id,
1639
+ format('role:%s', et.evtowner::regrole::text) AS referenced_stable_id,
1640
+ 'n'::"char" AS deptype,
1641
+ NULL::text AS dep_schema,
1642
+ NULL::text AS ref_schema
1643
+ FROM pg_event_trigger et
1644
+
1645
+ UNION ALL
1646
+
1647
+ -- Extension ownership dependencies
1648
+ SELECT DISTINCT
1649
+ format('extension:%I', e.extname) AS dependent_stable_id,
1650
+ format('role:%s', e.extowner::regrole::text) AS referenced_stable_id,
1651
+ 'n'::"char" AS deptype,
1652
+ NULL::text AS dep_schema,
1653
+ NULL::text AS ref_schema
1654
+ FROM pg_extension e
1655
+ WHERE e.extname <> 'plpgsql'
1656
+
1657
+ UNION ALL
1658
+
1659
+ -- Subscription ownership dependencies
1660
+ SELECT DISTINCT
1661
+ format('subscription:%I', s.subname) AS dependent_stable_id,
1662
+ format('role:%s', s.subowner::regrole::text) AS referenced_stable_id,
1663
+ 'n'::"char" AS deptype,
1664
+ NULL::text AS dep_schema,
1665
+ NULL::text AS ref_schema
1666
+ FROM pg_subscription s
1667
+ WHERE s.subdbid = (SELECT oid FROM pg_database WHERE datname = current_database())
1668
+
1669
+ UNION ALL
1670
+
1671
+ -- Publication ownership dependencies
1672
+ SELECT DISTINCT
1673
+ format('publication:%I', p.pubname) AS dependent_stable_id,
1674
+ format('role:%s', p.pubowner::regrole::text) AS referenced_stable_id,
1675
+ 'n'::"char" AS deptype,
1676
+ NULL::text AS dep_schema,
1677
+ NULL::text AS ref_schema
1678
+ FROM pg_publication p
1679
+
1680
+ UNION ALL
1681
+
1682
+ -- Collation ownership dependencies
1683
+ SELECT DISTINCT
1684
+ format('collation:%I.%I', n.nspname, c.collname) AS dependent_stable_id,
1685
+ format('role:%s', c.collowner::regrole::text) AS referenced_stable_id,
1686
+ 'n'::"char" AS deptype,
1687
+ n.nspname AS dep_schema,
1688
+ NULL::text AS ref_schema
1689
+ FROM pg_collation c
1690
+ JOIN pg_namespace n ON c.collnamespace = n.oid
1691
+
1692
+ UNION ALL
1693
+
1694
+ -- Foreign Data Wrapper ownership dependencies
1695
+ SELECT DISTINCT
1696
+ format('foreignDataWrapper:%I', fdw.fdwname) AS dependent_stable_id,
1697
+ format('role:%s', fdw.fdwowner::regrole::text) AS referenced_stable_id,
1698
+ 'n'::"char" AS deptype,
1699
+ NULL::text AS dep_schema,
1700
+ NULL::text AS ref_schema
1701
+ FROM pg_foreign_data_wrapper fdw
1702
+ WHERE NOT fdw.fdwname LIKE ANY (ARRAY['pg\\_%'])
1703
+
1704
+ UNION ALL
1705
+
1706
+ -- Server ownership dependencies
1707
+ SELECT DISTINCT
1708
+ format('server:%I', srv.srvname) AS dependent_stable_id,
1709
+ format('role:%s', srv.srvowner::regrole::text) AS referenced_stable_id,
1710
+ 'n'::"char" AS deptype,
1711
+ NULL::text AS dep_schema,
1712
+ NULL::text AS ref_schema
1713
+ FROM pg_foreign_server srv
1714
+ JOIN pg_foreign_data_wrapper fdw ON fdw.oid = srv.srvfdw
1715
+ WHERE NOT fdw.fdwname LIKE ANY (ARRAY['pg\\_%'])
1716
+
1717
+ UNION ALL
1718
+
1719
+ -- Foreign Table ownership dependencies
1720
+ SELECT DISTINCT
1721
+ format('foreignTable:%I.%I', n.nspname, c.relname) AS dependent_stable_id,
1722
+ format('role:%s', c.relowner::regrole::text) AS referenced_stable_id,
1723
+ 'n'::"char" AS deptype,
1724
+ n.nspname AS dep_schema,
1725
+ NULL::text AS ref_schema
1726
+ FROM pg_class c
1727
+ JOIN pg_namespace n ON c.relnamespace = n.oid
1728
+ JOIN pg_foreign_table ft ON ft.ftrelid = c.oid
1729
+ JOIN pg_foreign_server srv ON srv.oid = ft.ftserver
1730
+ JOIN pg_foreign_data_wrapper fdw ON fdw.oid = srv.srvfdw
1731
+ WHERE c.relkind = 'f'
1732
+ AND NOT fdw.fdwname LIKE ANY (ARRAY['pg\\_%'])
1733
+ ),
1734
+ publication_deps AS (
1735
+ SELECT DISTINCT
1736
+ format('publication:%I', pub.pubname) AS dependent_stable_id,
1737
+ format('table:%I.%I', ns.nspname, cls.relname) AS referenced_stable_id,
1738
+ 'n'::"char" AS deptype,
1739
+ NULL::text AS dep_schema,
1740
+ ns.nspname AS ref_schema
1741
+ FROM pg_publication pub
1742
+ JOIN pg_publication_rel pr ON pr.prpubid = pub.oid
1743
+ JOIN pg_class cls ON cls.oid = pr.prrelid
1744
+ JOIN pg_namespace ns ON ns.oid = cls.relnamespace
1745
+ WHERE NOT ns.nspname LIKE ANY (ARRAY['pg\\_%','information\\_schema'])
1746
+ ),
1747
+ publication_schema_deps AS (
1748
+ SELECT DISTINCT
1749
+ format('publication:%I', pub.pubname) AS dependent_stable_id,
1750
+ format('schema:%I', ns.nspname) AS referenced_stable_id,
1751
+ 'n'::"char" AS deptype,
1752
+ NULL::text AS dep_schema,
1753
+ ns.nspname AS ref_schema
1754
+ FROM pg_publication pub
1755
+ JOIN pg_publication_namespace pn ON pn.pnpubid = pub.oid
1756
+ JOIN pg_namespace ns ON ns.oid = pn.pnnspid
1757
+ WHERE NOT ns.nspname LIKE ANY (ARRAY['pg\\_%','information\\_schema'])
1758
+ ),
1759
+ fdw_deps AS (
1760
+ -- Servers depend on their Foreign Data Wrapper
1761
+ SELECT DISTINCT
1762
+ format('server:%I', srv.srvname) AS dependent_stable_id,
1763
+ format('foreignDataWrapper:%I', fdw.fdwname) AS referenced_stable_id,
1764
+ 'n'::"char" AS deptype,
1765
+ NULL::text AS dep_schema,
1766
+ NULL::text AS ref_schema
1767
+ FROM pg_foreign_server srv
1768
+ JOIN pg_foreign_data_wrapper fdw ON fdw.oid = srv.srvfdw
1769
+ WHERE NOT fdw.fdwname LIKE ANY (ARRAY['pg\\_%'])
1770
+
1771
+ UNION ALL
1772
+
1773
+ -- User Mappings depend on their Server
1774
+ SELECT DISTINCT
1775
+ format('userMapping:%I:%s', srv.srvname, CASE WHEN um.umuser = 0 THEN 'PUBLIC' ELSE um.umuser::regrole::text END) AS dependent_stable_id,
1776
+ format('server:%I', srv.srvname) AS referenced_stable_id,
1777
+ 'n'::"char" AS deptype,
1778
+ NULL::text AS dep_schema,
1779
+ NULL::text AS ref_schema
1780
+ FROM pg_user_mapping um
1781
+ JOIN pg_foreign_server srv ON srv.oid = um.umserver
1782
+ JOIN pg_foreign_data_wrapper fdw ON fdw.oid = srv.srvfdw
1783
+ WHERE NOT fdw.fdwname LIKE ANY (ARRAY['pg\\_%'])
1784
+
1785
+ UNION ALL
1786
+
1787
+ -- Foreign Tables depend on their Server
1788
+ SELECT DISTINCT
1789
+ format('foreignTable:%I.%I', n.nspname, c.relname) AS dependent_stable_id,
1790
+ format('server:%I', srv.srvname) AS referenced_stable_id,
1791
+ 'n'::"char" AS deptype,
1792
+ n.nspname AS dep_schema,
1793
+ NULL::text AS ref_schema
1794
+ FROM pg_class c
1795
+ JOIN pg_namespace n ON c.relnamespace = n.oid
1796
+ JOIN pg_foreign_table ft ON ft.ftrelid = c.oid
1797
+ JOIN pg_foreign_server srv ON srv.oid = ft.ftserver
1798
+ JOIN pg_foreign_data_wrapper fdw ON fdw.oid = srv.srvfdw
1799
+ WHERE c.relkind = 'f'
1800
+ AND NOT fdw.fdwname LIKE ANY (ARRAY['pg\\_%'])
1801
+
1802
+ UNION ALL
1803
+
1804
+ -- Foreign Tables depend on their Schema
1805
+ SELECT DISTINCT
1806
+ format('foreignTable:%I.%I', n.nspname, c.relname) AS dependent_stable_id,
1807
+ format('schema:%I', n.nspname) AS referenced_stable_id,
1808
+ 'n'::"char" AS deptype,
1809
+ n.nspname AS dep_schema,
1810
+ n.nspname AS ref_schema
1811
+ FROM pg_class c
1812
+ JOIN pg_namespace n ON c.relnamespace = n.oid
1813
+ JOIN pg_foreign_table ft ON ft.ftrelid = c.oid
1814
+ JOIN pg_foreign_server srv ON srv.oid = ft.ftserver
1815
+ JOIN pg_foreign_data_wrapper fdw ON fdw.oid = srv.srvfdw
1816
+ WHERE c.relkind = 'f'
1817
+ AND NOT fdw.fdwname LIKE ANY (ARRAY['pg\\_%'])
1818
+ ),
1819
+ all_rows AS (
1820
+ SELECT dependent_stable_id, referenced_stable_id, deptype, dep_schema, ref_schema FROM base
1821
+ UNION ALL
1822
+ SELECT dependent_stable_id, referenced_stable_id, deptype, dep_schema, ref_schema FROM comment_deps
1823
+ UNION ALL
1824
+ SELECT dependent_stable_id, referenced_stable_id, deptype, dep_schema, ref_schema FROM type_usage_deps
1825
+ UNION ALL
1826
+ SELECT dependent_stable_id, referenced_stable_id, deptype, dep_schema, ref_schema FROM view_rewrite_rel_deps
1827
+ UNION ALL
1828
+ SELECT dependent_stable_id, referenced_stable_id, deptype, dep_schema, ref_schema FROM view_rewrite_proc_deps
1829
+ UNION ALL
1830
+ SELECT dependent_stable_id, referenced_stable_id, deptype, dep_schema, ref_schema FROM constraint_deps
1831
+ UNION ALL
1832
+ SELECT dependent_stable_id, referenced_stable_id, deptype, dep_schema, ref_schema FROM index_schema_deps
1833
+ UNION ALL
1834
+ SELECT dependent_stable_id, referenced_stable_id, deptype, dep_schema, ref_schema FROM index_table_deps
1835
+ UNION ALL
1836
+ SELECT dependent_stable_id, referenced_stable_id, deptype, dep_schema, ref_schema FROM ownership_deps
1837
+ UNION ALL
1838
+ SELECT dependent_stable_id, referenced_stable_id, deptype, dep_schema, ref_schema FROM publication_deps
1839
+ UNION ALL
1840
+ SELECT dependent_stable_id, referenced_stable_id, deptype, dep_schema, ref_schema FROM publication_schema_deps
1841
+ UNION ALL
1842
+ SELECT dependent_stable_id, referenced_stable_id, deptype, dep_schema, ref_schema FROM fdw_deps
1843
+ )
1844
+ SELECT DISTINCT
1845
+ dependent_stable_id,
1846
+ referenced_stable_id,
1847
+ deptype
1848
+ FROM all_rows
1849
+ -- In some corner case (composite type) we can have the same stable ids in the case where an internal object depends on it's parent type
1850
+ -- eg: compositeType contains internal columns but we don't distinct them from the parent type itself in our stable ids
1851
+ WHERE dependent_stable_id <> referenced_stable_id
1852
+ -- filter rows where dependent object is part of Postgres internals
1853
+ AND NOT (
1854
+ COALESCE(dep_schema, '') LIKE ANY (ARRAY['pg\\_%','information\\_schema'])
1855
+ )
1856
+ ORDER BY dependent_stable_id, referenced_stable_id;
1857
+ `);
1858
+
1859
+ // Extract privilege and membership dependencies
1860
+ const privilegeDepends = await extractPrivilegeAndMembershipDepends(pool);
1861
+
1862
+ // Combine all dependency sources and remove duplicates
1863
+ const allDepends = new Set([...dependsRows, ...privilegeDepends]);
1864
+
1865
+ return Array.from(allDepends).sort(
1866
+ (a, b) =>
1867
+ a.dependent_stable_id.localeCompare(b.dependent_stable_id) ||
1868
+ a.referenced_stable_id.localeCompare(b.referenced_stable_id),
1869
+ );
1870
+ }