@prisma-next/target-postgres 0.1.0-dev.19 → 0.1.0-dev.21
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/README.md +2 -1
- package/dist/exports/control.js +406 -104
- package/dist/exports/control.js.map +1 -1
- package/package.json +11 -11
package/README.md
CHANGED
|
@@ -19,6 +19,7 @@ Provides the Postgres target descriptor (`SqlControlTargetDescriptor`) for CLI c
|
|
|
19
19
|
- **Multi-Plane Support**: Provides both migration-plane (control) and runtime-plane entry points for the Postgres target
|
|
20
20
|
- **Planner Factory**: Implements `createPlanner()` to create Postgres-specific migration planners
|
|
21
21
|
- **Runner Factory**: Implements `createRunner()` to create Postgres-specific migration runners
|
|
22
|
+
- **Database Dependency Consumption**: The planner extracts database dependencies from the configured framework components (passed as `frameworkComponents`), verifies each dependency against the live schema, and only emits install operations when required. The runner reuses the same metadata for post-apply verification, so there are no hardcoded extension mappings—database dependencies stay component-owned.
|
|
22
23
|
|
|
23
24
|
This package spans multiple planes:
|
|
24
25
|
- **Migration plane** (`src/exports/control.ts`): Control plane entry point that exports `SqlControlTargetDescriptor` for config files
|
|
@@ -91,7 +92,7 @@ Both the planner and runner return structured results instead of throwing:
|
|
|
91
92
|
|
|
92
93
|
**Planner** returns `PlannerResult` with either:
|
|
93
94
|
- `kind: 'success'` with a `MigrationPlan`
|
|
94
|
-
- `kind: 'failure'` with a list of `PlannerConflict` objects (e.g., `
|
|
95
|
+
- `kind: 'failure'` with a list of `PlannerConflict` objects (e.g., `unsupportedOperation`, `policyViolation`)
|
|
95
96
|
|
|
96
97
|
**Runner** returns `MigrationRunnerResult` (`Result<MigrationRunnerSuccessValue, MigrationRunnerFailure>`) with either:
|
|
97
98
|
- `ok: true` with operation counts
|
package/dist/exports/control.js
CHANGED
|
@@ -10,13 +10,10 @@ import {
|
|
|
10
10
|
plannerFailure,
|
|
11
11
|
plannerSuccess
|
|
12
12
|
} from "@prisma-next/family-sql/control";
|
|
13
|
+
import { arraysEqual, verifySqlSchema } from "@prisma-next/family-sql/schema-verify";
|
|
13
14
|
var DEFAULT_PLANNER_CONFIG = {
|
|
14
15
|
defaultSchema: "public"
|
|
15
16
|
};
|
|
16
|
-
var PG_EXTENSION_SQL = {
|
|
17
|
-
pgvector: "CREATE EXTENSION IF NOT EXISTS vector"
|
|
18
|
-
};
|
|
19
|
-
var ADAPTER_LEVEL_EXTENSIONS = /* @__PURE__ */ new Set(["pg", "postgres"]);
|
|
20
17
|
function createPostgresMigrationPlanner(config = {}) {
|
|
21
18
|
return new PostgresMigrationPlanner({
|
|
22
19
|
...DEFAULT_PLANNER_CONFIG,
|
|
@@ -33,28 +30,27 @@ var PostgresMigrationPlanner = class {
|
|
|
33
30
|
if (policyResult) {
|
|
34
31
|
return policyResult;
|
|
35
32
|
}
|
|
36
|
-
const
|
|
37
|
-
if (
|
|
38
|
-
|
|
39
|
-
return plannerFailure([
|
|
40
|
-
{
|
|
41
|
-
kind: "unsupportedOperation",
|
|
42
|
-
summary: `The Postgres migration planner currently supports only empty databases. Found ${existingTables.length} existing table(s): ${tableList}`,
|
|
43
|
-
why: "Remove existing tables or use a future planner mode that handles subsets/supersets."
|
|
44
|
-
}
|
|
45
|
-
]);
|
|
46
|
-
}
|
|
47
|
-
const extensionResult = this.validateExtensions(options.contract);
|
|
48
|
-
if (extensionResult) {
|
|
49
|
-
return extensionResult;
|
|
33
|
+
const classification = this.classifySchema(options);
|
|
34
|
+
if (classification.kind === "conflict") {
|
|
35
|
+
return plannerFailure(classification.conflicts);
|
|
50
36
|
}
|
|
51
37
|
const operations = [];
|
|
52
38
|
operations.push(
|
|
53
|
-
...this.
|
|
54
|
-
...this.buildTableOperations(options.contract.storage.tables, schemaName),
|
|
55
|
-
...this.
|
|
56
|
-
...this.
|
|
57
|
-
|
|
39
|
+
...this.buildDatabaseDependencyOperations(options),
|
|
40
|
+
...this.buildTableOperations(options.contract.storage.tables, options.schema, schemaName),
|
|
41
|
+
...this.buildColumnOperations(options.contract.storage.tables, options.schema, schemaName),
|
|
42
|
+
...this.buildPrimaryKeyOperations(
|
|
43
|
+
options.contract.storage.tables,
|
|
44
|
+
options.schema,
|
|
45
|
+
schemaName
|
|
46
|
+
),
|
|
47
|
+
...this.buildUniqueOperations(options.contract.storage.tables, options.schema, schemaName),
|
|
48
|
+
...this.buildIndexOperations(options.contract.storage.tables, options.schema, schemaName),
|
|
49
|
+
...this.buildForeignKeyOperations(
|
|
50
|
+
options.contract.storage.tables,
|
|
51
|
+
options.schema,
|
|
52
|
+
schemaName
|
|
53
|
+
)
|
|
58
54
|
);
|
|
59
55
|
const plan = createMigrationPlan({
|
|
60
56
|
targetId: "postgres",
|
|
@@ -67,29 +63,6 @@ var PostgresMigrationPlanner = class {
|
|
|
67
63
|
});
|
|
68
64
|
return plannerSuccess(plan);
|
|
69
65
|
}
|
|
70
|
-
validateExtensions(contract) {
|
|
71
|
-
const extensions = contract.extensions ?? {};
|
|
72
|
-
const extensionNames = Object.keys(extensions);
|
|
73
|
-
const databaseExtensions = extensionNames.filter(
|
|
74
|
-
(extensionName) => !ADAPTER_LEVEL_EXTENSIONS.has(extensionName)
|
|
75
|
-
);
|
|
76
|
-
const unsupportedExtensions = databaseExtensions.filter(
|
|
77
|
-
(extensionName) => !PG_EXTENSION_SQL[extensionName]
|
|
78
|
-
);
|
|
79
|
-
if (unsupportedExtensions.length > 0) {
|
|
80
|
-
const supportedExtensions = Object.keys(PG_EXTENSION_SQL).join(", ");
|
|
81
|
-
const unsupportedList = unsupportedExtensions.join(", ");
|
|
82
|
-
return plannerFailure([
|
|
83
|
-
{
|
|
84
|
-
kind: "unsupportedExtension",
|
|
85
|
-
summary: `Unsupported PostgreSQL extensions in contract: ${unsupportedList}`,
|
|
86
|
-
why: `The Postgres migration planner currently only supports: ${supportedExtensions}. Extensions are defined in contract.extensions.`,
|
|
87
|
-
location: { extension: unsupportedList }
|
|
88
|
-
}
|
|
89
|
-
]);
|
|
90
|
-
}
|
|
91
|
-
return null;
|
|
92
|
-
}
|
|
93
66
|
ensureAdditivePolicy(policy) {
|
|
94
67
|
if (!policy.allowedOperationClasses.includes("additive")) {
|
|
95
68
|
return plannerFailure([
|
|
@@ -102,96 +75,204 @@ var PostgresMigrationPlanner = class {
|
|
|
102
75
|
}
|
|
103
76
|
return null;
|
|
104
77
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
78
|
+
/**
|
|
79
|
+
* Builds migration operations from component-owned database dependencies.
|
|
80
|
+
* These operations install database-side persistence structures declared by components.
|
|
81
|
+
*/
|
|
82
|
+
buildDatabaseDependencyOperations(options) {
|
|
83
|
+
const dependencies = this.collectDependencies(options);
|
|
108
84
|
const operations = [];
|
|
109
|
-
|
|
110
|
-
|
|
85
|
+
const seenDependencyIds = /* @__PURE__ */ new Set();
|
|
86
|
+
const seenOperationIds = /* @__PURE__ */ new Set();
|
|
87
|
+
for (const dependency of dependencies) {
|
|
88
|
+
if (seenDependencyIds.has(dependency.id)) {
|
|
89
|
+
continue;
|
|
90
|
+
}
|
|
91
|
+
seenDependencyIds.add(dependency.id);
|
|
92
|
+
const issues = dependency.verifyDatabaseDependencyInstalled(options.schema);
|
|
93
|
+
if (issues.length === 0) {
|
|
111
94
|
continue;
|
|
112
95
|
}
|
|
113
|
-
const
|
|
114
|
-
|
|
115
|
-
|
|
96
|
+
for (const installOp of dependency.install) {
|
|
97
|
+
if (seenOperationIds.has(installOp.id)) {
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
seenOperationIds.add(installOp.id);
|
|
101
|
+
operations.push(installOp);
|
|
116
102
|
}
|
|
117
|
-
|
|
103
|
+
}
|
|
104
|
+
return operations;
|
|
105
|
+
}
|
|
106
|
+
collectDependencies(options) {
|
|
107
|
+
const components = options.frameworkComponents;
|
|
108
|
+
if (components.length === 0) {
|
|
109
|
+
return [];
|
|
110
|
+
}
|
|
111
|
+
const deps = [];
|
|
112
|
+
for (const component of components) {
|
|
113
|
+
if (!isSqlDependencyProvider(component)) {
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
const initDeps = component.databaseDependencies?.init;
|
|
117
|
+
if (initDeps && initDeps.length > 0) {
|
|
118
|
+
deps.push(...initDeps);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
return sortDependencies(deps);
|
|
122
|
+
}
|
|
123
|
+
buildTableOperations(tables, schema, schemaName) {
|
|
124
|
+
const operations = [];
|
|
125
|
+
for (const [tableName, table] of sortedEntries(tables)) {
|
|
126
|
+
if (schema.tables[tableName]) {
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
const qualified = qualifyTableName(schemaName, tableName);
|
|
118
130
|
operations.push({
|
|
119
|
-
id: `
|
|
120
|
-
label: `
|
|
121
|
-
summary: `
|
|
131
|
+
id: `table.${tableName}`,
|
|
132
|
+
label: `Create table ${tableName}`,
|
|
133
|
+
summary: `Creates table ${tableName} with required columns`,
|
|
122
134
|
operationClass: "additive",
|
|
123
|
-
target: {
|
|
135
|
+
target: {
|
|
136
|
+
id: "postgres",
|
|
137
|
+
details: this.buildTargetDetails("table", tableName, schemaName)
|
|
138
|
+
},
|
|
124
139
|
precheck: [
|
|
125
140
|
{
|
|
126
|
-
description: `
|
|
127
|
-
sql: `SELECT
|
|
128
|
-
this.extensionDatabaseName(extensionName)
|
|
129
|
-
)}')`
|
|
141
|
+
description: `ensure table "${tableName}" does not exist`,
|
|
142
|
+
sql: `SELECT to_regclass(${toRegclassLiteral(schemaName, tableName)}) IS NULL`
|
|
130
143
|
}
|
|
131
144
|
],
|
|
132
145
|
execute: [
|
|
133
146
|
{
|
|
134
|
-
description: `create
|
|
135
|
-
sql
|
|
147
|
+
description: `create table "${tableName}"`,
|
|
148
|
+
sql: buildCreateTableSql(qualified, table)
|
|
136
149
|
}
|
|
137
150
|
],
|
|
138
151
|
postcheck: [
|
|
139
152
|
{
|
|
140
|
-
description: `
|
|
141
|
-
sql: `SELECT
|
|
142
|
-
this.extensionDatabaseName(extensionName)
|
|
143
|
-
)}')`
|
|
153
|
+
description: `verify table "${tableName}" exists`,
|
|
154
|
+
sql: `SELECT to_regclass(${toRegclassLiteral(schemaName, tableName)}) IS NOT NULL`
|
|
144
155
|
}
|
|
145
156
|
]
|
|
146
157
|
});
|
|
147
158
|
}
|
|
148
159
|
return operations;
|
|
149
160
|
}
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
161
|
+
buildColumnOperations(tables, schema, schemaName) {
|
|
162
|
+
const operations = [];
|
|
163
|
+
for (const [tableName, table] of sortedEntries(tables)) {
|
|
164
|
+
const schemaTable = schema.tables[tableName];
|
|
165
|
+
if (!schemaTable) {
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
for (const [columnName, column] of sortedEntries(table.columns)) {
|
|
169
|
+
if (schemaTable.columns[columnName]) {
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
operations.push(this.buildAddColumnOperation(schemaName, tableName, columnName, column));
|
|
173
|
+
}
|
|
153
174
|
}
|
|
154
|
-
return
|
|
175
|
+
return operations;
|
|
176
|
+
}
|
|
177
|
+
buildAddColumnOperation(schema, tableName, columnName, column) {
|
|
178
|
+
const qualified = qualifyTableName(schema, tableName);
|
|
179
|
+
const notNull = column.nullable === false;
|
|
180
|
+
const precheck = [
|
|
181
|
+
{
|
|
182
|
+
description: `ensure column "${columnName}" is missing`,
|
|
183
|
+
sql: columnExistsCheck({ schema, table: tableName, column: columnName, exists: false })
|
|
184
|
+
},
|
|
185
|
+
...notNull ? [
|
|
186
|
+
{
|
|
187
|
+
description: `ensure table "${tableName}" is empty before adding NOT NULL column`,
|
|
188
|
+
sql: tableIsEmptyCheck(qualified)
|
|
189
|
+
}
|
|
190
|
+
] : []
|
|
191
|
+
];
|
|
192
|
+
const execute = [
|
|
193
|
+
{
|
|
194
|
+
description: `add column "${columnName}"`,
|
|
195
|
+
sql: buildAddColumnSql(qualified, columnName, column)
|
|
196
|
+
}
|
|
197
|
+
];
|
|
198
|
+
const postcheck = [
|
|
199
|
+
{
|
|
200
|
+
description: `verify column "${columnName}" exists`,
|
|
201
|
+
sql: columnExistsCheck({ schema, table: tableName, column: columnName })
|
|
202
|
+
},
|
|
203
|
+
...notNull ? [
|
|
204
|
+
{
|
|
205
|
+
description: `verify column "${columnName}" is NOT NULL`,
|
|
206
|
+
sql: columnIsNotNullCheck({ schema, table: tableName, column: columnName })
|
|
207
|
+
}
|
|
208
|
+
] : []
|
|
209
|
+
];
|
|
210
|
+
return {
|
|
211
|
+
id: `column.${tableName}.${columnName}`,
|
|
212
|
+
label: `Add column ${columnName} to ${tableName}`,
|
|
213
|
+
summary: `Adds column ${columnName} to table ${tableName}`,
|
|
214
|
+
operationClass: "additive",
|
|
215
|
+
target: {
|
|
216
|
+
id: "postgres",
|
|
217
|
+
details: this.buildTargetDetails("table", tableName, schema)
|
|
218
|
+
},
|
|
219
|
+
precheck,
|
|
220
|
+
execute,
|
|
221
|
+
postcheck
|
|
222
|
+
};
|
|
155
223
|
}
|
|
156
|
-
|
|
224
|
+
buildPrimaryKeyOperations(tables, schema, schemaName) {
|
|
157
225
|
const operations = [];
|
|
158
226
|
for (const [tableName, table] of sortedEntries(tables)) {
|
|
159
|
-
|
|
227
|
+
if (!table.primaryKey) {
|
|
228
|
+
continue;
|
|
229
|
+
}
|
|
230
|
+
const schemaTable = schema.tables[tableName];
|
|
231
|
+
if (!schemaTable || schemaTable.primaryKey) {
|
|
232
|
+
continue;
|
|
233
|
+
}
|
|
234
|
+
const constraintName = table.primaryKey.name ?? `${tableName}_pkey`;
|
|
160
235
|
operations.push({
|
|
161
|
-
id: `
|
|
162
|
-
label: `
|
|
163
|
-
summary: `
|
|
236
|
+
id: `primaryKey.${tableName}.${constraintName}`,
|
|
237
|
+
label: `Add primary key ${constraintName} on ${tableName}`,
|
|
238
|
+
summary: `Adds primary key ${constraintName} on ${tableName}`,
|
|
164
239
|
operationClass: "additive",
|
|
165
240
|
target: {
|
|
166
241
|
id: "postgres",
|
|
167
|
-
details: this.buildTargetDetails("table", tableName,
|
|
242
|
+
details: this.buildTargetDetails("table", tableName, schemaName)
|
|
168
243
|
},
|
|
169
244
|
precheck: [
|
|
170
245
|
{
|
|
171
|
-
description: `ensure
|
|
172
|
-
sql:
|
|
246
|
+
description: `ensure primary key does not exist on "${tableName}"`,
|
|
247
|
+
sql: tableHasPrimaryKeyCheck(schemaName, tableName, false)
|
|
173
248
|
}
|
|
174
249
|
],
|
|
175
250
|
execute: [
|
|
176
251
|
{
|
|
177
|
-
description: `
|
|
178
|
-
sql:
|
|
252
|
+
description: `add primary key "${constraintName}"`,
|
|
253
|
+
sql: `ALTER TABLE ${qualifyTableName(schemaName, tableName)}
|
|
254
|
+
ADD CONSTRAINT ${quoteIdentifier(constraintName)}
|
|
255
|
+
PRIMARY KEY (${table.primaryKey.columns.map(quoteIdentifier).join(", ")})`
|
|
179
256
|
}
|
|
180
257
|
],
|
|
181
258
|
postcheck: [
|
|
182
259
|
{
|
|
183
|
-
description: `verify
|
|
184
|
-
sql:
|
|
260
|
+
description: `verify primary key "${constraintName}" exists`,
|
|
261
|
+
sql: tableHasPrimaryKeyCheck(schemaName, tableName, true, constraintName)
|
|
185
262
|
}
|
|
186
263
|
]
|
|
187
264
|
});
|
|
188
265
|
}
|
|
189
266
|
return operations;
|
|
190
267
|
}
|
|
191
|
-
buildUniqueOperations(tables, schema) {
|
|
268
|
+
buildUniqueOperations(tables, schema, schemaName) {
|
|
192
269
|
const operations = [];
|
|
193
270
|
for (const [tableName, table] of sortedEntries(tables)) {
|
|
271
|
+
const schemaTable = schema.tables[tableName];
|
|
194
272
|
for (const unique of table.uniques) {
|
|
273
|
+
if (schemaTable && hasUniqueConstraint(schemaTable, unique.columns)) {
|
|
274
|
+
continue;
|
|
275
|
+
}
|
|
195
276
|
const constraintName = unique.name ?? `${tableName}_${unique.columns.join("_")}_key`;
|
|
196
277
|
operations.push({
|
|
197
278
|
id: `unique.${tableName}.${constraintName}`,
|
|
@@ -200,18 +281,18 @@ var PostgresMigrationPlanner = class {
|
|
|
200
281
|
operationClass: "additive",
|
|
201
282
|
target: {
|
|
202
283
|
id: "postgres",
|
|
203
|
-
details: this.buildTargetDetails("unique", constraintName,
|
|
284
|
+
details: this.buildTargetDetails("unique", constraintName, schemaName, tableName)
|
|
204
285
|
},
|
|
205
286
|
precheck: [
|
|
206
287
|
{
|
|
207
288
|
description: `ensure unique constraint "${constraintName}" is missing`,
|
|
208
|
-
sql: constraintExistsCheck({ constraintName, schema, exists: false })
|
|
289
|
+
sql: constraintExistsCheck({ constraintName, schema: schemaName, exists: false })
|
|
209
290
|
}
|
|
210
291
|
],
|
|
211
292
|
execute: [
|
|
212
293
|
{
|
|
213
294
|
description: `add unique constraint "${constraintName}"`,
|
|
214
|
-
sql: `ALTER TABLE ${qualifyTableName(
|
|
295
|
+
sql: `ALTER TABLE ${qualifyTableName(schemaName, tableName)}
|
|
215
296
|
ADD CONSTRAINT ${quoteIdentifier(constraintName)}
|
|
216
297
|
UNIQUE (${unique.columns.map(quoteIdentifier).join(", ")})`
|
|
217
298
|
}
|
|
@@ -219,7 +300,7 @@ UNIQUE (${unique.columns.map(quoteIdentifier).join(", ")})`
|
|
|
219
300
|
postcheck: [
|
|
220
301
|
{
|
|
221
302
|
description: `verify unique constraint "${constraintName}" exists`,
|
|
222
|
-
sql: constraintExistsCheck({ constraintName, schema })
|
|
303
|
+
sql: constraintExistsCheck({ constraintName, schema: schemaName })
|
|
223
304
|
}
|
|
224
305
|
]
|
|
225
306
|
});
|
|
@@ -227,10 +308,14 @@ UNIQUE (${unique.columns.map(quoteIdentifier).join(", ")})`
|
|
|
227
308
|
}
|
|
228
309
|
return operations;
|
|
229
310
|
}
|
|
230
|
-
buildIndexOperations(tables, schema) {
|
|
311
|
+
buildIndexOperations(tables, schema, schemaName) {
|
|
231
312
|
const operations = [];
|
|
232
313
|
for (const [tableName, table] of sortedEntries(tables)) {
|
|
314
|
+
const schemaTable = schema.tables[tableName];
|
|
233
315
|
for (const index of table.indexes) {
|
|
316
|
+
if (schemaTable && hasIndex(schemaTable, index.columns)) {
|
|
317
|
+
continue;
|
|
318
|
+
}
|
|
234
319
|
const indexName = index.name ?? `${tableName}_${index.columns.join("_")}_idx`;
|
|
235
320
|
operations.push({
|
|
236
321
|
id: `index.${tableName}.${indexName}`,
|
|
@@ -239,19 +324,19 @@ UNIQUE (${unique.columns.map(quoteIdentifier).join(", ")})`
|
|
|
239
324
|
operationClass: "additive",
|
|
240
325
|
target: {
|
|
241
326
|
id: "postgres",
|
|
242
|
-
details: this.buildTargetDetails("index", indexName,
|
|
327
|
+
details: this.buildTargetDetails("index", indexName, schemaName, tableName)
|
|
243
328
|
},
|
|
244
329
|
precheck: [
|
|
245
330
|
{
|
|
246
331
|
description: `ensure index "${indexName}" is missing`,
|
|
247
|
-
sql: `SELECT to_regclass(${toRegclassLiteral(
|
|
332
|
+
sql: `SELECT to_regclass(${toRegclassLiteral(schemaName, indexName)}) IS NULL`
|
|
248
333
|
}
|
|
249
334
|
],
|
|
250
335
|
execute: [
|
|
251
336
|
{
|
|
252
337
|
description: `create index "${indexName}"`,
|
|
253
338
|
sql: `CREATE INDEX ${quoteIdentifier(indexName)} ON ${qualifyTableName(
|
|
254
|
-
|
|
339
|
+
schemaName,
|
|
255
340
|
tableName
|
|
256
341
|
)} (${index.columns.map(quoteIdentifier).join(", ")})`
|
|
257
342
|
}
|
|
@@ -259,7 +344,7 @@ UNIQUE (${unique.columns.map(quoteIdentifier).join(", ")})`
|
|
|
259
344
|
postcheck: [
|
|
260
345
|
{
|
|
261
346
|
description: `verify index "${indexName}" exists`,
|
|
262
|
-
sql: `SELECT to_regclass(${toRegclassLiteral(
|
|
347
|
+
sql: `SELECT to_regclass(${toRegclassLiteral(schemaName, indexName)}) IS NOT NULL`
|
|
263
348
|
}
|
|
264
349
|
]
|
|
265
350
|
});
|
|
@@ -267,10 +352,14 @@ UNIQUE (${unique.columns.map(quoteIdentifier).join(", ")})`
|
|
|
267
352
|
}
|
|
268
353
|
return operations;
|
|
269
354
|
}
|
|
270
|
-
buildForeignKeyOperations(tables, schema) {
|
|
355
|
+
buildForeignKeyOperations(tables, schema, schemaName) {
|
|
271
356
|
const operations = [];
|
|
272
357
|
for (const [tableName, table] of sortedEntries(tables)) {
|
|
358
|
+
const schemaTable = schema.tables[tableName];
|
|
273
359
|
for (const foreignKey of table.foreignKeys) {
|
|
360
|
+
if (schemaTable && hasForeignKey(schemaTable, foreignKey)) {
|
|
361
|
+
continue;
|
|
362
|
+
}
|
|
274
363
|
const fkName = foreignKey.name ?? `${tableName}_${foreignKey.columns.join("_")}_fkey`;
|
|
275
364
|
operations.push({
|
|
276
365
|
id: `foreignKey.${tableName}.${fkName}`,
|
|
@@ -279,27 +368,31 @@ UNIQUE (${unique.columns.map(quoteIdentifier).join(", ")})`
|
|
|
279
368
|
operationClass: "additive",
|
|
280
369
|
target: {
|
|
281
370
|
id: "postgres",
|
|
282
|
-
details: this.buildTargetDetails("foreignKey", fkName,
|
|
371
|
+
details: this.buildTargetDetails("foreignKey", fkName, schemaName, tableName)
|
|
283
372
|
},
|
|
284
373
|
precheck: [
|
|
285
374
|
{
|
|
286
375
|
description: `ensure foreign key "${fkName}" is missing`,
|
|
287
|
-
sql: constraintExistsCheck({
|
|
376
|
+
sql: constraintExistsCheck({
|
|
377
|
+
constraintName: fkName,
|
|
378
|
+
schema: schemaName,
|
|
379
|
+
exists: false
|
|
380
|
+
})
|
|
288
381
|
}
|
|
289
382
|
],
|
|
290
383
|
execute: [
|
|
291
384
|
{
|
|
292
385
|
description: `add foreign key "${fkName}"`,
|
|
293
|
-
sql: `ALTER TABLE ${qualifyTableName(
|
|
386
|
+
sql: `ALTER TABLE ${qualifyTableName(schemaName, tableName)}
|
|
294
387
|
ADD CONSTRAINT ${quoteIdentifier(fkName)}
|
|
295
388
|
FOREIGN KEY (${foreignKey.columns.map(quoteIdentifier).join(", ")})
|
|
296
|
-
REFERENCES ${qualifyTableName(
|
|
389
|
+
REFERENCES ${qualifyTableName(schemaName, foreignKey.references.table)} (${foreignKey.references.columns.map(quoteIdentifier).join(", ")})`
|
|
297
390
|
}
|
|
298
391
|
],
|
|
299
392
|
postcheck: [
|
|
300
393
|
{
|
|
301
394
|
description: `verify foreign key "${fkName}" exists`,
|
|
302
|
-
sql: constraintExistsCheck({ constraintName: fkName, schema })
|
|
395
|
+
sql: constraintExistsCheck({ constraintName: fkName, schema: schemaName })
|
|
303
396
|
}
|
|
304
397
|
]
|
|
305
398
|
});
|
|
@@ -315,7 +408,86 @@ REFERENCES ${qualifyTableName(schema, foreignKey.references.table)} (${foreignKe
|
|
|
315
408
|
...table ? { table } : {}
|
|
316
409
|
};
|
|
317
410
|
}
|
|
411
|
+
classifySchema(options) {
|
|
412
|
+
const verifyOptions = {
|
|
413
|
+
contract: options.contract,
|
|
414
|
+
schema: options.schema,
|
|
415
|
+
strict: false,
|
|
416
|
+
typeMetadataRegistry: /* @__PURE__ */ new Map(),
|
|
417
|
+
frameworkComponents: options.frameworkComponents
|
|
418
|
+
};
|
|
419
|
+
const verifyResult = verifySqlSchema(verifyOptions);
|
|
420
|
+
const conflicts = this.extractConflicts(verifyResult.schema.issues);
|
|
421
|
+
if (conflicts.length > 0) {
|
|
422
|
+
return { kind: "conflict", conflicts };
|
|
423
|
+
}
|
|
424
|
+
return { kind: "ok" };
|
|
425
|
+
}
|
|
426
|
+
extractConflicts(issues) {
|
|
427
|
+
const conflicts = [];
|
|
428
|
+
for (const issue of issues) {
|
|
429
|
+
if (isAdditiveIssue(issue)) {
|
|
430
|
+
continue;
|
|
431
|
+
}
|
|
432
|
+
const conflict = this.convertIssueToConflict(issue);
|
|
433
|
+
if (conflict) {
|
|
434
|
+
conflicts.push(conflict);
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
return conflicts.sort(conflictComparator);
|
|
438
|
+
}
|
|
439
|
+
convertIssueToConflict(issue) {
|
|
440
|
+
switch (issue.kind) {
|
|
441
|
+
case "type_mismatch":
|
|
442
|
+
return this.buildConflict("typeMismatch", issue);
|
|
443
|
+
case "nullability_mismatch":
|
|
444
|
+
return this.buildConflict("nullabilityConflict", issue);
|
|
445
|
+
case "primary_key_mismatch":
|
|
446
|
+
return this.buildConflict("indexIncompatible", issue);
|
|
447
|
+
case "unique_constraint_mismatch":
|
|
448
|
+
return this.buildConflict("indexIncompatible", issue);
|
|
449
|
+
case "index_mismatch":
|
|
450
|
+
return this.buildConflict("indexIncompatible", issue);
|
|
451
|
+
case "foreign_key_mismatch":
|
|
452
|
+
return this.buildConflict("foreignKeyConflict", issue);
|
|
453
|
+
default:
|
|
454
|
+
return null;
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
buildConflict(kind, issue) {
|
|
458
|
+
const location = buildConflictLocation(issue);
|
|
459
|
+
const meta = issue.expected || issue.actual ? Object.freeze({
|
|
460
|
+
...issue.expected ? { expected: issue.expected } : {},
|
|
461
|
+
...issue.actual ? { actual: issue.actual } : {}
|
|
462
|
+
}) : void 0;
|
|
463
|
+
return {
|
|
464
|
+
kind,
|
|
465
|
+
summary: issue.message,
|
|
466
|
+
...location ? { location } : {},
|
|
467
|
+
...meta ? { meta } : {}
|
|
468
|
+
};
|
|
469
|
+
}
|
|
318
470
|
};
|
|
471
|
+
function isSqlDependencyProvider(component) {
|
|
472
|
+
if (typeof component !== "object" || component === null) {
|
|
473
|
+
return false;
|
|
474
|
+
}
|
|
475
|
+
const record = component;
|
|
476
|
+
if (Object.hasOwn(record, "familyId") && record["familyId"] !== "sql") {
|
|
477
|
+
return false;
|
|
478
|
+
}
|
|
479
|
+
if (!Object.hasOwn(record, "databaseDependencies")) {
|
|
480
|
+
return false;
|
|
481
|
+
}
|
|
482
|
+
const deps = record["databaseDependencies"];
|
|
483
|
+
return deps === void 0 || typeof deps === "object" && deps !== null;
|
|
484
|
+
}
|
|
485
|
+
function sortDependencies(dependencies) {
|
|
486
|
+
if (dependencies.length <= 1) {
|
|
487
|
+
return dependencies;
|
|
488
|
+
}
|
|
489
|
+
return [...dependencies].sort((a, b) => a.id.localeCompare(b.id));
|
|
490
|
+
}
|
|
319
491
|
function buildCreateTableSql(qualifiedTableName, table) {
|
|
320
492
|
const columnDefinitions = Object.entries(table.columns).map(
|
|
321
493
|
([columnName, column]) => {
|
|
@@ -367,10 +539,137 @@ function constraintExistsCheck({
|
|
|
367
539
|
AND n.nspname = '${escapeLiteral(schema)}'
|
|
368
540
|
)`;
|
|
369
541
|
}
|
|
542
|
+
function columnExistsCheck({
|
|
543
|
+
schema,
|
|
544
|
+
table,
|
|
545
|
+
column,
|
|
546
|
+
exists = true
|
|
547
|
+
}) {
|
|
548
|
+
const existsClause = exists ? "" : "NOT ";
|
|
549
|
+
return `SELECT ${existsClause}EXISTS (
|
|
550
|
+
SELECT 1
|
|
551
|
+
FROM information_schema.columns
|
|
552
|
+
WHERE table_schema = '${escapeLiteral(schema)}'
|
|
553
|
+
AND table_name = '${escapeLiteral(table)}'
|
|
554
|
+
AND column_name = '${escapeLiteral(column)}'
|
|
555
|
+
)`;
|
|
556
|
+
}
|
|
557
|
+
function columnIsNotNullCheck({
|
|
558
|
+
schema,
|
|
559
|
+
table,
|
|
560
|
+
column
|
|
561
|
+
}) {
|
|
562
|
+
return `SELECT EXISTS (
|
|
563
|
+
SELECT 1
|
|
564
|
+
FROM information_schema.columns
|
|
565
|
+
WHERE table_schema = '${escapeLiteral(schema)}'
|
|
566
|
+
AND table_name = '${escapeLiteral(table)}'
|
|
567
|
+
AND column_name = '${escapeLiteral(column)}'
|
|
568
|
+
AND is_nullable = 'NO'
|
|
569
|
+
)`;
|
|
570
|
+
}
|
|
571
|
+
function tableIsEmptyCheck(qualifiedTableName) {
|
|
572
|
+
return `SELECT NOT EXISTS (SELECT 1 FROM ${qualifiedTableName} LIMIT 1)`;
|
|
573
|
+
}
|
|
574
|
+
function buildAddColumnSql(qualifiedTableName, columnName, column) {
|
|
575
|
+
const parts = [
|
|
576
|
+
`ALTER TABLE ${qualifiedTableName}`,
|
|
577
|
+
`ADD COLUMN ${quoteIdentifier(columnName)} ${column.nativeType}`,
|
|
578
|
+
column.nullable ? "" : "NOT NULL"
|
|
579
|
+
].filter(Boolean);
|
|
580
|
+
return parts.join(" ");
|
|
581
|
+
}
|
|
582
|
+
function tableHasPrimaryKeyCheck(schema, table, exists, constraintName) {
|
|
583
|
+
const comparison = exists ? "" : "NOT ";
|
|
584
|
+
const constraintFilter = constraintName ? `AND c2.relname = '${escapeLiteral(constraintName)}'` : "";
|
|
585
|
+
return `SELECT ${comparison}EXISTS (
|
|
586
|
+
SELECT 1
|
|
587
|
+
FROM pg_index i
|
|
588
|
+
JOIN pg_class c ON c.oid = i.indrelid
|
|
589
|
+
JOIN pg_namespace n ON n.oid = c.relnamespace
|
|
590
|
+
LEFT JOIN pg_class c2 ON c2.oid = i.indexrelid
|
|
591
|
+
WHERE n.nspname = '${escapeLiteral(schema)}'
|
|
592
|
+
AND c.relname = '${escapeLiteral(table)}'
|
|
593
|
+
AND i.indisprimary
|
|
594
|
+
${constraintFilter}
|
|
595
|
+
)`;
|
|
596
|
+
}
|
|
597
|
+
function hasUniqueConstraint(table, columns) {
|
|
598
|
+
return table.uniques.some((unique) => arraysEqual(unique.columns, columns));
|
|
599
|
+
}
|
|
600
|
+
function hasIndex(table, columns) {
|
|
601
|
+
return table.indexes.some((index) => !index.unique && arraysEqual(index.columns, columns));
|
|
602
|
+
}
|
|
603
|
+
function hasForeignKey(table, fk) {
|
|
604
|
+
return table.foreignKeys.some(
|
|
605
|
+
(candidate) => arraysEqual(candidate.columns, fk.columns) && candidate.referencedTable === fk.references.table && arraysEqual(candidate.referencedColumns, fk.references.columns)
|
|
606
|
+
);
|
|
607
|
+
}
|
|
608
|
+
function isAdditiveIssue(issue) {
|
|
609
|
+
switch (issue.kind) {
|
|
610
|
+
case "missing_table":
|
|
611
|
+
case "missing_column":
|
|
612
|
+
case "extension_missing":
|
|
613
|
+
return true;
|
|
614
|
+
case "primary_key_mismatch":
|
|
615
|
+
return issue.actual === void 0;
|
|
616
|
+
case "unique_constraint_mismatch":
|
|
617
|
+
case "index_mismatch":
|
|
618
|
+
case "foreign_key_mismatch":
|
|
619
|
+
return issue.indexOrConstraint === void 0;
|
|
620
|
+
default:
|
|
621
|
+
return false;
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
function buildConflictLocation(issue) {
|
|
625
|
+
const location = {};
|
|
626
|
+
if (issue.table) {
|
|
627
|
+
location.table = issue.table;
|
|
628
|
+
}
|
|
629
|
+
if (issue.column) {
|
|
630
|
+
location.column = issue.column;
|
|
631
|
+
}
|
|
632
|
+
if (issue.indexOrConstraint) {
|
|
633
|
+
location.constraint = issue.indexOrConstraint;
|
|
634
|
+
}
|
|
635
|
+
return Object.keys(location).length > 0 ? location : void 0;
|
|
636
|
+
}
|
|
637
|
+
function conflictComparator(a, b) {
|
|
638
|
+
if (a.kind !== b.kind) {
|
|
639
|
+
return a.kind < b.kind ? -1 : 1;
|
|
640
|
+
}
|
|
641
|
+
const aLocation = a.location ?? {};
|
|
642
|
+
const bLocation = b.location ?? {};
|
|
643
|
+
const tableCompare = compareStrings(aLocation.table, bLocation.table);
|
|
644
|
+
if (tableCompare !== 0) {
|
|
645
|
+
return tableCompare;
|
|
646
|
+
}
|
|
647
|
+
const columnCompare = compareStrings(aLocation.column, bLocation.column);
|
|
648
|
+
if (columnCompare !== 0) {
|
|
649
|
+
return columnCompare;
|
|
650
|
+
}
|
|
651
|
+
const constraintCompare = compareStrings(aLocation.constraint, bLocation.constraint);
|
|
652
|
+
if (constraintCompare !== 0) {
|
|
653
|
+
return constraintCompare;
|
|
654
|
+
}
|
|
655
|
+
return compareStrings(a.summary, b.summary);
|
|
656
|
+
}
|
|
657
|
+
function compareStrings(a, b) {
|
|
658
|
+
if (a === b) {
|
|
659
|
+
return 0;
|
|
660
|
+
}
|
|
661
|
+
if (a === void 0) {
|
|
662
|
+
return -1;
|
|
663
|
+
}
|
|
664
|
+
if (b === void 0) {
|
|
665
|
+
return 1;
|
|
666
|
+
}
|
|
667
|
+
return a < b ? -1 : 1;
|
|
668
|
+
}
|
|
370
669
|
|
|
371
670
|
// src/core/migrations/runner.ts
|
|
372
671
|
import { runnerFailure, runnerSuccess } from "@prisma-next/family-sql/control";
|
|
373
|
-
import { verifySqlSchema } from "@prisma-next/family-sql/schema-verify";
|
|
672
|
+
import { verifySqlSchema as verifySqlSchema2 } from "@prisma-next/family-sql/schema-verify";
|
|
374
673
|
import { readMarker } from "@prisma-next/family-sql/verify";
|
|
375
674
|
import { ok, okVoid } from "@prisma-next/utils/result";
|
|
376
675
|
|
|
@@ -555,12 +854,13 @@ var PostgresMigrationRunner = class {
|
|
|
555
854
|
driver,
|
|
556
855
|
contractIR: options.destinationContract
|
|
557
856
|
});
|
|
558
|
-
const schemaVerifyResult =
|
|
857
|
+
const schemaVerifyResult = verifySqlSchema2({
|
|
559
858
|
contract: options.destinationContract,
|
|
560
859
|
schema: schemaIR,
|
|
561
860
|
strict: options.strictVerification ?? true,
|
|
562
861
|
context: options.context ?? {},
|
|
563
|
-
typeMetadataRegistry: this.family.typeMetadataRegistry
|
|
862
|
+
typeMetadataRegistry: this.family.typeMetadataRegistry,
|
|
863
|
+
frameworkComponents: options.frameworkComponents
|
|
564
864
|
});
|
|
565
865
|
if (!schemaVerifyResult.ok) {
|
|
566
866
|
return runnerFailure("SCHEMA_VERIFY_FAILED", schemaVerifyResult.summary, {
|
|
@@ -935,6 +1235,8 @@ var postgresTargetDescriptor = {
|
|
|
935
1235
|
manifest: loadTargetManifest(),
|
|
936
1236
|
/**
|
|
937
1237
|
* Migrations capability for CLI to access planner/runner via core types.
|
|
1238
|
+
* The SQL-specific planner/runner types are compatible with the generic
|
|
1239
|
+
* MigrationPlanner/MigrationRunner interfaces at runtime.
|
|
938
1240
|
*/
|
|
939
1241
|
migrations: {
|
|
940
1242
|
createPlanner(_family) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/exports/control.ts","../../src/core/migrations/planner.ts","../../src/core/migrations/runner.ts","../../src/core/migrations/statement-builders.ts"],"sourcesContent":["import { readFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport type { ExtensionPackManifest } from '@prisma-next/contract/pack-manifest-types';\nimport type { ControlTargetInstance } from '@prisma-next/core-control-plane/types';\nimport type {\n SqlControlFamilyInstance,\n SqlControlTargetDescriptor,\n} from '@prisma-next/family-sql/control';\nimport { type } from 'arktype';\nimport type { PostgresPlanTargetDetails } from '../core/migrations/planner';\nimport { createPostgresMigrationPlanner } from '../core/migrations/planner';\nimport { createPostgresMigrationRunner } from '../core/migrations/runner';\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n\nconst TypesImportSpecSchema = type({\n package: 'string',\n named: 'string',\n alias: 'string',\n});\n\nconst ExtensionPackManifestSchema = type({\n id: 'string',\n version: 'string',\n 'targets?': type({ '[string]': type({ 'minVersion?': 'string' }) }),\n 'capabilities?': 'Record<string, unknown>',\n 'types?': type({\n 'codecTypes?': type({\n import: TypesImportSpecSchema,\n }),\n 'operationTypes?': type({\n import: TypesImportSpecSchema,\n }),\n }),\n 'operations?': 'unknown[]',\n});\n\n/**\n * Loads the target manifest from packs/manifest.json.\n */\nfunction loadTargetManifest(): ExtensionPackManifest {\n const manifestPath = join(__dirname, '../../packs/manifest.json');\n const manifestJson = JSON.parse(readFileSync(manifestPath, 'utf-8'));\n\n const result = ExtensionPackManifestSchema(manifestJson);\n if (result instanceof type.errors) {\n const messages = result.map((p: { message: string }) => p.message).join('; ');\n throw new Error(`Invalid target manifest structure at ${manifestPath}: ${messages}`);\n }\n\n return result as ExtensionPackManifest;\n}\n\n/**\n * Postgres target descriptor for CLI config.\n */\nconst postgresTargetDescriptor: SqlControlTargetDescriptor<'postgres', PostgresPlanTargetDetails> =\n {\n kind: 'target',\n familyId: 'sql',\n targetId: 'postgres',\n id: 'postgres',\n manifest: loadTargetManifest(),\n /**\n * Migrations capability for CLI to access planner/runner via core types.\n */\n migrations: {\n createPlanner(_family: SqlControlFamilyInstance) {\n return createPostgresMigrationPlanner();\n },\n createRunner(family) {\n return createPostgresMigrationRunner(family);\n },\n },\n create(): ControlTargetInstance<'sql', 'postgres'> {\n return {\n familyId: 'sql',\n targetId: 'postgres',\n };\n },\n /**\n * Direct method for SQL-specific usage.\n * @deprecated Use migrations.createPlanner() for CLI compatibility.\n */\n createPlanner(_family: SqlControlFamilyInstance) {\n return createPostgresMigrationPlanner();\n },\n /**\n * Direct method for SQL-specific usage.\n * @deprecated Use migrations.createRunner() for CLI compatibility.\n */\n createRunner(family) {\n return createPostgresMigrationRunner(family);\n },\n };\n\nexport default postgresTargetDescriptor;\n","import type {\n MigrationOperationPolicy,\n SqlMigrationPlanner,\n SqlMigrationPlannerPlanOptions,\n SqlMigrationPlanOperation,\n} from '@prisma-next/family-sql/control';\nimport {\n createMigrationPlan,\n plannerFailure,\n plannerSuccess,\n} from '@prisma-next/family-sql/control';\nimport type {\n SqlContract,\n SqlStorage,\n StorageColumn,\n StorageTable,\n} from '@prisma-next/sql-contract/types';\n\ntype OperationClass = 'extension' | 'table' | 'unique' | 'index' | 'foreignKey';\n\nexport interface PostgresPlanTargetDetails {\n readonly schema: string;\n readonly objectType: OperationClass;\n readonly name: string;\n readonly table?: string;\n}\n\ninterface PlannerConfig {\n readonly defaultSchema: string;\n}\n\nconst DEFAULT_PLANNER_CONFIG: PlannerConfig = {\n defaultSchema: 'public',\n};\n\nconst PG_EXTENSION_SQL: Record<string, string> = {\n pgvector: 'CREATE EXTENSION IF NOT EXISTS vector',\n};\n\n/**\n * Adapter-level extensions that are NOT PostgreSQL database extensions.\n * These are metadata namespaces used by adapters for codec IDs (e.g., 'pg/int4@1').\n * The planner should skip these when validating extensions.\n */\nconst ADAPTER_LEVEL_EXTENSIONS = new Set(['pg', 'postgres']);\n\nexport function createPostgresMigrationPlanner(\n config: Partial<PlannerConfig> = {},\n): SqlMigrationPlanner<PostgresPlanTargetDetails> {\n return new PostgresMigrationPlanner({\n ...DEFAULT_PLANNER_CONFIG,\n ...config,\n });\n}\n\nclass PostgresMigrationPlanner implements SqlMigrationPlanner<PostgresPlanTargetDetails> {\n constructor(private readonly config: PlannerConfig) {}\n\n plan(options: SqlMigrationPlannerPlanOptions) {\n const schemaName = options.schemaName ?? this.config.defaultSchema;\n const policyResult = this.ensureAdditivePolicy(options.policy);\n if (policyResult) {\n return policyResult;\n }\n\n const existingTables = Object.keys(options.schema.tables);\n if (existingTables.length > 0) {\n const tableList = existingTables.sort().join(', ');\n return plannerFailure([\n {\n kind: 'unsupportedOperation',\n summary: `The Postgres migration planner currently supports only empty databases. Found ${existingTables.length} existing table(s): ${tableList}`,\n why: 'Remove existing tables or use a future planner mode that handles subsets/supersets.',\n },\n ]);\n }\n\n const extensionResult = this.validateExtensions(options.contract);\n if (extensionResult) {\n return extensionResult;\n }\n\n const operations: SqlMigrationPlanOperation<PostgresPlanTargetDetails>[] = [];\n\n operations.push(\n ...this.buildExtensionOperations(options.contract, schemaName),\n ...this.buildTableOperations(options.contract.storage.tables, schemaName),\n ...this.buildUniqueOperations(options.contract.storage.tables, schemaName),\n ...this.buildIndexOperations(options.contract.storage.tables, schemaName),\n ...this.buildForeignKeyOperations(options.contract.storage.tables, schemaName),\n );\n\n const plan = createMigrationPlan<PostgresPlanTargetDetails>({\n targetId: 'postgres',\n origin: null,\n destination: {\n coreHash: options.contract.coreHash,\n ...(options.contract.profileHash ? { profileHash: options.contract.profileHash } : {}),\n },\n operations,\n });\n\n return plannerSuccess(plan);\n }\n\n private validateExtensions(contract: SqlContract<SqlStorage>) {\n const extensions = contract.extensions ?? {};\n const extensionNames = Object.keys(extensions);\n // Filter out adapter-level extensions (like 'pg', 'postgres') which are metadata namespaces\n // used by adapters for codec IDs, not PostgreSQL database extensions\n const databaseExtensions = extensionNames.filter(\n (extensionName) => !ADAPTER_LEVEL_EXTENSIONS.has(extensionName),\n );\n const unsupportedExtensions = databaseExtensions.filter(\n (extensionName) => !PG_EXTENSION_SQL[extensionName],\n );\n if (unsupportedExtensions.length > 0) {\n const supportedExtensions = Object.keys(PG_EXTENSION_SQL).join(', ');\n const unsupportedList = unsupportedExtensions.join(', ');\n return plannerFailure([\n {\n kind: 'unsupportedExtension' as const,\n summary: `Unsupported PostgreSQL extensions in contract: ${unsupportedList}`,\n why: `The Postgres migration planner currently only supports: ${supportedExtensions}. Extensions are defined in contract.extensions.`,\n location: { extension: unsupportedList },\n },\n ]);\n }\n return null;\n }\n\n private ensureAdditivePolicy(policy: MigrationOperationPolicy) {\n if (!policy.allowedOperationClasses.includes('additive')) {\n return plannerFailure([\n {\n kind: 'unsupportedOperation',\n summary: 'Init planner requires additive operations be allowed',\n why: 'The init planner only emits additive operations. Update the policy to include \"additive\".',\n },\n ]);\n }\n return null;\n }\n\n private buildExtensionOperations(\n contract: SqlContract<SqlStorage>,\n schema: string,\n ): readonly SqlMigrationPlanOperation<PostgresPlanTargetDetails>[] {\n const extensions = contract.extensions ?? {};\n const extensionNames = Object.keys(extensions);\n const operations: SqlMigrationPlanOperation<PostgresPlanTargetDetails>[] = [];\n\n // Extensions are validated in validateExtensions() before this method is called\n for (const extensionName of extensionNames) {\n // Skip adapter-level extensions (metadata namespaces, not database extensions)\n if (ADAPTER_LEVEL_EXTENSIONS.has(extensionName)) {\n continue;\n }\n const sql = PG_EXTENSION_SQL[extensionName];\n if (!sql) {\n // This should never happen since we validate extensions in validateExtensions(), but TypeScript requires this check\n throw new Error(`Extension SQL not found for ${extensionName}`);\n }\n const details = this.buildTargetDetails('extension', extensionName, schema);\n operations.push({\n id: `extension.${extensionName}`,\n label: `Enable extension \"${extensionName}\"`,\n summary: `Ensures the ${extensionName} extension is available`,\n operationClass: 'additive',\n target: { id: 'postgres', details },\n precheck: [\n {\n description: `verify extension \"${extensionName}\" is not already enabled`,\n sql: `SELECT NOT EXISTS (SELECT 1 FROM pg_extension WHERE extname = '${escapeLiteral(\n this.extensionDatabaseName(extensionName),\n )}')`,\n },\n ],\n execute: [\n {\n description: `create extension \"${extensionName}\"`,\n sql,\n },\n ],\n postcheck: [\n {\n description: `confirm extension \"${extensionName}\" is enabled`,\n sql: `SELECT EXISTS (SELECT 1 FROM pg_extension WHERE extname = '${escapeLiteral(\n this.extensionDatabaseName(extensionName),\n )}')`,\n },\n ],\n });\n }\n\n return operations;\n }\n\n private extensionDatabaseName(extensionName: string): string {\n if (extensionName === 'pgvector') {\n return 'vector';\n }\n return extensionName;\n }\n\n private buildTableOperations(\n tables: SqlContract<SqlStorage>['storage']['tables'],\n schema: string,\n ): readonly SqlMigrationPlanOperation<PostgresPlanTargetDetails>[] {\n const operations: SqlMigrationPlanOperation<PostgresPlanTargetDetails>[] = [];\n for (const [tableName, table] of sortedEntries(tables)) {\n const qualified = qualifyTableName(schema, tableName);\n operations.push({\n id: `table.${tableName}`,\n label: `Create table ${tableName}`,\n summary: `Creates table ${tableName} with required columns`,\n operationClass: 'additive',\n target: {\n id: 'postgres',\n details: this.buildTargetDetails('table', tableName, schema),\n },\n precheck: [\n {\n description: `ensure table \"${tableName}\" does not exist`,\n sql: `SELECT to_regclass(${toRegclassLiteral(schema, tableName)}) IS NULL`,\n },\n ],\n execute: [\n {\n description: `create table \"${tableName}\"`,\n sql: buildCreateTableSql(qualified, table),\n },\n ],\n postcheck: [\n {\n description: `verify table \"${tableName}\" exists`,\n sql: `SELECT to_regclass(${toRegclassLiteral(schema, tableName)}) IS NOT NULL`,\n },\n ],\n });\n }\n return operations;\n }\n\n private buildUniqueOperations(\n tables: SqlContract<SqlStorage>['storage']['tables'],\n schema: string,\n ): readonly SqlMigrationPlanOperation<PostgresPlanTargetDetails>[] {\n const operations: SqlMigrationPlanOperation<PostgresPlanTargetDetails>[] = [];\n for (const [tableName, table] of sortedEntries(tables)) {\n for (const unique of table.uniques) {\n const constraintName = unique.name ?? `${tableName}_${unique.columns.join('_')}_key`;\n operations.push({\n id: `unique.${tableName}.${constraintName}`,\n label: `Add unique constraint ${constraintName} on ${tableName}`,\n summary: `Adds unique constraint ${constraintName} on ${tableName}`,\n operationClass: 'additive',\n target: {\n id: 'postgres',\n details: this.buildTargetDetails('unique', constraintName, schema, tableName),\n },\n precheck: [\n {\n description: `ensure unique constraint \"${constraintName}\" is missing`,\n sql: constraintExistsCheck({ constraintName, schema, exists: false }),\n },\n ],\n execute: [\n {\n description: `add unique constraint \"${constraintName}\"`,\n sql: `ALTER TABLE ${qualifyTableName(schema, tableName)}\nADD CONSTRAINT ${quoteIdentifier(constraintName)}\nUNIQUE (${unique.columns.map(quoteIdentifier).join(', ')})`,\n },\n ],\n postcheck: [\n {\n description: `verify unique constraint \"${constraintName}\" exists`,\n sql: constraintExistsCheck({ constraintName, schema }),\n },\n ],\n });\n }\n }\n return operations;\n }\n\n private buildIndexOperations(\n tables: SqlContract<SqlStorage>['storage']['tables'],\n schema: string,\n ): readonly SqlMigrationPlanOperation<PostgresPlanTargetDetails>[] {\n const operations: SqlMigrationPlanOperation<PostgresPlanTargetDetails>[] = [];\n for (const [tableName, table] of sortedEntries(tables)) {\n for (const index of table.indexes) {\n const indexName = index.name ?? `${tableName}_${index.columns.join('_')}_idx`;\n operations.push({\n id: `index.${tableName}.${indexName}`,\n label: `Create index ${indexName} on ${tableName}`,\n summary: `Creates index ${indexName} on ${tableName}`,\n operationClass: 'additive',\n target: {\n id: 'postgres',\n details: this.buildTargetDetails('index', indexName, schema, tableName),\n },\n precheck: [\n {\n description: `ensure index \"${indexName}\" is missing`,\n sql: `SELECT to_regclass(${toRegclassLiteral(schema, indexName)}) IS NULL`,\n },\n ],\n execute: [\n {\n description: `create index \"${indexName}\"`,\n sql: `CREATE INDEX ${quoteIdentifier(indexName)} ON ${qualifyTableName(\n schema,\n tableName,\n )} (${index.columns.map(quoteIdentifier).join(', ')})`,\n },\n ],\n postcheck: [\n {\n description: `verify index \"${indexName}\" exists`,\n sql: `SELECT to_regclass(${toRegclassLiteral(schema, indexName)}) IS NOT NULL`,\n },\n ],\n });\n }\n }\n return operations;\n }\n\n private buildForeignKeyOperations(\n tables: SqlContract<SqlStorage>['storage']['tables'],\n schema: string,\n ): readonly SqlMigrationPlanOperation<PostgresPlanTargetDetails>[] {\n const operations: SqlMigrationPlanOperation<PostgresPlanTargetDetails>[] = [];\n for (const [tableName, table] of sortedEntries(tables)) {\n for (const foreignKey of table.foreignKeys) {\n const fkName = foreignKey.name ?? `${tableName}_${foreignKey.columns.join('_')}_fkey`;\n operations.push({\n id: `foreignKey.${tableName}.${fkName}`,\n label: `Add foreign key ${fkName} on ${tableName}`,\n summary: `Adds foreign key ${fkName} referencing ${foreignKey.references.table}`,\n operationClass: 'additive',\n target: {\n id: 'postgres',\n details: this.buildTargetDetails('foreignKey', fkName, schema, tableName),\n },\n precheck: [\n {\n description: `ensure foreign key \"${fkName}\" is missing`,\n sql: constraintExistsCheck({ constraintName: fkName, schema, exists: false }),\n },\n ],\n execute: [\n {\n description: `add foreign key \"${fkName}\"`,\n sql: `ALTER TABLE ${qualifyTableName(schema, tableName)}\nADD CONSTRAINT ${quoteIdentifier(fkName)}\nFOREIGN KEY (${foreignKey.columns.map(quoteIdentifier).join(', ')})\nREFERENCES ${qualifyTableName(schema, foreignKey.references.table)} (${foreignKey.references.columns\n .map(quoteIdentifier)\n .join(', ')})`,\n },\n ],\n postcheck: [\n {\n description: `verify foreign key \"${fkName}\" exists`,\n sql: constraintExistsCheck({ constraintName: fkName, schema }),\n },\n ],\n });\n }\n }\n return operations;\n }\n\n private buildTargetDetails(\n objectType: OperationClass,\n name: string,\n schema: string,\n table?: string,\n ): PostgresPlanTargetDetails {\n return {\n schema,\n objectType,\n name,\n ...(table ? { table } : {}),\n };\n }\n}\n\nfunction buildCreateTableSql(qualifiedTableName: string, table: StorageTable): string {\n const columnDefinitions = Object.entries(table.columns).map(\n ([columnName, column]: [string, StorageColumn]) => {\n const parts = [\n quoteIdentifier(columnName),\n column.nativeType,\n column.nullable ? '' : 'NOT NULL',\n ].filter(Boolean);\n return parts.join(' ');\n },\n );\n\n const constraintDefinitions: string[] = [];\n if (table.primaryKey) {\n constraintDefinitions.push(\n `PRIMARY KEY (${table.primaryKey.columns.map(quoteIdentifier).join(', ')})`,\n );\n }\n\n const allDefinitions = [...columnDefinitions, ...constraintDefinitions];\n return `CREATE TABLE ${qualifiedTableName} (\\n ${allDefinitions.join(',\\n ')}\\n)`;\n}\n\nfunction qualifyTableName(schema: string, table: string): string {\n return `${quoteIdentifier(schema)}.${quoteIdentifier(table)}`;\n}\n\nfunction toRegclassLiteral(schema: string, name: string): string {\n const regclass = `${quoteIdentifier(schema)}.${quoteIdentifier(name)}`;\n return `'${escapeLiteral(regclass)}'`;\n}\n\nfunction quoteIdentifier(identifier: string): string {\n return `\"${identifier.replace(/\"/g, '\"\"')}\"`;\n}\n\nfunction escapeLiteral(value: string): string {\n return value.replace(/'/g, \"''\");\n}\n\nfunction sortedEntries<V>(record: Readonly<Record<string, V>>): Array<[string, V]> {\n return Object.entries(record).sort(([a], [b]) => a.localeCompare(b)) as Array<[string, V]>;\n}\n\nfunction constraintExistsCheck({\n constraintName,\n schema,\n exists = true,\n}: {\n constraintName: string;\n schema: string;\n exists?: boolean;\n}): string {\n const existsClause = exists ? 'EXISTS' : 'NOT EXISTS';\n return `SELECT ${existsClause} (\n SELECT 1 FROM pg_constraint c\n JOIN pg_namespace n ON c.connamespace = n.oid\n WHERE c.conname = '${escapeLiteral(constraintName)}'\n AND n.nspname = '${escapeLiteral(schema)}'\n)`;\n}\n","import type { ContractMarkerRecord } from '@prisma-next/contract/types';\nimport type {\n MigrationOperationPolicy,\n SqlControlFamilyInstance,\n SqlMigrationPlanContractInfo,\n SqlMigrationPlanOperation,\n SqlMigrationPlanOperationStep,\n SqlMigrationRunner,\n SqlMigrationRunnerExecuteOptions,\n SqlMigrationRunnerFailure,\n SqlMigrationRunnerResult,\n} from '@prisma-next/family-sql/control';\nimport { runnerFailure, runnerSuccess } from '@prisma-next/family-sql/control';\nimport { verifySqlSchema } from '@prisma-next/family-sql/schema-verify';\nimport { readMarker } from '@prisma-next/family-sql/verify';\nimport type { Result } from '@prisma-next/utils/result';\nimport { ok, okVoid } from '@prisma-next/utils/result';\nimport type { PostgresPlanTargetDetails } from './planner';\nimport {\n buildLedgerInsertStatement,\n buildWriteMarkerStatements,\n ensureLedgerTableStatement,\n ensureMarkerTableStatement,\n ensurePrismaContractSchemaStatement,\n type SqlStatement,\n} from './statement-builders';\n\ninterface RunnerConfig {\n readonly defaultSchema: string;\n}\n\ninterface ApplyPlanSuccessValue {\n readonly operationsExecuted: number;\n readonly executedOperations: readonly SqlMigrationPlanOperation<PostgresPlanTargetDetails>[];\n}\n\nconst DEFAULT_CONFIG: RunnerConfig = {\n defaultSchema: 'public',\n};\n\nconst LOCK_DOMAIN = 'prisma_next.contract.marker';\n\n/**\n * Deep clones and freezes a record object to prevent mutation.\n * Recursively clones nested objects and arrays to ensure complete isolation.\n */\nfunction cloneAndFreezeRecord<T extends Record<string, unknown>>(value: T): T {\n const cloned: Record<string, unknown> = {};\n for (const [key, val] of Object.entries(value)) {\n if (val === null || val === undefined) {\n cloned[key] = val;\n } else if (Array.isArray(val)) {\n // Clone array (shallow clone of array elements)\n cloned[key] = Object.freeze([...val]);\n } else if (typeof val === 'object') {\n // Recursively clone nested objects\n cloned[key] = cloneAndFreezeRecord(val as Record<string, unknown>);\n } else {\n // Primitives are copied as-is\n cloned[key] = val;\n }\n }\n return Object.freeze(cloned) as T;\n}\n\nexport function createPostgresMigrationRunner(\n family: SqlControlFamilyInstance,\n config: Partial<RunnerConfig> = {},\n): SqlMigrationRunner<PostgresPlanTargetDetails> {\n return new PostgresMigrationRunner(family, { ...DEFAULT_CONFIG, ...config });\n}\n\nclass PostgresMigrationRunner implements SqlMigrationRunner<PostgresPlanTargetDetails> {\n constructor(\n private readonly family: SqlControlFamilyInstance,\n private readonly config: RunnerConfig,\n ) {}\n\n async execute(\n options: SqlMigrationRunnerExecuteOptions<PostgresPlanTargetDetails>,\n ): Promise<SqlMigrationRunnerResult> {\n const schema = options.schemaName ?? this.config.defaultSchema;\n const driver = options.driver;\n const lockKey = `${LOCK_DOMAIN}:${schema}`;\n\n // Static checks - fail fast before transaction\n const destinationCheck = this.ensurePlanMatchesDestinationContract(\n options.plan.destination,\n options.destinationContract,\n );\n if (!destinationCheck.ok) {\n return destinationCheck;\n }\n\n const policyCheck = this.enforcePolicyCompatibility(options.policy, options.plan.operations);\n if (!policyCheck.ok) {\n return policyCheck;\n }\n\n // Begin transaction for DB operations\n await this.beginTransaction(driver);\n let committed = false;\n try {\n await this.acquireLock(driver, lockKey);\n await this.ensureControlTables(driver);\n const existingMarker = await readMarker(driver);\n\n // Validate plan origin matches existing marker (needs marker from DB)\n const markerCheck = this.ensureMarkerCompatibility(existingMarker, options.plan);\n if (!markerCheck.ok) {\n return markerCheck;\n }\n\n // Apply plan operations or skip if marker already at destination\n const markerAtDestination = this.markerMatchesDestination(existingMarker, options.plan);\n let applyValue: ApplyPlanSuccessValue;\n\n if (markerAtDestination) {\n applyValue = { operationsExecuted: 0, executedOperations: [] };\n } else {\n const applyResult = await this.applyPlan(driver, options);\n if (!applyResult.ok) {\n return applyResult;\n }\n applyValue = applyResult.value;\n }\n\n // Verify resulting schema matches contract\n // Step 1: Introspect live schema (DB I/O, family-owned)\n const schemaIR = await this.family.introspect({\n driver,\n contractIR: options.destinationContract,\n });\n\n // Step 2: Pure verification (no DB I/O)\n const schemaVerifyResult = verifySqlSchema({\n contract: options.destinationContract,\n schema: schemaIR,\n strict: options.strictVerification ?? true,\n context: options.context ?? {},\n typeMetadataRegistry: this.family.typeMetadataRegistry,\n });\n if (!schemaVerifyResult.ok) {\n return runnerFailure('SCHEMA_VERIFY_FAILED', schemaVerifyResult.summary, {\n why: 'The resulting database schema does not satisfy the destination contract.',\n meta: {\n issues: schemaVerifyResult.schema.issues,\n },\n });\n }\n\n // Record marker and ledger entries\n await this.upsertMarker(driver, options, existingMarker);\n await this.recordLedgerEntry(driver, options, existingMarker, applyValue.executedOperations);\n\n await this.commitTransaction(driver);\n committed = true;\n return runnerSuccess({\n operationsPlanned: options.plan.operations.length,\n operationsExecuted: applyValue.operationsExecuted,\n });\n } finally {\n if (!committed) {\n await this.rollbackTransaction(driver);\n }\n }\n }\n\n private async applyPlan(\n driver: SqlMigrationRunnerExecuteOptions<PostgresPlanTargetDetails>['driver'],\n options: SqlMigrationRunnerExecuteOptions<PostgresPlanTargetDetails>,\n ): Promise<Result<ApplyPlanSuccessValue, SqlMigrationRunnerFailure>> {\n let operationsExecuted = 0;\n const executedOperations: Array<SqlMigrationPlanOperation<PostgresPlanTargetDetails>> = [];\n for (const operation of options.plan.operations) {\n options.callbacks?.onOperationStart?.(operation);\n try {\n const postcheckAlreadySatisfied = await this.expectationsAreSatisfied(\n driver,\n operation.postcheck,\n );\n if (postcheckAlreadySatisfied) {\n executedOperations.push(this.createPostcheckPreSatisfiedSkipRecord(operation));\n continue;\n }\n\n const precheckResult = await this.runExpectationSteps(\n driver,\n operation.precheck,\n operation,\n 'precheck',\n );\n if (!precheckResult.ok) {\n return precheckResult;\n }\n\n const executeResult = await this.runExecuteSteps(driver, operation.execute, operation);\n if (!executeResult.ok) {\n return executeResult;\n }\n\n const postcheckResult = await this.runExpectationSteps(\n driver,\n operation.postcheck,\n operation,\n 'postcheck',\n );\n if (!postcheckResult.ok) {\n return postcheckResult;\n }\n\n executedOperations.push(operation);\n operationsExecuted += 1;\n } finally {\n options.callbacks?.onOperationComplete?.(operation);\n }\n }\n return ok({ operationsExecuted, executedOperations });\n }\n\n private async ensureControlTables(\n driver: SqlMigrationRunnerExecuteOptions<PostgresPlanTargetDetails>['driver'],\n ): Promise<void> {\n await this.executeStatement(driver, ensurePrismaContractSchemaStatement);\n await this.executeStatement(driver, ensureMarkerTableStatement);\n await this.executeStatement(driver, ensureLedgerTableStatement);\n }\n\n private async runExpectationSteps(\n driver: SqlMigrationRunnerExecuteOptions<PostgresPlanTargetDetails>['driver'],\n steps: readonly SqlMigrationPlanOperationStep[],\n operation: SqlMigrationPlanOperation<PostgresPlanTargetDetails>,\n phase: 'precheck' | 'postcheck',\n ): Promise<Result<void, SqlMigrationRunnerFailure>> {\n for (const step of steps) {\n const result = await driver.query(step.sql);\n if (!this.stepResultIsTrue(result.rows)) {\n const code = phase === 'precheck' ? 'PRECHECK_FAILED' : 'POSTCHECK_FAILED';\n return runnerFailure(\n code,\n `Operation ${operation.id} failed during ${phase}: ${step.description}`,\n {\n meta: {\n operationId: operation.id,\n phase,\n stepDescription: step.description,\n },\n },\n );\n }\n }\n return okVoid();\n }\n\n private async runExecuteSteps(\n driver: SqlMigrationRunnerExecuteOptions<PostgresPlanTargetDetails>['driver'],\n steps: readonly SqlMigrationPlanOperationStep[],\n operation: SqlMigrationPlanOperation<PostgresPlanTargetDetails>,\n ): Promise<Result<void, SqlMigrationRunnerFailure>> {\n for (const step of steps) {\n try {\n await driver.query(step.sql);\n } catch (error) {\n return runnerFailure(\n 'EXECUTION_FAILED',\n `Operation ${operation.id} failed during execution: ${step.description}`,\n {\n why: error instanceof Error ? error.message : String(error),\n meta: {\n operationId: operation.id,\n stepDescription: step.description,\n sql: step.sql,\n },\n },\n );\n }\n }\n return okVoid();\n }\n\n private stepResultIsTrue(rows: readonly Record<string, unknown>[]): boolean {\n if (!rows || rows.length === 0) {\n return false;\n }\n const firstRow = rows[0];\n const firstValue = firstRow ? Object.values(firstRow)[0] : undefined;\n if (typeof firstValue === 'boolean') {\n return firstValue;\n }\n if (typeof firstValue === 'number') {\n return firstValue !== 0;\n }\n if (typeof firstValue === 'string') {\n const lower = firstValue.toLowerCase();\n // PostgreSQL boolean representations: 't'/'f', 'true'/'false', '1'/'0'\n if (lower === 't' || lower === 'true' || lower === '1') {\n return true;\n }\n if (lower === 'f' || lower === 'false' || lower === '0') {\n return false;\n }\n // For other strings, non-empty is truthy (though this case shouldn't occur for boolean checks)\n return firstValue.length > 0;\n }\n return Boolean(firstValue);\n }\n\n private async expectationsAreSatisfied(\n driver: SqlMigrationRunnerExecuteOptions<PostgresPlanTargetDetails>['driver'],\n steps: readonly SqlMigrationPlanOperationStep[],\n ): Promise<boolean> {\n if (steps.length === 0) {\n return false;\n }\n for (const step of steps) {\n const result = await driver.query(step.sql);\n if (!this.stepResultIsTrue(result.rows)) {\n return false;\n }\n }\n return true;\n }\n\n private createPostcheckPreSatisfiedSkipRecord(\n operation: SqlMigrationPlanOperation<PostgresPlanTargetDetails>,\n ): SqlMigrationPlanOperation<PostgresPlanTargetDetails> {\n // Clone and freeze existing meta if present\n const clonedMeta = operation.meta ? cloneAndFreezeRecord(operation.meta) : undefined;\n\n // Create frozen runner metadata\n const runnerMeta = Object.freeze({\n skipped: true,\n reason: 'postcheck_pre_satisfied',\n });\n\n // Merge and freeze the combined meta\n const mergedMeta = Object.freeze({\n ...(clonedMeta ?? {}),\n runner: runnerMeta,\n });\n\n // Clone and freeze arrays to prevent mutation\n const frozenPostcheck = Object.freeze([...operation.postcheck]);\n\n return Object.freeze({\n id: operation.id,\n label: operation.label,\n ...(operation.summary ? { summary: operation.summary } : {}),\n operationClass: operation.operationClass,\n target: operation.target, // Already frozen from plan creation\n precheck: Object.freeze([]),\n execute: Object.freeze([]),\n postcheck: frozenPostcheck,\n ...(operation.meta || mergedMeta ? { meta: mergedMeta } : {}),\n });\n }\n\n private markerMatchesDestination(\n marker: ContractMarkerRecord | null,\n plan: SqlMigrationRunnerExecuteOptions<PostgresPlanTargetDetails>['plan'],\n ): boolean {\n if (!marker) {\n return false;\n }\n if (marker.coreHash !== plan.destination.coreHash) {\n return false;\n }\n if (plan.destination.profileHash && marker.profileHash !== plan.destination.profileHash) {\n return false;\n }\n return true;\n }\n\n private enforcePolicyCompatibility(\n policy: MigrationOperationPolicy,\n operations: readonly SqlMigrationPlanOperation<PostgresPlanTargetDetails>[],\n ): Result<void, SqlMigrationRunnerFailure> {\n const allowedClasses = new Set(policy.allowedOperationClasses);\n for (const operation of operations) {\n if (!allowedClasses.has(operation.operationClass)) {\n return runnerFailure(\n 'POLICY_VIOLATION',\n `Operation ${operation.id} has class \"${operation.operationClass}\" which is not allowed by policy.`,\n {\n why: `Policy only allows: ${policy.allowedOperationClasses.join(', ')}.`,\n meta: {\n operationId: operation.id,\n operationClass: operation.operationClass,\n allowedClasses: policy.allowedOperationClasses,\n },\n },\n );\n }\n }\n return okVoid();\n }\n\n private ensureMarkerCompatibility(\n marker: ContractMarkerRecord | null,\n plan: SqlMigrationRunnerExecuteOptions<PostgresPlanTargetDetails>['plan'],\n ): Result<void, SqlMigrationRunnerFailure> {\n const origin = plan.origin ?? null;\n if (!origin) {\n if (!marker) {\n return okVoid();\n }\n if (this.markerMatchesDestination(marker, plan)) {\n return okVoid();\n }\n return runnerFailure(\n 'MARKER_ORIGIN_MISMATCH',\n `Existing contract marker (${marker.coreHash}) does not match plan origin (no marker expected).`,\n {\n meta: {\n markerCoreHash: marker.coreHash,\n expectedOrigin: null,\n },\n },\n );\n }\n\n if (!marker) {\n return runnerFailure(\n 'MARKER_ORIGIN_MISMATCH',\n `Missing contract marker: expected origin core hash ${origin.coreHash}.`,\n {\n meta: {\n expectedOriginCoreHash: origin.coreHash,\n },\n },\n );\n }\n if (marker.coreHash !== origin.coreHash) {\n return runnerFailure(\n 'MARKER_ORIGIN_MISMATCH',\n `Existing contract marker (${marker.coreHash}) does not match plan origin (${origin.coreHash}).`,\n {\n meta: {\n markerCoreHash: marker.coreHash,\n expectedOriginCoreHash: origin.coreHash,\n },\n },\n );\n }\n if (origin.profileHash && marker.profileHash !== origin.profileHash) {\n return runnerFailure(\n 'MARKER_ORIGIN_MISMATCH',\n `Existing contract marker profile hash (${marker.profileHash}) does not match plan origin profile hash (${origin.profileHash}).`,\n {\n meta: {\n markerProfileHash: marker.profileHash,\n expectedOriginProfileHash: origin.profileHash,\n },\n },\n );\n }\n return okVoid();\n }\n\n private ensurePlanMatchesDestinationContract(\n destination: SqlMigrationPlanContractInfo,\n contract: SqlMigrationRunnerExecuteOptions<PostgresPlanTargetDetails>['destinationContract'],\n ): Result<void, SqlMigrationRunnerFailure> {\n if (destination.coreHash !== contract.coreHash) {\n return runnerFailure(\n 'DESTINATION_CONTRACT_MISMATCH',\n `Plan destination core hash (${destination.coreHash}) does not match provided contract core hash (${contract.coreHash}).`,\n {\n meta: {\n planCoreHash: destination.coreHash,\n contractCoreHash: contract.coreHash,\n },\n },\n );\n }\n if (\n destination.profileHash &&\n contract.profileHash &&\n destination.profileHash !== contract.profileHash\n ) {\n return runnerFailure(\n 'DESTINATION_CONTRACT_MISMATCH',\n `Plan destination profile hash (${destination.profileHash}) does not match provided contract profile hash (${contract.profileHash}).`,\n {\n meta: {\n planProfileHash: destination.profileHash,\n contractProfileHash: contract.profileHash,\n },\n },\n );\n }\n return okVoid();\n }\n\n private async upsertMarker(\n driver: SqlMigrationRunnerExecuteOptions<PostgresPlanTargetDetails>['driver'],\n options: SqlMigrationRunnerExecuteOptions<PostgresPlanTargetDetails>,\n existingMarker: ContractMarkerRecord | null,\n ): Promise<void> {\n const writeStatements = buildWriteMarkerStatements({\n coreHash: options.plan.destination.coreHash,\n profileHash:\n options.plan.destination.profileHash ??\n options.destinationContract.profileHash ??\n options.plan.destination.coreHash,\n contractJson: options.destinationContract,\n canonicalVersion: null,\n meta: {},\n });\n const statement = existingMarker ? writeStatements.update : writeStatements.insert;\n await this.executeStatement(driver, statement);\n }\n\n private async recordLedgerEntry(\n driver: SqlMigrationRunnerExecuteOptions<PostgresPlanTargetDetails>['driver'],\n options: SqlMigrationRunnerExecuteOptions<PostgresPlanTargetDetails>,\n existingMarker: ContractMarkerRecord | null,\n executedOperations: readonly SqlMigrationPlanOperation<PostgresPlanTargetDetails>[],\n ): Promise<void> {\n const ledgerStatement = buildLedgerInsertStatement({\n originCoreHash: existingMarker?.coreHash ?? null,\n originProfileHash: existingMarker?.profileHash ?? null,\n destinationCoreHash: options.plan.destination.coreHash,\n destinationProfileHash:\n options.plan.destination.profileHash ??\n options.destinationContract.profileHash ??\n options.plan.destination.coreHash,\n contractJsonBefore: existingMarker?.contractJson ?? null,\n contractJsonAfter: options.destinationContract,\n operations: executedOperations,\n });\n await this.executeStatement(driver, ledgerStatement);\n }\n\n private async acquireLock(\n driver: SqlMigrationRunnerExecuteOptions<PostgresPlanTargetDetails>['driver'],\n key: string,\n ): Promise<void> {\n await driver.query('select pg_advisory_xact_lock(hashtext($1))', [key]);\n }\n\n private async beginTransaction(\n driver: SqlMigrationRunnerExecuteOptions<PostgresPlanTargetDetails>['driver'],\n ): Promise<void> {\n await driver.query('BEGIN');\n }\n\n private async commitTransaction(\n driver: SqlMigrationRunnerExecuteOptions<PostgresPlanTargetDetails>['driver'],\n ): Promise<void> {\n await driver.query('COMMIT');\n }\n\n private async rollbackTransaction(\n driver: SqlMigrationRunnerExecuteOptions<PostgresPlanTargetDetails>['driver'],\n ): Promise<void> {\n await driver.query('ROLLBACK');\n }\n\n private async executeStatement(\n driver: SqlMigrationRunnerExecuteOptions<PostgresPlanTargetDetails>['driver'],\n statement: SqlStatement,\n ): Promise<void> {\n if (statement.params.length > 0) {\n await driver.query(statement.sql, statement.params);\n return;\n }\n await driver.query(statement.sql);\n }\n}\n","export interface SqlStatement {\n readonly sql: string;\n readonly params: readonly unknown[];\n}\n\nexport const ensurePrismaContractSchemaStatement: SqlStatement = {\n sql: 'create schema if not exists prisma_contract',\n params: [],\n};\n\nexport const ensureMarkerTableStatement: SqlStatement = {\n sql: `create table if not exists prisma_contract.marker (\n id smallint primary key default 1,\n core_hash text not null,\n profile_hash text not null,\n contract_json jsonb,\n canonical_version int,\n updated_at timestamptz not null default now(),\n app_tag text,\n meta jsonb not null default '{}'\n )`,\n params: [],\n};\n\nexport const ensureLedgerTableStatement: SqlStatement = {\n sql: `create table if not exists prisma_contract.ledger (\n id bigserial primary key,\n created_at timestamptz not null default now(),\n origin_core_hash text,\n origin_profile_hash text,\n destination_core_hash text not null,\n destination_profile_hash text,\n contract_json_before jsonb,\n contract_json_after jsonb,\n operations jsonb not null\n )`,\n params: [],\n};\n\nexport interface WriteMarkerInput {\n readonly coreHash: string;\n readonly profileHash: string;\n readonly contractJson?: unknown;\n readonly canonicalVersion?: number | null;\n readonly appTag?: string | null;\n readonly meta?: Record<string, unknown>;\n}\n\nexport function buildWriteMarkerStatements(input: WriteMarkerInput): {\n readonly insert: SqlStatement;\n readonly update: SqlStatement;\n} {\n const params: readonly unknown[] = [\n 1,\n input.coreHash,\n input.profileHash,\n jsonParam(input.contractJson),\n input.canonicalVersion ?? null,\n input.appTag ?? null,\n jsonParam(input.meta ?? {}),\n ];\n\n return {\n insert: {\n sql: `insert into prisma_contract.marker (\n id,\n core_hash,\n profile_hash,\n contract_json,\n canonical_version,\n updated_at,\n app_tag,\n meta\n ) values (\n $1,\n $2,\n $3,\n $4::jsonb,\n $5,\n now(),\n $6,\n $7::jsonb\n )`,\n params,\n },\n update: {\n sql: `update prisma_contract.marker set\n core_hash = $2,\n profile_hash = $3,\n contract_json = $4::jsonb,\n canonical_version = $5,\n updated_at = now(),\n app_tag = $6,\n meta = $7::jsonb\n where id = $1`,\n params,\n },\n };\n}\n\nexport interface LedgerInsertInput {\n readonly originCoreHash?: string | null;\n readonly originProfileHash?: string | null;\n readonly destinationCoreHash: string;\n readonly destinationProfileHash?: string | null;\n readonly contractJsonBefore?: unknown;\n readonly contractJsonAfter?: unknown;\n readonly operations: unknown;\n}\n\nexport function buildLedgerInsertStatement(input: LedgerInsertInput): SqlStatement {\n return {\n sql: `insert into prisma_contract.ledger (\n origin_core_hash,\n origin_profile_hash,\n destination_core_hash,\n destination_profile_hash,\n contract_json_before,\n contract_json_after,\n operations\n ) values (\n $1,\n $2,\n $3,\n $4,\n $5::jsonb,\n $6::jsonb,\n $7::jsonb\n )`,\n params: [\n input.originCoreHash ?? null,\n input.originProfileHash ?? null,\n input.destinationCoreHash,\n input.destinationProfileHash ?? null,\n jsonParam(input.contractJsonBefore),\n jsonParam(input.contractJsonAfter),\n jsonParam(input.operations),\n ],\n };\n}\n\nfunction jsonParam(value: unknown): string {\n return JSON.stringify(value ?? null);\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/exports/control.ts","../../src/core/migrations/planner.ts","../../src/core/migrations/runner.ts","../../src/core/migrations/statement-builders.ts"],"sourcesContent":["import { readFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport type { ExtensionPackManifest } from '@prisma-next/contract/pack-manifest-types';\nimport type {\n ControlTargetInstance,\n MigrationPlanner,\n MigrationRunner,\n} from '@prisma-next/core-control-plane/types';\nimport type {\n SqlControlFamilyInstance,\n SqlControlTargetDescriptor,\n} from '@prisma-next/family-sql/control';\nimport { type } from 'arktype';\nimport type { PostgresPlanTargetDetails } from '../core/migrations/planner';\nimport { createPostgresMigrationPlanner } from '../core/migrations/planner';\nimport { createPostgresMigrationRunner } from '../core/migrations/runner';\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n\nconst TypesImportSpecSchema = type({\n package: 'string',\n named: 'string',\n alias: 'string',\n});\n\nconst ExtensionPackManifestSchema = type({\n id: 'string',\n version: 'string',\n 'targets?': type({ '[string]': type({ 'minVersion?': 'string' }) }),\n 'capabilities?': 'Record<string, unknown>',\n 'types?': type({\n 'codecTypes?': type({\n import: TypesImportSpecSchema,\n }),\n 'operationTypes?': type({\n import: TypesImportSpecSchema,\n }),\n }),\n 'operations?': 'unknown[]',\n});\n\n/**\n * Loads the target manifest from packs/manifest.json.\n */\nfunction loadTargetManifest(): ExtensionPackManifest {\n const manifestPath = join(__dirname, '../../packs/manifest.json');\n const manifestJson = JSON.parse(readFileSync(manifestPath, 'utf-8'));\n\n const result = ExtensionPackManifestSchema(manifestJson);\n if (result instanceof type.errors) {\n const messages = result.map((p: { message: string }) => p.message).join('; ');\n throw new Error(`Invalid target manifest structure at ${manifestPath}: ${messages}`);\n }\n\n return result as ExtensionPackManifest;\n}\n\n/**\n * Postgres target descriptor for CLI config.\n */\nconst postgresTargetDescriptor: SqlControlTargetDescriptor<'postgres', PostgresPlanTargetDetails> =\n {\n kind: 'target',\n familyId: 'sql',\n targetId: 'postgres',\n id: 'postgres',\n manifest: loadTargetManifest(),\n /**\n * Migrations capability for CLI to access planner/runner via core types.\n * The SQL-specific planner/runner types are compatible with the generic\n * MigrationPlanner/MigrationRunner interfaces at runtime.\n */\n migrations: {\n createPlanner(_family: SqlControlFamilyInstance) {\n return createPostgresMigrationPlanner() as MigrationPlanner<'sql', 'postgres'>;\n },\n createRunner(family) {\n return createPostgresMigrationRunner(family) as MigrationRunner<'sql', 'postgres'>;\n },\n },\n create(): ControlTargetInstance<'sql', 'postgres'> {\n return {\n familyId: 'sql',\n targetId: 'postgres',\n };\n },\n /**\n * Direct method for SQL-specific usage.\n * @deprecated Use migrations.createPlanner() for CLI compatibility.\n */\n createPlanner(_family: SqlControlFamilyInstance) {\n return createPostgresMigrationPlanner();\n },\n /**\n * Direct method for SQL-specific usage.\n * @deprecated Use migrations.createRunner() for CLI compatibility.\n */\n createRunner(family) {\n return createPostgresMigrationRunner(family);\n },\n };\n\nexport default postgresTargetDescriptor;\n","import type { SchemaIssue } from '@prisma-next/core-control-plane/types';\nimport type {\n MigrationOperationPolicy,\n SqlMigrationPlanner,\n SqlMigrationPlannerPlanOptions,\n SqlMigrationPlanOperation,\n SqlPlannerConflict,\n} from '@prisma-next/family-sql/control';\nimport {\n createMigrationPlan,\n plannerFailure,\n plannerSuccess,\n} from '@prisma-next/family-sql/control';\nimport { arraysEqual, verifySqlSchema } from '@prisma-next/family-sql/schema-verify';\nimport type {\n ForeignKey,\n SqlContract,\n SqlStorage,\n StorageColumn,\n StorageTable,\n} from '@prisma-next/sql-contract/types';\nimport type { SqlSchemaIR } from '@prisma-next/sql-schema-ir/types';\n\ntype OperationClass = 'extension' | 'table' | 'unique' | 'index' | 'foreignKey';\n\ntype PlannerFrameworkComponents = SqlMigrationPlannerPlanOptions extends {\n readonly frameworkComponents: infer T;\n}\n ? T\n : ReadonlyArray<unknown>;\n\ntype PlannerOptionsWithComponents = SqlMigrationPlannerPlanOptions & {\n readonly frameworkComponents: PlannerFrameworkComponents;\n};\n\ntype VerifySqlSchemaOptionsWithComponents = Parameters<typeof verifySqlSchema>[0] & {\n readonly frameworkComponents: PlannerFrameworkComponents;\n};\n\ntype PlannerDatabaseDependency = {\n readonly id: string;\n readonly label: string;\n readonly install: readonly SqlMigrationPlanOperation<PostgresPlanTargetDetails>[];\n readonly verifyDatabaseDependencyInstalled: (schema: SqlSchemaIR) => readonly SchemaIssue[];\n};\n\nexport interface PostgresPlanTargetDetails {\n readonly schema: string;\n readonly objectType: OperationClass;\n readonly name: string;\n readonly table?: string;\n}\n\ninterface PlannerConfig {\n readonly defaultSchema: string;\n}\n\nconst DEFAULT_PLANNER_CONFIG: PlannerConfig = {\n defaultSchema: 'public',\n};\n\nexport function createPostgresMigrationPlanner(\n config: Partial<PlannerConfig> = {},\n): SqlMigrationPlanner<PostgresPlanTargetDetails> {\n return new PostgresMigrationPlanner({\n ...DEFAULT_PLANNER_CONFIG,\n ...config,\n });\n}\n\nclass PostgresMigrationPlanner implements SqlMigrationPlanner<PostgresPlanTargetDetails> {\n constructor(private readonly config: PlannerConfig) {}\n\n plan(options: SqlMigrationPlannerPlanOptions) {\n const schemaName = options.schemaName ?? this.config.defaultSchema;\n const policyResult = this.ensureAdditivePolicy(options.policy);\n if (policyResult) {\n return policyResult;\n }\n\n const classification = this.classifySchema(options);\n if (classification.kind === 'conflict') {\n return plannerFailure(classification.conflicts);\n }\n\n const operations: SqlMigrationPlanOperation<PostgresPlanTargetDetails>[] = [];\n\n // Build extension operations from component-owned database dependencies\n operations.push(\n ...this.buildDatabaseDependencyOperations(options),\n ...this.buildTableOperations(options.contract.storage.tables, options.schema, schemaName),\n ...this.buildColumnOperations(options.contract.storage.tables, options.schema, schemaName),\n ...this.buildPrimaryKeyOperations(\n options.contract.storage.tables,\n options.schema,\n schemaName,\n ),\n ...this.buildUniqueOperations(options.contract.storage.tables, options.schema, schemaName),\n ...this.buildIndexOperations(options.contract.storage.tables, options.schema, schemaName),\n ...this.buildForeignKeyOperations(\n options.contract.storage.tables,\n options.schema,\n schemaName,\n ),\n );\n\n const plan = createMigrationPlan<PostgresPlanTargetDetails>({\n targetId: 'postgres',\n origin: null,\n destination: {\n coreHash: options.contract.coreHash,\n ...(options.contract.profileHash ? { profileHash: options.contract.profileHash } : {}),\n },\n operations,\n });\n\n return plannerSuccess(plan);\n }\n\n private ensureAdditivePolicy(policy: MigrationOperationPolicy) {\n if (!policy.allowedOperationClasses.includes('additive')) {\n return plannerFailure([\n {\n kind: 'unsupportedOperation',\n summary: 'Init planner requires additive operations be allowed',\n why: 'The init planner only emits additive operations. Update the policy to include \"additive\".',\n },\n ]);\n }\n return null;\n }\n\n /**\n * Builds migration operations from component-owned database dependencies.\n * These operations install database-side persistence structures declared by components.\n */\n private buildDatabaseDependencyOperations(\n options: PlannerOptionsWithComponents,\n ): readonly SqlMigrationPlanOperation<PostgresPlanTargetDetails>[] {\n const dependencies = this.collectDependencies(options);\n const operations: SqlMigrationPlanOperation<PostgresPlanTargetDetails>[] = [];\n const seenDependencyIds = new Set<string>();\n const seenOperationIds = new Set<string>();\n\n for (const dependency of dependencies) {\n if (seenDependencyIds.has(dependency.id)) {\n continue;\n }\n seenDependencyIds.add(dependency.id);\n\n const issues = dependency.verifyDatabaseDependencyInstalled(options.schema);\n if (issues.length === 0) {\n continue;\n }\n\n for (const installOp of dependency.install) {\n if (seenOperationIds.has(installOp.id)) {\n continue;\n }\n seenOperationIds.add(installOp.id);\n // SQL family components are expected to provide compatible target details. This would be better if\n // the type system could enforce it but it's not likely to occur in practice.\n operations.push(installOp as SqlMigrationPlanOperation<PostgresPlanTargetDetails>);\n }\n }\n\n return operations;\n }\n private collectDependencies(\n options: PlannerOptionsWithComponents,\n ): ReadonlyArray<PlannerDatabaseDependency> {\n const components = options.frameworkComponents;\n if (components.length === 0) {\n return [];\n }\n const deps: PlannerDatabaseDependency[] = [];\n for (const component of components) {\n if (!isSqlDependencyProvider(component)) {\n continue;\n }\n const initDeps = component.databaseDependencies?.init;\n if (initDeps && initDeps.length > 0) {\n deps.push(...initDeps);\n }\n }\n return sortDependencies(deps);\n }\n\n private buildTableOperations(\n tables: SqlContract<SqlStorage>['storage']['tables'],\n schema: SqlSchemaIR,\n schemaName: string,\n ): readonly SqlMigrationPlanOperation<PostgresPlanTargetDetails>[] {\n const operations: SqlMigrationPlanOperation<PostgresPlanTargetDetails>[] = [];\n for (const [tableName, table] of sortedEntries(tables)) {\n if (schema.tables[tableName]) {\n continue;\n }\n const qualified = qualifyTableName(schemaName, tableName);\n operations.push({\n id: `table.${tableName}`,\n label: `Create table ${tableName}`,\n summary: `Creates table ${tableName} with required columns`,\n operationClass: 'additive',\n target: {\n id: 'postgres',\n details: this.buildTargetDetails('table', tableName, schemaName),\n },\n precheck: [\n {\n description: `ensure table \"${tableName}\" does not exist`,\n sql: `SELECT to_regclass(${toRegclassLiteral(schemaName, tableName)}) IS NULL`,\n },\n ],\n execute: [\n {\n description: `create table \"${tableName}\"`,\n sql: buildCreateTableSql(qualified, table),\n },\n ],\n postcheck: [\n {\n description: `verify table \"${tableName}\" exists`,\n sql: `SELECT to_regclass(${toRegclassLiteral(schemaName, tableName)}) IS NOT NULL`,\n },\n ],\n });\n }\n return operations;\n }\n\n private buildColumnOperations(\n tables: SqlContract<SqlStorage>['storage']['tables'],\n schema: SqlSchemaIR,\n schemaName: string,\n ): readonly SqlMigrationPlanOperation<PostgresPlanTargetDetails>[] {\n const operations: SqlMigrationPlanOperation<PostgresPlanTargetDetails>[] = [];\n for (const [tableName, table] of sortedEntries(tables)) {\n const schemaTable = schema.tables[tableName];\n if (!schemaTable) {\n continue;\n }\n for (const [columnName, column] of sortedEntries(table.columns)) {\n if (schemaTable.columns[columnName]) {\n continue;\n }\n operations.push(this.buildAddColumnOperation(schemaName, tableName, columnName, column));\n }\n }\n return operations;\n }\n\n private buildAddColumnOperation(\n schema: string,\n tableName: string,\n columnName: string,\n column: StorageColumn,\n ): SqlMigrationPlanOperation<PostgresPlanTargetDetails> {\n const qualified = qualifyTableName(schema, tableName);\n const notNull = column.nullable === false;\n const precheck = [\n {\n description: `ensure column \"${columnName}\" is missing`,\n sql: columnExistsCheck({ schema, table: tableName, column: columnName, exists: false }),\n },\n ...(notNull\n ? [\n {\n description: `ensure table \"${tableName}\" is empty before adding NOT NULL column`,\n sql: tableIsEmptyCheck(qualified),\n },\n ]\n : []),\n ];\n const execute = [\n {\n description: `add column \"${columnName}\"`,\n sql: buildAddColumnSql(qualified, columnName, column),\n },\n ];\n const postcheck = [\n {\n description: `verify column \"${columnName}\" exists`,\n sql: columnExistsCheck({ schema, table: tableName, column: columnName }),\n },\n ...(notNull\n ? [\n {\n description: `verify column \"${columnName}\" is NOT NULL`,\n sql: columnIsNotNullCheck({ schema, table: tableName, column: columnName }),\n },\n ]\n : []),\n ];\n\n return {\n id: `column.${tableName}.${columnName}`,\n label: `Add column ${columnName} to ${tableName}`,\n summary: `Adds column ${columnName} to table ${tableName}`,\n operationClass: 'additive',\n target: {\n id: 'postgres',\n details: this.buildTargetDetails('table', tableName, schema),\n },\n precheck,\n execute,\n postcheck,\n };\n }\n\n private buildPrimaryKeyOperations(\n tables: SqlContract<SqlStorage>['storage']['tables'],\n schema: SqlSchemaIR,\n schemaName: string,\n ): readonly SqlMigrationPlanOperation<PostgresPlanTargetDetails>[] {\n const operations: SqlMigrationPlanOperation<PostgresPlanTargetDetails>[] = [];\n for (const [tableName, table] of sortedEntries(tables)) {\n if (!table.primaryKey) {\n continue;\n }\n const schemaTable = schema.tables[tableName];\n if (!schemaTable || schemaTable.primaryKey) {\n continue;\n }\n const constraintName = table.primaryKey.name ?? `${tableName}_pkey`;\n operations.push({\n id: `primaryKey.${tableName}.${constraintName}`,\n label: `Add primary key ${constraintName} on ${tableName}`,\n summary: `Adds primary key ${constraintName} on ${tableName}`,\n operationClass: 'additive',\n target: {\n id: 'postgres',\n details: this.buildTargetDetails('table', tableName, schemaName),\n },\n precheck: [\n {\n description: `ensure primary key does not exist on \"${tableName}\"`,\n sql: tableHasPrimaryKeyCheck(schemaName, tableName, false),\n },\n ],\n execute: [\n {\n description: `add primary key \"${constraintName}\"`,\n sql: `ALTER TABLE ${qualifyTableName(schemaName, tableName)}\nADD CONSTRAINT ${quoteIdentifier(constraintName)}\nPRIMARY KEY (${table.primaryKey.columns.map(quoteIdentifier).join(', ')})`,\n },\n ],\n postcheck: [\n {\n description: `verify primary key \"${constraintName}\" exists`,\n sql: tableHasPrimaryKeyCheck(schemaName, tableName, true, constraintName),\n },\n ],\n });\n }\n return operations;\n }\n\n private buildUniqueOperations(\n tables: SqlContract<SqlStorage>['storage']['tables'],\n schema: SqlSchemaIR,\n schemaName: string,\n ): readonly SqlMigrationPlanOperation<PostgresPlanTargetDetails>[] {\n const operations: SqlMigrationPlanOperation<PostgresPlanTargetDetails>[] = [];\n for (const [tableName, table] of sortedEntries(tables)) {\n const schemaTable = schema.tables[tableName];\n for (const unique of table.uniques) {\n if (schemaTable && hasUniqueConstraint(schemaTable, unique.columns)) {\n continue;\n }\n const constraintName = unique.name ?? `${tableName}_${unique.columns.join('_')}_key`;\n operations.push({\n id: `unique.${tableName}.${constraintName}`,\n label: `Add unique constraint ${constraintName} on ${tableName}`,\n summary: `Adds unique constraint ${constraintName} on ${tableName}`,\n operationClass: 'additive',\n target: {\n id: 'postgres',\n details: this.buildTargetDetails('unique', constraintName, schemaName, tableName),\n },\n precheck: [\n {\n description: `ensure unique constraint \"${constraintName}\" is missing`,\n sql: constraintExistsCheck({ constraintName, schema: schemaName, exists: false }),\n },\n ],\n execute: [\n {\n description: `add unique constraint \"${constraintName}\"`,\n sql: `ALTER TABLE ${qualifyTableName(schemaName, tableName)}\nADD CONSTRAINT ${quoteIdentifier(constraintName)}\nUNIQUE (${unique.columns.map(quoteIdentifier).join(', ')})`,\n },\n ],\n postcheck: [\n {\n description: `verify unique constraint \"${constraintName}\" exists`,\n sql: constraintExistsCheck({ constraintName, schema: schemaName }),\n },\n ],\n });\n }\n }\n return operations;\n }\n\n private buildIndexOperations(\n tables: SqlContract<SqlStorage>['storage']['tables'],\n schema: SqlSchemaIR,\n schemaName: string,\n ): readonly SqlMigrationPlanOperation<PostgresPlanTargetDetails>[] {\n const operations: SqlMigrationPlanOperation<PostgresPlanTargetDetails>[] = [];\n for (const [tableName, table] of sortedEntries(tables)) {\n const schemaTable = schema.tables[tableName];\n for (const index of table.indexes) {\n if (schemaTable && hasIndex(schemaTable, index.columns)) {\n continue;\n }\n const indexName = index.name ?? `${tableName}_${index.columns.join('_')}_idx`;\n operations.push({\n id: `index.${tableName}.${indexName}`,\n label: `Create index ${indexName} on ${tableName}`,\n summary: `Creates index ${indexName} on ${tableName}`,\n operationClass: 'additive',\n target: {\n id: 'postgres',\n details: this.buildTargetDetails('index', indexName, schemaName, tableName),\n },\n precheck: [\n {\n description: `ensure index \"${indexName}\" is missing`,\n sql: `SELECT to_regclass(${toRegclassLiteral(schemaName, indexName)}) IS NULL`,\n },\n ],\n execute: [\n {\n description: `create index \"${indexName}\"`,\n sql: `CREATE INDEX ${quoteIdentifier(indexName)} ON ${qualifyTableName(\n schemaName,\n tableName,\n )} (${index.columns.map(quoteIdentifier).join(', ')})`,\n },\n ],\n postcheck: [\n {\n description: `verify index \"${indexName}\" exists`,\n sql: `SELECT to_regclass(${toRegclassLiteral(schemaName, indexName)}) IS NOT NULL`,\n },\n ],\n });\n }\n }\n return operations;\n }\n\n private buildForeignKeyOperations(\n tables: SqlContract<SqlStorage>['storage']['tables'],\n schema: SqlSchemaIR,\n schemaName: string,\n ): readonly SqlMigrationPlanOperation<PostgresPlanTargetDetails>[] {\n const operations: SqlMigrationPlanOperation<PostgresPlanTargetDetails>[] = [];\n for (const [tableName, table] of sortedEntries(tables)) {\n const schemaTable = schema.tables[tableName];\n for (const foreignKey of table.foreignKeys) {\n if (schemaTable && hasForeignKey(schemaTable, foreignKey)) {\n continue;\n }\n const fkName = foreignKey.name ?? `${tableName}_${foreignKey.columns.join('_')}_fkey`;\n operations.push({\n id: `foreignKey.${tableName}.${fkName}`,\n label: `Add foreign key ${fkName} on ${tableName}`,\n summary: `Adds foreign key ${fkName} referencing ${foreignKey.references.table}`,\n operationClass: 'additive',\n target: {\n id: 'postgres',\n details: this.buildTargetDetails('foreignKey', fkName, schemaName, tableName),\n },\n precheck: [\n {\n description: `ensure foreign key \"${fkName}\" is missing`,\n sql: constraintExistsCheck({\n constraintName: fkName,\n schema: schemaName,\n exists: false,\n }),\n },\n ],\n execute: [\n {\n description: `add foreign key \"${fkName}\"`,\n sql: `ALTER TABLE ${qualifyTableName(schemaName, tableName)}\nADD CONSTRAINT ${quoteIdentifier(fkName)}\nFOREIGN KEY (${foreignKey.columns.map(quoteIdentifier).join(', ')})\nREFERENCES ${qualifyTableName(schemaName, foreignKey.references.table)} (${foreignKey.references.columns\n .map(quoteIdentifier)\n .join(', ')})`,\n },\n ],\n postcheck: [\n {\n description: `verify foreign key \"${fkName}\" exists`,\n sql: constraintExistsCheck({ constraintName: fkName, schema: schemaName }),\n },\n ],\n });\n }\n }\n return operations;\n }\n\n private buildTargetDetails(\n objectType: OperationClass,\n name: string,\n schema: string,\n table?: string,\n ): PostgresPlanTargetDetails {\n return {\n schema,\n objectType,\n name,\n ...(table ? { table } : {}),\n };\n }\n\n private classifySchema(options: PlannerOptionsWithComponents):\n | { kind: 'ok' }\n | {\n kind: 'conflict';\n conflicts: SqlPlannerConflict[];\n } {\n const verifyOptions: VerifySqlSchemaOptionsWithComponents = {\n contract: options.contract,\n schema: options.schema,\n strict: false,\n typeMetadataRegistry: new Map(),\n frameworkComponents: options.frameworkComponents,\n };\n const verifyResult = verifySqlSchema(verifyOptions);\n\n const conflicts = this.extractConflicts(verifyResult.schema.issues);\n if (conflicts.length > 0) {\n return { kind: 'conflict', conflicts };\n }\n return { kind: 'ok' };\n }\n\n private extractConflicts(issues: readonly SchemaIssue[]): SqlPlannerConflict[] {\n const conflicts: SqlPlannerConflict[] = [];\n for (const issue of issues) {\n if (isAdditiveIssue(issue)) {\n continue;\n }\n const conflict = this.convertIssueToConflict(issue);\n if (conflict) {\n conflicts.push(conflict);\n }\n }\n return conflicts.sort(conflictComparator);\n }\n\n private convertIssueToConflict(issue: SchemaIssue): SqlPlannerConflict | null {\n switch (issue.kind) {\n case 'type_mismatch':\n return this.buildConflict('typeMismatch', issue);\n case 'nullability_mismatch':\n return this.buildConflict('nullabilityConflict', issue);\n case 'primary_key_mismatch':\n return this.buildConflict('indexIncompatible', issue);\n case 'unique_constraint_mismatch':\n return this.buildConflict('indexIncompatible', issue);\n case 'index_mismatch':\n return this.buildConflict('indexIncompatible', issue);\n case 'foreign_key_mismatch':\n return this.buildConflict('foreignKeyConflict', issue);\n default:\n return null;\n }\n }\n\n private buildConflict(kind: SqlPlannerConflict['kind'], issue: SchemaIssue): SqlPlannerConflict {\n const location = buildConflictLocation(issue);\n const meta =\n issue.expected || issue.actual\n ? Object.freeze({\n ...(issue.expected ? { expected: issue.expected } : {}),\n ...(issue.actual ? { actual: issue.actual } : {}),\n })\n : undefined;\n\n return {\n kind,\n summary: issue.message,\n ...(location ? { location } : {}),\n ...(meta ? { meta } : {}),\n };\n }\n}\n\nfunction isSqlDependencyProvider(component: unknown): component is {\n readonly databaseDependencies?: {\n readonly init?: readonly PlannerDatabaseDependency[];\n };\n} {\n if (typeof component !== 'object' || component === null) {\n return false;\n }\n const record = component as Record<string, unknown>;\n\n // If present, enforce familyId match to avoid mixing families at runtime.\n if (Object.hasOwn(record, 'familyId') && record['familyId'] !== 'sql') {\n return false;\n }\n\n if (!Object.hasOwn(record, 'databaseDependencies')) {\n return false;\n }\n const deps = record['databaseDependencies'];\n return deps === undefined || (typeof deps === 'object' && deps !== null);\n}\n\nfunction sortDependencies(\n dependencies: ReadonlyArray<PlannerDatabaseDependency>,\n): ReadonlyArray<PlannerDatabaseDependency> {\n if (dependencies.length <= 1) {\n return dependencies;\n }\n return [...dependencies].sort((a, b) => a.id.localeCompare(b.id));\n}\n\nfunction buildCreateTableSql(qualifiedTableName: string, table: StorageTable): string {\n const columnDefinitions = Object.entries(table.columns).map(\n ([columnName, column]: [string, StorageColumn]) => {\n const parts = [\n quoteIdentifier(columnName),\n column.nativeType,\n column.nullable ? '' : 'NOT NULL',\n ].filter(Boolean);\n return parts.join(' ');\n },\n );\n\n const constraintDefinitions: string[] = [];\n if (table.primaryKey) {\n constraintDefinitions.push(\n `PRIMARY KEY (${table.primaryKey.columns.map(quoteIdentifier).join(', ')})`,\n );\n }\n\n const allDefinitions = [...columnDefinitions, ...constraintDefinitions];\n return `CREATE TABLE ${qualifiedTableName} (\\n ${allDefinitions.join(',\\n ')}\\n)`;\n}\n\nfunction qualifyTableName(schema: string, table: string): string {\n return `${quoteIdentifier(schema)}.${quoteIdentifier(table)}`;\n}\n\nfunction toRegclassLiteral(schema: string, name: string): string {\n const regclass = `${quoteIdentifier(schema)}.${quoteIdentifier(name)}`;\n return `'${escapeLiteral(regclass)}'`;\n}\n\n/** Escapes and quotes a SQL identifier (table, column, schema name). */\nfunction quoteIdentifier(identifier: string): string {\n // TypeScript enforces string type - no runtime check needed for internal callers\n return `\"${identifier.replace(/\"/g, '\"\"')}\"`;\n}\n\nfunction escapeLiteral(value: string): string {\n return value.replace(/'/g, \"''\");\n}\n\nfunction sortedEntries<V>(record: Readonly<Record<string, V>>): Array<[string, V]> {\n return Object.entries(record).sort(([a], [b]) => a.localeCompare(b)) as Array<[string, V]>;\n}\n\nfunction constraintExistsCheck({\n constraintName,\n schema,\n exists = true,\n}: {\n constraintName: string;\n schema: string;\n exists?: boolean;\n}): string {\n const existsClause = exists ? 'EXISTS' : 'NOT EXISTS';\n return `SELECT ${existsClause} (\n SELECT 1 FROM pg_constraint c\n JOIN pg_namespace n ON c.connamespace = n.oid\n WHERE c.conname = '${escapeLiteral(constraintName)}'\n AND n.nspname = '${escapeLiteral(schema)}'\n)`;\n}\n\nfunction columnExistsCheck({\n schema,\n table,\n column,\n exists = true,\n}: {\n schema: string;\n table: string;\n column: string;\n exists?: boolean;\n}): string {\n const existsClause = exists ? '' : 'NOT ';\n return `SELECT ${existsClause}EXISTS (\n SELECT 1\n FROM information_schema.columns\n WHERE table_schema = '${escapeLiteral(schema)}'\n AND table_name = '${escapeLiteral(table)}'\n AND column_name = '${escapeLiteral(column)}'\n)`;\n}\n\nfunction columnIsNotNullCheck({\n schema,\n table,\n column,\n}: {\n schema: string;\n table: string;\n column: string;\n}): string {\n return `SELECT EXISTS (\n SELECT 1\n FROM information_schema.columns\n WHERE table_schema = '${escapeLiteral(schema)}'\n AND table_name = '${escapeLiteral(table)}'\n AND column_name = '${escapeLiteral(column)}'\n AND is_nullable = 'NO'\n)`;\n}\n\nfunction tableIsEmptyCheck(qualifiedTableName: string): string {\n return `SELECT NOT EXISTS (SELECT 1 FROM ${qualifiedTableName} LIMIT 1)`;\n}\n\nfunction buildAddColumnSql(\n qualifiedTableName: string,\n columnName: string,\n column: StorageColumn,\n): string {\n const parts = [\n `ALTER TABLE ${qualifiedTableName}`,\n `ADD COLUMN ${quoteIdentifier(columnName)} ${column.nativeType}`,\n column.nullable ? '' : 'NOT NULL',\n ].filter(Boolean);\n return parts.join(' ');\n}\n\nfunction tableHasPrimaryKeyCheck(\n schema: string,\n table: string,\n exists: boolean,\n constraintName?: string,\n): string {\n const comparison = exists ? '' : 'NOT ';\n const constraintFilter = constraintName\n ? `AND c2.relname = '${escapeLiteral(constraintName)}'`\n : '';\n return `SELECT ${comparison}EXISTS (\n SELECT 1\n FROM pg_index i\n JOIN pg_class c ON c.oid = i.indrelid\n JOIN pg_namespace n ON n.oid = c.relnamespace\n LEFT JOIN pg_class c2 ON c2.oid = i.indexrelid\n WHERE n.nspname = '${escapeLiteral(schema)}'\n AND c.relname = '${escapeLiteral(table)}'\n AND i.indisprimary\n ${constraintFilter}\n)`;\n}\n\nfunction hasUniqueConstraint(\n table: SqlSchemaIR['tables'][string],\n columns: readonly string[],\n): boolean {\n return table.uniques.some((unique) => arraysEqual(unique.columns, columns));\n}\n\nfunction hasIndex(table: SqlSchemaIR['tables'][string], columns: readonly string[]): boolean {\n return table.indexes.some((index) => !index.unique && arraysEqual(index.columns, columns));\n}\n\nfunction hasForeignKey(table: SqlSchemaIR['tables'][string], fk: ForeignKey): boolean {\n return table.foreignKeys.some(\n (candidate) =>\n arraysEqual(candidate.columns, fk.columns) &&\n candidate.referencedTable === fk.references.table &&\n arraysEqual(candidate.referencedColumns, fk.references.columns),\n );\n}\n\nfunction isAdditiveIssue(issue: SchemaIssue): boolean {\n switch (issue.kind) {\n case 'missing_table':\n case 'missing_column':\n case 'extension_missing':\n return true;\n case 'primary_key_mismatch':\n return issue.actual === undefined;\n case 'unique_constraint_mismatch':\n case 'index_mismatch':\n case 'foreign_key_mismatch':\n return issue.indexOrConstraint === undefined;\n default:\n return false;\n }\n}\n\nfunction buildConflictLocation(issue: SchemaIssue) {\n const location: {\n table?: string;\n column?: string;\n constraint?: string;\n } = {};\n if (issue.table) {\n location.table = issue.table;\n }\n if (issue.column) {\n location.column = issue.column;\n }\n if (issue.indexOrConstraint) {\n location.constraint = issue.indexOrConstraint;\n }\n return Object.keys(location).length > 0 ? location : undefined;\n}\n\nfunction conflictComparator(a: SqlPlannerConflict, b: SqlPlannerConflict): number {\n if (a.kind !== b.kind) {\n return a.kind < b.kind ? -1 : 1;\n }\n const aLocation = a.location ?? {};\n const bLocation = b.location ?? {};\n const tableCompare = compareStrings(aLocation.table, bLocation.table);\n if (tableCompare !== 0) {\n return tableCompare;\n }\n const columnCompare = compareStrings(aLocation.column, bLocation.column);\n if (columnCompare !== 0) {\n return columnCompare;\n }\n const constraintCompare = compareStrings(aLocation.constraint, bLocation.constraint);\n if (constraintCompare !== 0) {\n return constraintCompare;\n }\n return compareStrings(a.summary, b.summary);\n}\n\nfunction compareStrings(a?: string, b?: string): number {\n if (a === b) {\n return 0;\n }\n if (a === undefined) {\n return -1;\n }\n if (b === undefined) {\n return 1;\n }\n return a < b ? -1 : 1;\n}\n","import type { ContractMarkerRecord } from '@prisma-next/contract/types';\nimport type {\n MigrationOperationPolicy,\n SqlControlFamilyInstance,\n SqlMigrationPlanContractInfo,\n SqlMigrationPlanOperation,\n SqlMigrationPlanOperationStep,\n SqlMigrationRunner,\n SqlMigrationRunnerExecuteOptions,\n SqlMigrationRunnerFailure,\n SqlMigrationRunnerResult,\n} from '@prisma-next/family-sql/control';\nimport { runnerFailure, runnerSuccess } from '@prisma-next/family-sql/control';\nimport { verifySqlSchema } from '@prisma-next/family-sql/schema-verify';\nimport { readMarker } from '@prisma-next/family-sql/verify';\nimport type { Result } from '@prisma-next/utils/result';\nimport { ok, okVoid } from '@prisma-next/utils/result';\nimport type { PostgresPlanTargetDetails } from './planner';\nimport {\n buildLedgerInsertStatement,\n buildWriteMarkerStatements,\n ensureLedgerTableStatement,\n ensureMarkerTableStatement,\n ensurePrismaContractSchemaStatement,\n type SqlStatement,\n} from './statement-builders';\n\ninterface RunnerConfig {\n readonly defaultSchema: string;\n}\n\ninterface ApplyPlanSuccessValue {\n readonly operationsExecuted: number;\n readonly executedOperations: readonly SqlMigrationPlanOperation<PostgresPlanTargetDetails>[];\n}\n\nconst DEFAULT_CONFIG: RunnerConfig = {\n defaultSchema: 'public',\n};\n\nconst LOCK_DOMAIN = 'prisma_next.contract.marker';\n\n/**\n * Deep clones and freezes a record object to prevent mutation.\n * Recursively clones nested objects and arrays to ensure complete isolation.\n */\nfunction cloneAndFreezeRecord<T extends Record<string, unknown>>(value: T): T {\n const cloned: Record<string, unknown> = {};\n for (const [key, val] of Object.entries(value)) {\n if (val === null || val === undefined) {\n cloned[key] = val;\n } else if (Array.isArray(val)) {\n // Clone array (shallow clone of array elements)\n cloned[key] = Object.freeze([...val]);\n } else if (typeof val === 'object') {\n // Recursively clone nested objects\n cloned[key] = cloneAndFreezeRecord(val as Record<string, unknown>);\n } else {\n // Primitives are copied as-is\n cloned[key] = val;\n }\n }\n return Object.freeze(cloned) as T;\n}\n\nexport function createPostgresMigrationRunner(\n family: SqlControlFamilyInstance,\n config: Partial<RunnerConfig> = {},\n): SqlMigrationRunner<PostgresPlanTargetDetails> {\n return new PostgresMigrationRunner(family, { ...DEFAULT_CONFIG, ...config });\n}\n\nclass PostgresMigrationRunner implements SqlMigrationRunner<PostgresPlanTargetDetails> {\n constructor(\n private readonly family: SqlControlFamilyInstance,\n private readonly config: RunnerConfig,\n ) {}\n\n async execute(\n options: SqlMigrationRunnerExecuteOptions<PostgresPlanTargetDetails>,\n ): Promise<SqlMigrationRunnerResult> {\n const schema = options.schemaName ?? this.config.defaultSchema;\n const driver = options.driver;\n const lockKey = `${LOCK_DOMAIN}:${schema}`;\n\n // Static checks - fail fast before transaction\n const destinationCheck = this.ensurePlanMatchesDestinationContract(\n options.plan.destination,\n options.destinationContract,\n );\n if (!destinationCheck.ok) {\n return destinationCheck;\n }\n\n const policyCheck = this.enforcePolicyCompatibility(options.policy, options.plan.operations);\n if (!policyCheck.ok) {\n return policyCheck;\n }\n\n // Begin transaction for DB operations\n await this.beginTransaction(driver);\n let committed = false;\n try {\n await this.acquireLock(driver, lockKey);\n await this.ensureControlTables(driver);\n const existingMarker = await readMarker(driver);\n\n // Validate plan origin matches existing marker (needs marker from DB)\n const markerCheck = this.ensureMarkerCompatibility(existingMarker, options.plan);\n if (!markerCheck.ok) {\n return markerCheck;\n }\n\n // Apply plan operations or skip if marker already at destination\n const markerAtDestination = this.markerMatchesDestination(existingMarker, options.plan);\n let applyValue: ApplyPlanSuccessValue;\n\n if (markerAtDestination) {\n applyValue = { operationsExecuted: 0, executedOperations: [] };\n } else {\n const applyResult = await this.applyPlan(driver, options);\n if (!applyResult.ok) {\n return applyResult;\n }\n applyValue = applyResult.value;\n }\n\n // Verify resulting schema matches contract\n // Step 1: Introspect live schema (DB I/O, family-owned)\n const schemaIR = await this.family.introspect({\n driver,\n contractIR: options.destinationContract,\n });\n\n // Step 2: Pure verification (no DB I/O)\n const schemaVerifyResult = verifySqlSchema({\n contract: options.destinationContract,\n schema: schemaIR,\n strict: options.strictVerification ?? true,\n context: options.context ?? {},\n typeMetadataRegistry: this.family.typeMetadataRegistry,\n frameworkComponents: options.frameworkComponents,\n });\n if (!schemaVerifyResult.ok) {\n return runnerFailure('SCHEMA_VERIFY_FAILED', schemaVerifyResult.summary, {\n why: 'The resulting database schema does not satisfy the destination contract.',\n meta: {\n issues: schemaVerifyResult.schema.issues,\n },\n });\n }\n\n // Record marker and ledger entries\n await this.upsertMarker(driver, options, existingMarker);\n await this.recordLedgerEntry(driver, options, existingMarker, applyValue.executedOperations);\n\n await this.commitTransaction(driver);\n committed = true;\n return runnerSuccess({\n operationsPlanned: options.plan.operations.length,\n operationsExecuted: applyValue.operationsExecuted,\n });\n } finally {\n if (!committed) {\n await this.rollbackTransaction(driver);\n }\n }\n }\n\n private async applyPlan(\n driver: SqlMigrationRunnerExecuteOptions<PostgresPlanTargetDetails>['driver'],\n options: SqlMigrationRunnerExecuteOptions<PostgresPlanTargetDetails>,\n ): Promise<Result<ApplyPlanSuccessValue, SqlMigrationRunnerFailure>> {\n let operationsExecuted = 0;\n const executedOperations: Array<SqlMigrationPlanOperation<PostgresPlanTargetDetails>> = [];\n for (const operation of options.plan.operations) {\n options.callbacks?.onOperationStart?.(operation);\n try {\n const postcheckAlreadySatisfied = await this.expectationsAreSatisfied(\n driver,\n operation.postcheck,\n );\n if (postcheckAlreadySatisfied) {\n executedOperations.push(this.createPostcheckPreSatisfiedSkipRecord(operation));\n continue;\n }\n\n const precheckResult = await this.runExpectationSteps(\n driver,\n operation.precheck,\n operation,\n 'precheck',\n );\n if (!precheckResult.ok) {\n return precheckResult;\n }\n\n const executeResult = await this.runExecuteSteps(driver, operation.execute, operation);\n if (!executeResult.ok) {\n return executeResult;\n }\n\n const postcheckResult = await this.runExpectationSteps(\n driver,\n operation.postcheck,\n operation,\n 'postcheck',\n );\n if (!postcheckResult.ok) {\n return postcheckResult;\n }\n\n executedOperations.push(operation);\n operationsExecuted += 1;\n } finally {\n options.callbacks?.onOperationComplete?.(operation);\n }\n }\n return ok({ operationsExecuted, executedOperations });\n }\n\n private async ensureControlTables(\n driver: SqlMigrationRunnerExecuteOptions<PostgresPlanTargetDetails>['driver'],\n ): Promise<void> {\n await this.executeStatement(driver, ensurePrismaContractSchemaStatement);\n await this.executeStatement(driver, ensureMarkerTableStatement);\n await this.executeStatement(driver, ensureLedgerTableStatement);\n }\n\n private async runExpectationSteps(\n driver: SqlMigrationRunnerExecuteOptions<PostgresPlanTargetDetails>['driver'],\n steps: readonly SqlMigrationPlanOperationStep[],\n operation: SqlMigrationPlanOperation<PostgresPlanTargetDetails>,\n phase: 'precheck' | 'postcheck',\n ): Promise<Result<void, SqlMigrationRunnerFailure>> {\n for (const step of steps) {\n const result = await driver.query(step.sql);\n if (!this.stepResultIsTrue(result.rows)) {\n const code = phase === 'precheck' ? 'PRECHECK_FAILED' : 'POSTCHECK_FAILED';\n return runnerFailure(\n code,\n `Operation ${operation.id} failed during ${phase}: ${step.description}`,\n {\n meta: {\n operationId: operation.id,\n phase,\n stepDescription: step.description,\n },\n },\n );\n }\n }\n return okVoid();\n }\n\n private async runExecuteSteps(\n driver: SqlMigrationRunnerExecuteOptions<PostgresPlanTargetDetails>['driver'],\n steps: readonly SqlMigrationPlanOperationStep[],\n operation: SqlMigrationPlanOperation<PostgresPlanTargetDetails>,\n ): Promise<Result<void, SqlMigrationRunnerFailure>> {\n for (const step of steps) {\n try {\n await driver.query(step.sql);\n } catch (error) {\n return runnerFailure(\n 'EXECUTION_FAILED',\n `Operation ${operation.id} failed during execution: ${step.description}`,\n {\n why: error instanceof Error ? error.message : String(error),\n meta: {\n operationId: operation.id,\n stepDescription: step.description,\n sql: step.sql,\n },\n },\n );\n }\n }\n return okVoid();\n }\n\n private stepResultIsTrue(rows: readonly Record<string, unknown>[]): boolean {\n if (!rows || rows.length === 0) {\n return false;\n }\n const firstRow = rows[0];\n const firstValue = firstRow ? Object.values(firstRow)[0] : undefined;\n if (typeof firstValue === 'boolean') {\n return firstValue;\n }\n if (typeof firstValue === 'number') {\n return firstValue !== 0;\n }\n if (typeof firstValue === 'string') {\n const lower = firstValue.toLowerCase();\n // PostgreSQL boolean representations: 't'/'f', 'true'/'false', '1'/'0'\n if (lower === 't' || lower === 'true' || lower === '1') {\n return true;\n }\n if (lower === 'f' || lower === 'false' || lower === '0') {\n return false;\n }\n // For other strings, non-empty is truthy (though this case shouldn't occur for boolean checks)\n return firstValue.length > 0;\n }\n return Boolean(firstValue);\n }\n\n private async expectationsAreSatisfied(\n driver: SqlMigrationRunnerExecuteOptions<PostgresPlanTargetDetails>['driver'],\n steps: readonly SqlMigrationPlanOperationStep[],\n ): Promise<boolean> {\n if (steps.length === 0) {\n return false;\n }\n for (const step of steps) {\n const result = await driver.query(step.sql);\n if (!this.stepResultIsTrue(result.rows)) {\n return false;\n }\n }\n return true;\n }\n\n private createPostcheckPreSatisfiedSkipRecord(\n operation: SqlMigrationPlanOperation<PostgresPlanTargetDetails>,\n ): SqlMigrationPlanOperation<PostgresPlanTargetDetails> {\n // Clone and freeze existing meta if present\n const clonedMeta = operation.meta ? cloneAndFreezeRecord(operation.meta) : undefined;\n\n // Create frozen runner metadata\n const runnerMeta = Object.freeze({\n skipped: true,\n reason: 'postcheck_pre_satisfied',\n });\n\n // Merge and freeze the combined meta\n const mergedMeta = Object.freeze({\n ...(clonedMeta ?? {}),\n runner: runnerMeta,\n });\n\n // Clone and freeze arrays to prevent mutation\n const frozenPostcheck = Object.freeze([...operation.postcheck]);\n\n return Object.freeze({\n id: operation.id,\n label: operation.label,\n ...(operation.summary ? { summary: operation.summary } : {}),\n operationClass: operation.operationClass,\n target: operation.target, // Already frozen from plan creation\n precheck: Object.freeze([]),\n execute: Object.freeze([]),\n postcheck: frozenPostcheck,\n ...(operation.meta || mergedMeta ? { meta: mergedMeta } : {}),\n });\n }\n\n private markerMatchesDestination(\n marker: ContractMarkerRecord | null,\n plan: SqlMigrationRunnerExecuteOptions<PostgresPlanTargetDetails>['plan'],\n ): boolean {\n if (!marker) {\n return false;\n }\n if (marker.coreHash !== plan.destination.coreHash) {\n return false;\n }\n if (plan.destination.profileHash && marker.profileHash !== plan.destination.profileHash) {\n return false;\n }\n return true;\n }\n\n private enforcePolicyCompatibility(\n policy: MigrationOperationPolicy,\n operations: readonly SqlMigrationPlanOperation<PostgresPlanTargetDetails>[],\n ): Result<void, SqlMigrationRunnerFailure> {\n const allowedClasses = new Set(policy.allowedOperationClasses);\n for (const operation of operations) {\n if (!allowedClasses.has(operation.operationClass)) {\n return runnerFailure(\n 'POLICY_VIOLATION',\n `Operation ${operation.id} has class \"${operation.operationClass}\" which is not allowed by policy.`,\n {\n why: `Policy only allows: ${policy.allowedOperationClasses.join(', ')}.`,\n meta: {\n operationId: operation.id,\n operationClass: operation.operationClass,\n allowedClasses: policy.allowedOperationClasses,\n },\n },\n );\n }\n }\n return okVoid();\n }\n\n private ensureMarkerCompatibility(\n marker: ContractMarkerRecord | null,\n plan: SqlMigrationRunnerExecuteOptions<PostgresPlanTargetDetails>['plan'],\n ): Result<void, SqlMigrationRunnerFailure> {\n const origin = plan.origin ?? null;\n if (!origin) {\n if (!marker) {\n return okVoid();\n }\n if (this.markerMatchesDestination(marker, plan)) {\n return okVoid();\n }\n return runnerFailure(\n 'MARKER_ORIGIN_MISMATCH',\n `Existing contract marker (${marker.coreHash}) does not match plan origin (no marker expected).`,\n {\n meta: {\n markerCoreHash: marker.coreHash,\n expectedOrigin: null,\n },\n },\n );\n }\n\n if (!marker) {\n return runnerFailure(\n 'MARKER_ORIGIN_MISMATCH',\n `Missing contract marker: expected origin core hash ${origin.coreHash}.`,\n {\n meta: {\n expectedOriginCoreHash: origin.coreHash,\n },\n },\n );\n }\n if (marker.coreHash !== origin.coreHash) {\n return runnerFailure(\n 'MARKER_ORIGIN_MISMATCH',\n `Existing contract marker (${marker.coreHash}) does not match plan origin (${origin.coreHash}).`,\n {\n meta: {\n markerCoreHash: marker.coreHash,\n expectedOriginCoreHash: origin.coreHash,\n },\n },\n );\n }\n if (origin.profileHash && marker.profileHash !== origin.profileHash) {\n return runnerFailure(\n 'MARKER_ORIGIN_MISMATCH',\n `Existing contract marker profile hash (${marker.profileHash}) does not match plan origin profile hash (${origin.profileHash}).`,\n {\n meta: {\n markerProfileHash: marker.profileHash,\n expectedOriginProfileHash: origin.profileHash,\n },\n },\n );\n }\n return okVoid();\n }\n\n private ensurePlanMatchesDestinationContract(\n destination: SqlMigrationPlanContractInfo,\n contract: SqlMigrationRunnerExecuteOptions<PostgresPlanTargetDetails>['destinationContract'],\n ): Result<void, SqlMigrationRunnerFailure> {\n if (destination.coreHash !== contract.coreHash) {\n return runnerFailure(\n 'DESTINATION_CONTRACT_MISMATCH',\n `Plan destination core hash (${destination.coreHash}) does not match provided contract core hash (${contract.coreHash}).`,\n {\n meta: {\n planCoreHash: destination.coreHash,\n contractCoreHash: contract.coreHash,\n },\n },\n );\n }\n if (\n destination.profileHash &&\n contract.profileHash &&\n destination.profileHash !== contract.profileHash\n ) {\n return runnerFailure(\n 'DESTINATION_CONTRACT_MISMATCH',\n `Plan destination profile hash (${destination.profileHash}) does not match provided contract profile hash (${contract.profileHash}).`,\n {\n meta: {\n planProfileHash: destination.profileHash,\n contractProfileHash: contract.profileHash,\n },\n },\n );\n }\n return okVoid();\n }\n\n private async upsertMarker(\n driver: SqlMigrationRunnerExecuteOptions<PostgresPlanTargetDetails>['driver'],\n options: SqlMigrationRunnerExecuteOptions<PostgresPlanTargetDetails>,\n existingMarker: ContractMarkerRecord | null,\n ): Promise<void> {\n const writeStatements = buildWriteMarkerStatements({\n coreHash: options.plan.destination.coreHash,\n profileHash:\n options.plan.destination.profileHash ??\n options.destinationContract.profileHash ??\n options.plan.destination.coreHash,\n contractJson: options.destinationContract,\n canonicalVersion: null,\n meta: {},\n });\n const statement = existingMarker ? writeStatements.update : writeStatements.insert;\n await this.executeStatement(driver, statement);\n }\n\n private async recordLedgerEntry(\n driver: SqlMigrationRunnerExecuteOptions<PostgresPlanTargetDetails>['driver'],\n options: SqlMigrationRunnerExecuteOptions<PostgresPlanTargetDetails>,\n existingMarker: ContractMarkerRecord | null,\n executedOperations: readonly SqlMigrationPlanOperation<PostgresPlanTargetDetails>[],\n ): Promise<void> {\n const ledgerStatement = buildLedgerInsertStatement({\n originCoreHash: existingMarker?.coreHash ?? null,\n originProfileHash: existingMarker?.profileHash ?? null,\n destinationCoreHash: options.plan.destination.coreHash,\n destinationProfileHash:\n options.plan.destination.profileHash ??\n options.destinationContract.profileHash ??\n options.plan.destination.coreHash,\n contractJsonBefore: existingMarker?.contractJson ?? null,\n contractJsonAfter: options.destinationContract,\n operations: executedOperations,\n });\n await this.executeStatement(driver, ledgerStatement);\n }\n\n private async acquireLock(\n driver: SqlMigrationRunnerExecuteOptions<PostgresPlanTargetDetails>['driver'],\n key: string,\n ): Promise<void> {\n await driver.query('select pg_advisory_xact_lock(hashtext($1))', [key]);\n }\n\n private async beginTransaction(\n driver: SqlMigrationRunnerExecuteOptions<PostgresPlanTargetDetails>['driver'],\n ): Promise<void> {\n await driver.query('BEGIN');\n }\n\n private async commitTransaction(\n driver: SqlMigrationRunnerExecuteOptions<PostgresPlanTargetDetails>['driver'],\n ): Promise<void> {\n await driver.query('COMMIT');\n }\n\n private async rollbackTransaction(\n driver: SqlMigrationRunnerExecuteOptions<PostgresPlanTargetDetails>['driver'],\n ): Promise<void> {\n await driver.query('ROLLBACK');\n }\n\n private async executeStatement(\n driver: SqlMigrationRunnerExecuteOptions<PostgresPlanTargetDetails>['driver'],\n statement: SqlStatement,\n ): Promise<void> {\n if (statement.params.length > 0) {\n await driver.query(statement.sql, statement.params);\n return;\n }\n await driver.query(statement.sql);\n }\n}\n","export interface SqlStatement {\n readonly sql: string;\n readonly params: readonly unknown[];\n}\n\nexport const ensurePrismaContractSchemaStatement: SqlStatement = {\n sql: 'create schema if not exists prisma_contract',\n params: [],\n};\n\nexport const ensureMarkerTableStatement: SqlStatement = {\n sql: `create table if not exists prisma_contract.marker (\n id smallint primary key default 1,\n core_hash text not null,\n profile_hash text not null,\n contract_json jsonb,\n canonical_version int,\n updated_at timestamptz not null default now(),\n app_tag text,\n meta jsonb not null default '{}'\n )`,\n params: [],\n};\n\nexport const ensureLedgerTableStatement: SqlStatement = {\n sql: `create table if not exists prisma_contract.ledger (\n id bigserial primary key,\n created_at timestamptz not null default now(),\n origin_core_hash text,\n origin_profile_hash text,\n destination_core_hash text not null,\n destination_profile_hash text,\n contract_json_before jsonb,\n contract_json_after jsonb,\n operations jsonb not null\n )`,\n params: [],\n};\n\nexport interface WriteMarkerInput {\n readonly coreHash: string;\n readonly profileHash: string;\n readonly contractJson?: unknown;\n readonly canonicalVersion?: number | null;\n readonly appTag?: string | null;\n readonly meta?: Record<string, unknown>;\n}\n\nexport function buildWriteMarkerStatements(input: WriteMarkerInput): {\n readonly insert: SqlStatement;\n readonly update: SqlStatement;\n} {\n const params: readonly unknown[] = [\n 1,\n input.coreHash,\n input.profileHash,\n jsonParam(input.contractJson),\n input.canonicalVersion ?? null,\n input.appTag ?? null,\n jsonParam(input.meta ?? {}),\n ];\n\n return {\n insert: {\n sql: `insert into prisma_contract.marker (\n id,\n core_hash,\n profile_hash,\n contract_json,\n canonical_version,\n updated_at,\n app_tag,\n meta\n ) values (\n $1,\n $2,\n $3,\n $4::jsonb,\n $5,\n now(),\n $6,\n $7::jsonb\n )`,\n params,\n },\n update: {\n sql: `update prisma_contract.marker set\n core_hash = $2,\n profile_hash = $3,\n contract_json = $4::jsonb,\n canonical_version = $5,\n updated_at = now(),\n app_tag = $6,\n meta = $7::jsonb\n where id = $1`,\n params,\n },\n };\n}\n\nexport interface LedgerInsertInput {\n readonly originCoreHash?: string | null;\n readonly originProfileHash?: string | null;\n readonly destinationCoreHash: string;\n readonly destinationProfileHash?: string | null;\n readonly contractJsonBefore?: unknown;\n readonly contractJsonAfter?: unknown;\n readonly operations: unknown;\n}\n\nexport function buildLedgerInsertStatement(input: LedgerInsertInput): SqlStatement {\n return {\n sql: `insert into prisma_contract.ledger (\n origin_core_hash,\n origin_profile_hash,\n destination_core_hash,\n destination_profile_hash,\n contract_json_before,\n contract_json_after,\n operations\n ) values (\n $1,\n $2,\n $3,\n $4,\n $5::jsonb,\n $6::jsonb,\n $7::jsonb\n )`,\n params: [\n input.originCoreHash ?? null,\n input.originProfileHash ?? null,\n input.destinationCoreHash,\n input.destinationProfileHash ?? null,\n jsonParam(input.contractJsonBefore),\n jsonParam(input.contractJsonAfter),\n jsonParam(input.operations),\n ],\n };\n}\n\nfunction jsonParam(value: unknown): string {\n return JSON.stringify(value ?? null);\n}\n"],"mappings":"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","names":["verifySqlSchema","verifySqlSchema"]}
|
package/package.json
CHANGED
|
@@ -1,27 +1,27 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prisma-next/target-postgres",
|
|
3
|
-
"version": "0.1.0-dev.
|
|
3
|
+
"version": "0.1.0-dev.21",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"description": "Postgres target pack for Prisma Next",
|
|
7
7
|
"dependencies": {
|
|
8
8
|
"arktype": "^2.0.0",
|
|
9
|
-
"@prisma-next/family-sql": "0.1.0-dev.
|
|
10
|
-
"@prisma-next/
|
|
11
|
-
"@prisma-next/
|
|
12
|
-
"@prisma-next/sql-contract": "0.1.0-dev.
|
|
13
|
-
"@prisma-next/sql-schema-ir": "0.1.0-dev.
|
|
14
|
-
"@prisma-next/core-control-plane": "0.1.0-dev.
|
|
15
|
-
"@prisma-next/core-execution-plane": "0.1.0-dev.
|
|
16
|
-
"@prisma-next/utils": "0.1.0-dev.
|
|
9
|
+
"@prisma-next/family-sql": "0.1.0-dev.21",
|
|
10
|
+
"@prisma-next/cli": "0.1.0-dev.21",
|
|
11
|
+
"@prisma-next/contract": "0.1.0-dev.21",
|
|
12
|
+
"@prisma-next/sql-contract": "0.1.0-dev.21",
|
|
13
|
+
"@prisma-next/sql-schema-ir": "0.1.0-dev.21",
|
|
14
|
+
"@prisma-next/core-control-plane": "0.1.0-dev.21",
|
|
15
|
+
"@prisma-next/core-execution-plane": "0.1.0-dev.21",
|
|
16
|
+
"@prisma-next/utils": "0.1.0-dev.21"
|
|
17
17
|
},
|
|
18
18
|
"devDependencies": {
|
|
19
19
|
"vite-tsconfig-paths": "^5.1.4",
|
|
20
20
|
"tsup": "^8.3.0",
|
|
21
21
|
"typescript": "^5.9.3",
|
|
22
22
|
"vitest": "^4.0.16",
|
|
23
|
-
"@prisma-next/adapter-postgres": "0.1.0-dev.
|
|
24
|
-
"@prisma-next/driver-postgres": "0.1.0-dev.
|
|
23
|
+
"@prisma-next/adapter-postgres": "0.1.0-dev.21",
|
|
24
|
+
"@prisma-next/driver-postgres": "0.1.0-dev.21",
|
|
25
25
|
"@prisma-next/test-utils": "0.0.1"
|
|
26
26
|
},
|
|
27
27
|
"files": [
|