@prisma-next/target-postgres 0.1.0-pr.48.2 → 0.1.0-pr.49.2
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 +79 -11
- package/dist/exports/control.d.ts +10 -2
- package/dist/exports/control.js +898 -0
- package/dist/exports/control.js.map +1 -1
- package/package.json +12 -5
package/README.md
CHANGED
|
@@ -4,36 +4,74 @@ Postgres target pack for Prisma Next.
|
|
|
4
4
|
|
|
5
5
|
## Package Classification
|
|
6
6
|
|
|
7
|
-
- **Domain**:
|
|
7
|
+
- **Domain**: targets
|
|
8
8
|
- **Layer**: targets
|
|
9
9
|
- **Plane**: multi-plane (migration, runtime)
|
|
10
10
|
|
|
11
11
|
## Purpose
|
|
12
12
|
|
|
13
|
-
Provides the Postgres target descriptor (`
|
|
13
|
+
Provides the Postgres target descriptor (`SqlControlTargetDescriptor`) for CLI config. The target descriptor includes the target manifest with capabilities and type information, as well as factories for creating migration planners and runners.
|
|
14
14
|
|
|
15
15
|
## Responsibilities
|
|
16
16
|
|
|
17
|
-
- **Target Descriptor Export**: Exports the Postgres `
|
|
17
|
+
- **Target Descriptor Export**: Exports the Postgres `SqlControlTargetDescriptor` for use in CLI configuration files
|
|
18
18
|
- **Manifest Loading**: Loads the Postgres target manifest from `packs/manifest.json` with capabilities and type information
|
|
19
|
-
- **Multi-Plane Support**: Provides both migration-plane (
|
|
19
|
+
- **Multi-Plane Support**: Provides both migration-plane (control) and runtime-plane entry points for the Postgres target
|
|
20
|
+
- **Planner Factory**: Implements `createPlanner()` to create Postgres-specific migration planners
|
|
21
|
+
- **Runner Factory**: Implements `createRunner()` to create Postgres-specific migration runners
|
|
20
22
|
|
|
21
23
|
This package spans multiple planes:
|
|
22
|
-
- **Migration plane** (`src/exports/
|
|
24
|
+
- **Migration plane** (`src/exports/control.ts`): Control plane entry point that exports `SqlControlTargetDescriptor` for config files
|
|
23
25
|
- **Runtime plane** (`src/exports/runtime.ts`): Runtime entry point for target-specific runtime code (future)
|
|
24
26
|
|
|
25
27
|
## Usage
|
|
26
28
|
|
|
27
|
-
###
|
|
29
|
+
### Control Plane (CLI)
|
|
28
30
|
|
|
29
31
|
```typescript
|
|
30
32
|
import postgres from '@prisma-next/target-postgres/control';
|
|
33
|
+
import sqlFamilyDescriptor from '@prisma-next/family-sql/control';
|
|
34
|
+
import postgresAdapter from '@prisma-next/adapter-postgres/control';
|
|
35
|
+
import postgresDriver from '@prisma-next/driver-postgres/control';
|
|
31
36
|
|
|
32
|
-
// postgres is a
|
|
37
|
+
// postgres is a SqlControlTargetDescriptor with:
|
|
33
38
|
// - kind: 'target'
|
|
39
|
+
// - familyId: 'sql'
|
|
40
|
+
// - targetId: 'postgres'
|
|
34
41
|
// - id: 'postgres'
|
|
35
|
-
// - family: 'sql'
|
|
36
42
|
// - manifest: ExtensionPackManifest
|
|
43
|
+
// - createPlanner(): creates a Postgres migration planner
|
|
44
|
+
// - createRunner(): creates a Postgres migration runner
|
|
45
|
+
|
|
46
|
+
// Create family instance with target, adapter, and driver
|
|
47
|
+
const family = sqlFamilyDescriptor.create({
|
|
48
|
+
target: postgres,
|
|
49
|
+
adapter: postgresAdapter,
|
|
50
|
+
driver: postgresDriver,
|
|
51
|
+
extensions: [],
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
// Create planner and runner from target descriptor
|
|
55
|
+
const planner = postgres.createPlanner(family);
|
|
56
|
+
const runner = postgres.createRunner(family);
|
|
57
|
+
|
|
58
|
+
// Plan and execute migrations
|
|
59
|
+
const planResult = planner.plan({ contract, schema, policy });
|
|
60
|
+
if (planResult.kind === 'success') {
|
|
61
|
+
const executeResult = await runner.execute({
|
|
62
|
+
plan: planResult.plan,
|
|
63
|
+
driver,
|
|
64
|
+
destinationContract: contract,
|
|
65
|
+
policy,
|
|
66
|
+
});
|
|
67
|
+
if (!executeResult.ok) {
|
|
68
|
+
// Handle structured failure (e.g., EXECUTION_FAILED, PRECHECK_FAILED)
|
|
69
|
+
console.error(executeResult.failure.code, executeResult.failure.summary);
|
|
70
|
+
}
|
|
71
|
+
} else {
|
|
72
|
+
// Handle planner failure (e.g., unsupportedExtension, unsupportedOperation)
|
|
73
|
+
console.error(planResult.conflicts);
|
|
74
|
+
}
|
|
37
75
|
```
|
|
38
76
|
|
|
39
77
|
### Runtime Plane
|
|
@@ -45,11 +83,29 @@ import { ... } from '@prisma-next/target-postgres/runtime';
|
|
|
45
83
|
|
|
46
84
|
## Architecture
|
|
47
85
|
|
|
48
|
-
This package provides both
|
|
86
|
+
This package provides both control and runtime entry points for the Postgres target. The control entry point loads the target manifest from `packs/manifest.json` and exports it as a `SqlControlTargetDescriptor`. The runtime entry point will provide target-specific runtime functionality in the future.
|
|
87
|
+
|
|
88
|
+
## Error Handling
|
|
89
|
+
|
|
90
|
+
Both the planner and runner return structured results instead of throwing:
|
|
91
|
+
|
|
92
|
+
**Planner** returns `PlannerResult` with either:
|
|
93
|
+
- `kind: 'success'` with a `MigrationPlan`
|
|
94
|
+
- `kind: 'failure'` with a list of `PlannerConflict` objects (e.g., `unsupportedExtension`, `unsupportedOperation`)
|
|
95
|
+
|
|
96
|
+
**Runner** returns `MigrationRunnerResult` (`Result<MigrationRunnerSuccessValue, MigrationRunnerFailure>`) with either:
|
|
97
|
+
- `ok: true` with operation counts
|
|
98
|
+
- `ok: false` with a `MigrationRunnerFailure` containing error code, summary, and metadata
|
|
99
|
+
|
|
100
|
+
Runner error codes include: `EXECUTION_FAILED`, `PRECHECK_FAILED`, `POSTCHECK_FAILED`, `SCHEMA_VERIFY_FAILED`, `POLICY_VIOLATION`, `MARKER_ORIGIN_MISMATCH`, `DESTINATION_CONTRACT_MISMATCH`.
|
|
101
|
+
|
|
102
|
+
See `@prisma-next/family-sql/control` README for full error code documentation.
|
|
49
103
|
|
|
50
104
|
## Dependencies
|
|
51
105
|
|
|
52
|
-
- **`@prisma-next/
|
|
106
|
+
- **`@prisma-next/family-sql`**: SQL family types (`SqlControlTargetDescriptor`, `SqlControlFamilyInstance`)
|
|
107
|
+
- **`@prisma-next/core-control-plane`**: Control plane types (`ControlTargetInstance`)
|
|
108
|
+
- **`@prisma-next/contract`**: Manifest types (`ExtensionPackManifest`)
|
|
53
109
|
- **`arktype`**: Runtime validation
|
|
54
110
|
|
|
55
111
|
**Dependents:**
|
|
@@ -57,6 +113,18 @@ This package provides both CLI and runtime entry points for the Postgres target.
|
|
|
57
113
|
|
|
58
114
|
## Exports
|
|
59
115
|
|
|
60
|
-
- `./
|
|
116
|
+
- `./control`: Control plane entry point for `SqlControlTargetDescriptor`
|
|
61
117
|
- `./runtime`: Runtime entry point for target-specific runtime code (future)
|
|
62
118
|
|
|
119
|
+
## Tests
|
|
120
|
+
|
|
121
|
+
This package ships a mix of fast planner unit tests and slower runner integration tests that require a dev Postgres instance (via `@prisma/dev`).
|
|
122
|
+
|
|
123
|
+
- **Default (`pnpm --filter @prisma-next/target-postgres test`)**: runs all tests including integration tests
|
|
124
|
+
- **Test files**:
|
|
125
|
+
- `test/migrations/planner.case1.test.ts`: Planner unit tests
|
|
126
|
+
- `test/migrations/runner.*.integration.test.ts`: Runner integration tests (basic, errors, idempotency, policy)
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
pnpm --filter @prisma-next/target-postgres test
|
|
130
|
+
```
|
|
@@ -1,8 +1,16 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { SqlControlTargetDescriptor } from '@prisma-next/family-sql/control';
|
|
2
|
+
|
|
3
|
+
type OperationClass = 'extension' | 'table' | 'unique' | 'index' | 'foreignKey';
|
|
4
|
+
interface PostgresPlanTargetDetails {
|
|
5
|
+
readonly schema: string;
|
|
6
|
+
readonly objectType: OperationClass;
|
|
7
|
+
readonly name: string;
|
|
8
|
+
readonly table?: string;
|
|
9
|
+
}
|
|
2
10
|
|
|
3
11
|
/**
|
|
4
12
|
* Postgres target descriptor for CLI config.
|
|
5
13
|
*/
|
|
6
|
-
declare const postgresTargetDescriptor:
|
|
14
|
+
declare const postgresTargetDescriptor: SqlControlTargetDescriptor<'postgres', PostgresPlanTargetDetails>;
|
|
7
15
|
|
|
8
16
|
export { postgresTargetDescriptor as default };
|
package/dist/exports/control.js
CHANGED
|
@@ -3,6 +3,898 @@ import { readFileSync } from "fs";
|
|
|
3
3
|
import { dirname, join } from "path";
|
|
4
4
|
import { fileURLToPath } from "url";
|
|
5
5
|
import { type } from "arktype";
|
|
6
|
+
|
|
7
|
+
// src/core/migrations/planner.ts
|
|
8
|
+
import {
|
|
9
|
+
createMigrationPlan,
|
|
10
|
+
plannerFailure,
|
|
11
|
+
plannerSuccess
|
|
12
|
+
} from "@prisma-next/family-sql/control";
|
|
13
|
+
var DEFAULT_PLANNER_CONFIG = {
|
|
14
|
+
defaultSchema: "public"
|
|
15
|
+
};
|
|
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
|
+
function createPostgresMigrationPlanner(config = {}) {
|
|
21
|
+
return new PostgresMigrationPlanner({
|
|
22
|
+
...DEFAULT_PLANNER_CONFIG,
|
|
23
|
+
...config
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
var PostgresMigrationPlanner = class {
|
|
27
|
+
constructor(config) {
|
|
28
|
+
this.config = config;
|
|
29
|
+
}
|
|
30
|
+
plan(options) {
|
|
31
|
+
const schemaName = options.schemaName ?? this.config.defaultSchema;
|
|
32
|
+
const policyResult = this.ensureAdditivePolicy(options.policy);
|
|
33
|
+
if (policyResult) {
|
|
34
|
+
return policyResult;
|
|
35
|
+
}
|
|
36
|
+
const existingTables = Object.keys(options.schema.tables);
|
|
37
|
+
if (existingTables.length > 0) {
|
|
38
|
+
const tableList = existingTables.sort().join(", ");
|
|
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;
|
|
50
|
+
}
|
|
51
|
+
const operations = [];
|
|
52
|
+
operations.push(
|
|
53
|
+
...this.buildExtensionOperations(options.contract, schemaName),
|
|
54
|
+
...this.buildTableOperations(options.contract.storage.tables, schemaName),
|
|
55
|
+
...this.buildUniqueOperations(options.contract.storage.tables, schemaName),
|
|
56
|
+
...this.buildIndexOperations(options.contract.storage.tables, schemaName),
|
|
57
|
+
...this.buildForeignKeyOperations(options.contract.storage.tables, schemaName)
|
|
58
|
+
);
|
|
59
|
+
const plan = createMigrationPlan({
|
|
60
|
+
targetId: "postgres",
|
|
61
|
+
origin: null,
|
|
62
|
+
destination: {
|
|
63
|
+
coreHash: options.contract.coreHash,
|
|
64
|
+
...options.contract.profileHash ? { profileHash: options.contract.profileHash } : {}
|
|
65
|
+
},
|
|
66
|
+
operations
|
|
67
|
+
});
|
|
68
|
+
return plannerSuccess(plan);
|
|
69
|
+
}
|
|
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
|
+
ensureAdditivePolicy(policy) {
|
|
94
|
+
if (!policy.allowedOperationClasses.includes("additive")) {
|
|
95
|
+
return plannerFailure([
|
|
96
|
+
{
|
|
97
|
+
kind: "unsupportedOperation",
|
|
98
|
+
summary: "Init planner requires additive operations be allowed",
|
|
99
|
+
why: 'The init planner only emits additive operations. Update the policy to include "additive".'
|
|
100
|
+
}
|
|
101
|
+
]);
|
|
102
|
+
}
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
buildExtensionOperations(contract, schema) {
|
|
106
|
+
const extensions = contract.extensions ?? {};
|
|
107
|
+
const extensionNames = Object.keys(extensions);
|
|
108
|
+
const operations = [];
|
|
109
|
+
for (const extensionName of extensionNames) {
|
|
110
|
+
if (ADAPTER_LEVEL_EXTENSIONS.has(extensionName)) {
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
const sql = PG_EXTENSION_SQL[extensionName];
|
|
114
|
+
if (!sql) {
|
|
115
|
+
throw new Error(`Extension SQL not found for ${extensionName}`);
|
|
116
|
+
}
|
|
117
|
+
const details = this.buildTargetDetails("extension", extensionName, schema);
|
|
118
|
+
operations.push({
|
|
119
|
+
id: `extension.${extensionName}`,
|
|
120
|
+
label: `Enable extension "${extensionName}"`,
|
|
121
|
+
summary: `Ensures the ${extensionName} extension is available`,
|
|
122
|
+
operationClass: "additive",
|
|
123
|
+
target: { id: "postgres", details },
|
|
124
|
+
precheck: [
|
|
125
|
+
{
|
|
126
|
+
description: `verify extension "${extensionName}" is not already enabled`,
|
|
127
|
+
sql: `SELECT NOT EXISTS (SELECT 1 FROM pg_extension WHERE extname = '${escapeLiteral(
|
|
128
|
+
this.extensionDatabaseName(extensionName)
|
|
129
|
+
)}')`
|
|
130
|
+
}
|
|
131
|
+
],
|
|
132
|
+
execute: [
|
|
133
|
+
{
|
|
134
|
+
description: `create extension "${extensionName}"`,
|
|
135
|
+
sql
|
|
136
|
+
}
|
|
137
|
+
],
|
|
138
|
+
postcheck: [
|
|
139
|
+
{
|
|
140
|
+
description: `confirm extension "${extensionName}" is enabled`,
|
|
141
|
+
sql: `SELECT EXISTS (SELECT 1 FROM pg_extension WHERE extname = '${escapeLiteral(
|
|
142
|
+
this.extensionDatabaseName(extensionName)
|
|
143
|
+
)}')`
|
|
144
|
+
}
|
|
145
|
+
]
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
return operations;
|
|
149
|
+
}
|
|
150
|
+
extensionDatabaseName(extensionName) {
|
|
151
|
+
if (extensionName === "pgvector") {
|
|
152
|
+
return "vector";
|
|
153
|
+
}
|
|
154
|
+
return extensionName;
|
|
155
|
+
}
|
|
156
|
+
buildTableOperations(tables, schema) {
|
|
157
|
+
const operations = [];
|
|
158
|
+
for (const [tableName, table] of sortedEntries(tables)) {
|
|
159
|
+
const qualified = qualifyTableName(schema, tableName);
|
|
160
|
+
operations.push({
|
|
161
|
+
id: `table.${tableName}`,
|
|
162
|
+
label: `Create table ${tableName}`,
|
|
163
|
+
summary: `Creates table ${tableName} with required columns`,
|
|
164
|
+
operationClass: "additive",
|
|
165
|
+
target: {
|
|
166
|
+
id: "postgres",
|
|
167
|
+
details: this.buildTargetDetails("table", tableName, schema)
|
|
168
|
+
},
|
|
169
|
+
precheck: [
|
|
170
|
+
{
|
|
171
|
+
description: `ensure table "${tableName}" does not exist`,
|
|
172
|
+
sql: `SELECT to_regclass(${toRegclassLiteral(schema, tableName)}) IS NULL`
|
|
173
|
+
}
|
|
174
|
+
],
|
|
175
|
+
execute: [
|
|
176
|
+
{
|
|
177
|
+
description: `create table "${tableName}"`,
|
|
178
|
+
sql: buildCreateTableSql(qualified, table)
|
|
179
|
+
}
|
|
180
|
+
],
|
|
181
|
+
postcheck: [
|
|
182
|
+
{
|
|
183
|
+
description: `verify table "${tableName}" exists`,
|
|
184
|
+
sql: `SELECT to_regclass(${toRegclassLiteral(schema, tableName)}) IS NOT NULL`
|
|
185
|
+
}
|
|
186
|
+
]
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
return operations;
|
|
190
|
+
}
|
|
191
|
+
buildUniqueOperations(tables, schema) {
|
|
192
|
+
const operations = [];
|
|
193
|
+
for (const [tableName, table] of sortedEntries(tables)) {
|
|
194
|
+
for (const unique of table.uniques) {
|
|
195
|
+
const constraintName = unique.name ?? `${tableName}_${unique.columns.join("_")}_key`;
|
|
196
|
+
operations.push({
|
|
197
|
+
id: `unique.${tableName}.${constraintName}`,
|
|
198
|
+
label: `Add unique constraint ${constraintName} on ${tableName}`,
|
|
199
|
+
summary: `Adds unique constraint ${constraintName} on ${tableName}`,
|
|
200
|
+
operationClass: "additive",
|
|
201
|
+
target: {
|
|
202
|
+
id: "postgres",
|
|
203
|
+
details: this.buildTargetDetails("unique", constraintName, schema, tableName)
|
|
204
|
+
},
|
|
205
|
+
precheck: [
|
|
206
|
+
{
|
|
207
|
+
description: `ensure unique constraint "${constraintName}" is missing`,
|
|
208
|
+
sql: constraintExistsCheck({ constraintName, schema, exists: false })
|
|
209
|
+
}
|
|
210
|
+
],
|
|
211
|
+
execute: [
|
|
212
|
+
{
|
|
213
|
+
description: `add unique constraint "${constraintName}"`,
|
|
214
|
+
sql: `ALTER TABLE ${qualifyTableName(schema, tableName)}
|
|
215
|
+
ADD CONSTRAINT ${quoteIdentifier(constraintName)}
|
|
216
|
+
UNIQUE (${unique.columns.map(quoteIdentifier).join(", ")})`
|
|
217
|
+
}
|
|
218
|
+
],
|
|
219
|
+
postcheck: [
|
|
220
|
+
{
|
|
221
|
+
description: `verify unique constraint "${constraintName}" exists`,
|
|
222
|
+
sql: constraintExistsCheck({ constraintName, schema })
|
|
223
|
+
}
|
|
224
|
+
]
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
return operations;
|
|
229
|
+
}
|
|
230
|
+
buildIndexOperations(tables, schema) {
|
|
231
|
+
const operations = [];
|
|
232
|
+
for (const [tableName, table] of sortedEntries(tables)) {
|
|
233
|
+
for (const index of table.indexes) {
|
|
234
|
+
const indexName = index.name ?? `${tableName}_${index.columns.join("_")}_idx`;
|
|
235
|
+
operations.push({
|
|
236
|
+
id: `index.${tableName}.${indexName}`,
|
|
237
|
+
label: `Create index ${indexName} on ${tableName}`,
|
|
238
|
+
summary: `Creates index ${indexName} on ${tableName}`,
|
|
239
|
+
operationClass: "additive",
|
|
240
|
+
target: {
|
|
241
|
+
id: "postgres",
|
|
242
|
+
details: this.buildTargetDetails("index", indexName, schema, tableName)
|
|
243
|
+
},
|
|
244
|
+
precheck: [
|
|
245
|
+
{
|
|
246
|
+
description: `ensure index "${indexName}" is missing`,
|
|
247
|
+
sql: `SELECT to_regclass(${toRegclassLiteral(schema, indexName)}) IS NULL`
|
|
248
|
+
}
|
|
249
|
+
],
|
|
250
|
+
execute: [
|
|
251
|
+
{
|
|
252
|
+
description: `create index "${indexName}"`,
|
|
253
|
+
sql: `CREATE INDEX ${quoteIdentifier(indexName)} ON ${qualifyTableName(
|
|
254
|
+
schema,
|
|
255
|
+
tableName
|
|
256
|
+
)} (${index.columns.map(quoteIdentifier).join(", ")})`
|
|
257
|
+
}
|
|
258
|
+
],
|
|
259
|
+
postcheck: [
|
|
260
|
+
{
|
|
261
|
+
description: `verify index "${indexName}" exists`,
|
|
262
|
+
sql: `SELECT to_regclass(${toRegclassLiteral(schema, indexName)}) IS NOT NULL`
|
|
263
|
+
}
|
|
264
|
+
]
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
return operations;
|
|
269
|
+
}
|
|
270
|
+
buildForeignKeyOperations(tables, schema) {
|
|
271
|
+
const operations = [];
|
|
272
|
+
for (const [tableName, table] of sortedEntries(tables)) {
|
|
273
|
+
for (const foreignKey of table.foreignKeys) {
|
|
274
|
+
const fkName = foreignKey.name ?? `${tableName}_${foreignKey.columns.join("_")}_fkey`;
|
|
275
|
+
operations.push({
|
|
276
|
+
id: `foreignKey.${tableName}.${fkName}`,
|
|
277
|
+
label: `Add foreign key ${fkName} on ${tableName}`,
|
|
278
|
+
summary: `Adds foreign key ${fkName} referencing ${foreignKey.references.table}`,
|
|
279
|
+
operationClass: "additive",
|
|
280
|
+
target: {
|
|
281
|
+
id: "postgres",
|
|
282
|
+
details: this.buildTargetDetails("foreignKey", fkName, schema, tableName)
|
|
283
|
+
},
|
|
284
|
+
precheck: [
|
|
285
|
+
{
|
|
286
|
+
description: `ensure foreign key "${fkName}" is missing`,
|
|
287
|
+
sql: constraintExistsCheck({ constraintName: fkName, schema, exists: false })
|
|
288
|
+
}
|
|
289
|
+
],
|
|
290
|
+
execute: [
|
|
291
|
+
{
|
|
292
|
+
description: `add foreign key "${fkName}"`,
|
|
293
|
+
sql: `ALTER TABLE ${qualifyTableName(schema, tableName)}
|
|
294
|
+
ADD CONSTRAINT ${quoteIdentifier(fkName)}
|
|
295
|
+
FOREIGN KEY (${foreignKey.columns.map(quoteIdentifier).join(", ")})
|
|
296
|
+
REFERENCES ${qualifyTableName(schema, foreignKey.references.table)} (${foreignKey.references.columns.map(quoteIdentifier).join(", ")})`
|
|
297
|
+
}
|
|
298
|
+
],
|
|
299
|
+
postcheck: [
|
|
300
|
+
{
|
|
301
|
+
description: `verify foreign key "${fkName}" exists`,
|
|
302
|
+
sql: constraintExistsCheck({ constraintName: fkName, schema })
|
|
303
|
+
}
|
|
304
|
+
]
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
return operations;
|
|
309
|
+
}
|
|
310
|
+
buildTargetDetails(objectType, name, schema, table) {
|
|
311
|
+
return {
|
|
312
|
+
schema,
|
|
313
|
+
objectType,
|
|
314
|
+
name,
|
|
315
|
+
...table ? { table } : {}
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
};
|
|
319
|
+
function buildCreateTableSql(qualifiedTableName, table) {
|
|
320
|
+
const columnDefinitions = Object.entries(table.columns).map(
|
|
321
|
+
([columnName, column]) => {
|
|
322
|
+
const parts = [
|
|
323
|
+
quoteIdentifier(columnName),
|
|
324
|
+
column.nativeType,
|
|
325
|
+
column.nullable ? "" : "NOT NULL"
|
|
326
|
+
].filter(Boolean);
|
|
327
|
+
return parts.join(" ");
|
|
328
|
+
}
|
|
329
|
+
);
|
|
330
|
+
const constraintDefinitions = [];
|
|
331
|
+
if (table.primaryKey) {
|
|
332
|
+
constraintDefinitions.push(
|
|
333
|
+
`PRIMARY KEY (${table.primaryKey.columns.map(quoteIdentifier).join(", ")})`
|
|
334
|
+
);
|
|
335
|
+
}
|
|
336
|
+
const allDefinitions = [...columnDefinitions, ...constraintDefinitions];
|
|
337
|
+
return `CREATE TABLE ${qualifiedTableName} (
|
|
338
|
+
${allDefinitions.join(",\n ")}
|
|
339
|
+
)`;
|
|
340
|
+
}
|
|
341
|
+
function qualifyTableName(schema, table) {
|
|
342
|
+
return `${quoteIdentifier(schema)}.${quoteIdentifier(table)}`;
|
|
343
|
+
}
|
|
344
|
+
function toRegclassLiteral(schema, name) {
|
|
345
|
+
const regclass = `${quoteIdentifier(schema)}.${quoteIdentifier(name)}`;
|
|
346
|
+
return `'${escapeLiteral(regclass)}'`;
|
|
347
|
+
}
|
|
348
|
+
function quoteIdentifier(identifier) {
|
|
349
|
+
return `"${identifier.replace(/"/g, '""')}"`;
|
|
350
|
+
}
|
|
351
|
+
function escapeLiteral(value) {
|
|
352
|
+
return value.replace(/'/g, "''");
|
|
353
|
+
}
|
|
354
|
+
function sortedEntries(record) {
|
|
355
|
+
return Object.entries(record).sort(([a], [b]) => a.localeCompare(b));
|
|
356
|
+
}
|
|
357
|
+
function constraintExistsCheck({
|
|
358
|
+
constraintName,
|
|
359
|
+
schema,
|
|
360
|
+
exists = true
|
|
361
|
+
}) {
|
|
362
|
+
const existsClause = exists ? "EXISTS" : "NOT EXISTS";
|
|
363
|
+
return `SELECT ${existsClause} (
|
|
364
|
+
SELECT 1 FROM pg_constraint c
|
|
365
|
+
JOIN pg_namespace n ON c.connamespace = n.oid
|
|
366
|
+
WHERE c.conname = '${escapeLiteral(constraintName)}'
|
|
367
|
+
AND n.nspname = '${escapeLiteral(schema)}'
|
|
368
|
+
)`;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
// src/core/migrations/runner.ts
|
|
372
|
+
import { runnerFailure, runnerSuccess } from "@prisma-next/family-sql/control";
|
|
373
|
+
import { verifySqlSchema } from "@prisma-next/family-sql/schema-verify";
|
|
374
|
+
import { readMarker } from "@prisma-next/family-sql/verify";
|
|
375
|
+
import { ok, okVoid } from "@prisma-next/utils/result";
|
|
376
|
+
|
|
377
|
+
// src/core/migrations/statement-builders.ts
|
|
378
|
+
var ensurePrismaContractSchemaStatement = {
|
|
379
|
+
sql: "create schema if not exists prisma_contract",
|
|
380
|
+
params: []
|
|
381
|
+
};
|
|
382
|
+
var ensureMarkerTableStatement = {
|
|
383
|
+
sql: `create table if not exists prisma_contract.marker (
|
|
384
|
+
id smallint primary key default 1,
|
|
385
|
+
core_hash text not null,
|
|
386
|
+
profile_hash text not null,
|
|
387
|
+
contract_json jsonb,
|
|
388
|
+
canonical_version int,
|
|
389
|
+
updated_at timestamptz not null default now(),
|
|
390
|
+
app_tag text,
|
|
391
|
+
meta jsonb not null default '{}'
|
|
392
|
+
)`,
|
|
393
|
+
params: []
|
|
394
|
+
};
|
|
395
|
+
var ensureLedgerTableStatement = {
|
|
396
|
+
sql: `create table if not exists prisma_contract.ledger (
|
|
397
|
+
id bigserial primary key,
|
|
398
|
+
created_at timestamptz not null default now(),
|
|
399
|
+
origin_core_hash text,
|
|
400
|
+
origin_profile_hash text,
|
|
401
|
+
destination_core_hash text not null,
|
|
402
|
+
destination_profile_hash text,
|
|
403
|
+
contract_json_before jsonb,
|
|
404
|
+
contract_json_after jsonb,
|
|
405
|
+
operations jsonb not null
|
|
406
|
+
)`,
|
|
407
|
+
params: []
|
|
408
|
+
};
|
|
409
|
+
function buildWriteMarkerStatements(input) {
|
|
410
|
+
const params = [
|
|
411
|
+
1,
|
|
412
|
+
input.coreHash,
|
|
413
|
+
input.profileHash,
|
|
414
|
+
jsonParam(input.contractJson),
|
|
415
|
+
input.canonicalVersion ?? null,
|
|
416
|
+
input.appTag ?? null,
|
|
417
|
+
jsonParam(input.meta ?? {})
|
|
418
|
+
];
|
|
419
|
+
return {
|
|
420
|
+
insert: {
|
|
421
|
+
sql: `insert into prisma_contract.marker (
|
|
422
|
+
id,
|
|
423
|
+
core_hash,
|
|
424
|
+
profile_hash,
|
|
425
|
+
contract_json,
|
|
426
|
+
canonical_version,
|
|
427
|
+
updated_at,
|
|
428
|
+
app_tag,
|
|
429
|
+
meta
|
|
430
|
+
) values (
|
|
431
|
+
$1,
|
|
432
|
+
$2,
|
|
433
|
+
$3,
|
|
434
|
+
$4::jsonb,
|
|
435
|
+
$5,
|
|
436
|
+
now(),
|
|
437
|
+
$6,
|
|
438
|
+
$7::jsonb
|
|
439
|
+
)`,
|
|
440
|
+
params
|
|
441
|
+
},
|
|
442
|
+
update: {
|
|
443
|
+
sql: `update prisma_contract.marker set
|
|
444
|
+
core_hash = $2,
|
|
445
|
+
profile_hash = $3,
|
|
446
|
+
contract_json = $4::jsonb,
|
|
447
|
+
canonical_version = $5,
|
|
448
|
+
updated_at = now(),
|
|
449
|
+
app_tag = $6,
|
|
450
|
+
meta = $7::jsonb
|
|
451
|
+
where id = $1`,
|
|
452
|
+
params
|
|
453
|
+
}
|
|
454
|
+
};
|
|
455
|
+
}
|
|
456
|
+
function buildLedgerInsertStatement(input) {
|
|
457
|
+
return {
|
|
458
|
+
sql: `insert into prisma_contract.ledger (
|
|
459
|
+
origin_core_hash,
|
|
460
|
+
origin_profile_hash,
|
|
461
|
+
destination_core_hash,
|
|
462
|
+
destination_profile_hash,
|
|
463
|
+
contract_json_before,
|
|
464
|
+
contract_json_after,
|
|
465
|
+
operations
|
|
466
|
+
) values (
|
|
467
|
+
$1,
|
|
468
|
+
$2,
|
|
469
|
+
$3,
|
|
470
|
+
$4,
|
|
471
|
+
$5::jsonb,
|
|
472
|
+
$6::jsonb,
|
|
473
|
+
$7::jsonb
|
|
474
|
+
)`,
|
|
475
|
+
params: [
|
|
476
|
+
input.originCoreHash ?? null,
|
|
477
|
+
input.originProfileHash ?? null,
|
|
478
|
+
input.destinationCoreHash,
|
|
479
|
+
input.destinationProfileHash ?? null,
|
|
480
|
+
jsonParam(input.contractJsonBefore),
|
|
481
|
+
jsonParam(input.contractJsonAfter),
|
|
482
|
+
jsonParam(input.operations)
|
|
483
|
+
]
|
|
484
|
+
};
|
|
485
|
+
}
|
|
486
|
+
function jsonParam(value) {
|
|
487
|
+
return JSON.stringify(value ?? null);
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
// src/core/migrations/runner.ts
|
|
491
|
+
var DEFAULT_CONFIG = {
|
|
492
|
+
defaultSchema: "public"
|
|
493
|
+
};
|
|
494
|
+
var LOCK_DOMAIN = "prisma_next.contract.marker";
|
|
495
|
+
function cloneAndFreezeRecord(value) {
|
|
496
|
+
const cloned = {};
|
|
497
|
+
for (const [key, val] of Object.entries(value)) {
|
|
498
|
+
if (val === null || val === void 0) {
|
|
499
|
+
cloned[key] = val;
|
|
500
|
+
} else if (Array.isArray(val)) {
|
|
501
|
+
cloned[key] = Object.freeze([...val]);
|
|
502
|
+
} else if (typeof val === "object") {
|
|
503
|
+
cloned[key] = cloneAndFreezeRecord(val);
|
|
504
|
+
} else {
|
|
505
|
+
cloned[key] = val;
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
return Object.freeze(cloned);
|
|
509
|
+
}
|
|
510
|
+
function createPostgresMigrationRunner(family, config = {}) {
|
|
511
|
+
return new PostgresMigrationRunner(family, { ...DEFAULT_CONFIG, ...config });
|
|
512
|
+
}
|
|
513
|
+
var PostgresMigrationRunner = class {
|
|
514
|
+
constructor(family, config) {
|
|
515
|
+
this.family = family;
|
|
516
|
+
this.config = config;
|
|
517
|
+
}
|
|
518
|
+
async execute(options) {
|
|
519
|
+
const schema = options.schemaName ?? this.config.defaultSchema;
|
|
520
|
+
const driver = options.driver;
|
|
521
|
+
const lockKey = `${LOCK_DOMAIN}:${schema}`;
|
|
522
|
+
const destinationCheck = this.ensurePlanMatchesDestinationContract(
|
|
523
|
+
options.plan.destination,
|
|
524
|
+
options.destinationContract
|
|
525
|
+
);
|
|
526
|
+
if (!destinationCheck.ok) {
|
|
527
|
+
return destinationCheck;
|
|
528
|
+
}
|
|
529
|
+
const policyCheck = this.enforcePolicyCompatibility(options.policy, options.plan.operations);
|
|
530
|
+
if (!policyCheck.ok) {
|
|
531
|
+
return policyCheck;
|
|
532
|
+
}
|
|
533
|
+
await this.beginTransaction(driver);
|
|
534
|
+
let committed = false;
|
|
535
|
+
try {
|
|
536
|
+
await this.acquireLock(driver, lockKey);
|
|
537
|
+
await this.ensureControlTables(driver);
|
|
538
|
+
const existingMarker = await readMarker(driver);
|
|
539
|
+
const markerCheck = this.ensureMarkerCompatibility(existingMarker, options.plan);
|
|
540
|
+
if (!markerCheck.ok) {
|
|
541
|
+
return markerCheck;
|
|
542
|
+
}
|
|
543
|
+
const markerAtDestination = this.markerMatchesDestination(existingMarker, options.plan);
|
|
544
|
+
let applyValue;
|
|
545
|
+
if (markerAtDestination) {
|
|
546
|
+
applyValue = { operationsExecuted: 0, executedOperations: [] };
|
|
547
|
+
} else {
|
|
548
|
+
const applyResult = await this.applyPlan(driver, options);
|
|
549
|
+
if (!applyResult.ok) {
|
|
550
|
+
return applyResult;
|
|
551
|
+
}
|
|
552
|
+
applyValue = applyResult.value;
|
|
553
|
+
}
|
|
554
|
+
const schemaIR = await this.family.introspect({
|
|
555
|
+
driver,
|
|
556
|
+
contractIR: options.destinationContract
|
|
557
|
+
});
|
|
558
|
+
const schemaVerifyResult = verifySqlSchema({
|
|
559
|
+
contract: options.destinationContract,
|
|
560
|
+
schema: schemaIR,
|
|
561
|
+
strict: options.strictVerification ?? true,
|
|
562
|
+
context: options.context ?? {},
|
|
563
|
+
typeMetadataRegistry: this.family.typeMetadataRegistry
|
|
564
|
+
});
|
|
565
|
+
if (!schemaVerifyResult.ok) {
|
|
566
|
+
return runnerFailure("SCHEMA_VERIFY_FAILED", schemaVerifyResult.summary, {
|
|
567
|
+
why: "The resulting database schema does not satisfy the destination contract.",
|
|
568
|
+
meta: {
|
|
569
|
+
issues: schemaVerifyResult.schema.issues
|
|
570
|
+
}
|
|
571
|
+
});
|
|
572
|
+
}
|
|
573
|
+
await this.upsertMarker(driver, options, existingMarker);
|
|
574
|
+
await this.recordLedgerEntry(driver, options, existingMarker, applyValue.executedOperations);
|
|
575
|
+
await this.commitTransaction(driver);
|
|
576
|
+
committed = true;
|
|
577
|
+
return runnerSuccess({
|
|
578
|
+
operationsPlanned: options.plan.operations.length,
|
|
579
|
+
operationsExecuted: applyValue.operationsExecuted
|
|
580
|
+
});
|
|
581
|
+
} finally {
|
|
582
|
+
if (!committed) {
|
|
583
|
+
await this.rollbackTransaction(driver);
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
async applyPlan(driver, options) {
|
|
588
|
+
let operationsExecuted = 0;
|
|
589
|
+
const executedOperations = [];
|
|
590
|
+
for (const operation of options.plan.operations) {
|
|
591
|
+
options.callbacks?.onOperationStart?.(operation);
|
|
592
|
+
try {
|
|
593
|
+
const postcheckAlreadySatisfied = await this.expectationsAreSatisfied(
|
|
594
|
+
driver,
|
|
595
|
+
operation.postcheck
|
|
596
|
+
);
|
|
597
|
+
if (postcheckAlreadySatisfied) {
|
|
598
|
+
executedOperations.push(this.createPostcheckPreSatisfiedSkipRecord(operation));
|
|
599
|
+
continue;
|
|
600
|
+
}
|
|
601
|
+
const precheckResult = await this.runExpectationSteps(
|
|
602
|
+
driver,
|
|
603
|
+
operation.precheck,
|
|
604
|
+
operation,
|
|
605
|
+
"precheck"
|
|
606
|
+
);
|
|
607
|
+
if (!precheckResult.ok) {
|
|
608
|
+
return precheckResult;
|
|
609
|
+
}
|
|
610
|
+
const executeResult = await this.runExecuteSteps(driver, operation.execute, operation);
|
|
611
|
+
if (!executeResult.ok) {
|
|
612
|
+
return executeResult;
|
|
613
|
+
}
|
|
614
|
+
const postcheckResult = await this.runExpectationSteps(
|
|
615
|
+
driver,
|
|
616
|
+
operation.postcheck,
|
|
617
|
+
operation,
|
|
618
|
+
"postcheck"
|
|
619
|
+
);
|
|
620
|
+
if (!postcheckResult.ok) {
|
|
621
|
+
return postcheckResult;
|
|
622
|
+
}
|
|
623
|
+
executedOperations.push(operation);
|
|
624
|
+
operationsExecuted += 1;
|
|
625
|
+
} finally {
|
|
626
|
+
options.callbacks?.onOperationComplete?.(operation);
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
return ok({ operationsExecuted, executedOperations });
|
|
630
|
+
}
|
|
631
|
+
async ensureControlTables(driver) {
|
|
632
|
+
await this.executeStatement(driver, ensurePrismaContractSchemaStatement);
|
|
633
|
+
await this.executeStatement(driver, ensureMarkerTableStatement);
|
|
634
|
+
await this.executeStatement(driver, ensureLedgerTableStatement);
|
|
635
|
+
}
|
|
636
|
+
async runExpectationSteps(driver, steps, operation, phase) {
|
|
637
|
+
for (const step of steps) {
|
|
638
|
+
const result = await driver.query(step.sql);
|
|
639
|
+
if (!this.stepResultIsTrue(result.rows)) {
|
|
640
|
+
const code = phase === "precheck" ? "PRECHECK_FAILED" : "POSTCHECK_FAILED";
|
|
641
|
+
return runnerFailure(
|
|
642
|
+
code,
|
|
643
|
+
`Operation ${operation.id} failed during ${phase}: ${step.description}`,
|
|
644
|
+
{
|
|
645
|
+
meta: {
|
|
646
|
+
operationId: operation.id,
|
|
647
|
+
phase,
|
|
648
|
+
stepDescription: step.description
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
);
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
return okVoid();
|
|
655
|
+
}
|
|
656
|
+
async runExecuteSteps(driver, steps, operation) {
|
|
657
|
+
for (const step of steps) {
|
|
658
|
+
try {
|
|
659
|
+
await driver.query(step.sql);
|
|
660
|
+
} catch (error) {
|
|
661
|
+
return runnerFailure(
|
|
662
|
+
"EXECUTION_FAILED",
|
|
663
|
+
`Operation ${operation.id} failed during execution: ${step.description}`,
|
|
664
|
+
{
|
|
665
|
+
why: error instanceof Error ? error.message : String(error),
|
|
666
|
+
meta: {
|
|
667
|
+
operationId: operation.id,
|
|
668
|
+
stepDescription: step.description,
|
|
669
|
+
sql: step.sql
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
);
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
return okVoid();
|
|
676
|
+
}
|
|
677
|
+
stepResultIsTrue(rows) {
|
|
678
|
+
if (!rows || rows.length === 0) {
|
|
679
|
+
return false;
|
|
680
|
+
}
|
|
681
|
+
const firstRow = rows[0];
|
|
682
|
+
const firstValue = firstRow ? Object.values(firstRow)[0] : void 0;
|
|
683
|
+
if (typeof firstValue === "boolean") {
|
|
684
|
+
return firstValue;
|
|
685
|
+
}
|
|
686
|
+
if (typeof firstValue === "number") {
|
|
687
|
+
return firstValue !== 0;
|
|
688
|
+
}
|
|
689
|
+
if (typeof firstValue === "string") {
|
|
690
|
+
const lower = firstValue.toLowerCase();
|
|
691
|
+
if (lower === "t" || lower === "true" || lower === "1") {
|
|
692
|
+
return true;
|
|
693
|
+
}
|
|
694
|
+
if (lower === "f" || lower === "false" || lower === "0") {
|
|
695
|
+
return false;
|
|
696
|
+
}
|
|
697
|
+
return firstValue.length > 0;
|
|
698
|
+
}
|
|
699
|
+
return Boolean(firstValue);
|
|
700
|
+
}
|
|
701
|
+
async expectationsAreSatisfied(driver, steps) {
|
|
702
|
+
if (steps.length === 0) {
|
|
703
|
+
return false;
|
|
704
|
+
}
|
|
705
|
+
for (const step of steps) {
|
|
706
|
+
const result = await driver.query(step.sql);
|
|
707
|
+
if (!this.stepResultIsTrue(result.rows)) {
|
|
708
|
+
return false;
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
return true;
|
|
712
|
+
}
|
|
713
|
+
createPostcheckPreSatisfiedSkipRecord(operation) {
|
|
714
|
+
const clonedMeta = operation.meta ? cloneAndFreezeRecord(operation.meta) : void 0;
|
|
715
|
+
const runnerMeta = Object.freeze({
|
|
716
|
+
skipped: true,
|
|
717
|
+
reason: "postcheck_pre_satisfied"
|
|
718
|
+
});
|
|
719
|
+
const mergedMeta = Object.freeze({
|
|
720
|
+
...clonedMeta ?? {},
|
|
721
|
+
runner: runnerMeta
|
|
722
|
+
});
|
|
723
|
+
const frozenPostcheck = Object.freeze([...operation.postcheck]);
|
|
724
|
+
return Object.freeze({
|
|
725
|
+
id: operation.id,
|
|
726
|
+
label: operation.label,
|
|
727
|
+
...operation.summary ? { summary: operation.summary } : {},
|
|
728
|
+
operationClass: operation.operationClass,
|
|
729
|
+
target: operation.target,
|
|
730
|
+
// Already frozen from plan creation
|
|
731
|
+
precheck: Object.freeze([]),
|
|
732
|
+
execute: Object.freeze([]),
|
|
733
|
+
postcheck: frozenPostcheck,
|
|
734
|
+
...operation.meta || mergedMeta ? { meta: mergedMeta } : {}
|
|
735
|
+
});
|
|
736
|
+
}
|
|
737
|
+
markerMatchesDestination(marker, plan) {
|
|
738
|
+
if (!marker) {
|
|
739
|
+
return false;
|
|
740
|
+
}
|
|
741
|
+
if (marker.coreHash !== plan.destination.coreHash) {
|
|
742
|
+
return false;
|
|
743
|
+
}
|
|
744
|
+
if (plan.destination.profileHash && marker.profileHash !== plan.destination.profileHash) {
|
|
745
|
+
return false;
|
|
746
|
+
}
|
|
747
|
+
return true;
|
|
748
|
+
}
|
|
749
|
+
enforcePolicyCompatibility(policy, operations) {
|
|
750
|
+
const allowedClasses = new Set(policy.allowedOperationClasses);
|
|
751
|
+
for (const operation of operations) {
|
|
752
|
+
if (!allowedClasses.has(operation.operationClass)) {
|
|
753
|
+
return runnerFailure(
|
|
754
|
+
"POLICY_VIOLATION",
|
|
755
|
+
`Operation ${operation.id} has class "${operation.operationClass}" which is not allowed by policy.`,
|
|
756
|
+
{
|
|
757
|
+
why: `Policy only allows: ${policy.allowedOperationClasses.join(", ")}.`,
|
|
758
|
+
meta: {
|
|
759
|
+
operationId: operation.id,
|
|
760
|
+
operationClass: operation.operationClass,
|
|
761
|
+
allowedClasses: policy.allowedOperationClasses
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
);
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
return okVoid();
|
|
768
|
+
}
|
|
769
|
+
ensureMarkerCompatibility(marker, plan) {
|
|
770
|
+
const origin = plan.origin ?? null;
|
|
771
|
+
if (!origin) {
|
|
772
|
+
if (!marker) {
|
|
773
|
+
return okVoid();
|
|
774
|
+
}
|
|
775
|
+
if (this.markerMatchesDestination(marker, plan)) {
|
|
776
|
+
return okVoid();
|
|
777
|
+
}
|
|
778
|
+
return runnerFailure(
|
|
779
|
+
"MARKER_ORIGIN_MISMATCH",
|
|
780
|
+
`Existing contract marker (${marker.coreHash}) does not match plan origin (no marker expected).`,
|
|
781
|
+
{
|
|
782
|
+
meta: {
|
|
783
|
+
markerCoreHash: marker.coreHash,
|
|
784
|
+
expectedOrigin: null
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
);
|
|
788
|
+
}
|
|
789
|
+
if (!marker) {
|
|
790
|
+
return runnerFailure(
|
|
791
|
+
"MARKER_ORIGIN_MISMATCH",
|
|
792
|
+
`Missing contract marker: expected origin core hash ${origin.coreHash}.`,
|
|
793
|
+
{
|
|
794
|
+
meta: {
|
|
795
|
+
expectedOriginCoreHash: origin.coreHash
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
);
|
|
799
|
+
}
|
|
800
|
+
if (marker.coreHash !== origin.coreHash) {
|
|
801
|
+
return runnerFailure(
|
|
802
|
+
"MARKER_ORIGIN_MISMATCH",
|
|
803
|
+
`Existing contract marker (${marker.coreHash}) does not match plan origin (${origin.coreHash}).`,
|
|
804
|
+
{
|
|
805
|
+
meta: {
|
|
806
|
+
markerCoreHash: marker.coreHash,
|
|
807
|
+
expectedOriginCoreHash: origin.coreHash
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
);
|
|
811
|
+
}
|
|
812
|
+
if (origin.profileHash && marker.profileHash !== origin.profileHash) {
|
|
813
|
+
return runnerFailure(
|
|
814
|
+
"MARKER_ORIGIN_MISMATCH",
|
|
815
|
+
`Existing contract marker profile hash (${marker.profileHash}) does not match plan origin profile hash (${origin.profileHash}).`,
|
|
816
|
+
{
|
|
817
|
+
meta: {
|
|
818
|
+
markerProfileHash: marker.profileHash,
|
|
819
|
+
expectedOriginProfileHash: origin.profileHash
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
);
|
|
823
|
+
}
|
|
824
|
+
return okVoid();
|
|
825
|
+
}
|
|
826
|
+
ensurePlanMatchesDestinationContract(destination, contract) {
|
|
827
|
+
if (destination.coreHash !== contract.coreHash) {
|
|
828
|
+
return runnerFailure(
|
|
829
|
+
"DESTINATION_CONTRACT_MISMATCH",
|
|
830
|
+
`Plan destination core hash (${destination.coreHash}) does not match provided contract core hash (${contract.coreHash}).`,
|
|
831
|
+
{
|
|
832
|
+
meta: {
|
|
833
|
+
planCoreHash: destination.coreHash,
|
|
834
|
+
contractCoreHash: contract.coreHash
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
);
|
|
838
|
+
}
|
|
839
|
+
if (destination.profileHash && contract.profileHash && destination.profileHash !== contract.profileHash) {
|
|
840
|
+
return runnerFailure(
|
|
841
|
+
"DESTINATION_CONTRACT_MISMATCH",
|
|
842
|
+
`Plan destination profile hash (${destination.profileHash}) does not match provided contract profile hash (${contract.profileHash}).`,
|
|
843
|
+
{
|
|
844
|
+
meta: {
|
|
845
|
+
planProfileHash: destination.profileHash,
|
|
846
|
+
contractProfileHash: contract.profileHash
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
);
|
|
850
|
+
}
|
|
851
|
+
return okVoid();
|
|
852
|
+
}
|
|
853
|
+
async upsertMarker(driver, options, existingMarker) {
|
|
854
|
+
const writeStatements = buildWriteMarkerStatements({
|
|
855
|
+
coreHash: options.plan.destination.coreHash,
|
|
856
|
+
profileHash: options.plan.destination.profileHash ?? options.destinationContract.profileHash ?? options.plan.destination.coreHash,
|
|
857
|
+
contractJson: options.destinationContract,
|
|
858
|
+
canonicalVersion: null,
|
|
859
|
+
meta: {}
|
|
860
|
+
});
|
|
861
|
+
const statement = existingMarker ? writeStatements.update : writeStatements.insert;
|
|
862
|
+
await this.executeStatement(driver, statement);
|
|
863
|
+
}
|
|
864
|
+
async recordLedgerEntry(driver, options, existingMarker, executedOperations) {
|
|
865
|
+
const ledgerStatement = buildLedgerInsertStatement({
|
|
866
|
+
originCoreHash: existingMarker?.coreHash ?? null,
|
|
867
|
+
originProfileHash: existingMarker?.profileHash ?? null,
|
|
868
|
+
destinationCoreHash: options.plan.destination.coreHash,
|
|
869
|
+
destinationProfileHash: options.plan.destination.profileHash ?? options.destinationContract.profileHash ?? options.plan.destination.coreHash,
|
|
870
|
+
contractJsonBefore: existingMarker?.contractJson ?? null,
|
|
871
|
+
contractJsonAfter: options.destinationContract,
|
|
872
|
+
operations: executedOperations
|
|
873
|
+
});
|
|
874
|
+
await this.executeStatement(driver, ledgerStatement);
|
|
875
|
+
}
|
|
876
|
+
async acquireLock(driver, key) {
|
|
877
|
+
await driver.query("select pg_advisory_xact_lock(hashtext($1))", [key]);
|
|
878
|
+
}
|
|
879
|
+
async beginTransaction(driver) {
|
|
880
|
+
await driver.query("BEGIN");
|
|
881
|
+
}
|
|
882
|
+
async commitTransaction(driver) {
|
|
883
|
+
await driver.query("COMMIT");
|
|
884
|
+
}
|
|
885
|
+
async rollbackTransaction(driver) {
|
|
886
|
+
await driver.query("ROLLBACK");
|
|
887
|
+
}
|
|
888
|
+
async executeStatement(driver, statement) {
|
|
889
|
+
if (statement.params.length > 0) {
|
|
890
|
+
await driver.query(statement.sql, statement.params);
|
|
891
|
+
return;
|
|
892
|
+
}
|
|
893
|
+
await driver.query(statement.sql);
|
|
894
|
+
}
|
|
895
|
+
};
|
|
896
|
+
|
|
897
|
+
// src/exports/control.ts
|
|
6
898
|
var __filename = fileURLToPath(import.meta.url);
|
|
7
899
|
var __dirname = dirname(__filename);
|
|
8
900
|
var TypesImportSpecSchema = type({
|
|
@@ -46,6 +938,12 @@ var postgresTargetDescriptor = {
|
|
|
46
938
|
familyId: "sql",
|
|
47
939
|
targetId: "postgres"
|
|
48
940
|
};
|
|
941
|
+
},
|
|
942
|
+
createPlanner(_family) {
|
|
943
|
+
return createPostgresMigrationPlanner();
|
|
944
|
+
},
|
|
945
|
+
createRunner(family) {
|
|
946
|
+
return createPostgresMigrationRunner(family);
|
|
49
947
|
}
|
|
50
948
|
};
|
|
51
949
|
var control_default = postgresTargetDescriptor;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/exports/control.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 ControlTargetDescriptor,\n ControlTargetInstance,\n} from '@prisma-next/core-control-plane/types';\nimport { type } from 'arktype';\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: ControlTargetDescriptor<\n 'sql',\n 'postgres',\n ControlTargetInstance<'sql', 'postgres'>\n> = {\n kind: 'target',\n familyId: 'sql',\n targetId: 'postgres',\n id: 'postgres',\n manifest: loadTargetManifest(),\n create(): ControlTargetInstance<'sql', 'postgres'> {\n return {\n familyId: 'sql',\n targetId: 'postgres',\n };\n },\n};\n\nexport default postgresTargetDescriptor;\n"],"mappings":";AAAA,SAAS,oBAAoB;AAC7B,SAAS,SAAS,YAAY;AAC9B,SAAS,qBAAqB;AAM9B,SAAS,YAAY;AAErB,IAAM,aAAa,cAAc,YAAY,GAAG;AAChD,IAAM,YAAY,QAAQ,UAAU;AAEpC,IAAM,wBAAwB,KAAK;AAAA,EACjC,SAAS;AAAA,EACT,OAAO;AAAA,EACP,OAAO;AACT,CAAC;AAED,IAAM,8BAA8B,KAAK;AAAA,EACvC,IAAI;AAAA,EACJ,SAAS;AAAA,EACT,YAAY,KAAK,EAAE,YAAY,KAAK,EAAE,eAAe,SAAS,CAAC,EAAE,CAAC;AAAA,EAClE,iBAAiB;AAAA,EACjB,UAAU,KAAK;AAAA,IACb,eAAe,KAAK;AAAA,MAClB,QAAQ;AAAA,IACV,CAAC;AAAA,IACD,mBAAmB,KAAK;AAAA,MACtB,QAAQ;AAAA,IACV,CAAC;AAAA,EACH,CAAC;AAAA,EACD,eAAe;AACjB,CAAC;AAKD,SAAS,qBAA4C;AACnD,QAAM,eAAe,KAAK,WAAW,2BAA2B;AAChE,QAAM,eAAe,KAAK,MAAM,aAAa,cAAc,OAAO,CAAC;AAEnE,QAAM,SAAS,4BAA4B,YAAY;AACvD,MAAI,kBAAkB,KAAK,QAAQ;AACjC,UAAM,WAAW,OAAO,IAAI,CAAC,MAA2B,EAAE,OAAO,EAAE,KAAK,IAAI;AAC5E,UAAM,IAAI,MAAM,wCAAwC,YAAY,KAAK,QAAQ,EAAE;AAAA,EACrF;AAEA,SAAO;AACT;AAKA,IAAM,2BAIF;AAAA,EACF,MAAM;AAAA,EACN,UAAU;AAAA,EACV,UAAU;AAAA,EACV,IAAI;AAAA,EACJ,UAAU,mBAAmB;AAAA,EAC7B,SAAmD;AACjD,WAAO;AAAA,MACL,UAAU;AAAA,MACV,UAAU;AAAA,IACZ;AAAA,EACF;AACF;AAEA,IAAO,kBAAQ;","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 { 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 create(): ControlTargetInstance<'sql', 'postgres'> {\n return {\n familyId: 'sql',\n targetId: 'postgres',\n };\n },\n createPlanner(_family: SqlControlFamilyInstance) {\n return createPostgresMigrationPlanner();\n },\n createRunner(family) {\n return createPostgresMigrationRunner(family);\n },\n };\n\nexport default postgresTargetDescriptor;\n","import type {\n MigrationOperationPolicy,\n MigrationPlanner,\n MigrationPlannerPlanOptions,\n MigrationPlanOperation,\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): MigrationPlanner<PostgresPlanTargetDetails> {\n return new PostgresMigrationPlanner({\n ...DEFAULT_PLANNER_CONFIG,\n ...config,\n });\n}\n\nclass PostgresMigrationPlanner implements MigrationPlanner<PostgresPlanTargetDetails> {\n constructor(private readonly config: PlannerConfig) {}\n\n plan(options: MigrationPlannerPlanOptions) {\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: MigrationPlanOperation<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 MigrationPlanOperation<PostgresPlanTargetDetails>[] {\n const extensions = contract.extensions ?? {};\n const extensionNames = Object.keys(extensions);\n const operations: MigrationPlanOperation<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 MigrationPlanOperation<PostgresPlanTargetDetails>[] {\n const operations: MigrationPlanOperation<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 MigrationPlanOperation<PostgresPlanTargetDetails>[] {\n const operations: MigrationPlanOperation<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 MigrationPlanOperation<PostgresPlanTargetDetails>[] {\n const operations: MigrationPlanOperation<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 MigrationPlanOperation<PostgresPlanTargetDetails>[] {\n const operations: MigrationPlanOperation<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 MigrationPlanContractInfo,\n MigrationPlanOperation,\n MigrationPlanOperationStep,\n MigrationRunner,\n MigrationRunnerExecuteOptions,\n MigrationRunnerFailure,\n MigrationRunnerResult,\n SqlControlFamilyInstance,\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 MigrationPlanOperation<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): MigrationRunner<PostgresPlanTargetDetails> {\n return new PostgresMigrationRunner(family, { ...DEFAULT_CONFIG, ...config });\n}\n\nclass PostgresMigrationRunner implements MigrationRunner<PostgresPlanTargetDetails> {\n constructor(\n private readonly family: SqlControlFamilyInstance,\n private readonly config: RunnerConfig,\n ) {}\n\n async execute(\n options: MigrationRunnerExecuteOptions<PostgresPlanTargetDetails>,\n ): Promise<MigrationRunnerResult> {\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: MigrationRunnerExecuteOptions<PostgresPlanTargetDetails>['driver'],\n options: MigrationRunnerExecuteOptions<PostgresPlanTargetDetails>,\n ): Promise<Result<ApplyPlanSuccessValue, MigrationRunnerFailure>> {\n let operationsExecuted = 0;\n const executedOperations: Array<MigrationPlanOperation<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: MigrationRunnerExecuteOptions<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: MigrationRunnerExecuteOptions<PostgresPlanTargetDetails>['driver'],\n steps: readonly MigrationPlanOperationStep[],\n operation: MigrationPlanOperation<PostgresPlanTargetDetails>,\n phase: 'precheck' | 'postcheck',\n ): Promise<Result<void, MigrationRunnerFailure>> {\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: MigrationRunnerExecuteOptions<PostgresPlanTargetDetails>['driver'],\n steps: readonly MigrationPlanOperationStep[],\n operation: MigrationPlanOperation<PostgresPlanTargetDetails>,\n ): Promise<Result<void, MigrationRunnerFailure>> {\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: MigrationRunnerExecuteOptions<PostgresPlanTargetDetails>['driver'],\n steps: readonly MigrationPlanOperationStep[],\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: MigrationPlanOperation<PostgresPlanTargetDetails>,\n ): MigrationPlanOperation<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: MigrationRunnerExecuteOptions<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 MigrationPlanOperation<PostgresPlanTargetDetails>[],\n ): Result<void, MigrationRunnerFailure> {\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: MigrationRunnerExecuteOptions<PostgresPlanTargetDetails>['plan'],\n ): Result<void, MigrationRunnerFailure> {\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: MigrationPlanContractInfo,\n contract: MigrationRunnerExecuteOptions<PostgresPlanTargetDetails>['destinationContract'],\n ): Result<void, MigrationRunnerFailure> {\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: MigrationRunnerExecuteOptions<PostgresPlanTargetDetails>['driver'],\n options: MigrationRunnerExecuteOptions<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: MigrationRunnerExecuteOptions<PostgresPlanTargetDetails>['driver'],\n options: MigrationRunnerExecuteOptions<PostgresPlanTargetDetails>,\n existingMarker: ContractMarkerRecord | null,\n executedOperations: readonly MigrationPlanOperation<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: MigrationRunnerExecuteOptions<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: MigrationRunnerExecuteOptions<PostgresPlanTargetDetails>['driver'],\n ): Promise<void> {\n await driver.query('BEGIN');\n }\n\n private async commitTransaction(\n driver: MigrationRunnerExecuteOptions<PostgresPlanTargetDetails>['driver'],\n ): Promise<void> {\n await driver.query('COMMIT');\n }\n\n private async rollbackTransaction(\n driver: MigrationRunnerExecuteOptions<PostgresPlanTargetDetails>['driver'],\n ): Promise<void> {\n await driver.query('ROLLBACK');\n }\n\n private async executeStatement(\n driver: MigrationRunnerExecuteOptions<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":[]}
|
package/package.json
CHANGED
|
@@ -1,20 +1,27 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prisma-next/target-postgres",
|
|
3
|
-
"version": "0.1.0-pr.
|
|
3
|
+
"version": "0.1.0-pr.49.2",
|
|
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/
|
|
10
|
-
"@prisma-next/
|
|
11
|
-
"@prisma-next/
|
|
12
|
-
"@prisma-next/
|
|
9
|
+
"@prisma-next/family-sql": "0.1.0-pr.49.2",
|
|
10
|
+
"@prisma-next/cli": "0.1.0-pr.49.2",
|
|
11
|
+
"@prisma-next/contract": "0.1.0-pr.49.2",
|
|
12
|
+
"@prisma-next/sql-contract": "0.1.0-pr.49.2",
|
|
13
|
+
"@prisma-next/sql-schema-ir": "0.1.0-pr.49.2",
|
|
14
|
+
"@prisma-next/core-control-plane": "0.1.0-pr.49.2",
|
|
15
|
+
"@prisma-next/core-execution-plane": "0.1.0-pr.49.2",
|
|
16
|
+
"@prisma-next/utils": "0.1.0-pr.49.2"
|
|
13
17
|
},
|
|
14
18
|
"devDependencies": {
|
|
19
|
+
"vite-tsconfig-paths": "^5.1.4",
|
|
15
20
|
"tsup": "^8.3.0",
|
|
16
21
|
"typescript": "^5.9.3",
|
|
17
22
|
"vitest": "^2.1.1",
|
|
23
|
+
"@prisma-next/adapter-postgres": "0.1.0-pr.49.2",
|
|
24
|
+
"@prisma-next/driver-postgres": "0.1.0-pr.49.2",
|
|
18
25
|
"@prisma-next/test-utils": "0.0.1"
|
|
19
26
|
},
|
|
20
27
|
"files": [
|