@prisma-next/target-postgres 0.5.0-dev.7 → 0.5.0-dev.70
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 +131 -94
- 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-B10B70JF.mjs} +9 -13
- package/dist/issue-planner-B10B70JF.mjs.map +1 -0
- package/dist/issue-planner.d.mts +2 -4
- package/dist/issue-planner.d.mts.map +1 -1
- package/dist/issue-planner.mjs +2 -3
- package/dist/migration.d.mts +3 -3
- package/dist/migration.d.mts.map +1 -1
- package/dist/migration.mjs +4 -5
- 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-C3bWXKSP.d.mts → op-factory-call-CW8pzxmB.d.mts} +3 -4
- package/dist/op-factory-call-CW8pzxmB.d.mts.map +1 -0
- package/dist/{op-factory-call-BKlruaiC.mjs → op-factory-call-Cq8s4Fz1.mjs} +3 -4
- package/dist/{op-factory-call-BKlruaiC.mjs.map → op-factory-call-Cq8s4Fz1.mjs.map} +1 -1
- 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-JmqeNfGa.mjs} +23 -16
- package/dist/planner-JmqeNfGa.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-DSSPq8QS.mjs → planner-produced-postgres-migration-Br3NgwpH.mjs} +16 -8
- package/dist/planner-produced-postgres-migration-Br3NgwpH.mjs.map +1 -0
- package/dist/{planner-produced-postgres-migration-CRRTno6Z.d.mts → planner-produced-postgres-migration-D7Pe160c.d.mts} +11 -6
- package/dist/planner-produced-postgres-migration-D7Pe160c.d.mts.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-D6_DHdOK.mjs → render-ops-DXxV-PbF.mjs} +2 -2
- package/dist/{render-ops-D6_DHdOK.mjs.map → render-ops-DXxV-PbF.mjs.map} +1 -1
- package/dist/render-ops.d.mts +2 -3
- 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-pyz96rAY.mjs} +2 -4
- package/dist/render-typescript-pyz96rAY.mjs.map +1 -0
- package/dist/render-typescript.d.mts +2 -5
- 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-Ej122-iI.mjs} +4 -11
- package/dist/tables-Ej122-iI.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/operations/data-transform.ts +86 -21
- package/src/core/migrations/planner-produced-postgres-migration.ts +12 -2
- package/src/core/migrations/planner.ts +71 -20
- package/src/core/migrations/postgres-migration.ts +3 -6
- package/src/core/migrations/render-typescript.ts +1 -5
- 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/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-BoahtY_Q.mjs +0 -385
- package/dist/codecs-BoahtY_Q.mjs.map +0 -1
- package/dist/codecs-D-F2KJqt.d.mts +0 -299
- package/dist/codecs-D-F2KJqt.d.mts.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-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-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
|
@@ -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
|
|
|
@@ -41,11 +41,13 @@ export class TypeScriptRenderablePostgresMigration
|
|
|
41
41
|
{
|
|
42
42
|
readonly #calls: readonly PostgresOpFactoryCall[];
|
|
43
43
|
readonly #meta: MigrationMeta;
|
|
44
|
+
readonly #spaceId: string;
|
|
44
45
|
|
|
45
|
-
constructor(calls: readonly PostgresOpFactoryCall[], meta: MigrationMeta) {
|
|
46
|
+
constructor(calls: readonly PostgresOpFactoryCall[], meta: MigrationMeta, spaceId: string) {
|
|
46
47
|
super();
|
|
47
48
|
this.#calls = calls;
|
|
48
49
|
this.#meta = meta;
|
|
50
|
+
this.#spaceId = spaceId;
|
|
49
51
|
}
|
|
50
52
|
|
|
51
53
|
override get operations(): readonly Op[] {
|
|
@@ -56,11 +58,19 @@ export class TypeScriptRenderablePostgresMigration
|
|
|
56
58
|
return this.#meta;
|
|
57
59
|
}
|
|
58
60
|
|
|
61
|
+
/**
|
|
62
|
+
* Contract space this planner-produced plan applies to. Threaded
|
|
63
|
+
* from the planner options so the runner keys the marker row by
|
|
64
|
+
* the right space when executing the plan.
|
|
65
|
+
*/
|
|
66
|
+
get spaceId(): string {
|
|
67
|
+
return this.#spaceId;
|
|
68
|
+
}
|
|
69
|
+
|
|
59
70
|
renderTypeScript(): string {
|
|
60
71
|
return renderCallsToTypeScript(this.#calls, {
|
|
61
72
|
from: this.#meta.from,
|
|
62
73
|
to: this.#meta.to,
|
|
63
|
-
...ifDefined('kind', this.#meta.kind),
|
|
64
74
|
...ifDefined('labels', this.#meta.labels),
|
|
65
75
|
});
|
|
66
76
|
}
|
|
@@ -1,9 +1,15 @@
|
|
|
1
|
+
import type { Contract } from '@prisma-next/contract/types';
|
|
1
2
|
import type {
|
|
2
3
|
MigrationOperationPolicy,
|
|
3
4
|
SqlMigrationPlannerPlanOptions,
|
|
5
|
+
SqlMigrationPlanOperation,
|
|
4
6
|
SqlPlannerFailureResult,
|
|
5
7
|
} from '@prisma-next/family-sql/control';
|
|
6
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
extractCodecControlHooks,
|
|
10
|
+
planFieldEventOperations,
|
|
11
|
+
plannerFailure,
|
|
12
|
+
} from '@prisma-next/family-sql/control';
|
|
7
13
|
import { verifySqlSchema } from '@prisma-next/family-sql/schema-verify';
|
|
8
14
|
import type { TargetBoundComponentDescriptor } from '@prisma-next/framework-components/components';
|
|
9
15
|
import type {
|
|
@@ -15,8 +21,10 @@ import type {
|
|
|
15
21
|
import { parsePostgresDefault } from '../default-normalizer';
|
|
16
22
|
import { normalizeSchemaNativeType } from '../native-type-normalizer';
|
|
17
23
|
import { planIssues } from './issue-planner';
|
|
24
|
+
import { RawSqlCall } from './op-factory-call';
|
|
18
25
|
import { TypeScriptRenderablePostgresMigration } from './planner-produced-postgres-migration';
|
|
19
26
|
import { postgresPlannerStrategies } from './planner-strategies';
|
|
27
|
+
import type { PostgresPlanTargetDetails } from './planner-target-details';
|
|
20
28
|
|
|
21
29
|
type PlannerFrameworkComponents = SqlMigrationPlannerPlanOptions extends {
|
|
22
30
|
readonly frameworkComponents: infer T;
|
|
@@ -83,30 +91,48 @@ export class PostgresMigrationPlanner implements MigrationPlanner<'sql', 'postgr
|
|
|
83
91
|
readonly contract: unknown;
|
|
84
92
|
readonly schema: unknown;
|
|
85
93
|
readonly policy: MigrationOperationPolicy;
|
|
86
|
-
readonly fromHash?: string;
|
|
87
94
|
/**
|
|
88
95
|
* The "from" contract (state the planner assumes the database starts
|
|
89
|
-
* at)
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
-
* activate.
|
|
96
|
+
* at), or `null` for reconciliation flows. Only `migration plan` ever
|
|
97
|
+
* supplies a non-null value; `db update` / `db init` reconcile against
|
|
98
|
+
* the live schema and pass `null`. When present alongside the
|
|
99
|
+
* `'data'` operation class, strategies that need from/to column-shape
|
|
100
|
+
* comparisons (unsafe type change, nullability tightening) activate.
|
|
101
|
+
*
|
|
102
|
+
* Typed as the framework `Contract | null` to satisfy the
|
|
103
|
+
* `MigrationPlanner` interface contract; `planSql` narrows to the SQL
|
|
104
|
+
* shape via `SqlMigrationPlannerPlanOptions`. Used to populate
|
|
105
|
+
* `describe().from` on the produced plan as
|
|
106
|
+
* `fromContract?.storage.storageHash ?? null`.
|
|
94
107
|
*/
|
|
95
|
-
readonly fromContract
|
|
108
|
+
readonly fromContract: Contract | null;
|
|
96
109
|
readonly schemaName?: string;
|
|
97
110
|
readonly frameworkComponents: ReadonlyArray<TargetBoundComponentDescriptor<'sql', string>>;
|
|
111
|
+
/**
|
|
112
|
+
* Contract space this plan applies to. Stamped onto the produced
|
|
113
|
+
* {@link TypeScriptRenderablePostgresMigration.spaceId} so the runner keys
|
|
114
|
+
* the marker row by the right space.
|
|
115
|
+
*/
|
|
116
|
+
readonly spaceId: string;
|
|
98
117
|
}): PostgresPlanResult {
|
|
99
|
-
return this.planSql(options as SqlMigrationPlannerPlanOptions
|
|
118
|
+
return this.planSql(options as SqlMigrationPlannerPlanOptions);
|
|
100
119
|
}
|
|
101
120
|
|
|
102
|
-
emptyMigration(
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
121
|
+
emptyMigration(
|
|
122
|
+
context: MigrationScaffoldContext,
|
|
123
|
+
spaceId: string,
|
|
124
|
+
): MigrationPlanWithAuthoringSurface {
|
|
125
|
+
return new TypeScriptRenderablePostgresMigration(
|
|
126
|
+
[],
|
|
127
|
+
{
|
|
128
|
+
from: context.fromHash,
|
|
129
|
+
to: context.toHash,
|
|
130
|
+
},
|
|
131
|
+
spaceId,
|
|
132
|
+
);
|
|
107
133
|
}
|
|
108
134
|
|
|
109
|
-
private planSql(options: SqlMigrationPlannerPlanOptions
|
|
135
|
+
private planSql(options: SqlMigrationPlannerPlanOptions): PostgresPlanResult {
|
|
110
136
|
const schemaName = options.schemaName ?? this.config.defaultSchema;
|
|
111
137
|
const policyResult = this.ensureAdditivePolicy(options.policy);
|
|
112
138
|
if (policyResult) {
|
|
@@ -125,7 +151,7 @@ export class PostgresMigrationPlanner implements MigrationPlanner<'sql', 'postgr
|
|
|
125
151
|
// from/to comparisons (unsafe type change, nullable tightening) are
|
|
126
152
|
// inapplicable there — reconciliation falls through to
|
|
127
153
|
// `mapIssueToCall`'s direct destructive handlers.
|
|
128
|
-
fromContract: options.fromContract
|
|
154
|
+
fromContract: options.fromContract,
|
|
129
155
|
schemaName,
|
|
130
156
|
codecHooks,
|
|
131
157
|
storageTypes,
|
|
@@ -139,12 +165,37 @@ export class PostgresMigrationPlanner implements MigrationPlanner<'sql', 'postgr
|
|
|
139
165
|
return plannerFailure(result.failure);
|
|
140
166
|
}
|
|
141
167
|
|
|
168
|
+
// Inline `onFieldEvent`-emitted ops after structural DDL. The fixed
|
|
169
|
+
// ordering is `structural → added → dropped → altered`, with
|
|
170
|
+
// within-group sorting by `(tableName, fieldName)` so re-emits are
|
|
171
|
+
// byte-stable. The hook fires only at the application emitter —
|
|
172
|
+
// extension-space planning never reaches this helper.
|
|
173
|
+
const fieldEventOps = planFieldEventOperations({
|
|
174
|
+
priorContract: options.fromContract,
|
|
175
|
+
newContract: options.contract,
|
|
176
|
+
codecHooks,
|
|
177
|
+
});
|
|
178
|
+
// `extractCodecControlHooks` erases target-details to `unknown`; codec
|
|
179
|
+
// authors target a specific lane (here, postgres) and produce ops whose
|
|
180
|
+
// target-details are `PostgresPlanTargetDetails`-shaped by construction.
|
|
181
|
+
// The cast re-specializes the type at this trust boundary.
|
|
182
|
+
const calls = [
|
|
183
|
+
...result.value.calls,
|
|
184
|
+
...fieldEventOps.map(
|
|
185
|
+
(op) => new RawSqlCall(op as SqlMigrationPlanOperation<PostgresPlanTargetDetails>),
|
|
186
|
+
),
|
|
187
|
+
];
|
|
188
|
+
|
|
142
189
|
return Object.freeze({
|
|
143
190
|
kind: 'success' as const,
|
|
144
|
-
plan: new TypeScriptRenderablePostgresMigration(
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
191
|
+
plan: new TypeScriptRenderablePostgresMigration(
|
|
192
|
+
calls,
|
|
193
|
+
{
|
|
194
|
+
from: options.fromContract?.storage.storageHash ?? null,
|
|
195
|
+
to: options.contract.storage.storageHash,
|
|
196
|
+
},
|
|
197
|
+
options.spaceId,
|
|
198
|
+
),
|
|
148
199
|
});
|
|
149
200
|
}
|
|
150
201
|
|
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
import type { Contract } from '@prisma-next/contract/types';
|
|
2
|
+
import type { SqlMigrationPlanOperation } from '@prisma-next/family-sql/control';
|
|
2
3
|
import type { SqlControlAdapter } from '@prisma-next/family-sql/control-adapter';
|
|
3
4
|
import { Migration as SqlMigration } from '@prisma-next/family-sql/migration';
|
|
4
5
|
import type { ControlStack } from '@prisma-next/framework-components/control';
|
|
5
6
|
import type { SqlStorage } from '@prisma-next/sql-contract/types';
|
|
6
7
|
import { errorPostgresMigrationStackMissing } from '../errors';
|
|
7
|
-
import {
|
|
8
|
-
type DataTransformOptions,
|
|
9
|
-
dataTransform,
|
|
10
|
-
type PostgresDataTransformOperation,
|
|
11
|
-
} from './operations/data-transform';
|
|
8
|
+
import { type DataTransformOptions, dataTransform } from './operations/data-transform';
|
|
12
9
|
import type { PostgresPlanTargetDetails } from './planner-target-details';
|
|
13
10
|
|
|
14
11
|
/**
|
|
@@ -64,7 +61,7 @@ export abstract class PostgresMigration extends SqlMigration<
|
|
|
64
61
|
contract: TContract,
|
|
65
62
|
name: string,
|
|
66
63
|
options: DataTransformOptions,
|
|
67
|
-
):
|
|
64
|
+
): SqlMigrationPlanOperation<PostgresPlanTargetDetails> {
|
|
68
65
|
if (!this.controlAdapter) {
|
|
69
66
|
throw errorPostgresMigrationStackMissing();
|
|
70
67
|
}
|
|
@@ -14,9 +14,8 @@ import { type ImportRequirement, jsonToTsSource, renderImports } from '@prisma-n
|
|
|
14
14
|
import type { PostgresOpFactoryCall } from './op-factory-call';
|
|
15
15
|
|
|
16
16
|
export interface RenderMigrationMeta {
|
|
17
|
-
readonly from: string;
|
|
17
|
+
readonly from: string | null;
|
|
18
18
|
readonly to: string;
|
|
19
|
-
readonly kind?: string;
|
|
20
19
|
readonly labels?: readonly string[];
|
|
21
20
|
}
|
|
22
21
|
|
|
@@ -84,9 +83,6 @@ function buildDescribeMethod(meta: RenderMigrationMeta): string {
|
|
|
84
83
|
lines.push(' return {');
|
|
85
84
|
lines.push(` from: ${JSON.stringify(meta.from)},`);
|
|
86
85
|
lines.push(` to: ${JSON.stringify(meta.to)},`);
|
|
87
|
-
if (meta.kind) {
|
|
88
|
-
lines.push(` kind: ${JSON.stringify(meta.kind)},`);
|
|
89
|
-
}
|
|
90
86
|
if (meta.labels && meta.labels.length > 0) {
|
|
91
87
|
lines.push(` labels: ${jsonToTsSource(meta.labels)},`);
|
|
92
88
|
}
|