@prisma-next/target-postgres 0.15.0 → 0.16.0-dev.2
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.
- package/dist/{authoring-BtsOWgI3.mjs → authoring-34L18kA1.mjs} +18 -8
- package/dist/authoring-34L18kA1.mjs.map +1 -0
- package/dist/canonicalize-D1F4vUnP.d.mts.map +1 -1
- package/dist/{codec-ids-CI144z7g.d.mts → codec-ids-BswpvvND.d.mts} +3 -3
- package/dist/codec-ids-BswpvvND.d.mts.map +1 -0
- package/dist/{codec-ids-B10ZZHzw.mjs → codec-ids-D3G8K0YM.mjs} +3 -2
- package/dist/codec-ids-D3G8K0YM.mjs.map +1 -0
- package/dist/codec-ids.d.mts +2 -2
- package/dist/codec-ids.mjs +2 -2
- package/dist/{codec-types-CTfT4U4O.d.mts → codec-types-CQ07nOz-.d.mts} +4 -5
- package/dist/codec-types-CQ07nOz-.d.mts.map +1 -0
- package/dist/codec-types.d.mts +1 -1
- package/dist/{codecs-D7W9O0Xx.d.mts → codecs-G4DTY0F_.d.mts} +35 -7
- package/dist/codecs-G4DTY0F_.d.mts.map +1 -0
- package/dist/{codecs-DRbb26Or.mjs → codecs-TCsGgW-Y.mjs} +77 -5
- package/dist/codecs-TCsGgW-Y.mjs.map +1 -0
- package/dist/codecs.d.mts +2 -3
- package/dist/codecs.d.mts.map +1 -1
- package/dist/codecs.mjs +2 -2
- package/dist/contract-free.d.mts +2 -3
- package/dist/contract-free.d.mts.map +1 -1
- package/dist/contract-free.mjs +3 -3
- package/dist/{control-policy-DtbkLLGv.mjs → control-policy-CZKdMztu.mjs} +44 -75
- package/dist/control-policy-CZKdMztu.mjs.map +1 -0
- package/dist/control.d.mts +0 -1
- package/dist/control.d.mts.map +1 -1
- package/dist/control.mjs +75 -25
- package/dist/control.mjs.map +1 -1
- package/dist/data-transform-BOWpliq8.mjs.map +1 -1
- package/dist/{data-transform-DPzwBMhW.d.mts → data-transform-CGvE8yGx.d.mts} +1 -2
- package/dist/data-transform-CGvE8yGx.d.mts.map +1 -0
- package/dist/data-transform.d.mts +1 -1
- package/dist/{ddl-GTTOvjx_.mjs → ddl-DHXKzQ99.mjs} +3 -3
- package/dist/{ddl-GTTOvjx_.mjs.map → ddl-DHXKzQ99.mjs.map} +1 -1
- package/dist/ddl.d.mts +1 -1
- package/dist/default-normalizer-B9ZUiyUE.mjs +264 -0
- package/dist/default-normalizer-B9ZUiyUE.mjs.map +1 -0
- package/dist/default-normalizer.d.mts +14 -2
- package/dist/default-normalizer.d.mts.map +1 -1
- package/dist/default-normalizer.mjs +2 -248
- package/dist/{descriptor-meta-CFQKLXl_.mjs → descriptor-meta-qubYaxQA.mjs} +9 -4
- package/dist/descriptor-meta-qubYaxQA.mjs.map +1 -0
- package/dist/{diff-database-schema-GncqMuSI.mjs → diff-database-schema-C-hnJ5mr.mjs} +92 -26
- package/dist/diff-database-schema-C-hnJ5mr.mjs.map +1 -0
- package/dist/diff-database-schema.d.mts +4 -13
- package/dist/diff-database-schema.d.mts.map +1 -1
- package/dist/diff-database-schema.mjs +1 -1
- package/dist/{errors-DO-w0EUS.mjs → errors-ByDS0xJL.mjs} +6 -6
- package/dist/errors-ByDS0xJL.mjs.map +1 -0
- package/dist/errors.d.mts +4 -4
- package/dist/errors.d.mts.map +1 -1
- package/dist/errors.mjs +1 -1
- package/dist/issue-planner.d.mts +1 -2
- package/dist/issue-planner.d.mts.map +1 -1
- package/dist/issue-planner.mjs +1 -1
- package/dist/migration.d.mts +3 -4
- package/dist/migration.d.mts.map +1 -1
- package/dist/migration.mjs +2 -2
- package/dist/native-type-normalizer.d.mts.map +1 -1
- package/dist/{nodes-Dv5eCSq9.d.mts → nodes-CQzM2hR0.d.mts} +1 -2
- package/dist/nodes-CQzM2hR0.d.mts.map +1 -0
- package/dist/{op-factory-call-Bn9zDx4_.d.mts → op-factory-call-DT7kdjVP.d.mts} +10 -7
- package/dist/op-factory-call-DT7kdjVP.d.mts.map +1 -0
- package/dist/{op-factory-call-C38NzvQD.mjs → op-factory-call-DuRj7WXX.mjs} +37 -16
- package/dist/{op-factory-call-C38NzvQD.mjs.map → op-factory-call-DuRj7WXX.mjs.map} +1 -1
- package/dist/op-factory-call.d.mts +2 -2
- package/dist/op-factory-call.mjs +2 -2
- package/dist/pack.d.mts +122 -6
- package/dist/pack.d.mts.map +1 -1
- package/dist/pack.mjs +1 -1
- package/dist/{planner-kql24i_F.mjs → planner-DPGxFcXo.mjs} +13 -13
- package/dist/planner-DPGxFcXo.mjs.map +1 -0
- package/dist/planner-ddl-builders.d.mts +1 -2
- package/dist/planner-ddl-builders.d.mts.map +1 -1
- package/dist/planner-identity-values.d.mts +0 -1
- package/dist/planner-identity-values.d.mts.map +1 -1
- package/dist/{planner-produced-postgres-migration-BEY1T0Xm.d.mts → planner-produced-postgres-migration-C-dwGdb2.d.mts} +2 -3
- package/dist/planner-produced-postgres-migration-C-dwGdb2.d.mts.map +1 -0
- package/dist/{planner-produced-postgres-migration-D7y-PEHK.mjs → planner-produced-postgres-migration-CFDpqWWE.mjs} +2 -2
- package/dist/planner-produced-postgres-migration-CFDpqWWE.mjs.map +1 -0
- package/dist/planner-produced-postgres-migration.d.mts +1 -1
- package/dist/planner-produced-postgres-migration.mjs +1 -1
- package/dist/planner-schema-lookup.d.mts +0 -1
- package/dist/planner-schema-lookup.d.mts.map +1 -1
- package/dist/{planner-sql-checks-zqNfs2XZ.mjs → planner-sql-checks-BuB877wH.mjs} +2 -2
- package/dist/{planner-sql-checks-zqNfs2XZ.mjs.map → planner-sql-checks-BuB877wH.mjs.map} +1 -1
- package/dist/planner-sql-checks.d.mts +0 -1
- package/dist/planner-sql-checks.d.mts.map +1 -1
- package/dist/planner-sql-checks.mjs +1 -1
- package/dist/planner-target-details-HkP4RrRO.d.mts.map +1 -1
- package/dist/planner.d.mts +3 -4
- package/dist/planner.d.mts.map +1 -1
- package/dist/planner.mjs +2 -2
- package/dist/{postgres-contract-view-C9j5cqP0.d.mts → postgres-contract-view-CeU7FJjW.d.mts} +4 -3
- package/dist/postgres-contract-view-CeU7FJjW.d.mts.map +1 -0
- package/dist/{postgres-contract-view-DM8sN1Ot.mjs → postgres-contract-view-DebHMqGR.mjs} +4 -4
- package/dist/{postgres-contract-view-DM8sN1Ot.mjs.map → postgres-contract-view-DebHMqGR.mjs.map} +1 -1
- package/dist/{postgres-database-schema-node-CJv5bfbs.d.mts → postgres-database-schema-node-DMXsIwAb.d.mts} +12 -4
- package/dist/postgres-database-schema-node-DMXsIwAb.d.mts.map +1 -0
- package/dist/{postgres-migration-arMSWU9b.mjs → postgres-migration-C_OPFhIF.mjs} +22 -6
- package/dist/postgres-migration-C_OPFhIF.mjs.map +1 -0
- package/dist/{postgres-migration-DbckK1su.d.mts → postgres-migration-DLIvzHjX.d.mts} +31 -7
- package/dist/postgres-migration-DLIvzHjX.d.mts.map +1 -0
- package/dist/{postgres-rls-policy--CSddvMR.d.mts → postgres-rls-policy-CYXdqG9B.d.mts} +1 -2
- package/dist/postgres-rls-policy-CYXdqG9B.d.mts.map +1 -0
- package/dist/{postgres-role-schema-node-Cm-j0ZGM.mjs → postgres-role-schema-node-bg32e7I-.mjs} +3 -2
- package/dist/postgres-role-schema-node-bg32e7I-.mjs.map +1 -0
- package/dist/{postgres-schema-Cm4DtiGA.mjs → postgres-schema-CewLYHB7.mjs} +2 -2
- package/dist/{postgres-schema-Cm4DtiGA.mjs.map → postgres-schema-CewLYHB7.mjs.map} +1 -1
- package/dist/{postgres-schema-DKq6s1P3.d.mts → postgres-schema-FdKRwe7X.d.mts} +3 -4
- package/dist/postgres-schema-FdKRwe7X.d.mts.map +1 -0
- package/dist/render-ops.d.mts +0 -1
- package/dist/render-ops.d.mts.map +1 -1
- package/dist/render-typescript.d.mts +0 -1
- package/dist/render-typescript.d.mts.map +1 -1
- package/dist/{resolve-ddl-schema-XyBaaenM.mjs → resolve-ddl-schema-D0wi_P9Q.mjs} +2 -2
- package/dist/{resolve-ddl-schema-XyBaaenM.mjs.map → resolve-ddl-schema-D0wi_P9Q.mjs.map} +1 -1
- package/dist/rls-canonicalize.d.mts +0 -1
- package/dist/rls-canonicalize.d.mts.map +1 -1
- package/dist/runtime.d.mts +1 -2
- package/dist/runtime.d.mts.map +1 -1
- package/dist/runtime.mjs +1 -1
- package/dist/schema-ir-annotations.d.mts +0 -1
- package/dist/schema-ir-annotations.d.mts.map +1 -1
- package/dist/schema-ir-annotations.mjs +1 -1
- package/dist/schema-node-kinds-DxvWh2Ic.d.mts +29 -0
- package/dist/schema-node-kinds-DxvWh2Ic.d.mts.map +1 -0
- package/dist/sql-utils.d.mts.map +1 -1
- package/dist/{table-source-BvFo7gVs.d.mts → table-source-D5c2fxAQ.d.mts} +1 -2
- package/dist/table-source-D5c2fxAQ.d.mts.map +1 -0
- package/dist/{types-BDKkx8MA.d.mts → types-D2MLzLBD.d.mts} +1 -2
- package/dist/types-D2MLzLBD.d.mts.map +1 -0
- package/dist/types.d.mts +6 -5
- package/dist/types.mjs +4 -4
- package/package.json +21 -21
- package/src/core/authoring.ts +18 -5
- package/src/core/codec-helpers.ts +53 -1
- package/src/core/codec-ids.ts +1 -0
- package/src/core/codecs.ts +56 -3
- package/src/core/default-normalizer.ts +22 -0
- package/src/core/descriptor-meta.ts +2 -0
- package/src/core/errors.ts +5 -5
- package/src/core/index-types.ts +15 -0
- package/src/core/migrations/contract-to-postgres-database-schema-node.ts +99 -19
- package/src/core/migrations/control-policy.ts +4 -3
- package/src/core/migrations/diff-database-schema.ts +6 -3
- package/src/core/migrations/issue-planner.ts +41 -80
- package/src/core/migrations/op-factory-call.ts +40 -16
- package/src/core/migrations/operations/data-transform.ts +1 -1
- package/src/core/migrations/planner-produced-postgres-migration.ts +1 -1
- package/src/core/migrations/planner-strategies.ts +6 -6
- package/src/core/migrations/planner.ts +5 -4
- package/src/core/migrations/postgres-migration.ts +62 -2
- package/src/core/migrations/runner.ts +12 -11
- package/src/core/migrations/verify-postgres-namespaces.ts +0 -1
- package/src/core/psl-infer/infer-psl-contract.ts +130 -12
- package/src/core/schema-ir/postgres-policy-schema-node.ts +12 -2
- package/src/exports/codecs.ts +2 -0
- package/src/exports/control.ts +2 -0
- package/src/exports/default-normalizer.ts +1 -1
- package/src/exports/op-factory-call.ts +5 -0
- package/src/exports/types.ts +1 -0
- package/dist/authoring-BtsOWgI3.mjs.map +0 -1
- package/dist/codec-ids-B10ZZHzw.mjs.map +0 -1
- package/dist/codec-ids-CI144z7g.d.mts.map +0 -1
- package/dist/codec-types-CTfT4U4O.d.mts.map +0 -1
- package/dist/codecs-D7W9O0Xx.d.mts.map +0 -1
- package/dist/codecs-DRbb26Or.mjs.map +0 -1
- package/dist/control-policy-DtbkLLGv.mjs.map +0 -1
- package/dist/data-transform-DPzwBMhW.d.mts.map +0 -1
- package/dist/default-normalizer.mjs.map +0 -1
- package/dist/descriptor-meta-CFQKLXl_.mjs.map +0 -1
- package/dist/diff-database-schema-GncqMuSI.mjs.map +0 -1
- package/dist/errors-DO-w0EUS.mjs.map +0 -1
- package/dist/nodes-Dv5eCSq9.d.mts.map +0 -1
- package/dist/op-factory-call-Bn9zDx4_.d.mts.map +0 -1
- package/dist/planner-kql24i_F.mjs.map +0 -1
- package/dist/planner-produced-postgres-migration-BEY1T0Xm.d.mts.map +0 -1
- package/dist/planner-produced-postgres-migration-D7y-PEHK.mjs.map +0 -1
- package/dist/postgres-contract-view-C9j5cqP0.d.mts.map +0 -1
- package/dist/postgres-database-schema-node-CJv5bfbs.d.mts.map +0 -1
- package/dist/postgres-migration-DbckK1su.d.mts.map +0 -1
- package/dist/postgres-migration-arMSWU9b.mjs.map +0 -1
- package/dist/postgres-rls-policy--CSddvMR.d.mts.map +0 -1
- package/dist/postgres-role-schema-node-Cm-j0ZGM.mjs.map +0 -1
- package/dist/postgres-schema-DKq6s1P3.d.mts.map +0 -1
- package/dist/table-source-BvFo7gVs.d.mts.map +0 -1
- package/dist/types-BDKkx8MA.d.mts.map +0 -1
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
import type { ContractToSchemaIROptions } from '@prisma-next/family-sql/control';
|
|
2
2
|
import { contractNamespaceToSchemaIR } from '@prisma-next/family-sql/control';
|
|
3
|
+
import type { SchemaNodeRef } from '@prisma-next/framework-components/control';
|
|
3
4
|
import { UNBOUND_NAMESPACE_ID } from '@prisma-next/framework-components/ir';
|
|
4
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
PrimaryKey,
|
|
7
|
+
RelationalSchemaNodeKind,
|
|
8
|
+
SqlForeignKeyIR,
|
|
9
|
+
SqlIndexIR,
|
|
10
|
+
SqlUniqueIR,
|
|
11
|
+
} from '@prisma-next/sql-schema-ir/types';
|
|
5
12
|
import { ifDefined } from '@prisma-next/utils/defined';
|
|
6
13
|
import type { PostgresRlsPolicy } from '../postgres-rls-policy';
|
|
7
14
|
import type { PostgresContract } from '../postgres-schema';
|
|
@@ -12,8 +19,43 @@ import { PostgresNativeEnumSchemaNode } from '../schema-ir/postgres-native-enum-
|
|
|
12
19
|
import { PostgresPolicySchemaNode } from '../schema-ir/postgres-policy-schema-node';
|
|
13
20
|
import { PostgresRoleSchemaNode } from '../schema-ir/postgres-role-schema-node';
|
|
14
21
|
import { PostgresTableSchemaNode } from '../schema-ir/postgres-table-schema-node';
|
|
22
|
+
import { PostgresSchemaNodeKind } from '../schema-ir/schema-node-kinds';
|
|
15
23
|
import { resolveDdlSchemaForNamespaceStorage } from './resolve-ddl-schema';
|
|
16
24
|
|
|
25
|
+
/** The database root's fixed sentinel id (`PostgresDatabaseSchemaNode#id`). */
|
|
26
|
+
function databaseStep(): { readonly nodeKind: string; readonly id: string } {
|
|
27
|
+
return { nodeKind: PostgresSchemaNodeKind.database, id: 'database' };
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function tableDependsOn(namespaceId: string, tableName: string): SchemaNodeRef {
|
|
31
|
+
return [
|
|
32
|
+
databaseStep(),
|
|
33
|
+
{ nodeKind: PostgresSchemaNodeKind.namespace, id: namespaceId },
|
|
34
|
+
{ nodeKind: PostgresSchemaNodeKind.table, id: tableName },
|
|
35
|
+
];
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function roleDependsOn(role: string): SchemaNodeRef {
|
|
39
|
+
return [databaseStep(), { nodeKind: PostgresSchemaNodeKind.role, id: role }];
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* The chains from a table-child object (foreign key, index, unique, primary
|
|
44
|
+
* key) to each of the own columns it is built on, in the Postgres tree.
|
|
45
|
+
* Dropping a covered column auto-drops the object, so the object's drop must
|
|
46
|
+
* precede the column's; the graph derives that direction from these edges.
|
|
47
|
+
*/
|
|
48
|
+
function columnDependsOn(
|
|
49
|
+
namespaceId: string,
|
|
50
|
+
tableName: string,
|
|
51
|
+
columns: readonly string[],
|
|
52
|
+
): readonly SchemaNodeRef[] {
|
|
53
|
+
return columns.map((column) => [
|
|
54
|
+
...tableDependsOn(namespaceId, tableName),
|
|
55
|
+
{ nodeKind: RelationalSchemaNodeKind.column, id: `column:${column}` },
|
|
56
|
+
]);
|
|
57
|
+
}
|
|
58
|
+
|
|
17
59
|
function toPolicyNode(policy: PostgresRlsPolicy, namespaceId: string): PostgresPolicySchemaNode {
|
|
18
60
|
return new PostgresPolicySchemaNode({
|
|
19
61
|
name: policy.name,
|
|
@@ -25,6 +67,7 @@ function toPolicyNode(policy: PostgresRlsPolicy, namespaceId: string): PostgresP
|
|
|
25
67
|
...ifDefined('using', policy.using),
|
|
26
68
|
...ifDefined('withCheck', policy.withCheck),
|
|
27
69
|
permissive: policy.permissive,
|
|
70
|
+
dependsOn: [tableDependsOn(namespaceId, policy.tableName), ...policy.roles.map(roleDependsOn)],
|
|
28
71
|
});
|
|
29
72
|
}
|
|
30
73
|
|
|
@@ -115,30 +158,67 @@ export function contractToPostgresDatabaseSchemaNode(
|
|
|
115
158
|
// clauses, and resolves the real live DDL schema — introspected FKs
|
|
116
159
|
// already carry the live schema, so this is what lets an expected FK
|
|
117
160
|
// pair (by diff-node id) with its introspected counterpart.
|
|
118
|
-
const foreignKeys = sqlTable.foreignKeys.map(
|
|
119
|
-
(
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
161
|
+
const foreignKeys = sqlTable.foreignKeys.map((fk) => {
|
|
162
|
+
const resolvedReferencedNamespace = resolveDdlSchemaForNamespaceStorage(
|
|
163
|
+
contract.storage,
|
|
164
|
+
fk.referencedSchema ?? UNBOUND_NAMESPACE_ID,
|
|
165
|
+
);
|
|
166
|
+
return new SqlForeignKeyIR({
|
|
167
|
+
columns: fk.columns,
|
|
168
|
+
referencedTable: fk.referencedTable,
|
|
169
|
+
referencedColumns: fk.referencedColumns,
|
|
170
|
+
referencedSchema: fk.referencedSchema ?? UNBOUND_NAMESPACE_ID,
|
|
171
|
+
...ifDefined('name', fk.name),
|
|
172
|
+
...ifDefined('onDelete', fk.onDelete),
|
|
173
|
+
...ifDefined('onUpdate', fk.onUpdate),
|
|
174
|
+
...ifDefined('annotations', fk.annotations),
|
|
175
|
+
resolvedReferencedNamespace,
|
|
176
|
+
dependsOn: [
|
|
177
|
+
tableDependsOn(resolvedReferencedNamespace, fk.referencedTable),
|
|
178
|
+
...columnDependsOn(ddlSchema, tableName, fk.columns),
|
|
179
|
+
],
|
|
180
|
+
});
|
|
181
|
+
});
|
|
182
|
+
// The family stamped these children's own-column `dependsOn` with the
|
|
183
|
+
// flat (single-schema) chain; the Postgres tree nests them under a
|
|
184
|
+
// namespace, so re-stamp with the multi-schema chain that matches this
|
|
185
|
+
// tree's paths. Every other field is carried through unchanged.
|
|
186
|
+
const uniques = sqlTable.uniques.map(
|
|
187
|
+
(u) =>
|
|
188
|
+
new SqlUniqueIR({
|
|
189
|
+
columns: u.columns,
|
|
190
|
+
...ifDefined('name', u.name),
|
|
191
|
+
...ifDefined('annotations', u.annotations),
|
|
192
|
+
dependsOn: columnDependsOn(ddlSchema, tableName, u.columns),
|
|
193
|
+
}),
|
|
194
|
+
);
|
|
195
|
+
const indexes = sqlTable.indexes.map(
|
|
196
|
+
(i) =>
|
|
197
|
+
new SqlIndexIR({
|
|
198
|
+
columns: i.columns,
|
|
199
|
+
unique: i.unique,
|
|
200
|
+
...ifDefined('name', i.name),
|
|
201
|
+
...ifDefined('type', i.type),
|
|
202
|
+
...ifDefined('options', i.options),
|
|
203
|
+
...ifDefined('annotations', i.annotations),
|
|
204
|
+
dependsOn: columnDependsOn(ddlSchema, tableName, i.columns),
|
|
133
205
|
}),
|
|
134
206
|
);
|
|
207
|
+
const primaryKey =
|
|
208
|
+
sqlTable.primaryKey !== undefined
|
|
209
|
+
? new PrimaryKey({
|
|
210
|
+
columns: sqlTable.primaryKey.columns,
|
|
211
|
+
...ifDefined('name', sqlTable.primaryKey.name),
|
|
212
|
+
dependsOn: columnDependsOn(ddlSchema, tableName, sqlTable.primaryKey.columns),
|
|
213
|
+
})
|
|
214
|
+
: undefined;
|
|
135
215
|
tables[tableName] = new PostgresTableSchemaNode({
|
|
136
216
|
name: sqlTable.name,
|
|
137
217
|
columns: sqlTable.columns,
|
|
138
218
|
foreignKeys,
|
|
139
|
-
uniques
|
|
140
|
-
indexes
|
|
141
|
-
...ifDefined('primaryKey',
|
|
219
|
+
uniques,
|
|
220
|
+
indexes,
|
|
221
|
+
...ifDefined('primaryKey', primaryKey),
|
|
142
222
|
...ifDefined('annotations', sqlTable.annotations),
|
|
143
223
|
...ifDefined('checks', sqlTable.checks),
|
|
144
224
|
policies: policiesByTable.get(tableName) ?? [],
|
|
@@ -5,6 +5,7 @@ import type {
|
|
|
5
5
|
SuppressionRecord,
|
|
6
6
|
} from '@prisma-next/family-sql/control';
|
|
7
7
|
import type { SchemaDiffIssue } from '@prisma-next/framework-components/control';
|
|
8
|
+
import { issueOutcome } from '@prisma-next/framework-components/control';
|
|
8
9
|
import { entityAt, UNBOUND_NAMESPACE_ID } from '@prisma-next/framework-components/ir';
|
|
9
10
|
import type { SqlStorage, StorageTable } from '@prisma-next/sql-contract/types';
|
|
10
11
|
import { blindCast } from '@prisma-next/utils/casts';
|
|
@@ -252,7 +253,7 @@ const POSTGRES_NODE_CREATION_FACTORY: Readonly<Record<string, string>> = Object.
|
|
|
252
253
|
* it is not admitted as creation-class here.
|
|
253
254
|
*/
|
|
254
255
|
function isEnablementCreationIssue(issue: SchemaDiffIssue<SqlSchemaDiffNode>): boolean {
|
|
255
|
-
if (issue
|
|
256
|
+
if (issueOutcome(issue) !== 'not-equal') return false;
|
|
256
257
|
const { expected, actual } = issue;
|
|
257
258
|
return (
|
|
258
259
|
expected !== undefined &&
|
|
@@ -270,7 +271,7 @@ export function resolvePostgresNodeIssueCreationFactoryName(
|
|
|
270
271
|
if (isEnablementCreationIssue(issue)) {
|
|
271
272
|
return 'enableRowLevelSecurity';
|
|
272
273
|
}
|
|
273
|
-
if (issue
|
|
274
|
+
if (issueOutcome(issue) !== 'not-found') return undefined;
|
|
274
275
|
const node = issue.expected ?? issue.actual;
|
|
275
276
|
if (node === undefined) return undefined;
|
|
276
277
|
return POSTGRES_NODE_CREATION_FACTORY[node.nodeKind];
|
|
@@ -298,7 +299,7 @@ export function resolvePostgresNodeIssueControlPolicySubject(
|
|
|
298
299
|
>(node);
|
|
299
300
|
return {
|
|
300
301
|
namespaceId: resolveNamespaceIdForDdlSchema(contract, namespaceNode.schemaName),
|
|
301
|
-
createsNewObject: issue
|
|
302
|
+
createsNewObject: issueOutcome(issue) === 'not-found',
|
|
302
303
|
};
|
|
303
304
|
}
|
|
304
305
|
|
|
@@ -4,12 +4,13 @@ import { buildNativeTypeExpander } from '@prisma-next/family-sql/control';
|
|
|
4
4
|
import { classifyDiffSubjectGranularity } from '@prisma-next/family-sql/diff';
|
|
5
5
|
import type { TargetBoundComponentDescriptor } from '@prisma-next/framework-components/components';
|
|
6
6
|
import type { DiffableNode, SchemaDiffIssue } from '@prisma-next/framework-components/control';
|
|
7
|
-
import { diffSchemas } from '@prisma-next/framework-components/control';
|
|
7
|
+
import { diffSchemas, issueOutcome } from '@prisma-next/framework-components/control';
|
|
8
8
|
import { UNBOUND_NAMESPACE_ID } from '@prisma-next/framework-components/ir';
|
|
9
9
|
import type { SqlStorage } from '@prisma-next/sql-contract/types';
|
|
10
10
|
import type { SqlSchemaIRNode } from '@prisma-next/sql-schema-ir/types';
|
|
11
11
|
import { blindCast } from '@prisma-next/utils/casts';
|
|
12
12
|
import { ifDefined } from '@prisma-next/utils/defined';
|
|
13
|
+
import { postgresResolveDefault } from '../default-normalizer';
|
|
13
14
|
import type { PostgresContract } from '../postgres-schema';
|
|
14
15
|
import { PostgresDatabaseSchemaNode } from '../schema-ir/postgres-database-schema-node';
|
|
15
16
|
import { PostgresNamespaceSchemaNode } from '../schema-ir/postgres-namespace-schema-node';
|
|
@@ -135,12 +136,13 @@ export function diffPostgresSchema(input: {
|
|
|
135
136
|
const fullExpected = contractToPostgresDatabaseSchemaNode(postgresContract, {
|
|
136
137
|
annotationNamespace: 'pg',
|
|
137
138
|
...ifDefined('expandNativeType', expandNativeType),
|
|
139
|
+
resolveDefault: postgresResolveDefault,
|
|
138
140
|
});
|
|
139
141
|
const expected = pruneTableLessNamespaces(fullExpected);
|
|
140
142
|
const relationalOwned = ownedSchemaNames(expected);
|
|
141
143
|
const structuralOwned = ownedSchemaNames(fullExpected);
|
|
142
144
|
const issues = diffSchemas(expected, actual).filter((issue) => {
|
|
143
|
-
if (issue
|
|
145
|
+
if (issueOutcome(issue) !== 'not-expected') return true;
|
|
144
146
|
if (isClusterScopedIssue(issue)) return true;
|
|
145
147
|
const granularity = classifyDiffSubjectGranularity(issue, postgresDiffSubjectGranularity);
|
|
146
148
|
const namespaceSegment = issue.path[1];
|
|
@@ -230,6 +232,7 @@ export function buildPostgresPlanDiff(input: {
|
|
|
230
232
|
const projectionOptions = {
|
|
231
233
|
annotationNamespace: 'pg',
|
|
232
234
|
...ifDefined('expandNativeType', expandNativeType),
|
|
235
|
+
resolveDefault: postgresResolveDefault,
|
|
233
236
|
};
|
|
234
237
|
const fullExpected = contractToPostgresDatabaseSchemaNode(postgresContract, projectionOptions);
|
|
235
238
|
const expected = pruneTableLessNamespaces(fullExpected);
|
|
@@ -240,7 +243,7 @@ export function buildPostgresPlanDiff(input: {
|
|
|
240
243
|
readonly SchemaDiffIssue<SqlSchemaDiffNode>[],
|
|
241
244
|
'both trees are PostgresDatabaseSchemaNodes, so every diff-issue node is a SqlSchemaDiffNode'
|
|
242
245
|
>(diffSchemas(expected, paddedActual)).filter((issue) => {
|
|
243
|
-
if (issue
|
|
246
|
+
if (issueOutcome(issue) !== 'not-expected') return true;
|
|
244
247
|
if (isClusterScopedIssue(issue)) return true;
|
|
245
248
|
const granularity = classifyDiffSubjectGranularity(issue, postgresDiffSubjectGranularity);
|
|
246
249
|
const namespaceSegment = issue.path[1];
|
|
@@ -25,6 +25,7 @@ import type {
|
|
|
25
25
|
} from '@prisma-next/family-sql/control';
|
|
26
26
|
import type { TargetBoundComponentDescriptor } from '@prisma-next/framework-components/components';
|
|
27
27
|
import type { DiffableNode, SchemaDiffIssue } from '@prisma-next/framework-components/control';
|
|
28
|
+
import { issueOutcome, orderIssuesByDependencies } from '@prisma-next/framework-components/control';
|
|
28
29
|
import { UNBOUND_NAMESPACE_ID } from '@prisma-next/framework-components/ir';
|
|
29
30
|
import type { SqlStorage, StorageTypeInstance } from '@prisma-next/sql-contract/types';
|
|
30
31
|
import type { DdlTableConstraint } from '@prisma-next/sql-relational-core/ast';
|
|
@@ -136,6 +137,7 @@ export interface IssuePlannerValue {
|
|
|
136
137
|
type CallCategory =
|
|
137
138
|
| 'dep'
|
|
138
139
|
| 'drop'
|
|
140
|
+
| 'dropType'
|
|
139
141
|
| 'table'
|
|
140
142
|
| 'rlsEnable'
|
|
141
143
|
| 'rlsPolicy'
|
|
@@ -151,6 +153,13 @@ type CallCategory =
|
|
|
151
153
|
* legacy walk-schema planner's emission order so `db init` and `db update`
|
|
152
154
|
* produce byte-identical plans for the shared shape (deps → drops → tables
|
|
153
155
|
* → columns → alters → PKs → uniques → indexes → FKs).
|
|
156
|
+
*
|
|
157
|
+
* `dropType` (DROP TYPE for a managed native enum) is its own bucket, ordered
|
|
158
|
+
* after the general drop bucket: a type can only be dropped once every table
|
|
159
|
+
* whose column uses it is gone. A column→enum edge would make this precise,
|
|
160
|
+
* but `coalesceSubtreeIssues` removes the column issue under a whole-table
|
|
161
|
+
* drop, so the edge never reaches the graph; the coarse bucket stands in until
|
|
162
|
+
* that edge lands (the coordinate work is a later slice).
|
|
154
163
|
*/
|
|
155
164
|
function classifyCall(call: PostgresOpFactoryCall): CallCategory {
|
|
156
165
|
switch (call.factoryName) {
|
|
@@ -159,8 +168,9 @@ function classifyCall(call: PostgresOpFactoryCall): CallCategory {
|
|
|
159
168
|
case 'createNativeEnumType':
|
|
160
169
|
case 'addNativeEnumValue':
|
|
161
170
|
return 'dep';
|
|
162
|
-
case 'dropTable':
|
|
163
171
|
case 'dropNativeEnumType':
|
|
172
|
+
return 'dropType';
|
|
173
|
+
case 'dropTable':
|
|
164
174
|
case 'dropColumn':
|
|
165
175
|
case 'dropConstraint':
|
|
166
176
|
case 'dropCheckConstraint':
|
|
@@ -369,57 +379,6 @@ export function columnTypeChanged(expected: SqlColumnIR, actual: SqlColumnIR): b
|
|
|
369
379
|
);
|
|
370
380
|
}
|
|
371
381
|
|
|
372
|
-
// ----------------------------------------------------------------------------
|
|
373
|
-
// Node-keyed issue ordering (re-keys ISSUE_KIND_ORDER on nodeKind + reason)
|
|
374
|
-
// ----------------------------------------------------------------------------
|
|
375
|
-
|
|
376
|
-
/**
|
|
377
|
-
* Re-keys the legacy `ISSUE_KIND_ORDER` on `(nodeKind, reason)`, numbers
|
|
378
|
-
* preserved so the dependency intent stays legible. Final emission order is
|
|
379
|
-
* fixed downstream by `classifyCall` bucketing (dep → drop → table → column →
|
|
380
|
-
* recipe → alter → primaryKey → unique → index → foreignKey), so this only
|
|
381
|
-
* breaks ties within a bucket.
|
|
382
|
-
*/
|
|
383
|
-
export function nodeIssueOrder(issue: SchemaDiffIssue): number {
|
|
384
|
-
const node = issueNode(issue);
|
|
385
|
-
if (node === undefined) return 99;
|
|
386
|
-
switch (node.nodeKind) {
|
|
387
|
-
case PostgresSchemaNodeKind.namespace:
|
|
388
|
-
return 1;
|
|
389
|
-
case PostgresSchemaNodeKind.nativeEnum:
|
|
390
|
-
// Creates order right after namespace creates within the 'dep' bucket
|
|
391
|
-
// (CREATE SCHEMA before CREATE TYPE); drops order after table drops
|
|
392
|
-
// within the 'drop' bucket (DROP TYPE only after its dependents left).
|
|
393
|
-
return issue.reason === 'not-expected' ? 17 : 2;
|
|
394
|
-
case RelationalSchemaNodeKind.foreignKey:
|
|
395
|
-
return issue.reason === 'not-expected' ? 10 : 60;
|
|
396
|
-
case RelationalSchemaNodeKind.unique:
|
|
397
|
-
return issue.reason === 'not-expected' ? 11 : 51;
|
|
398
|
-
case RelationalSchemaNodeKind.primaryKey:
|
|
399
|
-
return issue.reason === 'not-expected' ? 12 : 50;
|
|
400
|
-
case RelationalSchemaNodeKind.index:
|
|
401
|
-
return issue.reason === 'not-expected' ? 13 : 52;
|
|
402
|
-
case RelationalSchemaNodeKind.columnDefault:
|
|
403
|
-
if (issue.reason === 'not-expected') return 14;
|
|
404
|
-
return issue.reason === 'not-found' ? 42 : 43;
|
|
405
|
-
case RelationalSchemaNodeKind.column:
|
|
406
|
-
if (issue.reason === 'not-expected') return 15;
|
|
407
|
-
return issue.reason === 'not-found' ? 30 : 40;
|
|
408
|
-
case PostgresSchemaNodeKind.table:
|
|
409
|
-
return issue.reason === 'not-expected' ? 16 : 20;
|
|
410
|
-
case RelationalSchemaNodeKind.check:
|
|
411
|
-
if (issue.reason === 'not-found') return 53;
|
|
412
|
-
return issue.reason === 'not-expected' ? 55 : 54;
|
|
413
|
-
default:
|
|
414
|
-
return 99;
|
|
415
|
-
}
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
/** Deterministic tiebreak within an order bucket: the diff path already encodes schema → table → child. */
|
|
419
|
-
export function nodeIssueKey(issue: SchemaDiffIssue): string {
|
|
420
|
-
return issue.path.join(' ');
|
|
421
|
-
}
|
|
422
|
-
|
|
423
382
|
// ----------------------------------------------------------------------------
|
|
424
383
|
// Subtree coalescing (the planner's responsibility per the differ's contract)
|
|
425
384
|
// ----------------------------------------------------------------------------
|
|
@@ -437,7 +396,7 @@ export function coalesceSubtreeIssues<TNode extends DiffableNode = DiffableNode>
|
|
|
437
396
|
issues: readonly SchemaDiffIssue<TNode>[],
|
|
438
397
|
): readonly SchemaDiffIssue<TNode>[] {
|
|
439
398
|
const collapsingPaths = issues
|
|
440
|
-
.filter((issue) => issue
|
|
399
|
+
.filter((issue) => issueOutcome(issue) !== 'not-equal')
|
|
441
400
|
.map((issue) => issue.path);
|
|
442
401
|
if (collapsingPaths.length === 0) return issues;
|
|
443
402
|
return issues.filter(
|
|
@@ -601,14 +560,14 @@ function mapNativeEnumNodeIssue(
|
|
|
601
560
|
);
|
|
602
561
|
}
|
|
603
562
|
const schemaName = emissionSchemaName(ctx, ddlSchemaName);
|
|
604
|
-
if (issue
|
|
563
|
+
if (issueOutcome(issue) === 'not-found') {
|
|
605
564
|
const expected = blindCast<
|
|
606
565
|
PostgresNativeEnumSchemaNode,
|
|
607
566
|
'a not-found native-enum issue always carries the expected PostgresNativeEnumSchemaNode'
|
|
608
567
|
>(issue.expected);
|
|
609
568
|
return ok([new CreateNativeEnumTypeCall(schemaName, expected.typeName, expected.members)]);
|
|
610
569
|
}
|
|
611
|
-
if (issue
|
|
570
|
+
if (issueOutcome(issue) === 'not-expected') {
|
|
612
571
|
const actual = blindCast<
|
|
613
572
|
PostgresNativeEnumSchemaNode,
|
|
614
573
|
'a not-expected native-enum issue always carries the actual PostgresNativeEnumSchemaNode'
|
|
@@ -654,14 +613,14 @@ function mapTableNodeIssue(
|
|
|
654
613
|
ddlSchemaName: string,
|
|
655
614
|
codecHooks: ReadonlyMap<string, CodecControlHooks>,
|
|
656
615
|
): Result<readonly PostgresOpFactoryCall[], SqlPlannerConflict> {
|
|
657
|
-
if (issue
|
|
616
|
+
if (issueOutcome(issue) === 'not-found') {
|
|
658
617
|
const table = blindCast<
|
|
659
618
|
PostgresTableSchemaNode,
|
|
660
619
|
'a not-found table issue always carries the expected PostgresTableSchemaNode'
|
|
661
620
|
>(issue.expected);
|
|
662
621
|
return ok(buildCreateTableCallsFromNode(schemaName, ddlSchemaName, table, codecHooks));
|
|
663
622
|
}
|
|
664
|
-
if (issue
|
|
623
|
+
if (issueOutcome(issue) === 'not-expected') {
|
|
665
624
|
const table = blindCast<
|
|
666
625
|
PostgresTableSchemaNode,
|
|
667
626
|
'a not-expected table issue always carries the actual PostgresTableSchemaNode'
|
|
@@ -703,7 +662,7 @@ function mapColumnNodeIssue(
|
|
|
703
662
|
tableName: string,
|
|
704
663
|
codecHooks: ReadonlyMap<string, CodecControlHooks>,
|
|
705
664
|
): Result<readonly PostgresOpFactoryCall[], SqlPlannerConflict> {
|
|
706
|
-
if (issue
|
|
665
|
+
if (issueOutcome(issue) === 'not-found') {
|
|
707
666
|
const column = blindCast<
|
|
708
667
|
SqlColumnIR,
|
|
709
668
|
'a not-found column issue always carries the expected column node'
|
|
@@ -712,7 +671,7 @@ function mapColumnNodeIssue(
|
|
|
712
671
|
new AddColumnCall(schemaName, tableName, renderColumnDdl(column.name, column, codecHooks)),
|
|
713
672
|
]);
|
|
714
673
|
}
|
|
715
|
-
if (issue
|
|
674
|
+
if (issueOutcome(issue) === 'not-expected') {
|
|
716
675
|
const column = blindCast<
|
|
717
676
|
SqlColumnIR,
|
|
718
677
|
'a not-expected column issue always carries the actual column node'
|
|
@@ -755,7 +714,7 @@ function mapColumnDefaultNodeIssue(
|
|
|
755
714
|
tableName: string,
|
|
756
715
|
columnName: string,
|
|
757
716
|
): Result<readonly PostgresOpFactoryCall[], SqlPlannerConflict> {
|
|
758
|
-
if (issue
|
|
717
|
+
if (issueOutcome(issue) === 'not-expected') {
|
|
759
718
|
return ok([new DropDefaultCall(schemaName, tableName, columnName)]);
|
|
760
719
|
}
|
|
761
720
|
// not-found (SET DEFAULT, additive) or not-equal (SET DEFAULT, widening).
|
|
@@ -772,7 +731,7 @@ function mapColumnDefaultNodeIssue(
|
|
|
772
731
|
tableName,
|
|
773
732
|
columnName,
|
|
774
733
|
defaultSql,
|
|
775
|
-
issue
|
|
734
|
+
issueOutcome(issue) === 'not-equal' ? 'widening' : 'additive',
|
|
776
735
|
),
|
|
777
736
|
]);
|
|
778
737
|
}
|
|
@@ -782,7 +741,7 @@ function mapPrimaryKeyNodeIssue(
|
|
|
782
741
|
schemaName: string,
|
|
783
742
|
tableName: string,
|
|
784
743
|
): Result<readonly PostgresOpFactoryCall[], SqlPlannerConflict> {
|
|
785
|
-
if (issue
|
|
744
|
+
if (issueOutcome(issue) === 'not-found') {
|
|
786
745
|
const pk = blindCast<
|
|
787
746
|
{ readonly columns: readonly string[]; readonly name?: string },
|
|
788
747
|
'a not-found primary-key issue always carries the expected PrimaryKey node'
|
|
@@ -790,7 +749,7 @@ function mapPrimaryKeyNodeIssue(
|
|
|
790
749
|
const constraintName = pk.name ?? `${tableName}_pkey`;
|
|
791
750
|
return ok([new AddPrimaryKeyCall(schemaName, tableName, constraintName, [...pk.columns])]);
|
|
792
751
|
}
|
|
793
|
-
if (issue
|
|
752
|
+
if (issueOutcome(issue) === 'not-expected') {
|
|
794
753
|
const pk = blindCast<
|
|
795
754
|
{ readonly name?: string },
|
|
796
755
|
'a not-expected primary-key issue always carries the actual PrimaryKey node'
|
|
@@ -807,14 +766,14 @@ function mapForeignKeyNodeIssue(
|
|
|
807
766
|
schemaName: string,
|
|
808
767
|
tableName: string,
|
|
809
768
|
): Result<readonly PostgresOpFactoryCall[], SqlPlannerConflict> {
|
|
810
|
-
if (issue
|
|
769
|
+
if (issueOutcome(issue) === 'not-found') {
|
|
811
770
|
const fk = blindCast<
|
|
812
771
|
SqlForeignKeyIR,
|
|
813
772
|
'a not-found foreign-key issue always carries the expected foreign-key node'
|
|
814
773
|
>(issue.expected);
|
|
815
774
|
return ok([new AddForeignKeyCall(schemaName, tableName, fkSpecFromNode(fk, tableName))]);
|
|
816
775
|
}
|
|
817
|
-
if (issue
|
|
776
|
+
if (issueOutcome(issue) === 'not-expected') {
|
|
818
777
|
const fk = blindCast<
|
|
819
778
|
SqlForeignKeyIR,
|
|
820
779
|
'a not-expected foreign-key issue always carries the actual foreign-key node'
|
|
@@ -830,7 +789,7 @@ function mapUniqueNodeIssue(
|
|
|
830
789
|
schemaName: string,
|
|
831
790
|
tableName: string,
|
|
832
791
|
): Result<readonly PostgresOpFactoryCall[], SqlPlannerConflict> {
|
|
833
|
-
if (issue
|
|
792
|
+
if (issueOutcome(issue) === 'not-found') {
|
|
834
793
|
const unique = blindCast<
|
|
835
794
|
SqlUniqueIR,
|
|
836
795
|
'a not-found unique issue always carries the expected unique node'
|
|
@@ -838,7 +797,7 @@ function mapUniqueNodeIssue(
|
|
|
838
797
|
const name = unique.name ?? `${tableName}_${unique.columns.join('_')}_key`;
|
|
839
798
|
return ok([new AddUniqueCall(schemaName, tableName, name, [...unique.columns])]);
|
|
840
799
|
}
|
|
841
|
-
if (issue
|
|
800
|
+
if (issueOutcome(issue) === 'not-expected') {
|
|
842
801
|
const unique = blindCast<
|
|
843
802
|
SqlUniqueIR,
|
|
844
803
|
'a not-expected unique issue always carries the actual unique node'
|
|
@@ -854,7 +813,7 @@ function mapIndexNodeIssue(
|
|
|
854
813
|
schemaName: string,
|
|
855
814
|
tableName: string,
|
|
856
815
|
): Result<readonly PostgresOpFactoryCall[], SqlPlannerConflict> {
|
|
857
|
-
if (issue
|
|
816
|
+
if (issueOutcome(issue) === 'not-found') {
|
|
858
817
|
const index = blindCast<
|
|
859
818
|
SqlIndexIR,
|
|
860
819
|
'a not-found index issue always carries the expected index node'
|
|
@@ -865,7 +824,7 @@ function mapIndexNodeIssue(
|
|
|
865
824
|
if (index.options !== undefined) extras.options = index.options;
|
|
866
825
|
return ok([new CreateIndexCall(schemaName, tableName, indexName, [...index.columns], extras)]);
|
|
867
826
|
}
|
|
868
|
-
if (issue
|
|
827
|
+
if (issueOutcome(issue) === 'not-expected') {
|
|
869
828
|
const index = blindCast<
|
|
870
829
|
SqlIndexIR,
|
|
871
830
|
'a not-expected index issue always carries the actual index node'
|
|
@@ -885,7 +844,7 @@ function mapCheckNodeIssue(
|
|
|
885
844
|
// the default mapper handles directly; check_missing / check_mismatch are
|
|
886
845
|
// consumed by `checkConstraintPlanCallStrategy` (drop+recreate), so reaching
|
|
887
846
|
// here for them means the strategy did not run — a conflict.
|
|
888
|
-
if (issue
|
|
847
|
+
if (issueOutcome(issue) === 'not-expected') {
|
|
889
848
|
const check = blindCast<
|
|
890
849
|
{ readonly name: string },
|
|
891
850
|
'a not-expected check issue always carries the actual check node'
|
|
@@ -902,8 +861,8 @@ function mapCheckNodeIssue(
|
|
|
902
861
|
|
|
903
862
|
/**
|
|
904
863
|
* Maps one node-typed diff issue to its migration call(s), dispatching on the
|
|
905
|
-
* node's `nodeKind`
|
|
906
|
-
* from `codecRef` via `column-ddl-rendering.ts`.
|
|
864
|
+
* node's `nodeKind` and the issue's presence-derived `issueOutcome`, reading
|
|
865
|
+
* nodes and resolving column DDL from `codecRef` via `column-ddl-rendering.ts`.
|
|
907
866
|
*/
|
|
908
867
|
export function mapNodeIssueToCall(
|
|
909
868
|
issue: SchemaDiffIssue,
|
|
@@ -919,7 +878,7 @@ export function mapNodeIssueToCall(
|
|
|
919
878
|
);
|
|
920
879
|
}
|
|
921
880
|
if (node.nodeKind === PostgresSchemaNodeKind.namespace) {
|
|
922
|
-
if (issue
|
|
881
|
+
if (issueOutcome(issue) !== 'not-found') {
|
|
923
882
|
return notOk(
|
|
924
883
|
nodeConflict('unsupportedOperation', `Unexpected namespace drift: ${issue.path.join('/')}`),
|
|
925
884
|
);
|
|
@@ -1052,13 +1011,12 @@ export function planIssues(
|
|
|
1052
1011
|
}
|
|
1053
1012
|
}
|
|
1054
1013
|
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
});
|
|
1014
|
+
// Dependency-graph order: a topological sort over the issues' `dependsOn`
|
|
1015
|
+
// cross-links and containment edges (the ordering law drives edge direction
|
|
1016
|
+
// by presence), path-tiebroken for determinism. `classifyCall` bucketing
|
|
1017
|
+
// downstream fixes the coarse cross-entity DDL sequence; this settles the
|
|
1018
|
+
// order within each bucket (notably the teardown order among drops).
|
|
1019
|
+
const sorted = orderIssuesByDependencies(remaining);
|
|
1062
1020
|
|
|
1063
1021
|
const defaultCalls: PostgresOpFactoryCall[] = [];
|
|
1064
1022
|
const conflicts: SqlPlannerConflict[] = [];
|
|
@@ -1106,6 +1064,9 @@ export function planIssues(
|
|
|
1106
1064
|
const calls: PostgresOpFactoryCall[] = [
|
|
1107
1065
|
...byCategory('dep'),
|
|
1108
1066
|
...byCategory('drop'),
|
|
1067
|
+
// DROP TYPE after every table drop — a managed enum type can only go once
|
|
1068
|
+
// no live column still uses it.
|
|
1069
|
+
...byCategory('dropType'),
|
|
1109
1070
|
...byCategory('table'),
|
|
1110
1071
|
...byCategory('column'),
|
|
1111
1072
|
...gatedRecipe,
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* - `toOp()` — converts the IR node to a runtime
|
|
10
10
|
* `SqlMigrationPlanOperation` by delegating to the matching pure factory
|
|
11
11
|
* under `operations/`. `DataTransformCall.toOp()` always throws
|
|
12
|
-
* `
|
|
12
|
+
* `MIGRATION.UNFILLED_PLACEHOLDER` because a planner-generated data transform is an
|
|
13
13
|
* unfilled authoring stub by construction.
|
|
14
14
|
* - `renderTypeScript()` / `importRequirements()` — inherited from
|
|
15
15
|
* `TsExpression`. Used by `renderCallsToTypeScript` to emit the call as
|
|
@@ -45,7 +45,7 @@ import {
|
|
|
45
45
|
tableExistsAst,
|
|
46
46
|
} from '../../contract-free/checks';
|
|
47
47
|
import * as contractFreeDdl from '../../contract-free/ddl';
|
|
48
|
-
import type { PostgresRlsPolicy } from '../postgres-rls-policy';
|
|
48
|
+
import type { PostgresRlsPolicy, PostgresRlsPolicyInput } from '../postgres-rls-policy';
|
|
49
49
|
import {
|
|
50
50
|
escapeLiteral,
|
|
51
51
|
quoteIdentifier,
|
|
@@ -740,10 +740,6 @@ export class AddNotNullColumnDirectCall extends PostgresOpFactoryCallNode {
|
|
|
740
740
|
renderTypeScript(): string {
|
|
741
741
|
return `rawSql(${jsonToTsSource({ id: `column.${this.tableName}.${this.columnName}`, label: this.label, operationClass: 'additive' })})`;
|
|
742
742
|
}
|
|
743
|
-
|
|
744
|
-
override importRequirements(): readonly ImportRequirement[] {
|
|
745
|
-
return [];
|
|
746
|
-
}
|
|
747
743
|
}
|
|
748
744
|
|
|
749
745
|
/**
|
|
@@ -810,10 +806,6 @@ export class AddNotNullColumnWithTempDefaultCall extends PostgresOpFactoryCallNo
|
|
|
810
806
|
renderTypeScript(): string {
|
|
811
807
|
return `rawSql(${jsonToTsSource({ id: `column.${this.tableName}.${this.columnName}`, label: this.label, operationClass: 'additive' })})`;
|
|
812
808
|
}
|
|
813
|
-
|
|
814
|
-
override importRequirements(): readonly ImportRequirement[] {
|
|
815
|
-
return [];
|
|
816
|
-
}
|
|
817
809
|
}
|
|
818
810
|
|
|
819
811
|
// ============================================================================
|
|
@@ -1515,7 +1507,7 @@ export class AddNativeEnumValueCall extends PostgresOpFactoryCallNode {
|
|
|
1515
1507
|
* A planner-generated data-transform stub. `checkSlot` and `runSlot` name
|
|
1516
1508
|
* the unfilled authoring slots that the rendered `migration.ts` will expose
|
|
1517
1509
|
* to the user via `placeholder("…")` calls. `toOp()` always throws
|
|
1518
|
-
* `
|
|
1510
|
+
* `MIGRATION.UNFILLED_PLACEHOLDER`: the planner cannot lower a stubbed transform to a runtime
|
|
1519
1511
|
* op — the user must fill the rendered `migration.ts` and re-emit.
|
|
1520
1512
|
*/
|
|
1521
1513
|
export class DataTransformCall extends PostgresOpFactoryCallNode {
|
|
@@ -1592,7 +1584,23 @@ export class CreatePostgresRlsPolicyCall extends PostgresOpFactoryCallNode {
|
|
|
1592
1584
|
}
|
|
1593
1585
|
|
|
1594
1586
|
renderTypeScript(): string {
|
|
1595
|
-
|
|
1587
|
+
const p = this.policy;
|
|
1588
|
+
const input: PostgresRlsPolicyInput = {
|
|
1589
|
+
name: p.name,
|
|
1590
|
+
prefix: p.prefix,
|
|
1591
|
+
tableName: p.tableName,
|
|
1592
|
+
namespaceId: p.namespaceId,
|
|
1593
|
+
operation: p.operation,
|
|
1594
|
+
roles: p.roles,
|
|
1595
|
+
...ifDefined('using', p.using),
|
|
1596
|
+
...ifDefined('withCheck', p.withCheck),
|
|
1597
|
+
permissive: p.permissive,
|
|
1598
|
+
};
|
|
1599
|
+
return `this.createRlsPolicy({ schema: ${jsonToTsSource(this.schemaName)}, table: ${jsonToTsSource(this.tableName)}, policy: ${jsonToTsSource(input)} })`;
|
|
1600
|
+
}
|
|
1601
|
+
|
|
1602
|
+
override importRequirements(): readonly ImportRequirement[] {
|
|
1603
|
+
return [];
|
|
1596
1604
|
}
|
|
1597
1605
|
}
|
|
1598
1606
|
|
|
@@ -1623,7 +1631,11 @@ export class DropPostgresRlsPolicyCall extends PostgresOpFactoryCallNode {
|
|
|
1623
1631
|
}
|
|
1624
1632
|
|
|
1625
1633
|
renderTypeScript(): string {
|
|
1626
|
-
return `dropRlsPolicy(${jsonToTsSource(this.schemaName)}, ${jsonToTsSource(this.tableName)}, ${jsonToTsSource(this.policyName)})`;
|
|
1634
|
+
return `this.dropRlsPolicy({ schema: ${jsonToTsSource(this.schemaName)}, table: ${jsonToTsSource(this.tableName)}, policy: ${jsonToTsSource(this.policyName)} })`;
|
|
1635
|
+
}
|
|
1636
|
+
|
|
1637
|
+
override importRequirements(): readonly ImportRequirement[] {
|
|
1638
|
+
return [];
|
|
1627
1639
|
}
|
|
1628
1640
|
}
|
|
1629
1641
|
|
|
@@ -1652,7 +1664,11 @@ export class EnableRowLevelSecurityCall extends PostgresOpFactoryCallNode {
|
|
|
1652
1664
|
}
|
|
1653
1665
|
|
|
1654
1666
|
renderTypeScript(): string {
|
|
1655
|
-
return `enableRowLevelSecurity(${jsonToTsSource(this.schemaName)}, ${jsonToTsSource(this.tableName)})`;
|
|
1667
|
+
return `this.enableRowLevelSecurity({ schema: ${jsonToTsSource(this.schemaName)}, table: ${jsonToTsSource(this.tableName)} })`;
|
|
1668
|
+
}
|
|
1669
|
+
|
|
1670
|
+
override importRequirements(): readonly ImportRequirement[] {
|
|
1671
|
+
return [];
|
|
1656
1672
|
}
|
|
1657
1673
|
}
|
|
1658
1674
|
|
|
@@ -1681,7 +1697,11 @@ export class DisableRowLevelSecurityCall extends PostgresOpFactoryCallNode {
|
|
|
1681
1697
|
}
|
|
1682
1698
|
|
|
1683
1699
|
renderTypeScript(): string {
|
|
1684
|
-
return `disableRowLevelSecurity(${jsonToTsSource(this.schemaName)}, ${jsonToTsSource(this.tableName)})`;
|
|
1700
|
+
return `this.disableRowLevelSecurity({ schema: ${jsonToTsSource(this.schemaName)}, table: ${jsonToTsSource(this.tableName)} })`;
|
|
1701
|
+
}
|
|
1702
|
+
|
|
1703
|
+
override importRequirements(): readonly ImportRequirement[] {
|
|
1704
|
+
return [];
|
|
1685
1705
|
}
|
|
1686
1706
|
}
|
|
1687
1707
|
|
|
@@ -1724,7 +1744,11 @@ export class RenamePostgresRlsPolicyCall extends PostgresOpFactoryCallNode {
|
|
|
1724
1744
|
}
|
|
1725
1745
|
|
|
1726
1746
|
renderTypeScript(): string {
|
|
1727
|
-
return `renameRlsPolicy(${jsonToTsSource(this.schemaName)}, ${jsonToTsSource(this.tableName)}, ${jsonToTsSource(this.oldPolicyName)}, ${jsonToTsSource(this.newPolicyName)})`;
|
|
1747
|
+
return `this.renameRlsPolicy({ schema: ${jsonToTsSource(this.schemaName)}, table: ${jsonToTsSource(this.tableName)}, from: ${jsonToTsSource(this.oldPolicyName)}, to: ${jsonToTsSource(this.newPolicyName)} })`;
|
|
1748
|
+
}
|
|
1749
|
+
|
|
1750
|
+
override importRequirements(): readonly ImportRequirement[] {
|
|
1751
|
+
return [];
|
|
1728
1752
|
}
|
|
1729
1753
|
}
|
|
1730
1754
|
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
*
|
|
22
22
|
* The factory accepts lazy closures (`() => SqlQueryPlan | Buildable`),
|
|
23
23
|
* invokes each one, asserts that its `meta.storageHash` matches the
|
|
24
|
-
* `contract` it was handed (→ `
|
|
24
|
+
* `contract` it was handed (→ `MIGRATION.DATA_TRANSFORM_CONTRACT_MISMATCH` on mismatch), and lowers the
|
|
25
25
|
* plan via the supplied control adapter to a serialized `{sql, params}`
|
|
26
26
|
* payload.
|
|
27
27
|
*
|