@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
|
@@ -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
|
(
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
import type { Pool } from "pg";
|
|
3
|
+
import { extractRules, Rule } from "./rule.model.ts";
|
|
4
|
+
|
|
5
|
+
const baseRow = {
|
|
6
|
+
schema: "public",
|
|
7
|
+
table_name: '"events"',
|
|
8
|
+
relation_kind: "r" as const,
|
|
9
|
+
event: "INSERT" as const,
|
|
10
|
+
enabled: "O" as const,
|
|
11
|
+
is_instead: false,
|
|
12
|
+
owner: "postgres",
|
|
13
|
+
comment: null,
|
|
14
|
+
columns: [] as string[],
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const mockPool = (rows: unknown[]): Pool =>
|
|
18
|
+
({ query: async () => ({ rows }) }) as unknown as Pool;
|
|
19
|
+
|
|
20
|
+
const mockPoolSequence = (...attempts: unknown[][]): Pool => {
|
|
21
|
+
let i = 0;
|
|
22
|
+
return {
|
|
23
|
+
query: async () => ({
|
|
24
|
+
rows: attempts[Math.min(i++, attempts.length - 1)],
|
|
25
|
+
}),
|
|
26
|
+
} as unknown as Pool;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const NO_BACKOFF = { backoffMs: 0 } as const;
|
|
30
|
+
|
|
31
|
+
describe("extractRules", () => {
|
|
32
|
+
test("skips rows where pg_get_ruledef returned NULL after exhausting retries", async () => {
|
|
33
|
+
const rules = await extractRules(
|
|
34
|
+
mockPool([
|
|
35
|
+
{
|
|
36
|
+
...baseRow,
|
|
37
|
+
name: '"good_rule"',
|
|
38
|
+
definition:
|
|
39
|
+
"CREATE RULE good_rule AS ON INSERT TO events DO INSTEAD NOTHING;",
|
|
40
|
+
},
|
|
41
|
+
{ ...baseRow, name: '"orphan_rule"', definition: null },
|
|
42
|
+
]),
|
|
43
|
+
NO_BACKOFF,
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
expect(rules).toHaveLength(1);
|
|
47
|
+
expect(rules[0]).toBeInstanceOf(Rule);
|
|
48
|
+
expect(rules[0]?.name).toBe('"good_rule"');
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
test("does not throw ZodError when the only row has a null definition", async () => {
|
|
52
|
+
await expect(
|
|
53
|
+
extractRules(
|
|
54
|
+
mockPool([{ ...baseRow, name: '"orphan"', definition: null }]),
|
|
55
|
+
NO_BACKOFF,
|
|
56
|
+
),
|
|
57
|
+
).resolves.toEqual([]);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
test("returns all rules when every row has a valid definition", async () => {
|
|
61
|
+
const rules = await extractRules(
|
|
62
|
+
mockPool([
|
|
63
|
+
{
|
|
64
|
+
...baseRow,
|
|
65
|
+
name: '"a"',
|
|
66
|
+
definition:
|
|
67
|
+
"CREATE RULE a AS ON INSERT TO events DO INSTEAD NOTHING;",
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
...baseRow,
|
|
71
|
+
name: '"b"',
|
|
72
|
+
definition:
|
|
73
|
+
"CREATE RULE b AS ON UPDATE TO events DO INSTEAD NOTHING;",
|
|
74
|
+
},
|
|
75
|
+
]),
|
|
76
|
+
NO_BACKOFF,
|
|
77
|
+
);
|
|
78
|
+
expect(rules.map((r) => r.name)).toEqual(['"a"', '"b"']);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
test("recovers when pg_get_ruledef is NULL on first attempt but resolved on retry", async () => {
|
|
82
|
+
const rules = await extractRules(
|
|
83
|
+
mockPoolSequence(
|
|
84
|
+
[{ ...baseRow, name: '"racy_rule"', definition: null }],
|
|
85
|
+
[
|
|
86
|
+
{
|
|
87
|
+
...baseRow,
|
|
88
|
+
name: '"racy_rule"',
|
|
89
|
+
definition:
|
|
90
|
+
"CREATE RULE racy_rule AS ON INSERT TO events DO INSTEAD NOTHING;",
|
|
91
|
+
},
|
|
92
|
+
],
|
|
93
|
+
),
|
|
94
|
+
{ retries: 2, backoffMs: 0 },
|
|
95
|
+
);
|
|
96
|
+
expect(rules).toHaveLength(1);
|
|
97
|
+
expect(rules[0]?.name).toBe('"racy_rule"');
|
|
98
|
+
});
|
|
99
|
+
});
|
|
@@ -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 ExtractRetryOptions,
|
|
7
|
+
extractWithDefinitionRetry,
|
|
8
|
+
} from "../extract-with-retry.ts";
|
|
5
9
|
import { stableId } from "../utils.ts";
|
|
6
10
|
|
|
7
11
|
const RuleEventSchema = z.enum(["SELECT", "INSERT", "UPDATE", "DELETE"]);
|
|
@@ -29,6 +33,15 @@ const rulePropsSchema = z.object({
|
|
|
29
33
|
columns: z.array(z.string()),
|
|
30
34
|
});
|
|
31
35
|
|
|
36
|
+
// pg_get_ruledef(oid, pretty) can return NULL when the rule (its pg_rewrite
|
|
37
|
+
// row) is dropped between catalog scan and resolution, or under transient
|
|
38
|
+
// catalog state. An unreadable rule cannot be diffed, so we accept NULL here
|
|
39
|
+
// and filter the row out at extraction time rather than crashing the whole
|
|
40
|
+
// catalog parse with a ZodError.
|
|
41
|
+
const ruleRowSchema = rulePropsSchema.extend({
|
|
42
|
+
definition: z.string().nullable(),
|
|
43
|
+
});
|
|
44
|
+
|
|
32
45
|
export type RuleEnabledState = z.infer<typeof RuleEnabledStateSchema>;
|
|
33
46
|
export type RuleProps = z.infer<typeof rulePropsSchema>;
|
|
34
47
|
|
|
@@ -97,8 +110,16 @@ export class Rule extends BasePgModel {
|
|
|
97
110
|
}
|
|
98
111
|
}
|
|
99
112
|
|
|
100
|
-
export async function extractRules(
|
|
101
|
-
|
|
113
|
+
export async function extractRules(
|
|
114
|
+
pool: Pool,
|
|
115
|
+
options?: ExtractRetryOptions,
|
|
116
|
+
): Promise<Rule[]> {
|
|
117
|
+
const ruleRows = await extractWithDefinitionRetry({
|
|
118
|
+
label: "rules",
|
|
119
|
+
options,
|
|
120
|
+
hasNullDefinition: (row) => row.definition === null,
|
|
121
|
+
query: async () => {
|
|
122
|
+
const result = await pool.query<RuleProps>(sql`
|
|
102
123
|
WITH extension_rule_oids AS (
|
|
103
124
|
SELECT
|
|
104
125
|
objid
|
|
@@ -164,9 +185,12 @@ export async function extractRules(pool: Pool): Promise<Rule[]> {
|
|
|
164
185
|
ORDER BY
|
|
165
186
|
1, 3, 2
|
|
166
187
|
`);
|
|
188
|
+
return result.rows.map((row: unknown) => ruleRowSchema.parse(row));
|
|
189
|
+
},
|
|
190
|
+
});
|
|
167
191
|
|
|
168
|
-
const validatedRows = ruleRows.
|
|
169
|
-
|
|
192
|
+
const validatedRows = ruleRows.filter(
|
|
193
|
+
(row): row is RuleProps => row.definition !== null,
|
|
170
194
|
);
|
|
171
195
|
|
|
172
196
|
return validatedRows.map((row) => new Rule(row));
|
|
@@ -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
|
+
});
|
|
@@ -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 { Schema } from "../schema.model.ts";
|
|
5
|
+
import { CreateSchemaChange, DropSchemaChange } from "./schema.base.ts";
|
|
6
|
+
|
|
7
|
+
export type SecurityLabelSchema =
|
|
8
|
+
| CreateSecurityLabelOnSchema
|
|
9
|
+
| DropSecurityLabelOnSchema;
|
|
10
|
+
|
|
11
|
+
export class CreateSecurityLabelOnSchema extends CreateSchemaChange {
|
|
12
|
+
public readonly schema: Schema;
|
|
13
|
+
public readonly securityLabel: SecurityLabelProps;
|
|
14
|
+
public readonly scope = "security_label" as const;
|
|
15
|
+
|
|
16
|
+
constructor(props: { schema: Schema; securityLabel: SecurityLabelProps }) {
|
|
17
|
+
super();
|
|
18
|
+
this.schema = props.schema;
|
|
19
|
+
this.securityLabel = props.securityLabel;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
get creates() {
|
|
23
|
+
return [
|
|
24
|
+
stableId.securityLabel(this.schema.stableId, this.securityLabel.provider),
|
|
25
|
+
];
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
get requires() {
|
|
29
|
+
return [this.schema.stableId];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
serialize(): string {
|
|
33
|
+
return [
|
|
34
|
+
"SECURITY LABEL FOR",
|
|
35
|
+
this.securityLabel.provider,
|
|
36
|
+
"ON SCHEMA",
|
|
37
|
+
this.schema.name,
|
|
38
|
+
"IS",
|
|
39
|
+
quoteLiteral(this.securityLabel.label),
|
|
40
|
+
].join(" ");
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export class DropSecurityLabelOnSchema extends DropSchemaChange {
|
|
45
|
+
public readonly schema: Schema;
|
|
46
|
+
public readonly securityLabel: SecurityLabelProps;
|
|
47
|
+
public readonly scope = "security_label" as const;
|
|
48
|
+
|
|
49
|
+
constructor(props: { schema: Schema; securityLabel: SecurityLabelProps }) {
|
|
50
|
+
super();
|
|
51
|
+
this.schema = props.schema;
|
|
52
|
+
this.securityLabel = props.securityLabel;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
get drops() {
|
|
56
|
+
return [
|
|
57
|
+
stableId.securityLabel(this.schema.stableId, this.securityLabel.provider),
|
|
58
|
+
];
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
get requires() {
|
|
62
|
+
return [
|
|
63
|
+
stableId.securityLabel(this.schema.stableId, this.securityLabel.provider),
|
|
64
|
+
this.schema.stableId,
|
|
65
|
+
];
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
serialize(): string {
|
|
69
|
+
return [
|
|
70
|
+
"SECURITY LABEL FOR",
|
|
71
|
+
this.securityLabel.provider,
|
|
72
|
+
"ON SCHEMA",
|
|
73
|
+
this.schema.name,
|
|
74
|
+
"IS NULL",
|
|
75
|
+
].join(" ");
|
|
76
|
+
}
|
|
77
|
+
}
|
|
@@ -3,6 +3,7 @@ import type { CommentSchema } from "./schema.comment.ts";
|
|
|
3
3
|
import type { CreateSchema } from "./schema.create.ts";
|
|
4
4
|
import type { DropSchema } from "./schema.drop.ts";
|
|
5
5
|
import type { SchemaPrivilege } from "./schema.privilege.ts";
|
|
6
|
+
import type { SecurityLabelSchema } from "./schema.security-label.ts";
|
|
6
7
|
|
|
7
8
|
/** Union of all schema-related change variants (`objectType: "schema"`). @category Change Types */
|
|
8
9
|
export type SchemaChange =
|
|
@@ -10,4 +11,5 @@ export type SchemaChange =
|
|
|
10
11
|
| CommentSchema
|
|
11
12
|
| CreateSchema
|
|
12
13
|
| DropSchema
|
|
13
|
-
| SchemaPrivilege
|
|
14
|
+
| SchemaPrivilege
|
|
15
|
+
| SecurityLabelSchema;
|
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
emitObjectPrivilegeChanges,
|
|
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 { AlterSchemaChangeOwner } from "./changes/schema.alter.ts";
|
|
8
9
|
import {
|
|
9
10
|
CreateCommentOnSchema,
|
|
@@ -16,6 +17,10 @@ import {
|
|
|
16
17
|
RevokeGrantOptionSchemaPrivileges,
|
|
17
18
|
RevokeSchemaPrivileges,
|
|
18
19
|
} from "./changes/schema.privilege.ts";
|
|
20
|
+
import {
|
|
21
|
+
CreateSecurityLabelOnSchema,
|
|
22
|
+
DropSecurityLabelOnSchema,
|
|
23
|
+
} from "./changes/schema.security-label.ts";
|
|
19
24
|
import type { SchemaChange } from "./changes/schema.types.ts";
|
|
20
25
|
import type { Schema } from "./schema.model.ts";
|
|
21
26
|
|
|
@@ -45,6 +50,14 @@ export function diffSchemas(
|
|
|
45
50
|
if (sc.comment !== null) {
|
|
46
51
|
changes.push(new CreateCommentOnSchema({ schema: sc }));
|
|
47
52
|
}
|
|
53
|
+
for (const label of sc.security_labels) {
|
|
54
|
+
changes.push(
|
|
55
|
+
new CreateSecurityLabelOnSchema({
|
|
56
|
+
schema: sc,
|
|
57
|
+
securityLabel: label,
|
|
58
|
+
}),
|
|
59
|
+
);
|
|
60
|
+
}
|
|
48
61
|
|
|
49
62
|
// PRIVILEGES: For created objects, compare against default privileges state
|
|
50
63
|
// The migration script will run ALTER DEFAULT PRIVILEGES before CREATE (via constraint spec),
|
|
@@ -87,7 +100,16 @@ export function diffSchemas(
|
|
|
87
100
|
}
|
|
88
101
|
|
|
89
102
|
for (const schemaId of dropped) {
|
|
90
|
-
|
|
103
|
+
const mainSchema = main[schemaId];
|
|
104
|
+
for (const label of mainSchema.security_labels) {
|
|
105
|
+
changes.push(
|
|
106
|
+
new DropSecurityLabelOnSchema({
|
|
107
|
+
schema: mainSchema,
|
|
108
|
+
securityLabel: label,
|
|
109
|
+
}),
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
changes.push(new DropSchema({ schema: mainSchema }));
|
|
91
113
|
}
|
|
92
114
|
|
|
93
115
|
for (const schemaId of altered) {
|
|
@@ -113,6 +135,26 @@ export function diffSchemas(
|
|
|
113
135
|
}
|
|
114
136
|
}
|
|
115
137
|
|
|
138
|
+
// SECURITY LABELS
|
|
139
|
+
changes.push(
|
|
140
|
+
...diffSecurityLabels<
|
|
141
|
+
CreateSecurityLabelOnSchema | DropSecurityLabelOnSchema
|
|
142
|
+
>(
|
|
143
|
+
mainSchema.security_labels,
|
|
144
|
+
branchSchema.security_labels,
|
|
145
|
+
(securityLabel) =>
|
|
146
|
+
new CreateSecurityLabelOnSchema({
|
|
147
|
+
schema: branchSchema,
|
|
148
|
+
securityLabel,
|
|
149
|
+
}),
|
|
150
|
+
(securityLabel) =>
|
|
151
|
+
new DropSecurityLabelOnSchema({
|
|
152
|
+
schema: mainSchema,
|
|
153
|
+
securityLabel,
|
|
154
|
+
}),
|
|
155
|
+
),
|
|
156
|
+
);
|
|
157
|
+
|
|
116
158
|
// PRIVILEGES
|
|
117
159
|
// Filter out owner privileges - owner always has ALL privileges implicitly
|
|
118
160
|
// and shouldn't be compared. Use branch owner as the reference.
|
|
@@ -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
|
/**
|
|
11
15
|
* All properties exposed by CREATE SCHEMA statement are included in diff output.
|
|
@@ -19,6 +23,7 @@ const schemaPropsSchema = z.object({
|
|
|
19
23
|
owner: z.string(),
|
|
20
24
|
comment: z.string().nullable(),
|
|
21
25
|
privileges: z.array(privilegePropsSchema),
|
|
26
|
+
security_labels: z.array(securityLabelPropsSchema).default([]).optional(),
|
|
22
27
|
});
|
|
23
28
|
|
|
24
29
|
type SchemaPrivilegeProps = PrivilegeProps;
|
|
@@ -29,6 +34,7 @@ export class Schema extends BasePgModel {
|
|
|
29
34
|
public readonly owner: SchemaProps["owner"];
|
|
30
35
|
public readonly comment: SchemaProps["comment"];
|
|
31
36
|
public readonly privileges: SchemaPrivilegeProps[];
|
|
37
|
+
public readonly security_labels: SecurityLabelProps[];
|
|
32
38
|
|
|
33
39
|
constructor(props: SchemaProps) {
|
|
34
40
|
super();
|
|
@@ -40,6 +46,7 @@ export class Schema extends BasePgModel {
|
|
|
40
46
|
this.owner = props.owner;
|
|
41
47
|
this.comment = props.comment;
|
|
42
48
|
this.privileges = props.privileges;
|
|
49
|
+
this.security_labels = props.security_labels ?? [];
|
|
43
50
|
}
|
|
44
51
|
|
|
45
52
|
get stableId(): `schema:${string}` {
|
|
@@ -57,6 +64,7 @@ export class Schema extends BasePgModel {
|
|
|
57
64
|
owner: this.owner,
|
|
58
65
|
comment: this.comment,
|
|
59
66
|
privileges: this.privileges,
|
|
67
|
+
security_labels: this.security_labels,
|
|
60
68
|
};
|
|
61
69
|
}
|
|
62
70
|
}
|
|
@@ -88,7 +96,19 @@ export async function extractSchemas(pool: Pool): Promise<Schema[]> {
|
|
|
88
96
|
)
|
|
89
97
|
from lateral aclexplode(COALESCE(nspacl, acldefault('n', nspowner))) as x(grantor, grantee, privilege_type, is_grantable)
|
|
90
98
|
), '[]'
|
|
91
|
-
) as privileges
|
|
99
|
+
) as privileges,
|
|
100
|
+
coalesce(
|
|
101
|
+
(
|
|
102
|
+
select json_agg(
|
|
103
|
+
json_build_object('provider', sl.provider, 'label', sl.label)
|
|
104
|
+
order by sl.provider
|
|
105
|
+
)
|
|
106
|
+
from pg_catalog.pg_seclabel sl
|
|
107
|
+
where sl.objoid = pg_namespace.oid
|
|
108
|
+
and sl.classoid = 'pg_namespace'::regclass
|
|
109
|
+
and sl.objsubid = 0
|
|
110
|
+
), '[]'
|
|
111
|
+
) as security_labels
|
|
92
112
|
from
|
|
93
113
|
pg_catalog.pg_namespace
|
|
94
114
|
left outer join extension_oids e on e.objid = oid
|