@prisma-next/target-postgres 0.4.0-dev.6 → 0.4.0-dev.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/control.mjs +137 -3
- package/dist/control.mjs.map +1 -1
- package/package.json +19 -17
- package/src/core/migrations/planner.ts +84 -7
- package/src/core/migrations/scaffolding.ts +140 -0
- package/src/exports/control.ts +5 -2
package/dist/control.mjs
CHANGED
|
@@ -4,13 +4,15 @@ import { LiteralExpr, SQL_CHAR_CODEC_ID, SQL_FLOAT_CODEC_ID, SQL_INT_CODEC_ID, S
|
|
|
4
4
|
import { ifDefined } from "@prisma-next/utils/defined";
|
|
5
5
|
import { type } from "arktype";
|
|
6
6
|
import { arraysEqual, verifySqlSchema } from "@prisma-next/family-sql/schema-verify";
|
|
7
|
-
import { collectInitDependencies, contractToSchemaIR, createMigrationPlan, extractCodecControlHooks, plannerFailure,
|
|
7
|
+
import { collectInitDependencies, contractToSchemaIR, createMigrationPlan, extractCodecControlHooks, plannerFailure, runnerFailure, runnerSuccess } from "@prisma-next/family-sql/control";
|
|
8
8
|
import { MigrationDescriptorArraySchema } from "@prisma-next/family-sql/operation-descriptors";
|
|
9
9
|
import { sql } from "@prisma-next/sql-builder/runtime";
|
|
10
10
|
import { notOk, ok, okVoid } from "@prisma-next/utils/result";
|
|
11
11
|
import { lowerSqlPlan } from "@prisma-next/sql-runtime";
|
|
12
|
+
import { errorPlanDoesNotSupportAuthoringSurface } from "@prisma-next/errors/migration";
|
|
12
13
|
import { defaultIndexName } from "@prisma-next/sql-schema-ir/naming";
|
|
13
14
|
import { invariant } from "@prisma-next/utils/assertions";
|
|
15
|
+
import { relative } from "pathe";
|
|
14
16
|
import { readMarker } from "@prisma-next/family-sql/verify";
|
|
15
17
|
import { SqlQueryError } from "@prisma-next/sql-errors";
|
|
16
18
|
|
|
@@ -4299,6 +4301,94 @@ function hasForeignKey(lookup, fk) {
|
|
|
4299
4301
|
return lookup.fkKeys.has(`${fk.columns.join(",")}|${fk.references.table}|${fk.references.columns.join(",")}`);
|
|
4300
4302
|
}
|
|
4301
4303
|
|
|
4304
|
+
//#endregion
|
|
4305
|
+
//#region src/core/migrations/scaffolding.ts
|
|
4306
|
+
function serializeQueryInput(input) {
|
|
4307
|
+
if (typeof input === "boolean") return String(input);
|
|
4308
|
+
if (typeof input === "symbol") return "TODO /* fill in using db.sql.from(...) */";
|
|
4309
|
+
if (input === null || input === void 0) return "null";
|
|
4310
|
+
if (Array.isArray(input)) {
|
|
4311
|
+
if (input.length === 0) return "[]";
|
|
4312
|
+
if (input.every((item) => typeof item === "symbol")) return "[TODO /* fill in using db.sql.from(...) */]";
|
|
4313
|
+
return `[${input.map(serializeQueryInput).join(", ")}]`;
|
|
4314
|
+
}
|
|
4315
|
+
return JSON.stringify(input);
|
|
4316
|
+
}
|
|
4317
|
+
function renderDescriptor(desc) {
|
|
4318
|
+
switch (desc.kind) {
|
|
4319
|
+
case "createTable": return `createTable(${JSON.stringify(desc["table"])})`;
|
|
4320
|
+
case "dropTable": return `dropTable(${JSON.stringify(desc["table"])})`;
|
|
4321
|
+
case "addColumn": {
|
|
4322
|
+
const args = [JSON.stringify(desc["table"]), JSON.stringify(desc["column"])];
|
|
4323
|
+
if (desc["overrides"]) args.push(JSON.stringify(desc["overrides"]));
|
|
4324
|
+
return `addColumn(${args.join(", ")})`;
|
|
4325
|
+
}
|
|
4326
|
+
case "dropColumn": return `dropColumn(${JSON.stringify(desc["table"])}, ${JSON.stringify(desc["column"])})`;
|
|
4327
|
+
case "alterColumnType": {
|
|
4328
|
+
const opts = {};
|
|
4329
|
+
if (desc["using"]) opts["using"] = desc["using"];
|
|
4330
|
+
if (desc["toType"]) opts["toType"] = desc["toType"];
|
|
4331
|
+
return Object.keys(opts).length > 0 ? `alterColumnType(${JSON.stringify(desc["table"])}, ${JSON.stringify(desc["column"])}, ${JSON.stringify(opts)})` : `alterColumnType(${JSON.stringify(desc["table"])}, ${JSON.stringify(desc["column"])})`;
|
|
4332
|
+
}
|
|
4333
|
+
case "setNotNull": return `setNotNull(${JSON.stringify(desc["table"])}, ${JSON.stringify(desc["column"])})`;
|
|
4334
|
+
case "dropNotNull": return `dropNotNull(${JSON.stringify(desc["table"])}, ${JSON.stringify(desc["column"])})`;
|
|
4335
|
+
case "setDefault": return `setDefault(${JSON.stringify(desc["table"])}, ${JSON.stringify(desc["column"])})`;
|
|
4336
|
+
case "dropDefault": return `dropDefault(${JSON.stringify(desc["table"])}, ${JSON.stringify(desc["column"])})`;
|
|
4337
|
+
case "addPrimaryKey": return `addPrimaryKey(${JSON.stringify(desc["table"])})`;
|
|
4338
|
+
case "addUnique": return `addUnique(${JSON.stringify(desc["table"])}, ${JSON.stringify(desc["columns"])})`;
|
|
4339
|
+
case "addForeignKey": return `addForeignKey(${JSON.stringify(desc["table"])}, ${JSON.stringify(desc["columns"])})`;
|
|
4340
|
+
case "dropConstraint": return `dropConstraint(${JSON.stringify(desc["table"])}, ${JSON.stringify(desc["constraintName"])})`;
|
|
4341
|
+
case "createIndex": return `createIndex(${JSON.stringify(desc["table"])}, ${JSON.stringify(desc["columns"])})`;
|
|
4342
|
+
case "dropIndex": return `dropIndex(${JSON.stringify(desc["table"])}, ${JSON.stringify(desc["indexName"])})`;
|
|
4343
|
+
case "createEnumType": return desc["values"] ? `createEnumType(${JSON.stringify(desc["typeName"])}, ${JSON.stringify(desc["values"])})` : `createEnumType(${JSON.stringify(desc["typeName"])})`;
|
|
4344
|
+
case "addEnumValues": return `addEnumValues(${JSON.stringify(desc["typeName"])}, ${JSON.stringify(desc["values"])})`;
|
|
4345
|
+
case "dropEnumType": return `dropEnumType(${JSON.stringify(desc["typeName"])})`;
|
|
4346
|
+
case "renameType": return `renameType(${JSON.stringify(desc["fromName"])}, ${JSON.stringify(desc["toName"])})`;
|
|
4347
|
+
case "createDependency": return `createDependency(${JSON.stringify(desc["dependencyId"])})`;
|
|
4348
|
+
case "dataTransform": return `dataTransform(${JSON.stringify(desc["name"])}, {\n check: ${serializeQueryInput(desc["check"])},\n run: ${serializeQueryInput(desc["run"])},\n })`;
|
|
4349
|
+
default: throw new Error(`Unknown Postgres descriptor kind: ${desc.kind}`);
|
|
4350
|
+
}
|
|
4351
|
+
}
|
|
4352
|
+
function renderPreamble(plan, context) {
|
|
4353
|
+
const hasDataTransform = plan.some((d) => d.kind === "dataTransform");
|
|
4354
|
+
if (hasDataTransform && context.contractJsonPath) {
|
|
4355
|
+
const relativeContractDts = relative(context.packageDir, context.contractJsonPath).replace(/\.json$/, ".d");
|
|
4356
|
+
const importList$1 = [...new Set(plan.map((d) => d.kind))];
|
|
4357
|
+
importList$1.push("TODO");
|
|
4358
|
+
return [
|
|
4359
|
+
`import type { Contract } from "${relativeContractDts}"`,
|
|
4360
|
+
`import { createBuilders } from "@prisma-next/target-postgres/migration-builders"`,
|
|
4361
|
+
"",
|
|
4362
|
+
`const { ${importList$1.join(", ")} } = createBuilders<Contract>()`
|
|
4363
|
+
];
|
|
4364
|
+
}
|
|
4365
|
+
const importList = [...new Set(plan.map((d) => d.kind))];
|
|
4366
|
+
if (importList.length === 0) importList.push("createTable");
|
|
4367
|
+
if (hasDataTransform) importList.push("TODO");
|
|
4368
|
+
return [`import { ${importList.join(", ")} } from "@prisma-next/target-postgres/migration-builders"`];
|
|
4369
|
+
}
|
|
4370
|
+
/**
|
|
4371
|
+
* Render a Postgres descriptor list to a `migration.ts` source string.
|
|
4372
|
+
*
|
|
4373
|
+
* Internal to the Postgres target — no longer part of the framework SPI.
|
|
4374
|
+
* Invoked from two paths:
|
|
4375
|
+
* - the migrations capability's `renderDescriptorTypeScript` hook (called by
|
|
4376
|
+
* the CLI after `planWithDescriptors` to seed an editable authoring
|
|
4377
|
+
* surface, and by `emptyMigration()` to produce the `migration new` stub);
|
|
4378
|
+
* - directly by this package's unit tests.
|
|
4379
|
+
*/
|
|
4380
|
+
function renderDescriptorTypeScript(descriptors, context) {
|
|
4381
|
+
const preamble = renderPreamble(descriptors, context);
|
|
4382
|
+
const calls = descriptors.map((d) => ` ${renderDescriptor(d)},`);
|
|
4383
|
+
const body = calls.length > 0 ? `\n${calls.join("\n")}\n` : "";
|
|
4384
|
+
return [
|
|
4385
|
+
...preamble,
|
|
4386
|
+
"",
|
|
4387
|
+
`export default () => [${body}]`,
|
|
4388
|
+
""
|
|
4389
|
+
].join("\n");
|
|
4390
|
+
}
|
|
4391
|
+
|
|
4302
4392
|
//#endregion
|
|
4303
4393
|
//#region src/core/migrations/planner.ts
|
|
4304
4394
|
const DEFAULT_PLANNER_CONFIG = { defaultSchema: "public" };
|
|
@@ -4308,11 +4398,43 @@ function createPostgresMigrationPlanner(config = {}) {
|
|
|
4308
4398
|
...config
|
|
4309
4399
|
});
|
|
4310
4400
|
}
|
|
4401
|
+
/**
|
|
4402
|
+
* Postgres migration planner.
|
|
4403
|
+
*
|
|
4404
|
+
* Implements the framework's `MigrationPlanner<'sql', 'postgres'>` directly
|
|
4405
|
+
* — meaning it owns `emptyMigration()` and attaches the `renderTypeScript()`
|
|
4406
|
+
* stub to success plans (Postgres uses descriptor-flow authoring, so
|
|
4407
|
+
* `renderTypeScript()` throws on planner-produced plans). No external wrapper
|
|
4408
|
+
* is required at the descriptor level.
|
|
4409
|
+
*
|
|
4410
|
+
* `plan()` accepts the framework's option shape (with `contract`/`schema`
|
|
4411
|
+
* typed as `unknown`); SQL-typed callers may pass the more specific
|
|
4412
|
+
* `SqlMigrationPlannerPlanOptions`, since those structurally satisfy the
|
|
4413
|
+
* looser framework contract. Internally we treat options as the SQL-typed
|
|
4414
|
+
* superset so the existing planner logic stays identical.
|
|
4415
|
+
*
|
|
4416
|
+
* `fromHash` is accepted but ignored: Postgres is descriptor-flow and never
|
|
4417
|
+
* needs it (only class-flow planners like Mongo populate `describe()` from
|
|
4418
|
+
* `fromHash`).
|
|
4419
|
+
*/
|
|
4311
4420
|
var PostgresMigrationPlanner = class {
|
|
4312
4421
|
constructor(config) {
|
|
4313
4422
|
this.config = config;
|
|
4314
4423
|
}
|
|
4315
4424
|
plan(options) {
|
|
4425
|
+
return this.planSql(options);
|
|
4426
|
+
}
|
|
4427
|
+
emptyMigration(context) {
|
|
4428
|
+
return {
|
|
4429
|
+
targetId: "postgres",
|
|
4430
|
+
destination: { storageHash: context.toHash },
|
|
4431
|
+
operations: [],
|
|
4432
|
+
renderTypeScript() {
|
|
4433
|
+
return renderDescriptorTypeScript([], context);
|
|
4434
|
+
}
|
|
4435
|
+
};
|
|
4436
|
+
}
|
|
4437
|
+
planSql(options) {
|
|
4316
4438
|
const schemaName = options.schemaName ?? this.config.defaultSchema;
|
|
4317
4439
|
const policyResult = this.ensureAdditivePolicy(options.policy);
|
|
4318
4440
|
if (policyResult) return policyResult;
|
|
@@ -4335,7 +4457,7 @@ var PostgresMigrationPlanner = class {
|
|
|
4335
4457
|
const sortedTables = sortedEntries(options.contract.storage.tables);
|
|
4336
4458
|
const schemaLookups = buildSchemaLookupMap(options.schema);
|
|
4337
4459
|
operations.push(...this.buildDatabaseDependencyOperations(options), ...storageTypePlan.operations, ...reconciliationPlan.operations, ...this.buildTableOperations(sortedTables, options.schema, schemaName, codecHooks, storageTypes), ...this.buildColumnOperations(sortedTables, options.schema, schemaLookups, schemaName, codecHooks, storageTypes), ...this.buildPrimaryKeyOperations(sortedTables, options.schema, schemaName), ...this.buildUniqueOperations(sortedTables, schemaLookups, schemaName), ...this.buildIndexOperations(sortedTables, schemaLookups, schemaName), ...this.buildFkBackingIndexOperations(sortedTables, schemaLookups, schemaName), ...this.buildForeignKeyOperations(sortedTables, schemaLookups, schemaName));
|
|
4338
|
-
|
|
4460
|
+
const plan = createMigrationPlan({
|
|
4339
4461
|
targetId: "postgres",
|
|
4340
4462
|
origin: null,
|
|
4341
4463
|
destination: {
|
|
@@ -4343,7 +4465,16 @@ var PostgresMigrationPlanner = class {
|
|
|
4343
4465
|
...ifDefined("profileHash", options.contract.profileHash)
|
|
4344
4466
|
},
|
|
4345
4467
|
operations
|
|
4346
|
-
})
|
|
4468
|
+
});
|
|
4469
|
+
return Object.freeze({
|
|
4470
|
+
kind: "success",
|
|
4471
|
+
plan: Object.freeze({
|
|
4472
|
+
...plan,
|
|
4473
|
+
renderTypeScript() {
|
|
4474
|
+
throw errorPlanDoesNotSupportAuthoringSurface({ targetId: "postgres" });
|
|
4475
|
+
}
|
|
4476
|
+
})
|
|
4477
|
+
});
|
|
4347
4478
|
}
|
|
4348
4479
|
ensureAdditivePolicy(policy) {
|
|
4349
4480
|
if (!policy.allowedOperationClasses.includes("additive")) return plannerFailure([{
|
|
@@ -5328,6 +5459,9 @@ const postgresTargetDescriptor = {
|
|
|
5328
5459
|
dependencies,
|
|
5329
5460
|
db
|
|
5330
5461
|
});
|
|
5462
|
+
},
|
|
5463
|
+
renderDescriptorTypeScript(descriptors, context) {
|
|
5464
|
+
return renderDescriptorTypeScript(descriptors, context);
|
|
5331
5465
|
}
|
|
5332
5466
|
},
|
|
5333
5467
|
create() {
|