@supabase/pg-delta 1.0.0-alpha.22 → 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.
Files changed (220) hide show
  1. package/dist/core/catalog.model.js +1 -0
  2. package/dist/core/integrations/filter/flatten.js +13 -0
  3. package/dist/core/objects/aggregate/aggregate.diff.js +16 -0
  4. package/dist/core/objects/aggregate/aggregate.model.d.ts +10 -0
  5. package/dist/core/objects/aggregate/aggregate.model.js +19 -1
  6. package/dist/core/objects/aggregate/changes/aggregate.base.d.ts +1 -1
  7. package/dist/core/objects/aggregate/changes/aggregate.security-label.d.ts +28 -0
  8. package/dist/core/objects/aggregate/changes/aggregate.security-label.js +64 -0
  9. package/dist/core/objects/aggregate/changes/aggregate.types.d.ts +2 -1
  10. package/dist/core/objects/base.model.d.ts +8 -0
  11. package/dist/core/objects/base.model.js +2 -0
  12. package/dist/core/objects/domain/changes/domain.base.d.ts +1 -1
  13. package/dist/core/objects/domain/changes/domain.security-label.d.ts +28 -0
  14. package/dist/core/objects/domain/changes/domain.security-label.js +61 -0
  15. package/dist/core/objects/domain/changes/domain.types.d.ts +2 -1
  16. package/dist/core/objects/domain/domain.diff.js +16 -0
  17. package/dist/core/objects/domain/domain.model.d.ts +10 -0
  18. package/dist/core/objects/domain/domain.model.js +19 -1
  19. package/dist/core/objects/event-trigger/changes/event-trigger.base.d.ts +1 -1
  20. package/dist/core/objects/event-trigger/changes/event-trigger.security-label.d.ts +28 -0
  21. package/dist/core/objects/event-trigger/changes/event-trigger.security-label.js +61 -0
  22. package/dist/core/objects/event-trigger/changes/event-trigger.types.d.ts +2 -1
  23. package/dist/core/objects/event-trigger/event-trigger.diff.js +16 -0
  24. package/dist/core/objects/event-trigger/event-trigger.model.d.ts +10 -0
  25. package/dist/core/objects/event-trigger/event-trigger.model.js +19 -1
  26. package/dist/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.base.d.ts +1 -1
  27. package/dist/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.security-label.d.ts +28 -0
  28. package/dist/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.security-label.js +61 -0
  29. package/dist/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.types.d.ts +2 -1
  30. package/dist/core/objects/foreign-data-wrapper/foreign-table/foreign-table.diff.js +16 -0
  31. package/dist/core/objects/foreign-data-wrapper/foreign-table/foreign-table.model.d.ts +22 -0
  32. package/dist/core/objects/foreign-data-wrapper/foreign-table/foreign-table.model.js +20 -1
  33. package/dist/core/objects/materialized-view/changes/materialized-view.base.d.ts +1 -1
  34. package/dist/core/objects/materialized-view/changes/materialized-view.security-label.d.ts +28 -0
  35. package/dist/core/objects/materialized-view/changes/materialized-view.security-label.js +61 -0
  36. package/dist/core/objects/materialized-view/changes/materialized-view.types.d.ts +2 -1
  37. package/dist/core/objects/materialized-view/materialized-view.diff.js +18 -0
  38. package/dist/core/objects/materialized-view/materialized-view.model.d.ts +22 -0
  39. package/dist/core/objects/materialized-view/materialized-view.model.js +20 -1
  40. package/dist/core/objects/procedure/changes/procedure.base.d.ts +1 -1
  41. package/dist/core/objects/procedure/changes/procedure.security-label.d.ts +28 -0
  42. package/dist/core/objects/procedure/changes/procedure.security-label.js +69 -0
  43. package/dist/core/objects/procedure/changes/procedure.types.d.ts +2 -1
  44. package/dist/core/objects/procedure/procedure.diff.js +16 -0
  45. package/dist/core/objects/procedure/procedure.model.d.ts +10 -0
  46. package/dist/core/objects/procedure/procedure.model.js +19 -1
  47. package/dist/core/objects/publication/changes/publication.base.d.ts +1 -1
  48. package/dist/core/objects/publication/changes/publication.security-label.d.ts +28 -0
  49. package/dist/core/objects/publication/changes/publication.security-label.js +61 -0
  50. package/dist/core/objects/publication/changes/publication.types.d.ts +2 -1
  51. package/dist/core/objects/publication/publication.diff.js +16 -0
  52. package/dist/core/objects/publication/publication.model.d.ts +14 -0
  53. package/dist/core/objects/publication/publication.model.js +20 -1
  54. package/dist/core/objects/role/changes/role.base.d.ts +1 -1
  55. package/dist/core/objects/role/changes/role.security-label.d.ts +28 -0
  56. package/dist/core/objects/role/changes/role.security-label.js +61 -0
  57. package/dist/core/objects/role/changes/role.types.d.ts +2 -1
  58. package/dist/core/objects/role/role.diff.js +16 -0
  59. package/dist/core/objects/role/role.model.d.ts +10 -0
  60. package/dist/core/objects/role/role.model.js +29 -0
  61. package/dist/core/objects/schema/changes/schema.base.d.ts +1 -1
  62. package/dist/core/objects/schema/changes/schema.security-label.d.ts +28 -0
  63. package/dist/core/objects/schema/changes/schema.security-label.js +61 -0
  64. package/dist/core/objects/schema/changes/schema.types.d.ts +2 -1
  65. package/dist/core/objects/schema/schema.diff.js +24 -1
  66. package/dist/core/objects/schema/schema.model.d.ts +10 -0
  67. package/dist/core/objects/schema/schema.model.js +18 -1
  68. package/dist/core/objects/security-label.types.d.ts +20 -0
  69. package/dist/core/objects/security-label.types.js +46 -0
  70. package/dist/core/objects/sequence/changes/sequence.base.d.ts +1 -1
  71. package/dist/core/objects/sequence/changes/sequence.security-label.d.ts +28 -0
  72. package/dist/core/objects/sequence/changes/sequence.security-label.js +61 -0
  73. package/dist/core/objects/sequence/changes/sequence.types.d.ts +2 -1
  74. package/dist/core/objects/sequence/sequence.diff.js +16 -0
  75. package/dist/core/objects/sequence/sequence.model.d.ts +10 -0
  76. package/dist/core/objects/sequence/sequence.model.js +19 -1
  77. package/dist/core/objects/subscription/changes/subscription.base.d.ts +1 -1
  78. package/dist/core/objects/subscription/changes/subscription.security-label.d.ts +28 -0
  79. package/dist/core/objects/subscription/changes/subscription.security-label.js +61 -0
  80. package/dist/core/objects/subscription/changes/subscription.types.d.ts +2 -1
  81. package/dist/core/objects/subscription/subscription.diff.js +16 -0
  82. package/dist/core/objects/subscription/subscription.model.d.ts +10 -0
  83. package/dist/core/objects/subscription/subscription.model.js +19 -1
  84. package/dist/core/objects/table/changes/table.base.d.ts +1 -1
  85. package/dist/core/objects/table/changes/table.security-label.d.ts +63 -0
  86. package/dist/core/objects/table/changes/table.security-label.js +134 -0
  87. package/dist/core/objects/table/changes/table.types.d.ts +2 -1
  88. package/dist/core/objects/table/table.diff.js +49 -0
  89. package/dist/core/objects/table/table.model.d.ts +30 -0
  90. package/dist/core/objects/table/table.model.js +34 -2
  91. package/dist/core/objects/type/composite-type/changes/composite-type.base.d.ts +1 -1
  92. package/dist/core/objects/type/composite-type/changes/composite-type.security-label.d.ts +28 -0
  93. package/dist/core/objects/type/composite-type/changes/composite-type.security-label.js +61 -0
  94. package/dist/core/objects/type/composite-type/changes/composite-type.types.d.ts +2 -1
  95. package/dist/core/objects/type/composite-type/composite-type.diff.js +16 -0
  96. package/dist/core/objects/type/composite-type/composite-type.model.d.ts +22 -0
  97. package/dist/core/objects/type/composite-type/composite-type.model.js +22 -2
  98. package/dist/core/objects/type/enum/changes/enum.base.d.ts +1 -1
  99. package/dist/core/objects/type/enum/changes/enum.security-label.d.ts +28 -0
  100. package/dist/core/objects/type/enum/changes/enum.security-label.js +61 -0
  101. package/dist/core/objects/type/enum/changes/enum.types.d.ts +2 -1
  102. package/dist/core/objects/type/enum/enum.diff.js +16 -0
  103. package/dist/core/objects/type/enum/enum.model.d.ts +10 -0
  104. package/dist/core/objects/type/enum/enum.model.js +20 -1
  105. package/dist/core/objects/type/range/changes/range.base.d.ts +1 -1
  106. package/dist/core/objects/type/range/changes/range.security-label.d.ts +28 -0
  107. package/dist/core/objects/type/range/changes/range.security-label.js +61 -0
  108. package/dist/core/objects/type/range/changes/range.types.d.ts +2 -1
  109. package/dist/core/objects/type/range/range.diff.js +16 -0
  110. package/dist/core/objects/type/range/range.model.d.ts +10 -0
  111. package/dist/core/objects/type/range/range.model.js +19 -1
  112. package/dist/core/objects/utils.d.ts +1 -0
  113. package/dist/core/objects/utils.js +3 -0
  114. package/dist/core/objects/view/changes/view.base.d.ts +1 -1
  115. package/dist/core/objects/view/changes/view.security-label.d.ts +28 -0
  116. package/dist/core/objects/view/changes/view.security-label.js +61 -0
  117. package/dist/core/objects/view/changes/view.types.d.ts +2 -1
  118. package/dist/core/objects/view/view.diff.js +13 -0
  119. package/dist/core/objects/view/view.model.d.ts +26 -0
  120. package/dist/core/objects/view/view.model.js +20 -1
  121. package/dist/core/plan/sql-format/fixtures.js +1 -0
  122. package/package.json +1 -1
  123. package/src/core/catalog.model.ts +1 -0
  124. package/src/core/integrations/filter/dsl.test.ts +27 -0
  125. package/src/core/integrations/filter/flatten.ts +16 -0
  126. package/src/core/objects/aggregate/aggregate.diff.ts +33 -0
  127. package/src/core/objects/aggregate/aggregate.model.ts +22 -1
  128. package/src/core/objects/aggregate/changes/aggregate.base.ts +5 -1
  129. package/src/core/objects/aggregate/changes/aggregate.security-label.ts +99 -0
  130. package/src/core/objects/aggregate/changes/aggregate.types.ts +3 -1
  131. package/src/core/objects/base.model.ts +2 -0
  132. package/src/core/objects/domain/changes/domain.base.ts +5 -1
  133. package/src/core/objects/domain/changes/domain.security-label.test.ts +56 -0
  134. package/src/core/objects/domain/changes/domain.security-label.ts +77 -0
  135. package/src/core/objects/domain/changes/domain.types.ts +3 -1
  136. package/src/core/objects/domain/domain.diff.ts +33 -0
  137. package/src/core/objects/domain/domain.model.ts +22 -1
  138. package/src/core/objects/event-trigger/changes/event-trigger.base.ts +1 -1
  139. package/src/core/objects/event-trigger/changes/event-trigger.security-label.ts +95 -0
  140. package/src/core/objects/event-trigger/changes/event-trigger.types.ts +3 -1
  141. package/src/core/objects/event-trigger/event-trigger.diff.ts +33 -0
  142. package/src/core/objects/event-trigger/event-trigger.model.ts +22 -1
  143. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.base.ts +5 -1
  144. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.security-label.ts +95 -0
  145. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.types.ts +3 -1
  146. package/src/core/objects/foreign-data-wrapper/foreign-table/foreign-table.diff.ts +33 -0
  147. package/src/core/objects/foreign-data-wrapper/foreign-table/foreign-table.model.ts +24 -1
  148. package/src/core/objects/materialized-view/changes/materialized-view.base.ts +5 -1
  149. package/src/core/objects/materialized-view/changes/materialized-view.security-label.test.ts +63 -0
  150. package/src/core/objects/materialized-view/changes/materialized-view.security-label.ts +95 -0
  151. package/src/core/objects/materialized-view/changes/materialized-view.types.ts +3 -1
  152. package/src/core/objects/materialized-view/materialized-view.diff.ts +37 -0
  153. package/src/core/objects/materialized-view/materialized-view.model.ts +25 -4
  154. package/src/core/objects/procedure/changes/procedure.base.ts +5 -1
  155. package/src/core/objects/procedure/changes/procedure.security-label.ts +105 -0
  156. package/src/core/objects/procedure/changes/procedure.types.ts +3 -1
  157. package/src/core/objects/procedure/procedure.diff.ts +33 -0
  158. package/src/core/objects/procedure/procedure.model.ts +23 -2
  159. package/src/core/objects/publication/changes/publication.base.ts +1 -1
  160. package/src/core/objects/publication/changes/publication.security-label.ts +95 -0
  161. package/src/core/objects/publication/changes/publication.types.ts +3 -1
  162. package/src/core/objects/publication/publication.diff.ts +33 -0
  163. package/src/core/objects/publication/publication.model.ts +24 -1
  164. package/src/core/objects/role/changes/role.base.ts +2 -1
  165. package/src/core/objects/role/changes/role.security-label.ts +77 -0
  166. package/src/core/objects/role/changes/role.types.ts +3 -1
  167. package/src/core/objects/role/role.diff.ts +33 -0
  168. package/src/core/objects/role/role.model.ts +32 -0
  169. package/src/core/objects/schema/changes/schema.alter.test.ts +1 -0
  170. package/src/core/objects/schema/changes/schema.base.ts +5 -1
  171. package/src/core/objects/schema/changes/schema.create.test.ts +1 -0
  172. package/src/core/objects/schema/changes/schema.drop.test.ts +1 -0
  173. package/src/core/objects/schema/changes/schema.security-label.test.ts +76 -0
  174. package/src/core/objects/schema/changes/schema.security-label.ts +77 -0
  175. package/src/core/objects/schema/changes/schema.types.ts +3 -1
  176. package/src/core/objects/schema/schema.diff.test.ts +1 -0
  177. package/src/core/objects/schema/schema.diff.ts +43 -1
  178. package/src/core/objects/schema/schema.model.ts +21 -1
  179. package/src/core/objects/security-label.types.test.ts +106 -0
  180. package/src/core/objects/security-label.types.ts +61 -0
  181. package/src/core/objects/sequence/changes/sequence.base.ts +5 -1
  182. package/src/core/objects/sequence/changes/sequence.security-label.test.ts +58 -0
  183. package/src/core/objects/sequence/changes/sequence.security-label.ts +92 -0
  184. package/src/core/objects/sequence/changes/sequence.types.ts +3 -1
  185. package/src/core/objects/sequence/sequence.diff.ts +33 -0
  186. package/src/core/objects/sequence/sequence.model.ts +22 -1
  187. package/src/core/objects/subscription/changes/subscription.base.ts +1 -1
  188. package/src/core/objects/subscription/changes/subscription.security-label.ts +95 -0
  189. package/src/core/objects/subscription/changes/subscription.types.ts +3 -1
  190. package/src/core/objects/subscription/subscription.diff.ts +33 -0
  191. package/src/core/objects/subscription/subscription.model.ts +22 -1
  192. package/src/core/objects/table/changes/table.base.ts +5 -1
  193. package/src/core/objects/table/changes/table.security-label.test.ts +140 -0
  194. package/src/core/objects/table/changes/table.security-label.ts +183 -0
  195. package/src/core/objects/table/changes/table.types.ts +3 -1
  196. package/src/core/objects/table/table.diff.ts +87 -0
  197. package/src/core/objects/table/table.model.ts +42 -2
  198. package/src/core/objects/type/composite-type/changes/composite-type.base.ts +5 -1
  199. package/src/core/objects/type/composite-type/changes/composite-type.security-label.ts +95 -0
  200. package/src/core/objects/type/composite-type/changes/composite-type.types.ts +3 -1
  201. package/src/core/objects/type/composite-type/composite-type.diff.ts +33 -0
  202. package/src/core/objects/type/composite-type/composite-type.model.ts +26 -2
  203. package/src/core/objects/type/enum/changes/enum.base.ts +5 -1
  204. package/src/core/objects/type/enum/changes/enum.security-label.ts +77 -0
  205. package/src/core/objects/type/enum/changes/enum.types.ts +3 -1
  206. package/src/core/objects/type/enum/enum.diff.ts +33 -0
  207. package/src/core/objects/type/enum/enum.model.ts +25 -1
  208. package/src/core/objects/type/range/changes/range.base.ts +5 -1
  209. package/src/core/objects/type/range/changes/range.security-label.ts +77 -0
  210. package/src/core/objects/type/range/changes/range.types.ts +3 -1
  211. package/src/core/objects/type/range/range.diff.ts +33 -0
  212. package/src/core/objects/type/range/range.model.ts +22 -1
  213. package/src/core/objects/utils.ts +3 -0
  214. package/src/core/objects/view/changes/view.base.ts +5 -1
  215. package/src/core/objects/view/changes/view.security-label.test.ts +64 -0
  216. package/src/core/objects/view/changes/view.security-label.ts +77 -0
  217. package/src/core/objects/view/changes/view.types.ts +3 -1
  218. package/src/core/objects/view/view.diff.ts +31 -0
  219. package/src/core/objects/view/view.model.ts +25 -2
  220. package/src/core/plan/sql-format/fixtures.ts +1 -0
@@ -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 rangePropsSchema = z.object({
11
15
  schema: z.string(),
@@ -30,6 +34,7 @@ const rangePropsSchema = z.object({
30
34
  subtype_opclass_schema: z.string().nullable(),
31
35
  subtype_opclass_name: z.string().nullable(),
32
36
  privileges: z.array(privilegePropsSchema),
37
+ security_labels: z.array(securityLabelPropsSchema).default([]).optional(),
33
38
  });
34
39
 
35
40
  type RangePrivilegeProps = PrivilegeProps;
@@ -54,6 +59,7 @@ export class Range extends BasePgModel {
54
59
  public readonly subtype_opclass_schema: RangeProps["subtype_opclass_schema"];
55
60
  public readonly subtype_opclass_name: RangeProps["subtype_opclass_name"];
56
61
  public readonly privileges: RangePrivilegeProps[];
62
+ public readonly security_labels: SecurityLabelProps[];
57
63
 
58
64
  constructor(props: RangeProps) {
59
65
  super();
@@ -75,6 +81,7 @@ export class Range extends BasePgModel {
75
81
  this.subtype_opclass_schema = props.subtype_opclass_schema;
76
82
  this.subtype_opclass_name = props.subtype_opclass_name;
77
83
  this.privileges = props.privileges;
84
+ this.security_labels = props.security_labels ?? [];
78
85
  }
79
86
 
80
87
  get stableId(): `type:${string}` {
@@ -102,6 +109,7 @@ export class Range extends BasePgModel {
102
109
  subtype_opclass_name: this.subtype_opclass_name,
103
110
  comment: this.comment,
104
111
  privileges: this.privileges,
112
+ security_labels: this.security_labels,
105
113
  };
106
114
  }
107
115
  }
@@ -166,7 +174,20 @@ select
166
174
  )
167
175
  from lateral aclexplode(COALESCE(t.typacl, acldefault('T', t.typowner))) as x(grantor, grantee, privilege_type, is_grantable)
168
176
  ), '[]'
169
- ) as privileges
177
+ ) as privileges,
178
+ coalesce(
179
+ (
180
+ select json_agg(
181
+ json_build_object('provider', sl.provider, 'label', sl.label)
182
+ order by sl.provider
183
+ )
184
+ from pg_catalog.pg_seclabel sl
185
+ where sl.objoid = t.oid
186
+ and sl.classoid = 'pg_type'::regclass
187
+ and sl.objsubid = 0
188
+ ),
189
+ '[]'::json
190
+ ) as security_labels
170
191
  from pg_catalog.pg_range r
171
192
  join pg_catalog.pg_type t on t.oid = r.rngtypid
172
193
  join pg_catalog.pg_type subt on subt.oid = r.rngsubtype
@@ -77,6 +77,9 @@ export const stableId = {
77
77
  comment(objectStableId: string) {
78
78
  return `comment:${objectStableId}` as const;
79
79
  },
80
+ securityLabel(objectStableId: string, provider: string) {
81
+ return `securityLabel:${objectStableId}::provider:${provider}` as const;
82
+ },
80
83
  role(role: string) {
81
84
  return `role:${role}` as const;
82
85
  },
@@ -3,7 +3,11 @@ import type { View } from "../view.model.ts";
3
3
 
4
4
  abstract class BaseViewChange extends BaseChange {
5
5
  abstract readonly view: View;
6
- abstract readonly scope: "object" | "comment" | "privilege";
6
+ abstract readonly scope:
7
+ | "object"
8
+ | "comment"
9
+ | "privilege"
10
+ | "security_label";
7
11
  readonly objectType: "view" = "view";
8
12
  }
9
13
 
@@ -0,0 +1,64 @@
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 { View, type ViewProps } from "../view.model.ts";
5
+ import {
6
+ CreateSecurityLabelOnView,
7
+ DropSecurityLabelOnView,
8
+ } from "./view.security-label.ts";
9
+
10
+ const makeView = (): View =>
11
+ new View({
12
+ schema: "public",
13
+ name: "v",
14
+ definition: "SELECT 1",
15
+ row_security: false,
16
+ force_row_security: false,
17
+ has_indexes: false,
18
+ has_rules: false,
19
+ has_triggers: false,
20
+ has_subclasses: false,
21
+ is_populated: true,
22
+ replica_identity: "d",
23
+ is_partition: false,
24
+ options: null,
25
+ partition_bound: null,
26
+ owner: "postgres",
27
+ comment: null,
28
+ columns: [],
29
+ privileges: [],
30
+ } as ViewProps);
31
+
32
+ describe("view.security-label", () => {
33
+ test("create serializes and tracks dependencies", async () => {
34
+ const view = makeView();
35
+ const change = new CreateSecurityLabelOnView({
36
+ view,
37
+ securityLabel: { provider: "dummy", label: "classified" },
38
+ });
39
+ expect(change.scope).toBe("security_label");
40
+ expect(change.creates).toEqual([
41
+ stableId.securityLabel(view.stableId, "dummy"),
42
+ ]);
43
+ expect(change.requires).toEqual([view.stableId]);
44
+ await assertValidSql(change.serialize());
45
+ expect(change.serialize()).toBe(
46
+ "SECURITY LABEL FOR dummy ON VIEW public.v IS 'classified'",
47
+ );
48
+ });
49
+
50
+ test("drop serializes to IS NULL", async () => {
51
+ const view = makeView();
52
+ const change = new DropSecurityLabelOnView({
53
+ view,
54
+ securityLabel: { provider: "dummy", label: "classified" },
55
+ });
56
+ expect(change.drops).toEqual([
57
+ stableId.securityLabel(view.stableId, "dummy"),
58
+ ]);
59
+ await assertValidSql(change.serialize());
60
+ expect(change.serialize()).toBe(
61
+ "SECURITY LABEL FOR dummy ON VIEW public.v IS NULL",
62
+ );
63
+ });
64
+ });
@@ -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 { View } from "../view.model.ts";
5
+ import { CreateViewChange, DropViewChange } from "./view.base.ts";
6
+
7
+ export type SecurityLabelView =
8
+ | CreateSecurityLabelOnView
9
+ | DropSecurityLabelOnView;
10
+
11
+ export class CreateSecurityLabelOnView extends CreateViewChange {
12
+ public readonly view: View;
13
+ public readonly securityLabel: SecurityLabelProps;
14
+ public readonly scope = "security_label" as const;
15
+
16
+ constructor(props: { view: View; securityLabel: SecurityLabelProps }) {
17
+ super();
18
+ this.view = props.view;
19
+ this.securityLabel = props.securityLabel;
20
+ }
21
+
22
+ get creates() {
23
+ return [
24
+ stableId.securityLabel(this.view.stableId, this.securityLabel.provider),
25
+ ];
26
+ }
27
+
28
+ get requires() {
29
+ return [this.view.stableId];
30
+ }
31
+
32
+ serialize(): string {
33
+ return [
34
+ "SECURITY LABEL FOR",
35
+ this.securityLabel.provider,
36
+ "ON VIEW",
37
+ `${this.view.schema}.${this.view.name}`,
38
+ "IS",
39
+ quoteLiteral(this.securityLabel.label),
40
+ ].join(" ");
41
+ }
42
+ }
43
+
44
+ export class DropSecurityLabelOnView extends DropViewChange {
45
+ public readonly view: View;
46
+ public readonly securityLabel: SecurityLabelProps;
47
+ public readonly scope = "security_label" as const;
48
+
49
+ constructor(props: { view: View; securityLabel: SecurityLabelProps }) {
50
+ super();
51
+ this.view = props.view;
52
+ this.securityLabel = props.securityLabel;
53
+ }
54
+
55
+ get drops() {
56
+ return [
57
+ stableId.securityLabel(this.view.stableId, this.securityLabel.provider),
58
+ ];
59
+ }
60
+
61
+ get requires() {
62
+ return [
63
+ stableId.securityLabel(this.view.stableId, this.securityLabel.provider),
64
+ this.view.stableId,
65
+ ];
66
+ }
67
+
68
+ serialize(): string {
69
+ return [
70
+ "SECURITY LABEL FOR",
71
+ this.securityLabel.provider,
72
+ "ON VIEW",
73
+ `${this.view.schema}.${this.view.name}`,
74
+ "IS NULL",
75
+ ].join(" ");
76
+ }
77
+ }
@@ -3,6 +3,7 @@ import type { CommentView } from "./view.comment.ts";
3
3
  import type { CreateView } from "./view.create.ts";
4
4
  import type { DropView } from "./view.drop.ts";
5
5
  import type { ViewPrivilege } from "./view.privilege.ts";
6
+ import type { SecurityLabelView } from "./view.security-label.ts";
6
7
 
7
8
  /** Union of all view-related change variants (`objectType: "view"`). @category Change Types */
8
9
  export type ViewChange =
@@ -10,4 +11,5 @@ export type ViewChange =
10
11
  | CommentView
11
12
  | CreateView
12
13
  | DropView
13
- | ViewPrivilege;
14
+ | ViewPrivilege
15
+ | SecurityLabelView;
@@ -5,6 +5,7 @@ import {
5
5
  emitColumnPrivilegeChanges,
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
  AlterViewChangeOwner,
@@ -22,6 +23,10 @@ import {
22
23
  RevokeGrantOptionViewPrivileges,
23
24
  RevokeViewPrivileges,
24
25
  } from "./changes/view.privilege.ts";
26
+ import {
27
+ CreateSecurityLabelOnView,
28
+ DropSecurityLabelOnView,
29
+ } from "./changes/view.security-label.ts";
25
30
  import type { ViewChange } from "./changes/view.types.ts";
26
31
  import type { View } from "./view.model.ts";
27
32
 
@@ -57,6 +62,12 @@ export function diffViews(
57
62
  changes.push(new CreateCommentOnView({ view }));
58
63
  }
59
64
 
65
+ for (const label of view.security_labels) {
66
+ changes.push(
67
+ new CreateSecurityLabelOnView({ view, securityLabel: label }),
68
+ );
69
+ }
70
+
60
71
  // PRIVILEGES: For created objects, compare against default privileges state
61
72
  // The migration script will run ALTER DEFAULT PRIVILEGES before CREATE (via constraint spec),
62
73
  // so objects are created with the default privileges state in effect.
@@ -195,6 +206,26 @@ export function diffViews(
195
206
  }
196
207
  }
197
208
 
209
+ // SECURITY LABELS
210
+ changes.push(
211
+ ...diffSecurityLabels<
212
+ CreateSecurityLabelOnView | DropSecurityLabelOnView
213
+ >(
214
+ mainView.security_labels,
215
+ branchView.security_labels,
216
+ (securityLabel) =>
217
+ new CreateSecurityLabelOnView({
218
+ view: branchView,
219
+ securityLabel,
220
+ }),
221
+ (securityLabel) =>
222
+ new DropSecurityLabelOnView({
223
+ view: mainView,
224
+ securityLabel,
225
+ }),
226
+ ),
227
+ );
228
+
198
229
  // Note: View renaming would also use ALTER VIEW ... RENAME TO ...
199
230
  // But since our View model uses 'name' as the identity field,
200
231
  // a name change would be handled as drop + create by diffObjects()
@@ -15,6 +15,11 @@ import {
15
15
  type ExtractRetryOptions,
16
16
  extractWithDefinitionRetry,
17
17
  } from "../extract-with-retry.ts";
18
+ import {
19
+ normalizeSecurityLabels,
20
+ type SecurityLabelProps,
21
+ securityLabelPropsSchema,
22
+ } from "../security-label.types.ts";
18
23
  import { ReplicaIdentitySchema } from "../table/table.model.ts";
19
24
 
20
25
  const viewPropsSchema = z.object({
@@ -36,6 +41,7 @@ const viewPropsSchema = z.object({
36
41
  comment: z.string().nullable(),
37
42
  columns: z.array(columnPropsSchema),
38
43
  privileges: z.array(privilegePropsSchema),
44
+ security_labels: z.array(securityLabelPropsSchema).default([]).optional(),
39
45
  });
40
46
 
41
47
  // pg_get_viewdef(oid) can return NULL when the underlying view (or its
@@ -69,6 +75,7 @@ export class View extends BasePgModel implements TableLikeObject {
69
75
  public readonly comment: ViewProps["comment"];
70
76
  public readonly columns: ViewProps["columns"];
71
77
  public readonly privileges: ViewPrivilegeProps[];
78
+ public readonly security_labels: SecurityLabelProps[];
72
79
 
73
80
  constructor(props: ViewProps) {
74
81
  super();
@@ -94,6 +101,7 @@ export class View extends BasePgModel implements TableLikeObject {
94
101
  this.comment = props.comment;
95
102
  this.columns = props.columns;
96
103
  this.privileges = props.privileges;
104
+ this.security_labels = props.security_labels ?? [];
97
105
  }
98
106
 
99
107
  get stableId(): `view:${string}` {
@@ -125,6 +133,7 @@ export class View extends BasePgModel implements TableLikeObject {
125
133
  comment: this.comment,
126
134
  columns: this.columns,
127
135
  privileges: this.privileges,
136
+ security_labels: this.security_labels,
128
137
  };
129
138
  }
130
139
 
@@ -134,6 +143,7 @@ export class View extends BasePgModel implements TableLikeObject {
134
143
  data: {
135
144
  ...this.dataFields,
136
145
  columns: normalizeColumns(this.columns),
146
+ security_labels: normalizeSecurityLabels(this.security_labels),
137
147
  },
138
148
  };
139
149
  }
@@ -264,7 +274,20 @@ select
264
274
  join lateral aclexplode(src.acl) as x(grantor, grantee, privilege_type, is_grantable) on true
265
275
  group by x.grantee, x.privilege_type
266
276
  ) as grp
267
- ), '[]') as privileges
277
+ ), '[]') as privileges,
278
+ coalesce(
279
+ (
280
+ select json_agg(
281
+ json_build_object('provider', sl.provider, 'label', sl.label)
282
+ order by sl.provider
283
+ )
284
+ from pg_catalog.pg_seclabel sl
285
+ where sl.objoid = v.oid
286
+ and sl.classoid = 'pg_class'::regclass
287
+ and sl.objsubid = 0
288
+ ),
289
+ '[]'::json
290
+ ) as security_labels
268
291
  from
269
292
  views v
270
293
  left join pg_attribute a on a.attrelid = v.oid and a.attnum > 0 and not a.attisdropped
@@ -281,5 +304,5 @@ order by
281
304
  const validatedRows = viewRows.filter(
282
305
  (row): row is ViewProps => row.definition !== null,
283
306
  );
284
- return validatedRows.map((row: ViewProps) => new View(row));
307
+ return validatedRows.map((row) => new View(row));
285
308
  }
@@ -1119,6 +1119,7 @@ const schema = new Schema({
1119
1119
  owner: "admin",
1120
1120
  comment: "application schema",
1121
1121
  privileges: [],
1122
+ security_labels: [],
1122
1123
  });
1123
1124
 
1124
1125
  const extension = new Extension({