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