@supabase/pg-delta 1.0.0-alpha.4 → 1.0.0-alpha.6
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 +40 -23
- package/dist/cli/app.js +26 -3
- package/dist/cli/bin/cli.js +5 -0
- package/dist/cli/commands/catalog-export.d.ts +5 -0
- package/dist/cli/commands/catalog-export.js +64 -0
- package/dist/cli/commands/declarative-apply.d.ts +6 -0
- package/dist/cli/commands/declarative-apply.js +288 -0
- package/dist/cli/commands/declarative-export.d.ts +5 -0
- package/dist/cli/commands/declarative-export.js +245 -0
- package/dist/cli/commands/plan.js +19 -6
- package/dist/cli/exit-code.d.ts +2 -0
- package/dist/cli/exit-code.js +7 -0
- package/dist/cli/formatters/tree/tree.js +3 -2
- package/dist/cli/utils/apply-display.d.ts +52 -0
- package/dist/cli/utils/apply-display.js +183 -0
- package/dist/cli/utils/export-display.d.ts +43 -0
- package/dist/cli/utils/export-display.js +202 -0
- package/dist/cli/utils/resolve-input.d.ts +7 -0
- package/dist/cli/utils/resolve-input.js +13 -0
- package/dist/core/catalog-export/index.d.ts +11 -0
- package/dist/core/catalog-export/index.js +10 -0
- package/dist/core/catalog.diff.d.ts +1 -0
- package/dist/core/catalog.diff.js +64 -48
- package/dist/core/catalog.model.d.ts +14 -1
- package/dist/core/catalog.model.js +103 -1
- package/dist/core/catalog.snapshot.d.ts +66 -0
- package/dist/core/catalog.snapshot.js +206 -0
- package/dist/core/declarative-apply/discover-sql.d.ts +18 -0
- package/dist/core/declarative-apply/discover-sql.js +86 -0
- package/dist/core/declarative-apply/extract-catalog-providers.d.ts +23 -0
- package/dist/core/declarative-apply/extract-catalog-providers.js +159 -0
- package/dist/core/declarative-apply/index.d.ts +49 -0
- package/dist/core/declarative-apply/index.js +134 -0
- package/dist/core/declarative-apply/round-apply.d.ts +100 -0
- package/dist/core/declarative-apply/round-apply.js +378 -0
- package/dist/core/export/file-mapper.d.ts +71 -0
- package/dist/core/export/file-mapper.js +474 -0
- package/dist/core/export/grouper.d.ts +13 -0
- package/dist/core/export/grouper.js +76 -0
- package/dist/core/export/index.d.ts +45 -0
- package/dist/core/export/index.js +63 -0
- package/dist/core/export/types.d.ts +84 -0
- package/dist/core/export/types.js +25 -0
- package/dist/core/fixtures/empty-catalogs/postgres-15-16-baseline.json +287 -0
- package/dist/core/integrations/filter/dsl.d.ts +38 -1
- package/dist/core/integrations/filter/dsl.js +20 -2
- package/dist/core/integrations/filter/extractors.js +42 -0
- package/dist/core/integrations/integration-dsl.d.ts +10 -0
- package/dist/core/integrations/supabase.d.ts +8 -0
- package/dist/core/integrations/supabase.js +9 -0
- package/dist/core/objects/aggregate/aggregate.diff.d.ts +2 -8
- package/dist/core/objects/aggregate/aggregate.diff.js +16 -70
- package/dist/core/objects/aggregate/aggregate.model.d.ts +8 -8
- package/dist/core/objects/aggregate/aggregate.model.js +1 -1
- package/dist/core/objects/aggregate/changes/aggregate.create.js +1 -1
- package/dist/core/objects/aggregate/changes/aggregate.drop.js +1 -1
- package/dist/core/objects/base.privilege-diff.d.ts +38 -13
- package/dist/core/objects/base.privilege-diff.js +104 -22
- package/dist/core/objects/base.privilege.d.ts +1 -0
- package/dist/core/objects/base.privilege.js +9 -2
- package/dist/core/objects/collation/collation.diff.d.ts +2 -3
- package/dist/core/objects/diff-context.d.ts +15 -0
- package/dist/core/objects/diff-context.js +1 -0
- package/dist/core/objects/domain/changes/domain.create.js +4 -2
- package/dist/core/objects/domain/domain.diff.d.ts +2 -8
- package/dist/core/objects/domain/domain.diff.js +16 -77
- package/dist/core/objects/domain/domain.model.js +1 -1
- package/dist/core/objects/event-trigger/event-trigger.diff.d.ts +2 -3
- package/dist/core/objects/foreign-data-wrapper/foreign-data-wrapper/foreign-data-wrapper.diff.d.ts +2 -8
- package/dist/core/objects/foreign-data-wrapper/foreign-data-wrapper/foreign-data-wrapper.diff.js +13 -77
- package/dist/core/objects/foreign-data-wrapper/foreign-data-wrapper/foreign-data-wrapper.model.js +2 -2
- package/dist/core/objects/foreign-data-wrapper/foreign-table/foreign-table.diff.d.ts +2 -8
- package/dist/core/objects/foreign-data-wrapper/foreign-table/foreign-table.diff.js +16 -77
- package/dist/core/objects/foreign-data-wrapper/foreign-table/foreign-table.model.js +1 -1
- package/dist/core/objects/foreign-data-wrapper/server/server.diff.d.ts +2 -8
- package/dist/core/objects/foreign-data-wrapper/server/server.diff.js +13 -77
- package/dist/core/objects/language/language.diff.d.ts +2 -5
- package/dist/core/objects/language/language.diff.js +7 -39
- package/dist/core/objects/materialized-view/materialized-view.diff.d.ts +2 -8
- package/dist/core/objects/materialized-view/materialized-view.diff.js +16 -158
- package/dist/core/objects/materialized-view/materialized-view.model.d.ts +3 -3
- package/dist/core/objects/materialized-view/materialized-view.model.js +1 -1
- package/dist/core/objects/procedure/changes/procedure.alter.js +12 -12
- package/dist/core/objects/procedure/procedure.diff.d.ts +2 -8
- package/dist/core/objects/procedure/procedure.diff.js +16 -77
- package/dist/core/objects/procedure/procedure.model.d.ts +9 -9
- package/dist/core/objects/procedure/procedure.model.js +1 -1
- package/dist/core/objects/publication/changes/publication.alter.d.ts +0 -9
- package/dist/core/objects/publication/changes/publication.alter.js +0 -14
- package/dist/core/objects/publication/changes/publication.types.d.ts +2 -2
- package/dist/core/objects/publication/publication.diff.d.ts +2 -3
- package/dist/core/objects/publication/publication.diff.js +8 -13
- package/dist/core/objects/rls-policy/changes/rls-policy.alter.js +3 -3
- package/dist/core/objects/rls-policy/rls-policy.model.d.ts +2 -2
- package/dist/core/objects/role/role.diff.js +22 -1
- package/dist/core/objects/role/role.model.d.ts +4 -3
- package/dist/core/objects/role/role.model.js +118 -12
- package/dist/core/objects/rule/rule.model.d.ts +1 -1
- package/dist/core/objects/schema/schema.diff.d.ts +2 -8
- package/dist/core/objects/schema/schema.diff.js +16 -77
- package/dist/core/objects/schema/schema.model.js +1 -1
- package/dist/core/objects/sequence/sequence.diff.d.ts +2 -8
- package/dist/core/objects/sequence/sequence.diff.js +16 -79
- package/dist/core/objects/sequence/sequence.model.js +1 -1
- package/dist/core/objects/subscription/subscription.diff.d.ts +2 -3
- package/dist/core/objects/table/changes/table.create.js +3 -0
- package/dist/core/objects/table/table.diff.d.ts +2 -8
- package/dist/core/objects/table/table.diff.js +26 -157
- package/dist/core/objects/table/table.model.d.ts +23 -22
- package/dist/core/objects/table/table.model.js +1 -1
- package/dist/core/objects/trigger/changes/trigger.create.js +2 -4
- package/dist/core/objects/trigger/trigger.model.d.ts +8 -0
- package/dist/core/objects/trigger/trigger.model.js +11 -0
- package/dist/core/objects/type/composite-type/composite-type.diff.d.ts +2 -8
- package/dist/core/objects/type/composite-type/composite-type.diff.js +16 -77
- package/dist/core/objects/type/composite-type/composite-type.model.d.ts +3 -3
- package/dist/core/objects/type/composite-type/composite-type.model.js +2 -1
- package/dist/core/objects/type/enum/enum.diff.d.ts +2 -8
- package/dist/core/objects/type/enum/enum.diff.js +25 -112
- package/dist/core/objects/type/enum/enum.model.js +1 -1
- package/dist/core/objects/type/range/changes/range.create.js +6 -3
- package/dist/core/objects/type/range/range.diff.d.ts +2 -8
- package/dist/core/objects/type/range/range.diff.js +16 -77
- package/dist/core/objects/type/range/range.model.js +1 -1
- package/dist/core/objects/view/view.diff.d.ts +2 -8
- package/dist/core/objects/view/view.diff.js +16 -158
- package/dist/core/objects/view/view.model.d.ts +18 -4
- package/dist/core/objects/view/view.model.js +3 -13
- package/dist/core/plan/apply.js +9 -26
- package/dist/core/plan/create.d.ts +19 -6
- package/dist/core/plan/create.js +134 -174
- package/dist/core/plan/serialize.js +16 -4
- package/dist/core/plan/sql-format/fixtures.js +3 -5
- package/dist/core/plan/sql-format/keyword-case.js +26 -1
- package/dist/core/plan/ssl-config.d.ts +32 -0
- package/dist/core/plan/ssl-config.js +115 -0
- package/dist/core/plan/types.d.ts +6 -0
- package/dist/core/postgres-config.d.ts +14 -0
- package/dist/core/postgres-config.js +53 -2
- package/dist/core/sort/graph-builder.js +10 -0
- package/dist/core/sort/logical-sort.js +31 -23
- package/dist/core/test-utils/assert-valid-sql.d.ts +10 -0
- package/dist/core/test-utils/assert-valid-sql.js +19 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +6 -1
- package/package.json +21 -4
- package/src/cli/app.ts +27 -3
- package/src/cli/bin/cli.ts +6 -0
- package/src/cli/commands/catalog-export.ts +78 -0
- package/src/cli/commands/declarative-apply.diagnostics.test.ts +77 -0
- package/src/cli/commands/declarative-apply.ts +380 -0
- package/src/cli/commands/declarative-export.ts +330 -0
- package/src/cli/commands/plan.ts +28 -7
- package/src/cli/exit-code.test.ts +19 -0
- package/src/cli/exit-code.ts +7 -0
- package/src/cli/formatters/tree/tree.ts +3 -2
- package/src/cli/utils/apply-display.test.ts +348 -0
- package/src/cli/utils/apply-display.ts +238 -0
- package/src/cli/utils/export-display.test.ts +103 -0
- package/src/cli/utils/export-display.ts +275 -0
- package/src/cli/utils/integrations.test.ts +44 -0
- package/src/cli/utils/resolve-input.test.ts +38 -0
- package/src/cli/utils/resolve-input.ts +17 -0
- package/src/core/catalog-export/index.ts +20 -0
- package/src/core/catalog.diff.ts +79 -78
- package/src/core/catalog.model.test.ts +122 -0
- package/src/core/catalog.model.ts +127 -1
- package/src/core/catalog.snapshot.test.ts +464 -0
- package/src/core/catalog.snapshot.ts +289 -0
- package/src/core/declarative-apply/discover-sql.test.ts +103 -0
- package/src/core/declarative-apply/discover-sql.ts +107 -0
- package/src/core/declarative-apply/extract-catalog-providers.ts +220 -0
- package/src/core/declarative-apply/index.test.ts +67 -0
- package/src/core/declarative-apply/index.ts +205 -0
- package/src/core/declarative-apply/round-apply.test.ts +504 -0
- package/src/core/declarative-apply/round-apply.ts +562 -0
- package/src/core/expand-replace-dependencies.test.ts +70 -0
- package/src/core/export/file-mapper.test.ts +816 -0
- package/src/core/export/file-mapper.ts +574 -0
- package/src/core/export/grouper.ts +108 -0
- package/src/core/export/index.ts +129 -0
- package/src/core/export/types.ts +104 -0
- package/src/core/fixtures/empty-catalogs/postgres-15-16-baseline.json +287 -0
- package/src/core/integrations/filter/dsl.test.ts +211 -0
- package/src/core/integrations/filter/dsl.ts +65 -3
- package/src/core/integrations/filter/extractors.test.ts +244 -0
- package/src/core/integrations/filter/extractors.ts +42 -0
- package/src/core/integrations/integration-dsl.ts +10 -0
- package/src/core/integrations/serialize/dsl.test.ts +91 -0
- package/src/core/integrations/supabase.ts +9 -0
- package/src/core/objects/aggregate/aggregate.diff.ts +39 -95
- package/src/core/objects/aggregate/aggregate.model.ts +1 -1
- package/src/core/objects/aggregate/changes/aggregate.alter.test.ts +3 -1
- package/src/core/objects/aggregate/changes/aggregate.comment.test.ts +5 -2
- package/src/core/objects/aggregate/changes/aggregate.create.test.ts +6 -3
- package/src/core/objects/aggregate/changes/aggregate.create.ts +1 -1
- package/src/core/objects/aggregate/changes/aggregate.drop.test.ts +7 -3
- package/src/core/objects/aggregate/changes/aggregate.drop.ts +1 -1
- package/src/core/objects/aggregate/changes/aggregate.privilege.test.ts +9 -3
- package/src/core/objects/base.privilege-diff.ts +178 -30
- package/src/core/objects/base.privilege.ts +9 -2
- package/src/core/objects/collation/changes/collation.alter.test.ts +7 -2
- package/src/core/objects/collation/changes/collation.create.test.ts +7 -2
- package/src/core/objects/collation/changes/collation.drop.test.ts +4 -1
- package/src/core/objects/collation/collation.diff.test.ts +9 -12
- package/src/core/objects/collation/collation.diff.ts +2 -1
- package/src/core/objects/diff-context.ts +16 -0
- package/src/core/objects/domain/changes/domain.alter.test.ts +28 -9
- package/src/core/objects/domain/changes/domain.create.test.ts +32 -2
- package/src/core/objects/domain/changes/domain.create.ts +7 -1
- package/src/core/objects/domain/changes/domain.drop.test.ts +4 -1
- package/src/core/objects/domain/domain.diff.ts +39 -102
- package/src/core/objects/domain/domain.model.ts +1 -1
- package/src/core/objects/event-trigger/changes/event-trigger.alter.test.ts +10 -3
- package/src/core/objects/event-trigger/changes/event-trigger.create.test.ts +4 -1
- package/src/core/objects/event-trigger/changes/event-trigger.drop.test.ts +4 -1
- package/src/core/objects/event-trigger/event-trigger.diff.test.ts +12 -7
- package/src/core/objects/event-trigger/event-trigger.diff.ts +2 -1
- package/src/core/objects/extension/changes/extension.alter.test.ts +7 -2
- package/src/core/objects/extension/changes/extension.create.test.ts +4 -1
- package/src/core/objects/extension/changes/extension.drop.test.ts +4 -1
- package/src/core/objects/extension/extension.model.test.ts +98 -0
- package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.alter.test.ts +16 -5
- package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.create.test.ts +51 -16
- package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.drop.test.ts +4 -1
- package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/foreign-data-wrapper.diff.test.ts +111 -4
- package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/foreign-data-wrapper.diff.ts +31 -101
- package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/foreign-data-wrapper.model.ts +2 -2
- package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.alter.test.ts +46 -15
- package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.create.test.ts +13 -4
- package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.drop.test.ts +4 -1
- package/src/core/objects/foreign-data-wrapper/foreign-table/foreign-table.diff.ts +39 -102
- package/src/core/objects/foreign-data-wrapper/foreign-table/foreign-table.model.ts +1 -1
- package/src/core/objects/foreign-data-wrapper/server/changes/server.alter.test.ts +22 -7
- package/src/core/objects/foreign-data-wrapper/server/changes/server.create.test.ts +19 -6
- package/src/core/objects/foreign-data-wrapper/server/changes/server.drop.test.ts +4 -1
- package/src/core/objects/foreign-data-wrapper/server/server.diff.test.ts +95 -0
- package/src/core/objects/foreign-data-wrapper/server/server.diff.ts +31 -101
- package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.alter.test.ts +13 -4
- package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.create.test.ts +16 -5
- package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.drop.test.ts +10 -3
- package/src/core/objects/index/changes/index.alter.test.ts +13 -4
- package/src/core/objects/index/changes/index.create.test.ts +4 -1
- package/src/core/objects/index/changes/index.drop.test.ts +4 -1
- package/src/core/objects/language/changes/language.alter.test.ts +4 -1
- package/src/core/objects/language/changes/language.create.test.ts +4 -1
- package/src/core/objects/language/changes/language.drop.test.ts +4 -1
- package/src/core/objects/language/language.diff.test.ts +86 -4
- package/src/core/objects/language/language.diff.ts +17 -49
- package/src/core/objects/materialized-view/changes/materialized-view.alter.test.ts +10 -3
- package/src/core/objects/materialized-view/changes/materialized-view.create.test.ts +7 -2
- package/src/core/objects/materialized-view/changes/materialized-view.drop.test.ts +4 -1
- package/src/core/objects/materialized-view/materialized-view.diff.test.ts +162 -0
- package/src/core/objects/materialized-view/materialized-view.diff.ts +41 -191
- package/src/core/objects/materialized-view/materialized-view.model.ts +1 -1
- package/src/core/objects/procedure/changes/procedure.alter.test.ts +121 -49
- package/src/core/objects/procedure/changes/procedure.alter.ts +15 -12
- package/src/core/objects/procedure/changes/procedure.create.test.ts +4 -1
- package/src/core/objects/procedure/changes/procedure.drop.test.ts +7 -2
- package/src/core/objects/procedure/procedure.diff.ts +39 -102
- package/src/core/objects/procedure/procedure.model.ts +1 -1
- package/src/core/objects/publication/changes/publication.alter.test.ts +15 -21
- package/src/core/objects/publication/changes/publication.alter.ts +0 -18
- package/src/core/objects/publication/changes/publication.comment.test.ts +5 -2
- package/src/core/objects/publication/changes/publication.create.test.ts +5 -2
- package/src/core/objects/publication/changes/publication.drop.test.ts +3 -1
- package/src/core/objects/publication/changes/publication.types.ts +0 -2
- package/src/core/objects/publication/publication.diff.test.ts +24 -19
- package/src/core/objects/publication/publication.diff.ts +9 -15
- package/src/core/objects/rls-policy/changes/rls-policy.alter.test.ts +31 -14
- package/src/core/objects/rls-policy/changes/rls-policy.alter.ts +3 -3
- package/src/core/objects/rls-policy/changes/rls-policy.create.test.ts +10 -3
- package/src/core/objects/rls-policy/changes/rls-policy.drop.test.ts +4 -1
- package/src/core/objects/role/changes/role.alter.test.ts +31 -15
- package/src/core/objects/role/changes/role.create.test.ts +6 -2
- package/src/core/objects/role/changes/role.drop.test.ts +4 -1
- package/src/core/objects/role/role.diff.test.ts +235 -0
- package/src/core/objects/role/role.diff.ts +21 -1
- package/src/core/objects/role/role.model.ts +122 -14
- package/src/core/objects/rule/changes/rule.alter.test.ts +7 -3
- package/src/core/objects/rule/changes/rule.comment.test.ts +5 -2
- package/src/core/objects/rule/changes/rule.create.test.ts +6 -2
- package/src/core/objects/rule/changes/rule.drop.test.ts +3 -1
- package/src/core/objects/schema/changes/schema.alter.test.ts +4 -1
- package/src/core/objects/schema/changes/schema.create.test.ts +4 -1
- package/src/core/objects/schema/changes/schema.drop.test.ts +4 -1
- package/src/core/objects/schema/schema.diff.ts +39 -102
- package/src/core/objects/schema/schema.model.ts +1 -1
- package/src/core/objects/sequence/changes/sequence.alter.test.ts +11 -5
- package/src/core/objects/sequence/changes/sequence.create.test.ts +8 -3
- package/src/core/objects/sequence/changes/sequence.drop.test.ts +4 -1
- package/src/core/objects/sequence/sequence.diff.test.ts +114 -0
- package/src/core/objects/sequence/sequence.diff.ts +39 -104
- package/src/core/objects/sequence/sequence.model.ts +1 -1
- package/src/core/objects/subscription/changes/subscription.alter.test.ts +15 -5
- package/src/core/objects/subscription/changes/subscription.comment.test.ts +5 -2
- package/src/core/objects/subscription/changes/subscription.create.test.ts +5 -2
- package/src/core/objects/subscription/changes/subscription.drop.test.ts +3 -1
- package/src/core/objects/subscription/subscription.diff.test.ts +16 -11
- package/src/core/objects/subscription/subscription.diff.ts +2 -1
- package/src/core/objects/table/changes/table.alter.test.ts +38 -15
- package/src/core/objects/table/changes/table.create.test.ts +41 -3
- package/src/core/objects/table/changes/table.create.ts +4 -0
- package/src/core/objects/table/changes/table.drop.test.ts +3 -1
- package/src/core/objects/table/table.diff.test.ts +157 -0
- package/src/core/objects/table/table.diff.ts +54 -190
- package/src/core/objects/table/table.model.ts +1 -1
- package/src/core/objects/trigger/changes/trigger.alter.test.ts +8 -4
- package/src/core/objects/trigger/changes/trigger.create.test.ts +5 -1
- package/src/core/objects/trigger/changes/trigger.create.ts +7 -4
- package/src/core/objects/trigger/changes/trigger.drop.test.ts +5 -1
- package/src/core/objects/trigger/trigger.diff.test.ts +1 -0
- package/src/core/objects/trigger/trigger.model.ts +12 -0
- package/src/core/objects/type/composite-type/changes/composite-type.alter.test.ts +10 -4
- package/src/core/objects/type/composite-type/changes/composite-type.create.test.ts +7 -2
- package/src/core/objects/type/composite-type/changes/composite-type.drop.test.ts +4 -1
- package/src/core/objects/type/composite-type/composite-type.diff.test.ts +78 -0
- package/src/core/objects/type/composite-type/composite-type.diff.ts +39 -101
- package/src/core/objects/type/composite-type/composite-type.model.ts +2 -1
- package/src/core/objects/type/enum/changes/enum.alter.test.ts +14 -5
- package/src/core/objects/type/enum/changes/enum.create.test.ts +4 -1
- package/src/core/objects/type/enum/changes/enum.drop.test.ts +4 -1
- package/src/core/objects/type/enum/enum.diff.test.ts +181 -0
- package/src/core/objects/type/enum/enum.diff.ts +58 -146
- package/src/core/objects/type/enum/enum.model.ts +1 -1
- package/src/core/objects/type/range/changes/range.alter.test.ts +3 -1
- package/src/core/objects/type/range/changes/range.create.test.ts +5 -2
- package/src/core/objects/type/range/changes/range.create.ts +6 -2
- package/src/core/objects/type/range/changes/range.drop.test.ts +3 -1
- package/src/core/objects/type/range/range.diff.test.ts +77 -0
- package/src/core/objects/type/range/range.diff.ts +39 -101
- package/src/core/objects/type/range/range.model.ts +1 -1
- package/src/core/objects/view/changes/view.alter.test.ts +8 -3
- package/src/core/objects/view/changes/view.create.test.ts +7 -2
- package/src/core/objects/view/changes/view.drop.test.ts +4 -1
- package/src/core/objects/view/view.diff.test.ts +82 -0
- package/src/core/objects/view/view.diff.ts +41 -191
- package/src/core/objects/view/view.model.ts +3 -17
- package/src/core/plan/apply.ts +9 -27
- package/src/core/plan/create.ts +173 -237
- package/src/core/plan/serialize.test.ts +317 -0
- package/src/core/plan/serialize.ts +18 -4
- package/src/core/plan/sql-format/fixtures.ts +2 -5
- package/src/core/plan/sql-format/format-lowercase-coverage.test.ts +52 -0
- package/src/core/plan/sql-format/format-off.test.ts +14 -17
- package/src/core/plan/sql-format/format-pretty-lower-leading.test.ts +27 -22
- package/src/core/plan/sql-format/format-pretty-narrow.test.ts +17 -21
- package/src/core/plan/sql-format/format-pretty-preserve.test.ts +25 -20
- package/src/core/plan/sql-format/format-pretty-upper.test.ts +23 -20
- package/src/core/plan/sql-format/keyword-case.ts +36 -1
- package/src/core/plan/ssl-config.ts +172 -0
- package/src/core/plan/types.ts +6 -0
- package/src/core/postgres-config.ts +71 -2
- package/src/core/sort/graph-builder.ts +12 -0
- package/src/core/sort/logical-sort.test.ts +371 -0
- package/src/core/sort/logical-sort.ts +32 -25
- package/src/core/sort/topological-sort.test.ts +275 -0
- package/src/core/test-utils/assert-valid-sql.ts +20 -0
- package/src/index.ts +26 -2
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
import type { Change } from "../../change.types.ts";
|
|
3
|
+
import { compileFilterDSL, evaluatePattern } from "./dsl.ts";
|
|
4
|
+
|
|
5
|
+
const tableCreate = {
|
|
6
|
+
objectType: "table",
|
|
7
|
+
operation: "create",
|
|
8
|
+
scope: "object",
|
|
9
|
+
table: { schema: "public", name: "t" },
|
|
10
|
+
requires: ["schema:public"],
|
|
11
|
+
} as unknown as Change;
|
|
12
|
+
|
|
13
|
+
const viewAlter = {
|
|
14
|
+
objectType: "view",
|
|
15
|
+
operation: "alter",
|
|
16
|
+
scope: "comment",
|
|
17
|
+
view: { schema: "private", name: "v" },
|
|
18
|
+
requires: ["schema:private", "type:auth.users"],
|
|
19
|
+
} as unknown as Change;
|
|
20
|
+
|
|
21
|
+
const roleDrop = {
|
|
22
|
+
objectType: "role",
|
|
23
|
+
operation: "drop",
|
|
24
|
+
scope: "object",
|
|
25
|
+
role: { name: "admin" },
|
|
26
|
+
requires: [],
|
|
27
|
+
} as unknown as Change;
|
|
28
|
+
|
|
29
|
+
describe("evaluatePattern", () => {
|
|
30
|
+
describe("core properties", () => {
|
|
31
|
+
test("type match", () => {
|
|
32
|
+
expect(evaluatePattern({ type: "table" }, tableCreate)).toBe(true);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
test("type mismatch", () => {
|
|
36
|
+
expect(evaluatePattern({ type: "view" }, tableCreate)).toBe(false);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test("operation match", () => {
|
|
40
|
+
expect(evaluatePattern({ operation: "create" }, tableCreate)).toBe(true);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
test("operation mismatch", () => {
|
|
44
|
+
expect(evaluatePattern({ operation: "drop" }, tableCreate)).toBe(false);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
test("scope match", () => {
|
|
48
|
+
expect(evaluatePattern({ scope: "object" }, tableCreate)).toBe(true);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
test("scope mismatch", () => {
|
|
52
|
+
expect(evaluatePattern({ scope: "comment" }, tableCreate)).toBe(false);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
test("multiple core properties AND together", () => {
|
|
56
|
+
expect(
|
|
57
|
+
evaluatePattern({ type: "table", operation: "create" }, tableCreate),
|
|
58
|
+
).toBe(true);
|
|
59
|
+
expect(
|
|
60
|
+
evaluatePattern({ type: "table", operation: "drop" }, tableCreate),
|
|
61
|
+
).toBe(false);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
test("empty pattern matches everything", () => {
|
|
65
|
+
expect(evaluatePattern({}, tableCreate)).toBe(true);
|
|
66
|
+
expect(evaluatePattern({}, roleDrop)).toBe(true);
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
describe("composition patterns", () => {
|
|
71
|
+
test("not negates a pattern", () => {
|
|
72
|
+
expect(evaluatePattern({ not: { type: "table" } }, tableCreate)).toBe(
|
|
73
|
+
false,
|
|
74
|
+
);
|
|
75
|
+
expect(evaluatePattern({ not: { type: "view" } }, tableCreate)).toBe(
|
|
76
|
+
true,
|
|
77
|
+
);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
test("and requires all to match", () => {
|
|
81
|
+
expect(
|
|
82
|
+
evaluatePattern(
|
|
83
|
+
{ and: [{ type: "table" }, { operation: "create" }] },
|
|
84
|
+
tableCreate,
|
|
85
|
+
),
|
|
86
|
+
).toBe(true);
|
|
87
|
+
expect(
|
|
88
|
+
evaluatePattern(
|
|
89
|
+
{ and: [{ type: "table" }, { operation: "drop" }] },
|
|
90
|
+
tableCreate,
|
|
91
|
+
),
|
|
92
|
+
).toBe(false);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
test("or requires any to match", () => {
|
|
96
|
+
expect(
|
|
97
|
+
evaluatePattern(
|
|
98
|
+
{ or: [{ type: "table" }, { type: "view" }] },
|
|
99
|
+
tableCreate,
|
|
100
|
+
),
|
|
101
|
+
).toBe(true);
|
|
102
|
+
expect(
|
|
103
|
+
evaluatePattern(
|
|
104
|
+
{ or: [{ type: "role" }, { type: "view" }] },
|
|
105
|
+
tableCreate,
|
|
106
|
+
),
|
|
107
|
+
).toBe(false);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
test("nested composition", () => {
|
|
111
|
+
expect(
|
|
112
|
+
evaluatePattern(
|
|
113
|
+
{ not: { or: [{ type: "role" }, { type: "view" }] } },
|
|
114
|
+
tableCreate,
|
|
115
|
+
),
|
|
116
|
+
).toBe(true);
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
describe("requiresMatching", () => {
|
|
121
|
+
test("prefix match on requires array", () => {
|
|
122
|
+
expect(
|
|
123
|
+
evaluatePattern({ requiresMatching: ["schema:public"] }, tableCreate),
|
|
124
|
+
).toBe(true);
|
|
125
|
+
expect(
|
|
126
|
+
evaluatePattern({ requiresMatching: ["schema:"] }, tableCreate),
|
|
127
|
+
).toBe(true);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
test("no match when prefix absent", () => {
|
|
131
|
+
expect(
|
|
132
|
+
evaluatePattern({ requiresMatching: ["type:auth."] }, tableCreate),
|
|
133
|
+
).toBe(false);
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
test("matches when any prefix matches any requires entry", () => {
|
|
137
|
+
expect(
|
|
138
|
+
evaluatePattern({ requiresMatching: ["type:auth."] }, viewAlter),
|
|
139
|
+
).toBe(true);
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
test("no match when requires is empty", () => {
|
|
143
|
+
expect(evaluatePattern({ requiresMatching: ["schema:"] }, roleDrop)).toBe(
|
|
144
|
+
false,
|
|
145
|
+
);
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
describe("extracted properties", () => {
|
|
150
|
+
test("schema as string exact match", () => {
|
|
151
|
+
expect(evaluatePattern({ schema: "public" }, tableCreate)).toBe(true);
|
|
152
|
+
expect(evaluatePattern({ schema: "private" }, tableCreate)).toBe(false);
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
test("schema as array checks inclusion", () => {
|
|
156
|
+
expect(
|
|
157
|
+
evaluatePattern({ schema: ["public", "private"] }, tableCreate),
|
|
158
|
+
).toBe(true);
|
|
159
|
+
expect(
|
|
160
|
+
evaluatePattern({ schema: ["private", "auth"] }, tableCreate),
|
|
161
|
+
).toBe(false);
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
test("null extracted value returns false", () => {
|
|
165
|
+
expect(evaluatePattern({ schema: "public" }, roleDrop)).toBe(false);
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
test("unknown property key is ignored", () => {
|
|
169
|
+
const pattern = { unknownKey: "value" } as Record<string, unknown>;
|
|
170
|
+
expect(
|
|
171
|
+
evaluatePattern(
|
|
172
|
+
pattern as Parameters<typeof evaluatePattern>[0],
|
|
173
|
+
tableCreate,
|
|
174
|
+
),
|
|
175
|
+
).toBe(true);
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
test("cascade property is ignored and does not affect match", () => {
|
|
179
|
+
expect(
|
|
180
|
+
evaluatePattern({ type: "table", cascade: true }, tableCreate),
|
|
181
|
+
).toBe(true);
|
|
182
|
+
expect(
|
|
183
|
+
evaluatePattern({ type: "table", cascade: false }, tableCreate),
|
|
184
|
+
).toBe(true);
|
|
185
|
+
expect(
|
|
186
|
+
evaluatePattern(
|
|
187
|
+
{ not: { schema: "auth" }, cascade: true },
|
|
188
|
+
tableCreate,
|
|
189
|
+
),
|
|
190
|
+
).toBe(true);
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
describe("compileFilterDSL", () => {
|
|
196
|
+
test("returns a function that evaluates the pattern", () => {
|
|
197
|
+
const filter = compileFilterDSL({ type: "table" });
|
|
198
|
+
expect(typeof filter).toBe("function");
|
|
199
|
+
expect(filter(tableCreate)).toBe(true);
|
|
200
|
+
expect(filter(roleDrop)).toBe(false);
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
test("works with composition patterns", () => {
|
|
204
|
+
const filter = compileFilterDSL({
|
|
205
|
+
or: [{ type: "table" }, { type: "role" }],
|
|
206
|
+
});
|
|
207
|
+
expect(filter(tableCreate)).toBe(true);
|
|
208
|
+
expect(filter(roleDrop)).toBe(true);
|
|
209
|
+
expect(filter(viewAlter)).toBe(false);
|
|
210
|
+
});
|
|
211
|
+
});
|
|
@@ -23,6 +23,30 @@ type ExtractedProperties = {
|
|
|
23
23
|
schema?: string | string[];
|
|
24
24
|
owner?: string | string[];
|
|
25
25
|
member?: string | string[];
|
|
26
|
+
grantee?: string | string[];
|
|
27
|
+
publication?: string | string[];
|
|
28
|
+
extension?: string | string[];
|
|
29
|
+
procedureLanguage?: string | string[];
|
|
30
|
+
eventTriggerName?: string | string[];
|
|
31
|
+
procedureBinaryPath?: string | string[];
|
|
32
|
+
triggerFunctionSchema?: string | string[];
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Special properties that use custom matching logic (not extractor-based).
|
|
37
|
+
*/
|
|
38
|
+
type SpecialProperties = {
|
|
39
|
+
/**
|
|
40
|
+
* Prefix match on `change.requires`.
|
|
41
|
+
* Matches when any element of `change.requires` starts with any of the given prefixes.
|
|
42
|
+
* Useful for excluding changes that depend on specific schemas/types.
|
|
43
|
+
*
|
|
44
|
+
* @example Filter out changes that require auth or extensions types:
|
|
45
|
+
* ```ts
|
|
46
|
+
* { not: { requiresMatching: ["type:auth.", "type:extensions."] } }
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
requiresMatching?: string[];
|
|
26
50
|
};
|
|
27
51
|
|
|
28
52
|
/**
|
|
@@ -30,7 +54,13 @@ type ExtractedProperties = {
|
|
|
30
54
|
* Multiple properties are combined with AND (all must match).
|
|
31
55
|
*/
|
|
32
56
|
type PropertyPattern = CoreProperties &
|
|
33
|
-
ExtractedProperties &
|
|
57
|
+
ExtractedProperties &
|
|
58
|
+
SpecialProperties & {
|
|
59
|
+
/**
|
|
60
|
+
* When true, exclusions from this filter cascade to dependents (requires/pg_depend).
|
|
61
|
+
* Default false for DSL filters (opt-in).
|
|
62
|
+
*/
|
|
63
|
+
cascade?: boolean;
|
|
34
64
|
// Composition operators are NOT allowed in property patterns
|
|
35
65
|
and?: never;
|
|
36
66
|
or?: never;
|
|
@@ -44,30 +74,39 @@ type PropertyPattern = CoreProperties &
|
|
|
44
74
|
type CompositionPattern =
|
|
45
75
|
| ({
|
|
46
76
|
and: FilterPattern[];
|
|
77
|
+
cascade?: boolean;
|
|
47
78
|
or?: never;
|
|
48
79
|
not?: never;
|
|
49
80
|
} & {
|
|
50
81
|
[K in keyof CoreProperties]?: never;
|
|
51
82
|
} & {
|
|
52
83
|
[K in keyof ExtractedProperties]?: never;
|
|
84
|
+
} & {
|
|
85
|
+
[K in keyof SpecialProperties]?: never;
|
|
53
86
|
})
|
|
54
87
|
| ({
|
|
55
88
|
or: FilterPattern[];
|
|
89
|
+
cascade?: boolean;
|
|
56
90
|
and?: never;
|
|
57
91
|
not?: never;
|
|
58
92
|
} & {
|
|
59
93
|
[K in keyof CoreProperties]?: never;
|
|
60
94
|
} & {
|
|
61
95
|
[K in keyof ExtractedProperties]?: never;
|
|
96
|
+
} & {
|
|
97
|
+
[K in keyof SpecialProperties]?: never;
|
|
62
98
|
})
|
|
63
99
|
| ({
|
|
64
100
|
not: FilterPattern;
|
|
101
|
+
cascade?: boolean;
|
|
65
102
|
and?: never;
|
|
66
103
|
or?: never;
|
|
67
104
|
} & {
|
|
68
105
|
[K in keyof CoreProperties]?: never;
|
|
69
106
|
} & {
|
|
70
107
|
[K in keyof ExtractedProperties]?: never;
|
|
108
|
+
} & {
|
|
109
|
+
[K in keyof SpecialProperties]?: never;
|
|
71
110
|
});
|
|
72
111
|
|
|
73
112
|
/**
|
|
@@ -135,10 +174,33 @@ export function evaluatePattern(
|
|
|
135
174
|
}
|
|
136
175
|
}
|
|
137
176
|
|
|
177
|
+
// Match requiresMatching (special property - prefix match on change.requires)
|
|
178
|
+
if (pattern.requiresMatching) {
|
|
179
|
+
const requires = change.requires ?? [];
|
|
180
|
+
const prefixes = pattern.requiresMatching;
|
|
181
|
+
const hasMatch = requires.some((r) =>
|
|
182
|
+
prefixes.some((p) => r.startsWith(p)),
|
|
183
|
+
);
|
|
184
|
+
if (!hasMatch) {
|
|
185
|
+
return false;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
138
189
|
// Match extracted properties
|
|
139
190
|
for (const [key, value] of Object.entries(pattern)) {
|
|
140
|
-
// Skip composition operators
|
|
141
|
-
if (
|
|
191
|
+
// Skip composition operators, core properties, special properties, and cascade
|
|
192
|
+
if (
|
|
193
|
+
[
|
|
194
|
+
"and",
|
|
195
|
+
"or",
|
|
196
|
+
"not",
|
|
197
|
+
"type",
|
|
198
|
+
"operation",
|
|
199
|
+
"scope",
|
|
200
|
+
"requiresMatching",
|
|
201
|
+
"cascade",
|
|
202
|
+
].includes(key)
|
|
203
|
+
) {
|
|
142
204
|
continue;
|
|
143
205
|
}
|
|
144
206
|
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
import type { Change } from "../../change.types.ts";
|
|
3
|
+
import { getSchema, PROPERTY_EXTRACTORS } from "./extractors.ts";
|
|
4
|
+
|
|
5
|
+
describe("getSchema", () => {
|
|
6
|
+
test("returns schema for table", () => {
|
|
7
|
+
const change = {
|
|
8
|
+
objectType: "table",
|
|
9
|
+
table: { schema: "public" },
|
|
10
|
+
} as unknown as Change;
|
|
11
|
+
expect(getSchema(change)).toBe("public");
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
test("returns schema for view", () => {
|
|
15
|
+
const change = {
|
|
16
|
+
objectType: "view",
|
|
17
|
+
view: { schema: "app" },
|
|
18
|
+
} as unknown as Change;
|
|
19
|
+
expect(getSchema(change)).toBe("app");
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
test("returns schema for enum", () => {
|
|
23
|
+
const change = {
|
|
24
|
+
objectType: "enum",
|
|
25
|
+
enum: { schema: "types" },
|
|
26
|
+
} as unknown as Change;
|
|
27
|
+
expect(getSchema(change)).toBe("types");
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
test("returns schema.name for schema type", () => {
|
|
31
|
+
const change = {
|
|
32
|
+
objectType: "schema",
|
|
33
|
+
schema: { name: "auth" },
|
|
34
|
+
} as unknown as Change;
|
|
35
|
+
expect(getSchema(change)).toBe("auth");
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
test("returns null for role", () => {
|
|
39
|
+
const change = {
|
|
40
|
+
objectType: "role",
|
|
41
|
+
role: { name: "admin" },
|
|
42
|
+
} as unknown as Change;
|
|
43
|
+
expect(getSchema(change)).toBeNull();
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
test("returns null for publication", () => {
|
|
47
|
+
const change = {
|
|
48
|
+
objectType: "publication",
|
|
49
|
+
publication: { name: "pub1" },
|
|
50
|
+
} as unknown as Change;
|
|
51
|
+
expect(getSchema(change)).toBeNull();
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
test("returns null for language", () => {
|
|
55
|
+
const change = {
|
|
56
|
+
objectType: "language",
|
|
57
|
+
language: { name: "plpgsql" },
|
|
58
|
+
} as unknown as Change;
|
|
59
|
+
expect(getSchema(change)).toBeNull();
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
describe("owner extractor", () => {
|
|
64
|
+
const getOwner = PROPERTY_EXTRACTORS.owner;
|
|
65
|
+
|
|
66
|
+
test("returns owner for table", () => {
|
|
67
|
+
const change = {
|
|
68
|
+
objectType: "table",
|
|
69
|
+
table: { owner: "postgres" },
|
|
70
|
+
} as unknown as Change;
|
|
71
|
+
expect(getOwner(change)).toBe("postgres");
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
test("returns owner for schema", () => {
|
|
75
|
+
const change = {
|
|
76
|
+
objectType: "schema",
|
|
77
|
+
schema: { owner: "admin" },
|
|
78
|
+
} as unknown as Change;
|
|
79
|
+
expect(getOwner(change)).toBe("admin");
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
test("returns role.name for role type", () => {
|
|
83
|
+
const change = {
|
|
84
|
+
objectType: "role",
|
|
85
|
+
role: { name: "supabase_admin" },
|
|
86
|
+
} as unknown as Change;
|
|
87
|
+
expect(getOwner(change)).toBe("supabase_admin");
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
test("returns null for user_mapping", () => {
|
|
91
|
+
const change = { objectType: "user_mapping" } as unknown as Change;
|
|
92
|
+
expect(getOwner(change)).toBeNull();
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
describe("PROPERTY_EXTRACTORS", () => {
|
|
97
|
+
test("has all expected keys", () => {
|
|
98
|
+
const expectedKeys = [
|
|
99
|
+
"schema",
|
|
100
|
+
"owner",
|
|
101
|
+
"member",
|
|
102
|
+
"grantee",
|
|
103
|
+
"publication",
|
|
104
|
+
"extension",
|
|
105
|
+
"procedureLanguage",
|
|
106
|
+
"eventTriggerName",
|
|
107
|
+
"procedureBinaryPath",
|
|
108
|
+
"triggerFunctionSchema",
|
|
109
|
+
];
|
|
110
|
+
expect(Object.keys(PROPERTY_EXTRACTORS).sort()).toEqual(
|
|
111
|
+
expectedKeys.sort(),
|
|
112
|
+
);
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
describe("member", () => {
|
|
116
|
+
test("returns member for membership scope", () => {
|
|
117
|
+
const change = {
|
|
118
|
+
scope: "membership",
|
|
119
|
+
member: "app_user",
|
|
120
|
+
} as unknown as Change;
|
|
121
|
+
expect(PROPERTY_EXTRACTORS.member(change)).toBe("app_user");
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
test("returns null for non-membership scope", () => {
|
|
125
|
+
const change = { scope: "object" } as unknown as Change;
|
|
126
|
+
expect(PROPERTY_EXTRACTORS.member(change)).toBeNull();
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
describe("grantee", () => {
|
|
131
|
+
test("returns grantee for privilege scope", () => {
|
|
132
|
+
const change = {
|
|
133
|
+
scope: "privilege",
|
|
134
|
+
grantee: "reader",
|
|
135
|
+
} as unknown as Change;
|
|
136
|
+
expect(PROPERTY_EXTRACTORS.grantee(change)).toBe("reader");
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
test("returns null for non-privilege scope", () => {
|
|
140
|
+
const change = { scope: "object" } as unknown as Change;
|
|
141
|
+
expect(PROPERTY_EXTRACTORS.grantee(change)).toBeNull();
|
|
142
|
+
});
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
describe("publication", () => {
|
|
146
|
+
test("returns name for publication type", () => {
|
|
147
|
+
const change = {
|
|
148
|
+
objectType: "publication",
|
|
149
|
+
publication: { name: "my_pub" },
|
|
150
|
+
} as unknown as Change;
|
|
151
|
+
expect(PROPERTY_EXTRACTORS.publication(change)).toBe("my_pub");
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
test("returns null for non-publication type", () => {
|
|
155
|
+
const change = { objectType: "table" } as unknown as Change;
|
|
156
|
+
expect(PROPERTY_EXTRACTORS.publication(change)).toBeNull();
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
describe("extension", () => {
|
|
161
|
+
test("returns name for extension type", () => {
|
|
162
|
+
const change = {
|
|
163
|
+
objectType: "extension",
|
|
164
|
+
extension: { name: "pgcrypto" },
|
|
165
|
+
} as unknown as Change;
|
|
166
|
+
expect(PROPERTY_EXTRACTORS.extension(change)).toBe("pgcrypto");
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
test("returns null for non-extension type", () => {
|
|
170
|
+
const change = { objectType: "table" } as unknown as Change;
|
|
171
|
+
expect(PROPERTY_EXTRACTORS.extension(change)).toBeNull();
|
|
172
|
+
});
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
describe("procedureLanguage", () => {
|
|
176
|
+
test("returns language for procedure type", () => {
|
|
177
|
+
const change = {
|
|
178
|
+
objectType: "procedure",
|
|
179
|
+
procedure: { language: "plpgsql" },
|
|
180
|
+
} as unknown as Change;
|
|
181
|
+
expect(PROPERTY_EXTRACTORS.procedureLanguage(change)).toBe("plpgsql");
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
test("returns null for non-procedure type", () => {
|
|
185
|
+
const change = { objectType: "table" } as unknown as Change;
|
|
186
|
+
expect(PROPERTY_EXTRACTORS.procedureLanguage(change)).toBeNull();
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
describe("eventTriggerName", () => {
|
|
191
|
+
test("returns name for event_trigger type", () => {
|
|
192
|
+
const change = {
|
|
193
|
+
objectType: "event_trigger",
|
|
194
|
+
eventTrigger: { name: "my_trigger" },
|
|
195
|
+
} as unknown as Change;
|
|
196
|
+
expect(PROPERTY_EXTRACTORS.eventTriggerName(change)).toBe("my_trigger");
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
test("returns null for non-event_trigger type", () => {
|
|
200
|
+
const change = { objectType: "table" } as unknown as Change;
|
|
201
|
+
expect(PROPERTY_EXTRACTORS.eventTriggerName(change)).toBeNull();
|
|
202
|
+
});
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
describe("procedureBinaryPath", () => {
|
|
206
|
+
test("returns binary_path for procedure type", () => {
|
|
207
|
+
const change = {
|
|
208
|
+
objectType: "procedure",
|
|
209
|
+
procedure: { binary_path: "/usr/bin/pg" },
|
|
210
|
+
} as unknown as Change;
|
|
211
|
+
expect(PROPERTY_EXTRACTORS.procedureBinaryPath(change)).toBe(
|
|
212
|
+
"/usr/bin/pg",
|
|
213
|
+
);
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
test("returns null when binary_path is undefined", () => {
|
|
217
|
+
const change = {
|
|
218
|
+
objectType: "procedure",
|
|
219
|
+
procedure: {},
|
|
220
|
+
} as unknown as Change;
|
|
221
|
+
expect(PROPERTY_EXTRACTORS.procedureBinaryPath(change)).toBeNull();
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
test("returns null for non-procedure type", () => {
|
|
225
|
+
const change = { objectType: "table" } as unknown as Change;
|
|
226
|
+
expect(PROPERTY_EXTRACTORS.procedureBinaryPath(change)).toBeNull();
|
|
227
|
+
});
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
describe("triggerFunctionSchema", () => {
|
|
231
|
+
test("returns function_schema for trigger type", () => {
|
|
232
|
+
const change = {
|
|
233
|
+
objectType: "trigger",
|
|
234
|
+
trigger: { function_schema: "public" },
|
|
235
|
+
} as unknown as Change;
|
|
236
|
+
expect(PROPERTY_EXTRACTORS.triggerFunctionSchema(change)).toBe("public");
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
test("returns null for non-trigger type", () => {
|
|
240
|
+
const change = { objectType: "table" } as unknown as Change;
|
|
241
|
+
expect(PROPERTY_EXTRACTORS.triggerFunctionSchema(change)).toBeNull();
|
|
242
|
+
});
|
|
243
|
+
});
|
|
244
|
+
});
|
|
@@ -18,6 +18,48 @@ export const PROPERTY_EXTRACTORS: Record<string, PropertyExtractor> = {
|
|
|
18
18
|
}
|
|
19
19
|
return null;
|
|
20
20
|
},
|
|
21
|
+
grantee: (change: Change) => {
|
|
22
|
+
if (change.scope === "privilege" && "grantee" in change) {
|
|
23
|
+
return change.grantee;
|
|
24
|
+
}
|
|
25
|
+
return null;
|
|
26
|
+
},
|
|
27
|
+
publication: (change: Change) => {
|
|
28
|
+
if (change.objectType === "publication") {
|
|
29
|
+
return change.publication.name;
|
|
30
|
+
}
|
|
31
|
+
return null;
|
|
32
|
+
},
|
|
33
|
+
extension: (change: Change) => {
|
|
34
|
+
if (change.objectType === "extension") {
|
|
35
|
+
return change.extension.name;
|
|
36
|
+
}
|
|
37
|
+
return null;
|
|
38
|
+
},
|
|
39
|
+
procedureLanguage: (change: Change) => {
|
|
40
|
+
if (change.objectType === "procedure") {
|
|
41
|
+
return change.procedure.language;
|
|
42
|
+
}
|
|
43
|
+
return null;
|
|
44
|
+
},
|
|
45
|
+
eventTriggerName: (change: Change) => {
|
|
46
|
+
if (change.objectType === "event_trigger") {
|
|
47
|
+
return change.eventTrigger.name;
|
|
48
|
+
}
|
|
49
|
+
return null;
|
|
50
|
+
},
|
|
51
|
+
procedureBinaryPath: (change: Change) => {
|
|
52
|
+
if (change.objectType === "procedure") {
|
|
53
|
+
return change.procedure.binary_path ?? null;
|
|
54
|
+
}
|
|
55
|
+
return null;
|
|
56
|
+
},
|
|
57
|
+
triggerFunctionSchema: (change: Change) => {
|
|
58
|
+
if (change.objectType === "trigger") {
|
|
59
|
+
return change.trigger.function_schema;
|
|
60
|
+
}
|
|
61
|
+
return null;
|
|
62
|
+
},
|
|
21
63
|
};
|
|
22
64
|
|
|
23
65
|
export function getSchema(change: Change) {
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* Combines filter and serialization DSLs into a single serializable structure.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
import type { CatalogSnapshot } from "../catalog.snapshot.ts";
|
|
7
8
|
import type { FilterDSL } from "./filter/dsl.ts";
|
|
8
9
|
import type { SerializeDSL } from "./serialize/dsl.ts";
|
|
9
10
|
|
|
@@ -21,4 +22,13 @@ export type IntegrationDSL = {
|
|
|
21
22
|
* If not provided, changes are serialized with default options.
|
|
22
23
|
*/
|
|
23
24
|
serialize?: SerializeDSL;
|
|
25
|
+
/**
|
|
26
|
+
* Baseline catalog snapshot for this integration.
|
|
27
|
+
*
|
|
28
|
+
* When `--source` is omitted, this snapshot is deserialized and used as the
|
|
29
|
+
* source catalog instead of `createEmptyCatalog`. This lets integrations
|
|
30
|
+
* define what "empty" means for their platform (e.g. Supabase ships with
|
|
31
|
+
* pre-existing schemas, extensions, and roles).
|
|
32
|
+
*/
|
|
33
|
+
emptyCatalog?: CatalogSnapshot;
|
|
24
34
|
};
|