@supabase/pg-delta 1.0.0-alpha.10 → 1.0.0-alpha.11

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 (123) hide show
  1. package/dist/cli/commands/declarative-export.js +12 -17
  2. package/dist/cli/commands/plan.js +10 -13
  3. package/dist/cli/commands/sync.js +8 -12
  4. package/dist/cli/utils/integrations.d.ts +30 -6
  5. package/dist/cli/utils/integrations.js +98 -6
  6. package/dist/core/change-utils.d.ts +9 -0
  7. package/dist/core/change-utils.js +71 -0
  8. package/dist/core/change.types.d.ts +22 -0
  9. package/dist/core/change.types.js +37 -1
  10. package/dist/core/depend.js +25 -0
  11. package/dist/core/export/file-mapper.d.ts +2 -2
  12. package/dist/core/integrations/filter/dsl.d.ts +78 -74
  13. package/dist/core/integrations/filter/dsl.js +127 -79
  14. package/dist/core/integrations/filter/flatten.d.ts +51 -0
  15. package/dist/core/integrations/filter/flatten.js +116 -0
  16. package/dist/core/integrations/integration-dsl.d.ts +17 -1
  17. package/dist/core/integrations/merge.d.ts +20 -0
  18. package/dist/core/integrations/merge.js +60 -0
  19. package/dist/core/integrations/serialize/dsl.d.ts +7 -4
  20. package/dist/core/integrations/serialize/dsl.js +2 -2
  21. package/dist/core/integrations/supabase.js +23 -8
  22. package/dist/core/objects/aggregate/changes/aggregate.types.d.ts +1 -0
  23. package/dist/core/objects/base.change.d.ts +10 -0
  24. package/dist/core/objects/base.change.js +10 -0
  25. package/dist/core/objects/base.model.d.ts +4 -1
  26. package/dist/core/objects/base.model.js +5 -2
  27. package/dist/core/objects/collation/changes/collation.types.d.ts +1 -0
  28. package/dist/core/objects/domain/changes/domain.create.d.ts +1 -1
  29. package/dist/core/objects/domain/changes/domain.create.js +7 -1
  30. package/dist/core/objects/domain/changes/domain.types.d.ts +1 -0
  31. package/dist/core/objects/event-trigger/changes/event-trigger.types.d.ts +1 -0
  32. package/dist/core/objects/extension/changes/extension.types.d.ts +1 -0
  33. package/dist/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.types.d.ts +1 -0
  34. package/dist/core/objects/foreign-data-wrapper/foreign-data-wrapper.types.d.ts +1 -0
  35. package/dist/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.types.d.ts +1 -0
  36. package/dist/core/objects/foreign-data-wrapper/server/changes/server.types.d.ts +1 -0
  37. package/dist/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.types.d.ts +1 -0
  38. package/dist/core/objects/index/changes/index.types.d.ts +1 -0
  39. package/dist/core/objects/language/changes/language.types.d.ts +1 -0
  40. package/dist/core/objects/materialized-view/changes/materialized-view.types.d.ts +1 -0
  41. package/dist/core/objects/procedure/changes/procedure.types.d.ts +1 -0
  42. package/dist/core/objects/publication/changes/publication.types.d.ts +1 -0
  43. package/dist/core/objects/rls-policy/changes/rls-policy.types.d.ts +1 -0
  44. package/dist/core/objects/role/changes/role.types.d.ts +1 -0
  45. package/dist/core/objects/rule/changes/rule.types.d.ts +1 -0
  46. package/dist/core/objects/schema/changes/schema.types.d.ts +1 -0
  47. package/dist/core/objects/sequence/changes/sequence.types.d.ts +1 -0
  48. package/dist/core/objects/subscription/changes/subscription.types.d.ts +1 -0
  49. package/dist/core/objects/table/changes/table.types.d.ts +1 -0
  50. package/dist/core/objects/trigger/changes/trigger.types.d.ts +1 -0
  51. package/dist/core/objects/type/composite-type/changes/composite-type.types.d.ts +1 -0
  52. package/dist/core/objects/type/enum/changes/enum.types.d.ts +1 -0
  53. package/dist/core/objects/type/range/changes/range.types.d.ts +1 -0
  54. package/dist/core/objects/type/type.types.d.ts +1 -0
  55. package/dist/core/objects/view/changes/view.types.d.ts +1 -0
  56. package/dist/core/objects/view/view.diff.js +24 -13
  57. package/dist/core/postgres-config.d.ts +2 -2
  58. package/dist/core/sort/custom-constraints.js +1 -1
  59. package/dist/core/sort/logical-sort.js +3 -24
  60. package/package.json +5 -1
  61. package/src/cli/commands/declarative-export.ts +19 -27
  62. package/src/cli/commands/plan.ts +14 -20
  63. package/src/cli/commands/sync.ts +8 -15
  64. package/src/cli/utils/integrations.test.ts +210 -3
  65. package/src/cli/utils/integrations.ts +134 -6
  66. package/src/core/catalog.snapshot.test.ts +11 -2
  67. package/src/core/change-utils.test.ts +61 -0
  68. package/src/core/change-utils.ts +73 -0
  69. package/src/core/change.types.ts +50 -0
  70. package/src/core/depend.ts +25 -0
  71. package/src/core/export/file-mapper.ts +7 -2
  72. package/src/core/integrations/filter/dsl.test.ts +299 -60
  73. package/src/core/integrations/filter/dsl.ts +208 -169
  74. package/src/core/integrations/filter/flatten.test.ts +282 -0
  75. package/src/core/integrations/filter/flatten.ts +150 -0
  76. package/src/core/integrations/integration-dsl.ts +17 -1
  77. package/src/core/integrations/merge.test.ts +128 -0
  78. package/src/core/integrations/merge.ts +72 -0
  79. package/src/core/integrations/serialize/dsl.test.ts +6 -6
  80. package/src/core/integrations/serialize/dsl.ts +7 -4
  81. package/src/core/integrations/supabase.ts +23 -8
  82. package/src/core/objects/aggregate/changes/aggregate.types.ts +1 -0
  83. package/src/core/objects/base.change.ts +10 -0
  84. package/src/core/objects/base.model.test.ts +43 -0
  85. package/src/core/objects/base.model.ts +5 -2
  86. package/src/core/objects/collation/changes/collation.types.ts +1 -0
  87. package/src/core/objects/domain/changes/domain.create.ts +17 -1
  88. package/src/core/objects/domain/changes/domain.types.ts +1 -0
  89. package/src/core/objects/event-trigger/changes/event-trigger.types.ts +1 -0
  90. package/src/core/objects/extension/changes/extension.types.ts +1 -0
  91. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper/changes/foreign-data-wrapper.types.ts +1 -0
  92. package/src/core/objects/foreign-data-wrapper/foreign-data-wrapper.types.ts +1 -0
  93. package/src/core/objects/foreign-data-wrapper/foreign-table/changes/foreign-table.types.ts +1 -0
  94. package/src/core/objects/foreign-data-wrapper/server/changes/server.types.ts +1 -0
  95. package/src/core/objects/foreign-data-wrapper/user-mapping/changes/user-mapping.types.ts +1 -0
  96. package/src/core/objects/index/changes/index.types.ts +1 -0
  97. package/src/core/objects/language/changes/language.types.ts +1 -0
  98. package/src/core/objects/materialized-view/changes/materialized-view.types.ts +1 -0
  99. package/src/core/objects/procedure/changes/procedure.types.ts +1 -0
  100. package/src/core/objects/publication/changes/publication.types.ts +1 -0
  101. package/src/core/objects/rls-policy/changes/rls-policy.types.ts +1 -0
  102. package/src/core/objects/role/changes/role.types.ts +1 -0
  103. package/src/core/objects/rule/changes/rule.types.ts +1 -0
  104. package/src/core/objects/schema/changes/schema.types.ts +1 -0
  105. package/src/core/objects/sequence/changes/sequence.types.ts +1 -0
  106. package/src/core/objects/subscription/changes/subscription.types.ts +1 -0
  107. package/src/core/objects/table/changes/table.types.ts +1 -0
  108. package/src/core/objects/trigger/changes/trigger.types.ts +1 -0
  109. package/src/core/objects/type/composite-type/changes/composite-type.types.ts +1 -0
  110. package/src/core/objects/type/enum/changes/enum.types.ts +1 -0
  111. package/src/core/objects/type/range/changes/range.types.ts +1 -0
  112. package/src/core/objects/type/type.types.ts +1 -0
  113. package/src/core/objects/view/changes/view.types.ts +1 -0
  114. package/src/core/objects/view/view.diff.test.ts +96 -0
  115. package/src/core/objects/view/view.diff.ts +30 -15
  116. package/src/core/postgres-config.ts +2 -2
  117. package/src/core/sort/custom-constraints.ts +1 -1
  118. package/src/core/sort/logical-sort.ts +3 -27
  119. package/src/typedoc.ts +248 -0
  120. package/dist/core/integrations/filter/extractors.d.ts +0 -12
  121. package/dist/core/integrations/filter/extractors.js +0 -178
  122. package/src/core/integrations/filter/extractors.test.ts +0 -244
  123. package/src/core/integrations/filter/extractors.ts +0 -187
@@ -20,7 +20,7 @@ describe("compileSerializeDSL", () => {
20
20
  test("matching rule applies its options", () => {
21
21
  const serializer = compileSerializeDSL([
22
22
  {
23
- when: { type: "schema" as const, operation: "create" as const },
23
+ when: { objectType: "schema", operation: "create" },
24
24
  options: { skipAuthorization: true },
25
25
  },
26
26
  ]);
@@ -37,7 +37,7 @@ describe("compileSerializeDSL", () => {
37
37
  test("no matching rule uses default serialization", () => {
38
38
  const serializer = compileSerializeDSL([
39
39
  {
40
- when: { type: "table" as const },
40
+ when: { objectType: "table" },
41
41
  options: { skipAuthorization: true },
42
42
  },
43
43
  ]);
@@ -54,11 +54,11 @@ describe("compileSerializeDSL", () => {
54
54
  test("first matching rule wins", () => {
55
55
  const serializer = compileSerializeDSL([
56
56
  {
57
- when: { type: "schema" as const },
57
+ when: { objectType: "schema" },
58
58
  options: { skipAuthorization: true },
59
59
  },
60
60
  {
61
- when: { type: "schema" as const },
61
+ when: { objectType: "schema" },
62
62
  options: { skipAuthorization: false },
63
63
  },
64
64
  ]);
@@ -73,11 +73,11 @@ describe("compileSerializeDSL", () => {
73
73
  test("skips non-matching first rule and applies second", () => {
74
74
  const serializer = compileSerializeDSL([
75
75
  {
76
- when: { type: "table" as const },
76
+ when: { objectType: "table" },
77
77
  options: { skipAuthorization: true },
78
78
  },
79
79
  {
80
- when: { type: "schema" as const },
80
+ when: { objectType: "schema" },
81
81
  options: { skipAuthorization: false },
82
82
  },
83
83
  ]);
@@ -33,8 +33,11 @@ type SerializeRule = {
33
33
  };
34
34
 
35
35
  /**
36
- * Serialization DSL - array of rules evaluated in order.
37
- * First matching rule's options are applied.
36
+ * Array of serialization rules evaluated in order. The first matching rule's
37
+ * options are passed to `change.serialize()`. If no rule matches, default
38
+ * serialization is used.
39
+ *
40
+ * @category Integration
38
41
  */
39
42
  export type SerializeDSL = SerializeRule[];
40
43
 
@@ -52,9 +55,9 @@ export type SerializeDSL = SerializeRule[];
52
55
  * const serializer = compileSerializeDSL([
53
56
  * {
54
57
  * when: {
55
- * type: "schema",
58
+ * objectType: "schema",
56
59
  * operation: "create",
57
- * owner: ["service_role"]
60
+ * "schema/owner": ["service_role"]
58
61
  * },
59
62
  * options: { skipAuthorization: true }
60
63
  * }
@@ -70,38 +70,53 @@ export const supabase: IntegrationDSL = {
70
70
  // TODO: emptyCatalog: undefined -- populate by running catalog-export on a clean Supabase container
71
71
  filter: {
72
72
  or: [
73
+ // Include user schema CREATE operations (only schemas not in system list)
73
74
  {
74
75
  and: [
75
76
  {
76
- type: "schema",
77
+ objectType: "schema",
77
78
  operation: "create",
78
79
  scope: "object",
79
80
  },
80
81
  {
81
82
  not: {
82
- schema: [...SUPABASE_SYSTEM_SCHEMAS],
83
+ // Schema objects have name, not schema — use schema/name
84
+ "schema/name": [...SUPABASE_SYSTEM_SCHEMAS],
83
85
  },
84
86
  },
85
87
  ],
86
88
  },
89
+ // Include extension CREATEs
87
90
  {
88
- type: "extension",
91
+ objectType: "extension",
89
92
  operation: "create",
90
93
  scope: "object",
91
94
  },
95
+ // Exclude system objects
92
96
  {
93
97
  not: {
94
98
  or: [
99
+ // Objects in system schemas (*/schema matches table/schema, view/schema, etc.)
95
100
  {
96
- schema: [...SUPABASE_SYSTEM_SCHEMAS],
101
+ "*/schema": [...SUPABASE_SYSTEM_SCHEMAS],
97
102
  },
103
+ // Schema objects whose own name is a system schema
98
104
  {
99
- owner: [...SUPABASE_SYSTEM_ROLES],
105
+ "schema/name": [...SUPABASE_SYSTEM_SCHEMAS],
100
106
  },
107
+ // Objects owned by system roles (*/owner matches table/owner, schema/owner, etc.)
108
+ {
109
+ "*/owner": [...SUPABASE_SYSTEM_ROLES],
110
+ },
111
+ // Role objects whose own name is a system role
112
+ {
113
+ "role/name": [...SUPABASE_SYSTEM_ROLES],
114
+ },
115
+ // Membership changes for system roles
101
116
  {
102
117
  and: [
103
118
  {
104
- type: "role",
119
+ objectType: "role",
105
120
  scope: "membership",
106
121
  },
107
122
  {
@@ -117,10 +132,10 @@ export const supabase: IntegrationDSL = {
117
132
  serialize: [
118
133
  {
119
134
  when: {
120
- type: "schema",
135
+ objectType: "schema",
121
136
  operation: "create",
122
137
  scope: "object",
123
- owner: [...SUPABASE_SYSTEM_ROLES],
138
+ "schema/owner": [...SUPABASE_SYSTEM_ROLES],
124
139
  },
125
140
  options: {
126
141
  skipAuthorization: true,
@@ -4,6 +4,7 @@ import type { CreateAggregate } from "./aggregate.create.ts";
4
4
  import type { DropAggregate } from "./aggregate.drop.ts";
5
5
  import type { AggregatePrivilege } from "./aggregate.privilege.ts";
6
6
 
7
+ /** Union of all aggregate-related change variants (`objectType: "aggregate"`). @category Change Types */
7
8
  export type AggregateChange =
8
9
  | AlterAggregate
9
10
  | CommentAggregate
@@ -1,5 +1,15 @@
1
1
  type ChangeOperation = "create" | "alter" | "drop";
2
2
 
3
+ /**
4
+ * Abstract base class for all change objects.
5
+ *
6
+ * Every concrete change (e.g. `CreateTable`, `AlterView`) extends this class and
7
+ * provides an `operation`, `objectType`, and `scope`. The filter DSL flattens
8
+ * these properties — along with the model sub-object — into path/value pairs
9
+ * for pattern matching.
10
+ *
11
+ * @category Base
12
+ */
3
13
  export abstract class BaseChange {
4
14
  /**
5
15
  * The operation of the change.
@@ -0,0 +1,43 @@
1
+ import { describe, expect, test } from "bun:test";
2
+ import { BasePgModel } from "./base.model.ts";
3
+
4
+ class NormalizedTestModel extends BasePgModel {
5
+ private readonly id: string;
6
+ private readonly values: string[];
7
+
8
+ constructor(id: string, values: string[]) {
9
+ super();
10
+ this.id = id;
11
+ this.values = values;
12
+ }
13
+
14
+ get stableId() {
15
+ return this.id;
16
+ }
17
+
18
+ get identityFields() {
19
+ return { id: this.id };
20
+ }
21
+
22
+ get dataFields() {
23
+ return { values: this.values };
24
+ }
25
+
26
+ override stableSnapshot() {
27
+ return {
28
+ identity: this.identityFields,
29
+ data: {
30
+ values: [...this.values].sort(),
31
+ },
32
+ };
33
+ }
34
+ }
35
+
36
+ describe("BasePgModel.equals", () => {
37
+ test("uses stable snapshots for normalized equality", () => {
38
+ const main = new NormalizedTestModel("same", ["b", "a"]);
39
+ const branch = new NormalizedTestModel("same", ["a", "b"]);
40
+
41
+ expect(main.equals(branch)).toBe(true);
42
+ });
43
+ });
@@ -60,12 +60,15 @@ export abstract class BasePgModel {
60
60
  abstract get dataFields(): Record<string, unknown>;
61
61
 
62
62
  /**
63
- * Compare this object with another BasePgModel for equality based on stableId and dataFields.
63
+ * Compare this object with another BasePgModel for equality based on the stableId and
64
+ * the data portion of the stable snapshot. By default, the snapshot's `data` comes
65
+ * from {@link dataFields}, but subclasses may override {@link stableSnapshot} to
66
+ * normalize or otherwise transform the data used for equality.
64
67
  */
65
68
  equals(other: BasePgModel): boolean {
66
69
  return (
67
70
  this.stableId === other.stableId &&
68
- deepEqual(this.dataFields, other.dataFields)
71
+ deepEqual(this.stableSnapshot().data, other.stableSnapshot().data)
69
72
  );
70
73
  }
71
74
 
@@ -3,6 +3,7 @@ import type { CommentCollation } from "./collation.comment.ts";
3
3
  import type { CreateCollation } from "./collation.create.ts";
4
4
  import type { DropCollation } from "./collation.drop.ts";
5
5
 
6
+ /** Union of all collation-related change variants (`objectType: "collation"`). @category Change Types */
6
7
  export type CollationChange =
7
8
  | AlterCollation
8
9
  | CommentCollation
@@ -34,7 +34,23 @@ export class CreateDomain extends CreateDomainChange {
34
34
  }
35
35
 
36
36
  get creates() {
37
- return [this.domain.stableId];
37
+ const creates: Array<
38
+ `domain:${string}` | `constraint:${string}.${string}.${string}`
39
+ > = [this.domain.stableId];
40
+
41
+ for (const constraint of this.domain.constraints) {
42
+ if (constraint.check_expression && constraint.validated) {
43
+ creates.push(
44
+ stableId.constraint(
45
+ this.domain.schema,
46
+ this.domain.name,
47
+ constraint.name,
48
+ ),
49
+ );
50
+ }
51
+ }
52
+
53
+ return creates;
38
54
  }
39
55
 
40
56
  get requires() {
@@ -4,6 +4,7 @@ import type { CreateDomain } from "./domain.create.ts";
4
4
  import type { DropDomain } from "./domain.drop.ts";
5
5
  import type { DomainPrivilege } from "./domain.privilege.ts";
6
6
 
7
+ /** Union of all domain-related change variants (`objectType: "domain"`). @category Change Types */
7
8
  export type DomainChange =
8
9
  | AlterDomain
9
10
  | CommentDomain
@@ -3,6 +3,7 @@ import type { CommentEventTrigger } from "./event-trigger.comment.ts";
3
3
  import type { CreateEventTrigger } from "./event-trigger.create.ts";
4
4
  import type { DropEventTrigger } from "./event-trigger.drop.ts";
5
5
 
6
+ /** Union of all event-trigger-related change variants (`objectType: "event_trigger"`). @category Change Types */
6
7
  export type EventTriggerChange =
7
8
  | AlterEventTrigger
8
9
  | CommentEventTrigger
@@ -3,6 +3,7 @@ import type { CommentExtension } from "./extension.comment.ts";
3
3
  import type { CreateExtension } from "./extension.create.ts";
4
4
  import type { DropExtension } from "./extension.drop.ts";
5
5
 
6
+ /** Union of all extension-related change variants (`objectType: "extension"`). @category Change Types */
6
7
  export type ExtensionChange =
7
8
  | AlterExtension
8
9
  | CommentExtension
@@ -4,6 +4,7 @@ import type { CreateForeignDataWrapper } from "./foreign-data-wrapper.create.ts"
4
4
  import type { DropForeignDataWrapper } from "./foreign-data-wrapper.drop.ts";
5
5
  import type { ForeignDataWrapperPrivilege } from "./foreign-data-wrapper.privilege.ts";
6
6
 
7
+ /** Union of all FDW wrapper-level change variants (`objectType: "foreign_data_wrapper"`). @category Change Types */
7
8
  export type ForeignDataWrapperChange =
8
9
  | AlterForeignDataWrapper
9
10
  | CommentForeignDataWrapper
@@ -3,6 +3,7 @@ import type { ForeignTableChange } from "./foreign-table/changes/foreign-table.t
3
3
  import type { ServerChange } from "./server/changes/server.types.ts";
4
4
  import type { UserMappingChange } from "./user-mapping/changes/user-mapping.types.ts";
5
5
 
6
+ /** Union of all foreign-data-wrapper-related change variants (`objectType: "foreign_data_wrapper" | "server" | "foreign_table" | "user_mapping"`). @category Change Types */
6
7
  export type ForeignDataWrapperChange =
7
8
  | FDWChange
8
9
  | ServerChange
@@ -4,6 +4,7 @@ import type { CreateForeignTable } from "./foreign-table.create.ts";
4
4
  import type { DropForeignTable } from "./foreign-table.drop.ts";
5
5
  import type { ForeignTablePrivilege } from "./foreign-table.privilege.ts";
6
6
 
7
+ /** Union of all foreign-table-related change variants (`objectType: "foreign_table"`). @category Change Types */
7
8
  export type ForeignTableChange =
8
9
  | AlterForeignTable
9
10
  | CommentForeignTable
@@ -4,6 +4,7 @@ import type { CreateServer } from "./server.create.ts";
4
4
  import type { DropServer } from "./server.drop.ts";
5
5
  import type { ServerPrivilege } from "./server.privilege.ts";
6
6
 
7
+ /** Union of all server-related change variants (`objectType: "server"`). @category Change Types */
7
8
  export type ServerChange =
8
9
  | AlterServer
9
10
  | CommentServer
@@ -2,6 +2,7 @@ import type { AlterUserMapping } from "./user-mapping.alter.ts";
2
2
  import type { CreateUserMapping } from "./user-mapping.create.ts";
3
3
  import type { DropUserMapping } from "./user-mapping.drop.ts";
4
4
 
5
+ /** Union of all user-mapping-related change variants (`objectType: "user_mapping"`). @category Change Types */
5
6
  export type UserMappingChange =
6
7
  | AlterUserMapping
7
8
  | CreateUserMapping
@@ -3,4 +3,5 @@ import type { CommentIndex } from "./index.comment.ts";
3
3
  import type { CreateIndex } from "./index.create.ts";
4
4
  import type { DropIndex } from "./index.drop.ts";
5
5
 
6
+ /** Union of all index-related change variants (`objectType: "index"`). @category Change Types */
6
7
  export type IndexChange = AlterIndex | CommentIndex | CreateIndex | DropIndex;
@@ -4,6 +4,7 @@ import type { CreateLanguage } from "./language.create.ts";
4
4
  import type { DropLanguage } from "./language.drop.ts";
5
5
  import type { LanguagePrivilege } from "./language.privilege.ts";
6
6
 
7
+ /** Union of all language-related change variants (`objectType: "language"`). @category Change Types */
7
8
  export type LanguageChange =
8
9
  | AlterLanguage
9
10
  | CommentLanguage
@@ -4,6 +4,7 @@ import type { CreateMaterializedView } from "./materialized-view.create.ts";
4
4
  import type { DropMaterializedView } from "./materialized-view.drop.ts";
5
5
  import type { MaterializedViewPrivilege } from "./materialized-view.privilege.ts";
6
6
 
7
+ /** Union of all materialized-view-related change variants (`objectType: "materialized_view"`). @category Change Types */
7
8
  export type MaterializedViewChange =
8
9
  | AlterMaterializedView
9
10
  | CommentMaterializedView
@@ -4,6 +4,7 @@ import type { CreateProcedure } from "./procedure.create.ts";
4
4
  import type { DropProcedure } from "./procedure.drop.ts";
5
5
  import type { ProcedurePrivilege } from "./procedure.privilege.ts";
6
6
 
7
+ /** Union of all procedure-related change variants (`objectType: "procedure"`). @category Change Types */
7
8
  export type ProcedureChange =
8
9
  | AlterProcedure
9
10
  | CommentProcedure
@@ -11,6 +11,7 @@ import type { CommentPublication } from "./publication.comment.ts";
11
11
  import type { CreatePublication } from "./publication.create.ts";
12
12
  import type { DropPublication } from "./publication.drop.ts";
13
13
 
14
+ /** Union of all publication-related change variants (`objectType: "publication"`). @category Change Types */
14
15
  export type PublicationChange =
15
16
  | AlterPublicationAddSchemas
16
17
  | AlterPublicationAddTables
@@ -3,6 +3,7 @@ import type { CommentRlsPolicy } from "./rls-policy.comment.ts";
3
3
  import type { CreateRlsPolicy } from "./rls-policy.create.ts";
4
4
  import type { DropRlsPolicy } from "./rls-policy.drop.ts";
5
5
 
6
+ /** Union of all RLS policy-related change variants (`objectType: "rls_policy"`). @category Change Types */
6
7
  export type RlsPolicyChange =
7
8
  | AlterRlsPolicy
8
9
  | CommentRlsPolicy
@@ -4,6 +4,7 @@ import type { CreateRole } from "./role.create.ts";
4
4
  import type { DropRole } from "./role.drop.ts";
5
5
  import type { RolePrivilege } from "./role.privilege.ts";
6
6
 
7
+ /** Union of all role-related change variants (`objectType: "role"`). @category Change Types */
7
8
  export type RoleChange =
8
9
  | AlterRole
9
10
  | CommentRole
@@ -3,6 +3,7 @@ import type { CreateCommentOnRule, DropCommentOnRule } from "./rule.comment.ts";
3
3
  import type { CreateRule } from "./rule.create.ts";
4
4
  import type { DropRule } from "./rule.drop.ts";
5
5
 
6
+ /** Union of all rule-related change variants (`objectType: "rule"`). @category Change Types */
6
7
  export type RuleChange =
7
8
  | CreateRule
8
9
  | DropRule
@@ -4,6 +4,7 @@ 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
6
 
7
+ /** Union of all schema-related change variants (`objectType: "schema"`). @category Change Types */
7
8
  export type SchemaChange =
8
9
  | AlterSchema
9
10
  | CommentSchema
@@ -4,6 +4,7 @@ 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
6
 
7
+ /** Union of all sequence-related change variants (`objectType: "sequence"`). @category Change Types */
7
8
  export type SequenceChange =
8
9
  | AlterSequence
9
10
  | CommentSequence
@@ -10,6 +10,7 @@ import type { CommentSubscription } from "./subscription.comment.ts";
10
10
  import type { CreateSubscription } from "./subscription.create.ts";
11
11
  import type { DropSubscription } from "./subscription.drop.ts";
12
12
 
13
+ /** Union of all subscription-related change variants (`objectType: "subscription"`). @category Change Types */
13
14
  export type SubscriptionChange =
14
15
  | CreateSubscription
15
16
  | DropSubscription
@@ -4,6 +4,7 @@ import type { CreateTable } from "./table.create.ts";
4
4
  import type { DropTable } from "./table.drop.ts";
5
5
  import type { TablePrivilege } from "./table.privilege.ts";
6
6
 
7
+ /** Union of all table-related change variants (`objectType: "table"`). @category Change Types */
7
8
  export type TableChange =
8
9
  | AlterTable
9
10
  | CommentTable
@@ -3,6 +3,7 @@ import type { CommentTrigger } from "./trigger.comment.ts";
3
3
  import type { CreateTrigger } from "./trigger.create.ts";
4
4
  import type { DropTrigger } from "./trigger.drop.ts";
5
5
 
6
+ /** Union of all trigger-related change variants (`objectType: "trigger"`). @category Change Types */
6
7
  export type TriggerChange =
7
8
  | AlterTrigger
8
9
  | CommentTrigger
@@ -4,6 +4,7 @@ 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
6
 
7
+ /** Union of all composite-type-related change variants (`objectType: "composite_type"`). @category Change Types */
7
8
  export type CompositeTypeChange =
8
9
  | AlterCompositeType
9
10
  | CommentCompositeType
@@ -4,6 +4,7 @@ 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
6
 
7
+ /** Union of all enum-related change variants (`objectType: "enum"`). @category Change Types */
7
8
  export type EnumChange =
8
9
  | AlterEnum
9
10
  | CommentEnum
@@ -4,6 +4,7 @@ import type { CreateRange } from "./range.create.ts";
4
4
  import type { DropRange } from "./range.drop.ts";
5
5
  import type { RangePrivilege } from "./range.privilege.ts";
6
6
 
7
+ /** Union of all range-related change variants (`objectType: "range"`). @category Change Types */
7
8
  export type RangeChange =
8
9
  | AlterRange
9
10
  | CommentRange
@@ -2,4 +2,5 @@ import type { CompositeTypeChange } from "./composite-type/changes/composite-typ
2
2
  import type { EnumChange } from "./enum/changes/enum.types.ts";
3
3
  import type { RangeChange } from "./range/changes/range.types.ts";
4
4
 
5
+ /** Union of all type-related change variants (`objectType: "composite_type" | "enum" | "range"`). @category Change Types */
5
6
  export type TypeChange = CompositeTypeChange | EnumChange | RangeChange;
@@ -4,6 +4,7 @@ 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
6
 
7
+ /** Union of all view-related change variants (`objectType: "view"`). @category Change Types */
7
8
  export type ViewChange =
8
9
  | AlterView
9
10
  | CommentView
@@ -105,6 +105,102 @@ describe.concurrent("view.diff", () => {
105
105
  expect(changes[0]).toBeInstanceOf(CreateView);
106
106
  });
107
107
 
108
+ test("drop and recreate when view columns change", () => {
109
+ const main = makeView({
110
+ owner: "postgres",
111
+ columns: [
112
+ {
113
+ name: "id",
114
+ position: 1,
115
+ data_type: "integer",
116
+ data_type_str: "integer",
117
+ is_custom_type: false,
118
+ custom_type_type: null,
119
+ custom_type_category: null,
120
+ custom_type_schema: null,
121
+ custom_type_name: null,
122
+ not_null: false,
123
+ is_identity: false,
124
+ is_identity_always: false,
125
+ is_generated: false,
126
+ collation: null,
127
+ default: null,
128
+ comment: null,
129
+ },
130
+ ],
131
+ });
132
+ const branch = makeView({
133
+ owner: "postgres",
134
+ columns: [
135
+ ...main.columns,
136
+ {
137
+ name: "priority",
138
+ position: 2,
139
+ data_type: "integer",
140
+ data_type_str: "integer",
141
+ is_custom_type: false,
142
+ custom_type_type: null,
143
+ custom_type_category: null,
144
+ custom_type_schema: null,
145
+ custom_type_name: null,
146
+ not_null: false,
147
+ is_identity: false,
148
+ is_identity_always: false,
149
+ is_generated: false,
150
+ collation: null,
151
+ default: null,
152
+ comment: null,
153
+ },
154
+ ],
155
+ });
156
+ const changes = diffViews(
157
+ testContext,
158
+ { [main.stableId]: main },
159
+ { [branch.stableId]: branch },
160
+ );
161
+ expect(changes).toHaveLength(2);
162
+ expect(changes[0]).toBeInstanceOf(DropView);
163
+ expect(changes[1]).toBeInstanceOf(CreateView);
164
+ });
165
+
166
+ test("column position-only change does not trigger drop+create", () => {
167
+ const col = {
168
+ name: "id",
169
+ position: 1,
170
+ data_type: "integer",
171
+ data_type_str: "integer",
172
+ is_custom_type: false,
173
+ custom_type_type: null,
174
+ custom_type_category: null,
175
+ custom_type_schema: null,
176
+ custom_type_name: null,
177
+ not_null: false,
178
+ is_identity: false,
179
+ is_identity_always: false,
180
+ is_generated: false,
181
+ collation: null,
182
+ default: null,
183
+ comment: "my column",
184
+ };
185
+ const main = makeView({
186
+ owner: "postgres",
187
+ comment: "old comment",
188
+ columns: [{ ...col, position: 1 }],
189
+ });
190
+ const branch = makeView({
191
+ owner: "postgres",
192
+ comment: "new comment",
193
+ columns: [{ ...col, position: 2 }],
194
+ });
195
+ const changes = diffViews(
196
+ testContext,
197
+ { [main.stableId]: main },
198
+ { [branch.stableId]: branch },
199
+ );
200
+ expect(changes.some((c) => c instanceof DropView)).toBe(false);
201
+ expect(changes.some((c) => c instanceof CreateCommentOnView)).toBe(true);
202
+ });
203
+
108
204
  test("create with privileges emits grant changes", () => {
109
205
  const v = makeView({
110
206
  privileges: [