@prisma-next/target-postgres 0.12.0-dev.9 → 0.13.0-dev.1
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/{codec-ids-DliyCWPY.d.mts → codec-ids-B1vOchLE.d.mts} +3 -2
- package/dist/codec-ids-B1vOchLE.d.mts.map +1 -0
- package/dist/{codec-ids-C5qzBqus.mjs → codec-ids-CTikp1if.mjs} +3 -2
- package/dist/codec-ids-CTikp1if.mjs.map +1 -0
- package/dist/codec-ids.d.mts +2 -2
- package/dist/codec-ids.mjs +2 -2
- package/dist/{codec-types-BF1DXTPs.d.mts → codec-types-CnFiNML4.d.mts} +8 -9
- package/dist/codec-types-CnFiNML4.d.mts.map +1 -0
- package/dist/codec-types.d.mts +2 -2
- package/dist/{codecs-DuP3d9Au.d.mts → codecs-CBpEv4s5.d.mts} +33 -35
- package/dist/codecs-CBpEv4s5.d.mts.map +1 -0
- package/dist/codecs.d.mts +1 -1
- package/dist/codecs.mjs +37 -2
- package/dist/codecs.mjs.map +1 -1
- package/dist/contract-free.d.mts +80 -0
- package/dist/contract-free.d.mts.map +1 -0
- package/dist/contract-free.mjs +117 -0
- package/dist/contract-free.mjs.map +1 -0
- package/dist/control.d.mts +1 -1
- package/dist/control.d.mts.map +1 -1
- package/dist/control.mjs +66 -40
- package/dist/control.mjs.map +1 -1
- package/dist/{data-transform-CRkv2T_U.mjs → data-transform-D25tLeYU.mjs} +1 -1
- package/dist/{data-transform-CRkv2T_U.mjs.map → data-transform-D25tLeYU.mjs.map} +1 -1
- package/dist/{data-transform-CAPmAdxS.d.mts → data-transform-DGOqcLrf.d.mts} +2 -2
- package/dist/{data-transform-CAPmAdxS.d.mts.map → data-transform-DGOqcLrf.d.mts.map} +1 -1
- package/dist/data-transform.d.mts +1 -1
- package/dist/data-transform.mjs +1 -1
- package/dist/ddl-77SyXgFt.mjs +30 -0
- package/dist/ddl-77SyXgFt.mjs.map +1 -0
- package/dist/ddl.d.mts +2 -0
- package/dist/ddl.mjs +2 -0
- package/dist/{default-normalizer-DaAhmzBV.mjs → default-normalizer-DyyCHQWs.mjs} +1 -1
- package/dist/{default-normalizer-DaAhmzBV.mjs.map → default-normalizer-DyyCHQWs.mjs.map} +1 -1
- package/dist/default-normalizer.mjs +1 -1
- package/dist/{descriptor-meta-Uu8QaClr.mjs → descriptor-meta-DKmj-IMN.mjs} +3 -2
- package/dist/descriptor-meta-DKmj-IMN.mjs.map +1 -0
- package/dist/{descriptor-meta-runtime-DMRX39kp.mjs → descriptor-meta-runtime-My8_s4cs.mjs} +2 -2
- package/dist/{descriptor-meta-runtime-DMRX39kp.mjs.map → descriptor-meta-runtime-My8_s4cs.mjs.map} +1 -1
- package/dist/{enum-planning-DRA9LaMU.mjs → enum-planning-BCyvlFHk.mjs} +0 -0
- package/dist/{enum-planning-DRA9LaMU.mjs.map → enum-planning-BCyvlFHk.mjs.map} +1 -1
- package/dist/enum-planning.d.mts +1 -1
- package/dist/enum-planning.mjs +1 -1
- package/dist/{errors-BbnITmAD.mjs → errors-CUk87ByX.mjs} +1 -1
- package/dist/{errors-BbnITmAD.mjs.map → errors-CUk87ByX.mjs.map} +1 -1
- package/dist/errors.d.mts.map +1 -1
- package/dist/errors.mjs +1 -1
- package/dist/{issue-planner-BtaL6OfW.mjs → issue-planner-Br0pt1Ea.mjs} +130 -28
- package/dist/issue-planner-Br0pt1Ea.mjs.map +1 -0
- package/dist/issue-planner.d.mts +1 -1
- package/dist/issue-planner.d.mts.map +1 -1
- package/dist/issue-planner.mjs +1 -1
- package/dist/migration.d.mts +7 -8
- package/dist/migration.d.mts.map +1 -1
- package/dist/migration.mjs +5 -4
- package/dist/migration.mjs.map +1 -1
- package/dist/{native-type-normalizer-BNEQ9VDs.mjs → native-type-normalizer-Bc9XJzWC.mjs} +1 -1
- package/dist/{native-type-normalizer-BNEQ9VDs.mjs.map → native-type-normalizer-Bc9XJzWC.mjs.map} +1 -1
- package/dist/native-type-normalizer.mjs +1 -1
- package/dist/nodes-779hmCfL.d.mts +40 -0
- package/dist/nodes-779hmCfL.d.mts.map +1 -0
- package/dist/nodes-DZk2JZG3.mjs +47 -0
- package/dist/nodes-DZk2JZG3.mjs.map +1 -0
- package/dist/op-factory-call-D2aAUhmS.mjs +1307 -0
- package/dist/op-factory-call-D2aAUhmS.mjs.map +1 -0
- package/dist/{op-factory-call-CDlImOF_.d.mts → op-factory-call-DMA86_2D.d.mts} +39 -14
- package/dist/op-factory-call-DMA86_2D.d.mts.map +1 -0
- package/dist/op-factory-call.d.mts +2 -2
- package/dist/op-factory-call.mjs +2 -2
- package/dist/pack.d.mts +5 -6
- package/dist/pack.d.mts.map +1 -1
- package/dist/pack.mjs +1 -1
- package/dist/planner-CAYPJObw.mjs +344 -0
- package/dist/planner-CAYPJObw.mjs.map +1 -0
- package/dist/{planner-ddl-builders-BNMfSE9r.mjs → planner-ddl-builders-Cw2n2llW.mjs} +7 -30
- package/dist/planner-ddl-builders-Cw2n2llW.mjs.map +1 -0
- package/dist/planner-ddl-builders.d.mts +6 -7
- package/dist/planner-ddl-builders.d.mts.map +1 -1
- package/dist/planner-ddl-builders.mjs +2 -2
- package/dist/{planner-identity-values-nhVj0hp-.mjs → planner-identity-values-BIpa5p2I.mjs} +1 -1
- package/dist/{planner-identity-values-nhVj0hp-.mjs.map → planner-identity-values-BIpa5p2I.mjs.map} +1 -1
- package/dist/planner-identity-values.mjs +1 -1
- package/dist/{planner-produced-postgres-migration-D02NOhVQ.d.mts → planner-produced-postgres-migration-B4EDvLdz.d.mts} +5 -4
- package/dist/planner-produced-postgres-migration-B4EDvLdz.d.mts.map +1 -0
- package/dist/{planner-produced-postgres-migration-D_nsXbhl.mjs → planner-produced-postgres-migration-NSEhWL0L.mjs} +8 -6
- package/dist/planner-produced-postgres-migration-NSEhWL0L.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-CGxxYfnD.mjs → planner-schema-lookup-CiVaAQP-.mjs} +1 -1
- package/dist/{planner-schema-lookup-CGxxYfnD.mjs.map → planner-schema-lookup-CiVaAQP-.mjs.map} +1 -1
- package/dist/planner-schema-lookup.mjs +1 -1
- package/dist/{planner-sql-checks-CfEiTXoQ.mjs → planner-sql-checks-DAdhnI2c.mjs} +41 -30
- package/dist/planner-sql-checks-DAdhnI2c.mjs.map +1 -0
- package/dist/planner-sql-checks.d.mts.map +1 -1
- package/dist/planner-sql-checks.mjs +1 -1
- package/dist/{planner-target-details-a_wuOiYf.d.mts → planner-target-details-CIY6tLeo.d.mts} +2 -2
- package/dist/planner-target-details-CIY6tLeo.d.mts.map +1 -0
- package/dist/planner-target-details.d.mts +2 -2
- package/dist/planner-type-resolution-836DExFN.mjs +20 -0
- package/dist/planner-type-resolution-836DExFN.mjs.map +1 -0
- package/dist/planner.d.mts +7 -3
- package/dist/planner.d.mts.map +1 -1
- package/dist/planner.mjs +1 -1
- package/dist/{postgres-contract-serializer-BnOboPWs.mjs → postgres-contract-serializer-DYTyXjPf.mjs} +33 -24
- package/dist/postgres-contract-serializer-DYTyXjPf.mjs.map +1 -0
- package/dist/{postgres-enum-type-CSzsvXrO.d.mts → postgres-enum-type-BVn63a89.d.mts} +1 -1
- package/dist/{postgres-enum-type-CSzsvXrO.d.mts.map → postgres-enum-type-BVn63a89.d.mts.map} +1 -1
- package/dist/{postgres-enum-type-BMgyxNyy.mjs → postgres-enum-type-DPKqCBem.mjs} +1 -1
- package/dist/{postgres-enum-type-BMgyxNyy.mjs.map → postgres-enum-type-DPKqCBem.mjs.map} +1 -1
- package/dist/{postgres-migration-BatbEvU6.mjs → postgres-migration-COore9Mz.mjs} +23 -3
- package/dist/postgres-migration-COore9Mz.mjs.map +1 -0
- package/dist/{postgres-migration-DRY8V-bQ.d.mts → postgres-migration-DZ_gLUOW.d.mts} +25 -3
- package/dist/postgres-migration-DZ_gLUOW.d.mts.map +1 -0
- package/dist/{postgres-schema-BxAuNFX0.mjs → postgres-schema-BuxCxbvB.mjs} +29 -14
- package/dist/postgres-schema-BuxCxbvB.mjs.map +1 -0
- package/dist/{render-ops-XhICjX_P.mjs → render-ops-BpjstrKQ.mjs} +4 -3
- package/dist/{render-ops-XhICjX_P.mjs.map → render-ops-BpjstrKQ.mjs.map} +1 -1
- package/dist/render-ops.d.mts +3 -2
- package/dist/render-ops.d.mts.map +1 -1
- package/dist/render-ops.mjs +1 -1
- package/dist/{render-typescript-K125n-RZ.mjs → render-typescript-KMgosran.mjs} +5 -2
- package/dist/render-typescript-KMgosran.mjs.map +1 -0
- package/dist/render-typescript.mjs +1 -1
- package/dist/runtime.d.mts.map +1 -1
- package/dist/runtime.mjs +2 -2
- package/dist/{shared-Do_a5ymU.d.mts → shared-DarONYBZ.d.mts} +5 -5
- package/dist/{shared-Do_a5ymU.d.mts.map → shared-DarONYBZ.d.mts.map} +1 -1
- package/dist/{sql-utils-CggjWNij.mjs → sql-utils-DcfMz4MQ.mjs} +1 -1
- package/dist/{sql-utils-CggjWNij.mjs.map → sql-utils-DcfMz4MQ.mjs.map} +1 -1
- package/dist/sql-utils.mjs +1 -1
- package/dist/{types-O40IcFV9.d.mts → types-BDKkx8MA.d.mts} +1 -1
- package/dist/types-BDKkx8MA.d.mts.map +1 -0
- package/dist/types.d.mts +16 -11
- package/dist/types.d.mts.map +1 -1
- package/dist/types.mjs +2 -2
- package/package.json +21 -20
- package/src/contract-free/columns.ts +49 -0
- package/src/contract-free/control-bootstrap.ts +55 -0
- package/src/contract-free/ddl.ts +37 -0
- package/src/core/ast/table-source.ts +23 -0
- package/src/core/codec-ids.ts +1 -0
- package/src/core/codecs.ts +44 -0
- package/src/core/ddl/nodes.ts +72 -0
- package/src/core/descriptor-meta.ts +1 -0
- package/src/core/migrations/control-policy.ts +234 -0
- package/src/core/migrations/issue-planner.ts +81 -13
- package/src/core/migrations/op-factory-call.ts +289 -46
- package/src/core/migrations/operations/constraints.ts +79 -10
- package/src/core/migrations/operations/dependencies.ts +0 -17
- package/src/core/migrations/operations/shared.ts +3 -3
- package/src/core/migrations/operations/tables.ts +1 -39
- package/src/core/migrations/planner-ddl-builders.ts +7 -48
- package/src/core/migrations/planner-produced-postgres-migration.ts +11 -6
- package/src/core/migrations/planner-sql-checks.ts +9 -9
- package/src/core/migrations/planner-strategies.ts +149 -11
- package/src/core/migrations/planner-target-details.ts +2 -1
- package/src/core/migrations/planner.ts +66 -8
- package/src/core/migrations/postgres-migration.ts +41 -0
- package/src/core/migrations/render-ops.ts +7 -2
- package/src/core/migrations/render-typescript.ts +5 -1
- package/src/core/migrations/runner.ts +78 -50
- package/src/core/postgres-contract-serializer.ts +52 -46
- package/src/core/postgres-schema.ts +43 -25
- package/src/exports/contract-free.ts +7 -0
- package/src/exports/control.ts +6 -8
- package/src/exports/ddl.ts +7 -0
- package/src/exports/migration.ts +11 -2
- package/src/exports/op-factory-call.ts +2 -0
- package/src/exports/planner-ddl-builders.ts +0 -1
- package/dist/codec-ids-C5qzBqus.mjs.map +0 -1
- package/dist/codec-ids-DliyCWPY.d.mts.map +0 -1
- package/dist/codec-types-BF1DXTPs.d.mts.map +0 -1
- package/dist/codecs-DuP3d9Au.d.mts.map +0 -1
- package/dist/descriptor-meta-Uu8QaClr.mjs.map +0 -1
- package/dist/issue-planner-BtaL6OfW.mjs.map +0 -1
- package/dist/op-factory-call-CDlImOF_.d.mts.map +0 -1
- package/dist/op-factory-call-ewOd5q6L.mjs +0 -625
- package/dist/op-factory-call-ewOd5q6L.mjs.map +0 -1
- package/dist/planner-Bjz5pnLa.mjs +0 -177
- package/dist/planner-Bjz5pnLa.mjs.map +0 -1
- package/dist/planner-ddl-builders-BNMfSE9r.mjs.map +0 -1
- package/dist/planner-produced-postgres-migration-D02NOhVQ.d.mts.map +0 -1
- package/dist/planner-produced-postgres-migration-D_nsXbhl.mjs.map +0 -1
- package/dist/planner-sql-checks-CfEiTXoQ.mjs.map +0 -1
- package/dist/planner-target-details-a_wuOiYf.d.mts.map +0 -1
- package/dist/postgres-contract-serializer-BnOboPWs.mjs.map +0 -1
- package/dist/postgres-migration-BatbEvU6.mjs.map +0 -1
- package/dist/postgres-migration-DRY8V-bQ.d.mts.map +0 -1
- package/dist/postgres-schema-BxAuNFX0.mjs.map +0 -1
- package/dist/render-typescript-K125n-RZ.mjs.map +0 -1
- package/dist/statement-builders-DVI5IVAa.mjs +0 -131
- package/dist/statement-builders-DVI5IVAa.mjs.map +0 -1
- package/dist/statement-builders.d.mts +0 -51
- package/dist/statement-builders.d.mts.map +0 -1
- package/dist/statement-builders.mjs +0 -2
- package/dist/tables-DoA39Yqo.mjs +0 -516
- package/dist/tables-DoA39Yqo.mjs.map +0 -1
- package/dist/types-O40IcFV9.d.mts.map +0 -1
- package/src/core/migrations/statement-builders.ts +0 -183
- package/src/exports/statement-builders.ts +0 -8
|
@@ -1,21 +1,19 @@
|
|
|
1
1
|
import type { CodecControlHooks } from '@prisma-next/family-sql/control';
|
|
2
2
|
import type {
|
|
3
|
-
ForeignKey,
|
|
4
3
|
PostgresEnumStorageEntry,
|
|
5
|
-
ReferentialAction,
|
|
6
4
|
StorageColumn,
|
|
7
5
|
StorageTable,
|
|
8
6
|
StorageTypeInstance,
|
|
9
7
|
} from '@prisma-next/sql-contract/types';
|
|
8
|
+
import { ifDefined } from '@prisma-next/utils/defined';
|
|
10
9
|
import { escapeLiteral, quoteIdentifier } from '../sql-utils';
|
|
11
10
|
import type { PostgresColumnDefault } from '../types';
|
|
12
|
-
import { qualifyTableName } from './planner-sql-checks';
|
|
13
11
|
import { resolveColumnTypeMetadata } from './planner-type-resolution';
|
|
14
12
|
|
|
15
13
|
export function buildCreateTableSql(
|
|
16
14
|
qualifiedTableName: string,
|
|
17
15
|
table: StorageTable,
|
|
18
|
-
codecHooks:
|
|
16
|
+
codecHooks: ReadonlyMap<string, CodecControlHooks>,
|
|
19
17
|
storageTypes: Record<string, StorageTypeInstance | PostgresEnumStorageEntry> = {},
|
|
20
18
|
): string {
|
|
21
19
|
const columnDefinitions = Object.entries(table.columns).map(
|
|
@@ -80,7 +78,7 @@ function assertSafeDefaultExpression(expression: string): void {
|
|
|
80
78
|
*/
|
|
81
79
|
export function buildColumnTypeSql(
|
|
82
80
|
column: StorageColumn,
|
|
83
|
-
codecHooks:
|
|
81
|
+
codecHooks: ReadonlyMap<string, CodecControlHooks>,
|
|
84
82
|
storageTypes: Record<string, StorageTypeInstance | PostgresEnumStorageEntry> = {},
|
|
85
83
|
allowPseudoTypes = true,
|
|
86
84
|
): string {
|
|
@@ -116,9 +114,9 @@ export function buildColumnTypeSql(
|
|
|
116
114
|
|
|
117
115
|
function expandParameterizedTypeSql(
|
|
118
116
|
column: Pick<StorageColumn, 'nativeType' | 'codecId' | 'typeParams'>,
|
|
119
|
-
codecHooks:
|
|
117
|
+
codecHooks: ReadonlyMap<string, CodecControlHooks>,
|
|
120
118
|
): string | null {
|
|
121
|
-
if (!column.typeParams) {
|
|
119
|
+
if (!column.typeParams || Object.keys(column.typeParams).length === 0) {
|
|
122
120
|
return null;
|
|
123
121
|
}
|
|
124
122
|
|
|
@@ -144,7 +142,7 @@ function expandParameterizedTypeSql(
|
|
|
144
142
|
const expanded = hooks.expandNativeType({
|
|
145
143
|
nativeType: column.nativeType,
|
|
146
144
|
codecId: column.codecId,
|
|
147
|
-
typeParams
|
|
145
|
+
...ifDefined('typeParams', column.typeParams),
|
|
148
146
|
});
|
|
149
147
|
|
|
150
148
|
return expanded !== column.nativeType ? expanded : null;
|
|
@@ -200,7 +198,7 @@ export function buildAddColumnSql(
|
|
|
200
198
|
qualifiedTableName: string,
|
|
201
199
|
columnName: string,
|
|
202
200
|
column: StorageColumn,
|
|
203
|
-
codecHooks:
|
|
201
|
+
codecHooks: ReadonlyMap<string, CodecControlHooks>,
|
|
204
202
|
temporaryDefault?: string | null,
|
|
205
203
|
storageTypes: Record<string, StorageTypeInstance | PostgresEnumStorageEntry> = {},
|
|
206
204
|
): string {
|
|
@@ -216,42 +214,3 @@ export function buildAddColumnSql(
|
|
|
216
214
|
].filter(Boolean);
|
|
217
215
|
return parts.join(' ');
|
|
218
216
|
}
|
|
219
|
-
|
|
220
|
-
const REFERENTIAL_ACTION_SQL: Record<ReferentialAction, string> = {
|
|
221
|
-
noAction: 'NO ACTION',
|
|
222
|
-
restrict: 'RESTRICT',
|
|
223
|
-
cascade: 'CASCADE',
|
|
224
|
-
setNull: 'SET NULL',
|
|
225
|
-
setDefault: 'SET DEFAULT',
|
|
226
|
-
};
|
|
227
|
-
|
|
228
|
-
export function buildForeignKeySql(
|
|
229
|
-
schemaName: string,
|
|
230
|
-
tableName: string,
|
|
231
|
-
fkName: string,
|
|
232
|
-
foreignKey: ForeignKey,
|
|
233
|
-
): string {
|
|
234
|
-
let sql = `ALTER TABLE ${qualifyTableName(schemaName, tableName)}
|
|
235
|
-
ADD CONSTRAINT ${quoteIdentifier(fkName)}
|
|
236
|
-
FOREIGN KEY (${foreignKey.source.columns.map(quoteIdentifier).join(', ')})
|
|
237
|
-
REFERENCES ${qualifyTableName(schemaName, foreignKey.target.tableName)} (${foreignKey.target.columns
|
|
238
|
-
.map(quoteIdentifier)
|
|
239
|
-
.join(', ')})`;
|
|
240
|
-
|
|
241
|
-
if (foreignKey.onDelete !== undefined) {
|
|
242
|
-
const action = REFERENTIAL_ACTION_SQL[foreignKey.onDelete];
|
|
243
|
-
if (!action) {
|
|
244
|
-
throw new Error(`Unknown referential action for onDelete: ${String(foreignKey.onDelete)}`);
|
|
245
|
-
}
|
|
246
|
-
sql += `\nON DELETE ${action}`;
|
|
247
|
-
}
|
|
248
|
-
if (foreignKey.onUpdate !== undefined) {
|
|
249
|
-
const action = REFERENTIAL_ACTION_SQL[foreignKey.onUpdate];
|
|
250
|
-
if (!action) {
|
|
251
|
-
throw new Error(`Unknown referential action for onUpdate: ${String(foreignKey.onUpdate)}`);
|
|
252
|
-
}
|
|
253
|
-
sql += `\nON UPDATE ${action}`;
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
return sql;
|
|
257
|
-
}
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
*/
|
|
25
25
|
|
|
26
26
|
import type { SqlMigrationPlanOperation } from '@prisma-next/family-sql/control';
|
|
27
|
+
import type { Lowerer } from '@prisma-next/family-sql/control-adapter';
|
|
27
28
|
import type {
|
|
28
29
|
MigrationPlanWithAuthoringSurface,
|
|
29
30
|
OpFactoryCall,
|
|
@@ -43,16 +44,23 @@ export class TypeScriptRenderablePostgresMigration
|
|
|
43
44
|
readonly #calls: readonly OpFactoryCall[];
|
|
44
45
|
readonly #meta: MigrationMeta;
|
|
45
46
|
readonly #spaceId: string;
|
|
47
|
+
readonly #lowerer: Lowerer | undefined;
|
|
46
48
|
|
|
47
|
-
constructor(
|
|
49
|
+
constructor(
|
|
50
|
+
calls: readonly OpFactoryCall[],
|
|
51
|
+
meta: MigrationMeta,
|
|
52
|
+
spaceId: string,
|
|
53
|
+
lowerer?: Lowerer,
|
|
54
|
+
) {
|
|
48
55
|
super();
|
|
49
56
|
this.#calls = calls;
|
|
50
57
|
this.#meta = meta;
|
|
51
58
|
this.#spaceId = spaceId;
|
|
59
|
+
this.#lowerer = lowerer;
|
|
52
60
|
}
|
|
53
61
|
|
|
54
62
|
override get operations(): readonly Op[] {
|
|
55
|
-
return renderOps(this.#calls);
|
|
63
|
+
return renderOps(this.#calls, this.#lowerer);
|
|
56
64
|
}
|
|
57
65
|
|
|
58
66
|
override describe(): MigrationMeta {
|
|
@@ -69,9 +77,6 @@ export class TypeScriptRenderablePostgresMigration
|
|
|
69
77
|
}
|
|
70
78
|
|
|
71
79
|
renderTypeScript(): string {
|
|
72
|
-
return renderCallsToTypeScript(this.#calls, {
|
|
73
|
-
from: this.#meta.from,
|
|
74
|
-
to: this.#meta.to,
|
|
75
|
-
});
|
|
80
|
+
return renderCallsToTypeScript(this.#calls, { from: this.#meta.from, to: this.#meta.to });
|
|
76
81
|
}
|
|
77
82
|
}
|
|
@@ -20,11 +20,11 @@ import { resolveColumnTypeMetadata } from './planner-type-resolution';
|
|
|
20
20
|
* site.
|
|
21
21
|
*/
|
|
22
22
|
export function qualifyTableName(schema: string, table: string): string {
|
|
23
|
-
return postgresCreateNamespace({ id: schema }).qualifyTable(table);
|
|
23
|
+
return postgresCreateNamespace({ id: schema, entries: { table: {} } }).qualifyTable(table);
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
export function toRegclassLiteral(schema: string, name: string): string {
|
|
27
|
-
return postgresCreateNamespace({ id: schema }).regclassLiteral(name);
|
|
27
|
+
return postgresCreateNamespace({ id: schema, entries: { table: {} } }).regclassLiteral(name);
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
/**
|
|
@@ -43,7 +43,7 @@ export function constraintExistsCheck({
|
|
|
43
43
|
table?: string;
|
|
44
44
|
exists?: boolean;
|
|
45
45
|
}): string {
|
|
46
|
-
const namespace = postgresCreateNamespace({ id: schema });
|
|
46
|
+
const namespace = postgresCreateNamespace({ id: schema, entries: { table: {} } });
|
|
47
47
|
const existsClause = exists ? 'EXISTS' : 'NOT EXISTS';
|
|
48
48
|
const tableFilter = table
|
|
49
49
|
? `AND c.conrelid = to_regclass(${namespace.regclassLiteral(table)})`
|
|
@@ -68,7 +68,7 @@ export function columnExistsCheck({
|
|
|
68
68
|
column: string;
|
|
69
69
|
exists?: boolean;
|
|
70
70
|
}): string {
|
|
71
|
-
const namespace = postgresCreateNamespace({ id: schema });
|
|
71
|
+
const namespace = postgresCreateNamespace({ id: schema, entries: { table: {} } });
|
|
72
72
|
const existsClause = exists ? '' : 'NOT ';
|
|
73
73
|
return `SELECT ${existsClause}EXISTS (
|
|
74
74
|
SELECT 1
|
|
@@ -90,7 +90,7 @@ export function columnNullabilityCheck({
|
|
|
90
90
|
column: string;
|
|
91
91
|
nullable: boolean;
|
|
92
92
|
}): string {
|
|
93
|
-
const namespace = postgresCreateNamespace({ id: schema });
|
|
93
|
+
const namespace = postgresCreateNamespace({ id: schema, entries: { table: {} } });
|
|
94
94
|
const expected = nullable ? 'YES' : 'NO';
|
|
95
95
|
return `SELECT EXISTS (
|
|
96
96
|
SELECT 1
|
|
@@ -111,7 +111,7 @@ export function columnHasNoDefaultCheck(opts: {
|
|
|
111
111
|
table: string;
|
|
112
112
|
column: string;
|
|
113
113
|
}): string {
|
|
114
|
-
const namespace = postgresCreateNamespace({ id: opts.schema });
|
|
114
|
+
const namespace = postgresCreateNamespace({ id: opts.schema, entries: { table: {} } });
|
|
115
115
|
return `SELECT NOT EXISTS (
|
|
116
116
|
SELECT 1
|
|
117
117
|
FROM information_schema.columns
|
|
@@ -282,7 +282,7 @@ export function columnTypeCheck({
|
|
|
282
282
|
column: string;
|
|
283
283
|
expectedType: string;
|
|
284
284
|
}): string {
|
|
285
|
-
const namespace = postgresCreateNamespace({ id: schema });
|
|
285
|
+
const namespace = postgresCreateNamespace({ id: schema, entries: { table: {} } });
|
|
286
286
|
return `SELECT EXISTS (
|
|
287
287
|
SELECT 1
|
|
288
288
|
FROM pg_attribute a
|
|
@@ -307,7 +307,7 @@ export function columnDefaultExistsCheck({
|
|
|
307
307
|
column: string;
|
|
308
308
|
exists?: boolean;
|
|
309
309
|
}): string {
|
|
310
|
-
const namespace = postgresCreateNamespace({ id: schema });
|
|
310
|
+
const namespace = postgresCreateNamespace({ id: schema, entries: { table: {} } });
|
|
311
311
|
const nullCheck = exists ? 'IS NOT NULL' : 'IS NULL';
|
|
312
312
|
return `SELECT EXISTS (
|
|
313
313
|
SELECT 1
|
|
@@ -325,7 +325,7 @@ export function tableHasPrimaryKeyCheck(
|
|
|
325
325
|
exists: boolean,
|
|
326
326
|
constraintName?: string,
|
|
327
327
|
): string {
|
|
328
|
-
const namespace = postgresCreateNamespace({ id: schema });
|
|
328
|
+
const namespace = postgresCreateNamespace({ id: schema, entries: { table: {} } });
|
|
329
329
|
const comparison = exists ? '' : 'NOT ';
|
|
330
330
|
const constraintFilter = constraintName
|
|
331
331
|
? `AND c2.relname = '${escapeLiteral(constraintName)}'`
|
|
@@ -24,6 +24,7 @@ import type {
|
|
|
24
24
|
MigrationOperationPolicy,
|
|
25
25
|
SqlMigrationPlanOperation,
|
|
26
26
|
} from '@prisma-next/family-sql/control';
|
|
27
|
+
import { resolveValueSetValues } from '@prisma-next/family-sql/control';
|
|
27
28
|
import type { TargetBoundComponentDescriptor } from '@prisma-next/framework-components/components';
|
|
28
29
|
import type { SchemaIssue } from '@prisma-next/framework-components/control';
|
|
29
30
|
import { UNBOUND_NAMESPACE_ID } from '@prisma-next/framework-components/ir';
|
|
@@ -31,10 +32,11 @@ import {
|
|
|
31
32
|
isPostgresEnumStorageEntry,
|
|
32
33
|
type PostgresEnumStorageEntry,
|
|
33
34
|
type SqlStorage,
|
|
34
|
-
|
|
35
|
+
StorageTable,
|
|
35
36
|
type StorageTypeInstance,
|
|
36
37
|
} from '@prisma-next/sql-contract/types';
|
|
37
38
|
import type { SqlSchemaIR } from '@prisma-next/sql-schema-ir/types';
|
|
39
|
+
import { blindCast } from '@prisma-next/utils/casts';
|
|
38
40
|
import { PostgresEnumType } from '../postgres-enum-type';
|
|
39
41
|
import { isPostgresSchema } from '../postgres-schema';
|
|
40
42
|
import {
|
|
@@ -43,11 +45,13 @@ import {
|
|
|
43
45
|
resolveDdlSchemaForNamespaceStorage,
|
|
44
46
|
} from './enum-planning';
|
|
45
47
|
import {
|
|
48
|
+
AddCheckConstraintCall,
|
|
46
49
|
AddColumnCall,
|
|
47
50
|
AddEnumValuesCall,
|
|
48
51
|
AlterColumnTypeCall,
|
|
49
52
|
CreateEnumTypeCall,
|
|
50
53
|
DataTransformCall,
|
|
54
|
+
DropCheckConstraintCall,
|
|
51
55
|
DropEnumTypeCall,
|
|
52
56
|
type PostgresOpFactoryCall,
|
|
53
57
|
RawSqlCall,
|
|
@@ -93,7 +97,7 @@ export function tableAt(
|
|
|
93
97
|
): StorageTable | undefined {
|
|
94
98
|
// Namespace.tables is typed as Record<string, IRNode> at the interface level;
|
|
95
99
|
// SQL family namespaces always hold StorageTable instances.
|
|
96
|
-
return storage.namespaces[namespaceId]?.
|
|
100
|
+
return storage.namespaces[namespaceId]?.entries.table[tableName] as StorageTable | undefined;
|
|
97
101
|
}
|
|
98
102
|
|
|
99
103
|
/**
|
|
@@ -134,8 +138,8 @@ const DEFAULT_ENUM_NAMESPACE_ID = 'public';
|
|
|
134
138
|
|
|
135
139
|
function namespaceHasEnum(storage: SqlStorage, namespaceId: string, typeName: string): boolean {
|
|
136
140
|
const ns = storage.namespaces[namespaceId];
|
|
137
|
-
if (!
|
|
138
|
-
return
|
|
141
|
+
if (!isPostgresSchema(ns)) return false;
|
|
142
|
+
return ns.entries.type[typeName] !== undefined;
|
|
139
143
|
}
|
|
140
144
|
|
|
141
145
|
/**
|
|
@@ -166,7 +170,7 @@ function resolveColumnEnumNamespace(
|
|
|
166
170
|
|
|
167
171
|
/**
|
|
168
172
|
* Finds a type entry by explicit namespace coordinate. Namespace types (e.g.
|
|
169
|
-
* Postgres enums) live under `storage.namespaces[nsId].
|
|
173
|
+
* Postgres enums) live under `storage.namespaces[nsId].entries.type`. Returns the
|
|
170
174
|
* entry from the named namespace only — never scans other namespaces, so two
|
|
171
175
|
* namespaces that hold an enum with the same name resolve independently.
|
|
172
176
|
*/
|
|
@@ -176,8 +180,12 @@ function locateNamespaceType(
|
|
|
176
180
|
typeName: string,
|
|
177
181
|
): PostgresEnumStorageEntry | undefined {
|
|
178
182
|
const ns = storage.namespaces[namespaceId];
|
|
179
|
-
|
|
180
|
-
|
|
183
|
+
const raw = ns?.entries['type']?.[typeName];
|
|
184
|
+
if (raw === undefined) return undefined;
|
|
185
|
+
return blindCast<
|
|
186
|
+
PostgresEnumStorageEntry,
|
|
187
|
+
'postgres type slot carries PostgresEnumStorageEntry at the postgres target layer'
|
|
188
|
+
>(raw);
|
|
181
189
|
}
|
|
182
190
|
|
|
183
191
|
// ============================================================================
|
|
@@ -248,6 +256,7 @@ function buildColumnSpec(
|
|
|
248
256
|
name: column,
|
|
249
257
|
typeSql: buildColumnTypeSql(col, mutableHooks, mutableTypes),
|
|
250
258
|
defaultSql: buildColumnDefaultSql(col.default, col),
|
|
259
|
+
columnDefault: col.default,
|
|
251
260
|
nullable: overrides?.nullable ?? col.nullable,
|
|
252
261
|
};
|
|
253
262
|
}
|
|
@@ -436,7 +445,7 @@ function enumRebuildCallRecipe(
|
|
|
436
445
|
// same-named enums in distinct namespaces keep their columns disjoint.
|
|
437
446
|
const columnRefs: { namespaceId: string; table: string; column: string }[] = [];
|
|
438
447
|
for (const [nsId, ns] of Object.entries(ctx.toContract.storage.namespaces)) {
|
|
439
|
-
for (const [tableName, tableNode] of Object.entries(ns.
|
|
448
|
+
for (const [tableName, tableNode] of Object.entries(ns.entries.table)) {
|
|
440
449
|
const table = tableNode as StorageTable;
|
|
441
450
|
for (const [columnName, column] of Object.entries(table.columns)) {
|
|
442
451
|
if (
|
|
@@ -639,9 +648,10 @@ export const nativeEnumPlanCallStrategy: CallMigrationStrategy = (issues, ctx) =
|
|
|
639
648
|
function collectPostgresEnumTypes(storage: SqlStorage): ReadonlyMap<string, PostgresEnumType> {
|
|
640
649
|
const result = new Map<string, PostgresEnumType>();
|
|
641
650
|
for (const [nsId, ns] of Object.entries(storage.namespaces)) {
|
|
642
|
-
if (!(
|
|
643
|
-
const
|
|
644
|
-
|
|
651
|
+
if (!isPostgresSchema(ns)) continue;
|
|
652
|
+
for (const [name, instance] of Object.entries(ns.entries.type).sort(([a], [b]) =>
|
|
653
|
+
a.localeCompare(b),
|
|
654
|
+
)) {
|
|
645
655
|
if (instance instanceof PostgresEnumType) {
|
|
646
656
|
result.set(enumCompoundKey(nsId, name), instance);
|
|
647
657
|
}
|
|
@@ -650,6 +660,133 @@ function collectPostgresEnumTypes(storage: SqlStorage): ReadonlyMap<string, Post
|
|
|
650
660
|
return result;
|
|
651
661
|
}
|
|
652
662
|
|
|
663
|
+
/**
|
|
664
|
+
* Collects every check constraint from a table in the contract storage.
|
|
665
|
+
* Returns an empty array when the table has no checks or the table is absent.
|
|
666
|
+
*/
|
|
667
|
+
function collectContractChecks(
|
|
668
|
+
storage: SqlStorage,
|
|
669
|
+
namespaceId: string,
|
|
670
|
+
tableName: string,
|
|
671
|
+
): ReadonlyArray<{ name: string; column: string; permittedValues: readonly string[] }> {
|
|
672
|
+
const ns = storage.namespaces[namespaceId];
|
|
673
|
+
const tableRaw = ns?.entries.table[tableName];
|
|
674
|
+
if (!(tableRaw instanceof StorageTable)) return [];
|
|
675
|
+
const checks = tableRaw.checks;
|
|
676
|
+
if (!checks || checks.length === 0) return [];
|
|
677
|
+
return checks.map((c) => ({
|
|
678
|
+
name: c.name,
|
|
679
|
+
column: c.column,
|
|
680
|
+
permittedValues: resolveValueSetValues(
|
|
681
|
+
c.valueSet,
|
|
682
|
+
storage,
|
|
683
|
+
`check "${c.name}" on "${tableName}"`,
|
|
684
|
+
),
|
|
685
|
+
}));
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
/**
|
|
689
|
+
* Compares two value arrays as unordered sets.
|
|
690
|
+
*/
|
|
691
|
+
function checkValueSetsEqual(a: readonly string[], b: readonly string[]): boolean {
|
|
692
|
+
if (a.length !== b.length) return false;
|
|
693
|
+
const bSet = new Set(b);
|
|
694
|
+
return a.every((v) => bSet.has(v));
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
/**
|
|
698
|
+
* Plans check-constraint migrations for `enumType`-authored columns.
|
|
699
|
+
*
|
|
700
|
+
* Walks every namespace's tables in the target contract. For each table that
|
|
701
|
+
* carries `checks`, diffs the contract-expected checks against the live
|
|
702
|
+
* schema's checks:
|
|
703
|
+
*
|
|
704
|
+
* - Check in contract, absent from live DB → `AddCheckConstraintCall`.
|
|
705
|
+
* - Check in live DB, absent from contract → `DropCheckConstraintCall`.
|
|
706
|
+
* - Check on both sides but value sets differ → `DropCheckConstraintCall`
|
|
707
|
+
* then `AddCheckConstraintCall` (drop + recreate; a check predicate cannot
|
|
708
|
+
* be altered in place).
|
|
709
|
+
*
|
|
710
|
+
* Consumes `check_missing`, `check_removed`, and `check_mismatch` issues.
|
|
711
|
+
* Does not touch the native enum path (`nativeEnumPlanCallStrategy` is
|
|
712
|
+
* unchanged).
|
|
713
|
+
*/
|
|
714
|
+
export const checkConstraintPlanCallStrategy: CallMigrationStrategy = (issues, ctx) => {
|
|
715
|
+
const calls: PostgresOpFactoryCall[] = [];
|
|
716
|
+
const handledIssueKeys = new Set<string>();
|
|
717
|
+
|
|
718
|
+
for (const [namespaceId, ns] of Object.entries(ctx.toContract.storage.namespaces)) {
|
|
719
|
+
for (const tableName of Object.keys(ns.entries.table)) {
|
|
720
|
+
const contractChecks = collectContractChecks(ctx.toContract.storage, namespaceId, tableName);
|
|
721
|
+
if (contractChecks.length === 0) continue;
|
|
722
|
+
|
|
723
|
+
const schemaTable = ctx.schema.tables[tableName];
|
|
724
|
+
const liveChecks = schemaTable?.checks ?? [];
|
|
725
|
+
const ddlSchema = resolveDdlSchemaForNamespace(ctx, namespaceId);
|
|
726
|
+
|
|
727
|
+
for (const contractCheck of contractChecks) {
|
|
728
|
+
const liveCheck = liveChecks.find((c) => c.name === contractCheck.name);
|
|
729
|
+
const issueKey = `${tableName}${contractCheck.name}`;
|
|
730
|
+
if (!liveCheck) {
|
|
731
|
+
calls.push(
|
|
732
|
+
new AddCheckConstraintCall(
|
|
733
|
+
ddlSchema,
|
|
734
|
+
tableName,
|
|
735
|
+
contractCheck.name,
|
|
736
|
+
contractCheck.column,
|
|
737
|
+
contractCheck.permittedValues,
|
|
738
|
+
),
|
|
739
|
+
);
|
|
740
|
+
handledIssueKeys.add(issueKey);
|
|
741
|
+
} else if (!checkValueSetsEqual(contractCheck.permittedValues, liveCheck.permittedValues)) {
|
|
742
|
+
calls.push(
|
|
743
|
+
new DropCheckConstraintCall(ddlSchema, tableName, contractCheck.name),
|
|
744
|
+
new AddCheckConstraintCall(
|
|
745
|
+
ddlSchema,
|
|
746
|
+
tableName,
|
|
747
|
+
contractCheck.name,
|
|
748
|
+
contractCheck.column,
|
|
749
|
+
contractCheck.permittedValues,
|
|
750
|
+
),
|
|
751
|
+
);
|
|
752
|
+
handledIssueKeys.add(issueKey);
|
|
753
|
+
}
|
|
754
|
+
// else: values match — no op needed, still consume the issue
|
|
755
|
+
else {
|
|
756
|
+
handledIssueKeys.add(issueKey);
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
// Emit drops for checks that are live but not in the contract.
|
|
761
|
+
for (const liveCheck of liveChecks) {
|
|
762
|
+
const inContract = contractChecks.some((c) => c.name === liveCheck.name);
|
|
763
|
+
if (!inContract) {
|
|
764
|
+
const issueKey = `${tableName}${liveCheck.name}`;
|
|
765
|
+
calls.push(new DropCheckConstraintCall(ddlSchema, tableName, liveCheck.name));
|
|
766
|
+
handledIssueKeys.add(issueKey);
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
if (calls.length === 0 && handledIssueKeys.size === 0) return { kind: 'no_match' };
|
|
773
|
+
|
|
774
|
+
const remaining = issues.filter((issue) => {
|
|
775
|
+
if (
|
|
776
|
+
issue.kind !== 'check_missing' &&
|
|
777
|
+
issue.kind !== 'check_removed' &&
|
|
778
|
+
issue.kind !== 'check_mismatch'
|
|
779
|
+
) {
|
|
780
|
+
return true;
|
|
781
|
+
}
|
|
782
|
+
if (!issue.table || !issue.indexOrConstraint) return true;
|
|
783
|
+
const key = `${issue.table}${issue.indexOrConstraint}`;
|
|
784
|
+
return !handledIssueKeys.has(key);
|
|
785
|
+
});
|
|
786
|
+
|
|
787
|
+
return { kind: 'match', issues: remaining, calls };
|
|
788
|
+
};
|
|
789
|
+
|
|
653
790
|
/**
|
|
654
791
|
* Dispatches non-enum codec-typed storage types through their codec's
|
|
655
792
|
* `planTypeOperations` hook (the authoritative source for codec-driven DDL
|
|
@@ -922,6 +1059,7 @@ export const postgresPlannerStrategies: readonly CallMigrationStrategy[] = [
|
|
|
922
1059
|
typeChangeCallStrategy,
|
|
923
1060
|
nullableTighteningCallStrategy,
|
|
924
1061
|
nativeEnumPlanCallStrategy,
|
|
1062
|
+
checkConstraintPlanCallStrategy,
|
|
925
1063
|
storageTypePlanCallStrategy,
|
|
926
1064
|
notNullAddColumnCallStrategy,
|
|
927
1065
|
];
|
|
@@ -2,13 +2,17 @@ import type { Contract } from '@prisma-next/contract/types';
|
|
|
2
2
|
import type {
|
|
3
3
|
MigrationOperationPolicy,
|
|
4
4
|
SqlMigrationPlannerPlanOptions,
|
|
5
|
+
SqlPlannerConflict,
|
|
5
6
|
SqlPlannerFailureResult,
|
|
6
7
|
} from '@prisma-next/family-sql/control';
|
|
7
8
|
import {
|
|
8
9
|
extractCodecControlHooks,
|
|
10
|
+
partitionCallsByControlPolicy,
|
|
11
|
+
partitionIssuesByControlPolicy,
|
|
9
12
|
planFieldEventOperations,
|
|
10
13
|
plannerFailure,
|
|
11
14
|
} from '@prisma-next/family-sql/control';
|
|
15
|
+
import type { Lowerer } from '@prisma-next/family-sql/control-adapter';
|
|
12
16
|
import { verifySqlSchema } from '@prisma-next/family-sql/schema-verify';
|
|
13
17
|
import type { TargetBoundComponentDescriptor } from '@prisma-next/framework-components/components';
|
|
14
18
|
import type {
|
|
@@ -18,10 +22,18 @@ import type {
|
|
|
18
22
|
SchemaIssue,
|
|
19
23
|
} from '@prisma-next/framework-components/control';
|
|
20
24
|
import { UNBOUND_NAMESPACE_ID } from '@prisma-next/framework-components/ir';
|
|
25
|
+
import { blindCast } from '@prisma-next/utils/casts';
|
|
21
26
|
import { parsePostgresDefault } from '../default-normalizer';
|
|
22
27
|
import { normalizeSchemaNativeType } from '../native-type-normalizer';
|
|
28
|
+
import {
|
|
29
|
+
formatPostgresControlPolicySubjectLabel,
|
|
30
|
+
resolvePostgresCallControlPolicySubject,
|
|
31
|
+
resolvePostgresIssueControlPolicySubject,
|
|
32
|
+
resolvePostgresIssueCreationFactoryName,
|
|
33
|
+
} from './control-policy';
|
|
23
34
|
import { createResolveExistingEnumValues } from './enum-planning';
|
|
24
35
|
import { planIssues } from './issue-planner';
|
|
36
|
+
import type { PostgresOpFactoryCall } from './op-factory-call';
|
|
25
37
|
import { TypeScriptRenderablePostgresMigration } from './planner-produced-postgres-migration';
|
|
26
38
|
import { postgresPlannerStrategies } from './planner-strategies';
|
|
27
39
|
import { verifyPostgresNamespacePresence } from './verify-postgres-namespaces';
|
|
@@ -40,8 +52,8 @@ type VerifySqlSchemaOptionsWithComponents = Parameters<typeof verifySqlSchema>[0
|
|
|
40
52
|
readonly frameworkComponents: PlannerFrameworkComponents;
|
|
41
53
|
};
|
|
42
54
|
|
|
43
|
-
export function createPostgresMigrationPlanner(): PostgresMigrationPlanner {
|
|
44
|
-
return new PostgresMigrationPlanner();
|
|
55
|
+
export function createPostgresMigrationPlanner(lowerer: Lowerer): PostgresMigrationPlanner {
|
|
56
|
+
return new PostgresMigrationPlanner(lowerer);
|
|
45
57
|
}
|
|
46
58
|
|
|
47
59
|
/**
|
|
@@ -52,7 +64,11 @@ export function createPostgresMigrationPlanner(): PostgresMigrationPlanner {
|
|
|
52
64
|
* uniformly.
|
|
53
65
|
*/
|
|
54
66
|
export type PostgresPlanResult =
|
|
55
|
-
| {
|
|
67
|
+
| {
|
|
68
|
+
readonly kind: 'success';
|
|
69
|
+
readonly plan: TypeScriptRenderablePostgresMigration;
|
|
70
|
+
readonly warnings?: readonly SqlPlannerConflict[];
|
|
71
|
+
}
|
|
56
72
|
| SqlPlannerFailureResult;
|
|
57
73
|
|
|
58
74
|
/**
|
|
@@ -72,6 +88,12 @@ export type PostgresPlanResult =
|
|
|
72
88
|
* authoring surface.
|
|
73
89
|
*/
|
|
74
90
|
export class PostgresMigrationPlanner implements MigrationPlanner<'sql', 'postgres'> {
|
|
91
|
+
readonly #lowerer: Lowerer | undefined;
|
|
92
|
+
|
|
93
|
+
constructor(lowerer?: Lowerer) {
|
|
94
|
+
this.#lowerer = lowerer;
|
|
95
|
+
}
|
|
96
|
+
|
|
75
97
|
plan(options: {
|
|
76
98
|
readonly contract: unknown;
|
|
77
99
|
readonly schema: unknown;
|
|
@@ -114,6 +136,7 @@ export class PostgresMigrationPlanner implements MigrationPlanner<'sql', 'postgr
|
|
|
114
136
|
to: context.toHash,
|
|
115
137
|
},
|
|
116
138
|
spaceId,
|
|
139
|
+
this.#lowerer,
|
|
117
140
|
);
|
|
118
141
|
}
|
|
119
142
|
|
|
@@ -131,8 +154,25 @@ export class PostgresMigrationPlanner implements MigrationPlanner<'sql', 'postgr
|
|
|
131
154
|
const codecHooks = extractCodecControlHooks(options.frameworkComponents);
|
|
132
155
|
const storageTypes = options.contract.storage.types ?? {};
|
|
133
156
|
|
|
134
|
-
|
|
157
|
+
// Input-side control-policy partition. `external` / `observed` subjects
|
|
158
|
+
// — and non-creation issues for `tolerated` subjects — are dropped from
|
|
159
|
+
// the planner's input entirely; the planner never observes them, never
|
|
160
|
+
// diffs them, never generates DDL for them. Suppression warnings are
|
|
161
|
+
// built directly from the suppressed partition (one per subject), so the
|
|
162
|
+
// user-visible message survives even when the planner would have failed
|
|
163
|
+
// to model the subject's live shape.
|
|
164
|
+
const issuePartition = partitionIssuesByControlPolicy({
|
|
135
165
|
issues: schemaIssues,
|
|
166
|
+
contract: options.contract,
|
|
167
|
+
resolveControlPolicySubject: (issue) =>
|
|
168
|
+
resolvePostgresIssueControlPolicySubject(issue, options.contract),
|
|
169
|
+
resolveCreationFactoryName: resolvePostgresIssueCreationFactoryName,
|
|
170
|
+
formatSubjectLabel: (factoryName, subject) =>
|
|
171
|
+
formatPostgresControlPolicySubjectLabel(factoryName, subject, options.contract),
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
const result = planIssues({
|
|
175
|
+
issues: issuePartition.plannable,
|
|
136
176
|
toContract: options.contract,
|
|
137
177
|
// `fromContract` is only supplied by `migration plan`. It is `null` for
|
|
138
178
|
// `db update` / `db init`, which means data-safety strategies needing
|
|
@@ -163,10 +203,26 @@ export class PostgresMigrationPlanner implements MigrationPlanner<'sql', 'postgr
|
|
|
163
203
|
newContract: options.contract,
|
|
164
204
|
codecHooks,
|
|
165
205
|
});
|
|
166
|
-
// Codec
|
|
167
|
-
//
|
|
168
|
-
|
|
169
|
-
|
|
206
|
+
// Codec hook ops are target-agnostic `OpFactoryCall`; Postgres planning
|
|
207
|
+
// lifts them at this integration boundary (see field-event-planner JSDoc).
|
|
208
|
+
const fieldEventPostgresCalls = blindCast<
|
|
209
|
+
readonly PostgresOpFactoryCall[],
|
|
210
|
+
'Codec hook ops conform to PostgresOpFactoryCall at the app emitter boundary'
|
|
211
|
+
>(fieldEventOps);
|
|
212
|
+
const fieldEventPartition = partitionCallsByControlPolicy({
|
|
213
|
+
calls: fieldEventPostgresCalls,
|
|
214
|
+
contract: options.contract,
|
|
215
|
+
resolveControlPolicySubject: (call) =>
|
|
216
|
+
resolvePostgresCallControlPolicySubject(call, options.contract),
|
|
217
|
+
resolveFactoryName: (call) => call.factoryName,
|
|
218
|
+
formatSubjectLabel: (factoryName, subject) =>
|
|
219
|
+
formatPostgresControlPolicySubjectLabel(factoryName, subject, options.contract),
|
|
220
|
+
});
|
|
221
|
+
const calls = [...result.value.calls, ...fieldEventPartition.kept];
|
|
222
|
+
const warnings: SqlPlannerConflict[] = [
|
|
223
|
+
...issuePartition.warnings,
|
|
224
|
+
...fieldEventPartition.warnings,
|
|
225
|
+
];
|
|
170
226
|
|
|
171
227
|
return Object.freeze({
|
|
172
228
|
kind: 'success' as const,
|
|
@@ -177,7 +233,9 @@ export class PostgresMigrationPlanner implements MigrationPlanner<'sql', 'postgr
|
|
|
177
233
|
to: options.contract.storage.storageHash,
|
|
178
234
|
},
|
|
179
235
|
options.spaceId,
|
|
236
|
+
this.#lowerer,
|
|
180
237
|
),
|
|
238
|
+
...(warnings.length > 0 ? { warnings: Object.freeze(warnings) } : {}),
|
|
181
239
|
});
|
|
182
240
|
}
|
|
183
241
|
|
|
@@ -3,8 +3,11 @@ import type { SqlMigrationPlanOperation } from '@prisma-next/family-sql/control'
|
|
|
3
3
|
import type { SqlControlAdapter } from '@prisma-next/family-sql/control-adapter';
|
|
4
4
|
import { Migration as SqlMigration } from '@prisma-next/family-sql/migration';
|
|
5
5
|
import type { ControlStack } from '@prisma-next/framework-components/control';
|
|
6
|
+
import { UNBOUND_NAMESPACE_ID } from '@prisma-next/framework-components/ir';
|
|
6
7
|
import type { SqlStorage } from '@prisma-next/sql-contract/types';
|
|
8
|
+
import type { DdlColumn, DdlTableConstraint } from '@prisma-next/sql-relational-core/ast';
|
|
7
9
|
import { errorPostgresMigrationStackMissing } from '../errors';
|
|
10
|
+
import { CreateSchemaCall, CreateTableCall } from './op-factory-call';
|
|
8
11
|
import { type DataTransformOptions, dataTransform } from './operations/data-transform';
|
|
9
12
|
import type { PostgresPlanTargetDetails } from './planner-target-details';
|
|
10
13
|
|
|
@@ -67,4 +70,42 @@ export abstract class PostgresMigration extends SqlMigration<
|
|
|
67
70
|
}
|
|
68
71
|
return dataTransform(contract, name, options, this.controlAdapter);
|
|
69
72
|
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Emit a `CREATE TABLE` migration operation. Builds a typed DDL node from
|
|
76
|
+
* the supplied options and lowers it through the stored control adapter.
|
|
77
|
+
* Throws if no adapter is present (i.e. migration instantiated without a stack).
|
|
78
|
+
*/
|
|
79
|
+
protected createTable(options: {
|
|
80
|
+
readonly schema?: string;
|
|
81
|
+
readonly table: string;
|
|
82
|
+
readonly ifNotExists?: boolean;
|
|
83
|
+
readonly columns: readonly DdlColumn[];
|
|
84
|
+
readonly constraints?: readonly DdlTableConstraint[];
|
|
85
|
+
}): SqlMigrationPlanOperation<PostgresPlanTargetDetails> {
|
|
86
|
+
if (!this.controlAdapter) {
|
|
87
|
+
throw errorPostgresMigrationStackMissing();
|
|
88
|
+
}
|
|
89
|
+
return new CreateTableCall(
|
|
90
|
+
options.schema ?? UNBOUND_NAMESPACE_ID,
|
|
91
|
+
options.table,
|
|
92
|
+
options.columns,
|
|
93
|
+
options.constraints,
|
|
94
|
+
).toOp(this.controlAdapter);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Emit a `CREATE SCHEMA` migration operation. Builds a typed DDL node from
|
|
99
|
+
* the supplied options and lowers it through the stored control adapter.
|
|
100
|
+
* Throws if no adapter is present (i.e. migration instantiated without a stack).
|
|
101
|
+
*/
|
|
102
|
+
protected createSchema(options: {
|
|
103
|
+
readonly schema: string;
|
|
104
|
+
readonly ifNotExists?: boolean;
|
|
105
|
+
}): SqlMigrationPlanOperation<PostgresPlanTargetDetails> {
|
|
106
|
+
if (!this.controlAdapter) {
|
|
107
|
+
throw errorPostgresMigrationStackMissing();
|
|
108
|
+
}
|
|
109
|
+
return new CreateSchemaCall(options.schema).toOp(this.controlAdapter);
|
|
110
|
+
}
|
|
70
111
|
}
|