@supabase/pg-delta 1.0.0-alpha.22 → 1.0.0-alpha.24
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.model.js +1 -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/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/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 +22 -0
- package/dist/core/objects/materialized-view/materialized-view.model.js +20 -1
- 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 +10 -0
- package/dist/core/objects/procedure/procedure.model.js +19 -1
- 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/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/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.js +16 -0
- 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.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 +49 -0
- package/dist/core/objects/table/table.model.d.ts +30 -0
- package/dist/core/objects/table/table.model.js +34 -2
- 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 +1 -0
- package/dist/core/objects/utils.js +3 -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 +26 -0
- package/dist/core/objects/view/view.model.js +20 -1
- package/dist/core/plan/sql-format/fixtures.js +1 -0
- package/dist/core/post-diff-normalization.d.ts +7 -0
- package/dist/core/post-diff-normalization.js +33 -4
- package/dist/core/sort/cycle-breakers.js +139 -17
- package/package.json +1 -1
- package/src/core/catalog.model.ts +1 -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/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/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.ts +25 -4
- 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.ts +23 -2
- 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/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/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.ts +33 -0
- 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.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 +87 -0
- package/src/core/objects/table/table.model.ts +42 -2
- 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 +3 -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.ts +25 -2
- package/src/core/plan/sql-format/fixtures.ts +1 -0
- package/src/core/post-diff-normalization.test.ts +123 -0
- package/src/core/post-diff-normalization.ts +40 -4
- package/src/core/sort/cycle-breakers.test.ts +236 -2
- package/src/core/sort/cycle-breakers.ts +184 -24
- package/src/core/sort/sort-changes.test.ts +317 -0
|
@@ -3,6 +3,7 @@ import z from "zod";
|
|
|
3
3
|
import { BasePgModel, columnPropsSchema, normalizeColumns, } from "../base.model.js";
|
|
4
4
|
import { privilegePropsSchema, } from "../base.privilege-diff.js";
|
|
5
5
|
import { extractWithDefinitionRetry, } from "../extract-with-retry.js";
|
|
6
|
+
import { normalizeSecurityLabels, securityLabelPropsSchema, } from "../security-label.types.js";
|
|
6
7
|
import { ReplicaIdentitySchema } from "../table/table.model.js";
|
|
7
8
|
const viewPropsSchema = z.object({
|
|
8
9
|
schema: z.string(),
|
|
@@ -23,6 +24,7 @@ const viewPropsSchema = z.object({
|
|
|
23
24
|
comment: z.string().nullable(),
|
|
24
25
|
columns: z.array(columnPropsSchema),
|
|
25
26
|
privileges: z.array(privilegePropsSchema),
|
|
27
|
+
security_labels: z.array(securityLabelPropsSchema).default([]).optional(),
|
|
26
28
|
});
|
|
27
29
|
// pg_get_viewdef(oid) can return NULL when the underlying view (or its
|
|
28
30
|
// pg_rewrite row) is dropped between catalog scan and resolution, or under
|
|
@@ -51,6 +53,7 @@ export class View extends BasePgModel {
|
|
|
51
53
|
comment;
|
|
52
54
|
columns;
|
|
53
55
|
privileges;
|
|
56
|
+
security_labels;
|
|
54
57
|
constructor(props) {
|
|
55
58
|
super();
|
|
56
59
|
// Identity fields
|
|
@@ -73,6 +76,7 @@ export class View extends BasePgModel {
|
|
|
73
76
|
this.comment = props.comment;
|
|
74
77
|
this.columns = props.columns;
|
|
75
78
|
this.privileges = props.privileges;
|
|
79
|
+
this.security_labels = props.security_labels ?? [];
|
|
76
80
|
}
|
|
77
81
|
get stableId() {
|
|
78
82
|
return `view:${this.schema}.${this.name}`;
|
|
@@ -101,6 +105,7 @@ export class View extends BasePgModel {
|
|
|
101
105
|
comment: this.comment,
|
|
102
106
|
columns: this.columns,
|
|
103
107
|
privileges: this.privileges,
|
|
108
|
+
security_labels: this.security_labels,
|
|
104
109
|
};
|
|
105
110
|
}
|
|
106
111
|
stableSnapshot() {
|
|
@@ -109,6 +114,7 @@ export class View extends BasePgModel {
|
|
|
109
114
|
data: {
|
|
110
115
|
...this.dataFields,
|
|
111
116
|
columns: normalizeColumns(this.columns),
|
|
117
|
+
security_labels: normalizeSecurityLabels(this.security_labels),
|
|
112
118
|
},
|
|
113
119
|
};
|
|
114
120
|
}
|
|
@@ -235,7 +241,20 @@ select
|
|
|
235
241
|
join lateral aclexplode(src.acl) as x(grantor, grantee, privilege_type, is_grantable) on true
|
|
236
242
|
group by x.grantee, x.privilege_type
|
|
237
243
|
) as grp
|
|
238
|
-
), '[]') as privileges
|
|
244
|
+
), '[]') as privileges,
|
|
245
|
+
coalesce(
|
|
246
|
+
(
|
|
247
|
+
select json_agg(
|
|
248
|
+
json_build_object('provider', sl.provider, 'label', sl.label)
|
|
249
|
+
order by sl.provider
|
|
250
|
+
)
|
|
251
|
+
from pg_catalog.pg_seclabel sl
|
|
252
|
+
where sl.objoid = v.oid
|
|
253
|
+
and sl.classoid = 'pg_class'::regclass
|
|
254
|
+
and sl.objsubid = 0
|
|
255
|
+
),
|
|
256
|
+
'[]'::json
|
|
257
|
+
) as security_labels
|
|
239
258
|
from
|
|
240
259
|
views v
|
|
241
260
|
left join pg_attribute a on a.attrelid = v.oid and a.attnum > 0 and not a.attisdropped
|
|
@@ -15,6 +15,13 @@ import type { Table } from "./objects/table/table.model.ts";
|
|
|
15
15
|
* `DropTable(T) + CreateTable(T)` pair. Without this, the apply phase
|
|
16
16
|
* would try to drop a column that no longer exists in the freshly
|
|
17
17
|
* recreated table.
|
|
18
|
+
* - Prunes `DropSequence(S)` changes when `S` is `OWNED BY` a column on a
|
|
19
|
+
* table promoted to `DropTable + CreateTable` by the expander. The
|
|
20
|
+
* `DROP TABLE` cascade drops the sequence at apply time; emitting an
|
|
21
|
+
* explicit `DROP SEQUENCE` in the same drop phase both duplicates the
|
|
22
|
+
* cascade and forms an unbreakable `DropSequence ↔ DropTable` cycle on
|
|
23
|
+
* the bidirectional pg_depend edges between the sequence and the
|
|
24
|
+
* owning column.
|
|
18
25
|
* - Dedupes duplicate `AlterTableAddConstraint` /
|
|
19
26
|
* `AlterTableValidateConstraint` / `CreateCommentOnConstraint` changes
|
|
20
27
|
* produced when `diffTables()` and `expandReplaceDependencies()` both
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { CreateIndex } from "./objects/index/changes/index.create.js";
|
|
2
2
|
import { DropIndex } from "./objects/index/changes/index.drop.js";
|
|
3
|
+
import { DropSequence } from "./objects/sequence/changes/sequence.drop.js";
|
|
3
4
|
import { AlterTableAddConstraint, AlterTableDropColumn, AlterTableDropConstraint, AlterTableSetReplicaIdentity, AlterTableValidateConstraint, } from "./objects/table/changes/table.alter.js";
|
|
4
5
|
import { CreateCommentOnConstraint } from "./objects/table/changes/table.comment.js";
|
|
5
6
|
import { stableId } from "./objects/utils.js";
|
|
@@ -7,11 +8,32 @@ function constraintStableId(table, constraintName) {
|
|
|
7
8
|
return stableId.constraint(table.schema, table.name, constraintName);
|
|
8
9
|
}
|
|
9
10
|
function isSupersededByTableReplacement(change, replacedTableIds) {
|
|
10
|
-
if (
|
|
11
|
-
|
|
12
|
-
return
|
|
11
|
+
if (change instanceof AlterTableDropColumn ||
|
|
12
|
+
change instanceof AlterTableDropConstraint) {
|
|
13
|
+
return replacedTableIds.has(change.table.stableId);
|
|
13
14
|
}
|
|
14
|
-
|
|
15
|
+
// `DropSequence(S)` is superseded when S is OWNED BY a column on a table
|
|
16
|
+
// that `expandReplaceDependencies` has promoted to `DropTable + CreateTable`
|
|
17
|
+
// in the same plan. PostgreSQL cascade-drops the OWNED BY sequence as part
|
|
18
|
+
// of the DROP TABLE, so the explicit DROP SEQUENCE is redundant and — more
|
|
19
|
+
// importantly — closes an unbreakable `DropSequence ↔ DropTable` cycle in
|
|
20
|
+
// the drop phase via the bidirectional pg_depend edges between the
|
|
21
|
+
// sequence and its owning column (`column → sequence` for the DEFAULT
|
|
22
|
+
// nextval reference, `sequence → column` for the OWNED BY auto-dependency).
|
|
23
|
+
// The alpha.15 short-circuit in `diffSequences.dropped` only suppresses
|
|
24
|
+
// `DropSequence` when the owning table itself is gone from `branchTables`;
|
|
25
|
+
// here the table survives in branch and the replacement is added later by
|
|
26
|
+
// the expander, so this whole-plan rewrite has to happen post-diff.
|
|
27
|
+
if (change instanceof DropSequence) {
|
|
28
|
+
if (!change.sequence.owned_by_schema ||
|
|
29
|
+
!change.sequence.owned_by_table ||
|
|
30
|
+
!change.sequence.owned_by_column) {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
const ownedByTableId = stableId.table(change.sequence.owned_by_schema, change.sequence.owned_by_table);
|
|
34
|
+
return replacedTableIds.has(ownedByTableId);
|
|
35
|
+
}
|
|
36
|
+
return false;
|
|
15
37
|
}
|
|
16
38
|
/**
|
|
17
39
|
* Drop earlier duplicates of `AlterTableAddConstraint` /
|
|
@@ -179,6 +201,13 @@ function restoreReplicaIdentityAfterIndexReplace(changes, branchTables) {
|
|
|
179
201
|
* `DropTable(T) + CreateTable(T)` pair. Without this, the apply phase
|
|
180
202
|
* would try to drop a column that no longer exists in the freshly
|
|
181
203
|
* recreated table.
|
|
204
|
+
* - Prunes `DropSequence(S)` changes when `S` is `OWNED BY` a column on a
|
|
205
|
+
* table promoted to `DropTable + CreateTable` by the expander. The
|
|
206
|
+
* `DROP TABLE` cascade drops the sequence at apply time; emitting an
|
|
207
|
+
* explicit `DROP SEQUENCE` in the same drop phase both duplicates the
|
|
208
|
+
* cascade and forms an unbreakable `DropSequence ↔ DropTable` cycle on
|
|
209
|
+
* the bidirectional pg_depend edges between the sequence and the
|
|
210
|
+
* owning column.
|
|
182
211
|
* - Dedupes duplicate `AlterTableAddConstraint` /
|
|
183
212
|
* `AlterTableValidateConstraint` / `CreateCommentOnConstraint` changes
|
|
184
213
|
* produced when `diffTables()` and `expandReplaceDependencies()` both
|
|
@@ -66,6 +66,32 @@ export function tryBreakCycleByChangeInjection(cycleNodeIndexes, phaseChanges) {
|
|
|
66
66
|
const pubColBroken = tryBreakPublicationColumnCycle(cycleNodeIndexes, phaseChanges);
|
|
67
67
|
if (pubColBroken)
|
|
68
68
|
return pubColBroken;
|
|
69
|
+
// ─── Branch C: Publication ↔ dropped FK chain ↔ constraint drop ──────
|
|
70
|
+
// Triggered when publication membership is being removed for tables in
|
|
71
|
+
// the same drop phase as a FK chain, and the chain ends at a separately
|
|
72
|
+
// emitted `AlterTableDropConstraint` on a table that is also being
|
|
73
|
+
// removed from the publication.
|
|
74
|
+
//
|
|
75
|
+
// Example (4-change cycle):
|
|
76
|
+
// AlterPublicationDropTables(p, [labs, posts, post_attachments])
|
|
77
|
+
// DropTable(post_attachments)
|
|
78
|
+
// DropTable(posts)
|
|
79
|
+
// AlterTableDropConstraint(labs.unique_lab_id)
|
|
80
|
+
//
|
|
81
|
+
// Cycle:
|
|
82
|
+
// publication:p → table:post_attachments
|
|
83
|
+
// post_attachments.post_id_fkey → column:posts.id
|
|
84
|
+
// posts.lab_id_fkey → constraint:labs.unique_lab_id
|
|
85
|
+
// constraint:labs.unique_lab_id → table:labs
|
|
86
|
+
//
|
|
87
|
+
// Fix: inject explicit FK drops for the FK constraints claimed by the
|
|
88
|
+
// DropTables in the cycle, including FKs that point at the terminal
|
|
89
|
+
// dropped constraint. The publication and terminal constraint changes
|
|
90
|
+
// stay unchanged; only the intermediate FK ownership is reassigned from
|
|
91
|
+
// DropTable to dedicated AlterTableDropConstraint changes.
|
|
92
|
+
const pubFkConstraintBroken = tryBreakPublicationFkConstraintDropCycle(cycleNodeIndexes, phaseChanges);
|
|
93
|
+
if (pubFkConstraintBroken)
|
|
94
|
+
return pubFkConstraintBroken;
|
|
69
95
|
// No known pattern. Returning null lets sortPhaseChanges throw the
|
|
70
96
|
// formatted CycleError with full diagnostic — better a clear bug
|
|
71
97
|
// report than silently shipping a broken plan.
|
|
@@ -90,6 +116,19 @@ function tryBreakFkCycle(cycleNodeIndexes, phaseChanges) {
|
|
|
90
116
|
cycleDropTables.push(change);
|
|
91
117
|
}
|
|
92
118
|
const cycleTableIds = new Set(cycleDropTables.map((change) => change.table.stableId));
|
|
119
|
+
return injectFkConstraintDropsForDropTables({
|
|
120
|
+
phaseChanges,
|
|
121
|
+
dropTables: cycleDropTables,
|
|
122
|
+
shouldInject: (fk, tableId) => isCrossCycleFkConstraint(fk, tableId, cycleTableIds),
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Shared FK-drop injection used by Branch A and Branch C. The caller owns
|
|
127
|
+
* the cycle-specific matcher; this helper only handles the mechanical
|
|
128
|
+
* rewrite: add dedicated `AlterTableDropConstraint` changes and rebuild
|
|
129
|
+
* affected `DropTable`s with updated `externallyDroppedConstraints`.
|
|
130
|
+
*/
|
|
131
|
+
function injectFkConstraintDropsForDropTables({ phaseChanges, dropTables, shouldInject, }) {
|
|
93
132
|
// For each DropTable in the cycle, find every FK whose referenced table
|
|
94
133
|
// is also in the cycle. Each such FK becomes one injected
|
|
95
134
|
// `AlterTableDropConstraint` and one entry on the source table's
|
|
@@ -100,11 +139,13 @@ function tryBreakFkCycle(cycleNodeIndexes, phaseChanges) {
|
|
|
100
139
|
const injectedDropsByTableId = new Map();
|
|
101
140
|
const updatedExternalsByTableId = new Map();
|
|
102
141
|
let didMutate = false;
|
|
103
|
-
for (const dropTable of
|
|
142
|
+
for (const dropTable of dropTables) {
|
|
104
143
|
const tableId = dropTable.table.stableId;
|
|
105
144
|
const existingExternals = new Set(dropTable.externallyDroppedConstraints);
|
|
106
145
|
let tableMutated = false;
|
|
107
|
-
for (const fk of
|
|
146
|
+
for (const fk of iterFkConstraints(dropTable.table.constraints)) {
|
|
147
|
+
if (!shouldInject(fk, tableId))
|
|
148
|
+
continue;
|
|
108
149
|
// Skip if a same-table `AlterTableDropConstraint` is already in the
|
|
109
150
|
// change list — could happen if a previous breaker iteration
|
|
110
151
|
// injected one, or the diff layer emitted one explicitly.
|
|
@@ -159,31 +200,37 @@ function tryBreakFkCycle(cycleNodeIndexes, phaseChanges) {
|
|
|
159
200
|
return rewritten;
|
|
160
201
|
}
|
|
161
202
|
/**
|
|
162
|
-
* Yield FK constraints on `constraints
|
|
163
|
-
* member of the cycle (i.e. an FK strictly between two cycle DropTables).
|
|
203
|
+
* Yield FK constraints on `constraints`.
|
|
164
204
|
*
|
|
165
|
-
*
|
|
166
|
-
*
|
|
167
|
-
* own; injecting an `AlterTableDropConstraint` for a self-FK would just
|
|
168
|
-
* add noise.
|
|
205
|
+
* Partition clones are skipped because PostgreSQL drops them when the
|
|
206
|
+
* parent constraint is dropped.
|
|
169
207
|
*/
|
|
170
|
-
function*
|
|
208
|
+
function* iterFkConstraints(constraints) {
|
|
171
209
|
for (const constraint of constraints) {
|
|
172
210
|
if (constraint.constraint_type !== "f")
|
|
173
211
|
continue;
|
|
174
212
|
if (constraint.is_partition_clone)
|
|
175
213
|
continue;
|
|
176
|
-
if (!constraint.foreign_key_schema || !constraint.foreign_key_table) {
|
|
177
|
-
continue;
|
|
178
|
-
}
|
|
179
|
-
const referencedId = stableId.table(constraint.foreign_key_schema, constraint.foreign_key_table);
|
|
180
|
-
if (referencedId === ownTableId)
|
|
181
|
-
continue;
|
|
182
|
-
if (!cycleTableIds.has(referencedId))
|
|
183
|
-
continue;
|
|
184
214
|
yield constraint;
|
|
185
215
|
}
|
|
186
216
|
}
|
|
217
|
+
/**
|
|
218
|
+
* True when `constraint` references another DropTable in the cycle.
|
|
219
|
+
*
|
|
220
|
+
* Self-referencing FKs are skipped — they create a self-loop in the
|
|
221
|
+
* dependency graph which the existing sort-phase handler resolves on its
|
|
222
|
+
* own; injecting an `AlterTableDropConstraint` for a self-FK would just
|
|
223
|
+
* add noise.
|
|
224
|
+
*/
|
|
225
|
+
function isCrossCycleFkConstraint(constraint, ownTableId, cycleTableIds) {
|
|
226
|
+
if (!constraint.foreign_key_schema || !constraint.foreign_key_table) {
|
|
227
|
+
return false;
|
|
228
|
+
}
|
|
229
|
+
const referencedId = stableId.table(constraint.foreign_key_schema, constraint.foreign_key_table);
|
|
230
|
+
if (referencedId === ownTableId)
|
|
231
|
+
return false;
|
|
232
|
+
return cycleTableIds.has(referencedId);
|
|
233
|
+
}
|
|
187
234
|
/**
|
|
188
235
|
* True iff `phaseChanges` already contains an explicit
|
|
189
236
|
* `AlterTableDropConstraint(table, constraint)` for the given pair —
|
|
@@ -267,3 +314,78 @@ function tryBreakPublicationColumnCycle(cycleNodeIndexes, phaseChanges) {
|
|
|
267
314
|
});
|
|
268
315
|
return rewritten;
|
|
269
316
|
}
|
|
317
|
+
/**
|
|
318
|
+
* Branch C worker — break a publication membership removal cycle where
|
|
319
|
+
* dropped tables form a FK chain ending at a separately dropped referenced
|
|
320
|
+
* constraint.
|
|
321
|
+
*/
|
|
322
|
+
function tryBreakPublicationFkConstraintDropCycle(cycleNodeIndexes, phaseChanges) {
|
|
323
|
+
let pubChange = null;
|
|
324
|
+
let terminalConstraintDrop = null;
|
|
325
|
+
const dropTables = [];
|
|
326
|
+
for (const nodeIndex of cycleNodeIndexes) {
|
|
327
|
+
const change = phaseChanges[nodeIndex];
|
|
328
|
+
if (change instanceof AlterPublicationDropTables) {
|
|
329
|
+
if (pubChange !== null)
|
|
330
|
+
return null;
|
|
331
|
+
pubChange = change;
|
|
332
|
+
}
|
|
333
|
+
else if (change instanceof AlterTableDropConstraint) {
|
|
334
|
+
if (terminalConstraintDrop !== null)
|
|
335
|
+
return null;
|
|
336
|
+
terminalConstraintDrop = change;
|
|
337
|
+
}
|
|
338
|
+
else if (change instanceof DropTable) {
|
|
339
|
+
dropTables.push(change);
|
|
340
|
+
}
|
|
341
|
+
else {
|
|
342
|
+
return null;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
if (pubChange === null ||
|
|
346
|
+
terminalConstraintDrop === null ||
|
|
347
|
+
dropTables.length === 0) {
|
|
348
|
+
return null;
|
|
349
|
+
}
|
|
350
|
+
const publicationTableIds = new Set(pubChange.tables.map((table) => stableId.table(table.schema, table.name)));
|
|
351
|
+
if (!publicationTableIds.has(terminalConstraintDrop.table.stableId)) {
|
|
352
|
+
return null;
|
|
353
|
+
}
|
|
354
|
+
for (const dropTable of dropTables) {
|
|
355
|
+
if (!publicationTableIds.has(dropTable.table.stableId))
|
|
356
|
+
return null;
|
|
357
|
+
}
|
|
358
|
+
const cycleDropTableIds = new Set(dropTables.map((change) => change.table.stableId));
|
|
359
|
+
let hasFkToTerminalConstraint = false;
|
|
360
|
+
for (const dropTable of dropTables) {
|
|
361
|
+
for (const fk of iterFkConstraints(dropTable.table.constraints)) {
|
|
362
|
+
if (fkReferencesConstraint(fk, terminalConstraintDrop)) {
|
|
363
|
+
hasFkToTerminalConstraint = true;
|
|
364
|
+
break;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
if (hasFkToTerminalConstraint)
|
|
368
|
+
break;
|
|
369
|
+
}
|
|
370
|
+
if (!hasFkToTerminalConstraint)
|
|
371
|
+
return null;
|
|
372
|
+
return injectFkConstraintDropsForDropTables({
|
|
373
|
+
phaseChanges,
|
|
374
|
+
dropTables,
|
|
375
|
+
shouldInject: (fk, tableId) => isCrossCycleFkConstraint(fk, tableId, cycleDropTableIds) ||
|
|
376
|
+
fkReferencesConstraint(fk, terminalConstraintDrop),
|
|
377
|
+
});
|
|
378
|
+
}
|
|
379
|
+
function fkReferencesConstraint(fk, constraintDrop) {
|
|
380
|
+
if (fk.foreign_key_schema !== constraintDrop.table.schema ||
|
|
381
|
+
fk.foreign_key_table !== constraintDrop.table.name ||
|
|
382
|
+
fk.foreign_key_columns === null) {
|
|
383
|
+
return false;
|
|
384
|
+
}
|
|
385
|
+
return sameOrderedStrings(fk.foreign_key_columns, constraintDrop.constraint.key_columns);
|
|
386
|
+
}
|
|
387
|
+
function sameOrderedStrings(left, right) {
|
|
388
|
+
if (left.length !== right.length)
|
|
389
|
+
return false;
|
|
390
|
+
return left.every((value, index) => value === right[index]);
|
|
391
|
+
}
|
package/package.json
CHANGED
|
@@ -41,6 +41,16 @@ const membershipChange = {
|
|
|
41
41
|
requires: [],
|
|
42
42
|
} as unknown as Change;
|
|
43
43
|
|
|
44
|
+
const securityLabelChange = {
|
|
45
|
+
objectType: "schema",
|
|
46
|
+
operation: "create",
|
|
47
|
+
scope: "security_label",
|
|
48
|
+
schema: { name: "labeled" },
|
|
49
|
+
securityLabel: { provider: "dummy", label: "classified" },
|
|
50
|
+
requires: ["schema:labeled"],
|
|
51
|
+
creates: ["security_label:schema:labeled:dummy"],
|
|
52
|
+
} as unknown as Change;
|
|
53
|
+
|
|
44
54
|
describe("evaluatePattern", () => {
|
|
45
55
|
describe("bare key matching (top-level properties)", () => {
|
|
46
56
|
test("objectType match", () => {
|
|
@@ -242,6 +252,23 @@ describe("evaluatePattern", () => {
|
|
|
242
252
|
});
|
|
243
253
|
});
|
|
244
254
|
|
|
255
|
+
describe("security label matching", () => {
|
|
256
|
+
test("provider matches security label changes", () => {
|
|
257
|
+
expect(
|
|
258
|
+
evaluatePattern(
|
|
259
|
+
{ scope: "security_label", provider: "dummy" },
|
|
260
|
+
securityLabelChange,
|
|
261
|
+
),
|
|
262
|
+
).toBe(true);
|
|
263
|
+
expect(
|
|
264
|
+
evaluatePattern(
|
|
265
|
+
{ scope: "security_label", provider: "other" },
|
|
266
|
+
securityLabelChange,
|
|
267
|
+
),
|
|
268
|
+
).toBe(false);
|
|
269
|
+
});
|
|
270
|
+
});
|
|
271
|
+
|
|
245
272
|
describe("composition patterns", () => {
|
|
246
273
|
test("not negates a pattern", () => {
|
|
247
274
|
expect(
|
|
@@ -105,6 +105,22 @@ export function flattenChange(change: Change): Record<string, FlatValue> {
|
|
|
105
105
|
flat[`${prefix}/${subKey}`] = flatVal;
|
|
106
106
|
}
|
|
107
107
|
}
|
|
108
|
+
} else if (
|
|
109
|
+
key === "securityLabel" &&
|
|
110
|
+
value &&
|
|
111
|
+
typeof value === "object" &&
|
|
112
|
+
!Array.isArray(value)
|
|
113
|
+
) {
|
|
114
|
+
// Security labels are change-level metadata, so expose provider/label as
|
|
115
|
+
// bare keys for filters like { scope: "security_label", provider: "..." }.
|
|
116
|
+
for (const [subKey, subValue] of Object.entries(
|
|
117
|
+
value as Record<string, unknown>,
|
|
118
|
+
)) {
|
|
119
|
+
const flatVal = toFlatValue(subValue);
|
|
120
|
+
if (flatVal !== undefined) {
|
|
121
|
+
flat[subKey] = flatVal;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
108
124
|
} else {
|
|
109
125
|
const flatVal = toFlatValue(value);
|
|
110
126
|
if (flatVal !== undefined) {
|
|
@@ -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 type { Aggregate } from "./aggregate.model.ts";
|
|
10
11
|
import { AlterAggregateChangeOwner } from "./changes/aggregate.alter.ts";
|
|
@@ -19,6 +20,10 @@ import {
|
|
|
19
20
|
RevokeAggregatePrivileges,
|
|
20
21
|
RevokeGrantOptionAggregatePrivileges,
|
|
21
22
|
} from "./changes/aggregate.privilege.ts";
|
|
23
|
+
import {
|
|
24
|
+
CreateSecurityLabelOnAggregate,
|
|
25
|
+
DropSecurityLabelOnAggregate,
|
|
26
|
+
} from "./changes/aggregate.security-label.ts";
|
|
22
27
|
import type { AggregateChange } from "./changes/aggregate.types.ts";
|
|
23
28
|
|
|
24
29
|
export function diffAggregates(
|
|
@@ -51,6 +56,14 @@ export function diffAggregates(
|
|
|
51
56
|
if (aggregate.comment !== null) {
|
|
52
57
|
changes.push(new CreateCommentOnAggregate({ aggregate }));
|
|
53
58
|
}
|
|
59
|
+
for (const label of aggregate.security_labels) {
|
|
60
|
+
changes.push(
|
|
61
|
+
new CreateSecurityLabelOnAggregate({
|
|
62
|
+
aggregate,
|
|
63
|
+
securityLabel: label,
|
|
64
|
+
}),
|
|
65
|
+
);
|
|
66
|
+
}
|
|
54
67
|
|
|
55
68
|
// PRIVILEGES: For created objects, compare against default privileges state
|
|
56
69
|
// The migration script will run ALTER DEFAULT PRIVILEGES before CREATE (via constraint spec),
|
|
@@ -182,6 +195,26 @@ export function diffAggregates(
|
|
|
182
195
|
}
|
|
183
196
|
}
|
|
184
197
|
|
|
198
|
+
// SECURITY LABELS
|
|
199
|
+
changes.push(
|
|
200
|
+
...diffSecurityLabels<
|
|
201
|
+
CreateSecurityLabelOnAggregate | DropSecurityLabelOnAggregate
|
|
202
|
+
>(
|
|
203
|
+
mainAggregate.security_labels,
|
|
204
|
+
branchAggregate.security_labels,
|
|
205
|
+
(securityLabel) =>
|
|
206
|
+
new CreateSecurityLabelOnAggregate({
|
|
207
|
+
aggregate: branchAggregate,
|
|
208
|
+
securityLabel,
|
|
209
|
+
}),
|
|
210
|
+
(securityLabel) =>
|
|
211
|
+
new DropSecurityLabelOnAggregate({
|
|
212
|
+
aggregate: mainAggregate,
|
|
213
|
+
securityLabel,
|
|
214
|
+
}),
|
|
215
|
+
),
|
|
216
|
+
);
|
|
217
|
+
|
|
185
218
|
// PRIVILEGES
|
|
186
219
|
// Filter out PUBLIC's built-in default EXECUTE privilege from main catalog
|
|
187
220
|
// (PostgreSQL grants it automatically, so we shouldn't compare it)
|
|
@@ -6,6 +6,10 @@ import {
|
|
|
6
6
|
type PrivilegeProps,
|
|
7
7
|
privilegePropsSchema,
|
|
8
8
|
} from "../base.privilege-diff.ts";
|
|
9
|
+
import {
|
|
10
|
+
type SecurityLabelProps,
|
|
11
|
+
securityLabelPropsSchema,
|
|
12
|
+
} from "../security-label.types.ts";
|
|
9
13
|
|
|
10
14
|
const AggregateKindSchema = z.enum([
|
|
11
15
|
"n", // normal aggregate
|
|
@@ -75,6 +79,7 @@ const aggregatePropsSchema = z.object({
|
|
|
75
79
|
owner: z.string(),
|
|
76
80
|
comment: z.string().nullable(),
|
|
77
81
|
privileges: z.array(privilegePropsSchema),
|
|
82
|
+
security_labels: z.array(securityLabelPropsSchema).default([]).optional(),
|
|
78
83
|
});
|
|
79
84
|
|
|
80
85
|
type AggregatePrivilegeProps = PrivilegeProps;
|
|
@@ -122,6 +127,7 @@ export class Aggregate extends BasePgModel {
|
|
|
122
127
|
public readonly owner: AggregateProps["owner"];
|
|
123
128
|
public readonly comment: AggregateProps["comment"];
|
|
124
129
|
public readonly privileges: AggregatePrivilegeProps[];
|
|
130
|
+
public readonly security_labels: SecurityLabelProps[];
|
|
125
131
|
|
|
126
132
|
constructor(props: AggregateProps) {
|
|
127
133
|
super();
|
|
@@ -168,6 +174,7 @@ export class Aggregate extends BasePgModel {
|
|
|
168
174
|
this.owner = props.owner;
|
|
169
175
|
this.comment = props.comment;
|
|
170
176
|
this.privileges = props.privileges;
|
|
177
|
+
this.security_labels = props.security_labels ?? [];
|
|
171
178
|
}
|
|
172
179
|
|
|
173
180
|
get stableId(): `aggregate:${string}` {
|
|
@@ -224,6 +231,7 @@ export class Aggregate extends BasePgModel {
|
|
|
224
231
|
owner: this.owner,
|
|
225
232
|
comment: this.comment,
|
|
226
233
|
privileges: this.privileges,
|
|
234
|
+
security_labels: this.security_labels,
|
|
227
235
|
};
|
|
228
236
|
}
|
|
229
237
|
}
|
|
@@ -294,7 +302,20 @@ select
|
|
|
294
302
|
)
|
|
295
303
|
from lateral aclexplode(COALESCE(p.proacl, acldefault('f', p.proowner))) as x(grantor, grantee, privilege_type, is_grantable)
|
|
296
304
|
), '[]'
|
|
297
|
-
) as privileges
|
|
305
|
+
) as privileges,
|
|
306
|
+
coalesce(
|
|
307
|
+
(
|
|
308
|
+
select json_agg(
|
|
309
|
+
json_build_object('provider', sl.provider, 'label', sl.label)
|
|
310
|
+
order by sl.provider
|
|
311
|
+
)
|
|
312
|
+
from pg_catalog.pg_seclabel sl
|
|
313
|
+
where sl.objoid = p.oid
|
|
314
|
+
and sl.classoid = 'pg_proc'::regclass
|
|
315
|
+
and sl.objsubid = 0
|
|
316
|
+
),
|
|
317
|
+
'[]'::json
|
|
318
|
+
) as security_labels
|
|
298
319
|
from
|
|
299
320
|
pg_catalog.pg_proc p
|
|
300
321
|
inner join pg_catalog.pg_aggregate a on a.aggfnoid = p.oid
|
|
@@ -3,7 +3,11 @@ import type { Aggregate } from "../aggregate.model.ts";
|
|
|
3
3
|
|
|
4
4
|
abstract class BaseAggregateChange extends BaseChange {
|
|
5
5
|
abstract readonly aggregate: Aggregate;
|
|
6
|
-
abstract readonly scope:
|
|
6
|
+
abstract readonly scope:
|
|
7
|
+
| "object"
|
|
8
|
+
| "comment"
|
|
9
|
+
| "privilege"
|
|
10
|
+
| "security_label";
|
|
7
11
|
readonly objectType: "aggregate" = "aggregate";
|
|
8
12
|
}
|
|
9
13
|
|
|
@@ -0,0 +1,99 @@
|
|
|
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 { Aggregate } from "../aggregate.model.ts";
|
|
5
|
+
import {
|
|
6
|
+
CreateAggregateChange,
|
|
7
|
+
DropAggregateChange,
|
|
8
|
+
} from "./aggregate.base.ts";
|
|
9
|
+
|
|
10
|
+
export type SecurityLabelAggregate =
|
|
11
|
+
| CreateSecurityLabelOnAggregate
|
|
12
|
+
| DropSecurityLabelOnAggregate;
|
|
13
|
+
|
|
14
|
+
function aggregateIdentity(a: Aggregate): string {
|
|
15
|
+
return `${a.schema}.${a.name}(${a.identityArguments})`;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export class CreateSecurityLabelOnAggregate extends CreateAggregateChange {
|
|
19
|
+
public readonly aggregate: Aggregate;
|
|
20
|
+
public readonly securityLabel: SecurityLabelProps;
|
|
21
|
+
public readonly scope = "security_label" as const;
|
|
22
|
+
|
|
23
|
+
constructor(props: {
|
|
24
|
+
aggregate: Aggregate;
|
|
25
|
+
securityLabel: SecurityLabelProps;
|
|
26
|
+
}) {
|
|
27
|
+
super();
|
|
28
|
+
this.aggregate = props.aggregate;
|
|
29
|
+
this.securityLabel = props.securityLabel;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
get creates() {
|
|
33
|
+
return [
|
|
34
|
+
stableId.securityLabel(
|
|
35
|
+
this.aggregate.stableId,
|
|
36
|
+
this.securityLabel.provider,
|
|
37
|
+
),
|
|
38
|
+
];
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
get requires() {
|
|
42
|
+
return [this.aggregate.stableId];
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
serialize(): string {
|
|
46
|
+
return [
|
|
47
|
+
"SECURITY LABEL FOR",
|
|
48
|
+
this.securityLabel.provider,
|
|
49
|
+
"ON AGGREGATE",
|
|
50
|
+
aggregateIdentity(this.aggregate),
|
|
51
|
+
"IS",
|
|
52
|
+
quoteLiteral(this.securityLabel.label),
|
|
53
|
+
].join(" ");
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export class DropSecurityLabelOnAggregate extends DropAggregateChange {
|
|
58
|
+
public readonly aggregate: Aggregate;
|
|
59
|
+
public readonly securityLabel: SecurityLabelProps;
|
|
60
|
+
public readonly scope = "security_label" as const;
|
|
61
|
+
|
|
62
|
+
constructor(props: {
|
|
63
|
+
aggregate: Aggregate;
|
|
64
|
+
securityLabel: SecurityLabelProps;
|
|
65
|
+
}) {
|
|
66
|
+
super();
|
|
67
|
+
this.aggregate = props.aggregate;
|
|
68
|
+
this.securityLabel = props.securityLabel;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
get drops() {
|
|
72
|
+
return [
|
|
73
|
+
stableId.securityLabel(
|
|
74
|
+
this.aggregate.stableId,
|
|
75
|
+
this.securityLabel.provider,
|
|
76
|
+
),
|
|
77
|
+
];
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
get requires() {
|
|
81
|
+
return [
|
|
82
|
+
stableId.securityLabel(
|
|
83
|
+
this.aggregate.stableId,
|
|
84
|
+
this.securityLabel.provider,
|
|
85
|
+
),
|
|
86
|
+
this.aggregate.stableId,
|
|
87
|
+
];
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
serialize(): string {
|
|
91
|
+
return [
|
|
92
|
+
"SECURITY LABEL FOR",
|
|
93
|
+
this.securityLabel.provider,
|
|
94
|
+
"ON AGGREGATE",
|
|
95
|
+
aggregateIdentity(this.aggregate),
|
|
96
|
+
"IS NULL",
|
|
97
|
+
].join(" ");
|
|
98
|
+
}
|
|
99
|
+
}
|