@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
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Integration merging — combines multiple IntegrationDSL objects.
3
+ *
4
+ * - Filters are AND-combined
5
+ * - Serialize rules are concatenated (earlier integrations first = higher priority)
6
+ * - emptyCatalog: most-specific (last) integration's value wins
7
+ */
8
+ /**
9
+ * Merge an ordered list of integrations into a single IntegrationDSL.
10
+ *
11
+ * Integrations are ordered from base (first) to most-specific (last).
12
+ * - Filters: AND-combined (all must pass)
13
+ * - Serialize: concatenated (base rules first → higher priority, first-match-wins)
14
+ * - emptyCatalog: most-specific non-undefined value wins
15
+ *
16
+ * @param integrations - Ordered list of integrations (base first, most-specific last)
17
+ * @returns A single merged IntegrationDSL
18
+ */
19
+ export function mergeIntegrations(integrations) {
20
+ if (integrations.length === 0)
21
+ return {};
22
+ if (integrations.length === 1)
23
+ return integrations[0];
24
+ // Collect all filters
25
+ const filters = [];
26
+ for (const integration of integrations) {
27
+ if (integration.filter) {
28
+ filters.push(integration.filter);
29
+ }
30
+ }
31
+ // Collect all serialize rules (base first = higher priority)
32
+ const serializeRules = [];
33
+ for (const integration of integrations) {
34
+ if (integration.serialize) {
35
+ serializeRules.push(...integration.serialize);
36
+ }
37
+ }
38
+ // emptyCatalog: most-specific (last) non-undefined wins
39
+ let emptyCatalog;
40
+ for (let i = integrations.length - 1; i >= 0; i--) {
41
+ if (integrations[i].emptyCatalog !== undefined) {
42
+ emptyCatalog = integrations[i].emptyCatalog;
43
+ break;
44
+ }
45
+ }
46
+ const merged = {};
47
+ if (filters.length === 1) {
48
+ merged.filter = filters[0];
49
+ }
50
+ else if (filters.length > 1) {
51
+ merged.filter = { and: filters };
52
+ }
53
+ if (serializeRules.length > 0) {
54
+ merged.serialize = serializeRules;
55
+ }
56
+ if (emptyCatalog !== undefined) {
57
+ merged.emptyCatalog = emptyCatalog;
58
+ }
59
+ return merged;
60
+ }
@@ -27,8 +27,11 @@ type SerializeRule = {
27
27
  options: SerializeOptions;
28
28
  };
29
29
  /**
30
- * Serialization DSL - array of rules evaluated in order.
31
- * First matching rule's options are applied.
30
+ * Array of serialization rules evaluated in order. The first matching rule's
31
+ * options are passed to `change.serialize()`. If no rule matches, default
32
+ * serialization is used.
33
+ *
34
+ * @category Integration
32
35
  */
33
36
  export type SerializeDSL = SerializeRule[];
34
37
  /**
@@ -45,9 +48,9 @@ export type SerializeDSL = SerializeRule[];
45
48
  * const serializer = compileSerializeDSL([
46
49
  * {
47
50
  * when: {
48
- * type: "schema",
51
+ * objectType: "schema",
49
52
  * operation: "create",
50
- * owner: ["service_role"]
53
+ * "schema/owner": ["service_role"]
51
54
  * },
52
55
  * options: { skipAuthorization: true }
53
56
  * }
@@ -18,9 +18,9 @@ import { evaluatePattern } from "../filter/dsl.js";
18
18
  * const serializer = compileSerializeDSL([
19
19
  * {
20
20
  * when: {
21
- * type: "schema",
21
+ * objectType: "schema",
22
22
  * operation: "create",
23
- * owner: ["service_role"]
23
+ * "schema/owner": ["service_role"]
24
24
  * },
25
25
  * options: { skipAuthorization: true }
26
26
  * }
@@ -65,38 +65,53 @@ export const supabase = {
65
65
  // TODO: emptyCatalog: undefined -- populate by running catalog-export on a clean Supabase container
66
66
  filter: {
67
67
  or: [
68
+ // Include user schema CREATE operations (only schemas not in system list)
68
69
  {
69
70
  and: [
70
71
  {
71
- type: "schema",
72
+ objectType: "schema",
72
73
  operation: "create",
73
74
  scope: "object",
74
75
  },
75
76
  {
76
77
  not: {
77
- schema: [...SUPABASE_SYSTEM_SCHEMAS],
78
+ // Schema objects have name, not schema — use schema/name
79
+ "schema/name": [...SUPABASE_SYSTEM_SCHEMAS],
78
80
  },
79
81
  },
80
82
  ],
81
83
  },
84
+ // Include extension CREATEs
82
85
  {
83
- type: "extension",
86
+ objectType: "extension",
84
87
  operation: "create",
85
88
  scope: "object",
86
89
  },
90
+ // Exclude system objects
87
91
  {
88
92
  not: {
89
93
  or: [
94
+ // Objects in system schemas (*/schema matches table/schema, view/schema, etc.)
90
95
  {
91
- schema: [...SUPABASE_SYSTEM_SCHEMAS],
96
+ "*/schema": [...SUPABASE_SYSTEM_SCHEMAS],
92
97
  },
98
+ // Schema objects whose own name is a system schema
93
99
  {
94
- owner: [...SUPABASE_SYSTEM_ROLES],
100
+ "schema/name": [...SUPABASE_SYSTEM_SCHEMAS],
95
101
  },
102
+ // Objects owned by system roles (*/owner matches table/owner, schema/owner, etc.)
103
+ {
104
+ "*/owner": [...SUPABASE_SYSTEM_ROLES],
105
+ },
106
+ // Role objects whose own name is a system role
107
+ {
108
+ "role/name": [...SUPABASE_SYSTEM_ROLES],
109
+ },
110
+ // Membership changes for system roles
96
111
  {
97
112
  and: [
98
113
  {
99
- type: "role",
114
+ objectType: "role",
100
115
  scope: "membership",
101
116
  },
102
117
  {
@@ -112,10 +127,10 @@ export const supabase = {
112
127
  serialize: [
113
128
  {
114
129
  when: {
115
- type: "schema",
130
+ objectType: "schema",
116
131
  operation: "create",
117
132
  scope: "object",
118
- owner: [...SUPABASE_SYSTEM_ROLES],
133
+ "schema/owner": [...SUPABASE_SYSTEM_ROLES],
119
134
  },
120
135
  options: {
121
136
  skipAuthorization: true,
@@ -3,4 +3,5 @@ import type { CommentAggregate } from "./aggregate.comment.ts";
3
3
  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
+ /** Union of all aggregate-related change variants (`objectType: "aggregate"`). @category Change Types */
6
7
  export type AggregateChange = AlterAggregate | CommentAggregate | CreateAggregate | DropAggregate | AggregatePrivilege;
@@ -1,4 +1,14 @@
1
1
  type ChangeOperation = "create" | "alter" | "drop";
2
+ /**
3
+ * Abstract base class for all change objects.
4
+ *
5
+ * Every concrete change (e.g. `CreateTable`, `AlterView`) extends this class and
6
+ * provides an `operation`, `objectType`, and `scope`. The filter DSL flattens
7
+ * these properties — along with the model sub-object — into path/value pairs
8
+ * for pattern matching.
9
+ *
10
+ * @category Base
11
+ */
2
12
  export declare abstract class BaseChange {
3
13
  /**
4
14
  * The operation of the change.
@@ -1,3 +1,13 @@
1
+ /**
2
+ * Abstract base class for all change objects.
3
+ *
4
+ * Every concrete change (e.g. `CreateTable`, `AlterView`) extends this class and
5
+ * provides an `operation`, `objectType`, and `scope`. The filter DSL flattens
6
+ * these properties — along with the model sub-object — into path/value pairs
7
+ * for pattern matching.
8
+ *
9
+ * @category Base
10
+ */
1
11
  export class BaseChange {
2
12
  /**
3
13
  * A unique identifier for the change.
@@ -60,7 +60,10 @@ export declare abstract class BasePgModel {
60
60
  */
61
61
  abstract get dataFields(): Record<string, unknown>;
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
  /**
@@ -28,11 +28,14 @@ export function normalizeColumns(columns) {
28
28
  }
29
29
  export class BasePgModel {
30
30
  /**
31
- * Compare this object with another BasePgModel for equality based on stableId and dataFields.
31
+ * Compare this object with another BasePgModel for equality based on the stableId and
32
+ * the data portion of the stable snapshot. By default, the snapshot's `data` comes
33
+ * from {@link dataFields}, but subclasses may override {@link stableSnapshot} to
34
+ * normalize or otherwise transform the data used for equality.
32
35
  */
33
36
  equals(other) {
34
37
  return (this.stableId === other.stableId &&
35
- deepEqual(this.dataFields, other.dataFields));
38
+ deepEqual(this.stableSnapshot().data, other.stableSnapshot().data));
36
39
  }
37
40
  /**
38
41
  * Stable representation used for equality/fingerprints.
@@ -2,4 +2,5 @@ import type { AlterCollation } from "./collation.alter.ts";
2
2
  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
+ /** Union of all collation-related change variants (`objectType: "collation"`). @category Change Types */
5
6
  export type CollationChange = AlterCollation | CommentCollation | CreateCollation | DropCollation;
@@ -24,7 +24,7 @@ export declare class CreateDomain extends CreateDomainChange {
24
24
  constructor(props: {
25
25
  domain: Domain;
26
26
  });
27
- get creates(): `domain:${string}`[];
27
+ get creates(): (`constraint:${string}.${string}.${string}` | `domain:${string}`)[];
28
28
  get requires(): string[];
29
29
  serialize(): string;
30
30
  }
@@ -26,7 +26,13 @@ export class CreateDomain extends CreateDomainChange {
26
26
  this.domain = props.domain;
27
27
  }
28
28
  get creates() {
29
- return [this.domain.stableId];
29
+ const creates = [this.domain.stableId];
30
+ for (const constraint of this.domain.constraints) {
31
+ if (constraint.check_expression && constraint.validated) {
32
+ creates.push(stableId.constraint(this.domain.schema, this.domain.name, constraint.name));
33
+ }
34
+ }
35
+ return creates;
30
36
  }
31
37
  get requires() {
32
38
  const dependencies = new Set();
@@ -3,4 +3,5 @@ import type { CommentDomain } from "./domain.comment.ts";
3
3
  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
+ /** Union of all domain-related change variants (`objectType: "domain"`). @category Change Types */
6
7
  export type DomainChange = AlterDomain | CommentDomain | CreateDomain | DropDomain | DomainPrivilege;
@@ -2,4 +2,5 @@ import type { AlterEventTrigger } from "./event-trigger.alter.ts";
2
2
  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
+ /** Union of all event-trigger-related change variants (`objectType: "event_trigger"`). @category Change Types */
5
6
  export type EventTriggerChange = AlterEventTrigger | CommentEventTrigger | CreateEventTrigger | DropEventTrigger;
@@ -2,4 +2,5 @@ import type { AlterExtension } from "./extension.alter.ts";
2
2
  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
+ /** Union of all extension-related change variants (`objectType: "extension"`). @category Change Types */
5
6
  export type ExtensionChange = AlterExtension | CommentExtension | CreateExtension | DropExtension;
@@ -3,4 +3,5 @@ import type { CommentForeignDataWrapper } from "./foreign-data-wrapper.comment.t
3
3
  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
+ /** Union of all FDW wrapper-level change variants (`objectType: "foreign_data_wrapper"`). @category Change Types */
6
7
  export type ForeignDataWrapperChange = AlterForeignDataWrapper | CommentForeignDataWrapper | CreateForeignDataWrapper | DropForeignDataWrapper | ForeignDataWrapperPrivilege;
@@ -2,4 +2,5 @@ import type { ForeignDataWrapperChange as FDWChange } from "./foreign-data-wrapp
2
2
  import type { ForeignTableChange } from "./foreign-table/changes/foreign-table.types.ts";
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
+ /** Union of all foreign-data-wrapper-related change variants (`objectType: "foreign_data_wrapper" | "server" | "foreign_table" | "user_mapping"`). @category Change Types */
5
6
  export type ForeignDataWrapperChange = FDWChange | ServerChange | UserMappingChange | ForeignTableChange;
@@ -3,4 +3,5 @@ import type { CommentForeignTable } from "./foreign-table.comment.ts";
3
3
  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
+ /** Union of all foreign-table-related change variants (`objectType: "foreign_table"`). @category Change Types */
6
7
  export type ForeignTableChange = AlterForeignTable | CommentForeignTable | CreateForeignTable | DropForeignTable | ForeignTablePrivilege;
@@ -3,4 +3,5 @@ import type { CommentServer } from "./server.comment.ts";
3
3
  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
+ /** Union of all server-related change variants (`objectType: "server"`). @category Change Types */
6
7
  export type ServerChange = AlterServer | CommentServer | CreateServer | DropServer | ServerPrivilege;
@@ -1,4 +1,5 @@
1
1
  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
+ /** Union of all user-mapping-related change variants (`objectType: "user_mapping"`). @category Change Types */
4
5
  export type UserMappingChange = AlterUserMapping | CreateUserMapping | DropUserMapping;
@@ -2,4 +2,5 @@ import type { AlterIndex } from "./index.alter.ts";
2
2
  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
+ /** Union of all index-related change variants (`objectType: "index"`). @category Change Types */
5
6
  export type IndexChange = AlterIndex | CommentIndex | CreateIndex | DropIndex;
@@ -3,4 +3,5 @@ import type { CommentLanguage } from "./language.comment.ts";
3
3
  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
+ /** Union of all language-related change variants (`objectType: "language"`). @category Change Types */
6
7
  export type LanguageChange = AlterLanguage | CommentLanguage | CreateLanguage | DropLanguage | LanguagePrivilege;
@@ -3,4 +3,5 @@ import type { CommentMaterializedView } from "./materialized-view.comment.ts";
3
3
  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
+ /** Union of all materialized-view-related change variants (`objectType: "materialized_view"`). @category Change Types */
6
7
  export type MaterializedViewChange = AlterMaterializedView | CommentMaterializedView | CreateMaterializedView | DropMaterializedView | MaterializedViewPrivilege;
@@ -3,4 +3,5 @@ import type { CommentProcedure } from "./procedure.comment.ts";
3
3
  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
+ /** Union of all procedure-related change variants (`objectType: "procedure"`). @category Change Types */
6
7
  export type ProcedureChange = AlterProcedure | CommentProcedure | CreateProcedure | DropProcedure | ProcedurePrivilege;
@@ -2,4 +2,5 @@ import type { AlterPublicationAddSchemas, AlterPublicationAddTables, AlterPublic
2
2
  import type { CommentPublication } from "./publication.comment.ts";
3
3
  import type { CreatePublication } from "./publication.create.ts";
4
4
  import type { DropPublication } from "./publication.drop.ts";
5
+ /** Union of all publication-related change variants (`objectType: "publication"`). @category Change Types */
5
6
  export type PublicationChange = AlterPublicationAddSchemas | AlterPublicationAddTables | AlterPublicationDropSchemas | AlterPublicationDropTables | AlterPublicationSetList | AlterPublicationSetOptions | AlterPublicationSetOwner | CommentPublication | CreatePublication | DropPublication;
@@ -2,4 +2,5 @@ import type { AlterRlsPolicy } from "./rls-policy.alter.ts";
2
2
  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
+ /** Union of all RLS policy-related change variants (`objectType: "rls_policy"`). @category Change Types */
5
6
  export type RlsPolicyChange = AlterRlsPolicy | CommentRlsPolicy | CreateRlsPolicy | DropRlsPolicy;
@@ -3,4 +3,5 @@ import type { CommentRole } from "./role.comment.ts";
3
3
  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
+ /** Union of all role-related change variants (`objectType: "role"`). @category Change Types */
6
7
  export type RoleChange = AlterRole | CommentRole | CreateRole | DropRole | RolePrivilege;
@@ -2,4 +2,5 @@ import type { ReplaceRule, SetRuleEnabledState } from "./rule.alter.ts";
2
2
  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
+ /** Union of all rule-related change variants (`objectType: "rule"`). @category Change Types */
5
6
  export type RuleChange = CreateRule | DropRule | ReplaceRule | SetRuleEnabledState | CreateCommentOnRule | DropCommentOnRule;
@@ -3,4 +3,5 @@ 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
+ /** Union of all schema-related change variants (`objectType: "schema"`). @category Change Types */
6
7
  export type SchemaChange = AlterSchema | CommentSchema | CreateSchema | DropSchema | SchemaPrivilege;
@@ -3,4 +3,5 @@ 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
+ /** Union of all sequence-related change variants (`objectType: "sequence"`). @category Change Types */
6
7
  export type SequenceChange = AlterSequence | CommentSequence | CreateSequence | DropSequence | SequencePrivilege;
@@ -2,4 +2,5 @@ import type { AlterSubscriptionDisable, AlterSubscriptionEnable, AlterSubscripti
2
2
  import type { CommentSubscription } from "./subscription.comment.ts";
3
3
  import type { CreateSubscription } from "./subscription.create.ts";
4
4
  import type { DropSubscription } from "./subscription.drop.ts";
5
+ /** Union of all subscription-related change variants (`objectType: "subscription"`). @category Change Types */
5
6
  export type SubscriptionChange = CreateSubscription | DropSubscription | AlterSubscriptionSetConnection | AlterSubscriptionSetPublication | AlterSubscriptionEnable | AlterSubscriptionDisable | AlterSubscriptionSetOptions | AlterSubscriptionSetOwner | CommentSubscription;
@@ -3,4 +3,5 @@ import type { CommentTable } from "./table.comment.ts";
3
3
  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
+ /** Union of all table-related change variants (`objectType: "table"`). @category Change Types */
6
7
  export type TableChange = AlterTable | CommentTable | CreateTable | DropTable | TablePrivilege;
@@ -2,4 +2,5 @@ import type { AlterTrigger } from "./trigger.alter.ts";
2
2
  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
+ /** Union of all trigger-related change variants (`objectType: "trigger"`). @category Change Types */
5
6
  export type TriggerChange = AlterTrigger | CommentTrigger | CreateTrigger | DropTrigger;
@@ -3,4 +3,5 @@ import type { CommentCompositeType } from "./composite-type.comment.ts";
3
3
  import type { CreateCompositeType } from "./composite-type.create.ts";
4
4
  import type { DropCompositeType } from "./composite-type.drop.ts";
5
5
  import type { CompositeTypePrivilege } from "./composite-type.privilege.ts";
6
+ /** Union of all composite-type-related change variants (`objectType: "composite_type"`). @category Change Types */
6
7
  export type CompositeTypeChange = AlterCompositeType | CommentCompositeType | CreateCompositeType | DropCompositeType | CompositeTypePrivilege;
@@ -3,4 +3,5 @@ import type { CommentEnum } from "./enum.comment.ts";
3
3
  import type { CreateEnum } from "./enum.create.ts";
4
4
  import type { DropEnum } from "./enum.drop.ts";
5
5
  import type { EnumPrivilege } from "./enum.privilege.ts";
6
+ /** Union of all enum-related change variants (`objectType: "enum"`). @category Change Types */
6
7
  export type EnumChange = AlterEnum | CommentEnum | CreateEnum | DropEnum | EnumPrivilege;
@@ -3,4 +3,5 @@ import type { CommentRange } from "./range.comment.ts";
3
3
  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
+ /** Union of all range-related change variants (`objectType: "range"`). @category Change Types */
6
7
  export type RangeChange = AlterRange | CommentRange | CreateRange | DropRange | RangePrivilege;
@@ -1,4 +1,5 @@
1
1
  import type { CompositeTypeChange } from "./composite-type/changes/composite-type.types.ts";
2
2
  import type { EnumChange } from "./enum/changes/enum.types.ts";
3
3
  import type { RangeChange } from "./range/changes/range.types.ts";
4
+ /** Union of all type-related change variants (`objectType: "composite_type" | "enum" | "range"`). @category Change Types */
4
5
  export type TypeChange = CompositeTypeChange | EnumChange | RangeChange;
@@ -3,4 +3,5 @@ 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
+ /** Union of all view-related change variants (`objectType: "view"`). @category Change Types */
6
7
  export type ViewChange = AlterView | CommentView | CreateView | DropView | ViewPrivilege;
@@ -1,4 +1,5 @@
1
1
  import { diffObjects } from "../base.diff.js";
2
+ import { normalizeColumns } from "../base.model.js";
2
3
  import { diffPrivileges, emitColumnPrivilegeChanges, } from "../base.privilege-diff.js";
3
4
  import { deepEqual, hasNonAlterableChanges } from "../utils.js";
4
5
  import { AlterViewChangeOwner, AlterViewResetOptions, AlterViewSetOptions, } from "./changes/view.alter.js";
@@ -17,35 +18,37 @@ import { GrantViewPrivileges, RevokeGrantOptionViewPrivileges, RevokeViewPrivile
17
18
  export function diffViews(ctx, main, branch) {
18
19
  const { created, dropped, altered } = diffObjects(main, branch);
19
20
  const changes = [];
20
- for (const viewId of created) {
21
- const v = branch[viewId];
22
- changes.push(new CreateView({ view: v }));
21
+ const appendCreateViewChanges = (view) => {
22
+ changes.push(new CreateView({ view }));
23
23
  // OWNER: If the view should be owned by someone other than the current user,
24
24
  // emit ALTER VIEW ... OWNER TO after creation
25
- if (v.owner !== ctx.currentUser) {
26
- changes.push(new AlterViewChangeOwner({ view: v, owner: v.owner }));
25
+ if (view.owner !== ctx.currentUser) {
26
+ changes.push(new AlterViewChangeOwner({ view, owner: view.owner }));
27
27
  }
28
- if (v.comment !== null) {
29
- changes.push(new CreateCommentOnView({ view: v }));
28
+ if (view.comment !== null) {
29
+ changes.push(new CreateCommentOnView({ view }));
30
30
  }
31
31
  // PRIVILEGES: For created objects, compare against default privileges state
32
32
  // The migration script will run ALTER DEFAULT PRIVILEGES before CREATE (via constraint spec),
33
33
  // so objects are created with the default privileges state in effect.
34
34
  // We compare default privileges against desired privileges to generate REVOKE/GRANT statements
35
35
  // needed to reach the final desired state.
36
- const effectiveDefaults = ctx.defaultPrivilegeState.getEffectiveDefaults(ctx.currentUser, "view", v.schema ?? "");
37
- const creatorFilteredDefaults = v.owner !== ctx.currentUser
36
+ const effectiveDefaults = ctx.defaultPrivilegeState.getEffectiveDefaults(ctx.currentUser, "view", view.schema ?? "");
37
+ const creatorFilteredDefaults = view.owner !== ctx.currentUser
38
38
  ? effectiveDefaults.filter((p) => p.grantee !== ctx.currentUser)
39
39
  : effectiveDefaults;
40
- const desiredPrivileges = v.privileges;
40
+ const desiredPrivileges = view.privileges;
41
41
  // Filter out owner privileges - owner always has ALL privileges implicitly
42
42
  // and shouldn't be compared. Use the view owner as the reference.
43
- const privilegeResults = diffPrivileges(creatorFilteredDefaults, desiredPrivileges, v.owner);
44
- changes.push(...emitColumnPrivilegeChanges(privilegeResults, v, v, "view", {
43
+ const privilegeResults = diffPrivileges(creatorFilteredDefaults, desiredPrivileges, view.owner);
44
+ changes.push(...emitColumnPrivilegeChanges(privilegeResults, view, view, "view", {
45
45
  Grant: GrantViewPrivileges,
46
46
  Revoke: RevokeViewPrivileges,
47
47
  RevokeGrantOption: RevokeGrantOptionViewPrivileges,
48
48
  }, effectiveDefaults, ctx.version));
49
+ };
50
+ for (const viewId of created) {
51
+ appendCreateViewChanges(branch[viewId]);
49
52
  }
50
53
  for (const viewId of dropped) {
51
54
  changes.push(new DropView({ view: main[viewId] }));
@@ -69,7 +72,15 @@ export function diffViews(ctx, main, branch) {
69
72
  "partition_bound",
70
73
  ];
71
74
  const nonAlterablePropsChanged = hasNonAlterableChanges(mainView, branchView, NON_ALTERABLE_FIELDS, { options: deepEqual });
72
- if (nonAlterablePropsChanged) {
75
+ // Normalize columns (strip position, sort by name) to match stableSnapshot().
76
+ // Position-only differences are safe to ignore here because column order in a
77
+ // view is determined by its definition, which is already checked above via
78
+ // NON_ALTERABLE_FIELDS - a position change always implies a definition change.
79
+ if (!deepEqual(normalizeColumns(mainView.columns), normalizeColumns(branchView.columns))) {
80
+ changes.push(new DropView({ view: mainView }));
81
+ appendCreateViewChanges(branchView);
82
+ }
83
+ else if (nonAlterablePropsChanged) {
73
84
  // Replace the entire view using CREATE OR REPLACE to avoid drop when possible
74
85
  changes.push(new CreateView({ view: branchView, orReplace: true }));
75
86
  }
@@ -1,14 +1,14 @@
1
1
  /**
2
2
  * PostgreSQL connection configuration with custom type handlers.
3
3
  */
4
- import type { PoolClient, PoolConfig } from "pg";
4
+ import type { ClientBase, PoolClient, PoolConfig } from "pg";
5
5
  import { Pool } from "pg";
6
6
  /**
7
7
  * Options for creating a Pool with event listeners.
8
8
  */
9
9
  interface CreatePoolOptions extends Partial<PoolConfig> {
10
10
  /** Called when a new client connects to the pool */
11
- onConnect?: (client: PoolClient) => void | Promise<void>;
11
+ onConnect?: (client: ClientBase) => void | Promise<void>;
12
12
  /** Called when an idle client emits an error */
13
13
  onError?: (err: Error, client: PoolClient) => void;
14
14
  /** Called when a client is acquired from the pool */
@@ -1,4 +1,4 @@
1
- import { getSchema } from "../integrations/filter/extractors.js";
1
+ import { getSchema } from "../change-utils.js";
2
2
  import { GrantRoleDefaultPrivileges, RevokeRoleDefaultPrivileges, } from "../objects/role/changes/role.privilege.js";
3
3
  /**
4
4
  * Maps object type names to PostgreSQL default privilege objtype codes.
@@ -8,7 +8,7 @@
8
8
  * It groups related changes together while preserving the ability for the dependency
9
9
  * resolver to reorder within groups when necessary.
10
10
  */
11
- import { getSchema } from "../integrations/filter/extractors.js";
11
+ import { getSchema } from "../change-utils.js";
12
12
  import { getExecutionPhase, isMetadataStableId } from "./utils.js";
13
13
  /**
14
14
  * Object type ordering for logical grouping.
@@ -287,27 +287,6 @@ function getParentStableId(change) {
287
287
  // Fallback: return first requires if available
288
288
  return requires.length > 0 ? requires[0] : null;
289
289
  }
290
- /**
291
- * Extract schema name from a change.
292
- * Returns the schema name if present, or null for non-schema objects.
293
- *
294
- * Uses the getSchema helper which directly accesses schema properties from change objects.
295
- * For default_privilege changes, accesses the inSchema property directly.
296
- * For event_trigger changes, groups by their function's schema.
297
- */
298
- function extractSchemaFromChange(change) {
299
- // Handle default_privilege changes specially (they have inSchema property)
300
- if (change.scope === "default_privilege") {
301
- // TypeScript doesn't know about inSchema, but we know it exists for default_privilege changes
302
- return change.inSchema ?? null;
303
- }
304
- // Handle event_trigger changes specially - group by their function's schema
305
- if (change.objectType === "event_trigger") {
306
- return change.eventTrigger.function_schema;
307
- }
308
- // Use the getSchema helper for all other changes
309
- return getSchema(change);
310
- }
311
290
  /**
312
291
  * Get the effective object type for sorting purposes.
313
292
  * For sub-entities, returns the parent's object type (table/view/materialized_view).
@@ -399,8 +378,8 @@ function sortPhase(changes, phase) {
399
378
  const changeA = a.change;
400
379
  const changeB = b.change;
401
380
  // 1. Compare schemas (group objects by schema)
402
- const schemaA = extractSchemaFromChange(changeA);
403
- const schemaB = extractSchemaFromChange(changeB);
381
+ const schemaA = getSchema(changeA);
382
+ const schemaB = getSchema(changeB);
404
383
  // Non-schema objects (roles, languages, extensions, etc.) sort first
405
384
  // Use a special prefix to ensure they come before schema objects
406
385
  const schemaKeyA = schemaA === null ? "::" : schemaA;