@prisma-next/target-postgres 0.5.0-dev.9 → 0.5.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-CojIXVf9.mjs → codec-ids-C5qzBqus.mjs} +4 -4
- package/dist/{codec-ids-CojIXVf9.mjs.map → codec-ids-C5qzBqus.mjs.map} +1 -1
- package/dist/codec-ids-CplrEfmx.d.mts +29 -0
- package/dist/codec-ids-CplrEfmx.d.mts.map +1 -0
- package/dist/codec-ids.d.mts +2 -28
- package/dist/codec-ids.mjs +2 -3
- package/dist/codec-types-lrsb3N07.d.mts +79 -0
- package/dist/codec-types-lrsb3N07.d.mts.map +1 -0
- package/dist/codec-types.d.mts +2 -42
- package/dist/codec-types.mjs +1 -3
- package/dist/codecs-Cue97Xqf.d.mts +558 -0
- package/dist/codecs-Cue97Xqf.d.mts.map +1 -0
- package/dist/codecs.d.mts +13 -2
- package/dist/codecs.d.mts.map +1 -0
- package/dist/codecs.mjs +738 -2
- package/dist/codecs.mjs.map +1 -0
- package/dist/control.d.mts +1 -1
- package/dist/control.d.mts.map +1 -1
- package/dist/control.mjs +132 -96
- package/dist/control.mjs.map +1 -1
- package/dist/{data-transform-VfEGzXWt.mjs → data-transform-DKWXdHuZ.mjs} +25 -7
- package/dist/data-transform-DKWXdHuZ.mjs.map +1 -0
- package/dist/data-transform-bIeAcZIJ.d.mts +38 -0
- package/dist/data-transform-bIeAcZIJ.d.mts.map +1 -0
- package/dist/data-transform.d.mts +1 -1
- package/dist/data-transform.mjs +2 -3
- package/dist/{default-normalizer-DNOpRoOF.mjs → default-normalizer-C8XyZj85.mjs} +2 -2
- package/dist/{default-normalizer-DNOpRoOF.mjs.map → default-normalizer-C8XyZj85.mjs.map} +1 -1
- package/dist/default-normalizer.d.mts +0 -1
- package/dist/default-normalizer.d.mts.map +1 -1
- package/dist/default-normalizer.mjs +2 -3
- package/dist/descriptor-meta-Dde_BS3K.mjs +99 -0
- package/dist/descriptor-meta-Dde_BS3K.mjs.map +1 -0
- package/dist/{errors-AFvEPZ1R.mjs → errors-Chm2bKcS.mjs} +2 -3
- package/dist/{errors-AFvEPZ1R.mjs.map → errors-Chm2bKcS.mjs.map} +1 -1
- package/dist/errors.d.mts +0 -1
- package/dist/errors.d.mts.map +1 -1
- package/dist/errors.mjs +2 -3
- package/dist/{issue-planner-CFjB0_oO.mjs → issue-planner-DQ6WJkad.mjs} +24 -91
- package/dist/issue-planner-DQ6WJkad.mjs.map +1 -0
- package/dist/issue-planner.d.mts +4 -7
- package/dist/issue-planner.d.mts.map +1 -1
- package/dist/issue-planner.mjs +2 -3
- package/dist/migration.d.mts +29 -5
- package/dist/migration.d.mts.map +1 -1
- package/dist/migration.mjs +5 -6
- package/dist/migration.mjs.map +1 -1
- package/dist/{native-type-normalizer-CInai_oY.mjs → native-type-normalizer-Cry4QoLf.mjs} +2 -2
- package/dist/native-type-normalizer-Cry4QoLf.mjs.map +1 -0
- package/dist/native-type-normalizer.d.mts.map +1 -1
- package/dist/native-type-normalizer.mjs +2 -3
- package/dist/{op-factory-call-BKlruaiC.mjs → op-factory-call-DeaFxa8_.mjs} +27 -10
- package/dist/op-factory-call-DeaFxa8_.mjs.map +1 -0
- package/dist/{op-factory-call-C3bWXKSP.d.mts → op-factory-call-UFpUPJL6.d.mts} +11 -8
- package/dist/op-factory-call-UFpUPJL6.d.mts.map +1 -0
- package/dist/op-factory-call.d.mts +1 -2
- package/dist/op-factory-call.mjs +2 -3
- package/dist/pack.d.mts +28 -9
- package/dist/pack.d.mts.map +1 -1
- package/dist/pack.mjs +2 -3
- package/dist/{planner-CLUvVhUN.mjs → planner-CYtKhLYa.mjs} +22 -16
- package/dist/planner-CYtKhLYa.mjs.map +1 -0
- package/dist/{planner-ddl-builders-Dxvw1LHw.mjs → planner-ddl-builders-CLB7Umhh.mjs} +4 -5
- package/dist/planner-ddl-builders-CLB7Umhh.mjs.map +1 -0
- package/dist/planner-ddl-builders.d.mts +1 -1
- package/dist/planner-ddl-builders.d.mts.map +1 -1
- package/dist/planner-ddl-builders.mjs +2 -3
- package/dist/{planner-identity-values-Dju-o5GF.mjs → planner-identity-values-DTx0gePL.mjs} +2 -3
- package/dist/{planner-identity-values-Dju-o5GF.mjs.map → planner-identity-values-DTx0gePL.mjs.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-identity-values.mjs +2 -3
- package/dist/{planner-produced-postgres-migration-CRRTno6Z.d.mts → planner-produced-postgres-migration-CjxWIVgh.d.mts} +11 -7
- package/dist/planner-produced-postgres-migration-CjxWIVgh.d.mts.map +1 -0
- package/dist/{planner-produced-postgres-migration-DSSPq8QS.mjs → planner-produced-postgres-migration-DphktB2N.mjs} +16 -8
- package/dist/planner-produced-postgres-migration-DphktB2N.mjs.map +1 -0
- package/dist/planner-produced-postgres-migration.d.mts +1 -4
- package/dist/planner-produced-postgres-migration.mjs +2 -3
- package/dist/{planner-schema-lookup-B7lkypwn.mjs → planner-schema-lookup-B1ags8ys.mjs} +2 -2
- package/dist/{planner-schema-lookup-B7lkypwn.mjs.map → planner-schema-lookup-B1ags8ys.mjs.map} +1 -1
- package/dist/planner-schema-lookup.d.mts +0 -1
- package/dist/planner-schema-lookup.d.mts.map +1 -1
- package/dist/planner-schema-lookup.mjs +2 -3
- package/dist/{planner-sql-checks-7jkgm9TX.mjs → planner-sql-checks-DwZvGlV4.mjs} +3 -5
- package/dist/planner-sql-checks-DwZvGlV4.mjs.map +1 -0
- package/dist/planner-sql-checks.d.mts.map +1 -1
- package/dist/planner-sql-checks.mjs +2 -3
- package/dist/{planner-target-details-DH-azLu-.d.mts → planner-target-details-bVVcanWh.d.mts} +1 -1
- package/dist/planner-target-details-bVVcanWh.d.mts.map +1 -0
- package/dist/planner-target-details.d.mts +1 -1
- package/dist/planner-target-details.mjs +1 -1
- package/dist/planner.d.mts +21 -12
- package/dist/planner.d.mts.map +1 -1
- package/dist/planner.mjs +2 -4
- package/dist/{postgres-migration-qtmtbONe.mjs → postgres-migration-Bkv140RW.mjs} +4 -5
- package/dist/postgres-migration-Bkv140RW.mjs.map +1 -0
- package/dist/{postgres-migration-BjA3Zmts.d.mts → postgres-migration-UkcHfZAA.d.mts} +6 -6
- package/dist/postgres-migration-UkcHfZAA.d.mts.map +1 -0
- package/dist/render-ops--1nnfNus.mjs +23 -0
- package/dist/render-ops--1nnfNus.mjs.map +1 -0
- package/dist/render-ops.d.mts +3 -4
- package/dist/render-ops.d.mts.map +1 -1
- package/dist/render-ops.mjs +2 -3
- package/dist/{render-typescript-1rF_SB4g.mjs → render-typescript-D3doH-vX.mjs} +2 -14
- package/dist/render-typescript-D3doH-vX.mjs.map +1 -0
- package/dist/render-typescript.d.mts +3 -6
- package/dist/render-typescript.d.mts.map +1 -1
- package/dist/render-typescript.mjs +2 -3
- package/dist/runtime.d.mts +5 -9
- package/dist/runtime.d.mts.map +1 -1
- package/dist/runtime.mjs +7 -14
- package/dist/runtime.mjs.map +1 -1
- package/dist/{shared-Bxkt8pNO.d.mts → shared-MpwjwAjM.d.mts} +2 -2
- package/dist/shared-MpwjwAjM.d.mts.map +1 -0
- package/dist/{sql-utils-r-Lw535w.mjs → sql-utils-CggjWNij.mjs} +4 -2
- package/dist/sql-utils-CggjWNij.mjs.map +1 -0
- package/dist/sql-utils.d.mts.map +1 -1
- package/dist/sql-utils.mjs +2 -3
- package/dist/{statement-builders-BPnmt6wx.mjs → statement-builders-BT889jV0.mjs} +28 -13
- package/dist/statement-builders-BT889jV0.mjs.map +1 -0
- package/dist/statement-builders.d.mts +31 -3
- package/dist/statement-builders.d.mts.map +1 -1
- package/dist/statement-builders.mjs +2 -3
- package/dist/{tables-BmdW_FWO.mjs → tables-DgYIXjUt.mjs} +53 -14
- package/dist/tables-DgYIXjUt.mjs.map +1 -0
- package/dist/{types-ClK03Ojd.d.mts → types-CTqpysRY.d.mts} +1 -1
- package/dist/types-CTqpysRY.d.mts.map +1 -0
- package/dist/types.d.mts +1 -1
- package/dist/types.mjs +1 -1
- package/package.json +21 -19
- package/src/core/authoring.ts +5 -11
- package/src/core/codec-helpers.ts +135 -0
- package/src/core/codec-ids.ts +1 -0
- package/src/core/codec-type-map.ts +81 -0
- package/src/core/codecs.ts +941 -547
- package/src/core/descriptor-meta.ts +1 -1
- package/src/core/migrations/issue-planner.ts +23 -35
- package/src/core/migrations/op-factory-call.ts +26 -5
- package/src/core/migrations/operations/data-transform.ts +86 -21
- package/src/core/migrations/operations/dependencies.ts +52 -0
- package/src/core/migrations/operations/indexes.ts +27 -2
- package/src/core/migrations/planner-produced-postgres-migration.ts +17 -5
- package/src/core/migrations/planner-strategies.ts +4 -86
- package/src/core/migrations/planner.ts +62 -20
- package/src/core/migrations/postgres-migration.ts +3 -6
- package/src/core/migrations/render-ops.ts +26 -3
- package/src/core/migrations/render-typescript.ts +5 -9
- package/src/core/migrations/runner.ts +172 -151
- package/src/core/migrations/statement-builders.ts +49 -10
- package/src/core/registry.ts +11 -0
- package/src/exports/codec-types.ts +4 -13
- package/src/exports/codecs.ts +49 -2
- package/src/exports/control.ts +0 -1
- package/src/exports/migration.ts +5 -1
- package/src/exports/runtime.ts +6 -11
- package/src/exports/statement-builders.ts +2 -1
- package/dist/codec-ids.d.mts.map +0 -1
- package/dist/codec-types.d.mts.map +0 -1
- package/dist/codecs-BQEm9_oo.d.mts +0 -319
- package/dist/codecs-BQEm9_oo.d.mts.map +0 -1
- package/dist/codecs-BoahtY_Q.mjs +0 -385
- package/dist/codecs-BoahtY_Q.mjs.map +0 -1
- package/dist/data-transform-CxFRBIUp.d.mts +0 -32
- package/dist/data-transform-CxFRBIUp.d.mts.map +0 -1
- package/dist/data-transform-VfEGzXWt.mjs.map +0 -1
- package/dist/descriptor-meta-BVoVtyp-.mjs +0 -120
- package/dist/descriptor-meta-BVoVtyp-.mjs.map +0 -1
- package/dist/issue-planner-CFjB0_oO.mjs.map +0 -1
- package/dist/native-type-normalizer-CInai_oY.mjs.map +0 -1
- package/dist/op-factory-call-BKlruaiC.mjs.map +0 -1
- package/dist/op-factory-call-C3bWXKSP.d.mts.map +0 -1
- package/dist/planner-CLUvVhUN.mjs.map +0 -1
- package/dist/planner-ddl-builders-Dxvw1LHw.mjs.map +0 -1
- package/dist/planner-produced-postgres-migration-CRRTno6Z.d.mts.map +0 -1
- package/dist/planner-produced-postgres-migration-DSSPq8QS.mjs.map +0 -1
- package/dist/planner-sql-checks-7jkgm9TX.mjs.map +0 -1
- package/dist/planner-target-details-DH-azLu-.d.mts.map +0 -1
- package/dist/postgres-migration-BjA3Zmts.d.mts.map +0 -1
- package/dist/postgres-migration-qtmtbONe.mjs.map +0 -1
- package/dist/render-ops-D6_DHdOK.mjs +0 -8
- package/dist/render-ops-D6_DHdOK.mjs.map +0 -1
- package/dist/render-typescript-1rF_SB4g.mjs.map +0 -1
- package/dist/shared-Bxkt8pNO.d.mts.map +0 -1
- package/dist/sql-utils-r-Lw535w.mjs.map +0 -1
- package/dist/statement-builders-BPnmt6wx.mjs.map +0 -1
- package/dist/tables-BmdW_FWO.mjs.map +0 -1
- package/dist/types-ClK03Ojd.d.mts.map +0 -1
- package/src/core/json-schema-type-expression.ts +0 -131
|
@@ -15,6 +15,7 @@ import type {
|
|
|
15
15
|
SqlPlannerConflict,
|
|
16
16
|
SqlPlannerConflictLocation,
|
|
17
17
|
} from '@prisma-next/family-sql/control';
|
|
18
|
+
import { arraysEqual } from '@prisma-next/family-sql/schema-verify';
|
|
18
19
|
import type { TargetBoundComponentDescriptor } from '@prisma-next/framework-components/components';
|
|
19
20
|
import type { SchemaIssue } from '@prisma-next/framework-components/control';
|
|
20
21
|
import type {
|
|
@@ -32,9 +33,7 @@ import {
|
|
|
32
33
|
AddUniqueCall,
|
|
33
34
|
AlterColumnTypeCall,
|
|
34
35
|
CreateEnumTypeCall,
|
|
35
|
-
CreateExtensionCall,
|
|
36
36
|
CreateIndexCall,
|
|
37
|
-
CreateSchemaCall,
|
|
38
37
|
CreateTableCall,
|
|
39
38
|
DropColumnCall,
|
|
40
39
|
DropConstraintCall,
|
|
@@ -62,8 +61,7 @@ export type { CallMigrationStrategy, StrategyContext };
|
|
|
62
61
|
// ============================================================================
|
|
63
62
|
|
|
64
63
|
const ISSUE_KIND_ORDER: Record<string, number> = {
|
|
65
|
-
//
|
|
66
|
-
dependency_missing: 1,
|
|
64
|
+
// Types first
|
|
67
65
|
type_missing: 2,
|
|
68
66
|
type_values_mismatch: 3,
|
|
69
67
|
enum_values_changed: 3,
|
|
@@ -149,9 +147,8 @@ export interface IssuePlannerOptions {
|
|
|
149
147
|
*/
|
|
150
148
|
readonly policy?: MigrationOperationPolicy;
|
|
151
149
|
/**
|
|
152
|
-
* Framework components participating in this composition.
|
|
153
|
-
*
|
|
154
|
-
* plan time.
|
|
150
|
+
* Framework components participating in this composition. Available to
|
|
151
|
+
* future strategies that may consult component metadata at plan time.
|
|
155
152
|
*/
|
|
156
153
|
readonly frameworkComponents?: ReadonlyArray<TargetBoundComponentDescriptor<'sql', string>>;
|
|
157
154
|
readonly strategies?: readonly CallMigrationStrategy[];
|
|
@@ -211,7 +208,12 @@ function mapIssueToCall(
|
|
|
211
208
|
];
|
|
212
209
|
for (const index of contractTable.indexes) {
|
|
213
210
|
const indexName = index.name ?? `${issue.table}_${index.columns.join('_')}_idx`;
|
|
214
|
-
|
|
211
|
+
const extras: { type?: string; options?: Record<string, unknown> } = {};
|
|
212
|
+
if (index.type !== undefined) extras.type = index.type;
|
|
213
|
+
if (index.options !== undefined) extras.options = index.options;
|
|
214
|
+
calls.push(
|
|
215
|
+
new CreateIndexCall(schemaName, issue.table, indexName, [...index.columns], extras),
|
|
216
|
+
);
|
|
215
217
|
}
|
|
216
218
|
const explicitIndexColumnSets = new Set(
|
|
217
219
|
contractTable.indexes.map((idx) => idx.columns.join(',')),
|
|
@@ -446,8 +448,14 @@ function mapIssueToCall(
|
|
|
446
448
|
return notOk(issueConflict('indexIncompatible', 'Index issue has no table name'));
|
|
447
449
|
if (isMissing(issue) && issue.expected) {
|
|
448
450
|
const columns = issue.expected.split(', ');
|
|
449
|
-
const
|
|
450
|
-
|
|
451
|
+
const contractIndex = ctx.toContract.storage.tables[issue.table]?.indexes.find((idx) =>
|
|
452
|
+
arraysEqual(idx.columns, columns),
|
|
453
|
+
);
|
|
454
|
+
const indexName = contractIndex?.name ?? `${issue.table}_${columns.join('_')}_idx`;
|
|
455
|
+
const extras: { type?: string; options?: Record<string, unknown> } = {};
|
|
456
|
+
if (contractIndex?.type !== undefined) extras.type = contractIndex.type;
|
|
457
|
+
if (contractIndex?.options !== undefined) extras.options = contractIndex.options;
|
|
458
|
+
return ok([new CreateIndexCall(schemaName, issue.table, indexName, columns, extras)]);
|
|
451
459
|
}
|
|
452
460
|
return notOk(
|
|
453
461
|
issueConflict(
|
|
@@ -527,21 +535,6 @@ function mapIssueToCall(
|
|
|
527
535
|
),
|
|
528
536
|
);
|
|
529
537
|
|
|
530
|
-
case 'dependency_missing':
|
|
531
|
-
if (!issue.dependencyId)
|
|
532
|
-
return notOk(
|
|
533
|
-
issueConflict('unsupportedOperation', 'Dependency missing issue has no dependencyId'),
|
|
534
|
-
);
|
|
535
|
-
if (issue.dependencyId.startsWith('ext:')) {
|
|
536
|
-
return ok([new CreateExtensionCall(issue.dependencyId.slice(4))]);
|
|
537
|
-
}
|
|
538
|
-
if (issue.dependencyId.startsWith('schema:')) {
|
|
539
|
-
return ok([new CreateSchemaCall(issue.dependencyId.slice(7))]);
|
|
540
|
-
}
|
|
541
|
-
return notOk(
|
|
542
|
-
issueConflict('unsupportedOperation', `Unknown dependency type: ${issue.dependencyId}`),
|
|
543
|
-
);
|
|
544
|
-
|
|
545
538
|
default:
|
|
546
539
|
return notOk(
|
|
547
540
|
issueConflict(
|
|
@@ -605,24 +598,19 @@ function classifyCall(call: PostgresOpFactoryCall): CallCategory {
|
|
|
605
598
|
case 'addForeignKey':
|
|
606
599
|
return 'foreignKey';
|
|
607
600
|
case 'rawSql': {
|
|
608
|
-
//
|
|
609
|
-
//
|
|
610
|
-
//
|
|
611
|
-
//
|
|
612
|
-
// underlying op's target details (`objectType: 'type'`) and id prefix
|
|
613
|
-
// (`extension.*` / `schema.*`).
|
|
601
|
+
// Type ops lifted through `RawSqlCall` by `storageTypePlanCallStrategy`
|
|
602
|
+
// to preserve the codec-emitted label and precheck/postcheck.
|
|
603
|
+
// Classification falls back to inspecting the underlying op's target
|
|
604
|
+
// details (`objectType: 'type'`).
|
|
614
605
|
const op = (
|
|
615
606
|
call as {
|
|
616
607
|
op?: {
|
|
617
|
-
id?: string;
|
|
618
608
|
target?: { details?: { objectType?: string } };
|
|
619
609
|
};
|
|
620
610
|
}
|
|
621
611
|
).op;
|
|
622
612
|
const objectType = op?.target?.details?.objectType;
|
|
623
613
|
if (objectType === 'type') return 'dep';
|
|
624
|
-
const id = typeof op?.id === 'string' ? op.id : '';
|
|
625
|
-
if (id.startsWith('extension.') || id.startsWith('schema.')) return 'dep';
|
|
626
614
|
return 'alter';
|
|
627
615
|
}
|
|
628
616
|
default:
|
|
@@ -651,7 +639,7 @@ const DEFAULT_POLICY: MigrationOperationPolicy = {
|
|
|
651
639
|
};
|
|
652
640
|
|
|
653
641
|
function emptySchemaIR(): SqlSchemaIR {
|
|
654
|
-
return { tables: {}
|
|
642
|
+
return { tables: {} };
|
|
655
643
|
}
|
|
656
644
|
|
|
657
645
|
function conflictKindForCall(call: PostgresOpFactoryCall): SqlPlannerConflict['kind'] {
|
|
@@ -506,6 +506,10 @@ export class CreateIndexCall extends PostgresOpFactoryCallNode {
|
|
|
506
506
|
readonly tableName: string;
|
|
507
507
|
readonly indexName: string;
|
|
508
508
|
readonly columns: readonly string[];
|
|
509
|
+
// Named indexType (not typeName) to avoid collision with CreateEnumTypeCall.typeName,
|
|
510
|
+
// which identifies a CREATE TYPE target and is read by `locationForCall` in issue-planner.ts.
|
|
511
|
+
readonly indexType: string | undefined;
|
|
512
|
+
readonly options: Record<string, unknown> | undefined;
|
|
509
513
|
readonly label: string;
|
|
510
514
|
|
|
511
515
|
constructor(
|
|
@@ -513,22 +517,40 @@ export class CreateIndexCall extends PostgresOpFactoryCallNode {
|
|
|
513
517
|
tableName: string,
|
|
514
518
|
indexName: string,
|
|
515
519
|
columns: readonly string[],
|
|
520
|
+
extras?: { readonly type?: string; readonly options?: Record<string, unknown> },
|
|
516
521
|
) {
|
|
517
522
|
super();
|
|
518
523
|
this.schemaName = schemaName;
|
|
519
524
|
this.tableName = tableName;
|
|
520
525
|
this.indexName = indexName;
|
|
521
526
|
this.columns = columns;
|
|
527
|
+
this.indexType = extras?.type;
|
|
528
|
+
this.options = extras?.options;
|
|
522
529
|
this.label = `Create index "${indexName}" on "${tableName}"`;
|
|
523
530
|
this.freeze();
|
|
524
531
|
}
|
|
525
532
|
|
|
526
533
|
toOp(): Op {
|
|
527
|
-
|
|
534
|
+
const extras: { type?: string; options?: Record<string, unknown> } = {};
|
|
535
|
+
if (this.indexType !== undefined) extras.type = this.indexType;
|
|
536
|
+
if (this.options !== undefined) extras.options = this.options;
|
|
537
|
+
return createIndex(this.schemaName, this.tableName, this.indexName, this.columns, extras);
|
|
528
538
|
}
|
|
529
539
|
|
|
530
540
|
renderTypeScript(): string {
|
|
531
|
-
|
|
541
|
+
const args = [
|
|
542
|
+
jsonToTsSource(this.schemaName),
|
|
543
|
+
jsonToTsSource(this.tableName),
|
|
544
|
+
jsonToTsSource(this.indexName),
|
|
545
|
+
jsonToTsSource(this.columns),
|
|
546
|
+
];
|
|
547
|
+
if (this.indexType !== undefined || this.options !== undefined) {
|
|
548
|
+
const extrasParts: string[] = [];
|
|
549
|
+
if (this.indexType !== undefined) extrasParts.push(`type: ${jsonToTsSource(this.indexType)}`);
|
|
550
|
+
if (this.options !== undefined) extrasParts.push(`options: ${jsonToTsSource(this.options)}`);
|
|
551
|
+
args.push(`{ ${extrasParts.join(', ')} }`);
|
|
552
|
+
}
|
|
553
|
+
return `createIndex(${args.join(', ')})`;
|
|
532
554
|
}
|
|
533
555
|
}
|
|
534
556
|
|
|
@@ -674,9 +696,8 @@ export class RenameTypeCall extends PostgresOpFactoryCallNode {
|
|
|
674
696
|
* Laundered pre-built operation.
|
|
675
697
|
*
|
|
676
698
|
* Wraps an already-materialized `SqlMigrationPlanOperation` — typically one
|
|
677
|
-
* produced by a SQL-family method
|
|
678
|
-
*
|
|
679
|
-
* alongside IR nodes without reverse-engineering it into a
|
|
699
|
+
* produced by a SQL-family method or a codec control hook — so the planner
|
|
700
|
+
* can carry it alongside IR nodes without reverse-engineering it into a
|
|
680
701
|
* structured call class. Doubles as the user-facing escape hatch for raw
|
|
681
702
|
* migrations: authors can pass a full op shape to `rawSql({...})`.
|
|
682
703
|
*
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* override get operations() {
|
|
12
12
|
* return [
|
|
13
13
|
* this.dataTransform(endContract, 'backfill emails', {
|
|
14
|
-
* check: () => db.users.
|
|
14
|
+
* check: () => db.users.select('id').where(({ email }) => email.isNull()).limit(1),
|
|
15
15
|
* run: () => db.users.update({ email: '' }).where(({ email }) => email.isNull()),
|
|
16
16
|
* }),
|
|
17
17
|
* ];
|
|
@@ -23,20 +23,49 @@
|
|
|
23
23
|
* invokes each one, asserts that its `meta.storageHash` matches the
|
|
24
24
|
* `contract` it was handed (→ `PN-MIG-2005` on mismatch), and lowers the
|
|
25
25
|
* plan via the supplied control adapter to a serialized `{sql, params}`
|
|
26
|
-
* payload
|
|
27
|
-
*
|
|
28
|
-
*
|
|
26
|
+
* payload.
|
|
27
|
+
*
|
|
28
|
+
* The factory then lowers the data transform to the unified migration-op
|
|
29
|
+
* shape `{ precheck, execute, postcheck }`. The user's `check` plan is
|
|
30
|
+
* wrapped twice with opposite truth values:
|
|
31
|
+
*
|
|
32
|
+
* - precheck `SELECT EXISTS (<check>) AS ok` asserts there is work to do
|
|
33
|
+
* (precheck is short-circuited by the runner's pre-satisfied-skip path
|
|
34
|
+
* when nothing remains to backfill).
|
|
35
|
+
* - postcheck `SELECT NOT EXISTS (<check>) AS ok` asserts the work is
|
|
36
|
+
* complete after the run steps execute.
|
|
37
|
+
*
|
|
38
|
+
* The `check` plan is therefore expected to be a **rowset query whose
|
|
39
|
+
* presence of any row signals "work remains"** — typically `select('id')
|
|
40
|
+
* .where(<violation predicate>).limit(1)`. Scalar/aggregate shapes
|
|
41
|
+
* (`count(*)`, `bool_and(...)`) do not work under this contract: they
|
|
42
|
+
* always return exactly one row, so `EXISTS` is always true and
|
|
43
|
+
* `NOT EXISTS` is always false. (This is the same row-presence contract
|
|
44
|
+
* the pre-unification runner relied on; the wrapping is just lifting it
|
|
45
|
+
* into SQL.)
|
|
46
|
+
*
|
|
47
|
+
* Each `run` plan becomes an execute step. Because the `Step.params`
|
|
48
|
+
* field threads through `driver.query(sql, params)`, the user's bound
|
|
49
|
+
* values flow through the driver's parameter binder rather than being
|
|
50
|
+
* inlined into the SQL text.
|
|
51
|
+
*
|
|
52
|
+
* The free factory remains usable standalone (tests, ad-hoc tooling,
|
|
53
|
+
* non-class contexts) by passing the adapter explicitly as the fourth
|
|
54
|
+
* argument.
|
|
29
55
|
*/
|
|
30
56
|
|
|
31
57
|
import type { Contract } from '@prisma-next/contract/types';
|
|
32
58
|
import { errorDataTransformContractMismatch } from '@prisma-next/errors/migration';
|
|
33
|
-
import type { SqlControlAdapter } from '@prisma-next/family-sql/control-adapter';
|
|
34
59
|
import type {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
} from '@prisma-next/
|
|
60
|
+
SqlMigrationPlanOperation,
|
|
61
|
+
SqlMigrationPlanOperationStep,
|
|
62
|
+
} from '@prisma-next/family-sql/control';
|
|
63
|
+
import type { SqlControlAdapter } from '@prisma-next/family-sql/control-adapter';
|
|
64
|
+
import type { SerializedQueryPlan } from '@prisma-next/framework-components/control';
|
|
38
65
|
import type { SqlStorage } from '@prisma-next/sql-contract/types';
|
|
39
66
|
import type { SqlQueryPlan } from '@prisma-next/sql-relational-core/plan';
|
|
67
|
+
import { ifDefined } from '@prisma-next/utils/defined';
|
|
68
|
+
import type { PostgresPlanTargetDetails } from '../planner-target-details';
|
|
40
69
|
|
|
41
70
|
interface Buildable<R = unknown> {
|
|
42
71
|
build(): SqlQueryPlan<R>;
|
|
@@ -49,36 +78,72 @@ interface Buildable<R = unknown> {
|
|
|
49
78
|
export type DataTransformClosure = () => SqlQueryPlan | Buildable;
|
|
50
79
|
|
|
51
80
|
export interface DataTransformOptions {
|
|
52
|
-
/**
|
|
81
|
+
/**
|
|
82
|
+
* Optional opt-in routing identity. Presence opts the transform into
|
|
83
|
+
* invariant-aware routing; absence means it is path-dependent and
|
|
84
|
+
* not referenceable from refs.
|
|
85
|
+
*/
|
|
86
|
+
readonly invariantId?: string;
|
|
87
|
+
/**
|
|
88
|
+
* Optional pre-flight query. `undefined` means "no check". When
|
|
89
|
+
* supplied, the closure must return a **rowset query** whose
|
|
90
|
+
* presence of any row signals "violations remain". Conventional
|
|
91
|
+
* shape: `db.<table>.select('id').where(<violation>).limit(1)`.
|
|
92
|
+
* Scalar/aggregate shapes do not satisfy this contract.
|
|
93
|
+
*/
|
|
53
94
|
readonly check?: DataTransformClosure;
|
|
54
95
|
/** One or more mutation queries to execute. */
|
|
55
96
|
readonly run: DataTransformClosure | readonly DataTransformClosure[];
|
|
56
97
|
}
|
|
57
98
|
|
|
58
|
-
/**
|
|
59
|
-
* Concrete Postgres flavor of `DataTransformOperation`, re-exported so the
|
|
60
|
-
* `PostgresMigration.dataTransform` instance method can name it without
|
|
61
|
-
* leaking the framework-components symbol into call sites.
|
|
62
|
-
*/
|
|
63
|
-
export type PostgresDataTransformOperation = DataTransformOperation;
|
|
64
|
-
|
|
65
99
|
export function dataTransform<TContract extends Contract<SqlStorage>>(
|
|
66
100
|
contract: TContract,
|
|
67
101
|
name: string,
|
|
68
102
|
options: DataTransformOptions,
|
|
69
103
|
adapter: SqlControlAdapter<'postgres'>,
|
|
70
|
-
):
|
|
104
|
+
): SqlMigrationPlanOperation<PostgresPlanTargetDetails> {
|
|
71
105
|
const runClosures: readonly DataTransformClosure[] = Array.isArray(options.run)
|
|
72
106
|
? options.run
|
|
73
107
|
: [options.run as DataTransformClosure];
|
|
108
|
+
|
|
109
|
+
const checkPlan = options.check ? invokeAndLower(options.check, contract, adapter, name) : null;
|
|
110
|
+
const runPlans = runClosures.map((closure) => invokeAndLower(closure, contract, adapter, name));
|
|
111
|
+
|
|
112
|
+
const precheck: readonly SqlMigrationPlanOperationStep[] = checkPlan
|
|
113
|
+
? [
|
|
114
|
+
{
|
|
115
|
+
description: `Check ${name} has work to do`,
|
|
116
|
+
sql: `SELECT EXISTS (${checkPlan.sql}) AS ok`,
|
|
117
|
+
params: checkPlan.params,
|
|
118
|
+
},
|
|
119
|
+
]
|
|
120
|
+
: [];
|
|
121
|
+
|
|
122
|
+
const execute: readonly SqlMigrationPlanOperationStep[] = runPlans.map((plan) => ({
|
|
123
|
+
description: `Run ${name}`,
|
|
124
|
+
sql: plan.sql,
|
|
125
|
+
params: plan.params,
|
|
126
|
+
}));
|
|
127
|
+
|
|
128
|
+
const postcheck: readonly SqlMigrationPlanOperationStep[] = checkPlan
|
|
129
|
+
? [
|
|
130
|
+
{
|
|
131
|
+
description: `Verify ${name} resolved all violations`,
|
|
132
|
+
sql: `SELECT NOT EXISTS (${checkPlan.sql}) AS ok`,
|
|
133
|
+
params: checkPlan.params,
|
|
134
|
+
},
|
|
135
|
+
]
|
|
136
|
+
: [];
|
|
137
|
+
|
|
74
138
|
return {
|
|
75
139
|
id: `data_migration.${name}`,
|
|
76
140
|
label: `Data transform: ${name}`,
|
|
77
141
|
operationClass: 'data',
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
142
|
+
...ifDefined('invariantId', options.invariantId),
|
|
143
|
+
target: { id: 'postgres' },
|
|
144
|
+
precheck,
|
|
145
|
+
execute,
|
|
146
|
+
postcheck,
|
|
82
147
|
};
|
|
83
148
|
}
|
|
84
149
|
|
|
@@ -18,6 +18,58 @@ export function createExtension(extensionName: string): Op {
|
|
|
18
18
|
};
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
+
/**
|
|
22
|
+
* Install a Postgres extension as the baseline op for an extension-pack
|
|
23
|
+
* contract space. Layered on top of {@link createExtension}: stamps an
|
|
24
|
+
* `invariantId` (required so the per-space marker records the install),
|
|
25
|
+
* scopes the op `id` under a caller-chosen namespace (e.g. `pgvector.`),
|
|
26
|
+
* and emits pre- and postcheck SQL probing `pg_extension`. The richer
|
|
27
|
+
* shape lets the runner's idempotency probe skip the install on re-run
|
|
28
|
+
* (postcheck-pre-satisfied) without firing the precheck.
|
|
29
|
+
*
|
|
30
|
+
* Use this for hand-rolled baseline migrations in contract-space
|
|
31
|
+
* extension packages (e.g. `extension-pgvector`, `extension-paradedb`);
|
|
32
|
+
* use the bare {@link createExtension} for planner-emitted ops where the
|
|
33
|
+
* caller already controls idempotency through the surrounding plan.
|
|
34
|
+
*/
|
|
35
|
+
export function installExtension(options: {
|
|
36
|
+
readonly extensionName: string;
|
|
37
|
+
readonly invariantId: string;
|
|
38
|
+
readonly id: string;
|
|
39
|
+
readonly label?: string;
|
|
40
|
+
}): Op {
|
|
41
|
+
const { extensionName, invariantId, id } = options;
|
|
42
|
+
const label = options.label ?? `Enable extension "${extensionName}"`;
|
|
43
|
+
return {
|
|
44
|
+
id,
|
|
45
|
+
label,
|
|
46
|
+
operationClass: 'additive',
|
|
47
|
+
invariantId,
|
|
48
|
+
target: {
|
|
49
|
+
id: 'postgres',
|
|
50
|
+
details: { schema: 'public', objectType: 'dependency', name: extensionName },
|
|
51
|
+
},
|
|
52
|
+
precheck: [
|
|
53
|
+
step(
|
|
54
|
+
`verify extension "${extensionName}" is not already enabled`,
|
|
55
|
+
`SELECT NOT EXISTS (SELECT 1 FROM pg_extension WHERE extname = '${extensionName}')`,
|
|
56
|
+
),
|
|
57
|
+
],
|
|
58
|
+
execute: [
|
|
59
|
+
step(
|
|
60
|
+
`create extension "${extensionName}"`,
|
|
61
|
+
`CREATE EXTENSION IF NOT EXISTS ${extensionName}`,
|
|
62
|
+
),
|
|
63
|
+
],
|
|
64
|
+
postcheck: [
|
|
65
|
+
step(
|
|
66
|
+
`confirm extension "${extensionName}" is enabled`,
|
|
67
|
+
`SELECT EXISTS (SELECT 1 FROM pg_extension WHERE extname = '${extensionName}')`,
|
|
68
|
+
),
|
|
69
|
+
],
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
21
73
|
export function createSchema(schemaName: string): Op {
|
|
22
74
|
return {
|
|
23
75
|
id: `schema.${schemaName}`,
|
|
@@ -1,15 +1,40 @@
|
|
|
1
|
-
import { quoteIdentifier } from '../../sql-utils';
|
|
1
|
+
import { escapeLiteral, quoteIdentifier } from '../../sql-utils';
|
|
2
2
|
import { qualifyTableName, toRegclassLiteral } from '../planner-sql-checks';
|
|
3
3
|
import { type Op, step, targetDetails } from './shared';
|
|
4
4
|
|
|
5
|
+
export interface CreateIndexExtras {
|
|
6
|
+
readonly type?: string;
|
|
7
|
+
readonly options?: Record<string, unknown>;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function renderIndexOptionValue(key: string, value: unknown): string {
|
|
11
|
+
if (typeof value === 'string') return `'${escapeLiteral(value)}'`;
|
|
12
|
+
if (typeof value === 'number' && Number.isFinite(value)) return String(value);
|
|
13
|
+
if (typeof value === 'boolean') return value ? 'true' : 'false';
|
|
14
|
+
throw new Error(
|
|
15
|
+
`Index option "${key}" must be a string, finite number, or boolean; got ${typeof value}`,
|
|
16
|
+
);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function renderIndexOptions(options: Record<string, unknown>): string {
|
|
20
|
+
return Object.entries(options)
|
|
21
|
+
.map(([key, value]) => `${quoteIdentifier(key)} = ${renderIndexOptionValue(key, value)}`)
|
|
22
|
+
.join(', ');
|
|
23
|
+
}
|
|
24
|
+
|
|
5
25
|
export function createIndex(
|
|
6
26
|
schemaName: string,
|
|
7
27
|
tableName: string,
|
|
8
28
|
indexName: string,
|
|
9
29
|
columns: readonly string[],
|
|
30
|
+
extras?: CreateIndexExtras,
|
|
10
31
|
): Op {
|
|
11
32
|
const qualified = qualifyTableName(schemaName, tableName);
|
|
12
33
|
const columnList = columns.map(quoteIdentifier).join(', ');
|
|
34
|
+
const using = extras?.type ? ` USING ${quoteIdentifier(extras.type)}` : '';
|
|
35
|
+
const options = extras?.options;
|
|
36
|
+
const withClause =
|
|
37
|
+
options && Object.keys(options).length > 0 ? ` WITH (${renderIndexOptions(options)})` : '';
|
|
13
38
|
return {
|
|
14
39
|
id: `index.${tableName}.${indexName}`,
|
|
15
40
|
label: `Create index "${indexName}" on "${tableName}"`,
|
|
@@ -24,7 +49,7 @@ export function createIndex(
|
|
|
24
49
|
execute: [
|
|
25
50
|
step(
|
|
26
51
|
`create index "${indexName}"`,
|
|
27
|
-
`CREATE INDEX ${quoteIdentifier(indexName)} ON ${qualified} (${columnList})`,
|
|
52
|
+
`CREATE INDEX ${quoteIdentifier(indexName)} ON ${qualified}${using} (${columnList})${withClause}`,
|
|
28
53
|
),
|
|
29
54
|
],
|
|
30
55
|
postcheck: [
|
|
@@ -24,10 +24,12 @@
|
|
|
24
24
|
*/
|
|
25
25
|
|
|
26
26
|
import type { SqlMigrationPlanOperation } from '@prisma-next/family-sql/control';
|
|
27
|
-
import type {
|
|
27
|
+
import type {
|
|
28
|
+
MigrationPlanWithAuthoringSurface,
|
|
29
|
+
OpFactoryCall,
|
|
30
|
+
} from '@prisma-next/framework-components/control';
|
|
28
31
|
import type { MigrationMeta } from '@prisma-next/migration-tools/migration';
|
|
29
32
|
import { ifDefined } from '@prisma-next/utils/defined';
|
|
30
|
-
import type { PostgresOpFactoryCall } from './op-factory-call';
|
|
31
33
|
import type { PostgresPlanTargetDetails } from './planner-target-details';
|
|
32
34
|
import { PostgresMigration } from './postgres-migration';
|
|
33
35
|
import { renderOps } from './render-ops';
|
|
@@ -39,13 +41,15 @@ export class TypeScriptRenderablePostgresMigration
|
|
|
39
41
|
extends PostgresMigration
|
|
40
42
|
implements MigrationPlanWithAuthoringSurface
|
|
41
43
|
{
|
|
42
|
-
readonly #calls: readonly
|
|
44
|
+
readonly #calls: readonly OpFactoryCall[];
|
|
43
45
|
readonly #meta: MigrationMeta;
|
|
46
|
+
readonly #spaceId: string;
|
|
44
47
|
|
|
45
|
-
constructor(calls: readonly
|
|
48
|
+
constructor(calls: readonly OpFactoryCall[], meta: MigrationMeta, spaceId: string) {
|
|
46
49
|
super();
|
|
47
50
|
this.#calls = calls;
|
|
48
51
|
this.#meta = meta;
|
|
52
|
+
this.#spaceId = spaceId;
|
|
49
53
|
}
|
|
50
54
|
|
|
51
55
|
override get operations(): readonly Op[] {
|
|
@@ -56,11 +60,19 @@ export class TypeScriptRenderablePostgresMigration
|
|
|
56
60
|
return this.#meta;
|
|
57
61
|
}
|
|
58
62
|
|
|
63
|
+
/**
|
|
64
|
+
* Contract space this planner-produced plan applies to. Threaded
|
|
65
|
+
* from the planner options so the runner keys the marker row by
|
|
66
|
+
* the right space when executing the plan.
|
|
67
|
+
*/
|
|
68
|
+
get spaceId(): string {
|
|
69
|
+
return this.#spaceId;
|
|
70
|
+
}
|
|
71
|
+
|
|
59
72
|
renderTypeScript(): string {
|
|
60
73
|
return renderCallsToTypeScript(this.#calls, {
|
|
61
74
|
from: this.#meta.from,
|
|
62
75
|
to: this.#meta.to,
|
|
63
|
-
...ifDefined('kind', this.#meta.kind),
|
|
64
76
|
...ifDefined('labels', this.#meta.labels),
|
|
65
77
|
});
|
|
66
78
|
}
|
|
@@ -14,19 +14,16 @@
|
|
|
14
14
|
* nullability tightening, unsafe type changes, enum shrink/rebuild) emit
|
|
15
15
|
* `DataTransformCall` placeholders that the user fills in.
|
|
16
16
|
* - When `'data'` is excluded, those strategies short-circuit so the
|
|
17
|
-
* downstream walk-schema strategies (codec-hook type ops
|
|
18
|
-
*
|
|
19
|
-
* direct DDL instead.
|
|
17
|
+
* downstream walk-schema strategies (codec-hook type ops and temp-default
|
|
18
|
+
* backfill) and `mapIssueToCall` defaults emit direct DDL instead.
|
|
20
19
|
*/
|
|
21
20
|
|
|
22
21
|
import type { Contract } from '@prisma-next/contract/types';
|
|
23
22
|
import type {
|
|
24
23
|
CodecControlHooks,
|
|
25
|
-
ComponentDatabaseDependency,
|
|
26
24
|
MigrationOperationPolicy,
|
|
27
25
|
SqlMigrationPlanOperation,
|
|
28
26
|
} from '@prisma-next/family-sql/control';
|
|
29
|
-
import { collectInitDependencies } from '@prisma-next/family-sql/control';
|
|
30
27
|
import type { TargetBoundComponentDescriptor } from '@prisma-next/framework-components/components';
|
|
31
28
|
import type { SchemaIssue } from '@prisma-next/framework-components/control';
|
|
32
29
|
import type { SqlStorage, StorageTypeInstance } from '@prisma-next/sql-contract/types';
|
|
@@ -428,47 +425,6 @@ export const storageTypePlanCallStrategy: CallMigrationStrategy = (issues, ctx)
|
|
|
428
425
|
return { kind: 'match', issues: remaining, calls };
|
|
429
426
|
};
|
|
430
427
|
|
|
431
|
-
/**
|
|
432
|
-
* Dispatches component-declared database dependencies. Replaces the
|
|
433
|
-
* walk-schema `buildDatabaseDependencyOperations` path. Rather than consuming
|
|
434
|
-
* `dependency_missing` issues (which only carry the id), this strategy
|
|
435
|
-
* re-invokes `collectInitDependencies(frameworkComponents)` at plan time so
|
|
436
|
-
* the handler has access to the structured `install` ops each component
|
|
437
|
-
* declared — including arbitrary SQL launders — and dedupes by dependency id
|
|
438
|
-
* plus per-op id.
|
|
439
|
-
*/
|
|
440
|
-
export const dependencyInstallCallStrategy: CallMigrationStrategy = (issues, ctx) => {
|
|
441
|
-
const installedIds = new Set(ctx.schema.dependencies.map((d) => d.id));
|
|
442
|
-
const dependencies = sortDependencies(
|
|
443
|
-
collectInitDependencies(ctx.frameworkComponents).filter(isPostgresPlannerDependency),
|
|
444
|
-
);
|
|
445
|
-
|
|
446
|
-
const calls: PostgresOpFactoryCall[] = [];
|
|
447
|
-
const handledDependencyIds = new Set<string>();
|
|
448
|
-
const seenOperationIds = new Set<string>();
|
|
449
|
-
|
|
450
|
-
for (const dep of dependencies) {
|
|
451
|
-
handledDependencyIds.add(dep.id);
|
|
452
|
-
if (installedIds.has(dep.id)) continue;
|
|
453
|
-
for (const installOp of dep.install) {
|
|
454
|
-
if (seenOperationIds.has(installOp.id)) continue;
|
|
455
|
-
seenOperationIds.add(installOp.id);
|
|
456
|
-
calls.push(liftInstallOpToCall(installOp));
|
|
457
|
-
}
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
// Consume ALL `dependency_missing` issues — even non-postgres ones. The
|
|
461
|
-
// walk-schema predecessor silently skipped non-postgres deps; leaving those
|
|
462
|
-
// issues in the stream would let `mapIssueToCall` reject them as
|
|
463
|
-
// "Unknown dependency type".
|
|
464
|
-
const remaining = issues.filter((issue) => issue.kind !== 'dependency_missing');
|
|
465
|
-
|
|
466
|
-
if (calls.length === 0 && remaining.length === issues.length) {
|
|
467
|
-
return { kind: 'no_match' };
|
|
468
|
-
}
|
|
469
|
-
return { kind: 'match', issues: remaining, calls };
|
|
470
|
-
};
|
|
471
|
-
|
|
472
428
|
/**
|
|
473
429
|
* Handles `missing_column` issues for NOT NULL columns without a contract
|
|
474
430
|
* default. Replaces the walk-schema `buildAddColumnItem` non-default branches.
|
|
@@ -633,43 +589,6 @@ function canUseSharedTemporaryDefaultStrategy(options: {
|
|
|
633
589
|
return true;
|
|
634
590
|
}
|
|
635
591
|
|
|
636
|
-
type PlannerDatabaseDependency = ComponentDatabaseDependency<unknown> & {
|
|
637
|
-
readonly install: readonly SqlMigrationPlanOperation<PostgresPlanTargetDetails>[];
|
|
638
|
-
};
|
|
639
|
-
|
|
640
|
-
function isPostgresPlannerDependency(
|
|
641
|
-
dependency: ComponentDatabaseDependency<unknown>,
|
|
642
|
-
): dependency is PlannerDatabaseDependency {
|
|
643
|
-
return dependency.install.every((operation) => operation.target.id === 'postgres');
|
|
644
|
-
}
|
|
645
|
-
|
|
646
|
-
function sortDependencies(
|
|
647
|
-
dependencies: ReadonlyArray<PlannerDatabaseDependency>,
|
|
648
|
-
): ReadonlyArray<PlannerDatabaseDependency> {
|
|
649
|
-
return [...dependencies].sort((a, b) => a.id.localeCompare(b.id));
|
|
650
|
-
}
|
|
651
|
-
|
|
652
|
-
/**
|
|
653
|
-
* Lift a component install op into migration IR. Structured shapes — extension
|
|
654
|
-
* and schema installs with predictable SQL — collapse to typed `*Call`
|
|
655
|
-
* subclasses so the scaffolded migration authoring surface stays readable.
|
|
656
|
-
* Everything else (arbitrary SQL) falls through to `RawSqlCall` as an escape
|
|
657
|
-
* hatch.
|
|
658
|
-
*/
|
|
659
|
-
/**
|
|
660
|
-
* Component-declared install ops are wrapped as `RawSqlCall` so the
|
|
661
|
-
* component's original `label`, `precheck`, `execute`, `postcheck`, and op
|
|
662
|
-
* id are preserved verbatim. Structured conversion (to e.g.
|
|
663
|
-
* `CreateExtensionCall`) would drop the precheck/postcheck pair and
|
|
664
|
-
* change the DDL label, breaking walk-schema output parity. Classification
|
|
665
|
-
* as `'dep'` happens in `classifyCall` via the underlying op's id prefix.
|
|
666
|
-
*/
|
|
667
|
-
function liftInstallOpToCall(
|
|
668
|
-
op: SqlMigrationPlanOperation<PostgresPlanTargetDetails>,
|
|
669
|
-
): PostgresOpFactoryCall {
|
|
670
|
-
return new RawSqlCall(op);
|
|
671
|
-
}
|
|
672
|
-
|
|
673
592
|
/**
|
|
674
593
|
* Ordered list of Postgres planner strategies, shared by `migration plan`
|
|
675
594
|
* and `db update` / `db init`. The issue planner runs each strategy in
|
|
@@ -685,8 +604,8 @@ function liftInstallOpToCall(
|
|
|
685
604
|
* - When `'data'` is not allowed (`db update` / `db init`), each data-safe
|
|
686
605
|
* strategy short-circuits to `no_match`, leaving the issue for the
|
|
687
606
|
* downstream walk-schema strategies (`storageTypePlanCallStrategy`,
|
|
688
|
-
* `
|
|
689
|
-
*
|
|
607
|
+
* `notNullAddColumnCallStrategy`) or the `mapIssueToCall` default to handle
|
|
608
|
+
* with direct DDL.
|
|
690
609
|
*
|
|
691
610
|
* Order matters: data-safe strategies must run before the walk-schema
|
|
692
611
|
* strategies on overlapping issue kinds (e.g. `enum_values_changed`,
|
|
@@ -698,6 +617,5 @@ export const postgresPlannerStrategies: readonly CallMigrationStrategy[] = [
|
|
|
698
617
|
typeChangeCallStrategy,
|
|
699
618
|
nullableTighteningCallStrategy,
|
|
700
619
|
storageTypePlanCallStrategy,
|
|
701
|
-
dependencyInstallCallStrategy,
|
|
702
620
|
notNullAddColumnCallStrategy,
|
|
703
621
|
];
|