@supabase/pg-delta 1.0.0-alpha.21 → 1.0.0-alpha.23
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/dist/core/catalog.diff.js +4 -3
- package/dist/core/catalog.model.d.ts +8 -1
- package/dist/core/catalog.model.js +10 -8
- package/dist/core/expand-replace-dependencies.js +23 -0
- package/dist/core/integrations/filter/flatten.js +13 -0
- package/dist/core/objects/aggregate/aggregate.diff.js +16 -0
- package/dist/core/objects/aggregate/aggregate.model.d.ts +10 -0
- package/dist/core/objects/aggregate/aggregate.model.js +19 -1
- package/dist/core/objects/aggregate/changes/aggregate.base.d.ts +1 -1
- package/dist/core/objects/aggregate/changes/aggregate.security-label.d.ts +28 -0
- package/dist/core/objects/aggregate/changes/aggregate.security-label.js +64 -0
- package/dist/core/objects/aggregate/changes/aggregate.types.d.ts +2 -1
- package/dist/core/objects/base.model.d.ts +8 -0
- package/dist/core/objects/base.model.js +2 -0
- package/dist/core/objects/domain/changes/domain.base.d.ts +1 -1
- package/dist/core/objects/domain/changes/domain.security-label.d.ts +28 -0
- package/dist/core/objects/domain/changes/domain.security-label.js +61 -0
- package/dist/core/objects/domain/changes/domain.types.d.ts +2 -1
- package/dist/core/objects/domain/domain.diff.js +16 -0
- package/dist/core/objects/domain/domain.model.d.ts +10 -0
- package/dist/core/objects/domain/domain.model.js +19 -1
- package/dist/core/objects/event-trigger/changes/event-trigger.base.d.ts +1 -1
- package/dist/core/objects/event-trigger/changes/event-trigger.security-label.d.ts +28 -0
- package/dist/core/objects/event-trigger/changes/event-trigger.security-label.js +61 -0
- package/dist/core/objects/event-trigger/changes/event-trigger.types.d.ts +2 -1
- package/dist/core/objects/event-trigger/event-trigger.diff.js +16 -0
- package/dist/core/objects/event-trigger/event-trigger.model.d.ts +10 -0
- package/dist/core/objects/event-trigger/event-trigger.model.js +19 -1
- package/dist/core/objects/extract-with-retry.d.ts +36 -0
- package/dist/core/objects/extract-with-retry.js +51 -0
- package/dist/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.base.d.ts +1 -1
- package/dist/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.security-label.d.ts +28 -0
- package/dist/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.security-label.js +61 -0
- package/dist/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.types.d.ts +2 -1
- package/dist/core/objects/foreign-data-wrapper/foreign-table/foreign-table.diff.js +16 -0
- package/dist/core/objects/foreign-data-wrapper/foreign-table/foreign-table.model.d.ts +22 -0
- package/dist/core/objects/foreign-data-wrapper/foreign-table/foreign-table.model.js +20 -1
- package/dist/core/objects/index/index.diff.js +0 -1
- package/dist/core/objects/index/index.model.d.ts +2 -3
- package/dist/core/objects/index/index.model.js +17 -6
- package/dist/core/objects/materialized-view/changes/materialized-view.base.d.ts +1 -1
- package/dist/core/objects/materialized-view/changes/materialized-view.security-label.d.ts +28 -0
- package/dist/core/objects/materialized-view/changes/materialized-view.security-label.js +61 -0
- package/dist/core/objects/materialized-view/changes/materialized-view.types.d.ts +2 -1
- package/dist/core/objects/materialized-view/materialized-view.diff.js +18 -0
- package/dist/core/objects/materialized-view/materialized-view.model.d.ts +24 -1
- package/dist/core/objects/materialized-view/materialized-view.model.js +40 -5
- package/dist/core/objects/procedure/changes/procedure.base.d.ts +1 -1
- package/dist/core/objects/procedure/changes/procedure.security-label.d.ts +28 -0
- package/dist/core/objects/procedure/changes/procedure.security-label.js +69 -0
- package/dist/core/objects/procedure/changes/procedure.types.d.ts +2 -1
- package/dist/core/objects/procedure/procedure.diff.js +16 -0
- package/dist/core/objects/procedure/procedure.model.d.ts +12 -1
- package/dist/core/objects/procedure/procedure.model.js +39 -5
- package/dist/core/objects/publication/changes/publication.base.d.ts +1 -1
- package/dist/core/objects/publication/changes/publication.security-label.d.ts +28 -0
- package/dist/core/objects/publication/changes/publication.security-label.js +61 -0
- package/dist/core/objects/publication/changes/publication.types.d.ts +2 -1
- package/dist/core/objects/publication/publication.diff.js +16 -0
- package/dist/core/objects/publication/publication.model.d.ts +14 -0
- package/dist/core/objects/publication/publication.model.js +20 -1
- package/dist/core/objects/rls-policy/rls-policy.diff.js +13 -1
- package/dist/core/objects/role/changes/role.base.d.ts +1 -1
- package/dist/core/objects/role/changes/role.security-label.d.ts +28 -0
- package/dist/core/objects/role/changes/role.security-label.js +61 -0
- package/dist/core/objects/role/changes/role.types.d.ts +2 -1
- package/dist/core/objects/role/role.diff.js +16 -0
- package/dist/core/objects/role/role.model.d.ts +10 -0
- package/dist/core/objects/role/role.model.js +29 -0
- package/dist/core/objects/rule/rule.model.d.ts +2 -1
- package/dist/core/objects/rule/rule.model.js +20 -3
- package/dist/core/objects/schema/changes/schema.base.d.ts +1 -1
- package/dist/core/objects/schema/changes/schema.security-label.d.ts +28 -0
- package/dist/core/objects/schema/changes/schema.security-label.js +61 -0
- package/dist/core/objects/schema/changes/schema.types.d.ts +2 -1
- package/dist/core/objects/schema/schema.diff.js +24 -1
- package/dist/core/objects/schema/schema.model.d.ts +10 -0
- package/dist/core/objects/schema/schema.model.js +18 -1
- package/dist/core/objects/security-label.types.d.ts +20 -0
- package/dist/core/objects/security-label.types.js +46 -0
- package/dist/core/objects/sequence/changes/sequence.base.d.ts +1 -1
- package/dist/core/objects/sequence/changes/sequence.security-label.d.ts +28 -0
- package/dist/core/objects/sequence/changes/sequence.security-label.js +61 -0
- package/dist/core/objects/sequence/changes/sequence.types.d.ts +2 -1
- package/dist/core/objects/sequence/sequence.diff.d.ts +2 -1
- package/dist/core/objects/sequence/sequence.diff.js +44 -4
- package/dist/core/objects/sequence/sequence.model.d.ts +10 -0
- package/dist/core/objects/sequence/sequence.model.js +19 -1
- package/dist/core/objects/subscription/changes/subscription.base.d.ts +1 -1
- package/dist/core/objects/subscription/changes/subscription.security-label.d.ts +28 -0
- package/dist/core/objects/subscription/changes/subscription.security-label.js +61 -0
- package/dist/core/objects/subscription/changes/subscription.types.d.ts +2 -1
- package/dist/core/objects/subscription/subscription.diff.js +16 -0
- package/dist/core/objects/subscription/subscription.model.d.ts +10 -0
- package/dist/core/objects/subscription/subscription.model.js +19 -1
- package/dist/core/objects/table/changes/table.alter.d.ts +12 -1
- package/dist/core/objects/table/changes/table.alter.js +20 -2
- package/dist/core/objects/table/changes/table.base.d.ts +1 -1
- package/dist/core/objects/table/changes/table.security-label.d.ts +63 -0
- package/dist/core/objects/table/changes/table.security-label.js +134 -0
- package/dist/core/objects/table/changes/table.types.d.ts +2 -1
- package/dist/core/objects/table/table.diff.js +68 -15
- package/dist/core/objects/table/table.model.d.ts +36 -1
- package/dist/core/objects/table/table.model.js +74 -7
- package/dist/core/objects/trigger/trigger.model.d.ts +2 -1
- package/dist/core/objects/trigger/trigger.model.js +20 -4
- package/dist/core/objects/type/composite-type/changes/composite-type.base.d.ts +1 -1
- package/dist/core/objects/type/composite-type/changes/composite-type.security-label.d.ts +28 -0
- package/dist/core/objects/type/composite-type/changes/composite-type.security-label.js +61 -0
- package/dist/core/objects/type/composite-type/changes/composite-type.types.d.ts +2 -1
- package/dist/core/objects/type/composite-type/composite-type.diff.js +16 -0
- package/dist/core/objects/type/composite-type/composite-type.model.d.ts +22 -0
- package/dist/core/objects/type/composite-type/composite-type.model.js +22 -2
- package/dist/core/objects/type/enum/changes/enum.base.d.ts +1 -1
- package/dist/core/objects/type/enum/changes/enum.security-label.d.ts +28 -0
- package/dist/core/objects/type/enum/changes/enum.security-label.js +61 -0
- package/dist/core/objects/type/enum/changes/enum.types.d.ts +2 -1
- package/dist/core/objects/type/enum/enum.diff.js +16 -0
- package/dist/core/objects/type/enum/enum.model.d.ts +10 -0
- package/dist/core/objects/type/enum/enum.model.js +20 -1
- package/dist/core/objects/type/range/changes/range.base.d.ts +1 -1
- package/dist/core/objects/type/range/changes/range.security-label.d.ts +28 -0
- package/dist/core/objects/type/range/changes/range.security-label.js +61 -0
- package/dist/core/objects/type/range/changes/range.types.d.ts +2 -1
- package/dist/core/objects/type/range/range.diff.js +16 -0
- package/dist/core/objects/type/range/range.model.d.ts +10 -0
- package/dist/core/objects/type/range/range.model.js +19 -1
- package/dist/core/objects/utils.d.ts +2 -0
- package/dist/core/objects/utils.js +6 -0
- package/dist/core/objects/view/changes/view.base.d.ts +1 -1
- package/dist/core/objects/view/changes/view.security-label.d.ts +28 -0
- package/dist/core/objects/view/changes/view.security-label.js +61 -0
- package/dist/core/objects/view/changes/view.types.d.ts +2 -1
- package/dist/core/objects/view/view.diff.js +13 -0
- package/dist/core/objects/view/view.model.d.ts +28 -1
- package/dist/core/objects/view/view.model.js +40 -5
- package/dist/core/plan/create.js +3 -1
- package/dist/core/plan/sql-format/fixtures.js +1 -0
- package/dist/core/plan/types.d.ts +8 -0
- package/dist/core/{post-diff-cycle-breaking.d.ts → post-diff-normalization.d.ts} +8 -1
- package/dist/core/post-diff-normalization.js +202 -0
- package/dist/core/sort/cycle-breakers.js +1 -1
- package/dist/core/sort/utils.d.ts +10 -0
- package/dist/core/sort/utils.js +28 -0
- package/package.json +1 -1
- package/src/core/catalog.diff.ts +4 -2
- package/src/core/catalog.model.ts +21 -8
- package/src/core/expand-replace-dependencies.test.ts +131 -0
- package/src/core/expand-replace-dependencies.ts +24 -0
- package/src/core/integrations/filter/dsl.test.ts +27 -0
- package/src/core/integrations/filter/flatten.ts +16 -0
- package/src/core/objects/aggregate/aggregate.diff.ts +33 -0
- package/src/core/objects/aggregate/aggregate.model.ts +22 -1
- package/src/core/objects/aggregate/changes/aggregate.base.ts +5 -1
- package/src/core/objects/aggregate/changes/aggregate.security-label.ts +99 -0
- package/src/core/objects/aggregate/changes/aggregate.types.ts +3 -1
- package/src/core/objects/base.model.ts +2 -0
- package/src/core/objects/domain/changes/domain.base.ts +5 -1
- package/src/core/objects/domain/changes/domain.security-label.test.ts +56 -0
- package/src/core/objects/domain/changes/domain.security-label.ts +77 -0
- package/src/core/objects/domain/changes/domain.types.ts +3 -1
- package/src/core/objects/domain/domain.diff.ts +33 -0
- package/src/core/objects/domain/domain.model.ts +22 -1
- package/src/core/objects/event-trigger/changes/event-trigger.base.ts +1 -1
- package/src/core/objects/event-trigger/changes/event-trigger.security-label.ts +95 -0
- package/src/core/objects/event-trigger/changes/event-trigger.types.ts +3 -1
- package/src/core/objects/event-trigger/event-trigger.diff.ts +33 -0
- package/src/core/objects/event-trigger/event-trigger.model.ts +22 -1
- package/src/core/objects/extract-with-retry.test.ts +143 -0
- package/src/core/objects/extract-with-retry.ts +87 -0
- package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.base.ts +5 -1
- package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.security-label.ts +95 -0
- package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.types.ts +3 -1
- package/src/core/objects/foreign-data-wrapper/foreign-table/foreign-table.diff.ts +33 -0
- package/src/core/objects/foreign-data-wrapper/foreign-table/foreign-table.model.ts +24 -1
- package/src/core/objects/index/index.diff.ts +0 -1
- package/src/core/objects/index/index.model.test.ts +37 -1
- package/src/core/objects/index/index.model.ts +25 -6
- package/src/core/objects/materialized-view/changes/materialized-view.base.ts +5 -1
- package/src/core/objects/materialized-view/changes/materialized-view.security-label.test.ts +63 -0
- package/src/core/objects/materialized-view/changes/materialized-view.security-label.ts +95 -0
- package/src/core/objects/materialized-view/changes/materialized-view.types.ts +3 -1
- package/src/core/objects/materialized-view/materialized-view.diff.ts +37 -0
- package/src/core/objects/materialized-view/materialized-view.model.test.ts +93 -0
- package/src/core/objects/materialized-view/materialized-view.model.ts +52 -8
- package/src/core/objects/procedure/changes/procedure.base.ts +5 -1
- package/src/core/objects/procedure/changes/procedure.security-label.ts +105 -0
- package/src/core/objects/procedure/changes/procedure.types.ts +3 -1
- package/src/core/objects/procedure/procedure.diff.ts +33 -0
- package/src/core/objects/procedure/procedure.model.test.ts +117 -0
- package/src/core/objects/procedure/procedure.model.ts +51 -7
- package/src/core/objects/publication/changes/publication.base.ts +1 -1
- package/src/core/objects/publication/changes/publication.security-label.ts +95 -0
- package/src/core/objects/publication/changes/publication.types.ts +3 -1
- package/src/core/objects/publication/publication.diff.ts +33 -0
- package/src/core/objects/publication/publication.model.ts +24 -1
- package/src/core/objects/rls-policy/rls-policy.diff.ts +19 -1
- package/src/core/objects/role/changes/role.base.ts +2 -1
- package/src/core/objects/role/changes/role.security-label.ts +77 -0
- package/src/core/objects/role/changes/role.types.ts +3 -1
- package/src/core/objects/role/role.diff.ts +33 -0
- package/src/core/objects/role/role.model.ts +32 -0
- package/src/core/objects/rule/rule.model.test.ts +99 -0
- package/src/core/objects/rule/rule.model.ts +28 -4
- package/src/core/objects/schema/changes/schema.alter.test.ts +1 -0
- package/src/core/objects/schema/changes/schema.base.ts +5 -1
- package/src/core/objects/schema/changes/schema.create.test.ts +1 -0
- package/src/core/objects/schema/changes/schema.drop.test.ts +1 -0
- package/src/core/objects/schema/changes/schema.security-label.test.ts +76 -0
- package/src/core/objects/schema/changes/schema.security-label.ts +77 -0
- package/src/core/objects/schema/changes/schema.types.ts +3 -1
- package/src/core/objects/schema/schema.diff.test.ts +1 -0
- package/src/core/objects/schema/schema.diff.ts +43 -1
- package/src/core/objects/schema/schema.model.ts +21 -1
- package/src/core/objects/security-label.types.test.ts +106 -0
- package/src/core/objects/security-label.types.ts +61 -0
- package/src/core/objects/sequence/changes/sequence.base.ts +5 -1
- package/src/core/objects/sequence/changes/sequence.security-label.test.ts +58 -0
- package/src/core/objects/sequence/changes/sequence.security-label.ts +92 -0
- package/src/core/objects/sequence/changes/sequence.types.ts +3 -1
- package/src/core/objects/sequence/sequence.diff.test.ts +87 -0
- package/src/core/objects/sequence/sequence.diff.ts +64 -6
- package/src/core/objects/sequence/sequence.model.ts +22 -1
- package/src/core/objects/subscription/changes/subscription.base.ts +1 -1
- package/src/core/objects/subscription/changes/subscription.security-label.ts +95 -0
- package/src/core/objects/subscription/changes/subscription.types.ts +3 -1
- package/src/core/objects/subscription/subscription.diff.ts +33 -0
- package/src/core/objects/subscription/subscription.model.ts +22 -1
- package/src/core/objects/table/changes/table.alter.test.ts +13 -21
- package/src/core/objects/table/changes/table.alter.ts +30 -3
- package/src/core/objects/table/changes/table.base.ts +5 -1
- package/src/core/objects/table/changes/table.security-label.test.ts +140 -0
- package/src/core/objects/table/changes/table.security-label.ts +183 -0
- package/src/core/objects/table/changes/table.types.ts +3 -1
- package/src/core/objects/table/table.diff.ts +111 -19
- package/src/core/objects/table/table.model.test.ts +209 -0
- package/src/core/objects/table/table.model.ts +94 -9
- package/src/core/objects/trigger/trigger.model.test.ts +113 -0
- package/src/core/objects/trigger/trigger.model.ts +28 -5
- package/src/core/objects/type/composite-type/changes/composite-type.base.ts +5 -1
- package/src/core/objects/type/composite-type/changes/composite-type.security-label.ts +95 -0
- package/src/core/objects/type/composite-type/changes/composite-type.types.ts +3 -1
- package/src/core/objects/type/composite-type/composite-type.diff.ts +33 -0
- package/src/core/objects/type/composite-type/composite-type.model.ts +26 -2
- package/src/core/objects/type/enum/changes/enum.base.ts +5 -1
- package/src/core/objects/type/enum/changes/enum.security-label.ts +77 -0
- package/src/core/objects/type/enum/changes/enum.types.ts +3 -1
- package/src/core/objects/type/enum/enum.diff.ts +33 -0
- package/src/core/objects/type/enum/enum.model.ts +25 -1
- package/src/core/objects/type/range/changes/range.base.ts +5 -1
- package/src/core/objects/type/range/changes/range.security-label.ts +77 -0
- package/src/core/objects/type/range/changes/range.types.ts +3 -1
- package/src/core/objects/type/range/range.diff.ts +33 -0
- package/src/core/objects/type/range/range.model.ts +22 -1
- package/src/core/objects/utils.ts +6 -0
- package/src/core/objects/view/changes/view.base.ts +5 -1
- package/src/core/objects/view/changes/view.security-label.test.ts +64 -0
- package/src/core/objects/view/changes/view.security-label.ts +77 -0
- package/src/core/objects/view/changes/view.types.ts +3 -1
- package/src/core/objects/view/view.diff.ts +31 -0
- package/src/core/objects/view/view.model.test.ts +90 -0
- package/src/core/objects/view/view.model.ts +53 -7
- package/src/core/plan/create.ts +3 -1
- package/src/core/plan/sql-format/fixtures.ts +1 -0
- package/src/core/plan/types.ts +8 -0
- package/src/core/{post-diff-cycle-breaking.test.ts → post-diff-normalization.test.ts} +168 -4
- package/src/core/post-diff-normalization.ts +260 -0
- package/src/core/sort/cycle-breakers.ts +1 -1
- package/src/core/sort/utils.ts +38 -0
- package/dist/core/post-diff-cycle-breaking.js +0 -100
- package/src/core/post-diff-cycle-breaking.ts +0 -138
|
@@ -3,7 +3,11 @@ import type { MaterializedView } from "../materialized-view.model.ts";
|
|
|
3
3
|
|
|
4
4
|
abstract class BaseMaterializedViewChange extends BaseChange {
|
|
5
5
|
abstract readonly materializedView: MaterializedView;
|
|
6
|
-
abstract readonly scope:
|
|
6
|
+
abstract readonly scope:
|
|
7
|
+
| "object"
|
|
8
|
+
| "comment"
|
|
9
|
+
| "privilege"
|
|
10
|
+
| "security_label";
|
|
7
11
|
readonly objectType: "materialized_view" = "materialized_view";
|
|
8
12
|
}
|
|
9
13
|
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
import { assertValidSql } from "../../../test-utils/assert-valid-sql.ts";
|
|
3
|
+
import { stableId } from "../../utils.ts";
|
|
4
|
+
import {
|
|
5
|
+
MaterializedView,
|
|
6
|
+
type MaterializedViewProps,
|
|
7
|
+
} from "../materialized-view.model.ts";
|
|
8
|
+
import {
|
|
9
|
+
CreateSecurityLabelOnMaterializedView,
|
|
10
|
+
DropSecurityLabelOnMaterializedView,
|
|
11
|
+
} from "./materialized-view.security-label.ts";
|
|
12
|
+
|
|
13
|
+
const makeMV = (): MaterializedView =>
|
|
14
|
+
new MaterializedView({
|
|
15
|
+
schema: "public",
|
|
16
|
+
name: "mv",
|
|
17
|
+
definition: "SELECT 1",
|
|
18
|
+
row_security: false,
|
|
19
|
+
force_row_security: false,
|
|
20
|
+
has_indexes: false,
|
|
21
|
+
has_rules: false,
|
|
22
|
+
has_triggers: false,
|
|
23
|
+
has_subclasses: false,
|
|
24
|
+
is_populated: true,
|
|
25
|
+
replica_identity: "d",
|
|
26
|
+
is_partition: false,
|
|
27
|
+
options: null,
|
|
28
|
+
partition_bound: null,
|
|
29
|
+
owner: "postgres",
|
|
30
|
+
comment: null,
|
|
31
|
+
columns: [],
|
|
32
|
+
privileges: [],
|
|
33
|
+
} as MaterializedViewProps);
|
|
34
|
+
|
|
35
|
+
describe("materialized-view.security-label", () => {
|
|
36
|
+
test("create serializes", async () => {
|
|
37
|
+
const mv = makeMV();
|
|
38
|
+
const change = new CreateSecurityLabelOnMaterializedView({
|
|
39
|
+
materializedView: mv,
|
|
40
|
+
securityLabel: { provider: "dummy", label: "classified" },
|
|
41
|
+
});
|
|
42
|
+
expect(change.scope).toBe("security_label");
|
|
43
|
+
expect(change.creates).toEqual([
|
|
44
|
+
stableId.securityLabel(mv.stableId, "dummy"),
|
|
45
|
+
]);
|
|
46
|
+
await assertValidSql(change.serialize());
|
|
47
|
+
expect(change.serialize()).toBe(
|
|
48
|
+
"SECURITY LABEL FOR dummy ON MATERIALIZED VIEW public.mv IS 'classified'",
|
|
49
|
+
);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
test("drop serializes to IS NULL", async () => {
|
|
53
|
+
const mv = makeMV();
|
|
54
|
+
const change = new DropSecurityLabelOnMaterializedView({
|
|
55
|
+
materializedView: mv,
|
|
56
|
+
securityLabel: { provider: "dummy", label: "x" },
|
|
57
|
+
});
|
|
58
|
+
await assertValidSql(change.serialize());
|
|
59
|
+
expect(change.serialize()).toBe(
|
|
60
|
+
"SECURITY LABEL FOR dummy ON MATERIALIZED VIEW public.mv IS NULL",
|
|
61
|
+
);
|
|
62
|
+
});
|
|
63
|
+
});
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { quoteLiteral } from "../../base.change.ts";
|
|
2
|
+
import type { SecurityLabelProps } from "../../security-label.types.ts";
|
|
3
|
+
import { stableId } from "../../utils.ts";
|
|
4
|
+
import type { MaterializedView } from "../materialized-view.model.ts";
|
|
5
|
+
import {
|
|
6
|
+
CreateMaterializedViewChange,
|
|
7
|
+
DropMaterializedViewChange,
|
|
8
|
+
} from "./materialized-view.base.ts";
|
|
9
|
+
|
|
10
|
+
export type SecurityLabelMaterializedView =
|
|
11
|
+
| CreateSecurityLabelOnMaterializedView
|
|
12
|
+
| DropSecurityLabelOnMaterializedView;
|
|
13
|
+
|
|
14
|
+
export class CreateSecurityLabelOnMaterializedView extends CreateMaterializedViewChange {
|
|
15
|
+
public readonly materializedView: MaterializedView;
|
|
16
|
+
public readonly securityLabel: SecurityLabelProps;
|
|
17
|
+
public readonly scope = "security_label" as const;
|
|
18
|
+
|
|
19
|
+
constructor(props: {
|
|
20
|
+
materializedView: MaterializedView;
|
|
21
|
+
securityLabel: SecurityLabelProps;
|
|
22
|
+
}) {
|
|
23
|
+
super();
|
|
24
|
+
this.materializedView = props.materializedView;
|
|
25
|
+
this.securityLabel = props.securityLabel;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
get creates() {
|
|
29
|
+
return [
|
|
30
|
+
stableId.securityLabel(
|
|
31
|
+
this.materializedView.stableId,
|
|
32
|
+
this.securityLabel.provider,
|
|
33
|
+
),
|
|
34
|
+
];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
get requires() {
|
|
38
|
+
return [this.materializedView.stableId];
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
serialize(): string {
|
|
42
|
+
return [
|
|
43
|
+
"SECURITY LABEL FOR",
|
|
44
|
+
this.securityLabel.provider,
|
|
45
|
+
"ON MATERIALIZED VIEW",
|
|
46
|
+
`${this.materializedView.schema}.${this.materializedView.name}`,
|
|
47
|
+
"IS",
|
|
48
|
+
quoteLiteral(this.securityLabel.label),
|
|
49
|
+
].join(" ");
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export class DropSecurityLabelOnMaterializedView extends DropMaterializedViewChange {
|
|
54
|
+
public readonly materializedView: MaterializedView;
|
|
55
|
+
public readonly securityLabel: SecurityLabelProps;
|
|
56
|
+
public readonly scope = "security_label" as const;
|
|
57
|
+
|
|
58
|
+
constructor(props: {
|
|
59
|
+
materializedView: MaterializedView;
|
|
60
|
+
securityLabel: SecurityLabelProps;
|
|
61
|
+
}) {
|
|
62
|
+
super();
|
|
63
|
+
this.materializedView = props.materializedView;
|
|
64
|
+
this.securityLabel = props.securityLabel;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
get drops() {
|
|
68
|
+
return [
|
|
69
|
+
stableId.securityLabel(
|
|
70
|
+
this.materializedView.stableId,
|
|
71
|
+
this.securityLabel.provider,
|
|
72
|
+
),
|
|
73
|
+
];
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
get requires() {
|
|
77
|
+
return [
|
|
78
|
+
stableId.securityLabel(
|
|
79
|
+
this.materializedView.stableId,
|
|
80
|
+
this.securityLabel.provider,
|
|
81
|
+
),
|
|
82
|
+
this.materializedView.stableId,
|
|
83
|
+
];
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
serialize(): string {
|
|
87
|
+
return [
|
|
88
|
+
"SECURITY LABEL FOR",
|
|
89
|
+
this.securityLabel.provider,
|
|
90
|
+
"ON MATERIALIZED VIEW",
|
|
91
|
+
`${this.materializedView.schema}.${this.materializedView.name}`,
|
|
92
|
+
"IS NULL",
|
|
93
|
+
].join(" ");
|
|
94
|
+
}
|
|
95
|
+
}
|
|
@@ -3,6 +3,7 @@ import type { CommentMaterializedView } from "./materialized-view.comment.ts";
|
|
|
3
3
|
import type { CreateMaterializedView } from "./materialized-view.create.ts";
|
|
4
4
|
import type { DropMaterializedView } from "./materialized-view.drop.ts";
|
|
5
5
|
import type { MaterializedViewPrivilege } from "./materialized-view.privilege.ts";
|
|
6
|
+
import type { SecurityLabelMaterializedView } from "./materialized-view.security-label.ts";
|
|
6
7
|
|
|
7
8
|
/** Union of all materialized-view-related change variants (`objectType: "materialized_view"`). @category Change Types */
|
|
8
9
|
export type MaterializedViewChange =
|
|
@@ -10,4 +11,5 @@ export type MaterializedViewChange =
|
|
|
10
11
|
| CommentMaterializedView
|
|
11
12
|
| CreateMaterializedView
|
|
12
13
|
| DropMaterializedView
|
|
13
|
-
| MaterializedViewPrivilege
|
|
14
|
+
| MaterializedViewPrivilege
|
|
15
|
+
| SecurityLabelMaterializedView;
|
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
emitColumnPrivilegeChanges,
|
|
5
5
|
} from "../base.privilege-diff.ts";
|
|
6
6
|
import type { ObjectDiffContext } from "../diff-context.ts";
|
|
7
|
+
import { diffSecurityLabels } from "../security-label.types.ts";
|
|
7
8
|
import { deepEqual, hasNonAlterableChanges } from "../utils.ts";
|
|
8
9
|
import {
|
|
9
10
|
AlterMaterializedViewChangeOwner,
|
|
@@ -22,6 +23,10 @@ import {
|
|
|
22
23
|
RevokeGrantOptionMaterializedViewPrivileges,
|
|
23
24
|
RevokeMaterializedViewPrivileges,
|
|
24
25
|
} from "./changes/materialized-view.privilege.ts";
|
|
26
|
+
import {
|
|
27
|
+
CreateSecurityLabelOnMaterializedView,
|
|
28
|
+
DropSecurityLabelOnMaterializedView,
|
|
29
|
+
} from "./changes/materialized-view.security-label.ts";
|
|
25
30
|
import type { MaterializedViewChange } from "./changes/materialized-view.types.ts";
|
|
26
31
|
import type { MaterializedView } from "./materialized-view.model.ts";
|
|
27
32
|
|
|
@@ -88,6 +93,17 @@ export function diffMaterializedViews(
|
|
|
88
93
|
}
|
|
89
94
|
}
|
|
90
95
|
|
|
96
|
+
// Security labels on the matview itself (columns of matviews are not
|
|
97
|
+
// supported targets of SECURITY LABEL, so we only label the relation).
|
|
98
|
+
for (const label of mv.security_labels) {
|
|
99
|
+
changes.push(
|
|
100
|
+
new CreateSecurityLabelOnMaterializedView({
|
|
101
|
+
materializedView: mv,
|
|
102
|
+
securityLabel: label,
|
|
103
|
+
}),
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
|
|
91
107
|
// PRIVILEGES: For created objects, compare against default privileges state
|
|
92
108
|
// The migration script will run ALTER DEFAULT PRIVILEGES before CREATE (via constraint spec),
|
|
93
109
|
// so objects are created with the default privileges state in effect.
|
|
@@ -241,6 +257,27 @@ export function diffMaterializedViews(
|
|
|
241
257
|
);
|
|
242
258
|
}
|
|
243
259
|
}
|
|
260
|
+
|
|
261
|
+
// SECURITY LABELS
|
|
262
|
+
changes.push(
|
|
263
|
+
...diffSecurityLabels<
|
|
264
|
+
| CreateSecurityLabelOnMaterializedView
|
|
265
|
+
| DropSecurityLabelOnMaterializedView
|
|
266
|
+
>(
|
|
267
|
+
mainMaterializedView.security_labels,
|
|
268
|
+
branchMaterializedView.security_labels,
|
|
269
|
+
(securityLabel) =>
|
|
270
|
+
new CreateSecurityLabelOnMaterializedView({
|
|
271
|
+
materializedView: branchMaterializedView,
|
|
272
|
+
securityLabel,
|
|
273
|
+
}),
|
|
274
|
+
(securityLabel) =>
|
|
275
|
+
new DropSecurityLabelOnMaterializedView({
|
|
276
|
+
materializedView: mainMaterializedView,
|
|
277
|
+
securityLabel,
|
|
278
|
+
}),
|
|
279
|
+
),
|
|
280
|
+
);
|
|
244
281
|
// COMMENT changes on columns
|
|
245
282
|
const mainCols = new Map(
|
|
246
283
|
mainMaterializedView.columns.map((c) => [c.name, c]),
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
import type { Pool } from "pg";
|
|
3
|
+
import {
|
|
4
|
+
extractMaterializedViews,
|
|
5
|
+
MaterializedView,
|
|
6
|
+
} from "./materialized-view.model.ts";
|
|
7
|
+
|
|
8
|
+
const baseRow = {
|
|
9
|
+
schema: "public",
|
|
10
|
+
row_security: false,
|
|
11
|
+
force_row_security: false,
|
|
12
|
+
has_indexes: false,
|
|
13
|
+
has_rules: false,
|
|
14
|
+
has_triggers: false,
|
|
15
|
+
has_subclasses: false,
|
|
16
|
+
is_populated: true,
|
|
17
|
+
replica_identity: "d" as const,
|
|
18
|
+
is_partition: false,
|
|
19
|
+
options: null,
|
|
20
|
+
partition_bound: null,
|
|
21
|
+
owner: "postgres",
|
|
22
|
+
comment: null,
|
|
23
|
+
columns: [],
|
|
24
|
+
privileges: [],
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const mockPool = (rows: unknown[]): Pool =>
|
|
28
|
+
({ query: async () => ({ rows }) }) as unknown as Pool;
|
|
29
|
+
|
|
30
|
+
const mockPoolSequence = (...attempts: unknown[][]): Pool => {
|
|
31
|
+
let i = 0;
|
|
32
|
+
return {
|
|
33
|
+
query: async () => ({
|
|
34
|
+
rows: attempts[Math.min(i++, attempts.length - 1)],
|
|
35
|
+
}),
|
|
36
|
+
} as unknown as Pool;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const NO_BACKOFF = { backoffMs: 0 } as const;
|
|
40
|
+
|
|
41
|
+
describe("extractMaterializedViews", () => {
|
|
42
|
+
test("skips rows where pg_get_viewdef returned NULL after exhausting retries", async () => {
|
|
43
|
+
const mvs = await extractMaterializedViews(
|
|
44
|
+
mockPool([
|
|
45
|
+
{
|
|
46
|
+
...baseRow,
|
|
47
|
+
name: '"good_mv"',
|
|
48
|
+
definition: "SELECT 1",
|
|
49
|
+
},
|
|
50
|
+
{ ...baseRow, name: '"orphan_mv"', definition: null },
|
|
51
|
+
]),
|
|
52
|
+
NO_BACKOFF,
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
expect(mvs).toHaveLength(1);
|
|
56
|
+
expect(mvs[0]).toBeInstanceOf(MaterializedView);
|
|
57
|
+
expect(mvs[0]?.name).toBe('"good_mv"');
|
|
58
|
+
expect(mvs[0]?.definition).toBe("SELECT 1");
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
test("does not throw ZodError when the only row has a null definition", async () => {
|
|
62
|
+
await expect(
|
|
63
|
+
extractMaterializedViews(
|
|
64
|
+
mockPool([{ ...baseRow, name: '"orphan"', definition: null }]),
|
|
65
|
+
NO_BACKOFF,
|
|
66
|
+
),
|
|
67
|
+
).resolves.toEqual([]);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
test("returns all materialized views when every row has a valid definition", async () => {
|
|
71
|
+
const mvs = await extractMaterializedViews(
|
|
72
|
+
mockPool([
|
|
73
|
+
{ ...baseRow, name: '"a"', definition: "SELECT 1" },
|
|
74
|
+
{ ...baseRow, name: '"b"', definition: "SELECT 2" },
|
|
75
|
+
]),
|
|
76
|
+
NO_BACKOFF,
|
|
77
|
+
);
|
|
78
|
+
expect(mvs.map((m) => m.name)).toEqual(['"a"', '"b"']);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
test("recovers when pg_get_viewdef is NULL on first attempt but resolved on retry", async () => {
|
|
82
|
+
const mvs = await extractMaterializedViews(
|
|
83
|
+
mockPoolSequence(
|
|
84
|
+
[{ ...baseRow, name: '"racy_mv"', definition: null }],
|
|
85
|
+
[{ ...baseRow, name: '"racy_mv"', definition: "SELECT 42" }],
|
|
86
|
+
),
|
|
87
|
+
{ retries: 2, backoffMs: 0 },
|
|
88
|
+
);
|
|
89
|
+
expect(mvs).toHaveLength(1);
|
|
90
|
+
expect(mvs[0]?.name).toBe('"racy_mv"');
|
|
91
|
+
expect(mvs[0]?.definition).toBe("SELECT 42");
|
|
92
|
+
});
|
|
93
|
+
});
|
|
@@ -10,6 +10,15 @@ import {
|
|
|
10
10
|
type PrivilegeProps,
|
|
11
11
|
privilegePropsSchema,
|
|
12
12
|
} from "../base.privilege-diff.ts";
|
|
13
|
+
import {
|
|
14
|
+
type ExtractRetryOptions,
|
|
15
|
+
extractWithDefinitionRetry,
|
|
16
|
+
} from "../extract-with-retry.ts";
|
|
17
|
+
import {
|
|
18
|
+
normalizeSecurityLabels,
|
|
19
|
+
type SecurityLabelProps,
|
|
20
|
+
securityLabelPropsSchema,
|
|
21
|
+
} from "../security-label.types.ts";
|
|
13
22
|
import { ReplicaIdentitySchema } from "../table/table.model.ts";
|
|
14
23
|
|
|
15
24
|
const materializedViewPropsSchema = z.object({
|
|
@@ -31,6 +40,16 @@ const materializedViewPropsSchema = z.object({
|
|
|
31
40
|
comment: z.string().nullable(),
|
|
32
41
|
columns: z.array(columnPropsSchema),
|
|
33
42
|
privileges: z.array(privilegePropsSchema),
|
|
43
|
+
security_labels: z.array(securityLabelPropsSchema).default([]).optional(),
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
// pg_get_viewdef(oid) can return NULL when the underlying matview (or its
|
|
47
|
+
// pg_rewrite row) is dropped between catalog scan and resolution, or under
|
|
48
|
+
// transient catalog state during recovery. An unreadable matview cannot be
|
|
49
|
+
// diffed, so we accept NULL here and filter the row out at extraction time
|
|
50
|
+
// rather than crashing the whole catalog parse with a ZodError.
|
|
51
|
+
const materializedViewRowSchema = materializedViewPropsSchema.extend({
|
|
52
|
+
definition: z.string().nullable(),
|
|
34
53
|
});
|
|
35
54
|
|
|
36
55
|
type MaterializedViewPrivilegeProps = PrivilegeProps;
|
|
@@ -55,6 +74,7 @@ export class MaterializedView extends BasePgModel implements TableLikeObject {
|
|
|
55
74
|
public readonly comment: MaterializedViewProps["comment"];
|
|
56
75
|
public readonly columns: MaterializedViewProps["columns"];
|
|
57
76
|
public readonly privileges: MaterializedViewPrivilegeProps[];
|
|
77
|
+
public readonly security_labels: SecurityLabelProps[];
|
|
58
78
|
|
|
59
79
|
constructor(props: MaterializedViewProps) {
|
|
60
80
|
super();
|
|
@@ -80,6 +100,7 @@ export class MaterializedView extends BasePgModel implements TableLikeObject {
|
|
|
80
100
|
this.comment = props.comment;
|
|
81
101
|
this.columns = props.columns;
|
|
82
102
|
this.privileges = props.privileges;
|
|
103
|
+
this.security_labels = props.security_labels ?? [];
|
|
83
104
|
}
|
|
84
105
|
|
|
85
106
|
get stableId(): `materializedView:${string}` {
|
|
@@ -111,6 +132,7 @@ export class MaterializedView extends BasePgModel implements TableLikeObject {
|
|
|
111
132
|
comment: this.comment,
|
|
112
133
|
columns: this.columns,
|
|
113
134
|
privileges: this.privileges,
|
|
135
|
+
security_labels: this.security_labels,
|
|
114
136
|
};
|
|
115
137
|
}
|
|
116
138
|
|
|
@@ -135,6 +157,7 @@ export class MaterializedView extends BasePgModel implements TableLikeObject {
|
|
|
135
157
|
data: {
|
|
136
158
|
...this.dataFields,
|
|
137
159
|
columns: normalizeColumns(),
|
|
160
|
+
security_labels: normalizeSecurityLabels(this.security_labels),
|
|
138
161
|
},
|
|
139
162
|
};
|
|
140
163
|
}
|
|
@@ -142,8 +165,14 @@ export class MaterializedView extends BasePgModel implements TableLikeObject {
|
|
|
142
165
|
|
|
143
166
|
export async function extractMaterializedViews(
|
|
144
167
|
pool: Pool,
|
|
168
|
+
options?: ExtractRetryOptions,
|
|
145
169
|
): Promise<MaterializedView[]> {
|
|
146
|
-
const
|
|
170
|
+
const mvRows = await extractWithDefinitionRetry({
|
|
171
|
+
label: "materialized views",
|
|
172
|
+
options,
|
|
173
|
+
hasNullDefinition: (row) => row.definition === null,
|
|
174
|
+
query: async () => {
|
|
175
|
+
const result = await pool.query<MaterializedViewProps>(sql`
|
|
147
176
|
with extension_oids as (
|
|
148
177
|
select
|
|
149
178
|
objid
|
|
@@ -233,7 +262,20 @@ select
|
|
|
233
262
|
join lateral aclexplode(src.acl) as x(grantor, grantee, privilege_type, is_grantable) on true
|
|
234
263
|
group by x.grantee, x.privilege_type
|
|
235
264
|
) as grp
|
|
236
|
-
), '[]') as privileges
|
|
265
|
+
), '[]') as privileges,
|
|
266
|
+
coalesce(
|
|
267
|
+
(
|
|
268
|
+
select json_agg(
|
|
269
|
+
json_build_object('provider', sl.provider, 'label', sl.label)
|
|
270
|
+
order by sl.provider
|
|
271
|
+
)
|
|
272
|
+
from pg_catalog.pg_seclabel sl
|
|
273
|
+
where sl.objoid = c.oid
|
|
274
|
+
and sl.classoid = 'pg_class'::regclass
|
|
275
|
+
and sl.objsubid = 0
|
|
276
|
+
),
|
|
277
|
+
'[]'::json
|
|
278
|
+
) as security_labels
|
|
237
279
|
from
|
|
238
280
|
pg_catalog.pg_class c
|
|
239
281
|
left outer join extension_oids e on c.oid = e.objid
|
|
@@ -248,11 +290,13 @@ group by
|
|
|
248
290
|
order by
|
|
249
291
|
c.relnamespace::regnamespace, c.relname
|
|
250
292
|
`);
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
293
|
+
return result.rows.map((row: unknown) =>
|
|
294
|
+
materializedViewRowSchema.parse(row),
|
|
295
|
+
);
|
|
296
|
+
},
|
|
297
|
+
});
|
|
298
|
+
const validatedRows = mvRows.filter(
|
|
299
|
+
(row): row is MaterializedViewProps => row.definition !== null,
|
|
257
300
|
);
|
|
301
|
+
return validatedRows.map((row) => new MaterializedView(row));
|
|
258
302
|
}
|
|
@@ -3,7 +3,11 @@ import type { Procedure } from "../procedure.model.ts";
|
|
|
3
3
|
|
|
4
4
|
abstract class BaseProcedureChange extends BaseChange {
|
|
5
5
|
abstract readonly procedure: Procedure;
|
|
6
|
-
abstract readonly scope:
|
|
6
|
+
abstract readonly scope:
|
|
7
|
+
| "object"
|
|
8
|
+
| "comment"
|
|
9
|
+
| "privilege"
|
|
10
|
+
| "security_label";
|
|
7
11
|
readonly objectType: "procedure" = "procedure";
|
|
8
12
|
}
|
|
9
13
|
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { quoteLiteral } from "../../base.change.ts";
|
|
2
|
+
import type { SecurityLabelProps } from "../../security-label.types.ts";
|
|
3
|
+
import { stableId } from "../../utils.ts";
|
|
4
|
+
import type { Procedure } from "../procedure.model.ts";
|
|
5
|
+
import {
|
|
6
|
+
CreateProcedureChange,
|
|
7
|
+
DropProcedureChange,
|
|
8
|
+
} from "./procedure.base.ts";
|
|
9
|
+
|
|
10
|
+
export type SecurityLabelProcedure =
|
|
11
|
+
| CreateSecurityLabelOnProcedure
|
|
12
|
+
| DropSecurityLabelOnProcedure;
|
|
13
|
+
|
|
14
|
+
function targetKeyword(p: Procedure): "FUNCTION" | "PROCEDURE" {
|
|
15
|
+
return p.kind === "p" ? "PROCEDURE" : "FUNCTION";
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function procedureIdentity(p: Procedure): string {
|
|
19
|
+
return `${p.schema}.${p.name}(${(p.argument_types ?? []).join(",")})`;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export class CreateSecurityLabelOnProcedure extends CreateProcedureChange {
|
|
23
|
+
public readonly procedure: Procedure;
|
|
24
|
+
public readonly securityLabel: SecurityLabelProps;
|
|
25
|
+
public readonly scope = "security_label" as const;
|
|
26
|
+
|
|
27
|
+
constructor(props: {
|
|
28
|
+
procedure: Procedure;
|
|
29
|
+
securityLabel: SecurityLabelProps;
|
|
30
|
+
}) {
|
|
31
|
+
super();
|
|
32
|
+
this.procedure = props.procedure;
|
|
33
|
+
this.securityLabel = props.securityLabel;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
get creates() {
|
|
37
|
+
return [
|
|
38
|
+
stableId.securityLabel(
|
|
39
|
+
this.procedure.stableId,
|
|
40
|
+
this.securityLabel.provider,
|
|
41
|
+
),
|
|
42
|
+
];
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
get requires() {
|
|
46
|
+
return [this.procedure.stableId];
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
serialize(): string {
|
|
50
|
+
return [
|
|
51
|
+
"SECURITY LABEL FOR",
|
|
52
|
+
this.securityLabel.provider,
|
|
53
|
+
"ON",
|
|
54
|
+
targetKeyword(this.procedure),
|
|
55
|
+
procedureIdentity(this.procedure),
|
|
56
|
+
"IS",
|
|
57
|
+
quoteLiteral(this.securityLabel.label),
|
|
58
|
+
].join(" ");
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export class DropSecurityLabelOnProcedure extends DropProcedureChange {
|
|
63
|
+
public readonly procedure: Procedure;
|
|
64
|
+
public readonly securityLabel: SecurityLabelProps;
|
|
65
|
+
public readonly scope = "security_label" as const;
|
|
66
|
+
|
|
67
|
+
constructor(props: {
|
|
68
|
+
procedure: Procedure;
|
|
69
|
+
securityLabel: SecurityLabelProps;
|
|
70
|
+
}) {
|
|
71
|
+
super();
|
|
72
|
+
this.procedure = props.procedure;
|
|
73
|
+
this.securityLabel = props.securityLabel;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
get drops() {
|
|
77
|
+
return [
|
|
78
|
+
stableId.securityLabel(
|
|
79
|
+
this.procedure.stableId,
|
|
80
|
+
this.securityLabel.provider,
|
|
81
|
+
),
|
|
82
|
+
];
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
get requires() {
|
|
86
|
+
return [
|
|
87
|
+
stableId.securityLabel(
|
|
88
|
+
this.procedure.stableId,
|
|
89
|
+
this.securityLabel.provider,
|
|
90
|
+
),
|
|
91
|
+
this.procedure.stableId,
|
|
92
|
+
];
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
serialize(): string {
|
|
96
|
+
return [
|
|
97
|
+
"SECURITY LABEL FOR",
|
|
98
|
+
this.securityLabel.provider,
|
|
99
|
+
"ON",
|
|
100
|
+
targetKeyword(this.procedure),
|
|
101
|
+
procedureIdentity(this.procedure),
|
|
102
|
+
"IS NULL",
|
|
103
|
+
].join(" ");
|
|
104
|
+
}
|
|
105
|
+
}
|
|
@@ -3,6 +3,7 @@ import type { CommentProcedure } from "./procedure.comment.ts";
|
|
|
3
3
|
import type { CreateProcedure } from "./procedure.create.ts";
|
|
4
4
|
import type { DropProcedure } from "./procedure.drop.ts";
|
|
5
5
|
import type { ProcedurePrivilege } from "./procedure.privilege.ts";
|
|
6
|
+
import type { SecurityLabelProcedure } from "./procedure.security-label.ts";
|
|
6
7
|
|
|
7
8
|
/** Union of all procedure-related change variants (`objectType: "procedure"`). @category Change Types */
|
|
8
9
|
export type ProcedureChange =
|
|
@@ -10,4 +11,5 @@ export type ProcedureChange =
|
|
|
10
11
|
| CommentProcedure
|
|
11
12
|
| CreateProcedure
|
|
12
13
|
| DropProcedure
|
|
13
|
-
| ProcedurePrivilege
|
|
14
|
+
| ProcedurePrivilege
|
|
15
|
+
| SecurityLabelProcedure;
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
filterPublicBuiltInDefaults,
|
|
6
6
|
} from "../base.privilege-diff.ts";
|
|
7
7
|
import type { ObjectDiffContext } from "../diff-context.ts";
|
|
8
|
+
import { diffSecurityLabels } from "../security-label.types.ts";
|
|
8
9
|
import { deepEqual, hasNonAlterableChanges } from "../utils.ts";
|
|
9
10
|
import {
|
|
10
11
|
AlterProcedureChangeOwner,
|
|
@@ -26,6 +27,10 @@ import {
|
|
|
26
27
|
RevokeGrantOptionProcedurePrivileges,
|
|
27
28
|
RevokeProcedurePrivileges,
|
|
28
29
|
} from "./changes/procedure.privilege.ts";
|
|
30
|
+
import {
|
|
31
|
+
CreateSecurityLabelOnProcedure,
|
|
32
|
+
DropSecurityLabelOnProcedure,
|
|
33
|
+
} from "./changes/procedure.security-label.ts";
|
|
29
34
|
import type { ProcedureChange } from "./changes/procedure.types.ts";
|
|
30
35
|
import type { Procedure } from "./procedure.model.ts";
|
|
31
36
|
|
|
@@ -66,6 +71,14 @@ export function diffProcedures(
|
|
|
66
71
|
if (proc.comment !== null) {
|
|
67
72
|
changes.push(new CreateCommentOnProcedure({ procedure: proc }));
|
|
68
73
|
}
|
|
74
|
+
for (const label of proc.security_labels) {
|
|
75
|
+
changes.push(
|
|
76
|
+
new CreateSecurityLabelOnProcedure({
|
|
77
|
+
procedure: proc,
|
|
78
|
+
securityLabel: label,
|
|
79
|
+
}),
|
|
80
|
+
);
|
|
81
|
+
}
|
|
69
82
|
|
|
70
83
|
// PRIVILEGES: For created objects, compare against default privileges state
|
|
71
84
|
// The migration script will run ALTER DEFAULT PRIVILEGES before CREATE (via constraint spec),
|
|
@@ -225,6 +238,26 @@ export function diffProcedures(
|
|
|
225
238
|
}
|
|
226
239
|
}
|
|
227
240
|
|
|
241
|
+
// SECURITY LABELS
|
|
242
|
+
changes.push(
|
|
243
|
+
...diffSecurityLabels<
|
|
244
|
+
CreateSecurityLabelOnProcedure | DropSecurityLabelOnProcedure
|
|
245
|
+
>(
|
|
246
|
+
mainProcedure.security_labels,
|
|
247
|
+
branchProcedure.security_labels,
|
|
248
|
+
(securityLabel) =>
|
|
249
|
+
new CreateSecurityLabelOnProcedure({
|
|
250
|
+
procedure: branchProcedure,
|
|
251
|
+
securityLabel,
|
|
252
|
+
}),
|
|
253
|
+
(securityLabel) =>
|
|
254
|
+
new DropSecurityLabelOnProcedure({
|
|
255
|
+
procedure: mainProcedure,
|
|
256
|
+
securityLabel,
|
|
257
|
+
}),
|
|
258
|
+
),
|
|
259
|
+
);
|
|
260
|
+
|
|
228
261
|
// SECURITY DEFINER/INVOKER
|
|
229
262
|
if (mainProcedure.security_definer !== branchProcedure.security_definer) {
|
|
230
263
|
changes.push(
|