@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
|
@@ -10,6 +10,10 @@ import {
|
|
|
10
10
|
type ExtractRetryOptions,
|
|
11
11
|
extractWithDefinitionRetry,
|
|
12
12
|
} from "../extract-with-retry.ts";
|
|
13
|
+
import {
|
|
14
|
+
type SecurityLabelProps,
|
|
15
|
+
securityLabelPropsSchema,
|
|
16
|
+
} from "../security-label.types.ts";
|
|
13
17
|
|
|
14
18
|
const FunctionKindSchema = z.enum([
|
|
15
19
|
"f", // function
|
|
@@ -68,6 +72,7 @@ const procedurePropsSchema = z.object({
|
|
|
68
72
|
owner: z.string(),
|
|
69
73
|
comment: z.string().nullable(),
|
|
70
74
|
privileges: z.array(privilegePropsSchema),
|
|
75
|
+
security_labels: z.array(securityLabelPropsSchema).default([]).optional(),
|
|
71
76
|
});
|
|
72
77
|
|
|
73
78
|
// pg_get_functiondef(oid) can return NULL when the function (its pg_proc
|
|
@@ -112,6 +117,7 @@ export class Procedure extends BasePgModel {
|
|
|
112
117
|
public readonly owner: ProcedureProps["owner"];
|
|
113
118
|
public readonly comment: ProcedureProps["comment"];
|
|
114
119
|
public readonly privileges: ProcedurePrivilegeProps[];
|
|
120
|
+
public readonly security_labels: SecurityLabelProps[];
|
|
115
121
|
|
|
116
122
|
constructor(props: ProcedureProps) {
|
|
117
123
|
super();
|
|
@@ -148,6 +154,7 @@ export class Procedure extends BasePgModel {
|
|
|
148
154
|
this.owner = props.owner;
|
|
149
155
|
this.comment = props.comment;
|
|
150
156
|
this.privileges = props.privileges;
|
|
157
|
+
this.security_labels = props.security_labels ?? [];
|
|
151
158
|
}
|
|
152
159
|
|
|
153
160
|
get stableId(): `procedure:${string}` {
|
|
@@ -192,6 +199,7 @@ export class Procedure extends BasePgModel {
|
|
|
192
199
|
owner: this.owner,
|
|
193
200
|
comment: this.comment,
|
|
194
201
|
privileges: this.privileges,
|
|
202
|
+
security_labels: this.security_labels,
|
|
195
203
|
};
|
|
196
204
|
}
|
|
197
205
|
}
|
|
@@ -265,7 +273,20 @@ select
|
|
|
265
273
|
)
|
|
266
274
|
from lateral aclexplode(COALESCE(p.proacl, acldefault('f', p.proowner))) as x(grantor, grantee, privilege_type, is_grantable)
|
|
267
275
|
), '[]'
|
|
268
|
-
) as privileges
|
|
276
|
+
) as privileges,
|
|
277
|
+
coalesce(
|
|
278
|
+
(
|
|
279
|
+
select json_agg(
|
|
280
|
+
json_build_object('provider', sl.provider, 'label', sl.label)
|
|
281
|
+
order by sl.provider
|
|
282
|
+
)
|
|
283
|
+
from pg_catalog.pg_seclabel sl
|
|
284
|
+
where sl.objoid = p.oid
|
|
285
|
+
and sl.classoid = 'pg_proc'::regclass
|
|
286
|
+
and sl.objsubid = 0
|
|
287
|
+
),
|
|
288
|
+
'[]'::json
|
|
289
|
+
) as security_labels
|
|
269
290
|
from
|
|
270
291
|
pg_catalog.pg_proc p
|
|
271
292
|
inner join pg_catalog.pg_language l on l.oid = p.prolang
|
|
@@ -283,5 +304,5 @@ order by
|
|
|
283
304
|
const validatedRows = procedureRows.filter(
|
|
284
305
|
(row): row is ProcedureProps => row.definition !== null,
|
|
285
306
|
);
|
|
286
|
-
return validatedRows.map((row
|
|
307
|
+
return validatedRows.map((row) => new Procedure(row));
|
|
287
308
|
}
|
|
@@ -3,7 +3,7 @@ import type { Publication } from "../publication.model.ts";
|
|
|
3
3
|
|
|
4
4
|
abstract class BasePublicationChange extends BaseChange {
|
|
5
5
|
abstract readonly publication: Publication;
|
|
6
|
-
abstract readonly scope: "object" | "comment";
|
|
6
|
+
abstract readonly scope: "object" | "comment" | "security_label";
|
|
7
7
|
readonly objectType = "publication" as const;
|
|
8
8
|
}
|
|
9
9
|
|
|
@@ -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 { Publication } from "../publication.model.ts";
|
|
5
|
+
import {
|
|
6
|
+
CreatePublicationChange,
|
|
7
|
+
DropPublicationChange,
|
|
8
|
+
} from "./publication.base.ts";
|
|
9
|
+
|
|
10
|
+
export type SecurityLabelPublication =
|
|
11
|
+
| CreateSecurityLabelOnPublication
|
|
12
|
+
| DropSecurityLabelOnPublication;
|
|
13
|
+
|
|
14
|
+
export class CreateSecurityLabelOnPublication extends CreatePublicationChange {
|
|
15
|
+
public readonly publication: Publication;
|
|
16
|
+
public readonly securityLabel: SecurityLabelProps;
|
|
17
|
+
public readonly scope = "security_label" as const;
|
|
18
|
+
|
|
19
|
+
constructor(props: {
|
|
20
|
+
publication: Publication;
|
|
21
|
+
securityLabel: SecurityLabelProps;
|
|
22
|
+
}) {
|
|
23
|
+
super();
|
|
24
|
+
this.publication = props.publication;
|
|
25
|
+
this.securityLabel = props.securityLabel;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
get creates() {
|
|
29
|
+
return [
|
|
30
|
+
stableId.securityLabel(
|
|
31
|
+
this.publication.stableId,
|
|
32
|
+
this.securityLabel.provider,
|
|
33
|
+
),
|
|
34
|
+
];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
get requires() {
|
|
38
|
+
return [this.publication.stableId];
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
serialize(): string {
|
|
42
|
+
return [
|
|
43
|
+
"SECURITY LABEL FOR",
|
|
44
|
+
this.securityLabel.provider,
|
|
45
|
+
"ON PUBLICATION",
|
|
46
|
+
this.publication.name,
|
|
47
|
+
"IS",
|
|
48
|
+
quoteLiteral(this.securityLabel.label),
|
|
49
|
+
].join(" ");
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export class DropSecurityLabelOnPublication extends DropPublicationChange {
|
|
54
|
+
public readonly publication: Publication;
|
|
55
|
+
public readonly securityLabel: SecurityLabelProps;
|
|
56
|
+
public readonly scope = "security_label" as const;
|
|
57
|
+
|
|
58
|
+
constructor(props: {
|
|
59
|
+
publication: Publication;
|
|
60
|
+
securityLabel: SecurityLabelProps;
|
|
61
|
+
}) {
|
|
62
|
+
super();
|
|
63
|
+
this.publication = props.publication;
|
|
64
|
+
this.securityLabel = props.securityLabel;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
get drops() {
|
|
68
|
+
return [
|
|
69
|
+
stableId.securityLabel(
|
|
70
|
+
this.publication.stableId,
|
|
71
|
+
this.securityLabel.provider,
|
|
72
|
+
),
|
|
73
|
+
];
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
get requires() {
|
|
77
|
+
return [
|
|
78
|
+
stableId.securityLabel(
|
|
79
|
+
this.publication.stableId,
|
|
80
|
+
this.securityLabel.provider,
|
|
81
|
+
),
|
|
82
|
+
this.publication.stableId,
|
|
83
|
+
];
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
serialize(): string {
|
|
87
|
+
return [
|
|
88
|
+
"SECURITY LABEL FOR",
|
|
89
|
+
this.securityLabel.provider,
|
|
90
|
+
"ON PUBLICATION",
|
|
91
|
+
this.publication.name,
|
|
92
|
+
"IS NULL",
|
|
93
|
+
].join(" ");
|
|
94
|
+
}
|
|
95
|
+
}
|
|
@@ -10,6 +10,7 @@ import type {
|
|
|
10
10
|
import type { CommentPublication } from "./publication.comment.ts";
|
|
11
11
|
import type { CreatePublication } from "./publication.create.ts";
|
|
12
12
|
import type { DropPublication } from "./publication.drop.ts";
|
|
13
|
+
import type { SecurityLabelPublication } from "./publication.security-label.ts";
|
|
13
14
|
|
|
14
15
|
/** Union of all publication-related change variants (`objectType: "publication"`). @category Change Types */
|
|
15
16
|
export type PublicationChange =
|
|
@@ -22,4 +23,5 @@ export type PublicationChange =
|
|
|
22
23
|
| AlterPublicationSetOwner
|
|
23
24
|
| CommentPublication
|
|
24
25
|
| CreatePublication
|
|
25
|
-
| DropPublication
|
|
26
|
+
| DropPublication
|
|
27
|
+
| SecurityLabelPublication;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { diffObjects } from "../base.diff.ts";
|
|
2
2
|
import type { ObjectDiffContext } from "../diff-context.ts";
|
|
3
|
+
import { diffSecurityLabels } from "../security-label.types.ts";
|
|
3
4
|
import { deepEqual } from "../utils.ts";
|
|
4
5
|
import {
|
|
5
6
|
AlterPublicationAddSchemas,
|
|
@@ -15,6 +16,10 @@ import {
|
|
|
15
16
|
} from "./changes/publication.comment.ts";
|
|
16
17
|
import { CreatePublication } from "./changes/publication.create.ts";
|
|
17
18
|
import { DropPublication } from "./changes/publication.drop.ts";
|
|
19
|
+
import {
|
|
20
|
+
CreateSecurityLabelOnPublication,
|
|
21
|
+
DropSecurityLabelOnPublication,
|
|
22
|
+
} from "./changes/publication.security-label.ts";
|
|
18
23
|
import type { PublicationChange } from "./changes/publication.types.ts";
|
|
19
24
|
import type {
|
|
20
25
|
Publication,
|
|
@@ -47,6 +52,14 @@ export function diffPublications(
|
|
|
47
52
|
if (publication.comment !== null) {
|
|
48
53
|
changes.push(new CreateCommentOnPublication({ publication }));
|
|
49
54
|
}
|
|
55
|
+
for (const label of publication.security_labels) {
|
|
56
|
+
changes.push(
|
|
57
|
+
new CreateSecurityLabelOnPublication({
|
|
58
|
+
publication,
|
|
59
|
+
securityLabel: label,
|
|
60
|
+
}),
|
|
61
|
+
);
|
|
62
|
+
}
|
|
50
63
|
}
|
|
51
64
|
|
|
52
65
|
for (const id of dropped) {
|
|
@@ -172,6 +185,26 @@ export function diffPublications(
|
|
|
172
185
|
);
|
|
173
186
|
}
|
|
174
187
|
}
|
|
188
|
+
|
|
189
|
+
// SECURITY LABELS
|
|
190
|
+
changes.push(
|
|
191
|
+
...diffSecurityLabels<
|
|
192
|
+
CreateSecurityLabelOnPublication | DropSecurityLabelOnPublication
|
|
193
|
+
>(
|
|
194
|
+
mainPublication.security_labels,
|
|
195
|
+
branchPublication.security_labels,
|
|
196
|
+
(securityLabel) =>
|
|
197
|
+
new CreateSecurityLabelOnPublication({
|
|
198
|
+
publication: branchPublication,
|
|
199
|
+
securityLabel,
|
|
200
|
+
}),
|
|
201
|
+
(securityLabel) =>
|
|
202
|
+
new DropSecurityLabelOnPublication({
|
|
203
|
+
publication: mainPublication,
|
|
204
|
+
securityLabel,
|
|
205
|
+
}),
|
|
206
|
+
),
|
|
207
|
+
);
|
|
175
208
|
}
|
|
176
209
|
|
|
177
210
|
return changes;
|
|
@@ -2,6 +2,11 @@ import { sql } from "@ts-safeql/sql-tag";
|
|
|
2
2
|
import type { Pool } from "pg";
|
|
3
3
|
import z from "zod";
|
|
4
4
|
import { BasePgModel } from "../base.model.ts";
|
|
5
|
+
import {
|
|
6
|
+
normalizeSecurityLabels,
|
|
7
|
+
type SecurityLabelProps,
|
|
8
|
+
securityLabelPropsSchema,
|
|
9
|
+
} from "../security-label.types.ts";
|
|
5
10
|
|
|
6
11
|
const publicationTablePropsSchema = z.object({
|
|
7
12
|
schema: z.string(),
|
|
@@ -22,6 +27,7 @@ const publicationPropsSchema = z.object({
|
|
|
22
27
|
publish_via_partition_root: z.boolean(),
|
|
23
28
|
tables: z.array(publicationTablePropsSchema),
|
|
24
29
|
schemas: z.array(z.string()),
|
|
30
|
+
security_labels: z.array(securityLabelPropsSchema).default([]).optional(),
|
|
25
31
|
});
|
|
26
32
|
|
|
27
33
|
export type PublicationTableProps = z.infer<typeof publicationTablePropsSchema>;
|
|
@@ -44,6 +50,7 @@ export class Publication extends BasePgModel {
|
|
|
44
50
|
public readonly publish_via_partition_root: PublicationProps["publish_via_partition_root"];
|
|
45
51
|
public readonly tables: PublicationTableProps[];
|
|
46
52
|
public readonly schemas: PublicationProps["schemas"];
|
|
53
|
+
public readonly security_labels: SecurityLabelProps[];
|
|
47
54
|
|
|
48
55
|
constructor(props: PublicationProps) {
|
|
49
56
|
super();
|
|
@@ -72,6 +79,7 @@ export class Publication extends BasePgModel {
|
|
|
72
79
|
});
|
|
73
80
|
|
|
74
81
|
this.schemas = [...props.schemas].sort((a, b) => a.localeCompare(b));
|
|
82
|
+
this.security_labels = props.security_labels ?? [];
|
|
75
83
|
}
|
|
76
84
|
|
|
77
85
|
get stableId(): `publication:${string}` {
|
|
@@ -96,6 +104,7 @@ export class Publication extends BasePgModel {
|
|
|
96
104
|
publish_via_partition_root: this.publish_via_partition_root,
|
|
97
105
|
tables: this.tables,
|
|
98
106
|
schemas: this.schemas,
|
|
107
|
+
security_labels: this.security_labels,
|
|
99
108
|
};
|
|
100
109
|
}
|
|
101
110
|
|
|
@@ -118,6 +127,7 @@ export class Publication extends BasePgModel {
|
|
|
118
127
|
a.schema.localeCompare(b.schema) || a.name.localeCompare(b.name),
|
|
119
128
|
),
|
|
120
129
|
schemas: [...this.schemas].sort((a, b) => a.localeCompare(b)),
|
|
130
|
+
security_labels: normalizeSecurityLabels(this.security_labels),
|
|
121
131
|
},
|
|
122
132
|
};
|
|
123
133
|
}
|
|
@@ -194,7 +204,20 @@ export async function extractPublications(pool: Pool): Promise<Publication[]> {
|
|
|
194
204
|
where s.pnpubid = p.oid
|
|
195
205
|
),
|
|
196
206
|
'[]'::json
|
|
197
|
-
) as schemas
|
|
207
|
+
) as schemas,
|
|
208
|
+
coalesce(
|
|
209
|
+
(
|
|
210
|
+
select json_agg(
|
|
211
|
+
json_build_object('provider', sl.provider, 'label', sl.label)
|
|
212
|
+
order by sl.provider
|
|
213
|
+
)
|
|
214
|
+
from pg_catalog.pg_seclabel sl
|
|
215
|
+
where sl.objoid = p.oid
|
|
216
|
+
and sl.classoid = 'pg_publication'::regclass
|
|
217
|
+
and sl.objsubid = 0
|
|
218
|
+
),
|
|
219
|
+
'[]'::json
|
|
220
|
+
) as security_labels
|
|
198
221
|
from pg_publication p
|
|
199
222
|
left join extension_oids e on e.objid = p.oid
|
|
200
223
|
where e.objid is null
|
|
@@ -0,0 +1,77 @@
|
|
|
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 { Role } from "../role.model.ts";
|
|
5
|
+
import { CreateRoleChange, DropRoleChange } from "./role.base.ts";
|
|
6
|
+
|
|
7
|
+
export type SecurityLabelRole =
|
|
8
|
+
| CreateSecurityLabelOnRole
|
|
9
|
+
| DropSecurityLabelOnRole;
|
|
10
|
+
|
|
11
|
+
export class CreateSecurityLabelOnRole extends CreateRoleChange {
|
|
12
|
+
public readonly role: Role;
|
|
13
|
+
public readonly securityLabel: SecurityLabelProps;
|
|
14
|
+
public readonly scope = "security_label" as const;
|
|
15
|
+
|
|
16
|
+
constructor(props: { role: Role; securityLabel: SecurityLabelProps }) {
|
|
17
|
+
super();
|
|
18
|
+
this.role = props.role;
|
|
19
|
+
this.securityLabel = props.securityLabel;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
get creates() {
|
|
23
|
+
return [
|
|
24
|
+
stableId.securityLabel(this.role.stableId, this.securityLabel.provider),
|
|
25
|
+
];
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
get requires() {
|
|
29
|
+
return [this.role.stableId];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
serialize(): string {
|
|
33
|
+
return [
|
|
34
|
+
"SECURITY LABEL FOR",
|
|
35
|
+
this.securityLabel.provider,
|
|
36
|
+
"ON ROLE",
|
|
37
|
+
this.role.name,
|
|
38
|
+
"IS",
|
|
39
|
+
quoteLiteral(this.securityLabel.label),
|
|
40
|
+
].join(" ");
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export class DropSecurityLabelOnRole extends DropRoleChange {
|
|
45
|
+
public readonly role: Role;
|
|
46
|
+
public readonly securityLabel: SecurityLabelProps;
|
|
47
|
+
public readonly scope = "security_label" as const;
|
|
48
|
+
|
|
49
|
+
constructor(props: { role: Role; securityLabel: SecurityLabelProps }) {
|
|
50
|
+
super();
|
|
51
|
+
this.role = props.role;
|
|
52
|
+
this.securityLabel = props.securityLabel;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
get drops() {
|
|
56
|
+
return [
|
|
57
|
+
stableId.securityLabel(this.role.stableId, this.securityLabel.provider),
|
|
58
|
+
];
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
get requires() {
|
|
62
|
+
return [
|
|
63
|
+
stableId.securityLabel(this.role.stableId, this.securityLabel.provider),
|
|
64
|
+
this.role.stableId,
|
|
65
|
+
];
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
serialize(): string {
|
|
69
|
+
return [
|
|
70
|
+
"SECURITY LABEL FOR",
|
|
71
|
+
this.securityLabel.provider,
|
|
72
|
+
"ON ROLE",
|
|
73
|
+
this.role.name,
|
|
74
|
+
"IS NULL",
|
|
75
|
+
].join(" ");
|
|
76
|
+
}
|
|
77
|
+
}
|
|
@@ -3,6 +3,7 @@ import type { CommentRole } from "./role.comment.ts";
|
|
|
3
3
|
import type { CreateRole } from "./role.create.ts";
|
|
4
4
|
import type { DropRole } from "./role.drop.ts";
|
|
5
5
|
import type { RolePrivilege } from "./role.privilege.ts";
|
|
6
|
+
import type { SecurityLabelRole } from "./role.security-label.ts";
|
|
6
7
|
|
|
7
8
|
/** Union of all role-related change variants (`objectType: "role"`). @category Change Types */
|
|
8
9
|
export type RoleChange =
|
|
@@ -10,4 +11,5 @@ export type RoleChange =
|
|
|
10
11
|
| CommentRole
|
|
11
12
|
| CreateRole
|
|
12
13
|
| DropRole
|
|
13
|
-
| RolePrivilege
|
|
14
|
+
| RolePrivilege
|
|
15
|
+
| SecurityLabelRole;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { diffObjects } from "../base.diff.ts";
|
|
2
|
+
import { diffSecurityLabels } from "../security-label.types.ts";
|
|
2
3
|
import {
|
|
3
4
|
AlterRoleSetConfig,
|
|
4
5
|
AlterRoleSetOptions,
|
|
@@ -16,6 +17,10 @@ import {
|
|
|
16
17
|
RevokeRoleMembership,
|
|
17
18
|
RevokeRoleMembershipOptions,
|
|
18
19
|
} from "./changes/role.privilege.ts";
|
|
20
|
+
import {
|
|
21
|
+
CreateSecurityLabelOnRole,
|
|
22
|
+
DropSecurityLabelOnRole,
|
|
23
|
+
} from "./changes/role.security-label.ts";
|
|
19
24
|
import type { RoleChange } from "./changes/role.types.ts";
|
|
20
25
|
import type { Role } from "./role.model.ts";
|
|
21
26
|
|
|
@@ -51,6 +56,14 @@ export function diffRoles(
|
|
|
51
56
|
if (role.comment !== null) {
|
|
52
57
|
changes.push(new CreateCommentOnRole({ role }));
|
|
53
58
|
}
|
|
59
|
+
for (const label of role.security_labels) {
|
|
60
|
+
changes.push(
|
|
61
|
+
new CreateSecurityLabelOnRole({
|
|
62
|
+
role,
|
|
63
|
+
securityLabel: label,
|
|
64
|
+
}),
|
|
65
|
+
);
|
|
66
|
+
}
|
|
54
67
|
// MEMBERSHIPS: Grant memberships immediately after role creation.
|
|
55
68
|
// Members are already deduplicated by the Role model constructor.
|
|
56
69
|
for (const membership of role.members) {
|
|
@@ -215,6 +228,26 @@ export function diffRoles(
|
|
|
215
228
|
}
|
|
216
229
|
}
|
|
217
230
|
|
|
231
|
+
// SECURITY LABELS
|
|
232
|
+
changes.push(
|
|
233
|
+
...diffSecurityLabels<
|
|
234
|
+
CreateSecurityLabelOnRole | DropSecurityLabelOnRole
|
|
235
|
+
>(
|
|
236
|
+
mainRole.security_labels,
|
|
237
|
+
branchRole.security_labels,
|
|
238
|
+
(securityLabel) =>
|
|
239
|
+
new CreateSecurityLabelOnRole({
|
|
240
|
+
role: branchRole,
|
|
241
|
+
securityLabel,
|
|
242
|
+
}),
|
|
243
|
+
(securityLabel) =>
|
|
244
|
+
new DropSecurityLabelOnRole({
|
|
245
|
+
role: mainRole,
|
|
246
|
+
securityLabel,
|
|
247
|
+
}),
|
|
248
|
+
),
|
|
249
|
+
);
|
|
250
|
+
|
|
218
251
|
// MEMBERSHIPS
|
|
219
252
|
// Members are already deduplicated by the Role model constructor.
|
|
220
253
|
const mainMembers = new Map(mainRole.members.map((m) => [m.member, m]));
|
|
@@ -2,6 +2,10 @@ import { sql } from "@ts-safeql/sql-tag";
|
|
|
2
2
|
import type { Pool } from "pg";
|
|
3
3
|
import z from "zod";
|
|
4
4
|
import { BasePgModel } from "../base.model.ts";
|
|
5
|
+
import {
|
|
6
|
+
type SecurityLabelProps,
|
|
7
|
+
securityLabelPropsSchema,
|
|
8
|
+
} from "../security-label.types.ts";
|
|
5
9
|
|
|
6
10
|
const membershipInfoSchema = z.object({
|
|
7
11
|
member: z.string(),
|
|
@@ -35,6 +39,7 @@ const rolePropsSchema = z.object({
|
|
|
35
39
|
comment: z.string().nullable(),
|
|
36
40
|
members: z.array(membershipInfoSchema),
|
|
37
41
|
default_privileges: z.array(defaultPrivilegeSchema),
|
|
42
|
+
security_labels: z.array(securityLabelPropsSchema).default([]).optional(),
|
|
38
43
|
});
|
|
39
44
|
|
|
40
45
|
export type RoleProps = z.infer<typeof rolePropsSchema>;
|
|
@@ -53,6 +58,7 @@ export class Role extends BasePgModel {
|
|
|
53
58
|
public readonly comment: RoleProps["comment"];
|
|
54
59
|
public readonly members: RoleProps["members"];
|
|
55
60
|
public readonly default_privileges: RoleProps["default_privileges"];
|
|
61
|
+
public readonly security_labels: SecurityLabelProps[];
|
|
56
62
|
|
|
57
63
|
constructor(props: RoleProps) {
|
|
58
64
|
super();
|
|
@@ -73,6 +79,7 @@ export class Role extends BasePgModel {
|
|
|
73
79
|
this.comment = props.comment;
|
|
74
80
|
this.members = deduplicateMembers(props.members);
|
|
75
81
|
this.default_privileges = props.default_privileges;
|
|
82
|
+
this.security_labels = props.security_labels ?? [];
|
|
76
83
|
}
|
|
77
84
|
|
|
78
85
|
get stableId(): `role:${string}` {
|
|
@@ -129,6 +136,7 @@ export class Role extends BasePgModel {
|
|
|
129
136
|
comment: this.comment,
|
|
130
137
|
members: sortedMembers,
|
|
131
138
|
default_privileges: sortedDefaultPrivs,
|
|
139
|
+
security_labels: this.security_labels,
|
|
132
140
|
};
|
|
133
141
|
}
|
|
134
142
|
}
|
|
@@ -232,6 +240,18 @@ export async function extractRoles(pool: Pool): Promise<Role[]> {
|
|
|
232
240
|
r.rolbypassrls AS can_bypass_rls,
|
|
233
241
|
r.rolconfig AS config,
|
|
234
242
|
obj_description(r.oid, 'pg_authid') AS comment,
|
|
243
|
+
COALESCE(
|
|
244
|
+
(
|
|
245
|
+
SELECT json_agg(
|
|
246
|
+
json_build_object('provider', sl.provider, 'label', sl.label)
|
|
247
|
+
ORDER BY sl.provider
|
|
248
|
+
)
|
|
249
|
+
FROM pg_catalog.pg_shseclabel sl
|
|
250
|
+
WHERE sl.objoid = r.oid
|
|
251
|
+
AND sl.classoid = 'pg_authid'::regclass
|
|
252
|
+
),
|
|
253
|
+
'[]'::json
|
|
254
|
+
) AS security_labels,
|
|
235
255
|
COALESCE(rm.members, '[]') AS members,
|
|
236
256
|
COALESCE(
|
|
237
257
|
(
|
|
@@ -353,6 +373,18 @@ export async function extractRoles(pool: Pool): Promise<Role[]> {
|
|
|
353
373
|
r.rolbypassrls AS can_bypass_rls,
|
|
354
374
|
r.rolconfig AS config,
|
|
355
375
|
obj_description(r.oid, 'pg_authid') AS comment,
|
|
376
|
+
COALESCE(
|
|
377
|
+
(
|
|
378
|
+
SELECT json_agg(
|
|
379
|
+
json_build_object('provider', sl.provider, 'label', sl.label)
|
|
380
|
+
ORDER BY sl.provider
|
|
381
|
+
)
|
|
382
|
+
FROM pg_catalog.pg_shseclabel sl
|
|
383
|
+
WHERE sl.objoid = r.oid
|
|
384
|
+
AND sl.classoid = 'pg_authid'::regclass
|
|
385
|
+
),
|
|
386
|
+
'[]'::json
|
|
387
|
+
) AS security_labels,
|
|
356
388
|
COALESCE(rm.members, '[]') AS members,
|
|
357
389
|
COALESCE(
|
|
358
390
|
(
|
|
@@ -3,7 +3,11 @@ import type { Schema } from "../schema.model.ts";
|
|
|
3
3
|
|
|
4
4
|
abstract class BaseSchemaChange extends BaseChange {
|
|
5
5
|
abstract readonly schema: Schema;
|
|
6
|
-
abstract readonly scope:
|
|
6
|
+
abstract readonly scope:
|
|
7
|
+
| "object"
|
|
8
|
+
| "comment"
|
|
9
|
+
| "privilege"
|
|
10
|
+
| "security_label";
|
|
7
11
|
readonly objectType: "schema" = "schema";
|
|
8
12
|
}
|
|
9
13
|
|
|
@@ -0,0 +1,76 @@
|
|
|
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 { Schema } from "../schema.model.ts";
|
|
5
|
+
import {
|
|
6
|
+
CreateSecurityLabelOnSchema,
|
|
7
|
+
DropSecurityLabelOnSchema,
|
|
8
|
+
} from "./schema.security-label.ts";
|
|
9
|
+
|
|
10
|
+
const makeSchema = () =>
|
|
11
|
+
new Schema({
|
|
12
|
+
name: "app",
|
|
13
|
+
owner: "postgres",
|
|
14
|
+
comment: null,
|
|
15
|
+
privileges: [],
|
|
16
|
+
security_labels: [],
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
describe("schema.security-label", () => {
|
|
20
|
+
test("create serializes and tracks dependencies", async () => {
|
|
21
|
+
const schema = makeSchema();
|
|
22
|
+
const change = new CreateSecurityLabelOnSchema({
|
|
23
|
+
schema,
|
|
24
|
+
securityLabel: {
|
|
25
|
+
provider: "pg_graphql",
|
|
26
|
+
label: '{"inflect_names":true}',
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
expect(change.scope).toBe("security_label");
|
|
31
|
+
expect(change.operation).toBe("create");
|
|
32
|
+
expect(change.objectType).toBe("schema");
|
|
33
|
+
expect(change.creates).toEqual([
|
|
34
|
+
stableId.securityLabel(schema.stableId, "pg_graphql"),
|
|
35
|
+
]);
|
|
36
|
+
expect(change.requires).toEqual([schema.stableId]);
|
|
37
|
+
await assertValidSql(change.serialize());
|
|
38
|
+
expect(change.serialize()).toBe(
|
|
39
|
+
`SECURITY LABEL FOR pg_graphql ON SCHEMA app IS '{"inflect_names":true}'`,
|
|
40
|
+
);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
test("drop serializes to IS NULL and tracks dependencies", async () => {
|
|
44
|
+
const schema = makeSchema();
|
|
45
|
+
const change = new DropSecurityLabelOnSchema({
|
|
46
|
+
schema,
|
|
47
|
+
securityLabel: { provider: "pg_graphql", label: "old" },
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
expect(change.scope).toBe("security_label");
|
|
51
|
+
expect(change.operation).toBe("drop");
|
|
52
|
+
expect(change.drops).toEqual([
|
|
53
|
+
stableId.securityLabel(schema.stableId, "pg_graphql"),
|
|
54
|
+
]);
|
|
55
|
+
expect(change.requires).toEqual([
|
|
56
|
+
stableId.securityLabel(schema.stableId, "pg_graphql"),
|
|
57
|
+
schema.stableId,
|
|
58
|
+
]);
|
|
59
|
+
await assertValidSql(change.serialize());
|
|
60
|
+
expect(change.serialize()).toBe(
|
|
61
|
+
"SECURITY LABEL FOR pg_graphql ON SCHEMA app IS NULL",
|
|
62
|
+
);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
test("create escapes single quotes in label", async () => {
|
|
66
|
+
const schema = makeSchema();
|
|
67
|
+
const change = new CreateSecurityLabelOnSchema({
|
|
68
|
+
schema,
|
|
69
|
+
securityLabel: { provider: "p", label: "it's a test" },
|
|
70
|
+
});
|
|
71
|
+
await assertValidSql(change.serialize());
|
|
72
|
+
expect(change.serialize()).toBe(
|
|
73
|
+
"SECURITY LABEL FOR p ON SCHEMA app IS 'it''s a test'",
|
|
74
|
+
);
|
|
75
|
+
});
|
|
76
|
+
});
|