@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
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
import type { Pool } from "pg";
|
|
3
|
+
import { extractTriggers, Trigger } from "./trigger.model.ts";
|
|
4
|
+
|
|
5
|
+
const baseRow = {
|
|
6
|
+
schema: "public",
|
|
7
|
+
table_name: '"users"',
|
|
8
|
+
table_relkind: "r" as const,
|
|
9
|
+
function_schema: "public",
|
|
10
|
+
function_name: '"my_fn"',
|
|
11
|
+
trigger_type: 7,
|
|
12
|
+
enabled: "O" as const,
|
|
13
|
+
is_internal: false,
|
|
14
|
+
deferrable: false,
|
|
15
|
+
initially_deferred: false,
|
|
16
|
+
argument_count: 0,
|
|
17
|
+
column_numbers: null,
|
|
18
|
+
arguments: [] as string[],
|
|
19
|
+
when_condition: null,
|
|
20
|
+
old_table: null,
|
|
21
|
+
new_table: null,
|
|
22
|
+
is_partition_clone: false,
|
|
23
|
+
parent_trigger_name: null,
|
|
24
|
+
parent_table_schema: null,
|
|
25
|
+
parent_table_name: null,
|
|
26
|
+
is_on_partitioned_table: false,
|
|
27
|
+
owner: "postgres",
|
|
28
|
+
comment: null,
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const mockPool = (rows: unknown[]): Pool =>
|
|
32
|
+
({ query: async () => ({ rows }) }) as unknown as Pool;
|
|
33
|
+
|
|
34
|
+
const mockPoolSequence = (...attempts: unknown[][]): Pool => {
|
|
35
|
+
let i = 0;
|
|
36
|
+
return {
|
|
37
|
+
query: async () => ({
|
|
38
|
+
rows: attempts[Math.min(i++, attempts.length - 1)],
|
|
39
|
+
}),
|
|
40
|
+
} as unknown as Pool;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
const NO_BACKOFF = { backoffMs: 0 } as const;
|
|
44
|
+
|
|
45
|
+
describe("extractTriggers", () => {
|
|
46
|
+
test("skips rows where pg_get_triggerdef returned NULL after exhausting retries", async () => {
|
|
47
|
+
const triggers = await extractTriggers(
|
|
48
|
+
mockPool([
|
|
49
|
+
{
|
|
50
|
+
...baseRow,
|
|
51
|
+
name: '"good_trg"',
|
|
52
|
+
definition:
|
|
53
|
+
"CREATE TRIGGER good_trg BEFORE INSERT ON users FOR EACH ROW EXECUTE FUNCTION my_fn()",
|
|
54
|
+
},
|
|
55
|
+
{ ...baseRow, name: '"orphan_trg"', definition: null },
|
|
56
|
+
]),
|
|
57
|
+
NO_BACKOFF,
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
expect(triggers).toHaveLength(1);
|
|
61
|
+
expect(triggers[0]).toBeInstanceOf(Trigger);
|
|
62
|
+
expect(triggers[0]?.name).toBe('"good_trg"');
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
test("does not throw ZodError when the only row has a null definition", async () => {
|
|
66
|
+
await expect(
|
|
67
|
+
extractTriggers(
|
|
68
|
+
mockPool([{ ...baseRow, name: '"orphan"', definition: null }]),
|
|
69
|
+
NO_BACKOFF,
|
|
70
|
+
),
|
|
71
|
+
).resolves.toEqual([]);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
test("returns all triggers when every row has a valid definition", async () => {
|
|
75
|
+
const triggers = await extractTriggers(
|
|
76
|
+
mockPool([
|
|
77
|
+
{
|
|
78
|
+
...baseRow,
|
|
79
|
+
name: '"a"',
|
|
80
|
+
definition:
|
|
81
|
+
"CREATE TRIGGER a BEFORE INSERT ON users FOR EACH ROW EXECUTE FUNCTION my_fn()",
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
...baseRow,
|
|
85
|
+
name: '"b"',
|
|
86
|
+
definition:
|
|
87
|
+
"CREATE TRIGGER b AFTER UPDATE ON users FOR EACH ROW EXECUTE FUNCTION my_fn()",
|
|
88
|
+
},
|
|
89
|
+
]),
|
|
90
|
+
NO_BACKOFF,
|
|
91
|
+
);
|
|
92
|
+
expect(triggers.map((t) => t.name)).toEqual(['"a"', '"b"']);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
test("recovers when pg_get_triggerdef is NULL on first attempt but resolved on retry", async () => {
|
|
96
|
+
const triggers = await extractTriggers(
|
|
97
|
+
mockPoolSequence(
|
|
98
|
+
[{ ...baseRow, name: '"racy_trg"', definition: null }],
|
|
99
|
+
[
|
|
100
|
+
{
|
|
101
|
+
...baseRow,
|
|
102
|
+
name: '"racy_trg"',
|
|
103
|
+
definition:
|
|
104
|
+
"CREATE TRIGGER racy_trg BEFORE INSERT ON users FOR EACH ROW EXECUTE FUNCTION my_fn()",
|
|
105
|
+
},
|
|
106
|
+
],
|
|
107
|
+
),
|
|
108
|
+
{ retries: 2, backoffMs: 0 },
|
|
109
|
+
);
|
|
110
|
+
expect(triggers).toHaveLength(1);
|
|
111
|
+
expect(triggers[0]?.name).toBe('"racy_trg"');
|
|
112
|
+
});
|
|
113
|
+
});
|
|
@@ -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
|
|
|
6
10
|
const TriggerEnabledSchema = z.enum([
|
|
7
11
|
"O", // ORIGIN - trigger fires in "origin" and "local" replica modes
|
|
@@ -46,6 +50,15 @@ const triggerPropsSchema = z.object({
|
|
|
46
50
|
comment: z.string().nullable(),
|
|
47
51
|
});
|
|
48
52
|
|
|
53
|
+
// pg_get_triggerdef(oid, pretty) can return NULL when the trigger (its
|
|
54
|
+
// pg_trigger row) is dropped between catalog scan and resolution, or under
|
|
55
|
+
// transient catalog state. An unreadable trigger cannot be diffed, so we
|
|
56
|
+
// accept NULL here and filter the row out at extraction time rather than
|
|
57
|
+
// crashing the whole catalog parse with a ZodError.
|
|
58
|
+
const triggerRowSchema = triggerPropsSchema.extend({
|
|
59
|
+
definition: z.string().nullable(),
|
|
60
|
+
});
|
|
61
|
+
|
|
49
62
|
export type TriggerProps = z.infer<typeof triggerPropsSchema>;
|
|
50
63
|
|
|
51
64
|
export class Trigger extends BasePgModel {
|
|
@@ -154,8 +167,16 @@ export class Trigger extends BasePgModel {
|
|
|
154
167
|
}
|
|
155
168
|
}
|
|
156
169
|
|
|
157
|
-
export async function extractTriggers(
|
|
158
|
-
|
|
170
|
+
export async function extractTriggers(
|
|
171
|
+
pool: Pool,
|
|
172
|
+
options?: ExtractRetryOptions,
|
|
173
|
+
): Promise<Trigger[]> {
|
|
174
|
+
const triggerRows = await extractWithDefinitionRetry({
|
|
175
|
+
label: "triggers",
|
|
176
|
+
options,
|
|
177
|
+
hasNullDefinition: (row) => row.definition === null,
|
|
178
|
+
query: async () => {
|
|
179
|
+
const result = await pool.query<TriggerProps>(sql`
|
|
159
180
|
with extension_trigger_oids as (
|
|
160
181
|
select objid
|
|
161
182
|
from pg_depend d
|
|
@@ -260,9 +281,11 @@ export async function extractTriggers(pool: Pool): Promise<Trigger[]> {
|
|
|
260
281
|
|
|
261
282
|
order by 1, 2
|
|
262
283
|
`);
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
284
|
+
return result.rows.map((row: unknown) => triggerRowSchema.parse(row));
|
|
285
|
+
},
|
|
286
|
+
});
|
|
287
|
+
const validatedRows = triggerRows.filter(
|
|
288
|
+
(row): row is TriggerProps => row.definition !== null,
|
|
266
289
|
);
|
|
267
290
|
return validatedRows.map((row: TriggerProps) => new Trigger(row));
|
|
268
291
|
}
|
|
@@ -3,7 +3,11 @@ import type { CompositeType } from "../composite-type.model.ts";
|
|
|
3
3
|
|
|
4
4
|
abstract class BaseCompositeTypeChange extends BaseChange {
|
|
5
5
|
abstract readonly compositeType: CompositeType;
|
|
6
|
-
abstract readonly scope:
|
|
6
|
+
abstract readonly scope:
|
|
7
|
+
| "object"
|
|
8
|
+
| "comment"
|
|
9
|
+
| "privilege"
|
|
10
|
+
| "security_label";
|
|
7
11
|
readonly objectType: "composite_type" = "composite_type";
|
|
8
12
|
}
|
|
9
13
|
|
|
@@ -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 { CompositeType } from "../composite-type.model.ts";
|
|
5
|
+
import {
|
|
6
|
+
CreateCompositeTypeChange,
|
|
7
|
+
DropCompositeTypeChange,
|
|
8
|
+
} from "./composite-type.base.ts";
|
|
9
|
+
|
|
10
|
+
export type SecurityLabelCompositeType =
|
|
11
|
+
| CreateSecurityLabelOnCompositeType
|
|
12
|
+
| DropSecurityLabelOnCompositeType;
|
|
13
|
+
|
|
14
|
+
export class CreateSecurityLabelOnCompositeType extends CreateCompositeTypeChange {
|
|
15
|
+
public readonly compositeType: CompositeType;
|
|
16
|
+
public readonly securityLabel: SecurityLabelProps;
|
|
17
|
+
public readonly scope = "security_label" as const;
|
|
18
|
+
|
|
19
|
+
constructor(props: {
|
|
20
|
+
compositeType: CompositeType;
|
|
21
|
+
securityLabel: SecurityLabelProps;
|
|
22
|
+
}) {
|
|
23
|
+
super();
|
|
24
|
+
this.compositeType = props.compositeType;
|
|
25
|
+
this.securityLabel = props.securityLabel;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
get creates() {
|
|
29
|
+
return [
|
|
30
|
+
stableId.securityLabel(
|
|
31
|
+
this.compositeType.stableId,
|
|
32
|
+
this.securityLabel.provider,
|
|
33
|
+
),
|
|
34
|
+
];
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
get requires() {
|
|
38
|
+
return [this.compositeType.stableId];
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
serialize(): string {
|
|
42
|
+
return [
|
|
43
|
+
"SECURITY LABEL FOR",
|
|
44
|
+
this.securityLabel.provider,
|
|
45
|
+
"ON TYPE",
|
|
46
|
+
`${this.compositeType.schema}.${this.compositeType.name}`,
|
|
47
|
+
"IS",
|
|
48
|
+
quoteLiteral(this.securityLabel.label),
|
|
49
|
+
].join(" ");
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export class DropSecurityLabelOnCompositeType extends DropCompositeTypeChange {
|
|
54
|
+
public readonly compositeType: CompositeType;
|
|
55
|
+
public readonly securityLabel: SecurityLabelProps;
|
|
56
|
+
public readonly scope = "security_label" as const;
|
|
57
|
+
|
|
58
|
+
constructor(props: {
|
|
59
|
+
compositeType: CompositeType;
|
|
60
|
+
securityLabel: SecurityLabelProps;
|
|
61
|
+
}) {
|
|
62
|
+
super();
|
|
63
|
+
this.compositeType = props.compositeType;
|
|
64
|
+
this.securityLabel = props.securityLabel;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
get drops() {
|
|
68
|
+
return [
|
|
69
|
+
stableId.securityLabel(
|
|
70
|
+
this.compositeType.stableId,
|
|
71
|
+
this.securityLabel.provider,
|
|
72
|
+
),
|
|
73
|
+
];
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
get requires() {
|
|
77
|
+
return [
|
|
78
|
+
stableId.securityLabel(
|
|
79
|
+
this.compositeType.stableId,
|
|
80
|
+
this.securityLabel.provider,
|
|
81
|
+
),
|
|
82
|
+
this.compositeType.stableId,
|
|
83
|
+
];
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
serialize(): string {
|
|
87
|
+
return [
|
|
88
|
+
"SECURITY LABEL FOR",
|
|
89
|
+
this.securityLabel.provider,
|
|
90
|
+
"ON TYPE",
|
|
91
|
+
`${this.compositeType.schema}.${this.compositeType.name}`,
|
|
92
|
+
"IS NULL",
|
|
93
|
+
].join(" ");
|
|
94
|
+
}
|
|
95
|
+
}
|
|
@@ -3,6 +3,7 @@ import type { CommentCompositeType } from "./composite-type.comment.ts";
|
|
|
3
3
|
import type { CreateCompositeType } from "./composite-type.create.ts";
|
|
4
4
|
import type { DropCompositeType } from "./composite-type.drop.ts";
|
|
5
5
|
import type { CompositeTypePrivilege } from "./composite-type.privilege.ts";
|
|
6
|
+
import type { SecurityLabelCompositeType } from "./composite-type.security-label.ts";
|
|
6
7
|
|
|
7
8
|
/** Union of all composite-type-related change variants (`objectType: "composite_type"`). @category Change Types */
|
|
8
9
|
export type CompositeTypeChange =
|
|
@@ -10,4 +11,5 @@ export type CompositeTypeChange =
|
|
|
10
11
|
| CommentCompositeType
|
|
11
12
|
| CreateCompositeType
|
|
12
13
|
| DropCompositeType
|
|
13
|
-
| CompositeTypePrivilege
|
|
14
|
+
| CompositeTypePrivilege
|
|
15
|
+
| SecurityLabelCompositeType;
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
filterPublicBuiltInDefaults,
|
|
6
6
|
} from "../../base.privilege-diff.ts";
|
|
7
7
|
import type { ObjectDiffContext } from "../../diff-context.ts";
|
|
8
|
+
import { diffSecurityLabels } from "../../security-label.types.ts";
|
|
8
9
|
import { deepEqual, hasNonAlterableChanges } from "../../utils.ts";
|
|
9
10
|
import {
|
|
10
11
|
AlterCompositeTypeAddAttribute,
|
|
@@ -25,6 +26,10 @@ import {
|
|
|
25
26
|
RevokeCompositeTypePrivileges,
|
|
26
27
|
RevokeGrantOptionCompositeTypePrivileges,
|
|
27
28
|
} from "./changes/composite-type.privilege.ts";
|
|
29
|
+
import {
|
|
30
|
+
CreateSecurityLabelOnCompositeType,
|
|
31
|
+
DropSecurityLabelOnCompositeType,
|
|
32
|
+
} from "./changes/composite-type.security-label.ts";
|
|
28
33
|
import type { CompositeTypeChange } from "./changes/composite-type.types.ts";
|
|
29
34
|
import type { CompositeType } from "./composite-type.model.ts";
|
|
30
35
|
|
|
@@ -67,6 +72,14 @@ export function diffCompositeTypes(
|
|
|
67
72
|
if (ct.comment !== null) {
|
|
68
73
|
changes.push(new CreateCommentOnCompositeType({ compositeType: ct }));
|
|
69
74
|
}
|
|
75
|
+
for (const label of ct.security_labels) {
|
|
76
|
+
changes.push(
|
|
77
|
+
new CreateSecurityLabelOnCompositeType({
|
|
78
|
+
compositeType: ct,
|
|
79
|
+
securityLabel: label,
|
|
80
|
+
}),
|
|
81
|
+
);
|
|
82
|
+
}
|
|
70
83
|
// Attribute comments on creation
|
|
71
84
|
for (const attr of ct.columns) {
|
|
72
85
|
if (attr.comment !== null) {
|
|
@@ -189,6 +202,26 @@ export function diffCompositeTypes(
|
|
|
189
202
|
}
|
|
190
203
|
}
|
|
191
204
|
|
|
205
|
+
// SECURITY LABELS
|
|
206
|
+
changes.push(
|
|
207
|
+
...diffSecurityLabels<
|
|
208
|
+
CreateSecurityLabelOnCompositeType | DropSecurityLabelOnCompositeType
|
|
209
|
+
>(
|
|
210
|
+
mainCompositeType.security_labels,
|
|
211
|
+
branchCompositeType.security_labels,
|
|
212
|
+
(securityLabel) =>
|
|
213
|
+
new CreateSecurityLabelOnCompositeType({
|
|
214
|
+
compositeType: branchCompositeType,
|
|
215
|
+
securityLabel,
|
|
216
|
+
}),
|
|
217
|
+
(securityLabel) =>
|
|
218
|
+
new DropSecurityLabelOnCompositeType({
|
|
219
|
+
compositeType: mainCompositeType,
|
|
220
|
+
securityLabel,
|
|
221
|
+
}),
|
|
222
|
+
),
|
|
223
|
+
);
|
|
224
|
+
|
|
192
225
|
// ATTRIBUTE diffs
|
|
193
226
|
const mainAttrs = new Map(
|
|
194
227
|
mainCompositeType.columns.map((c) => [c.name, c]),
|
|
@@ -10,6 +10,11 @@ import {
|
|
|
10
10
|
type PrivilegeProps,
|
|
11
11
|
privilegePropsSchema,
|
|
12
12
|
} from "../../base.privilege-diff.ts";
|
|
13
|
+
import {
|
|
14
|
+
normalizeSecurityLabels,
|
|
15
|
+
type SecurityLabelProps,
|
|
16
|
+
securityLabelPropsSchema,
|
|
17
|
+
} from "../../security-label.types.ts";
|
|
13
18
|
import { ReplicaIdentitySchema } from "../../table/table.model.ts";
|
|
14
19
|
|
|
15
20
|
const compositeTypePropsSchema = z.object({
|
|
@@ -30,6 +35,7 @@ const compositeTypePropsSchema = z.object({
|
|
|
30
35
|
comment: z.string().nullable(),
|
|
31
36
|
columns: z.array(columnPropsSchema),
|
|
32
37
|
privileges: z.array(privilegePropsSchema),
|
|
38
|
+
security_labels: z.array(securityLabelPropsSchema).default([]).optional(),
|
|
33
39
|
});
|
|
34
40
|
|
|
35
41
|
type CompositeTypePrivilegeProps = PrivilegeProps;
|
|
@@ -53,6 +59,7 @@ export class CompositeType extends BasePgModel implements TableLikeObject {
|
|
|
53
59
|
public readonly comment: CompositeTypeProps["comment"];
|
|
54
60
|
public readonly columns: CompositeTypeProps["columns"];
|
|
55
61
|
public readonly privileges: CompositeTypePrivilegeProps[];
|
|
62
|
+
public readonly security_labels: SecurityLabelProps[];
|
|
56
63
|
|
|
57
64
|
constructor(props: CompositeTypeProps) {
|
|
58
65
|
super();
|
|
@@ -77,6 +84,7 @@ export class CompositeType extends BasePgModel implements TableLikeObject {
|
|
|
77
84
|
this.comment = props.comment;
|
|
78
85
|
this.columns = props.columns;
|
|
79
86
|
this.privileges = props.privileges;
|
|
87
|
+
this.security_labels = props.security_labels ?? [];
|
|
80
88
|
}
|
|
81
89
|
|
|
82
90
|
get stableId(): `type:${string}` {
|
|
@@ -107,6 +115,7 @@ export class CompositeType extends BasePgModel implements TableLikeObject {
|
|
|
107
115
|
comment: this.comment,
|
|
108
116
|
columns: this.columns,
|
|
109
117
|
privileges: this.privileges,
|
|
118
|
+
security_labels: this.security_labels,
|
|
110
119
|
};
|
|
111
120
|
}
|
|
112
121
|
|
|
@@ -131,6 +140,7 @@ export class CompositeType extends BasePgModel implements TableLikeObject {
|
|
|
131
140
|
data: {
|
|
132
141
|
...this.dataFields,
|
|
133
142
|
columns: normalizeColumns(),
|
|
143
|
+
security_labels: normalizeSecurityLabels(this.security_labels),
|
|
134
144
|
},
|
|
135
145
|
};
|
|
136
146
|
}
|
|
@@ -165,7 +175,8 @@ export async function extractCompositeTypes(
|
|
|
165
175
|
obj_description(c.reltype, 'pg_type') AS comment,
|
|
166
176
|
c.relacl AS relacl, -- used by privileges LATERAL
|
|
167
177
|
c.relowner AS relowner,
|
|
168
|
-
c.oid AS oid
|
|
178
|
+
c.oid AS oid,
|
|
179
|
+
c.reltype AS reltype
|
|
169
180
|
FROM pg_catalog.pg_class c
|
|
170
181
|
LEFT JOIN extension_oids e ON c.reltype = e.objid
|
|
171
182
|
WHERE NOT c.relnamespace::regnamespace::text LIKE ANY (ARRAY['pg\\_%', 'information\\_schema'])
|
|
@@ -189,7 +200,20 @@ export async function extractCompositeTypes(
|
|
|
189
200
|
ct.owner,
|
|
190
201
|
ct.comment,
|
|
191
202
|
COALESCE(priv.privileges, '[]') AS privileges,
|
|
192
|
-
COALESCE(cols.columns, '[]') AS columns
|
|
203
|
+
COALESCE(cols.columns, '[]') AS columns,
|
|
204
|
+
COALESCE(
|
|
205
|
+
(
|
|
206
|
+
SELECT json_agg(
|
|
207
|
+
json_build_object('provider', sl.provider, 'label', sl.label)
|
|
208
|
+
ORDER BY sl.provider
|
|
209
|
+
)
|
|
210
|
+
FROM pg_catalog.pg_seclabel sl
|
|
211
|
+
WHERE sl.objoid = ct.reltype
|
|
212
|
+
AND sl.classoid = 'pg_type'::regclass
|
|
213
|
+
AND sl.objsubid = 0
|
|
214
|
+
),
|
|
215
|
+
'[]'::json
|
|
216
|
+
) AS security_labels
|
|
193
217
|
FROM composite_types ct
|
|
194
218
|
|
|
195
219
|
-- privileges as a per-row LATERAL subquery
|
|
@@ -3,7 +3,11 @@ import type { Enum } from "../enum.model.ts";
|
|
|
3
3
|
|
|
4
4
|
abstract class BaseEnumChange extends BaseChange {
|
|
5
5
|
abstract readonly enum: Enum;
|
|
6
|
-
abstract readonly scope:
|
|
6
|
+
abstract readonly scope:
|
|
7
|
+
| "object"
|
|
8
|
+
| "comment"
|
|
9
|
+
| "privilege"
|
|
10
|
+
| "security_label";
|
|
7
11
|
readonly objectType: "enum" = "enum";
|
|
8
12
|
}
|
|
9
13
|
|
|
@@ -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 { Enum } from "../enum.model.ts";
|
|
5
|
+
import { CreateEnumChange, DropEnumChange } from "./enum.base.ts";
|
|
6
|
+
|
|
7
|
+
export type SecurityLabelEnum =
|
|
8
|
+
| CreateSecurityLabelOnEnum
|
|
9
|
+
| DropSecurityLabelOnEnum;
|
|
10
|
+
|
|
11
|
+
export class CreateSecurityLabelOnEnum extends CreateEnumChange {
|
|
12
|
+
public readonly enum: Enum;
|
|
13
|
+
public readonly securityLabel: SecurityLabelProps;
|
|
14
|
+
public readonly scope = "security_label" as const;
|
|
15
|
+
|
|
16
|
+
constructor(props: { enum: Enum; securityLabel: SecurityLabelProps }) {
|
|
17
|
+
super();
|
|
18
|
+
this.enum = props.enum;
|
|
19
|
+
this.securityLabel = props.securityLabel;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
get creates() {
|
|
23
|
+
return [
|
|
24
|
+
stableId.securityLabel(this.enum.stableId, this.securityLabel.provider),
|
|
25
|
+
];
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
get requires() {
|
|
29
|
+
return [this.enum.stableId];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
serialize(): string {
|
|
33
|
+
return [
|
|
34
|
+
"SECURITY LABEL FOR",
|
|
35
|
+
this.securityLabel.provider,
|
|
36
|
+
"ON TYPE",
|
|
37
|
+
`${this.enum.schema}.${this.enum.name}`,
|
|
38
|
+
"IS",
|
|
39
|
+
quoteLiteral(this.securityLabel.label),
|
|
40
|
+
].join(" ");
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export class DropSecurityLabelOnEnum extends DropEnumChange {
|
|
45
|
+
public readonly enum: Enum;
|
|
46
|
+
public readonly securityLabel: SecurityLabelProps;
|
|
47
|
+
public readonly scope = "security_label" as const;
|
|
48
|
+
|
|
49
|
+
constructor(props: { enum: Enum; securityLabel: SecurityLabelProps }) {
|
|
50
|
+
super();
|
|
51
|
+
this.enum = props.enum;
|
|
52
|
+
this.securityLabel = props.securityLabel;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
get drops() {
|
|
56
|
+
return [
|
|
57
|
+
stableId.securityLabel(this.enum.stableId, this.securityLabel.provider),
|
|
58
|
+
];
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
get requires() {
|
|
62
|
+
return [
|
|
63
|
+
stableId.securityLabel(this.enum.stableId, this.securityLabel.provider),
|
|
64
|
+
this.enum.stableId,
|
|
65
|
+
];
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
serialize(): string {
|
|
69
|
+
return [
|
|
70
|
+
"SECURITY LABEL FOR",
|
|
71
|
+
this.securityLabel.provider,
|
|
72
|
+
"ON TYPE",
|
|
73
|
+
`${this.enum.schema}.${this.enum.name}`,
|
|
74
|
+
"IS NULL",
|
|
75
|
+
].join(" ");
|
|
76
|
+
}
|
|
77
|
+
}
|
|
@@ -3,6 +3,7 @@ import type { CommentEnum } from "./enum.comment.ts";
|
|
|
3
3
|
import type { CreateEnum } from "./enum.create.ts";
|
|
4
4
|
import type { DropEnum } from "./enum.drop.ts";
|
|
5
5
|
import type { EnumPrivilege } from "./enum.privilege.ts";
|
|
6
|
+
import type { SecurityLabelEnum } from "./enum.security-label.ts";
|
|
6
7
|
|
|
7
8
|
/** Union of all enum-related change variants (`objectType: "enum"`). @category Change Types */
|
|
8
9
|
export type EnumChange =
|
|
@@ -10,4 +11,5 @@ export type EnumChange =
|
|
|
10
11
|
| CommentEnum
|
|
11
12
|
| CreateEnum
|
|
12
13
|
| DropEnum
|
|
13
|
-
| EnumPrivilege
|
|
14
|
+
| EnumPrivilege
|
|
15
|
+
| SecurityLabelEnum;
|
|
@@ -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 {
|
|
9
10
|
AlterEnumAddValue,
|
|
10
11
|
AlterEnumChangeOwner,
|
|
@@ -20,6 +21,10 @@ import {
|
|
|
20
21
|
RevokeEnumPrivileges,
|
|
21
22
|
RevokeGrantOptionEnumPrivileges,
|
|
22
23
|
} from "./changes/enum.privilege.ts";
|
|
24
|
+
import {
|
|
25
|
+
CreateSecurityLabelOnEnum,
|
|
26
|
+
DropSecurityLabelOnEnum,
|
|
27
|
+
} from "./changes/enum.security-label.ts";
|
|
23
28
|
import type { EnumChange } from "./changes/enum.types.ts";
|
|
24
29
|
import type { Enum } from "./enum.model.ts";
|
|
25
30
|
|
|
@@ -61,6 +66,14 @@ export function diffEnums(
|
|
|
61
66
|
if (createdEnum.comment !== null) {
|
|
62
67
|
changes.push(new CreateCommentOnEnum({ enum: createdEnum }));
|
|
63
68
|
}
|
|
69
|
+
for (const label of createdEnum.security_labels) {
|
|
70
|
+
changes.push(
|
|
71
|
+
new CreateSecurityLabelOnEnum({
|
|
72
|
+
enum: createdEnum,
|
|
73
|
+
securityLabel: label,
|
|
74
|
+
}),
|
|
75
|
+
);
|
|
76
|
+
}
|
|
64
77
|
|
|
65
78
|
// PRIVILEGES: For created objects, compare against default privileges state
|
|
66
79
|
// The migration script will run ALTER DEFAULT PRIVILEGES before CREATE (via constraint spec),
|
|
@@ -196,6 +209,26 @@ export function diffEnums(
|
|
|
196
209
|
}
|
|
197
210
|
}
|
|
198
211
|
|
|
212
|
+
// SECURITY LABELS
|
|
213
|
+
changes.push(
|
|
214
|
+
...diffSecurityLabels<
|
|
215
|
+
CreateSecurityLabelOnEnum | DropSecurityLabelOnEnum
|
|
216
|
+
>(
|
|
217
|
+
mainEnum.security_labels,
|
|
218
|
+
branchEnum.security_labels,
|
|
219
|
+
(securityLabel) =>
|
|
220
|
+
new CreateSecurityLabelOnEnum({
|
|
221
|
+
enum: branchEnum,
|
|
222
|
+
securityLabel,
|
|
223
|
+
}),
|
|
224
|
+
(securityLabel) =>
|
|
225
|
+
new DropSecurityLabelOnEnum({
|
|
226
|
+
enum: mainEnum,
|
|
227
|
+
securityLabel,
|
|
228
|
+
}),
|
|
229
|
+
),
|
|
230
|
+
);
|
|
231
|
+
|
|
199
232
|
// PRIVILEGES
|
|
200
233
|
// Filter out PUBLIC's built-in default USAGE privilege from main catalog
|
|
201
234
|
// (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 enumLabelSchema = z.object({
|
|
11
15
|
sort_order: z.number(),
|
|
@@ -33,6 +37,7 @@ const enumPropsSchema = z.object({
|
|
|
33
37
|
labels: z.array(enumLabelSchema),
|
|
34
38
|
comment: z.string().nullable(),
|
|
35
39
|
privileges: z.array(privilegePropsSchema),
|
|
40
|
+
security_labels: z.array(securityLabelPropsSchema).default([]).optional(),
|
|
36
41
|
});
|
|
37
42
|
|
|
38
43
|
type EnumPrivilegeProps = PrivilegeProps;
|
|
@@ -45,6 +50,7 @@ export class Enum extends BasePgModel {
|
|
|
45
50
|
public readonly labels: EnumProps["labels"];
|
|
46
51
|
public readonly comment: EnumProps["comment"];
|
|
47
52
|
public readonly privileges: EnumPrivilegeProps[];
|
|
53
|
+
public readonly security_labels: SecurityLabelProps[];
|
|
48
54
|
|
|
49
55
|
constructor(props: EnumProps) {
|
|
50
56
|
super();
|
|
@@ -58,6 +64,7 @@ export class Enum extends BasePgModel {
|
|
|
58
64
|
this.labels = props.labels;
|
|
59
65
|
this.comment = props.comment;
|
|
60
66
|
this.privileges = props.privileges;
|
|
67
|
+
this.security_labels = props.security_labels ?? [];
|
|
61
68
|
}
|
|
62
69
|
|
|
63
70
|
get stableId(): `type:${string}` {
|
|
@@ -105,6 +112,7 @@ export class Enum extends BasePgModel {
|
|
|
105
112
|
labels,
|
|
106
113
|
comment: this.comment,
|
|
107
114
|
privileges,
|
|
115
|
+
security_labels: this.security_labels,
|
|
108
116
|
};
|
|
109
117
|
}
|
|
110
118
|
}
|
|
@@ -118,6 +126,7 @@ export async function extractEnums(pool: Pool): Promise<Enum[]> {
|
|
|
118
126
|
owner: string;
|
|
119
127
|
comment: string | null;
|
|
120
128
|
privileges: { grantee: string; privilege: string; grantable: boolean }[];
|
|
129
|
+
security_labels: { provider: string; label: string }[];
|
|
121
130
|
}>(sql`
|
|
122
131
|
with extension_oids as (
|
|
123
132
|
select
|
|
@@ -147,7 +156,20 @@ select
|
|
|
147
156
|
)
|
|
148
157
|
from lateral aclexplode(COALESCE(t.typacl, acldefault('T', t.typowner))) as x(grantor, grantee, privilege_type, is_grantable)
|
|
149
158
|
), '[]'
|
|
150
|
-
) as privileges
|
|
159
|
+
) as privileges,
|
|
160
|
+
coalesce(
|
|
161
|
+
(
|
|
162
|
+
select json_agg(
|
|
163
|
+
json_build_object('provider', sl.provider, 'label', sl.label)
|
|
164
|
+
order by sl.provider
|
|
165
|
+
)
|
|
166
|
+
from pg_catalog.pg_seclabel sl
|
|
167
|
+
where sl.objoid = t.oid
|
|
168
|
+
and sl.classoid = 'pg_type'::regclass
|
|
169
|
+
and sl.objsubid = 0
|
|
170
|
+
),
|
|
171
|
+
'[]'::json
|
|
172
|
+
) as security_labels
|
|
151
173
|
from
|
|
152
174
|
pg_catalog.pg_enum e
|
|
153
175
|
inner join pg_catalog.pg_type t on t.oid = e.enumtypid
|
|
@@ -170,6 +192,7 @@ order by
|
|
|
170
192
|
privilege: string;
|
|
171
193
|
grantable: boolean;
|
|
172
194
|
}[];
|
|
195
|
+
security_labels: { provider: string; label: string }[];
|
|
173
196
|
}
|
|
174
197
|
> = {};
|
|
175
198
|
for (const e of enumRows) {
|
|
@@ -182,6 +205,7 @@ order by
|
|
|
182
205
|
labels: [],
|
|
183
206
|
comment: e.comment,
|
|
184
207
|
privileges: e.privileges,
|
|
208
|
+
security_labels: e.security_labels,
|
|
185
209
|
};
|
|
186
210
|
}
|
|
187
211
|
grouped[key].labels.push({ sort_order: e.sort_order, label: e.label });
|