@supabase/pg-delta 1.0.0-alpha.22 → 1.0.0-alpha.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (228) 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/dist/core/post-diff-normalization.d.ts +7 -0
  123. package/dist/core/post-diff-normalization.js +33 -4
  124. package/dist/core/sort/cycle-breakers.js +139 -17
  125. package/package.json +1 -1
  126. package/src/core/catalog.model.ts +1 -0
  127. package/src/core/integrations/filter/dsl.test.ts +27 -0
  128. package/src/core/integrations/filter/flatten.ts +16 -0
  129. package/src/core/objects/aggregate/aggregate.diff.ts +33 -0
  130. package/src/core/objects/aggregate/aggregate.model.ts +22 -1
  131. package/src/core/objects/aggregate/changes/aggregate.base.ts +5 -1
  132. package/src/core/objects/aggregate/changes/aggregate.security-label.ts +99 -0
  133. package/src/core/objects/aggregate/changes/aggregate.types.ts +3 -1
  134. package/src/core/objects/base.model.ts +2 -0
  135. package/src/core/objects/domain/changes/domain.base.ts +5 -1
  136. package/src/core/objects/domain/changes/domain.security-label.test.ts +56 -0
  137. package/src/core/objects/domain/changes/domain.security-label.ts +77 -0
  138. package/src/core/objects/domain/changes/domain.types.ts +3 -1
  139. package/src/core/objects/domain/domain.diff.ts +33 -0
  140. package/src/core/objects/domain/domain.model.ts +22 -1
  141. package/src/core/objects/event-trigger/changes/event-trigger.base.ts +1 -1
  142. package/src/core/objects/event-trigger/changes/event-trigger.security-label.ts +95 -0
  143. package/src/core/objects/event-trigger/changes/event-trigger.types.ts +3 -1
  144. package/src/core/objects/event-trigger/event-trigger.diff.ts +33 -0
  145. package/src/core/objects/event-trigger/event-trigger.model.ts +22 -1
  146. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.base.ts +5 -1
  147. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.security-label.ts +95 -0
  148. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.types.ts +3 -1
  149. package/src/core/objects/foreign-data-wrapper/foreign-table/foreign-table.diff.ts +33 -0
  150. package/src/core/objects/foreign-data-wrapper/foreign-table/foreign-table.model.ts +24 -1
  151. package/src/core/objects/materialized-view/changes/materialized-view.base.ts +5 -1
  152. package/src/core/objects/materialized-view/changes/materialized-view.security-label.test.ts +63 -0
  153. package/src/core/objects/materialized-view/changes/materialized-view.security-label.ts +95 -0
  154. package/src/core/objects/materialized-view/changes/materialized-view.types.ts +3 -1
  155. package/src/core/objects/materialized-view/materialized-view.diff.ts +37 -0
  156. package/src/core/objects/materialized-view/materialized-view.model.ts +25 -4
  157. package/src/core/objects/procedure/changes/procedure.base.ts +5 -1
  158. package/src/core/objects/procedure/changes/procedure.security-label.ts +105 -0
  159. package/src/core/objects/procedure/changes/procedure.types.ts +3 -1
  160. package/src/core/objects/procedure/procedure.diff.ts +33 -0
  161. package/src/core/objects/procedure/procedure.model.ts +23 -2
  162. package/src/core/objects/publication/changes/publication.base.ts +1 -1
  163. package/src/core/objects/publication/changes/publication.security-label.ts +95 -0
  164. package/src/core/objects/publication/changes/publication.types.ts +3 -1
  165. package/src/core/objects/publication/publication.diff.ts +33 -0
  166. package/src/core/objects/publication/publication.model.ts +24 -1
  167. package/src/core/objects/role/changes/role.base.ts +2 -1
  168. package/src/core/objects/role/changes/role.security-label.ts +77 -0
  169. package/src/core/objects/role/changes/role.types.ts +3 -1
  170. package/src/core/objects/role/role.diff.ts +33 -0
  171. package/src/core/objects/role/role.model.ts +32 -0
  172. package/src/core/objects/schema/changes/schema.alter.test.ts +1 -0
  173. package/src/core/objects/schema/changes/schema.base.ts +5 -1
  174. package/src/core/objects/schema/changes/schema.create.test.ts +1 -0
  175. package/src/core/objects/schema/changes/schema.drop.test.ts +1 -0
  176. package/src/core/objects/schema/changes/schema.security-label.test.ts +76 -0
  177. package/src/core/objects/schema/changes/schema.security-label.ts +77 -0
  178. package/src/core/objects/schema/changes/schema.types.ts +3 -1
  179. package/src/core/objects/schema/schema.diff.test.ts +1 -0
  180. package/src/core/objects/schema/schema.diff.ts +43 -1
  181. package/src/core/objects/schema/schema.model.ts +21 -1
  182. package/src/core/objects/security-label.types.test.ts +106 -0
  183. package/src/core/objects/security-label.types.ts +61 -0
  184. package/src/core/objects/sequence/changes/sequence.base.ts +5 -1
  185. package/src/core/objects/sequence/changes/sequence.security-label.test.ts +58 -0
  186. package/src/core/objects/sequence/changes/sequence.security-label.ts +92 -0
  187. package/src/core/objects/sequence/changes/sequence.types.ts +3 -1
  188. package/src/core/objects/sequence/sequence.diff.ts +33 -0
  189. package/src/core/objects/sequence/sequence.model.ts +22 -1
  190. package/src/core/objects/subscription/changes/subscription.base.ts +1 -1
  191. package/src/core/objects/subscription/changes/subscription.security-label.ts +95 -0
  192. package/src/core/objects/subscription/changes/subscription.types.ts +3 -1
  193. package/src/core/objects/subscription/subscription.diff.ts +33 -0
  194. package/src/core/objects/subscription/subscription.model.ts +22 -1
  195. package/src/core/objects/table/changes/table.base.ts +5 -1
  196. package/src/core/objects/table/changes/table.security-label.test.ts +140 -0
  197. package/src/core/objects/table/changes/table.security-label.ts +183 -0
  198. package/src/core/objects/table/changes/table.types.ts +3 -1
  199. package/src/core/objects/table/table.diff.ts +87 -0
  200. package/src/core/objects/table/table.model.ts +42 -2
  201. package/src/core/objects/type/composite-type/changes/composite-type.base.ts +5 -1
  202. package/src/core/objects/type/composite-type/changes/composite-type.security-label.ts +95 -0
  203. package/src/core/objects/type/composite-type/changes/composite-type.types.ts +3 -1
  204. package/src/core/objects/type/composite-type/composite-type.diff.ts +33 -0
  205. package/src/core/objects/type/composite-type/composite-type.model.ts +26 -2
  206. package/src/core/objects/type/enum/changes/enum.base.ts +5 -1
  207. package/src/core/objects/type/enum/changes/enum.security-label.ts +77 -0
  208. package/src/core/objects/type/enum/changes/enum.types.ts +3 -1
  209. package/src/core/objects/type/enum/enum.diff.ts +33 -0
  210. package/src/core/objects/type/enum/enum.model.ts +25 -1
  211. package/src/core/objects/type/range/changes/range.base.ts +5 -1
  212. package/src/core/objects/type/range/changes/range.security-label.ts +77 -0
  213. package/src/core/objects/type/range/changes/range.types.ts +3 -1
  214. package/src/core/objects/type/range/range.diff.ts +33 -0
  215. package/src/core/objects/type/range/range.model.ts +22 -1
  216. package/src/core/objects/utils.ts +3 -0
  217. package/src/core/objects/view/changes/view.base.ts +5 -1
  218. package/src/core/objects/view/changes/view.security-label.test.ts +64 -0
  219. package/src/core/objects/view/changes/view.security-label.ts +77 -0
  220. package/src/core/objects/view/changes/view.types.ts +3 -1
  221. package/src/core/objects/view/view.diff.ts +31 -0
  222. package/src/core/objects/view/view.model.ts +25 -2
  223. package/src/core/plan/sql-format/fixtures.ts +1 -0
  224. package/src/core/post-diff-normalization.test.ts +123 -0
  225. package/src/core/post-diff-normalization.ts +40 -4
  226. package/src/core/sort/cycle-breakers.test.ts +236 -2
  227. package/src/core/sort/cycle-breakers.ts +184 -24
  228. package/src/core/sort/sort-changes.test.ts +317 -0
@@ -0,0 +1,77 @@
1
+ import { quoteLiteral } from "../../base.change.ts";
2
+ import type { SecurityLabelProps } from "../../security-label.types.ts";
3
+ import { stableId } from "../../utils.ts";
4
+ import type { Schema } from "../schema.model.ts";
5
+ import { CreateSchemaChange, DropSchemaChange } from "./schema.base.ts";
6
+
7
+ export type SecurityLabelSchema =
8
+ | CreateSecurityLabelOnSchema
9
+ | DropSecurityLabelOnSchema;
10
+
11
+ export class CreateSecurityLabelOnSchema extends CreateSchemaChange {
12
+ public readonly schema: Schema;
13
+ public readonly securityLabel: SecurityLabelProps;
14
+ public readonly scope = "security_label" as const;
15
+
16
+ constructor(props: { schema: Schema; securityLabel: SecurityLabelProps }) {
17
+ super();
18
+ this.schema = props.schema;
19
+ this.securityLabel = props.securityLabel;
20
+ }
21
+
22
+ get creates() {
23
+ return [
24
+ stableId.securityLabel(this.schema.stableId, this.securityLabel.provider),
25
+ ];
26
+ }
27
+
28
+ get requires() {
29
+ return [this.schema.stableId];
30
+ }
31
+
32
+ serialize(): string {
33
+ return [
34
+ "SECURITY LABEL FOR",
35
+ this.securityLabel.provider,
36
+ "ON SCHEMA",
37
+ this.schema.name,
38
+ "IS",
39
+ quoteLiteral(this.securityLabel.label),
40
+ ].join(" ");
41
+ }
42
+ }
43
+
44
+ export class DropSecurityLabelOnSchema extends DropSchemaChange {
45
+ public readonly schema: Schema;
46
+ public readonly securityLabel: SecurityLabelProps;
47
+ public readonly scope = "security_label" as const;
48
+
49
+ constructor(props: { schema: Schema; securityLabel: SecurityLabelProps }) {
50
+ super();
51
+ this.schema = props.schema;
52
+ this.securityLabel = props.securityLabel;
53
+ }
54
+
55
+ get drops() {
56
+ return [
57
+ stableId.securityLabel(this.schema.stableId, this.securityLabel.provider),
58
+ ];
59
+ }
60
+
61
+ get requires() {
62
+ return [
63
+ stableId.securityLabel(this.schema.stableId, this.securityLabel.provider),
64
+ this.schema.stableId,
65
+ ];
66
+ }
67
+
68
+ serialize(): string {
69
+ return [
70
+ "SECURITY LABEL FOR",
71
+ this.securityLabel.provider,
72
+ "ON SCHEMA",
73
+ this.schema.name,
74
+ "IS NULL",
75
+ ].join(" ");
76
+ }
77
+ }
@@ -3,6 +3,7 @@ import type { CommentSchema } from "./schema.comment.ts";
3
3
  import type { CreateSchema } from "./schema.create.ts";
4
4
  import type { DropSchema } from "./schema.drop.ts";
5
5
  import type { SchemaPrivilege } from "./schema.privilege.ts";
6
+ import type { SecurityLabelSchema } from "./schema.security-label.ts";
6
7
 
7
8
  /** Union of all schema-related change variants (`objectType: "schema"`). @category Change Types */
8
9
  export type SchemaChange =
@@ -10,4 +11,5 @@ export type SchemaChange =
10
11
  | CommentSchema
11
12
  | CreateSchema
12
13
  | DropSchema
13
- | SchemaPrivilege;
14
+ | SchemaPrivilege
15
+ | SecurityLabelSchema;
@@ -11,6 +11,7 @@ const base: SchemaProps = {
11
11
  owner: "o1",
12
12
  comment: null,
13
13
  privileges: [],
14
+ security_labels: [],
14
15
  };
15
16
 
16
17
  const testContext = {
@@ -4,6 +4,7 @@ import {
4
4
  emitObjectPrivilegeChanges,
5
5
  } from "../base.privilege-diff.ts";
6
6
  import type { ObjectDiffContext } from "../diff-context.ts";
7
+ import { diffSecurityLabels } from "../security-label.types.ts";
7
8
  import { AlterSchemaChangeOwner } from "./changes/schema.alter.ts";
8
9
  import {
9
10
  CreateCommentOnSchema,
@@ -16,6 +17,10 @@ import {
16
17
  RevokeGrantOptionSchemaPrivileges,
17
18
  RevokeSchemaPrivileges,
18
19
  } from "./changes/schema.privilege.ts";
20
+ import {
21
+ CreateSecurityLabelOnSchema,
22
+ DropSecurityLabelOnSchema,
23
+ } from "./changes/schema.security-label.ts";
19
24
  import type { SchemaChange } from "./changes/schema.types.ts";
20
25
  import type { Schema } from "./schema.model.ts";
21
26
 
@@ -45,6 +50,14 @@ export function diffSchemas(
45
50
  if (sc.comment !== null) {
46
51
  changes.push(new CreateCommentOnSchema({ schema: sc }));
47
52
  }
53
+ for (const label of sc.security_labels) {
54
+ changes.push(
55
+ new CreateSecurityLabelOnSchema({
56
+ schema: sc,
57
+ securityLabel: label,
58
+ }),
59
+ );
60
+ }
48
61
 
49
62
  // PRIVILEGES: For created objects, compare against default privileges state
50
63
  // The migration script will run ALTER DEFAULT PRIVILEGES before CREATE (via constraint spec),
@@ -87,7 +100,16 @@ export function diffSchemas(
87
100
  }
88
101
 
89
102
  for (const schemaId of dropped) {
90
- changes.push(new DropSchema({ schema: main[schemaId] }));
103
+ const mainSchema = main[schemaId];
104
+ for (const label of mainSchema.security_labels) {
105
+ changes.push(
106
+ new DropSecurityLabelOnSchema({
107
+ schema: mainSchema,
108
+ securityLabel: label,
109
+ }),
110
+ );
111
+ }
112
+ changes.push(new DropSchema({ schema: mainSchema }));
91
113
  }
92
114
 
93
115
  for (const schemaId of altered) {
@@ -113,6 +135,26 @@ export function diffSchemas(
113
135
  }
114
136
  }
115
137
 
138
+ // SECURITY LABELS
139
+ changes.push(
140
+ ...diffSecurityLabels<
141
+ CreateSecurityLabelOnSchema | DropSecurityLabelOnSchema
142
+ >(
143
+ mainSchema.security_labels,
144
+ branchSchema.security_labels,
145
+ (securityLabel) =>
146
+ new CreateSecurityLabelOnSchema({
147
+ schema: branchSchema,
148
+ securityLabel,
149
+ }),
150
+ (securityLabel) =>
151
+ new DropSecurityLabelOnSchema({
152
+ schema: mainSchema,
153
+ securityLabel,
154
+ }),
155
+ ),
156
+ );
157
+
116
158
  // PRIVILEGES
117
159
  // Filter out owner privileges - owner always has ALL privileges implicitly
118
160
  // and shouldn't be compared. Use branch owner as the reference.
@@ -6,6 +6,10 @@ import {
6
6
  type PrivilegeProps,
7
7
  privilegePropsSchema,
8
8
  } from "../base.privilege-diff.ts";
9
+ import {
10
+ type SecurityLabelProps,
11
+ securityLabelPropsSchema,
12
+ } from "../security-label.types.ts";
9
13
 
10
14
  /**
11
15
  * All properties exposed by CREATE SCHEMA statement are included in diff output.
@@ -19,6 +23,7 @@ const schemaPropsSchema = z.object({
19
23
  owner: z.string(),
20
24
  comment: z.string().nullable(),
21
25
  privileges: z.array(privilegePropsSchema),
26
+ security_labels: z.array(securityLabelPropsSchema).default([]).optional(),
22
27
  });
23
28
 
24
29
  type SchemaPrivilegeProps = PrivilegeProps;
@@ -29,6 +34,7 @@ export class Schema extends BasePgModel {
29
34
  public readonly owner: SchemaProps["owner"];
30
35
  public readonly comment: SchemaProps["comment"];
31
36
  public readonly privileges: SchemaPrivilegeProps[];
37
+ public readonly security_labels: SecurityLabelProps[];
32
38
 
33
39
  constructor(props: SchemaProps) {
34
40
  super();
@@ -40,6 +46,7 @@ export class Schema extends BasePgModel {
40
46
  this.owner = props.owner;
41
47
  this.comment = props.comment;
42
48
  this.privileges = props.privileges;
49
+ this.security_labels = props.security_labels ?? [];
43
50
  }
44
51
 
45
52
  get stableId(): `schema:${string}` {
@@ -57,6 +64,7 @@ export class Schema extends BasePgModel {
57
64
  owner: this.owner,
58
65
  comment: this.comment,
59
66
  privileges: this.privileges,
67
+ security_labels: this.security_labels,
60
68
  };
61
69
  }
62
70
  }
@@ -88,7 +96,19 @@ export async function extractSchemas(pool: Pool): Promise<Schema[]> {
88
96
  )
89
97
  from lateral aclexplode(COALESCE(nspacl, acldefault('n', nspowner))) as x(grantor, grantee, privilege_type, is_grantable)
90
98
  ), '[]'
91
- ) as privileges
99
+ ) as privileges,
100
+ coalesce(
101
+ (
102
+ select json_agg(
103
+ json_build_object('provider', sl.provider, 'label', sl.label)
104
+ order by sl.provider
105
+ )
106
+ from pg_catalog.pg_seclabel sl
107
+ where sl.objoid = pg_namespace.oid
108
+ and sl.classoid = 'pg_namespace'::regclass
109
+ and sl.objsubid = 0
110
+ ), '[]'
111
+ ) as security_labels
92
112
  from
93
113
  pg_catalog.pg_namespace
94
114
  left outer join extension_oids e on e.objid = oid
@@ -0,0 +1,106 @@
1
+ import { describe, expect, test } from "bun:test";
2
+ import {
3
+ diffSecurityLabels,
4
+ type SecurityLabelProps,
5
+ securityLabelPropsSchema,
6
+ } from "./security-label.types.ts";
7
+
8
+ describe("securityLabelPropsSchema", () => {
9
+ test("parses valid props", () => {
10
+ const parsed = securityLabelPropsSchema.parse({
11
+ provider: "p",
12
+ label: "l",
13
+ });
14
+ expect(parsed).toEqual({ provider: "p", label: "l" });
15
+ });
16
+
17
+ test("rejects null provider", () => {
18
+ expect(() =>
19
+ securityLabelPropsSchema.parse({ provider: null, label: "l" }),
20
+ ).toThrow();
21
+ });
22
+
23
+ test("rejects null label", () => {
24
+ expect(() =>
25
+ securityLabelPropsSchema.parse({ provider: "p", label: null }),
26
+ ).toThrow();
27
+ });
28
+ });
29
+
30
+ describe("diffSecurityLabels", () => {
31
+ type Change = { kind: "create" | "drop" } & SecurityLabelProps;
32
+ const makeCreate = (p: SecurityLabelProps): Change => ({
33
+ kind: "create",
34
+ ...p,
35
+ });
36
+ const makeDrop = (p: SecurityLabelProps): Change => ({
37
+ kind: "drop",
38
+ ...p,
39
+ });
40
+
41
+ test("both empty → no changes", () => {
42
+ expect(diffSecurityLabels([], [], makeCreate, makeDrop)).toEqual([]);
43
+ });
44
+
45
+ test("added providers emit create", () => {
46
+ expect(
47
+ diffSecurityLabels(
48
+ [],
49
+ [{ provider: "a", label: "x" }],
50
+ makeCreate,
51
+ makeDrop,
52
+ ),
53
+ ).toEqual([{ kind: "create", provider: "a", label: "x" }]);
54
+ });
55
+
56
+ test("removed providers emit drop", () => {
57
+ expect(
58
+ diffSecurityLabels(
59
+ [{ provider: "a", label: "x" }],
60
+ [],
61
+ makeCreate,
62
+ makeDrop,
63
+ ),
64
+ ).toEqual([{ kind: "drop", provider: "a", label: "x" }]);
65
+ });
66
+
67
+ test("changed label emits create (overwrite semantics)", () => {
68
+ expect(
69
+ diffSecurityLabels(
70
+ [{ provider: "a", label: "old" }],
71
+ [{ provider: "a", label: "new" }],
72
+ makeCreate,
73
+ makeDrop,
74
+ ),
75
+ ).toEqual([{ kind: "create", provider: "a", label: "new" }]);
76
+ });
77
+
78
+ test("unchanged label emits nothing", () => {
79
+ expect(
80
+ diffSecurityLabels(
81
+ [{ provider: "a", label: "x" }],
82
+ [{ provider: "a", label: "x" }],
83
+ makeCreate,
84
+ makeDrop,
85
+ ),
86
+ ).toEqual([]);
87
+ });
88
+
89
+ test("mixed add/remove/change/unchanged across providers, sorted by provider", () => {
90
+ const main = [
91
+ { provider: "a", label: "stay" },
92
+ { provider: "b", label: "old" },
93
+ { provider: "c", label: "remove" },
94
+ ];
95
+ const branch = [
96
+ { provider: "a", label: "stay" },
97
+ { provider: "b", label: "new" },
98
+ { provider: "d", label: "add" },
99
+ ];
100
+ expect(diffSecurityLabels(main, branch, makeCreate, makeDrop)).toEqual([
101
+ { kind: "create", provider: "b", label: "new" },
102
+ { kind: "drop", provider: "c", label: "remove" },
103
+ { kind: "create", provider: "d", label: "add" },
104
+ ]);
105
+ });
106
+ });
@@ -0,0 +1,61 @@
1
+ import { z } from "zod";
2
+
3
+ export const securityLabelPropsSchema = z.object({
4
+ provider: z.string(),
5
+ label: z.string(),
6
+ });
7
+
8
+ export type SecurityLabelProps = z.infer<typeof securityLabelPropsSchema>;
9
+
10
+ export function normalizeSecurityLabels(
11
+ labels: readonly SecurityLabelProps[],
12
+ ): SecurityLabelProps[] {
13
+ return [...labels].sort((a, b) => a.provider.localeCompare(b.provider));
14
+ }
15
+
16
+ /**
17
+ * Pure helper: compares two arrays of security labels keyed by provider and
18
+ * returns a deterministic list of create/drop changes.
19
+ *
20
+ * - Labels present only on `branch` → emit create (via makeCreate).
21
+ * - Labels present only on `main` → emit drop (via makeDrop).
22
+ * - Labels with differing `label` under the same provider → emit create
23
+ * (PostgreSQL's SECURITY LABEL … IS '…' overwrites, so no separate alter).
24
+ * - Unchanged labels → nothing.
25
+ *
26
+ * Output order: by provider ascending.
27
+ */
28
+ export function diffSecurityLabels<C>(
29
+ main: readonly SecurityLabelProps[],
30
+ branch: readonly SecurityLabelProps[],
31
+ makeCreate: (props: SecurityLabelProps) => C,
32
+ makeDrop: (props: SecurityLabelProps) => C,
33
+ ): C[] {
34
+ const mainByProvider = new Map(main.map((l) => [l.provider, l.label]));
35
+ const branchByProvider = new Map(branch.map((l) => [l.provider, l.label]));
36
+
37
+ const providers = new Set<string>([
38
+ ...mainByProvider.keys(),
39
+ ...branchByProvider.keys(),
40
+ ]);
41
+ const sortedProviders = [...providers].sort();
42
+
43
+ const out: C[] = [];
44
+ for (const provider of sortedProviders) {
45
+ const mainLabel = mainByProvider.get(provider);
46
+ const branchLabel = branchByProvider.get(provider);
47
+
48
+ if (mainLabel === undefined && branchLabel !== undefined) {
49
+ out.push(makeCreate({ provider, label: branchLabel }));
50
+ } else if (mainLabel !== undefined && branchLabel === undefined) {
51
+ out.push(makeDrop({ provider, label: mainLabel }));
52
+ } else if (
53
+ mainLabel !== undefined &&
54
+ branchLabel !== undefined &&
55
+ mainLabel !== branchLabel
56
+ ) {
57
+ out.push(makeCreate({ provider, label: branchLabel }));
58
+ }
59
+ }
60
+ return out;
61
+ }
@@ -3,7 +3,11 @@ import type { Sequence } from "../sequence.model.ts";
3
3
 
4
4
  abstract class BaseSequenceChange extends BaseChange {
5
5
  abstract readonly sequence: Sequence;
6
- abstract readonly scope: "object" | "comment" | "privilege";
6
+ abstract readonly scope:
7
+ | "object"
8
+ | "comment"
9
+ | "privilege"
10
+ | "security_label";
7
11
  readonly objectType: "sequence" = "sequence";
8
12
  }
9
13
 
@@ -0,0 +1,58 @@
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 { Sequence, type SequenceProps } from "../sequence.model.ts";
5
+ import {
6
+ CreateSecurityLabelOnSequence,
7
+ DropSecurityLabelOnSequence,
8
+ } from "./sequence.security-label.ts";
9
+
10
+ const makeSequence = (): Sequence =>
11
+ new Sequence({
12
+ schema: "public",
13
+ name: "s1",
14
+ data_type: "bigint",
15
+ start_value: 1,
16
+ minimum_value: BigInt(1),
17
+ maximum_value: BigInt("9223372036854775807"),
18
+ increment: 1,
19
+ cycle_option: false,
20
+ cache_size: 1,
21
+ persistence: "p",
22
+ owned_by_schema: null,
23
+ owned_by_table: null,
24
+ owned_by_column: null,
25
+ comment: null,
26
+ privileges: [],
27
+ owner: "postgres",
28
+ } as SequenceProps);
29
+
30
+ describe("sequence.security-label", () => {
31
+ test("create serializes", async () => {
32
+ const sequence = makeSequence();
33
+ const change = new CreateSecurityLabelOnSequence({
34
+ sequence,
35
+ securityLabel: { provider: "dummy", label: "classified" },
36
+ });
37
+ expect(change.scope).toBe("security_label");
38
+ expect(change.creates).toEqual([
39
+ stableId.securityLabel(sequence.stableId, "dummy"),
40
+ ]);
41
+ await assertValidSql(change.serialize());
42
+ expect(change.serialize()).toBe(
43
+ "SECURITY LABEL FOR dummy ON SEQUENCE public.s1 IS 'classified'",
44
+ );
45
+ });
46
+
47
+ test("drop serializes to IS NULL", async () => {
48
+ const sequence = makeSequence();
49
+ const change = new DropSecurityLabelOnSequence({
50
+ sequence,
51
+ securityLabel: { provider: "dummy", label: "x" },
52
+ });
53
+ await assertValidSql(change.serialize());
54
+ expect(change.serialize()).toBe(
55
+ "SECURITY LABEL FOR dummy ON SEQUENCE public.s1 IS NULL",
56
+ );
57
+ });
58
+ });
@@ -0,0 +1,92 @@
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 { Sequence } from "../sequence.model.ts";
5
+ import { CreateSequenceChange, DropSequenceChange } from "./sequence.base.ts";
6
+
7
+ export type SecurityLabelSequence =
8
+ | CreateSecurityLabelOnSequence
9
+ | DropSecurityLabelOnSequence;
10
+
11
+ export class CreateSecurityLabelOnSequence extends CreateSequenceChange {
12
+ public readonly sequence: Sequence;
13
+ public readonly securityLabel: SecurityLabelProps;
14
+ public readonly scope = "security_label" as const;
15
+
16
+ constructor(props: {
17
+ sequence: Sequence;
18
+ securityLabel: SecurityLabelProps;
19
+ }) {
20
+ super();
21
+ this.sequence = props.sequence;
22
+ this.securityLabel = props.securityLabel;
23
+ }
24
+
25
+ get creates() {
26
+ return [
27
+ stableId.securityLabel(
28
+ this.sequence.stableId,
29
+ this.securityLabel.provider,
30
+ ),
31
+ ];
32
+ }
33
+
34
+ get requires() {
35
+ return [this.sequence.stableId];
36
+ }
37
+
38
+ serialize(): string {
39
+ return [
40
+ "SECURITY LABEL FOR",
41
+ this.securityLabel.provider,
42
+ "ON SEQUENCE",
43
+ `${this.sequence.schema}.${this.sequence.name}`,
44
+ "IS",
45
+ quoteLiteral(this.securityLabel.label),
46
+ ].join(" ");
47
+ }
48
+ }
49
+
50
+ export class DropSecurityLabelOnSequence extends DropSequenceChange {
51
+ public readonly sequence: Sequence;
52
+ public readonly securityLabel: SecurityLabelProps;
53
+ public readonly scope = "security_label" as const;
54
+
55
+ constructor(props: {
56
+ sequence: Sequence;
57
+ securityLabel: SecurityLabelProps;
58
+ }) {
59
+ super();
60
+ this.sequence = props.sequence;
61
+ this.securityLabel = props.securityLabel;
62
+ }
63
+
64
+ get drops() {
65
+ return [
66
+ stableId.securityLabel(
67
+ this.sequence.stableId,
68
+ this.securityLabel.provider,
69
+ ),
70
+ ];
71
+ }
72
+
73
+ get requires() {
74
+ return [
75
+ stableId.securityLabel(
76
+ this.sequence.stableId,
77
+ this.securityLabel.provider,
78
+ ),
79
+ this.sequence.stableId,
80
+ ];
81
+ }
82
+
83
+ serialize(): string {
84
+ return [
85
+ "SECURITY LABEL FOR",
86
+ this.securityLabel.provider,
87
+ "ON SEQUENCE",
88
+ `${this.sequence.schema}.${this.sequence.name}`,
89
+ "IS NULL",
90
+ ].join(" ");
91
+ }
92
+ }
@@ -3,6 +3,7 @@ import type { CommentSequence } from "./sequence.comment.ts";
3
3
  import type { CreateSequence } from "./sequence.create.ts";
4
4
  import type { DropSequence } from "./sequence.drop.ts";
5
5
  import type { SequencePrivilege } from "./sequence.privilege.ts";
6
+ import type { SecurityLabelSequence } from "./sequence.security-label.ts";
6
7
 
7
8
  /** Union of all sequence-related change variants (`objectType: "sequence"`). @category Change Types */
8
9
  export type SequenceChange =
@@ -10,4 +11,5 @@ export type SequenceChange =
10
11
  | CommentSequence
11
12
  | CreateSequence
12
13
  | DropSequence
13
- | SequencePrivilege;
14
+ | SequencePrivilege
15
+ | SecurityLabelSequence;
@@ -4,6 +4,7 @@ import {
4
4
  emitObjectPrivilegeChanges,
5
5
  } from "../base.privilege-diff.ts";
6
6
  import type { ObjectDiffContext } from "../diff-context.ts";
7
+ import { diffSecurityLabels } from "../security-label.types.ts";
7
8
  import { AlterTableAlterColumnSetDefault } from "../table/changes/table.alter.ts";
8
9
  import type { Table } from "../table/table.model.ts";
9
10
  import { hasNonAlterableChanges } from "../utils.ts";
@@ -22,6 +23,10 @@ import {
22
23
  RevokeGrantOptionSequencePrivileges,
23
24
  RevokeSequencePrivileges,
24
25
  } from "./changes/sequence.privilege.ts";
26
+ import {
27
+ CreateSecurityLabelOnSequence,
28
+ DropSecurityLabelOnSequence,
29
+ } from "./changes/sequence.security-label.ts";
25
30
  import type { SequenceChange } from "./changes/sequence.types.ts";
26
31
  import type { Sequence } from "./sequence.model.ts";
27
32
 
@@ -59,6 +64,14 @@ export function diffSequences(
59
64
  if (createdSeq.comment !== null) {
60
65
  changes.push(new CreateCommentOnSequence({ sequence: createdSeq }));
61
66
  }
67
+ for (const label of createdSeq.security_labels) {
68
+ changes.push(
69
+ new CreateSecurityLabelOnSequence({
70
+ sequence: createdSeq,
71
+ securityLabel: label,
72
+ }),
73
+ );
74
+ }
62
75
  // If the created sequence is OWNED BY a column, emit an ALTER to set it
63
76
  if (
64
77
  createdSeq.owned_by_schema !== null &&
@@ -325,6 +338,26 @@ export function diffSequences(
325
338
  }
326
339
  }
327
340
 
341
+ // SECURITY LABELS
342
+ changes.push(
343
+ ...diffSecurityLabels<
344
+ CreateSecurityLabelOnSequence | DropSecurityLabelOnSequence
345
+ >(
346
+ mainSequence.security_labels,
347
+ branchSequence.security_labels,
348
+ (securityLabel) =>
349
+ new CreateSecurityLabelOnSequence({
350
+ sequence: branchSequence,
351
+ securityLabel,
352
+ }),
353
+ (securityLabel) =>
354
+ new DropSecurityLabelOnSequence({
355
+ sequence: mainSequence,
356
+ securityLabel,
357
+ }),
358
+ ),
359
+ );
360
+
328
361
  // PRIVILEGES
329
362
  // Filter out owner privileges - owner always has ALL privileges implicitly
330
363
  // and shouldn't be compared. Use branch owner as the reference.