@supabase/pg-delta 1.0.0-alpha.3 → 1.0.0-alpha.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -0
- package/dist/cli/bin/cli.js +0 -0
- package/dist/cli/commands/plan.js +21 -0
- package/dist/cli/utils.d.ts +2 -0
- package/dist/cli/utils.js +1 -1
- package/dist/core/objects/table/table.model.d.ts +4 -2
- package/dist/core/objects/table/table.model.js +3 -0
- package/dist/core/objects/trigger/changes/trigger.alter.js +23 -0
- package/dist/core/objects/trigger/changes/trigger.create.js +2 -1
- package/dist/core/objects/trigger/trigger.model.d.ts +1 -0
- package/dist/core/objects/trigger/trigger.model.js +3 -0
- package/dist/core/plan/apply.js +3 -3
- package/dist/core/plan/create.js +34 -15
- package/dist/core/plan/sql-format/constants.d.ts +2 -0
- package/dist/core/plan/sql-format/constants.js +11 -0
- package/dist/core/plan/sql-format/fixtures.d.ts +2 -0
- package/dist/core/plan/sql-format/fixtures.js +2449 -0
- package/dist/core/plan/sql-format/format-utils.d.ts +37 -0
- package/dist/core/plan/sql-format/format-utils.js +274 -0
- package/dist/core/plan/sql-format/formatters.d.ts +20 -0
- package/dist/core/plan/sql-format/formatters.js +737 -0
- package/dist/core/plan/sql-format/index.d.ts +2 -0
- package/dist/core/plan/sql-format/index.js +98 -0
- package/dist/core/plan/sql-format/keyword-case.d.ts +2 -0
- package/dist/core/plan/sql-format/keyword-case.js +868 -0
- package/dist/core/plan/sql-format/protect.d.ts +3 -0
- package/dist/core/plan/sql-format/protect.js +269 -0
- package/dist/core/plan/sql-format/sql-scanner.d.ts +59 -0
- package/dist/core/plan/sql-format/sql-scanner.js +202 -0
- package/dist/core/plan/sql-format/tokenizer.d.ts +22 -0
- package/dist/core/plan/sql-format/tokenizer.js +118 -0
- package/dist/core/plan/sql-format/types.d.ts +28 -0
- package/dist/core/plan/sql-format/types.js +1 -0
- package/dist/core/plan/sql-format/wrap.d.ts +2 -0
- package/dist/core/plan/sql-format/wrap.js +165 -0
- package/dist/core/plan/sql-format.d.ts +2 -0
- package/dist/core/plan/sql-format.js +1 -0
- package/dist/core/plan/statements.d.ts +2 -1
- package/dist/core/plan/statements.js +6 -2
- package/dist/core/postgres-config.d.ts +15 -0
- package/dist/core/postgres-config.js +30 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/package.json +37 -22
- package/src/cli/app.ts +28 -0
- package/src/cli/bin/cli.ts +9 -0
- package/src/cli/commands/apply.ts +101 -0
- package/src/cli/commands/plan.ts +195 -0
- package/src/cli/commands/sync.ts +185 -0
- package/src/cli/formatters/index.ts +5 -0
- package/src/cli/formatters/tree/tree-builder.ts +380 -0
- package/src/cli/formatters/tree/tree-renderer.ts +372 -0
- package/src/cli/formatters/tree/tree.ts +237 -0
- package/src/cli/utils/integrations.ts +42 -0
- package/src/cli/utils.ts +231 -0
- package/src/core/catalog.diff.ts +246 -0
- package/src/core/catalog.model.ts +384 -0
- package/src/core/change.types.ts +44 -0
- package/src/core/context.ts +26 -0
- package/src/core/depend.ts +1870 -0
- package/src/core/expand-replace-dependencies.ts +380 -0
- package/src/core/fingerprint.ts +204 -0
- package/src/core/integrations/filter/dsl.ts +204 -0
- package/src/core/integrations/filter/extractors.ts +145 -0
- package/src/core/integrations/filter/filter.types.ts +3 -0
- package/src/core/integrations/integration-dsl.ts +24 -0
- package/src/core/integrations/integration.types.ts +7 -0
- package/src/core/integrations/serialize/dsl.ts +77 -0
- package/src/core/integrations/serialize/serialize.types.ts +3 -0
- package/src/core/integrations/supabase.ts +121 -0
- package/src/core/objects/aggregate/aggregate.diff.test.ts +215 -0
- package/src/core/objects/aggregate/aggregate.diff.ts +278 -0
- package/src/core/objects/aggregate/aggregate.model.ts +317 -0
- package/src/core/objects/aggregate/changes/aggregate.alter.test.ts +64 -0
- package/src/core/objects/aggregate/changes/aggregate.alter.ts +32 -0
- package/src/core/objects/aggregate/changes/aggregate.base.ts +20 -0
- package/src/core/objects/aggregate/changes/aggregate.comment.test.ts +86 -0
- package/src/core/objects/aggregate/changes/aggregate.comment.ts +62 -0
- package/src/core/objects/aggregate/changes/aggregate.create.test.ts +101 -0
- package/src/core/objects/aggregate/changes/aggregate.create.ts +329 -0
- package/src/core/objects/aggregate/changes/aggregate.drop.test.ts +78 -0
- package/src/core/objects/aggregate/changes/aggregate.drop.ts +32 -0
- package/src/core/objects/aggregate/changes/aggregate.privilege.test.ts +130 -0
- package/src/core/objects/aggregate/changes/aggregate.privilege.ts +146 -0
- package/src/core/objects/aggregate/changes/aggregate.types.ts +12 -0
- package/src/core/objects/base.change.ts +62 -0
- package/src/core/objects/base.default-privileges.ts +204 -0
- package/src/core/objects/base.diff.ts +20 -0
- package/src/core/objects/base.model.ts +82 -0
- package/src/core/objects/base.privilege-diff.ts +299 -0
- package/src/core/objects/base.privilege.ts +184 -0
- package/src/core/objects/collation/changes/collation.alter.test.ts +63 -0
- package/src/core/objects/collation/changes/collation.alter.ts +79 -0
- package/src/core/objects/collation/changes/collation.base.ts +20 -0
- package/src/core/objects/collation/changes/collation.comment.ts +68 -0
- package/src/core/objects/collation/changes/collation.create.test.ts +51 -0
- package/src/core/objects/collation/changes/collation.create.ts +106 -0
- package/src/core/objects/collation/changes/collation.drop.test.ts +28 -0
- package/src/core/objects/collation/changes/collation.drop.ts +37 -0
- package/src/core/objects/collation/changes/collation.types.ts +10 -0
- package/src/core/objects/collation/collation.diff.test.ts +100 -0
- package/src/core/objects/collation/collation.diff.ts +126 -0
- package/src/core/objects/collation/collation.model.ts +224 -0
- package/src/core/objects/domain/changes/domain.alter.test.ts +316 -0
- package/src/core/objects/domain/changes/domain.alter.ts +286 -0
- package/src/core/objects/domain/changes/domain.base.ts +20 -0
- package/src/core/objects/domain/changes/domain.comment.ts +59 -0
- package/src/core/objects/domain/changes/domain.create.test.ts +65 -0
- package/src/core/objects/domain/changes/domain.create.ts +118 -0
- package/src/core/objects/domain/changes/domain.drop.test.ts +30 -0
- package/src/core/objects/domain/changes/domain.drop.ts +34 -0
- package/src/core/objects/domain/changes/domain.privilege.ts +171 -0
- package/src/core/objects/domain/changes/domain.types.ts +12 -0
- package/src/core/objects/domain/domain.diff.test.ts +284 -0
- package/src/core/objects/domain/domain.diff.ts +358 -0
- package/src/core/objects/domain/domain.model.ts +190 -0
- package/src/core/objects/event-trigger/changes/event-trigger.alter.test.ts +50 -0
- package/src/core/objects/event-trigger/changes/event-trigger.alter.ts +82 -0
- package/src/core/objects/event-trigger/changes/event-trigger.base.ts +20 -0
- package/src/core/objects/event-trigger/changes/event-trigger.comment.ts +66 -0
- package/src/core/objects/event-trigger/changes/event-trigger.create.test.ts +24 -0
- package/src/core/objects/event-trigger/changes/event-trigger.create.ts +72 -0
- package/src/core/objects/event-trigger/changes/event-trigger.drop.test.ts +22 -0
- package/src/core/objects/event-trigger/changes/event-trigger.drop.ts +34 -0
- package/src/core/objects/event-trigger/changes/event-trigger.types.ts +10 -0
- package/src/core/objects/event-trigger/event-trigger.diff.test.ts +126 -0
- package/src/core/objects/event-trigger/event-trigger.diff.ts +126 -0
- package/src/core/objects/event-trigger/event-trigger.model.ts +106 -0
- package/src/core/objects/extension/changes/extension.alter.test.ts +58 -0
- package/src/core/objects/extension/changes/extension.alter.ts +78 -0
- package/src/core/objects/extension/changes/extension.base.ts +20 -0
- package/src/core/objects/extension/changes/extension.comment.ts +64 -0
- package/src/core/objects/extension/changes/extension.create.test.ts +25 -0
- package/src/core/objects/extension/changes/extension.create.ts +63 -0
- package/src/core/objects/extension/changes/extension.drop.test.ts +23 -0
- package/src/core/objects/extension/changes/extension.drop.ts +34 -0
- package/src/core/objects/extension/changes/extension.types.ts +10 -0
- package/src/core/objects/extension/extension.diff.test.ts +42 -0
- package/src/core/objects/extension/extension.diff.ts +90 -0
- package/src/core/objects/extension/extension.model.ts +280 -0
- package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.alter.test.ts +125 -0
- package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.alter.ts +101 -0
- package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.base.ts +20 -0
- package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.comment.ts +72 -0
- package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.create.test.ts +125 -0
- package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.create.ts +95 -0
- package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.drop.test.ts +23 -0
- package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.drop.ts +36 -0
- package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.privilege.ts +172 -0
- package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.types.ts +12 -0
- package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/foreign-data-wrapper.diff.test.ts +179 -0
- package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/foreign-data-wrapper.diff.ts +341 -0
- package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/foreign-data-wrapper.model.ts +149 -0
- package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper.types.ts +10 -0
- package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.alter.test.ts +309 -0
- package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.alter.ts +341 -0
- package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.base.ts +20 -0
- package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.comment.ts +72 -0
- package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.create.test.ts +201 -0
- package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.create.ts +81 -0
- package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.drop.test.ts +43 -0
- package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.drop.ts +37 -0
- package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.privilege.ts +181 -0
- package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.types.ts +12 -0
- package/src/core/objects/foreign-data-wrapper/foreign-table/foreign-table.diff.test.ts +813 -0
- package/src/core/objects/foreign-data-wrapper/foreign-table/foreign-table.diff.ts +406 -0
- package/src/core/objects/foreign-data-wrapper/foreign-table/foreign-table.model.ts +242 -0
- package/src/core/objects/foreign-data-wrapper/server/changes/server.alter.test.ts +168 -0
- package/src/core/objects/foreign-data-wrapper/server/changes/server.alter.ts +126 -0
- package/src/core/objects/foreign-data-wrapper/server/changes/server.base.ts +20 -0
- package/src/core/objects/foreign-data-wrapper/server/changes/server.comment.ts +60 -0
- package/src/core/objects/foreign-data-wrapper/server/changes/server.create.test.ts +131 -0
- package/src/core/objects/foreign-data-wrapper/server/changes/server.create.ts +81 -0
- package/src/core/objects/foreign-data-wrapper/server/changes/server.drop.test.ts +24 -0
- package/src/core/objects/foreign-data-wrapper/server/changes/server.drop.ts +34 -0
- package/src/core/objects/foreign-data-wrapper/server/changes/server.privilege.ts +164 -0
- package/src/core/objects/foreign-data-wrapper/server/changes/server.types.ts +12 -0
- package/src/core/objects/foreign-data-wrapper/server/server.diff.test.ts +167 -0
- package/src/core/objects/foreign-data-wrapper/server/server.diff.ts +317 -0
- package/src/core/objects/foreign-data-wrapper/server/server.model.ts +133 -0
- package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.alter.test.ts +82 -0
- package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.alter.ts +69 -0
- package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.base.ts +20 -0
- package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.create.test.ts +85 -0
- package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.create.ts +66 -0
- package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.drop.test.ts +53 -0
- package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.drop.ts +40 -0
- package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.types.ts +8 -0
- package/src/core/objects/foreign-data-wrapper/user-mapping/user-mapping.diff.test.ts +77 -0
- package/src/core/objects/foreign-data-wrapper/user-mapping/user-mapping.diff.ts +107 -0
- package/src/core/objects/foreign-data-wrapper/user-mapping/user-mapping.model.ts +96 -0
- package/src/core/objects/index/changes/index.alter.test.ts +200 -0
- package/src/core/objects/index/changes/index.alter.ts +144 -0
- package/src/core/objects/index/changes/index.base.ts +20 -0
- package/src/core/objects/index/changes/index.comment.ts +63 -0
- package/src/core/objects/index/changes/index.create.test.ts +66 -0
- package/src/core/objects/index/changes/index.create.ts +68 -0
- package/src/core/objects/index/changes/index.drop.test.ts +44 -0
- package/src/core/objects/index/changes/index.drop.ts +34 -0
- package/src/core/objects/index/changes/index.types.ts +6 -0
- package/src/core/objects/index/changes/utils.ts +16 -0
- package/src/core/objects/index/index.diff.test.ts +153 -0
- package/src/core/objects/index/index.diff.ts +243 -0
- package/src/core/objects/index/index.model.ts +370 -0
- package/src/core/objects/language/changes/language.alter.test.ts +33 -0
- package/src/core/objects/language/changes/language.alter.ts +53 -0
- package/src/core/objects/language/changes/language.base.ts +20 -0
- package/src/core/objects/language/changes/language.comment.ts +58 -0
- package/src/core/objects/language/changes/language.create.test.ts +27 -0
- package/src/core/objects/language/changes/language.create.ts +104 -0
- package/src/core/objects/language/changes/language.drop.test.ts +25 -0
- package/src/core/objects/language/changes/language.drop.ts +39 -0
- package/src/core/objects/language/changes/language.privilege.ts +172 -0
- package/src/core/objects/language/changes/language.types.ts +12 -0
- package/src/core/objects/language/language.diff.test.ts +53 -0
- package/src/core/objects/language/language.diff.ts +176 -0
- package/src/core/objects/language/language.model.ts +150 -0
- package/src/core/objects/materialized-view/changes/materialized-view.alter.test.ts +123 -0
- package/src/core/objects/materialized-view/changes/materialized-view.alter.ts +113 -0
- package/src/core/objects/materialized-view/changes/materialized-view.base.ts +20 -0
- package/src/core/objects/materialized-view/changes/materialized-view.comment.ts +176 -0
- package/src/core/objects/materialized-view/changes/materialized-view.create.test.ts +64 -0
- package/src/core/objects/materialized-view/changes/materialized-view.create.ts +93 -0
- package/src/core/objects/materialized-view/changes/materialized-view.drop.test.ts +34 -0
- package/src/core/objects/materialized-view/changes/materialized-view.drop.ts +60 -0
- package/src/core/objects/materialized-view/changes/materialized-view.privilege.ts +212 -0
- package/src/core/objects/materialized-view/changes/materialized-view.types.ts +12 -0
- package/src/core/objects/materialized-view/materialized-view.diff.test.ts +102 -0
- package/src/core/objects/materialized-view/materialized-view.diff.ts +451 -0
- package/src/core/objects/materialized-view/materialized-view.model.ts +258 -0
- package/src/core/objects/procedure/changes/procedure.alter.test.ts +1005 -0
- package/src/core/objects/procedure/changes/procedure.alter.ts +287 -0
- package/src/core/objects/procedure/changes/procedure.base.ts +20 -0
- package/src/core/objects/procedure/changes/procedure.comment.ts +70 -0
- package/src/core/objects/procedure/changes/procedure.create.test.ts +48 -0
- package/src/core/objects/procedure/changes/procedure.create.ts +92 -0
- package/src/core/objects/procedure/changes/procedure.drop.test.ts +85 -0
- package/src/core/objects/procedure/changes/procedure.drop.ts +49 -0
- package/src/core/objects/procedure/changes/procedure.privilege.ts +188 -0
- package/src/core/objects/procedure/changes/procedure.types.ts +12 -0
- package/src/core/objects/procedure/procedure.diff.test.ts +161 -0
- package/src/core/objects/procedure/procedure.diff.ts +404 -0
- package/src/core/objects/procedure/procedure.model.ts +264 -0
- package/src/core/objects/procedure/utils.ts +58 -0
- package/src/core/objects/publication/changes/publication.alter.test.ts +223 -0
- package/src/core/objects/publication/changes/publication.alter.ts +243 -0
- package/src/core/objects/publication/changes/publication.base.ts +20 -0
- package/src/core/objects/publication/changes/publication.comment.test.ts +70 -0
- package/src/core/objects/publication/changes/publication.comment.ts +64 -0
- package/src/core/objects/publication/changes/publication.create.test.ts +87 -0
- package/src/core/objects/publication/changes/publication.create.ts +82 -0
- package/src/core/objects/publication/changes/publication.drop.test.ts +46 -0
- package/src/core/objects/publication/changes/publication.drop.ts +29 -0
- package/src/core/objects/publication/changes/publication.types.ts +26 -0
- package/src/core/objects/publication/publication.diff.test.ts +292 -0
- package/src/core/objects/publication/publication.diff.ts +253 -0
- package/src/core/objects/publication/publication.model.ts +206 -0
- package/src/core/objects/publication/utils.ts +55 -0
- package/src/core/objects/rls-policy/changes/rls-policy.alter.test.ts +250 -0
- package/src/core/objects/rls-policy/changes/rls-policy.alter.ts +128 -0
- package/src/core/objects/rls-policy/changes/rls-policy.base.ts +20 -0
- package/src/core/objects/rls-policy/changes/rls-policy.comment.ts +69 -0
- package/src/core/objects/rls-policy/changes/rls-policy.create.test.ts +74 -0
- package/src/core/objects/rls-policy/changes/rls-policy.create.ts +100 -0
- package/src/core/objects/rls-policy/changes/rls-policy.drop.test.ts +28 -0
- package/src/core/objects/rls-policy/changes/rls-policy.drop.ts +39 -0
- package/src/core/objects/rls-policy/changes/rls-policy.types.ts +10 -0
- package/src/core/objects/rls-policy/rls-policy.diff.test.ts +79 -0
- package/src/core/objects/rls-policy/rls-policy.diff.ts +121 -0
- package/src/core/objects/rls-policy/rls-policy.model.ts +140 -0
- package/src/core/objects/role/changes/role.alter.test.ts +346 -0
- package/src/core/objects/role/changes/role.alter.ts +110 -0
- package/src/core/objects/role/changes/role.base.ts +24 -0
- package/src/core/objects/role/changes/role.comment.ts +55 -0
- package/src/core/objects/role/changes/role.create.test.ts +52 -0
- package/src/core/objects/role/changes/role.create.ts +102 -0
- package/src/core/objects/role/changes/role.drop.test.ts +29 -0
- package/src/core/objects/role/changes/role.drop.ts +34 -0
- package/src/core/objects/role/changes/role.privilege.ts +376 -0
- package/src/core/objects/role/changes/role.types.ts +12 -0
- package/src/core/objects/role/role.diff.test.ts +44 -0
- package/src/core/objects/role/role.diff.ts +479 -0
- package/src/core/objects/role/role.model.ts +344 -0
- package/src/core/objects/rule/changes/rule.alter.test.ts +78 -0
- package/src/core/objects/rule/changes/rule.alter.ts +72 -0
- package/src/core/objects/rule/changes/rule.base.ts +20 -0
- package/src/core/objects/rule/changes/rule.comment.test.ts +55 -0
- package/src/core/objects/rule/changes/rule.comment.ts +62 -0
- package/src/core/objects/rule/changes/rule.create.test.ts +59 -0
- package/src/core/objects/rule/changes/rule.create.ts +42 -0
- package/src/core/objects/rule/changes/rule.drop.test.ts +38 -0
- package/src/core/objects/rule/changes/rule.drop.ts +29 -0
- package/src/core/objects/rule/changes/rule.types.ts +12 -0
- package/src/core/objects/rule/rule.diff.test.ts +132 -0
- package/src/core/objects/rule/rule.diff.ts +79 -0
- package/src/core/objects/rule/rule.model.ts +173 -0
- package/src/core/objects/schema/changes/schema.alter.test.ts +28 -0
- package/src/core/objects/schema/changes/schema.alter.ts +45 -0
- package/src/core/objects/schema/changes/schema.base.ts +20 -0
- package/src/core/objects/schema/changes/schema.comment.ts +56 -0
- package/src/core/objects/schema/changes/schema.create.test.ts +22 -0
- package/src/core/objects/schema/changes/schema.create.ts +47 -0
- package/src/core/objects/schema/changes/schema.drop.test.ts +20 -0
- package/src/core/objects/schema/changes/schema.drop.ts +34 -0
- package/src/core/objects/schema/changes/schema.privilege.ts +175 -0
- package/src/core/objects/schema/changes/schema.types.ts +12 -0
- package/src/core/objects/schema/schema.diff.test.ts +42 -0
- package/src/core/objects/schema/schema.diff.ts +209 -0
- package/src/core/objects/schema/schema.model.ts +107 -0
- package/src/core/objects/sequence/changes/sequence.alter.test.ts +151 -0
- package/src/core/objects/sequence/changes/sequence.alter.ts +115 -0
- package/src/core/objects/sequence/changes/sequence.base.ts +20 -0
- package/src/core/objects/sequence/changes/sequence.comment.ts +60 -0
- package/src/core/objects/sequence/changes/sequence.create.test.ts +84 -0
- package/src/core/objects/sequence/changes/sequence.create.ts +111 -0
- package/src/core/objects/sequence/changes/sequence.drop.test.ts +32 -0
- package/src/core/objects/sequence/changes/sequence.drop.ts +37 -0
- package/src/core/objects/sequence/changes/sequence.privilege.ts +179 -0
- package/src/core/objects/sequence/changes/sequence.types.ts +12 -0
- package/src/core/objects/sequence/sequence.diff.test.ts +141 -0
- package/src/core/objects/sequence/sequence.diff.ts +359 -0
- package/src/core/objects/sequence/sequence.model.ts +185 -0
- package/src/core/objects/subscription/changes/subscription.alter.test.ts +124 -0
- package/src/core/objects/subscription/changes/subscription.alter.ts +110 -0
- package/src/core/objects/subscription/changes/subscription.base.ts +20 -0
- package/src/core/objects/subscription/changes/subscription.comment.test.ts +67 -0
- package/src/core/objects/subscription/changes/subscription.comment.ts +64 -0
- package/src/core/objects/subscription/changes/subscription.create.test.ts +77 -0
- package/src/core/objects/subscription/changes/subscription.create.ts +69 -0
- package/src/core/objects/subscription/changes/subscription.drop.test.ts +46 -0
- package/src/core/objects/subscription/changes/subscription.drop.ts +20 -0
- package/src/core/objects/subscription/changes/subscription.types.ts +22 -0
- package/src/core/objects/subscription/subscription.diff.test.ts +232 -0
- package/src/core/objects/subscription/subscription.diff.ts +241 -0
- package/src/core/objects/subscription/subscription.model.ts +190 -0
- package/src/core/objects/subscription/utils.ts +156 -0
- package/src/core/objects/table/changes/table.alter.test.ts +823 -0
- package/src/core/objects/table/changes/table.alter.ts +806 -0
- package/src/core/objects/table/changes/table.base.ts +20 -0
- package/src/core/objects/table/changes/table.comment.ts +266 -0
- package/src/core/objects/table/changes/table.create.test.ts +150 -0
- package/src/core/objects/table/changes/table.create.ts +188 -0
- package/src/core/objects/table/changes/table.drop.test.ts +34 -0
- package/src/core/objects/table/changes/table.drop.ts +45 -0
- package/src/core/objects/table/changes/table.privilege.ts +200 -0
- package/src/core/objects/table/changes/table.types.ts +12 -0
- package/src/core/objects/table/table.diff.test.ts +711 -0
- package/src/core/objects/table/table.diff.ts +953 -0
- package/src/core/objects/table/table.model.ts +460 -0
- package/src/core/objects/trigger/changes/trigger.alter.test.ts +46 -0
- package/src/core/objects/trigger/changes/trigger.alter.ts +76 -0
- package/src/core/objects/trigger/changes/trigger.base.ts +20 -0
- package/src/core/objects/trigger/changes/trigger.comment.ts +64 -0
- package/src/core/objects/trigger/changes/trigger.create.test.ts +43 -0
- package/src/core/objects/trigger/changes/trigger.create.ts +85 -0
- package/src/core/objects/trigger/changes/trigger.drop.test.ts +43 -0
- package/src/core/objects/trigger/changes/trigger.drop.ts +39 -0
- package/src/core/objects/trigger/changes/trigger.types.ts +10 -0
- package/src/core/objects/trigger/trigger.diff.test.ts +83 -0
- package/src/core/objects/trigger/trigger.diff.ts +116 -0
- package/src/core/objects/trigger/trigger.model.ts +252 -0
- package/src/core/objects/type/composite-type/changes/composite-type.alter.test.ts +202 -0
- package/src/core/objects/type/composite-type/changes/composite-type.alter.ts +174 -0
- package/src/core/objects/type/composite-type/changes/composite-type.base.ts +20 -0
- package/src/core/objects/type/composite-type/changes/composite-type.comment.ts +145 -0
- package/src/core/objects/type/composite-type/changes/composite-type.create.test.ts +101 -0
- package/src/core/objects/type/composite-type/changes/composite-type.create.ts +95 -0
- package/src/core/objects/type/composite-type/changes/composite-type.drop.test.ts +33 -0
- package/src/core/objects/type/composite-type/changes/composite-type.drop.ts +37 -0
- package/src/core/objects/type/composite-type/changes/composite-type.privilege.ts +175 -0
- package/src/core/objects/type/composite-type/changes/composite-type.types.ts +12 -0
- package/src/core/objects/type/composite-type/composite-type.diff.test.ts +191 -0
- package/src/core/objects/type/composite-type/composite-type.diff.ts +372 -0
- package/src/core/objects/type/composite-type/composite-type.model.ts +252 -0
- package/src/core/objects/type/enum/changes/enum.alter.test.ts +104 -0
- package/src/core/objects/type/enum/changes/enum.alter.ts +91 -0
- package/src/core/objects/type/enum/changes/enum.base.ts +20 -0
- package/src/core/objects/type/enum/changes/enum.comment.ts +64 -0
- package/src/core/objects/type/enum/changes/enum.create.test.ts +28 -0
- package/src/core/objects/type/enum/changes/enum.create.ts +56 -0
- package/src/core/objects/type/enum/changes/enum.drop.test.ts +25 -0
- package/src/core/objects/type/enum/changes/enum.drop.ts +34 -0
- package/src/core/objects/type/enum/changes/enum.privilege.ts +175 -0
- package/src/core/objects/type/enum/changes/enum.types.ts +12 -0
- package/src/core/objects/type/enum/enum.diff.test.ts +191 -0
- package/src/core/objects/type/enum/enum.diff.ts +396 -0
- package/src/core/objects/type/enum/enum.model.ts +194 -0
- package/src/core/objects/type/range/changes/range.alter.test.ts +27 -0
- package/src/core/objects/type/range/changes/range.alter.ts +51 -0
- package/src/core/objects/type/range/changes/range.base.ts +20 -0
- package/src/core/objects/type/range/changes/range.comment.ts +64 -0
- package/src/core/objects/type/range/changes/range.create.test.ts +51 -0
- package/src/core/objects/type/range/changes/range.create.ts +151 -0
- package/src/core/objects/type/range/changes/range.drop.test.ts +26 -0
- package/src/core/objects/type/range/changes/range.drop.ts +34 -0
- package/src/core/objects/type/range/changes/range.privilege.ts +175 -0
- package/src/core/objects/type/range/changes/range.types.ts +12 -0
- package/src/core/objects/type/range/range.diff.test.ts +70 -0
- package/src/core/objects/type/range/range.diff.ts +259 -0
- package/src/core/objects/type/range/range.model.ts +187 -0
- package/src/core/objects/type/type.types.ts +5 -0
- package/src/core/objects/utils.ts +171 -0
- package/src/core/objects/view/changes/view.alter.test.ts +110 -0
- package/src/core/objects/view/changes/view.alter.ts +112 -0
- package/src/core/objects/view/changes/view.base.ts +20 -0
- package/src/core/objects/view/changes/view.comment.ts +59 -0
- package/src/core/objects/view/changes/view.create.test.ts +65 -0
- package/src/core/objects/view/changes/view.create.ts +73 -0
- package/src/core/objects/view/changes/view.drop.test.ts +34 -0
- package/src/core/objects/view/changes/view.drop.ts +40 -0
- package/src/core/objects/view/changes/view.privilege.ts +200 -0
- package/src/core/objects/view/changes/view.types.ts +12 -0
- package/src/core/objects/view/view.diff.test.ts +91 -0
- package/src/core/objects/view/view.diff.ts +365 -0
- package/src/core/objects/view/view.model.ts +276 -0
- package/src/core/plan/apply.ts +190 -0
- package/src/core/plan/create.ts +432 -0
- package/src/core/plan/hierarchy.ts +574 -0
- package/src/core/plan/index.ts +29 -0
- package/src/core/plan/io.ts +20 -0
- package/src/core/plan/risk.ts +48 -0
- package/src/core/plan/serialize.ts +195 -0
- package/src/core/plan/sql-format/constants.ts +13 -0
- package/src/core/plan/sql-format/fixtures.ts +2806 -0
- package/src/core/plan/sql-format/format-comment-literals.test.ts +96 -0
- package/src/core/plan/sql-format/format-functions.test.ts +127 -0
- package/src/core/plan/sql-format/format-lowercase-coverage.test.ts +67 -0
- package/src/core/plan/sql-format/format-off.test.ts +809 -0
- package/src/core/plan/sql-format/format-pretty-lower-leading.test.ts +1056 -0
- package/src/core/plan/sql-format/format-pretty-narrow.test.ts +1283 -0
- package/src/core/plan/sql-format/format-pretty-preserve.test.ts +1052 -0
- package/src/core/plan/sql-format/format-pretty-upper.test.ts +1045 -0
- package/src/core/plan/sql-format/format-stress.test.ts +616 -0
- package/src/core/plan/sql-format/format-utils.test.ts +91 -0
- package/src/core/plan/sql-format/format-utils.ts +391 -0
- package/src/core/plan/sql-format/formatters.ts +921 -0
- package/src/core/plan/sql-format/index.ts +149 -0
- package/src/core/plan/sql-format/keyword-case.test.ts +118 -0
- package/src/core/plan/sql-format/keyword-case.ts +1085 -0
- package/src/core/plan/sql-format/protect.test.ts +127 -0
- package/src/core/plan/sql-format/protect.ts +337 -0
- package/src/core/plan/sql-format/sql-scanner.test.ts +240 -0
- package/src/core/plan/sql-format/sql-scanner.ts +252 -0
- package/src/core/plan/sql-format/tokenizer.test.ts +68 -0
- package/src/core/plan/sql-format/tokenizer.ts +152 -0
- package/src/core/plan/sql-format/types.ts +31 -0
- package/src/core/plan/sql-format/wrap.test.ts +119 -0
- package/src/core/plan/sql-format/wrap.ts +196 -0
- package/src/core/plan/sql-format.ts +2 -0
- package/src/core/plan/statements.ts +22 -0
- package/src/core/plan/types.ts +165 -0
- package/src/core/postgres-config.ts +169 -0
- package/src/core/sort/custom-constraints.ts +161 -0
- package/src/core/sort/debug-visualization.ts +239 -0
- package/src/core/sort/dependency-filter.ts +224 -0
- package/src/core/sort/graph-builder.ts +223 -0
- package/src/core/sort/graph-utils.ts +51 -0
- package/src/core/sort/logical-sort.ts +590 -0
- package/src/core/sort/sort-changes.ts +234 -0
- package/src/core/sort/topological-sort.ts +184 -0
- package/src/core/sort/types.ts +112 -0
- package/src/core/sort/utils.ts +69 -0
- package/src/index.ts +14 -0
|
@@ -0,0 +1,451 @@
|
|
|
1
|
+
import type { DefaultPrivilegeState } from "../base.default-privileges.ts";
|
|
2
|
+
import { diffObjects } from "../base.diff.ts";
|
|
3
|
+
import {
|
|
4
|
+
diffPrivileges,
|
|
5
|
+
groupPrivilegesByColumns,
|
|
6
|
+
} from "../base.privilege-diff.ts";
|
|
7
|
+
import type { Role } from "../role/role.model.ts";
|
|
8
|
+
import { deepEqual, hasNonAlterableChanges } from "../utils.ts";
|
|
9
|
+
import {
|
|
10
|
+
AlterMaterializedViewChangeOwner,
|
|
11
|
+
AlterMaterializedViewSetStorageParams,
|
|
12
|
+
} from "./changes/materialized-view.alter.ts";
|
|
13
|
+
import {
|
|
14
|
+
CreateCommentOnMaterializedView,
|
|
15
|
+
CreateCommentOnMaterializedViewColumn,
|
|
16
|
+
DropCommentOnMaterializedView,
|
|
17
|
+
DropCommentOnMaterializedViewColumn,
|
|
18
|
+
} from "./changes/materialized-view.comment.ts";
|
|
19
|
+
import { CreateMaterializedView } from "./changes/materialized-view.create.ts";
|
|
20
|
+
import { DropMaterializedView } from "./changes/materialized-view.drop.ts";
|
|
21
|
+
import {
|
|
22
|
+
GrantMaterializedViewPrivileges,
|
|
23
|
+
RevokeGrantOptionMaterializedViewPrivileges,
|
|
24
|
+
RevokeMaterializedViewPrivileges,
|
|
25
|
+
} from "./changes/materialized-view.privilege.ts";
|
|
26
|
+
import type { MaterializedViewChange } from "./changes/materialized-view.types.ts";
|
|
27
|
+
import type { MaterializedView } from "./materialized-view.model.ts";
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Diff two sets of materialized views from main and branch catalogs.
|
|
31
|
+
*
|
|
32
|
+
* @param ctx - Context containing version, currentUser, and defaultPrivilegeState
|
|
33
|
+
* @param main - The materialized views in the main catalog.
|
|
34
|
+
* @param branch - The materialized views in the branch catalog.
|
|
35
|
+
* @returns A list of changes to apply to main to make it match branch.
|
|
36
|
+
*/
|
|
37
|
+
export function diffMaterializedViews(
|
|
38
|
+
ctx: {
|
|
39
|
+
version: number;
|
|
40
|
+
currentUser: string;
|
|
41
|
+
defaultPrivilegeState: DefaultPrivilegeState;
|
|
42
|
+
mainRoles: Record<string, Role>;
|
|
43
|
+
},
|
|
44
|
+
main: Record<string, MaterializedView>,
|
|
45
|
+
branch: Record<string, MaterializedView>,
|
|
46
|
+
): MaterializedViewChange[] {
|
|
47
|
+
const { created, dropped, altered } = diffObjects(main, branch);
|
|
48
|
+
|
|
49
|
+
const changes: MaterializedViewChange[] = [];
|
|
50
|
+
|
|
51
|
+
for (const materializedViewId of created) {
|
|
52
|
+
const mv = branch[materializedViewId];
|
|
53
|
+
changes.push(
|
|
54
|
+
new CreateMaterializedView({
|
|
55
|
+
materializedView: mv,
|
|
56
|
+
}),
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
// OWNER: If the materialized view should be owned by someone other than the current user,
|
|
60
|
+
// emit ALTER MATERIALIZED VIEW ... OWNER TO after creation
|
|
61
|
+
if (mv.owner !== ctx.currentUser) {
|
|
62
|
+
changes.push(
|
|
63
|
+
new AlterMaterializedViewChangeOwner({
|
|
64
|
+
materializedView: mv,
|
|
65
|
+
owner: mv.owner,
|
|
66
|
+
}),
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Note: RLS (row_security, force_row_security) is a non-alterable property for materialized views.
|
|
71
|
+
// If RLS needs to be enabled, the materialized view must be dropped and recreated, which is
|
|
72
|
+
// handled in the "altered" section when non-alterable properties change.
|
|
73
|
+
|
|
74
|
+
// Materialized view comment on creation
|
|
75
|
+
if (mv.comment !== null) {
|
|
76
|
+
changes.push(
|
|
77
|
+
new CreateCommentOnMaterializedView({
|
|
78
|
+
materializedView: mv,
|
|
79
|
+
}),
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
// Column comments on creation
|
|
83
|
+
for (const col of mv.columns) {
|
|
84
|
+
if (col.comment !== null) {
|
|
85
|
+
changes.push(
|
|
86
|
+
new CreateCommentOnMaterializedViewColumn({
|
|
87
|
+
materializedView: mv,
|
|
88
|
+
column: col,
|
|
89
|
+
}),
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// PRIVILEGES: For created objects, compare against default privileges state
|
|
95
|
+
// The migration script will run ALTER DEFAULT PRIVILEGES before CREATE (via constraint spec),
|
|
96
|
+
// so objects are created with the default privileges state in effect.
|
|
97
|
+
// We compare default privileges against desired privileges to generate REVOKE/GRANT statements
|
|
98
|
+
// needed to reach the final desired state.
|
|
99
|
+
const effectiveDefaults = ctx.defaultPrivilegeState.getEffectiveDefaults(
|
|
100
|
+
ctx.currentUser,
|
|
101
|
+
"materialized_view",
|
|
102
|
+
mv.schema ?? "",
|
|
103
|
+
);
|
|
104
|
+
const desiredPrivileges = mv.privileges;
|
|
105
|
+
// Filter out owner privileges - owner always has ALL privileges implicitly
|
|
106
|
+
// and shouldn't be compared. Use the materialized view owner as the reference.
|
|
107
|
+
const privilegeResults = diffPrivileges(
|
|
108
|
+
effectiveDefaults,
|
|
109
|
+
desiredPrivileges,
|
|
110
|
+
mv.owner,
|
|
111
|
+
ctx.mainRoles,
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
// Generate grant changes
|
|
115
|
+
for (const [grantee, result] of privilegeResults) {
|
|
116
|
+
if (result.grants.length > 0) {
|
|
117
|
+
const grantGroups = groupPrivilegesByColumns(result.grants);
|
|
118
|
+
for (const [, group] of grantGroups) {
|
|
119
|
+
for (const [grantable, privSet] of group.byGrant) {
|
|
120
|
+
const privileges = Array.from(privSet).map((priv) => ({
|
|
121
|
+
privilege: priv,
|
|
122
|
+
grantable,
|
|
123
|
+
}));
|
|
124
|
+
changes.push(
|
|
125
|
+
new GrantMaterializedViewPrivileges({
|
|
126
|
+
materializedView: mv,
|
|
127
|
+
grantee,
|
|
128
|
+
privileges,
|
|
129
|
+
columns: group.columns,
|
|
130
|
+
version: ctx.version,
|
|
131
|
+
}),
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Generate revoke changes
|
|
138
|
+
if (result.revokes.length > 0) {
|
|
139
|
+
const revokeGroups = groupPrivilegesByColumns(result.revokes);
|
|
140
|
+
for (const [, group] of revokeGroups) {
|
|
141
|
+
const allPrivileges = new Set<string>();
|
|
142
|
+
for (const [, privSet] of group.byGrant) {
|
|
143
|
+
for (const priv of privSet) {
|
|
144
|
+
allPrivileges.add(priv);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
const privileges = Array.from(allPrivileges).map((priv) => ({
|
|
148
|
+
privilege: priv,
|
|
149
|
+
grantable: false,
|
|
150
|
+
}));
|
|
151
|
+
changes.push(
|
|
152
|
+
new RevokeMaterializedViewPrivileges({
|
|
153
|
+
materializedView: mv,
|
|
154
|
+
grantee,
|
|
155
|
+
privileges,
|
|
156
|
+
columns: group.columns,
|
|
157
|
+
version: ctx.version,
|
|
158
|
+
}),
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Generate revoke grant option changes
|
|
164
|
+
if (result.revokeGrantOption.length > 0) {
|
|
165
|
+
const revokeGrantGroups = new Map<
|
|
166
|
+
string,
|
|
167
|
+
{ columns?: string[]; privileges: Set<string> }
|
|
168
|
+
>();
|
|
169
|
+
for (const r of result.revokeGrantOption) {
|
|
170
|
+
// For revoke grant option, we need to find the columns from the effective defaults
|
|
171
|
+
const originalPriv = effectiveDefaults.find(
|
|
172
|
+
(p) => p.grantee === grantee && p.privilege === r,
|
|
173
|
+
);
|
|
174
|
+
const key = originalPriv?.columns
|
|
175
|
+
? originalPriv.columns.sort().join(",")
|
|
176
|
+
: "";
|
|
177
|
+
if (!revokeGrantGroups.has(key)) {
|
|
178
|
+
revokeGrantGroups.set(key, {
|
|
179
|
+
columns: originalPriv?.columns
|
|
180
|
+
? [...originalPriv.columns]
|
|
181
|
+
: undefined,
|
|
182
|
+
privileges: new Set(),
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
const group = revokeGrantGroups.get(key);
|
|
186
|
+
if (!group) continue;
|
|
187
|
+
group.privileges.add(r);
|
|
188
|
+
}
|
|
189
|
+
for (const [, group] of revokeGrantGroups) {
|
|
190
|
+
const privilegeNames = Array.from(group.privileges);
|
|
191
|
+
changes.push(
|
|
192
|
+
new RevokeGrantOptionMaterializedViewPrivileges({
|
|
193
|
+
materializedView: mv,
|
|
194
|
+
grantee,
|
|
195
|
+
privilegeNames,
|
|
196
|
+
columns: group.columns,
|
|
197
|
+
version: ctx.version,
|
|
198
|
+
}),
|
|
199
|
+
);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
for (const materializedViewId of dropped) {
|
|
206
|
+
changes.push(
|
|
207
|
+
new DropMaterializedView({ materializedView: main[materializedViewId] }),
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
for (const materializedViewId of altered) {
|
|
212
|
+
const mainMaterializedView = main[materializedViewId];
|
|
213
|
+
const branchMaterializedView = branch[materializedViewId];
|
|
214
|
+
|
|
215
|
+
// Check if non-alterable properties have changed
|
|
216
|
+
// These require dropping and recreating the materialized view
|
|
217
|
+
const NON_ALTERABLE_FIELDS: Array<keyof MaterializedView> = [
|
|
218
|
+
"definition",
|
|
219
|
+
"row_security",
|
|
220
|
+
"force_row_security",
|
|
221
|
+
"has_indexes",
|
|
222
|
+
"has_rules",
|
|
223
|
+
"has_triggers",
|
|
224
|
+
"has_subclasses",
|
|
225
|
+
"is_populated",
|
|
226
|
+
"replica_identity",
|
|
227
|
+
"is_partition",
|
|
228
|
+
"partition_bound",
|
|
229
|
+
];
|
|
230
|
+
const nonAlterablePropsChanged = hasNonAlterableChanges(
|
|
231
|
+
mainMaterializedView,
|
|
232
|
+
branchMaterializedView,
|
|
233
|
+
NON_ALTERABLE_FIELDS,
|
|
234
|
+
{ options: deepEqual },
|
|
235
|
+
);
|
|
236
|
+
|
|
237
|
+
if (nonAlterablePropsChanged) {
|
|
238
|
+
// Replace the entire materialized view (drop + create)
|
|
239
|
+
changes.push(
|
|
240
|
+
new DropMaterializedView({ materializedView: mainMaterializedView }),
|
|
241
|
+
new CreateMaterializedView({
|
|
242
|
+
materializedView: branchMaterializedView,
|
|
243
|
+
}),
|
|
244
|
+
);
|
|
245
|
+
} else {
|
|
246
|
+
// Only alterable properties changed - check each one
|
|
247
|
+
|
|
248
|
+
// OWNER
|
|
249
|
+
if (mainMaterializedView.owner !== branchMaterializedView.owner) {
|
|
250
|
+
changes.push(
|
|
251
|
+
new AlterMaterializedViewChangeOwner({
|
|
252
|
+
materializedView: mainMaterializedView,
|
|
253
|
+
owner: branchMaterializedView.owner,
|
|
254
|
+
}),
|
|
255
|
+
);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// STORAGE PARAMETERS (reloptions)
|
|
259
|
+
// Emit a combined SET/RESET change similar to indexes
|
|
260
|
+
if (
|
|
261
|
+
!deepEqual(mainMaterializedView.options, branchMaterializedView.options)
|
|
262
|
+
) {
|
|
263
|
+
const parseOptions = (options: string[] | null | undefined) => {
|
|
264
|
+
const map = new Map<string, string>();
|
|
265
|
+
if (!options) return map;
|
|
266
|
+
for (const opt of options) {
|
|
267
|
+
const eqIndex = opt.indexOf("=");
|
|
268
|
+
const key = opt.slice(0, eqIndex).trim();
|
|
269
|
+
const value = opt.slice(eqIndex + 1).trim();
|
|
270
|
+
map.set(key, value);
|
|
271
|
+
}
|
|
272
|
+
return map;
|
|
273
|
+
};
|
|
274
|
+
const mainMap = parseOptions(mainMaterializedView.options);
|
|
275
|
+
const branchMap = parseOptions(branchMaterializedView.options);
|
|
276
|
+
const keysToReset: string[] = [];
|
|
277
|
+
for (const key of mainMap.keys()) {
|
|
278
|
+
if (!branchMap.has(key)) keysToReset.push(key);
|
|
279
|
+
}
|
|
280
|
+
const paramsToSet: string[] = [];
|
|
281
|
+
for (const [key, newValue] of branchMap.entries()) {
|
|
282
|
+
const oldValue = mainMap.get(key);
|
|
283
|
+
const changed = oldValue !== newValue;
|
|
284
|
+
if (changed) {
|
|
285
|
+
paramsToSet.push(
|
|
286
|
+
newValue === undefined ? key : `${key}=${newValue}`,
|
|
287
|
+
);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
changes.push(
|
|
291
|
+
new AlterMaterializedViewSetStorageParams({
|
|
292
|
+
materializedView: mainMaterializedView,
|
|
293
|
+
paramsToSet,
|
|
294
|
+
keysToReset,
|
|
295
|
+
}),
|
|
296
|
+
);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// Note: Materialized view renaming would also use ALTER MATERIALIZED VIEW ... RENAME TO ...
|
|
300
|
+
// But since our MaterializedView model uses 'name' as the identity field,
|
|
301
|
+
// a name change would be handled as drop + create by diffObjects()
|
|
302
|
+
// MATERIALIZED VIEW COMMENT (create/drop when comment changes)
|
|
303
|
+
if (mainMaterializedView.comment !== branchMaterializedView.comment) {
|
|
304
|
+
if (branchMaterializedView.comment === null) {
|
|
305
|
+
changes.push(
|
|
306
|
+
new DropCommentOnMaterializedView({
|
|
307
|
+
materializedView: mainMaterializedView,
|
|
308
|
+
}),
|
|
309
|
+
);
|
|
310
|
+
} else {
|
|
311
|
+
changes.push(
|
|
312
|
+
new CreateCommentOnMaterializedView({
|
|
313
|
+
materializedView: branchMaterializedView,
|
|
314
|
+
}),
|
|
315
|
+
);
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
// COMMENT changes on columns
|
|
319
|
+
const mainCols = new Map(
|
|
320
|
+
mainMaterializedView.columns.map((c) => [c.name, c]),
|
|
321
|
+
);
|
|
322
|
+
const branchCols = new Map(
|
|
323
|
+
branchMaterializedView.columns.map((c) => [c.name, c]),
|
|
324
|
+
);
|
|
325
|
+
for (const [name, branchCol] of branchCols) {
|
|
326
|
+
const mainCol = mainCols.get(name);
|
|
327
|
+
if (!mainCol) continue;
|
|
328
|
+
if (mainCol.comment !== branchCol.comment) {
|
|
329
|
+
if (branchCol.comment === null) {
|
|
330
|
+
changes.push(
|
|
331
|
+
new DropCommentOnMaterializedViewColumn({
|
|
332
|
+
materializedView: mainMaterializedView,
|
|
333
|
+
column: mainCol,
|
|
334
|
+
}),
|
|
335
|
+
);
|
|
336
|
+
} else {
|
|
337
|
+
changes.push(
|
|
338
|
+
new CreateCommentOnMaterializedViewColumn({
|
|
339
|
+
materializedView: branchMaterializedView,
|
|
340
|
+
column: branchCol,
|
|
341
|
+
}),
|
|
342
|
+
);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// PRIVILEGES (unified object and column privileges)
|
|
348
|
+
// Filter out owner privileges - owner always has ALL privileges implicitly
|
|
349
|
+
// and shouldn't be compared. Use branch owner as the reference.
|
|
350
|
+
const privilegeResults = diffPrivileges(
|
|
351
|
+
mainMaterializedView.privileges,
|
|
352
|
+
branchMaterializedView.privileges,
|
|
353
|
+
branchMaterializedView.owner,
|
|
354
|
+
ctx.mainRoles,
|
|
355
|
+
);
|
|
356
|
+
|
|
357
|
+
for (const [grantee, result] of privilegeResults) {
|
|
358
|
+
// Generate grant changes
|
|
359
|
+
if (result.grants.length > 0) {
|
|
360
|
+
const grantGroups = groupPrivilegesByColumns(result.grants);
|
|
361
|
+
for (const [, group] of grantGroups) {
|
|
362
|
+
for (const [grantable, privSet] of group.byGrant) {
|
|
363
|
+
const privileges = Array.from(privSet).map((priv) => ({
|
|
364
|
+
privilege: priv,
|
|
365
|
+
grantable,
|
|
366
|
+
}));
|
|
367
|
+
changes.push(
|
|
368
|
+
new GrantMaterializedViewPrivileges({
|
|
369
|
+
materializedView: branchMaterializedView,
|
|
370
|
+
grantee,
|
|
371
|
+
privileges,
|
|
372
|
+
columns: group.columns,
|
|
373
|
+
version: ctx.version,
|
|
374
|
+
}),
|
|
375
|
+
);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
// Generate revoke changes
|
|
381
|
+
if (result.revokes.length > 0) {
|
|
382
|
+
const revokeGroups = groupPrivilegesByColumns(result.revokes);
|
|
383
|
+
for (const [, group] of revokeGroups) {
|
|
384
|
+
// Collapse all grantable groups into a single revoke (grantable: false)
|
|
385
|
+
const allPrivileges = new Set<string>();
|
|
386
|
+
for (const [, privSet] of group.byGrant) {
|
|
387
|
+
for (const priv of privSet) {
|
|
388
|
+
allPrivileges.add(priv);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
const privileges = Array.from(allPrivileges).map((priv) => ({
|
|
392
|
+
privilege: priv,
|
|
393
|
+
grantable: false,
|
|
394
|
+
}));
|
|
395
|
+
changes.push(
|
|
396
|
+
new RevokeMaterializedViewPrivileges({
|
|
397
|
+
materializedView: mainMaterializedView,
|
|
398
|
+
grantee,
|
|
399
|
+
privileges,
|
|
400
|
+
columns: group.columns,
|
|
401
|
+
version: ctx.version,
|
|
402
|
+
}),
|
|
403
|
+
);
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
// Generate revoke grant option changes
|
|
408
|
+
if (result.revokeGrantOption.length > 0) {
|
|
409
|
+
const revokeGrantGroups = new Map<
|
|
410
|
+
string,
|
|
411
|
+
{ columns?: string[]; privileges: Set<string> }
|
|
412
|
+
>();
|
|
413
|
+
for (const r of result.revokeGrantOption) {
|
|
414
|
+
// For revoke grant option, we need to find the columns from the original privilege
|
|
415
|
+
const originalPriv = mainMaterializedView.privileges.find(
|
|
416
|
+
(p) => p.grantee === grantee && p.privilege === r,
|
|
417
|
+
);
|
|
418
|
+
const key = originalPriv?.columns
|
|
419
|
+
? originalPriv.columns.sort().join(",")
|
|
420
|
+
: "";
|
|
421
|
+
if (!revokeGrantGroups.has(key)) {
|
|
422
|
+
revokeGrantGroups.set(key, {
|
|
423
|
+
columns: originalPriv?.columns
|
|
424
|
+
? [...originalPriv.columns]
|
|
425
|
+
: undefined,
|
|
426
|
+
privileges: new Set(),
|
|
427
|
+
});
|
|
428
|
+
}
|
|
429
|
+
const group = revokeGrantGroups.get(key);
|
|
430
|
+
if (!group) continue;
|
|
431
|
+
group.privileges.add(r);
|
|
432
|
+
}
|
|
433
|
+
for (const [, group] of revokeGrantGroups) {
|
|
434
|
+
const privilegeNames = Array.from(group.privileges);
|
|
435
|
+
changes.push(
|
|
436
|
+
new RevokeGrantOptionMaterializedViewPrivileges({
|
|
437
|
+
materializedView: mainMaterializedView,
|
|
438
|
+
grantee,
|
|
439
|
+
privilegeNames,
|
|
440
|
+
columns: group.columns,
|
|
441
|
+
version: ctx.version,
|
|
442
|
+
}),
|
|
443
|
+
);
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
return changes;
|
|
451
|
+
}
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
import { sql } from "@ts-safeql/sql-tag";
|
|
2
|
+
import type { Pool } from "pg";
|
|
3
|
+
import z from "zod";
|
|
4
|
+
import {
|
|
5
|
+
BasePgModel,
|
|
6
|
+
columnPropsSchema,
|
|
7
|
+
type TableLikeObject,
|
|
8
|
+
} from "../base.model.ts";
|
|
9
|
+
import {
|
|
10
|
+
type PrivilegeProps,
|
|
11
|
+
privilegePropsSchema,
|
|
12
|
+
} from "../base.privilege-diff.ts";
|
|
13
|
+
import { ReplicaIdentitySchema } from "../table/table.model.ts";
|
|
14
|
+
|
|
15
|
+
const materializedViewPropsSchema = z.object({
|
|
16
|
+
schema: z.string(),
|
|
17
|
+
name: z.string(),
|
|
18
|
+
definition: z.string(),
|
|
19
|
+
row_security: z.boolean(),
|
|
20
|
+
force_row_security: z.boolean(),
|
|
21
|
+
has_indexes: z.boolean(),
|
|
22
|
+
has_rules: z.boolean(),
|
|
23
|
+
has_triggers: z.boolean(),
|
|
24
|
+
has_subclasses: z.boolean(),
|
|
25
|
+
is_populated: z.boolean(),
|
|
26
|
+
replica_identity: ReplicaIdentitySchema,
|
|
27
|
+
is_partition: z.boolean(),
|
|
28
|
+
options: z.array(z.string()).nullable(),
|
|
29
|
+
partition_bound: z.string().nullable(),
|
|
30
|
+
owner: z.string(),
|
|
31
|
+
comment: z.string().nullable(),
|
|
32
|
+
columns: z.array(columnPropsSchema),
|
|
33
|
+
privileges: z.array(privilegePropsSchema),
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
type MaterializedViewPrivilegeProps = PrivilegeProps;
|
|
37
|
+
export type MaterializedViewProps = z.infer<typeof materializedViewPropsSchema>;
|
|
38
|
+
|
|
39
|
+
export class MaterializedView extends BasePgModel implements TableLikeObject {
|
|
40
|
+
public readonly schema: MaterializedViewProps["schema"];
|
|
41
|
+
public readonly name: MaterializedViewProps["name"];
|
|
42
|
+
public readonly definition: MaterializedViewProps["definition"];
|
|
43
|
+
public readonly row_security: MaterializedViewProps["row_security"];
|
|
44
|
+
public readonly force_row_security: MaterializedViewProps["force_row_security"];
|
|
45
|
+
public readonly has_indexes: MaterializedViewProps["has_indexes"];
|
|
46
|
+
public readonly has_rules: MaterializedViewProps["has_rules"];
|
|
47
|
+
public readonly has_triggers: MaterializedViewProps["has_triggers"];
|
|
48
|
+
public readonly has_subclasses: MaterializedViewProps["has_subclasses"];
|
|
49
|
+
public readonly is_populated: MaterializedViewProps["is_populated"];
|
|
50
|
+
public readonly replica_identity: MaterializedViewProps["replica_identity"];
|
|
51
|
+
public readonly is_partition: MaterializedViewProps["is_partition"];
|
|
52
|
+
public readonly options: MaterializedViewProps["options"];
|
|
53
|
+
public readonly partition_bound: MaterializedViewProps["partition_bound"];
|
|
54
|
+
public readonly owner: MaterializedViewProps["owner"];
|
|
55
|
+
public readonly comment: MaterializedViewProps["comment"];
|
|
56
|
+
public readonly columns: MaterializedViewProps["columns"];
|
|
57
|
+
public readonly privileges: MaterializedViewPrivilegeProps[];
|
|
58
|
+
|
|
59
|
+
constructor(props: MaterializedViewProps) {
|
|
60
|
+
super();
|
|
61
|
+
|
|
62
|
+
// Identity fields
|
|
63
|
+
this.schema = props.schema;
|
|
64
|
+
this.name = props.name;
|
|
65
|
+
|
|
66
|
+
// Data fields
|
|
67
|
+
this.definition = props.definition;
|
|
68
|
+
this.row_security = props.row_security;
|
|
69
|
+
this.force_row_security = props.force_row_security;
|
|
70
|
+
this.has_indexes = props.has_indexes;
|
|
71
|
+
this.has_rules = props.has_rules;
|
|
72
|
+
this.has_triggers = props.has_triggers;
|
|
73
|
+
this.has_subclasses = props.has_subclasses;
|
|
74
|
+
this.is_populated = props.is_populated;
|
|
75
|
+
this.replica_identity = props.replica_identity;
|
|
76
|
+
this.is_partition = props.is_partition;
|
|
77
|
+
this.options = props.options;
|
|
78
|
+
this.partition_bound = props.partition_bound;
|
|
79
|
+
this.owner = props.owner;
|
|
80
|
+
this.comment = props.comment;
|
|
81
|
+
this.columns = props.columns;
|
|
82
|
+
this.privileges = props.privileges;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
get stableId(): `materializedView:${string}` {
|
|
86
|
+
return `materializedView:${this.schema}.${this.name}`;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
get identityFields() {
|
|
90
|
+
return {
|
|
91
|
+
schema: this.schema,
|
|
92
|
+
name: this.name,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
get dataFields() {
|
|
97
|
+
return {
|
|
98
|
+
definition: this.definition,
|
|
99
|
+
row_security: this.row_security,
|
|
100
|
+
force_row_security: this.force_row_security,
|
|
101
|
+
has_indexes: this.has_indexes,
|
|
102
|
+
has_rules: this.has_rules,
|
|
103
|
+
has_triggers: this.has_triggers,
|
|
104
|
+
has_subclasses: this.has_subclasses,
|
|
105
|
+
is_populated: this.is_populated,
|
|
106
|
+
replica_identity: this.replica_identity,
|
|
107
|
+
is_partition: this.is_partition,
|
|
108
|
+
options: this.options,
|
|
109
|
+
partition_bound: this.partition_bound,
|
|
110
|
+
owner: this.owner,
|
|
111
|
+
comment: this.comment,
|
|
112
|
+
columns: this.columns,
|
|
113
|
+
privileges: this.privileges,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
override stableSnapshot() {
|
|
118
|
+
const normalizeColumns = () =>
|
|
119
|
+
[...this.columns]
|
|
120
|
+
.map((col) => {
|
|
121
|
+
const { position: _pos, ...rest } = col as unknown as Record<
|
|
122
|
+
string,
|
|
123
|
+
unknown
|
|
124
|
+
>;
|
|
125
|
+
return rest;
|
|
126
|
+
})
|
|
127
|
+
.sort((a, b) => {
|
|
128
|
+
const nameA = (a.name as string | undefined) ?? "";
|
|
129
|
+
const nameB = (b.name as string | undefined) ?? "";
|
|
130
|
+
return nameA.localeCompare(nameB);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
return {
|
|
134
|
+
identity: this.identityFields,
|
|
135
|
+
data: {
|
|
136
|
+
...this.dataFields,
|
|
137
|
+
columns: normalizeColumns(),
|
|
138
|
+
},
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export async function extractMaterializedViews(
|
|
144
|
+
pool: Pool,
|
|
145
|
+
): Promise<MaterializedView[]> {
|
|
146
|
+
const { rows: mvRows } = await pool.query<MaterializedViewProps>(sql`
|
|
147
|
+
with extension_oids as (
|
|
148
|
+
select
|
|
149
|
+
objid
|
|
150
|
+
from
|
|
151
|
+
pg_depend d
|
|
152
|
+
where
|
|
153
|
+
d.refclassid = 'pg_extension'::regclass
|
|
154
|
+
and d.classid = 'pg_class'::regclass
|
|
155
|
+
)
|
|
156
|
+
select
|
|
157
|
+
c.relnamespace::regnamespace::text as schema,
|
|
158
|
+
quote_ident(c.relname) as name,
|
|
159
|
+
-- remove trailing semicolon from the definition if present
|
|
160
|
+
rtrim(pg_get_viewdef(c.oid), ';') as definition,
|
|
161
|
+
c.relrowsecurity as row_security,
|
|
162
|
+
c.relforcerowsecurity as force_row_security,
|
|
163
|
+
c.relhasindex as has_indexes,
|
|
164
|
+
c.relhasrules as has_rules,
|
|
165
|
+
c.relhastriggers as has_triggers,
|
|
166
|
+
c.relhassubclass as has_subclasses,
|
|
167
|
+
c.relispopulated as is_populated,
|
|
168
|
+
c.relreplident as replica_identity,
|
|
169
|
+
c.relispartition as is_partition,
|
|
170
|
+
c.reloptions as options,
|
|
171
|
+
pg_get_expr(c.relpartbound, c.oid) as partition_bound,
|
|
172
|
+
c.relowner::regrole::text as owner,
|
|
173
|
+
obj_description(c.oid, 'pg_class') as comment,
|
|
174
|
+
coalesce(json_agg(
|
|
175
|
+
case when a.attname is not null then
|
|
176
|
+
json_build_object(
|
|
177
|
+
'name', quote_ident(a.attname),
|
|
178
|
+
'position', a.attnum,
|
|
179
|
+
'data_type', a.atttypid::regtype::text,
|
|
180
|
+
'data_type_str', format_type(a.atttypid, a.atttypmod),
|
|
181
|
+
'is_custom_type', ty.typnamespace::regnamespace::text not in ('pg_catalog', 'information_schema'),
|
|
182
|
+
'custom_type_type', case when ty.typnamespace::regnamespace::text not in ('pg_catalog', 'information_schema') then ty.typtype else null end,
|
|
183
|
+
'custom_type_category', case when ty.typnamespace::regnamespace::text not in ('pg_catalog', 'information_schema') then ty.typcategory else null end,
|
|
184
|
+
'custom_type_schema', case when ty.typnamespace::regnamespace::text not in ('pg_catalog', 'information_schema') then ty.typnamespace::regnamespace else null end,
|
|
185
|
+
'custom_type_name', case when ty.typnamespace::regnamespace::text not in ('pg_catalog', 'information_schema') then quote_ident(ty.typname) else null end,
|
|
186
|
+
'not_null', a.attnotnull,
|
|
187
|
+
'is_identity', a.attidentity != '',
|
|
188
|
+
'is_identity_always', a.attidentity = 'a',
|
|
189
|
+
'is_generated', a.attgenerated != '',
|
|
190
|
+
'collation', (
|
|
191
|
+
select quote_ident(c2.collname)
|
|
192
|
+
from pg_collation c2, pg_type t2
|
|
193
|
+
where c2.oid = a.attcollation
|
|
194
|
+
and t2.oid = a.atttypid
|
|
195
|
+
and a.attcollation <> t2.typcollation
|
|
196
|
+
),
|
|
197
|
+
'default', pg_get_expr(ad.adbin, ad.adrelid),
|
|
198
|
+
'comment', col_description(a.attrelid, a.attnum)
|
|
199
|
+
)
|
|
200
|
+
end
|
|
201
|
+
order by a.attnum
|
|
202
|
+
) filter (where a.attname is not null), '[]') as columns,
|
|
203
|
+
coalesce((
|
|
204
|
+
select json_agg(
|
|
205
|
+
json_build_object(
|
|
206
|
+
'grantee', case when grp.grantee = 0 then 'PUBLIC' else grp.grantee::regrole::text end,
|
|
207
|
+
'privilege', grp.privilege_type,
|
|
208
|
+
'grantable', grp.is_grantable,
|
|
209
|
+
'columns', case when grp.cols is not null and array_length(grp.cols,1) > 0
|
|
210
|
+
then grp.cols
|
|
211
|
+
else null end
|
|
212
|
+
)
|
|
213
|
+
order by grp.grantee, grp.privilege_type
|
|
214
|
+
)
|
|
215
|
+
from (
|
|
216
|
+
select
|
|
217
|
+
x.grantee,
|
|
218
|
+
x.privilege_type,
|
|
219
|
+
bool_or(x.is_grantable) as is_grantable,
|
|
220
|
+
array_agg(quote_ident(src.attname) order by src.attname)
|
|
221
|
+
filter (where src.attname is not null) as cols
|
|
222
|
+
from (
|
|
223
|
+
-- one row for object ACL + one row per column ACL
|
|
224
|
+
select null::name as attname, c.relacl as acl
|
|
225
|
+
union all
|
|
226
|
+
select a2.attname, a2.attacl
|
|
227
|
+
from pg_attribute a2
|
|
228
|
+
where a2.attrelid = c.oid
|
|
229
|
+
and a2.attnum > 0
|
|
230
|
+
and not a2.attisdropped
|
|
231
|
+
and a2.attacl is not null
|
|
232
|
+
) as src
|
|
233
|
+
join lateral aclexplode(src.acl) as x(grantor, grantee, privilege_type, is_grantable) on true
|
|
234
|
+
group by x.grantee, x.privilege_type
|
|
235
|
+
) as grp
|
|
236
|
+
), '[]') as privileges
|
|
237
|
+
from
|
|
238
|
+
pg_catalog.pg_class c
|
|
239
|
+
left outer join extension_oids e on c.oid = e.objid
|
|
240
|
+
left join pg_attribute a on a.attrelid = c.oid and a.attnum > 0 and not a.attisdropped
|
|
241
|
+
left join pg_attrdef ad on a.attrelid = ad.adrelid and a.attnum = ad.adnum
|
|
242
|
+
left join pg_type ty on ty.oid = a.atttypid
|
|
243
|
+
where not c.relnamespace::regnamespace::text like any(array['pg\\_%', 'information\\_schema'])
|
|
244
|
+
and e.objid is null
|
|
245
|
+
and c.relkind = 'm'
|
|
246
|
+
group by
|
|
247
|
+
c.oid, c.relnamespace, c.relname, pg_get_viewdef(c.oid), c.relrowsecurity, c.relforcerowsecurity, c.relhasindex, c.relhasrules, c.relhastriggers, c.relhassubclass, c.relispopulated, c.relreplident, c.relispartition, c.reloptions, pg_get_expr(c.relpartbound, c.oid), c.relowner
|
|
248
|
+
order by
|
|
249
|
+
c.relnamespace::regnamespace, c.relname
|
|
250
|
+
`);
|
|
251
|
+
// Validate and parse each row using the Zod schema
|
|
252
|
+
const validatedRows = mvRows.map((row: unknown) =>
|
|
253
|
+
materializedViewPropsSchema.parse(row),
|
|
254
|
+
);
|
|
255
|
+
return validatedRows.map(
|
|
256
|
+
(row: MaterializedViewProps) => new MaterializedView(row),
|
|
257
|
+
);
|
|
258
|
+
}
|