@supabase/pg-delta 1.0.0-alpha.17 → 1.0.0-alpha.19

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.
Files changed (33) hide show
  1. package/dist/core/expand-replace-dependencies.js +69 -0
  2. package/dist/core/objects/index/index.model.js +12 -2
  3. package/dist/core/objects/procedure/procedure.diff.js +33 -20
  4. package/dist/core/objects/rls-policy/changes/rls-policy.create.js +23 -0
  5. package/dist/core/objects/rls-policy/rls-policy.model.d.ts +49 -0
  6. package/dist/core/objects/rls-policy/rls-policy.model.js +122 -1
  7. package/dist/core/objects/table/table.diff.js +1 -0
  8. package/dist/core/objects/table/table.model.d.ts +4 -0
  9. package/dist/core/objects/table/table.model.js +2 -0
  10. package/dist/core/plan/sql-format/fixtures.js +8 -0
  11. package/dist/core/post-diff-cycle-breaking.d.ts +7 -0
  12. package/dist/core/post-diff-cycle-breaking.js +69 -3
  13. package/package.json +1 -1
  14. package/src/core/catalog.snapshot.test.ts +2 -0
  15. package/src/core/expand-replace-dependencies.test.ts +118 -0
  16. package/src/core/expand-replace-dependencies.ts +78 -0
  17. package/src/core/objects/index/index.model.test.ts +83 -0
  18. package/src/core/objects/index/index.model.ts +13 -4
  19. package/src/core/objects/procedure/procedure.diff.test.ts +100 -2
  20. package/src/core/objects/procedure/procedure.diff.ts +39 -21
  21. package/src/core/objects/rls-policy/changes/rls-policy.alter.test.ts +16 -0
  22. package/src/core/objects/rls-policy/changes/rls-policy.create.test.ts +128 -0
  23. package/src/core/objects/rls-policy/changes/rls-policy.create.ts +27 -0
  24. package/src/core/objects/rls-policy/changes/rls-policy.drop.test.ts +2 -0
  25. package/src/core/objects/rls-policy/rls-policy.diff.test.ts +2 -0
  26. package/src/core/objects/rls-policy/rls-policy.model.ts +134 -1
  27. package/src/core/objects/table/changes/table.alter.test.ts +1 -0
  28. package/src/core/objects/table/table.diff.test.ts +102 -0
  29. package/src/core/objects/table/table.diff.ts +1 -0
  30. package/src/core/objects/table/table.model.ts +2 -0
  31. package/src/core/plan/sql-format/fixtures.ts +8 -0
  32. package/src/core/post-diff-cycle-breaking.test.ts +142 -0
  33. package/src/core/post-diff-cycle-breaking.ts +83 -2
@@ -49,8 +49,7 @@ export function diffProcedures(
49
49
 
50
50
  const changes: ProcedureChange[] = [];
51
51
 
52
- for (const procedureId of created) {
53
- const proc = branch[procedureId];
52
+ const appendCreateProcedureChanges = (proc: Procedure) => {
54
53
  changes.push(new CreateProcedure({ procedure: proc }));
55
54
 
56
55
  // OWNER: If the procedure should be owned by someone other than the current user,
@@ -112,6 +111,10 @@ export function diffProcedures(
112
111
  ctx.version,
113
112
  ) as ProcedureChange[]),
114
113
  );
114
+ };
115
+
116
+ for (const procedureId of created) {
117
+ appendCreateProcedureChanges(branch[procedureId]);
115
118
  }
116
119
 
117
120
  for (const procedureId of dropped) {
@@ -122,22 +125,18 @@ export function diffProcedures(
122
125
  const mainProcedure = main[procedureId];
123
126
  const branchProcedure = branch[procedureId];
124
127
 
125
- // Check if non-alterable properties have changed
126
- // These require dropping and recreating the procedure
127
- const NON_ALTERABLE_FIELDS: Array<keyof Procedure> = [
128
+ // Fields that are part of the function's identity/signature. PostgreSQL
129
+ // rejects `CREATE OR REPLACE FUNCTION` for any of these changes with
130
+ // errors such as:
131
+ // - cannot change return type of existing function
132
+ // - cannot change name of input parameter "..."
133
+ // - cannot change whether a procedure has output parameters
134
+ // - cannot remove parameter defaults from existing function
135
+ // These require `DROP FUNCTION` followed by `CREATE FUNCTION`.
136
+ const SIGNATURE_BREAKING_FIELDS: Array<keyof Procedure> = [
128
137
  "kind",
129
138
  "return_type",
130
139
  "return_type_schema",
131
- "language",
132
- // The following properties are alterable in SQL, but our generator may choose
133
- // to replace on changes not covered by explicit ALTER actions. Keep them out here
134
- // to allow ALTER for those we implement below.
135
- // security_definer,
136
- // volatility,
137
- // parallel_safety,
138
- // is_strict,
139
- // leakproof,
140
- // Returns-set is part of the signature and not alterable
141
140
  "returns_set",
142
141
  "argument_count",
143
142
  "argument_default_count",
@@ -146,26 +145,45 @@ export function diffProcedures(
146
145
  "all_argument_types",
147
146
  "argument_modes",
148
147
  "argument_defaults",
148
+ ];
149
+ // Fields where `CREATE OR REPLACE` is sufficient - body replacement only.
150
+ // Other fields (security_definer, volatility, parallel_safety, is_strict,
151
+ // leakproof, config) are alterable via dedicated ALTER actions below.
152
+ const OR_REPLACEABLE_NON_ALTERABLE_FIELDS: Array<keyof Procedure> = [
153
+ "language",
149
154
  "source_code",
150
155
  "binary_path",
151
156
  "sql_body",
152
- // config is alterable via SET/RESET
153
157
  ];
154
- const nonAlterablePropsChanged = hasNonAlterableChanges(
158
+ const signatureChanged = hasNonAlterableChanges(
155
159
  mainProcedure,
156
160
  branchProcedure,
157
- NON_ALTERABLE_FIELDS,
161
+ SIGNATURE_BREAKING_FIELDS,
158
162
  {
159
163
  argument_names: deepEqual,
160
164
  argument_types: deepEqual,
161
165
  all_argument_types: deepEqual,
162
166
  argument_modes: deepEqual,
163
- config: deepEqual,
164
167
  },
165
168
  );
169
+ const nonAlterablePropsChanged =
170
+ signatureChanged ||
171
+ hasNonAlterableChanges(
172
+ mainProcedure,
173
+ branchProcedure,
174
+ OR_REPLACEABLE_NON_ALTERABLE_FIELDS,
175
+ );
166
176
 
167
- if (nonAlterablePropsChanged) {
168
- // Replace the entire procedure
177
+ if (signatureChanged) {
178
+ // PostgreSQL cannot change an existing function's signature via
179
+ // `CREATE OR REPLACE`. Drop the old signature, then recreate.
180
+ // `expandReplaceDependencies` will cascade the replacement to dependent
181
+ // objects (views, triggers, column defaults) via pg_depend edges.
182
+ changes.push(new DropProcedure({ procedure: mainProcedure }));
183
+ appendCreateProcedureChanges(branchProcedure);
184
+ } else if (nonAlterablePropsChanged) {
185
+ // Body-only non-alterable change - `CREATE OR REPLACE` preserves the
186
+ // function OID and keeps dependent objects attached.
169
187
  changes.push(
170
188
  new CreateProcedure({ procedure: branchProcedure, orReplace: true }),
171
189
  );
@@ -23,6 +23,8 @@ describe.concurrent("rls-policy", () => {
23
23
  with_check_expression: null,
24
24
  owner: "owner",
25
25
  comment: null,
26
+ referenced_relations: [],
27
+ referenced_procedures: [],
26
28
  };
27
29
  const policy = new RlsPolicy({
28
30
  ...props,
@@ -52,6 +54,8 @@ describe.concurrent("rls-policy", () => {
52
54
  with_check_expression: null,
53
55
  owner: "owner",
54
56
  comment: null,
57
+ referenced_relations: [],
58
+ referenced_procedures: [],
55
59
  };
56
60
  const policy = new RlsPolicy({
57
61
  ...props,
@@ -81,6 +85,8 @@ describe.concurrent("rls-policy", () => {
81
85
  with_check_expression: null,
82
86
  owner: "owner",
83
87
  comment: null,
88
+ referenced_relations: [],
89
+ referenced_procedures: [],
84
90
  };
85
91
  const main = new RlsPolicy({
86
92
  ...props,
@@ -120,6 +126,8 @@ describe.concurrent("rls-policy", () => {
120
126
  with_check_expression: null,
121
127
  owner: "owner",
122
128
  comment: null,
129
+ referenced_relations: [],
130
+ referenced_procedures: [],
123
131
  };
124
132
  const main = new RlsPolicy({
125
133
  ...props,
@@ -159,6 +167,8 @@ describe.concurrent("rls-policy", () => {
159
167
  with_check_expression: null,
160
168
  owner: "test",
161
169
  comment: null,
170
+ referenced_relations: [],
171
+ referenced_procedures: [],
162
172
  };
163
173
  const policy = new RlsPolicy({
164
174
  ...props,
@@ -188,6 +198,8 @@ describe.concurrent("rls-policy", () => {
188
198
  with_check_expression: null,
189
199
  owner: "test",
190
200
  comment: null,
201
+ referenced_relations: [],
202
+ referenced_procedures: [],
191
203
  };
192
204
  const policy = new RlsPolicy({
193
205
  ...props,
@@ -217,6 +229,8 @@ describe.concurrent("rls-policy", () => {
217
229
  using_expression: "expr",
218
230
  owner: "test",
219
231
  comment: null,
232
+ referenced_relations: [],
233
+ referenced_procedures: [],
220
234
  };
221
235
  const policy = new RlsPolicy({
222
236
  ...props,
@@ -246,6 +260,8 @@ describe.concurrent("rls-policy", () => {
246
260
  using_expression: "expr",
247
261
  owner: "test",
248
262
  comment: null,
263
+ referenced_relations: [],
264
+ referenced_procedures: [],
249
265
  };
250
266
  const policy = new RlsPolicy({
251
267
  ...props,
@@ -1,5 +1,6 @@
1
1
  import { describe, expect, test } from "bun:test";
2
2
  import { assertValidSql } from "../../../test-utils/assert-valid-sql.ts";
3
+ import { stableId } from "../../utils.ts";
3
4
  import { RlsPolicy } from "../rls-policy.model.ts";
4
5
  import { CreateRlsPolicy } from "./rls-policy.create.ts";
5
6
 
@@ -16,6 +17,8 @@ describe("rls-policy", () => {
16
17
  with_check_expression: null,
17
18
  owner: "test",
18
19
  comment: null,
20
+ referenced_relations: [],
21
+ referenced_procedures: [],
19
22
  });
20
23
 
21
24
  const change = new CreateRlsPolicy({
@@ -41,6 +44,8 @@ describe("rls-policy", () => {
41
44
  with_check_expression: null,
42
45
  owner: "test",
43
46
  comment: null,
47
+ referenced_relations: [],
48
+ referenced_procedures: [],
44
49
  });
45
50
 
46
51
  const change = new CreateRlsPolicy({
@@ -66,6 +71,8 @@ describe("rls-policy", () => {
66
71
  with_check_expression: "expr2",
67
72
  owner: "test",
68
73
  comment: null,
74
+ referenced_relations: [],
75
+ referenced_procedures: [],
69
76
  });
70
77
 
71
78
  const change = new CreateRlsPolicy({
@@ -78,4 +85,125 @@ describe("rls-policy", () => {
78
85
  "CREATE POLICY test_policy_all ON public.test_table AS RESTRICTIVE FOR UPDATE TO role1, role2 USING (expr1) WITH CHECK (expr2)",
79
86
  );
80
87
  });
88
+
89
+ test("requires referenced relations reported by pg_depend", () => {
90
+ const policy = new RlsPolicy({
91
+ schema: "app",
92
+ name: "cross_relation_policy",
93
+ table_name: "accounts",
94
+ command: "r",
95
+ permissive: true,
96
+ roles: ["public"],
97
+ using_expression:
98
+ "(EXISTS (SELECT 1 FROM app.users) AND EXISTS (SELECT 1 FROM app.active_accounts))",
99
+ with_check_expression:
100
+ "(id IN (SELECT account_id FROM app.memberships WHERE active))",
101
+ owner: "test",
102
+ comment: null,
103
+ referenced_relations: [
104
+ { kind: "table", schema: "app", name: "users" },
105
+ { kind: "table", schema: "app", name: "memberships" },
106
+ { kind: "view", schema: "app", name: "active_accounts" },
107
+ { kind: "materialized_view", schema: "app", name: "account_stats" },
108
+ { kind: "foreign_table", schema: "app", name: "remote_profiles" },
109
+ ],
110
+ referenced_procedures: [],
111
+ });
112
+
113
+ const change = new CreateRlsPolicy({ policy });
114
+
115
+ expect(change.requires).toContain(stableId.table("app", "users"));
116
+ expect(change.requires).toContain(stableId.table("app", "memberships"));
117
+ expect(change.requires).toContain(stableId.view("app", "active_accounts"));
118
+ expect(change.requires).toContain(
119
+ stableId.materializedView("app", "account_stats"),
120
+ );
121
+ expect(change.requires).toContain(
122
+ stableId.foreignTable("app", "remote_profiles"),
123
+ );
124
+ });
125
+
126
+ test("requires referenced procedures reported by pg_depend", () => {
127
+ const policy = new RlsPolicy({
128
+ schema: "app",
129
+ name: "function_guarded_policy",
130
+ table_name: "accounts",
131
+ command: "r",
132
+ permissive: true,
133
+ roles: ["public"],
134
+ using_expression: "public.is_admin()",
135
+ with_check_expression: null,
136
+ owner: "test",
137
+ comment: null,
138
+ referenced_relations: [],
139
+ referenced_procedures: [
140
+ { schema: "public", name: "is_admin", argument_types: [] },
141
+ {
142
+ schema: "public",
143
+ name: "has_role",
144
+ argument_types: ["text", "integer"],
145
+ },
146
+ ],
147
+ });
148
+
149
+ const change = new CreateRlsPolicy({ policy });
150
+
151
+ expect(change.requires).toContain(stableId.procedure("public", "is_admin"));
152
+ expect(change.requires).toContain(
153
+ stableId.procedure("public", "has_role", "text,integer"),
154
+ );
155
+ });
156
+
157
+ test("does not require additional objects when referenced lists are empty", () => {
158
+ const policy = new RlsPolicy({
159
+ schema: "app",
160
+ name: "simple_policy",
161
+ table_name: "accounts",
162
+ command: "*",
163
+ permissive: true,
164
+ roles: [],
165
+ using_expression: null,
166
+ with_check_expression: null,
167
+ owner: "test",
168
+ comment: null,
169
+ referenced_relations: [],
170
+ referenced_procedures: [],
171
+ });
172
+
173
+ const change = new CreateRlsPolicy({ policy });
174
+
175
+ expect(change.requires).toEqual([
176
+ stableId.schema("app"),
177
+ stableId.table("app", "accounts"),
178
+ stableId.role("test"),
179
+ ]);
180
+ });
181
+
182
+ // Sequences referenced via nextval() are a known gap. pg_depend only
183
+ // records the sequence edge when the argument is written as a regclass
184
+ // literal (e.g. `nextval('app.seq'::regclass)`); bare string literals
185
+ // produce no pg_depend row. Tracked in
186
+ // https://github.com/supabase/pg-toolbelt/issues/220.
187
+ test.skip("requires referenced sequences (follow-up)", () => {
188
+ const policy = new RlsPolicy({
189
+ schema: "app",
190
+ name: "sequence_policy",
191
+ table_name: "accounts",
192
+ command: "r",
193
+ permissive: true,
194
+ roles: ["public"],
195
+ using_expression: "id < nextval('app.next_id'::regclass)",
196
+ with_check_expression: null,
197
+ owner: "test",
198
+ comment: null,
199
+ referenced_relations: [],
200
+ referenced_procedures: [],
201
+ });
202
+
203
+ const change = new CreateRlsPolicy({ policy });
204
+
205
+ // Expected once the gap is closed:
206
+ // expect(change.requires).toContain(stableId.sequence("app", "next_id"));
207
+ expect(change.requires.length).toBeGreaterThan(0);
208
+ });
81
209
  });
@@ -45,6 +45,33 @@ export class CreateRlsPolicy extends CreateRlsPolicyChange {
45
45
  // Owner dependency
46
46
  dependencies.add(stableId.role(this.policy.owner));
47
47
 
48
+ // Relations and functions referenced inside USING / WITH CHECK
49
+ // expressions must exist before the policy is created. These come from
50
+ // pg_depend (populated by PostgreSQL's recordDependencyOnExpr at policy
51
+ // creation), not from re-parsing the expression text.
52
+ for (const ref of this.policy.referenced_relations) {
53
+ switch (ref.kind) {
54
+ case "table":
55
+ dependencies.add(stableId.table(ref.schema, ref.name));
56
+ break;
57
+ case "view":
58
+ dependencies.add(stableId.view(ref.schema, ref.name));
59
+ break;
60
+ case "materialized_view":
61
+ dependencies.add(stableId.materializedView(ref.schema, ref.name));
62
+ break;
63
+ case "foreign_table":
64
+ dependencies.add(stableId.foreignTable(ref.schema, ref.name));
65
+ break;
66
+ }
67
+ }
68
+
69
+ for (const ref of this.policy.referenced_procedures) {
70
+ dependencies.add(
71
+ stableId.procedure(ref.schema, ref.name, ref.argument_types.join(",")),
72
+ );
73
+ }
74
+
48
75
  return Array.from(dependencies);
49
76
  }
50
77
 
@@ -16,6 +16,8 @@ describe("rls-policy", () => {
16
16
  with_check_expression: null,
17
17
  owner: "test",
18
18
  comment: null,
19
+ referenced_relations: [],
20
+ referenced_procedures: [],
19
21
  });
20
22
 
21
23
  const change = new DropRlsPolicy({
@@ -20,6 +20,8 @@ const base: RlsPolicyProps = {
20
20
  with_check_expression: null,
21
21
  owner: "o1",
22
22
  comment: null,
23
+ referenced_relations: [],
24
+ referenced_procedures: [],
23
25
  };
24
26
 
25
27
  describe.concurrent("rls-policy.diff", () => {
@@ -11,6 +11,33 @@ const RlsPolicyCommandSchema = z.enum([
11
11
  "*", // ALL commands
12
12
  ]);
13
13
 
14
+ const RlsPolicyReferencedRelationKindSchema = z.enum([
15
+ "table",
16
+ "view",
17
+ "materialized_view",
18
+ "foreign_table",
19
+ ]);
20
+
21
+ const rlsPolicyReferencedRelationSchema = z.object({
22
+ kind: RlsPolicyReferencedRelationKindSchema,
23
+ schema: z.string(),
24
+ name: z.string(),
25
+ });
26
+
27
+ export type RlsPolicyReferencedRelation = z.infer<
28
+ typeof rlsPolicyReferencedRelationSchema
29
+ >;
30
+
31
+ const rlsPolicyReferencedProcedureSchema = z.object({
32
+ schema: z.string(),
33
+ name: z.string(),
34
+ argument_types: z.array(z.string()),
35
+ });
36
+
37
+ export type RlsPolicyReferencedProcedure = z.infer<
38
+ typeof rlsPolicyReferencedProcedureSchema
39
+ >;
40
+
14
41
  const rlsPolicyPropsSchema = z.object({
15
42
  schema: z.string(),
16
43
  name: z.string(),
@@ -22,6 +49,8 @@ const rlsPolicyPropsSchema = z.object({
22
49
  with_check_expression: z.string().nullable(),
23
50
  owner: z.string(),
24
51
  comment: z.string().nullable(),
52
+ referenced_relations: z.array(rlsPolicyReferencedRelationSchema),
53
+ referenced_procedures: z.array(rlsPolicyReferencedProcedureSchema),
25
54
  });
26
55
 
27
56
  export type RlsPolicyProps = z.infer<typeof rlsPolicyPropsSchema>;
@@ -37,6 +66,23 @@ export class RlsPolicy extends BasePgModel {
37
66
  public readonly with_check_expression: RlsPolicyProps["with_check_expression"];
38
67
  public readonly owner: RlsPolicyProps["owner"];
39
68
  public readonly comment: RlsPolicyProps["comment"];
69
+ /**
70
+ * Tables / views / materialized views / foreign tables that
71
+ * `using_expression` / `with_check_expression` reference, sourced from
72
+ * `pg_depend` (`recordDependencyOnExpr` at policy creation). Drives
73
+ * ordering dependencies in `CreateRlsPolicy.requires`. Intentionally
74
+ * excluded from `dataFields` — it's derived from the expression text
75
+ * and changes lockstep with it.
76
+ */
77
+ public readonly referenced_relations: RlsPolicyProps["referenced_relations"];
78
+ /**
79
+ * Functions / procedures that `using_expression` / `with_check_expression`
80
+ * reference, sourced from `pg_depend` (refclassid = `pg_proc`). The
81
+ * argument-type signature comes straight from `pg_proc.proargtypes` via
82
+ * `format_type`, so it matches the signature the procedure extractor
83
+ * embeds in `stableId.procedure(...)`. Not part of `dataFields`.
84
+ */
85
+ public readonly referenced_procedures: RlsPolicyProps["referenced_procedures"];
40
86
 
41
87
  constructor(props: RlsPolicyProps) {
42
88
  super();
@@ -54,6 +100,10 @@ export class RlsPolicy extends BasePgModel {
54
100
  this.with_check_expression = props.with_check_expression;
55
101
  this.owner = props.owner;
56
102
  this.comment = props.comment;
103
+
104
+ // Derived metadata (not part of equality)
105
+ this.referenced_relations = props.referenced_relations;
106
+ this.referenced_procedures = props.referenced_procedures;
57
107
  }
58
108
 
59
109
  get stableId(): `rlsPolicy:${string}` {
@@ -101,6 +151,59 @@ extension_table_oids as (
101
151
  d.refclassid = 'pg_extension'::regclass
102
152
  and d.classid = 'pg_class'::regclass
103
153
  and d.deptype = 'e'
154
+ ),
155
+ policy_relation_deps as (
156
+ -- Relations referenced inside polqual / polwithcheck. PostgreSQL records
157
+ -- these via recordDependencyOnExpr(..., DEPENDENCY_NORMAL = 'n') at
158
+ -- CREATE POLICY time, so pg_depend is authoritative and we don't need to
159
+ -- re-parse the expression text. Covers regular tables, partitioned
160
+ -- tables, views, materialized views, and foreign tables — any relation
161
+ -- kind the policy can reference in a subquery.
162
+ select distinct
163
+ d.objid as policy_oid,
164
+ case ref_c.relkind
165
+ when 'r' then 'table'
166
+ when 'p' then 'table'
167
+ when 'v' then 'view'
168
+ when 'm' then 'materialized_view'
169
+ when 'f' then 'foreign_table'
170
+ end as ref_kind,
171
+ ref_ns.nspname as ref_schema,
172
+ ref_c.relname as ref_name
173
+ from
174
+ pg_depend d
175
+ join pg_policy p on p.oid = d.objid
176
+ join pg_class ref_c on ref_c.oid = d.refobjid
177
+ join pg_namespace ref_ns on ref_ns.oid = ref_c.relnamespace
178
+ where
179
+ d.classid = 'pg_policy'::regclass
180
+ and d.refclassid = 'pg_class'::regclass
181
+ and d.deptype = 'n'
182
+ and ref_c.relkind in ('r', 'p', 'v', 'm', 'f')
183
+ and d.refobjid <> p.polrelid
184
+ ),
185
+ policy_procedure_deps as (
186
+ -- Functions / procedures referenced inside polqual / polwithcheck. Same
187
+ -- pg_depend mechanism as above, just refclassid = pg_proc. proargtypes
188
+ -- formatted via format_type(oid, null) matches the signature produced by
189
+ -- the procedure extractor (see procedure.model.ts), so stableId.procedure
190
+ -- on both sides of the diff lines up exactly.
191
+ select distinct
192
+ d.objid as policy_oid,
193
+ ref_ns.nspname as ref_schema,
194
+ ref_p.proname as ref_name,
195
+ array(
196
+ select format_type(oid, null)
197
+ from unnest(ref_p.proargtypes) as oid
198
+ ) as ref_argument_types
199
+ from
200
+ pg_depend d
201
+ join pg_proc ref_p on ref_p.oid = d.refobjid
202
+ join pg_namespace ref_ns on ref_ns.oid = ref_p.pronamespace
203
+ where
204
+ d.classid = 'pg_policy'::regclass
205
+ and d.refclassid = 'pg_proc'::regclass
206
+ and d.deptype = 'n'
104
207
  )
105
208
  select
106
209
  tc.relnamespace::regnamespace::text as schema,
@@ -120,7 +223,37 @@ select
120
223
  pg_get_expr(p.polqual, p.polrelid) as using_expression,
121
224
  pg_get_expr(p.polwithcheck, p.polrelid) as with_check_expression,
122
225
  tc.relowner::regrole::text as owner,
123
- obj_description(p.oid, 'pg_policy') as comment
226
+ obj_description(p.oid, 'pg_policy') as comment,
227
+ coalesce(
228
+ (
229
+ select json_agg(
230
+ json_build_object(
231
+ 'kind', prd.ref_kind,
232
+ 'schema', prd.ref_schema,
233
+ 'name', prd.ref_name
234
+ )
235
+ order by prd.ref_schema, prd.ref_name
236
+ )
237
+ from policy_relation_deps prd
238
+ where prd.policy_oid = p.oid
239
+ ),
240
+ '[]'
241
+ ) as referenced_relations,
242
+ coalesce(
243
+ (
244
+ select json_agg(
245
+ json_build_object(
246
+ 'schema', ppd.ref_schema,
247
+ 'name', ppd.ref_name,
248
+ 'argument_types', ppd.ref_argument_types
249
+ )
250
+ order by ppd.ref_schema, ppd.ref_name, ppd.ref_argument_types
251
+ )
252
+ from policy_procedure_deps ppd
253
+ where ppd.policy_oid = p.oid
254
+ ),
255
+ '[]'
256
+ ) as referenced_procedures
124
257
  from
125
258
  pg_catalog.pg_policy p
126
259
  inner join pg_catalog.pg_class tc on tc.oid = p.polrelid
@@ -766,6 +766,7 @@ describe.concurrent("table", () => {
766
766
  validated: true,
767
767
  is_local: true,
768
768
  no_inherit: false,
769
+ is_temporal: false,
769
770
  is_partition_clone: false,
770
771
  parent_constraint_schema: null,
771
772
  parent_constraint_name: null,