@prisma-next/target-postgres 0.4.0-dev.5 → 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 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, plannerSuccess, runnerFailure, runnerSuccess } from "@prisma-next/family-sql/control";
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
 
@@ -2407,7 +2409,7 @@ function planDescriptors(options) {
2407
2409
  const columnOps = defaultOps.filter((op) => op.kind === "addColumn");
2408
2410
  const alterOps = defaultOps.filter((op) => op.kind === "alterColumnType" || op.kind === "setNotNull" || op.kind === "dropNotNull" || op.kind === "setDefault");
2409
2411
  const constraintOps = defaultOps.filter((op) => op.kind === "addPrimaryKey" || op.kind === "addUnique" || op.kind === "createIndex" || op.kind === "addForeignKey");
2410
- const descriptors = [
2412
+ return ok({ descriptors: [
2411
2413
  ...depOps,
2412
2414
  ...dropOps,
2413
2415
  ...tableOps,
@@ -2415,11 +2417,7 @@ function planDescriptors(options) {
2415
2417
  ...patternOps,
2416
2418
  ...alterOps,
2417
2419
  ...constraintOps
2418
- ];
2419
- return ok({
2420
- descriptors,
2421
- needsDataMigration: descriptors.some((op) => op.kind === "dataTransform")
2422
- });
2420
+ ] });
2423
2421
  }
2424
2422
 
2425
2423
  //#endregion
@@ -4303,6 +4301,94 @@ function hasForeignKey(lookup, fk) {
4303
4301
  return lookup.fkKeys.has(`${fk.columns.join(",")}|${fk.references.table}|${fk.references.columns.join(",")}`);
4304
4302
  }
4305
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
+
4306
4392
  //#endregion
4307
4393
  //#region src/core/migrations/planner.ts
4308
4394
  const DEFAULT_PLANNER_CONFIG = { defaultSchema: "public" };
@@ -4312,11 +4398,43 @@ function createPostgresMigrationPlanner(config = {}) {
4312
4398
  ...config
4313
4399
  });
4314
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
+ */
4315
4420
  var PostgresMigrationPlanner = class {
4316
4421
  constructor(config) {
4317
4422
  this.config = config;
4318
4423
  }
4319
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) {
4320
4438
  const schemaName = options.schemaName ?? this.config.defaultSchema;
4321
4439
  const policyResult = this.ensureAdditivePolicy(options.policy);
4322
4440
  if (policyResult) return policyResult;
@@ -4339,7 +4457,7 @@ var PostgresMigrationPlanner = class {
4339
4457
  const sortedTables = sortedEntries(options.contract.storage.tables);
4340
4458
  const schemaLookups = buildSchemaLookupMap(options.schema);
4341
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));
4342
- return plannerSuccess(createMigrationPlan({
4460
+ const plan = createMigrationPlan({
4343
4461
  targetId: "postgres",
4344
4462
  origin: null,
4345
4463
  destination: {
@@ -4347,7 +4465,16 @@ var PostgresMigrationPlanner = class {
4347
4465
  ...ifDefined("profileHash", options.contract.profileHash)
4348
4466
  },
4349
4467
  operations
4350
- }));
4468
+ });
4469
+ return Object.freeze({
4470
+ kind: "success",
4471
+ plan: Object.freeze({
4472
+ ...plan,
4473
+ renderTypeScript() {
4474
+ throw errorPlanDoesNotSupportAuthoringSurface({ targetId: "postgres" });
4475
+ }
4476
+ })
4477
+ });
4351
4478
  }
4352
4479
  ensureAdditivePolicy(policy) {
4353
4480
  if (!policy.allowedOperationClasses.includes("additive")) return plannerFailure([{
@@ -5316,8 +5443,7 @@ const postgresTargetDescriptor = {
5316
5443
  };
5317
5444
  return {
5318
5445
  ok: true,
5319
- descriptors: planResult.value.descriptors,
5320
- needsDataMigration: planResult.value.needsDataMigration
5446
+ descriptors: planResult.value.descriptors
5321
5447
  };
5322
5448
  },
5323
5449
  resolveDescriptors(descriptors, context) {
@@ -5333,6 +5459,9 @@ const postgresTargetDescriptor = {
5333
5459
  dependencies,
5334
5460
  db
5335
5461
  });
5462
+ },
5463
+ renderDescriptorTypeScript(descriptors, context) {
5464
+ return renderDescriptorTypeScript(descriptors, context);
5336
5465
  }
5337
5466
  },
5338
5467
  create() {