@prisma-next/target-postgres 0.13.0-dev.2 → 0.13.0-dev.20
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-B1vOchLE.d.mts → codec-ids-BzrFF-I4.d.mts} +3 -2
- package/dist/{codec-ids-B1vOchLE.d.mts.map → codec-ids-BzrFF-I4.d.mts.map} +1 -1
- package/dist/{codec-ids-CTikp1if.mjs → codec-ids-C_-Hj6bL.mjs} +3 -2
- package/dist/{codec-ids-CTikp1if.mjs.map → codec-ids-C_-Hj6bL.mjs.map} +1 -1
- package/dist/codec-ids.d.mts +2 -2
- package/dist/codec-ids.mjs +2 -2
- package/dist/{codec-types-CnFiNML4.d.mts → codec-types-B0WT0obB.d.mts} +3 -2
- package/dist/codec-types-B0WT0obB.d.mts.map +1 -0
- package/dist/codec-types.d.mts +1 -1
- package/dist/{codecs-CBpEv4s5.d.mts → codecs-CX56Smsj.d.mts} +26 -3
- package/dist/{codecs-CBpEv4s5.d.mts.map → codecs-CX56Smsj.d.mts.map} +1 -1
- package/dist/codecs.d.mts +2 -2
- package/dist/codecs.mjs +31 -2
- package/dist/codecs.mjs.map +1 -1
- package/dist/contract-free.mjs +1 -1
- package/dist/control.d.mts.map +1 -1
- package/dist/control.mjs +19 -22
- package/dist/control.mjs.map +1 -1
- package/dist/{data-transform-D25tLeYU.mjs → data-transform-BOWpliq8.mjs} +9 -17
- package/dist/data-transform-BOWpliq8.mjs.map +1 -0
- package/dist/{data-transform-DGOqcLrf.d.mts → data-transform-DDgWdB5o.d.mts} +2 -2
- package/dist/data-transform-DDgWdB5o.d.mts.map +1 -0
- package/dist/data-transform.d.mts +1 -1
- package/dist/data-transform.mjs +1 -1
- package/dist/{descriptor-meta-DKmj-IMN.mjs → descriptor-meta-26XbSdrs.mjs} +2 -2
- package/dist/{descriptor-meta-DKmj-IMN.mjs.map → descriptor-meta-26XbSdrs.mjs.map} +1 -1
- package/dist/{descriptor-meta-runtime-My8_s4cs.mjs → descriptor-meta-runtime-B5ZtrgVF.mjs} +40 -2
- package/dist/descriptor-meta-runtime-B5ZtrgVF.mjs.map +1 -0
- package/dist/{enum-planning-BCyvlFHk.mjs → enum-planning-eI1gxdKF.mjs} +0 -0
- package/dist/enum-planning-eI1gxdKF.mjs.map +1 -0
- package/dist/enum-planning.d.mts +13 -7
- package/dist/enum-planning.d.mts.map +1 -1
- package/dist/enum-planning.mjs +2 -2
- package/dist/{issue-planner-Br0pt1Ea.mjs → issue-planner-DsCMvGja.mjs} +14 -7
- package/dist/issue-planner-DsCMvGja.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 +2 -2
- package/dist/migration.mjs +3 -3
- package/dist/{op-factory-call-D2aAUhmS.mjs → op-factory-call-BZ3xDgCY.mjs} +18 -10
- package/dist/op-factory-call-BZ3xDgCY.mjs.map +1 -0
- package/dist/{op-factory-call-DMA86_2D.d.mts → op-factory-call-DEvD9sbB.d.mts} +5 -5
- package/dist/op-factory-call-DEvD9sbB.d.mts.map +1 -0
- package/dist/op-factory-call.d.mts +1 -1
- package/dist/op-factory-call.mjs +1 -1
- package/dist/pack.d.mts +38 -1
- package/dist/pack.d.mts.map +1 -1
- package/dist/pack.mjs +1 -1
- package/dist/{planner-CAYPJObw.mjs → planner-QWZaVIrn.mjs} +6 -6
- package/dist/planner-QWZaVIrn.mjs.map +1 -0
- package/dist/{planner-produced-postgres-migration-NSEhWL0L.mjs → planner-produced-postgres-migration-BHH6-2-1.mjs} +6 -4
- package/dist/planner-produced-postgres-migration-BHH6-2-1.mjs.map +1 -0
- package/dist/{planner-produced-postgres-migration-B4EDvLdz.d.mts → planner-produced-postgres-migration-CIX9peJN.d.mts} +5 -6
- package/dist/planner-produced-postgres-migration-CIX9peJN.d.mts.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-sql-checks-DAdhnI2c.mjs → planner-sql-checks-CrAbk7gX.mjs} +2 -2
- package/dist/{planner-sql-checks-DAdhnI2c.mjs.map → planner-sql-checks-CrAbk7gX.mjs.map} +1 -1
- package/dist/planner-sql-checks.mjs +1 -1
- package/dist/planner.d.mts +4 -4
- package/dist/planner.d.mts.map +1 -1
- package/dist/planner.mjs +1 -1
- package/dist/{postgres-contract-serializer-DYTyXjPf.mjs → postgres-contract-serializer-BDbqgeFb.mjs} +14 -7
- package/dist/postgres-contract-serializer-BDbqgeFb.mjs.map +1 -0
- package/dist/{postgres-migration-COore9Mz.mjs → postgres-migration-BN6TNJNf.mjs} +3 -3
- package/dist/{postgres-migration-COore9Mz.mjs.map → postgres-migration-BN6TNJNf.mjs.map} +1 -1
- package/dist/{postgres-migration-DZ_gLUOW.d.mts → postgres-migration-h_DA3LRq.d.mts} +5 -5
- package/dist/postgres-migration-h_DA3LRq.d.mts.map +1 -0
- package/dist/{postgres-schema-BuxCxbvB.mjs → postgres-schema-BAgkIU9u.mjs} +17 -6
- package/dist/postgres-schema-BAgkIU9u.mjs.map +1 -0
- package/dist/{render-ops-BpjstrKQ.mjs → render-ops-BREh1kHe.mjs} +10 -5
- package/dist/render-ops-BREh1kHe.mjs.map +1 -0
- package/dist/render-ops.d.mts +2 -2
- package/dist/render-ops.d.mts.map +1 -1
- package/dist/render-ops.mjs +1 -1
- package/dist/runtime.d.mts.map +1 -1
- package/dist/runtime.mjs +2 -2
- package/dist/types.d.mts +3 -1
- package/dist/types.d.mts.map +1 -1
- package/dist/types.mjs +1 -1
- package/package.json +17 -17
- package/src/core/authoring.ts +42 -0
- package/src/core/codec-ids.ts +1 -0
- package/src/core/codec-type-map.ts +2 -0
- package/src/core/codecs.ts +44 -0
- package/src/core/migrations/enum-planning.ts +33 -29
- package/src/core/migrations/issue-planner.ts +24 -3
- package/src/core/migrations/op-factory-call.ts +22 -9
- package/src/core/migrations/operations/data-transform.ts +15 -18
- package/src/core/migrations/planner-produced-postgres-migration.ts +15 -7
- package/src/core/migrations/planner.ts +6 -4
- package/src/core/migrations/postgres-migration.ts +3 -3
- package/src/core/migrations/render-ops.ts +26 -13
- package/src/core/migrations/runner.ts +26 -16
- package/src/core/postgres-contract-serializer.ts +15 -1
- package/src/core/postgres-schema.ts +35 -16
- package/src/exports/codecs.ts +2 -0
- package/src/exports/control.ts +9 -16
- package/src/exports/enum-planning.ts +0 -1
- package/dist/codec-types-CnFiNML4.d.mts.map +0 -1
- package/dist/data-transform-D25tLeYU.mjs.map +0 -1
- package/dist/data-transform-DGOqcLrf.d.mts.map +0 -1
- package/dist/descriptor-meta-runtime-My8_s4cs.mjs.map +0 -1
- package/dist/enum-planning-BCyvlFHk.mjs.map +0 -1
- package/dist/issue-planner-Br0pt1Ea.mjs.map +0 -1
- package/dist/op-factory-call-D2aAUhmS.mjs.map +0 -1
- package/dist/op-factory-call-DMA86_2D.d.mts.map +0 -1
- package/dist/planner-CAYPJObw.mjs.map +0 -1
- package/dist/planner-produced-postgres-migration-B4EDvLdz.d.mts.map +0 -1
- package/dist/planner-produced-postgres-migration-NSEhWL0L.mjs.map +0 -1
- package/dist/postgres-contract-serializer-DYTyXjPf.mjs.map +0 -1
- package/dist/postgres-migration-DZ_gLUOW.d.mts.map +0 -1
- package/dist/postgres-schema-BuxCxbvB.mjs.map +0 -1
- package/dist/render-ops-BpjstrKQ.mjs.map +0 -1
|
@@ -18,7 +18,8 @@ import { APP_SPACE_ID } from '@prisma-next/framework-components/control';
|
|
|
18
18
|
import { UNBOUND_NAMESPACE_ID } from '@prisma-next/framework-components/ir';
|
|
19
19
|
import type { SqlControlDriverInstance, SqlStorage } from '@prisma-next/sql-contract/types';
|
|
20
20
|
import { SqlQueryError } from '@prisma-next/sql-errors';
|
|
21
|
-
import type {
|
|
21
|
+
import type { SqlExecuteRequest } from '@prisma-next/sql-relational-core/ast';
|
|
22
|
+
import { blindCast } from '@prisma-next/utils/casts';
|
|
22
23
|
import { ifDefined } from '@prisma-next/utils/defined';
|
|
23
24
|
import type { Result } from '@prisma-next/utils/result';
|
|
24
25
|
import { notOk, ok, okVoid } from '@prisma-next/utils/result';
|
|
@@ -86,6 +87,12 @@ class PostgresMigrationRunner implements SqlMigrationRunner<PostgresPlanTargetDe
|
|
|
86
87
|
const space = options.plan.spaceId;
|
|
87
88
|
const lockKey = `${LOCK_DOMAIN}:${schema}:${space}`;
|
|
88
89
|
|
|
90
|
+
// Materialize any async ops before running checks or executing.
|
|
91
|
+
const planOps = blindCast<
|
|
92
|
+
readonly SqlMigrationPlanOperation<PostgresPlanTargetDetails>[],
|
|
93
|
+
'ops were produced by the PG planner and are SqlMigrationPlanOperation<PostgresPlanTargetDetails>; MigrationPlan.operations uses the wider framework type to accommodate Promise covariance'
|
|
94
|
+
>(await Promise.all(options.plan.operations));
|
|
95
|
+
|
|
89
96
|
// Static checks (idempotent — safe to run again when the caller is
|
|
90
97
|
// `execute(...)` because the cost is a single object comparison).
|
|
91
98
|
const destinationCheck = this.ensurePlanMatchesDestinationContract(
|
|
@@ -94,7 +101,7 @@ class PostgresMigrationRunner implements SqlMigrationRunner<PostgresPlanTargetDe
|
|
|
94
101
|
);
|
|
95
102
|
if (!destinationCheck.ok) return destinationCheck;
|
|
96
103
|
|
|
97
|
-
const policyCheck = this.enforcePolicyCompatibility(options.policy,
|
|
104
|
+
const policyCheck = this.enforcePolicyCompatibility(options.policy, planOps);
|
|
98
105
|
if (!policyCheck.ok) return policyCheck;
|
|
99
106
|
|
|
100
107
|
await this.acquireLock(driver, lockKey);
|
|
@@ -113,7 +120,7 @@ class PostgresMigrationRunner implements SqlMigrationRunner<PostgresPlanTargetDe
|
|
|
113
120
|
if (skipOperations) {
|
|
114
121
|
applyValue = { operationsExecuted: 0, executedOperations: [] };
|
|
115
122
|
} else {
|
|
116
|
-
const applyResult = await this.applyPlan(driver, options);
|
|
123
|
+
const applyResult = await this.applyPlan(driver, options, planOps);
|
|
117
124
|
if (!applyResult.ok) return applyResult;
|
|
118
125
|
applyValue = applyResult.value;
|
|
119
126
|
}
|
|
@@ -158,11 +165,16 @@ class PostgresMigrationRunner implements SqlMigrationRunner<PostgresPlanTargetDe
|
|
|
158
165
|
if (!isSelfEdgeNoOp) {
|
|
159
166
|
const markerResult = await this.upsertMarker(driver, options, existingMarker, space);
|
|
160
167
|
if (!markerResult.ok) return markerResult;
|
|
161
|
-
await this.recordLedgerEntries(
|
|
168
|
+
await this.recordLedgerEntries(
|
|
169
|
+
driver,
|
|
170
|
+
options,
|
|
171
|
+
applyValue.executedOperations,
|
|
172
|
+
planOps.length,
|
|
173
|
+
);
|
|
162
174
|
}
|
|
163
175
|
|
|
164
176
|
return runnerSuccess({
|
|
165
|
-
operationsPlanned:
|
|
177
|
+
operationsPlanned: planOps.length,
|
|
166
178
|
operationsExecuted: applyValue.operationsExecuted,
|
|
167
179
|
});
|
|
168
180
|
}
|
|
@@ -209,6 +221,7 @@ class PostgresMigrationRunner implements SqlMigrationRunner<PostgresPlanTargetDe
|
|
|
209
221
|
private async applyPlan(
|
|
210
222
|
driver: SqlMigrationRunnerExecuteOptions<PostgresPlanTargetDetails>['driver'],
|
|
211
223
|
options: SqlMigrationRunnerExecuteOptions<PostgresPlanTargetDetails>,
|
|
224
|
+
ops: readonly SqlMigrationPlanOperation<PostgresPlanTargetDetails>[],
|
|
212
225
|
): Promise<Result<ApplyPlanSuccessValue, SqlMigrationRunnerFailure>> {
|
|
213
226
|
const checks = options.executionChecks;
|
|
214
227
|
const runPrechecks = checks?.prechecks !== false; // Default true
|
|
@@ -217,7 +230,7 @@ class PostgresMigrationRunner implements SqlMigrationRunner<PostgresPlanTargetDe
|
|
|
217
230
|
|
|
218
231
|
let operationsExecuted = 0;
|
|
219
232
|
const executedOperations: Array<SqlMigrationPlanOperation<PostgresPlanTargetDetails>> = [];
|
|
220
|
-
for (const operation of
|
|
233
|
+
for (const operation of ops) {
|
|
221
234
|
options.callbacks?.onOperationStart?.(operation);
|
|
222
235
|
try {
|
|
223
236
|
// Idempotency probe: only run if both postchecks and idempotency checks are enabled
|
|
@@ -282,13 +295,13 @@ class PostgresMigrationRunner implements SqlMigrationRunner<PostgresPlanTargetDe
|
|
|
282
295
|
if (schemaQuery === undefined) {
|
|
283
296
|
throw new Error('Postgres control-table bootstrap must include CREATE SCHEMA');
|
|
284
297
|
}
|
|
285
|
-
await this.executeStatement(driver, this.family.lowerAst(schemaQuery, lowererContext));
|
|
298
|
+
await this.executeStatement(driver, await this.family.lowerAst(schemaQuery, lowererContext));
|
|
286
299
|
const legacyDetection = await this.detectLegacyMarkerShape(driver);
|
|
287
300
|
if (!legacyDetection.ok) {
|
|
288
301
|
return legacyDetection;
|
|
289
302
|
}
|
|
290
303
|
for (const query of tableQueries) {
|
|
291
|
-
await this.executeStatement(driver, this.family.lowerAst(query, lowererContext));
|
|
304
|
+
await this.executeStatement(driver, await this.family.lowerAst(query, lowererContext));
|
|
292
305
|
}
|
|
293
306
|
return okVoid();
|
|
294
307
|
}
|
|
@@ -629,14 +642,15 @@ class PostgresMigrationRunner implements SqlMigrationRunner<PostgresPlanTargetDe
|
|
|
629
642
|
driver: SqlMigrationRunnerExecuteOptions<PostgresPlanTargetDetails>['driver'],
|
|
630
643
|
options: SqlMigrationRunnerExecuteOptions<PostgresPlanTargetDetails>,
|
|
631
644
|
executedOperations: readonly SqlMigrationPlanOperation<PostgresPlanTargetDetails>[],
|
|
645
|
+
planOpsLength: number,
|
|
632
646
|
): Promise<void> {
|
|
633
647
|
const plan = options.plan;
|
|
634
648
|
const space = plan.spaceId;
|
|
635
649
|
const edges = options.migrationEdges;
|
|
636
650
|
const totalEdgeOps = edges.reduce((sum, edge) => sum + edge.operationCount, 0);
|
|
637
|
-
if (totalEdgeOps !==
|
|
651
|
+
if (totalEdgeOps !== planOpsLength) {
|
|
638
652
|
throw new Error(
|
|
639
|
-
`Ledger write: plan.operations length (${
|
|
653
|
+
`Ledger write: plan.operations length (${planOpsLength}) does not match sum of migrationEdges operationCount (${totalEdgeOps})`,
|
|
640
654
|
);
|
|
641
655
|
}
|
|
642
656
|
// The ledger records the operations as executed — idempotency-skipped ops
|
|
@@ -688,12 +702,8 @@ class PostgresMigrationRunner implements SqlMigrationRunner<PostgresPlanTargetDe
|
|
|
688
702
|
|
|
689
703
|
private async executeStatement(
|
|
690
704
|
driver: SqlMigrationRunnerExecuteOptions<PostgresPlanTargetDetails>['driver'],
|
|
691
|
-
statement:
|
|
705
|
+
statement: SqlExecuteRequest,
|
|
692
706
|
): Promise<void> {
|
|
693
|
-
|
|
694
|
-
await driver.query(statement.sql, statement.params);
|
|
695
|
-
return;
|
|
696
|
-
}
|
|
697
|
-
await driver.query(statement.sql);
|
|
707
|
+
await driver.query(statement.sql, statement.params);
|
|
698
708
|
}
|
|
699
709
|
}
|
|
@@ -112,9 +112,11 @@ export class PostgresContractSerializer extends SqlContractSerializerBase<Contra
|
|
|
112
112
|
}
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
+
const valueSetSlot = entries.valueSet;
|
|
116
|
+
const hasValueSets = valueSetSlot !== undefined && Object.keys(valueSetSlot).length > 0;
|
|
115
117
|
const emptyTables = Object.keys(entries.table).length === 0;
|
|
116
118
|
const emptyTypes = !typeSlot || Object.keys(typeSlot).length === 0;
|
|
117
|
-
if (id === UNBOUND_NAMESPACE_ID && emptyTables && emptyTypes) {
|
|
119
|
+
if (id === UNBOUND_NAMESPACE_ID && emptyTables && emptyTypes && !hasValueSets) {
|
|
118
120
|
return PostgresSchema.unbound;
|
|
119
121
|
}
|
|
120
122
|
return new PostgresSchema({
|
|
@@ -122,6 +124,7 @@ export class PostgresContractSerializer extends SqlContractSerializerBase<Contra
|
|
|
122
124
|
entries: {
|
|
123
125
|
table: entries.table,
|
|
124
126
|
type: typeSlot ?? {},
|
|
127
|
+
...(hasValueSets ? { valueSet: valueSetSlot } : {}),
|
|
125
128
|
},
|
|
126
129
|
});
|
|
127
130
|
}
|
|
@@ -174,12 +177,23 @@ export class PostgresContractSerializer extends SqlContractSerializerBase<Contra
|
|
|
174
177
|
for (const [typeName, ty] of Object.entries(ns.entries.type)) {
|
|
175
178
|
typeOut[typeName] = this.serializeJsonValue(ty) as JsonObject;
|
|
176
179
|
}
|
|
180
|
+
const valueSetEntries = ns.entries.valueSet;
|
|
181
|
+
const valueSetOut: Record<string, JsonObject> = {};
|
|
182
|
+
if (valueSetEntries !== undefined) {
|
|
183
|
+
for (const [valueSetName, valueSet] of Object.entries(valueSetEntries)) {
|
|
184
|
+
valueSetOut[valueSetName] = blindCast<
|
|
185
|
+
JsonObject,
|
|
186
|
+
'serializeJsonValue round-trips the value-set node through JSON, yielding a JsonObject'
|
|
187
|
+
>(this.serializeJsonValue(valueSet));
|
|
188
|
+
}
|
|
189
|
+
}
|
|
177
190
|
return {
|
|
178
191
|
id: ns.id,
|
|
179
192
|
kind: isUnboundSlot ? 'postgres-unbound-schema' : 'postgres-schema',
|
|
180
193
|
entries: {
|
|
181
194
|
table: tablesOut,
|
|
182
195
|
type: typeOut,
|
|
196
|
+
...(Object.keys(valueSetOut).length > 0 ? { valueSet: valueSetOut } : {}),
|
|
183
197
|
},
|
|
184
198
|
};
|
|
185
199
|
}
|
|
@@ -9,6 +9,8 @@ import {
|
|
|
9
9
|
type SqlStorage,
|
|
10
10
|
StorageTable,
|
|
11
11
|
type StorageTableInput,
|
|
12
|
+
StorageValueSet,
|
|
13
|
+
type StorageValueSetInput,
|
|
12
14
|
} from '@prisma-next/sql-contract/types';
|
|
13
15
|
import { PostgresEnumType, type PostgresEnumTypeInput } from './postgres-enum-type';
|
|
14
16
|
import { escapeLiteral } from './sql-utils';
|
|
@@ -18,6 +20,7 @@ export interface PostgresSchemaInput {
|
|
|
18
20
|
readonly entries: {
|
|
19
21
|
readonly table: Record<string, StorageTable | StorageTableInput>;
|
|
20
22
|
readonly type: Record<string, PostgresEnumType | PostgresEnumTypeInput>;
|
|
23
|
+
readonly valueSet?: Record<string, StorageValueSet | StorageValueSetInput>;
|
|
21
24
|
};
|
|
22
25
|
}
|
|
23
26
|
|
|
@@ -50,29 +53,44 @@ export class PostgresSchema extends NamespaceBase {
|
|
|
50
53
|
readonly entries: Readonly<{
|
|
51
54
|
readonly table: Readonly<Record<string, StorageTable>>;
|
|
52
55
|
readonly type: Readonly<Record<string, PostgresEnumType>>;
|
|
56
|
+
readonly valueSet?: Readonly<Record<string, StorageValueSet>>;
|
|
53
57
|
}>;
|
|
54
58
|
|
|
55
59
|
constructor(input: PostgresSchemaInput) {
|
|
56
60
|
super();
|
|
57
61
|
this.id = input.id;
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
Object.
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
]),
|
|
65
|
-
),
|
|
62
|
+
const table = Object.freeze(
|
|
63
|
+
Object.fromEntries(
|
|
64
|
+
Object.entries(input.entries.table).map(([k, v]) => [
|
|
65
|
+
k,
|
|
66
|
+
v instanceof StorageTable ? v : new StorageTable(v as StorageTableInput),
|
|
67
|
+
]),
|
|
66
68
|
),
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
),
|
|
69
|
+
);
|
|
70
|
+
const type = Object.freeze(
|
|
71
|
+
Object.fromEntries(
|
|
72
|
+
Object.entries(input.entries.type).map(([k, v]) => [
|
|
73
|
+
k,
|
|
74
|
+
v instanceof PostgresEnumType ? v : new PostgresEnumType(v as PostgresEnumTypeInput),
|
|
75
|
+
]),
|
|
74
76
|
),
|
|
75
|
-
|
|
77
|
+
);
|
|
78
|
+
const valueSetInput = input.entries.valueSet;
|
|
79
|
+
this.entries =
|
|
80
|
+
valueSetInput !== undefined && Object.keys(valueSetInput).length > 0
|
|
81
|
+
? Object.freeze({
|
|
82
|
+
table,
|
|
83
|
+
type,
|
|
84
|
+
valueSet: Object.freeze(
|
|
85
|
+
Object.fromEntries(
|
|
86
|
+
Object.entries(valueSetInput).map(([k, v]) => [
|
|
87
|
+
k,
|
|
88
|
+
new StorageValueSet({ kind: 'valueSet', values: v.values }),
|
|
89
|
+
]),
|
|
90
|
+
),
|
|
91
|
+
),
|
|
92
|
+
})
|
|
93
|
+
: Object.freeze({ table, type });
|
|
76
94
|
Object.defineProperty(this, 'kind', {
|
|
77
95
|
value: 'schema',
|
|
78
96
|
writable: false,
|
|
@@ -213,6 +231,7 @@ export function postgresCreateNamespace(
|
|
|
213
231
|
entries: {
|
|
214
232
|
table: input.entries.table,
|
|
215
233
|
type: (enumTypes ?? {}) as Record<string, PostgresEnumTypeInput>,
|
|
234
|
+
...(input.entries.valueSet !== undefined ? { valueSet: input.entries.valueSet } : {}),
|
|
216
235
|
},
|
|
217
236
|
};
|
|
218
237
|
if (input.id === UNBOUND_NAMESPACE_ID) {
|
package/src/exports/codecs.ts
CHANGED
|
@@ -19,6 +19,7 @@ export type {
|
|
|
19
19
|
PgTimestampDescriptor,
|
|
20
20
|
PgTimestamptzDescriptor,
|
|
21
21
|
PgTimetzDescriptor,
|
|
22
|
+
PgUuidDescriptor,
|
|
22
23
|
PgVarbitDescriptor,
|
|
23
24
|
PgVarcharDescriptor,
|
|
24
25
|
} from '../core/codecs';
|
|
@@ -43,6 +44,7 @@ export {
|
|
|
43
44
|
pgTimestampColumn,
|
|
44
45
|
pgTimestamptzColumn,
|
|
45
46
|
pgTimetzColumn,
|
|
47
|
+
pgUuidColumn,
|
|
46
48
|
pgVarbitColumn,
|
|
47
49
|
pgVarcharColumn,
|
|
48
50
|
} from '../core/codecs';
|
package/src/exports/control.ts
CHANGED
|
@@ -10,10 +10,7 @@ import type {
|
|
|
10
10
|
import type { SqlStorage, StorageColumn } from '@prisma-next/sql-contract/types';
|
|
11
11
|
import { ifDefined } from '@prisma-next/utils/defined';
|
|
12
12
|
import { postgresTargetDescriptorMeta } from '../core/descriptor-meta';
|
|
13
|
-
import {
|
|
14
|
-
enumStorageCompoundKey,
|
|
15
|
-
resolveDdlSchemaForNamespaceStorage,
|
|
16
|
-
} from '../core/migrations/enum-planning';
|
|
13
|
+
import { resolveDdlSchemaForNamespaceStorage } from '../core/migrations/enum-planning';
|
|
17
14
|
import { createPostgresMigrationPlanner } from '../core/migrations/planner';
|
|
18
15
|
import { renderDefaultLiteral } from '../core/migrations/planner-ddl-builders';
|
|
19
16
|
import type { PostgresPlanTargetDetails } from '../core/migrations/planner-target-details';
|
|
@@ -80,18 +77,14 @@ const postgresTargetDescriptor: SqlControlTargetDescriptor<'postgres', PostgresP
|
|
|
80
77
|
annotationNamespace: 'pg',
|
|
81
78
|
...ifDefined('expandNativeType', expander),
|
|
82
79
|
renderDefault: postgresRenderDefault,
|
|
83
|
-
//
|
|
84
|
-
//
|
|
85
|
-
// (the contract-to-contract `migration
|
|
86
|
-
//
|
|
87
|
-
//
|
|
88
|
-
//
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
enumStorageCompoundKey(
|
|
92
|
-
resolveDdlSchemaForNamespaceStorage(storage, namespaceId, undefined),
|
|
93
|
-
nativeType,
|
|
94
|
-
),
|
|
80
|
+
// Map each namespace to the live DDL schema its enums are stored
|
|
81
|
+
// under, so the projected "from" IR nests enums by the same schema
|
|
82
|
+
// `readExistingEnumValues` reads (the contract-to-contract `migration
|
|
83
|
+
// plan` path). `undefined` schema IR ⇒ the unbound coordinate
|
|
84
|
+
// resolves to the default `public` landing schema, matching the
|
|
85
|
+
// read-side fallback.
|
|
86
|
+
resolveEnumNamespaceSchema: (storage, namespaceId) =>
|
|
87
|
+
resolveDdlSchemaForNamespaceStorage(storage, namespaceId, undefined),
|
|
95
88
|
});
|
|
96
89
|
},
|
|
97
90
|
},
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"codec-types-CnFiNML4.d.mts","names":[],"sources":["../src/core/codec-type-map.ts","../src/exports/codec-types.ts"],"mappings":";;;;;cA4Ca,kBAAA;EAAA;;;;;;iBA8BH,gBAAA;EAAA;;;;;;;;;;;;;;;;;;;;;;;KAEE,OAAA,6BAAoC,CAAA,0BAA2B,CAAA,CAAE,CAAA,IAAK,CAAA,CAAE,CAAA,EAAG,CAAA;AAAA,KAE3E,kBAAA,UAA4B,kBAAkB;AAAA,KAE9C,mBAAA,GAAsB,iBAAiB,CAAC,kBAAA;;;KCrExC,UAAA,GAAa,OAAO,CAAC,mBAAA;AAAA,KAI5B,OAAA,kBAAyB,MAAA,qBAA2B,CAAA,0BAClC,KAAA,GAAQ,KAAA,CAAM,CAAA;AAAA,KAGhC,aAAA,eAA4B,MAAA,qBAA2B,OAAA,SAAgB,KAAA;AAAA,KAEhE,IAAA,qBAAyB,aAAa;EAAG,YAAA,EAAc,CAAA;AAAA;AAAA,KACvD,OAAA,qBAA4B,aAAa;EAAG,eAAA,EAAiB,CAAA;AAAA;AAAA,KAC7D,OAAA,+DAAsE,aAAA;EAChF,kBAAA,EAAoB,CAAA;EACpB,cAAA,EAAgB,CAAA;AAAA;AAAA,KAEN,GAAA,qBAAwB,aAAa;EAAG,WAAA,EAAa,CAAA;AAAA;AAAA,KACrD,MAAA,qBAA2B,aAAa;EAAG,cAAA,EAAgB,CAAA;AAAA;AAAA,KAC3D,SAAA,6CAAsD,aAAa;EAC7E,oBAAA,EAAsB,CAAA;AAAA;AAAA,KAEZ,WAAA,6CAAwD,aAAa;EAC/E,sBAAA,EAAwB,CAAA;AAAA;AAAA,KAEd,IAAA,6CAAiD,aAAa;EAAG,eAAA,EAAiB,CAAA;AAAA;AAAA,KAClF,MAAA,6CAAmD,aAAa;EAC1E,iBAAA,EAAmB,CAAA;AAAA;AAAA,KAET,QAAA,6CAAqD,aAAa;EAC5E,mBAAA,EAAqB,CAAA;AAAA"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"data-transform-D25tLeYU.mjs","names":[],"sources":["../src/core/migrations/operations/data-transform.ts"],"sourcesContent":["/**\n * User-facing `dataTransform` factory for the Postgres migration authoring\n * surface. Invoked directly inside a `migration.ts` file via the\n * `PostgresMigration` instance method (`this.dataTransform(...)`), which\n * supplies the control adapter from the migration's injected stack:\n *\n * ```ts\n * import endContract from './end-contract.json' with { type: 'json' };\n *\n * class M extends Migration {\n * override get operations() {\n * return [\n * this.dataTransform(endContract, 'backfill emails', {\n * check: () => db.users.select('id').where(({ email }) => email.isNull()).limit(1),\n * run: () => db.users.update({ email: '' }).where(({ email }) => email.isNull()),\n * }),\n * ];\n * }\n * }\n * ```\n *\n * The factory accepts lazy closures (`() => SqlQueryPlan | Buildable`),\n * invokes each one, asserts that its `meta.storageHash` matches the\n * `contract` it was handed (→ `PN-MIG-2005` on mismatch), and lowers the\n * plan via the supplied control adapter to a serialized `{sql, params}`\n * payload.\n *\n * The factory then lowers the data transform to the unified migration-op\n * shape `{ precheck, execute, postcheck }`. The user's `check` plan is\n * wrapped twice with opposite truth values:\n *\n * - precheck `SELECT EXISTS (<check>) AS ok` asserts there is work to do\n * (precheck is short-circuited by the runner's pre-satisfied-skip path\n * when nothing remains to backfill).\n * - postcheck `SELECT NOT EXISTS (<check>) AS ok` asserts the work is\n * complete after the run steps execute.\n *\n * The `check` plan is therefore expected to be a **rowset query whose\n * presence of any row signals \"work remains\"** — typically `select('id')\n * .where(<violation predicate>).limit(1)`. Scalar/aggregate shapes\n * (`count(*)`, `bool_and(...)`) do not work under this contract: they\n * always return exactly one row, so `EXISTS` is always true and\n * `NOT EXISTS` is always false. (This is the same row-presence contract\n * the pre-unification runner relied on; the wrapping is just lifting it\n * into SQL.)\n *\n * Each `run` plan becomes an execute step. Because the `Step.params`\n * field threads through `driver.query(sql, params)`, the user's bound\n * values flow through the driver's parameter binder rather than being\n * inlined into the SQL text.\n *\n * The free factory remains usable standalone (tests, ad-hoc tooling,\n * non-class contexts) by passing the adapter explicitly as the fourth\n * argument.\n */\n\nimport type { Contract } from '@prisma-next/contract/types';\nimport { errorDataTransformContractMismatch } from '@prisma-next/errors/migration';\nimport type {\n SqlMigrationPlanOperation,\n SqlMigrationPlanOperationStep,\n} from '@prisma-next/family-sql/control';\nimport type { SqlControlAdapter } from '@prisma-next/family-sql/control-adapter';\nimport type { SerializedQueryPlan } from '@prisma-next/framework-components/control';\nimport type { SqlStorage } from '@prisma-next/sql-contract/types';\nimport type { SqlQueryPlan } from '@prisma-next/sql-relational-core/plan';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport type { PostgresPlanTargetDetails } from '../planner-target-details';\n\ninterface Buildable<R = unknown> {\n build(): SqlQueryPlan<R>;\n}\n\n/**\n * A single-closure producer of a SQL query plan. Shared between\n * `check` and each `run` entry.\n */\nexport type DataTransformClosure = () => SqlQueryPlan | Buildable;\n\nexport interface DataTransformOptions {\n /**\n * Optional opt-in routing identity. Presence opts the transform into\n * invariant-aware routing; absence means it is path-dependent and\n * not referenceable from refs.\n */\n readonly invariantId?: string;\n /**\n * Optional pre-flight query. `undefined` means \"no check\". When\n * supplied, the closure must return a **rowset query** whose\n * presence of any row signals \"violations remain\". Conventional\n * shape: `db.<table>.select('id').where(<violation>).limit(1)`.\n * Scalar/aggregate shapes do not satisfy this contract.\n */\n readonly check?: DataTransformClosure;\n /** One or more mutation queries to execute. */\n readonly run: DataTransformClosure | readonly DataTransformClosure[];\n}\n\nexport function dataTransform<TContract extends Contract<SqlStorage>>(\n contract: TContract,\n name: string,\n options: DataTransformOptions,\n adapter: SqlControlAdapter<'postgres'>,\n): SqlMigrationPlanOperation<PostgresPlanTargetDetails> {\n const runClosures: readonly DataTransformClosure[] = Array.isArray(options.run)\n ? options.run\n : [options.run as DataTransformClosure];\n\n const checkPlan = options.check ? invokeAndLower(options.check, contract, adapter, name) : null;\n const runPlans = runClosures.map((closure) => invokeAndLower(closure, contract, adapter, name));\n\n const precheck: readonly SqlMigrationPlanOperationStep[] = checkPlan\n ? [\n {\n description: `Check ${name} has work to do`,\n sql: `SELECT EXISTS (${checkPlan.sql}) AS ok`,\n params: checkPlan.params,\n },\n ]\n : [];\n\n const execute: readonly SqlMigrationPlanOperationStep[] = runPlans.map((plan) => ({\n description: `Run ${name}`,\n sql: plan.sql,\n params: plan.params,\n }));\n\n const postcheck: readonly SqlMigrationPlanOperationStep[] = checkPlan\n ? [\n {\n description: `Verify ${name} resolved all violations`,\n sql: `SELECT NOT EXISTS (${checkPlan.sql}) AS ok`,\n params: checkPlan.params,\n },\n ]\n : [];\n\n return {\n id: `data_migration.${name}`,\n label: `Data transform: ${name}`,\n operationClass: 'data',\n ...ifDefined('invariantId', options.invariantId),\n target: { id: 'postgres' },\n precheck,\n execute,\n postcheck,\n };\n}\n\nfunction invokeAndLower(\n closure: DataTransformClosure,\n contract: Contract<SqlStorage>,\n adapter: SqlControlAdapter<'postgres'>,\n name: string,\n): SerializedQueryPlan {\n const result = closure();\n const plan = isBuildable(result) ? result.build() : result;\n assertContractMatches(plan, contract, name);\n const lowered = adapter.lower(plan.ast, { contract });\n const params = lowered.params.map((slot) => {\n if (slot.kind === 'literal') return slot.value;\n throw new Error(\n `data-transform: bind-site slot '${slot.name}' is not allowed in migration plans`,\n );\n });\n return { sql: lowered.sql, params };\n}\n\nfunction isBuildable(value: unknown): value is Buildable {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'build' in value &&\n typeof (value as { build: unknown }).build === 'function'\n );\n}\n\nfunction assertContractMatches(\n plan: SqlQueryPlan,\n contract: Contract<SqlStorage>,\n name: string,\n): void {\n if (plan.meta.storageHash !== contract.storage.storageHash) {\n throw errorDataTransformContractMismatch({\n dataTransformName: name,\n expected: contract.storage.storageHash,\n actual: plan.meta.storageHash,\n });\n }\n}\n"],"mappings":";;;AAkGA,SAAgB,cACd,UACA,MACA,SACA,SACsD;CACtD,MAAM,cAA+C,MAAM,QAAQ,QAAQ,GAAG,IAC1E,QAAQ,MACR,CAAC,QAAQ,GAA2B;CAExC,MAAM,YAAY,QAAQ,QAAQ,eAAe,QAAQ,OAAO,UAAU,SAAS,IAAI,IAAI;CAC3F,MAAM,WAAW,YAAY,KAAK,YAAY,eAAe,SAAS,UAAU,SAAS,IAAI,CAAC;CAE9F,MAAM,WAAqD,YACvD,CACE;EACE,aAAa,SAAS,KAAK;EAC3B,KAAK,kBAAkB,UAAU,IAAI;EACrC,QAAQ,UAAU;CACpB,CACF,IACA,CAAC;CAEL,MAAM,UAAoD,SAAS,KAAK,UAAU;EAChF,aAAa,OAAO;EACpB,KAAK,KAAK;EACV,QAAQ,KAAK;CACf,EAAE;CAEF,MAAM,YAAsD,YACxD,CACE;EACE,aAAa,UAAU,KAAK;EAC5B,KAAK,sBAAsB,UAAU,IAAI;EACzC,QAAQ,UAAU;CACpB,CACF,IACA,CAAC;CAEL,OAAO;EACL,IAAI,kBAAkB;EACtB,OAAO,mBAAmB;EAC1B,gBAAgB;EAChB,GAAG,UAAU,eAAe,QAAQ,WAAW;EAC/C,QAAQ,EAAE,IAAI,WAAW;EACzB;EACA;EACA;CACF;AACF;AAEA,SAAS,eACP,SACA,UACA,SACA,MACqB;CACrB,MAAM,SAAS,QAAQ;CACvB,MAAM,OAAO,YAAY,MAAM,IAAI,OAAO,MAAM,IAAI;CACpD,sBAAsB,MAAM,UAAU,IAAI;CAC1C,MAAM,UAAU,QAAQ,MAAM,KAAK,KAAK,EAAE,SAAS,CAAC;CACpD,MAAM,SAAS,QAAQ,OAAO,KAAK,SAAS;EAC1C,IAAI,KAAK,SAAS,WAAW,OAAO,KAAK;EACzC,MAAM,IAAI,MACR,mCAAmC,KAAK,KAAK,oCAC/C;CACF,CAAC;CACD,OAAO;EAAE,KAAK,QAAQ;EAAK;CAAO;AACpC;AAEA,SAAS,YAAY,OAAoC;CACvD,OACE,OAAO,UAAU,YACjB,UAAU,QACV,WAAW,SACX,OAAQ,MAA6B,UAAU;AAEnD;AAEA,SAAS,sBACP,MACA,UACA,MACM;CACN,IAAI,KAAK,KAAK,gBAAgB,SAAS,QAAQ,aAC7C,MAAM,mCAAmC;EACvC,mBAAmB;EACnB,UAAU,SAAS,QAAQ;EAC3B,QAAQ,KAAK,KAAK;CACpB,CAAC;AAEL"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"data-transform-DGOqcLrf.d.mts","names":[],"sources":["../src/core/migrations/operations/data-transform.ts"],"mappings":";;;;;;;;UAqEU,SAAA;EACR,KAAA,IAAS,YAAY,CAAC,CAAA;AAAA;AAiC8B;;;;AAAA,KA1B1C,oBAAA,SAA6B,YAAA,GAAe,SAAS;AAAA,UAEhD,oBAAA;;;;;;WAMN,WAAA;;;;;;;;WAQA,KAAA,GAAQ,oBAAA;;WAER,GAAA,EAAK,oBAAA,YAAgC,oBAAA;AAAA;AAAA,iBAGhC,aAAA,mBAAgC,QAAA,CAAS,UAAA,GACvD,QAAA,EAAU,SAAA,EACV,IAAA,UACA,OAAA,EAAS,oBAAA,EACT,OAAA,EAAS,iBAAA,eACR,yBAAA,CAA0B,yBAAA"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"descriptor-meta-runtime-My8_s4cs.mjs","names":[],"sources":["../src/core/authoring.ts","../src/core/descriptor-meta-runtime.ts"],"sourcesContent":["import { temporalAuthoringPresets } from '@prisma-next/family-sql/control';\nimport type {\n AuthoringEntityTypeNamespace,\n AuthoringFieldNamespace,\n AuthoringTypeNamespace,\n} from '@prisma-next/framework-components/authoring';\nimport type { PostgresEnumStorageEntry } from '@prisma-next/sql-contract/types';\nimport { PostgresEnumTypeSchema } from '@prisma-next/sql-contract/validators';\nimport { PostgresEnumType, type PostgresEnumTypeInput } from './postgres-enum-type';\n\nexport const postgresAuthoringTypes = {} as const satisfies AuthoringTypeNamespace;\n\n/**\n * Entity type contributions surface as top-level helpers on the\n * composed-helpers shape (e.g. `helpers.enum({...})`), flattened\n * alongside the built-in `model` / `rel` helpers. Pack contributions\n * still ship via the contribution data structure\n * `authoring.entityTypes.<name>`; the composed-helpers template\n * performs the rename in the type system.\n *\n * `enum` is the first real consumer of the entities-namespace mechanism:\n * the factory constructs a `PostgresEnumType` IR-class instance from\n * the user-supplied input. Both authoring runtimes (TS DSL and PSL)\n * dispatch through this single contribution — PSL `enum Status { … }`\n * declarations are lowered by the interpreter into a factory call\n * with the parsed name + value list; TS DSL `helpers.enum({...})`\n * resolves through the same path. Removing this contribution makes\n * both surfaces fail with a \"no entity helper named `enum`\" type\n * error at the contract-definition site.\n */\n/**\n * The factory constructs a `PostgresEnumType` instance natively — the\n * `SqlStorage.types` slot accepts polymorphic IR (the framework\n * `StorageType` alphabet), so no cast is needed at the contribution\n * surface. The declared return type is the structural\n * `PostgresEnumStorageEntry` so the inferred contract type stays\n * portable (it names a type exported from\n * `@prisma-next/sql-contract/types`, a public surface every consumer\n * already imports). Sharpening the inferred contract type to surface\n * enum-specific narrowing through `EntityHelperFunction` is a\n * separable refinement and lives outside this PR.\n */\nexport const postgresAuthoringEntityTypes = {\n enum: {\n kind: 'entity',\n discriminator: 'postgres-enum',\n validatorSchema: PostgresEnumTypeSchema,\n output: {\n factory: (input: PostgresEnumTypeInput): PostgresEnumStorageEntry =>\n new PostgresEnumType(input),\n },\n },\n} as const satisfies AuthoringEntityTypeNamespace;\n\n/**\n * Field presets contributed by the Postgres target pack.\n *\n * These mirror the PSL scalar-to-codec mapping used by the Postgres adapter\n * (see `createPostgresPslScalarTypeDescriptors`), so that authoring a field\n * via the TS callback surface (e.g. `field.int()`) and via the PSL scalar\n * surface (e.g. `Int`) lowers to byte-identical contracts.\n */\nexport const postgresAuthoringFieldPresets = {\n text: {\n kind: 'fieldPreset',\n output: {\n codecId: 'pg/text@1',\n nativeType: 'text',\n },\n },\n int: {\n kind: 'fieldPreset',\n output: {\n codecId: 'pg/int4@1',\n nativeType: 'int4',\n },\n },\n bigint: {\n kind: 'fieldPreset',\n output: {\n codecId: 'pg/int8@1',\n nativeType: 'int8',\n },\n },\n float: {\n kind: 'fieldPreset',\n output: {\n codecId: 'pg/float8@1',\n nativeType: 'float8',\n },\n },\n decimal: {\n kind: 'fieldPreset',\n output: {\n codecId: 'pg/numeric@1',\n nativeType: 'numeric',\n },\n },\n boolean: {\n kind: 'fieldPreset',\n output: {\n codecId: 'pg/bool@1',\n nativeType: 'bool',\n },\n },\n json: {\n kind: 'fieldPreset',\n output: {\n codecId: 'pg/jsonb@1',\n nativeType: 'jsonb',\n },\n },\n bytes: {\n kind: 'fieldPreset',\n output: {\n codecId: 'pg/bytea@1',\n nativeType: 'bytea',\n },\n },\n dateTime: {\n kind: 'fieldPreset',\n output: {\n codecId: 'pg/timestamptz@1',\n nativeType: 'timestamptz',\n },\n },\n temporal: /* @__PURE__ */ temporalAuthoringPresets({\n codecId: 'pg/timestamptz@1',\n nativeType: 'timestamptz',\n }),\n} as const satisfies AuthoringFieldNamespace;\n","// Runtime-safe slice of the postgres target descriptor metadata.\n//\n// This file exists separately from ./descriptor-meta on purpose: the runtime\n// plane reads only `kind/familyId/targetId/id/version/capabilities` (plus the\n// `__codecTypes` phantom). The `authoring` slot lives on the pack/control\n// descriptor only, because authoring contributions are consumed at\n// contract-construction time by `assembleAuthoringContributions` (control\n// plane) and the PSL interpreter — never at runtime.\n//\n// Keeping the runtime closure free of the `./authoring` import is what lets\n// the bundler tree-shake `@prisma-next/family-sql/control` (and its\n// transitive `verify-sql-schema` chunk) out of the runtime entry. Do not\n// add an `authoring` field here — if you need to, the pack/control meta in\n// `./descriptor-meta` is the right place. See TML-2766 for context.\nimport type { CodecTypes } from '../exports/codec-types';\n\nconst postgresTargetDescriptorMetaRuntimeBase = {\n kind: 'target',\n familyId: 'sql',\n targetId: 'postgres',\n id: 'postgres',\n version: '0.0.1',\n capabilities: {},\n} as const;\n\nexport const postgresTargetDescriptorMetaRuntime: typeof postgresTargetDescriptorMetaRuntimeBase & {\n readonly __codecTypes?: CodecTypes;\n} = postgresTargetDescriptorMetaRuntimeBase;\n"],"mappings":";;;;AAUA,MAAa,yBAAyB,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgCvC,MAAa,+BAA+B,EAC1C,MAAM;CACJ,MAAM;CACN,eAAe;CACf,iBAAiB;CACjB,QAAQ,EACN,UAAU,UACR,IAAI,iBAAiB,KAAK,EAC9B;AACF,EACF;;;;;;;;;AAUA,MAAa,gCAAgC;CAC3C,MAAM;EACJ,MAAM;EACN,QAAQ;GACN,SAAS;GACT,YAAY;EACd;CACF;CACA,KAAK;EACH,MAAM;EACN,QAAQ;GACN,SAAS;GACT,YAAY;EACd;CACF;CACA,QAAQ;EACN,MAAM;EACN,QAAQ;GACN,SAAS;GACT,YAAY;EACd;CACF;CACA,OAAO;EACL,MAAM;EACN,QAAQ;GACN,SAAS;GACT,YAAY;EACd;CACF;CACA,SAAS;EACP,MAAM;EACN,QAAQ;GACN,SAAS;GACT,YAAY;EACd;CACF;CACA,SAAS;EACP,MAAM;EACN,QAAQ;GACN,SAAS;GACT,YAAY;EACd;CACF;CACA,MAAM;EACJ,MAAM;EACN,QAAQ;GACN,SAAS;GACT,YAAY;EACd;CACF;CACA,OAAO;EACL,MAAM;EACN,QAAQ;GACN,SAAS;GACT,YAAY;EACd;CACF;CACA,UAAU;EACR,MAAM;EACN,QAAQ;GACN,SAAS;GACT,YAAY;EACd;CACF;CACA,UAA0B,yCAAyB;EACjD,SAAS;EACT,YAAY;CACd,CAAC;AACH;ACzGA,MAAa,sCAET;CAVF,MAAM;CACN,UAAU;CACV,UAAU;CACV,IAAI;CACJ,SAAS;CACT,cAAc,CAAC;AAKb"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"enum-planning-BCyvlFHk.mjs","names":[],"sources":["../src/core/migrations/enum-planning.ts"],"sourcesContent":["/**\n * Pure planning helpers for Postgres enum types: the diff/rebuild logic\n * that the verifier and planner use to walk `PostgresEnumType` instances\n * natively. Op builders live in `./operations/enums.ts`.\n */\n\nimport { arraysEqual } from '@prisma-next/family-sql/schema-verify';\nimport { UNBOUND_NAMESPACE_ID } from '@prisma-next/framework-components/ir';\nimport type { PostgresEnumStorageEntry, SqlStorage } from '@prisma-next/sql-contract/types';\nimport type { SqlSchemaIR } from '@prisma-next/sql-schema-ir/types';\nimport { PG_ENUM_CODEC_ID } from '../codec-ids';\nimport type { PostgresEnumType } from '../postgres-enum-type';\nimport { isPostgresSchema } from '../postgres-schema';\n\n/**\n * Codec-typed enum entry shape stored under\n * `schema.annotations.pg.storageTypes[(schemaName, nativeType)]`.\n */\ninterface PgStorageTypeEntry {\n readonly codecId?: string;\n readonly typeParams?: { readonly values?: unknown };\n}\n\n/** Postgres-specific subtree on family `SqlSchemaIR.annotations`. */\nexport interface PostgresSchemaIrAnnotations {\n readonly schema?: string;\n readonly storageTypes?: Readonly<Record<string, PgStorageTypeEntry>>;\n}\n\nfunction readOptionalString(value: unknown): string | undefined {\n return typeof value === 'string' ? value : undefined;\n}\n\nfunction readPgStorageTypeEntry(value: unknown): PgStorageTypeEntry | undefined {\n if (value === null || typeof value !== 'object' || Array.isArray(value)) {\n return undefined;\n }\n const codecId = Reflect.get(value, 'codecId');\n const typeParamsRaw = Reflect.get(value, 'typeParams');\n const typeParams =\n typeParamsRaw !== undefined &&\n typeParamsRaw !== null &&\n typeof typeParamsRaw === 'object' &&\n !Array.isArray(typeParamsRaw)\n ? { values: Reflect.get(typeParamsRaw, 'values') }\n : undefined;\n return {\n ...(typeof codecId === 'string' ? { codecId } : {}),\n ...(typeParams !== undefined ? { typeParams } : {}),\n };\n}\n\nfunction readPgStorageTypesMap(\n value: unknown,\n): Readonly<Record<string, PgStorageTypeEntry>> | undefined {\n if (value === null || typeof value !== 'object' || Array.isArray(value)) {\n return undefined;\n }\n const entries: Record<string, PgStorageTypeEntry> = {};\n for (const [key, entryValue] of Object.entries(value)) {\n const entry = readPgStorageTypeEntry(entryValue);\n if (entry !== undefined) {\n entries[key] = entry;\n }\n }\n return Object.keys(entries).length > 0 ? entries : undefined;\n}\n\n/**\n * Reads the Postgres annotation envelope (`schema.annotations.pg`) from\n * family Schema IR. `SqlAnnotations` is an open target-pack extensibility\n * map (`Record<string, unknown>`); this accessor narrows the `pg` slot at\n * runtime so Postgres code can read introspection fields without casts.\n */\nexport function readPostgresSchemaIrAnnotations(schema: SqlSchemaIR): PostgresSchemaIrAnnotations {\n const raw = schema.annotations?.['pg'];\n if (raw === undefined || raw === null || typeof raw !== 'object' || Array.isArray(raw)) {\n return {};\n }\n const schemaField = readOptionalString(Reflect.get(raw, 'schema'));\n const storageTypes = readPgStorageTypesMap(Reflect.get(raw, 'storageTypes'));\n return {\n ...(schemaField !== undefined ? { schema: schemaField } : {}),\n ...(storageTypes !== undefined ? { storageTypes } : {}),\n };\n}\n\n/**\n * Separator for `(schemaName, nativeType)` keys in introspected\n * `schema.annotations.pg.storageTypes`. NUL cannot appear in Postgres\n * identifiers, so the pair is unambiguous.\n */\nexport const ENUM_STORAGE_KEY_SEP = '\\u0000';\n\n/** Builds the schema-qualified storageTypes map key for a live Postgres enum. */\nexport function enumStorageCompoundKey(schemaName: string, nativeType: string): string {\n return `${schemaName}${ENUM_STORAGE_KEY_SEP}${nativeType}`;\n}\n\n/**\n * Resolves the live-schema name a namespace's enums are introspected under,\n * for keying `readExistingEnumValues` lookups. The unbound namespace's\n * `ddlSchemaName` is a planner-emit sentinel (`__unbound__`) that never names a\n * real schema, so for the unbound coordinate we read the *introspected* schema\n * recorded on `annotations.pg.schema` (the live `current_schema()` the adapter\n * walked) — that is the schema the enum's `storageTypes` entry is keyed under.\n * Named namespaces resolve to their own DDL schema, which matches the\n * per-schema introspection key directly.\n */\nexport function resolveDdlSchemaForNamespaceStorage(\n storage: SqlStorage,\n namespaceId: string,\n schemaIr?: SqlSchemaIR,\n): string {\n if (namespaceId === UNBOUND_NAMESPACE_ID) {\n return (schemaIr ? readPostgresSchemaIrAnnotations(schemaIr).schema : undefined) ?? 'public';\n }\n const namespace = storage.namespaces[namespaceId];\n if (namespace && isPostgresSchema(namespace)) {\n return namespace.ddlSchemaName(storage);\n }\n return namespaceId;\n}\n\n/** Contract-scoped bridge for the family verifier's enum value resolver. */\nexport function createResolveExistingEnumValues(\n storage: SqlStorage,\n): (\n schema: SqlSchemaIR,\n enumType: PostgresEnumStorageEntry,\n namespaceId: string,\n) => readonly string[] | null {\n return (schema, enumType, namespaceId) =>\n readExistingEnumValues(\n schema,\n resolveDdlSchemaForNamespaceStorage(storage, namespaceId, schema),\n enumType.nativeType,\n );\n}\n\n/**\n * Categorisation of how an existing enum type's values relate to the\n * desired set in the contract.\n */\nexport type EnumDiff =\n | { readonly kind: 'unchanged' }\n | { readonly kind: 'add_values'; readonly values: readonly string[] }\n | { readonly kind: 'rebuild'; readonly removedValues: readonly string[] };\n\n/**\n * Reads existing enum values for `(schemaName, nativeType)` from the\n * Postgres-introspected `schema.annotations.pg.storageTypes` map.\n *\n * Schema IR's `storageTypes` slots are always codec-typed\n * (`{codecId: PG_ENUM_CODEC_ID, typeParams.values}`): the introspector\n * writes that shape, and the Contract→Schema IR projector resolves\n * `PostgresEnumType` instances down to the same codec-typed triple before\n * they ever land in Schema IR. There is no second on-disk shape to\n * accept here.\n *\n * Returns `null` when no enum entry exists for the given native type.\n */\nexport function readExistingEnumValues(\n schema: SqlSchemaIR,\n schemaName: string,\n nativeType: string,\n): readonly string[] | null {\n const storageTypes = readPostgresSchemaIrAnnotations(schema).storageTypes;\n const existing = storageTypes?.[enumStorageCompoundKey(schemaName, nativeType)];\n if (!existing || existing.codecId !== PG_ENUM_CODEC_ID) {\n return null;\n }\n const enumValues = existing.typeParams?.values;\n if (!Array.isArray(enumValues) || !enumValues.every((v) => typeof v === 'string')) {\n return null;\n }\n return enumValues;\n}\n\n/**\n * Determines what changes are needed to transform existing enum values to\n * desired values.\n *\n * Postgres enums can only have values added (not removed or reordered)\n * without a full type rebuild involving temp type creation and column\n * migration; `'rebuild'` covers the value-removal and reorder cases.\n */\nexport function determineEnumDiff(\n existing: readonly string[],\n desired: readonly string[],\n): EnumDiff {\n if (arraysEqual(existing, desired)) {\n return { kind: 'unchanged' };\n }\n const existingSet = new Set(existing);\n const desiredSet = new Set(desired);\n const missingValues = desired.filter((value) => !existingSet.has(value));\n const removedValues = existing.filter((value) => !desiredSet.has(value));\n const orderMismatch =\n missingValues.length === 0 && removedValues.length === 0 && !arraysEqual(existing, desired);\n if (removedValues.length > 0 || orderMismatch) {\n return { kind: 'rebuild', removedValues };\n }\n return { kind: 'add_values', values: missingValues };\n}\n\n/**\n * Convenience accessor — returns the enum's desired values from a\n * `PostgresEnumType` IR instance.\n */\nexport function getDesiredEnumValues(typeInstance: PostgresEnumType): readonly string[] {\n return typeInstance.values;\n}\n"],"mappings":"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"}
|