@prisma-next/target-postgres 0.5.0-dev.44 → 0.5.0-dev.46

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.
Files changed (53) hide show
  1. package/dist/{codec-ids-CojIXVf9.mjs → codec-ids-ckQX9Kcg.mjs} +3 -2
  2. package/dist/{codec-ids-CojIXVf9.mjs.map → codec-ids-ckQX9Kcg.mjs.map} +1 -1
  3. package/dist/codec-ids.d.mts +2 -1
  4. package/dist/codec-ids.d.mts.map +1 -1
  5. package/dist/codec-ids.mjs +2 -2
  6. package/dist/codec-types.d.mts +1 -1
  7. package/dist/codec-types.mjs +1 -1
  8. package/dist/{codecs-CE5EUsNM.d.mts → codecs-B03dFv94.d.mts} +11 -1
  9. package/dist/codecs-B03dFv94.d.mts.map +1 -0
  10. package/dist/{codecs-dzZ_dMpK.mjs → codecs-D0oXyJIH.mjs} +18 -3
  11. package/dist/codecs-D0oXyJIH.mjs.map +1 -0
  12. package/dist/codecs.d.mts +1 -1
  13. package/dist/codecs.mjs +1 -1
  14. package/dist/control.mjs +6 -56
  15. package/dist/control.mjs.map +1 -1
  16. package/dist/{data-transform-C83dy0vk.mjs → data-transform-Be_i_DBc.mjs} +22 -5
  17. package/dist/data-transform-Be_i_DBc.mjs.map +1 -0
  18. package/dist/{data-transform-D8x5m1YV.d.mts → data-transform-CrpmG4uJ.d.mts} +12 -11
  19. package/dist/data-transform-CrpmG4uJ.d.mts.map +1 -0
  20. package/dist/data-transform.d.mts +1 -1
  21. package/dist/data-transform.mjs +1 -1
  22. package/dist/issue-planner.d.mts +1 -1
  23. package/dist/migration.d.mts +2 -2
  24. package/dist/migration.mjs +2 -2
  25. package/dist/pack.d.mts +1 -1
  26. package/dist/{planner-B4ZSLHRI.mjs → planner-Cm-ZLutk.mjs} +2 -2
  27. package/dist/{planner-B4ZSLHRI.mjs.map → planner-Cm-ZLutk.mjs.map} +1 -1
  28. package/dist/{planner-produced-postgres-migration-C0GNhHGw.mjs → planner-produced-postgres-migration-Bi-RWO4-.mjs} +2 -2
  29. package/dist/{planner-produced-postgres-migration-C0GNhHGw.mjs.map → planner-produced-postgres-migration-Bi-RWO4-.mjs.map} +1 -1
  30. package/dist/{planner-produced-postgres-migration-Dw_mPMKt.d.mts → planner-produced-postgres-migration-M3EfhWSS.d.mts} +2 -2
  31. package/dist/planner-produced-postgres-migration-M3EfhWSS.d.mts.map +1 -0
  32. package/dist/planner-produced-postgres-migration.d.mts +3 -2
  33. package/dist/planner-produced-postgres-migration.mjs +1 -1
  34. package/dist/planner.d.mts +4 -3
  35. package/dist/planner.d.mts.map +1 -1
  36. package/dist/planner.mjs +1 -1
  37. package/dist/{postgres-migration-DcfWGqhe.d.mts → postgres-migration-BFjbb25b.d.mts} +4 -3
  38. package/dist/postgres-migration-BFjbb25b.d.mts.map +1 -0
  39. package/dist/{postgres-migration-EGSlO4jO.mjs → postgres-migration-BS9vQW97.mjs} +2 -2
  40. package/dist/postgres-migration-BS9vQW97.mjs.map +1 -0
  41. package/package.json +16 -16
  42. package/src/core/codec-ids.ts +1 -0
  43. package/src/core/codecs.ts +36 -0
  44. package/src/core/migrations/operations/data-transform.ts +78 -21
  45. package/src/core/migrations/postgres-migration.ts +3 -6
  46. package/src/core/migrations/runner.ts +16 -121
  47. package/dist/codecs-CE5EUsNM.d.mts.map +0 -1
  48. package/dist/codecs-dzZ_dMpK.mjs.map +0 -1
  49. package/dist/data-transform-C83dy0vk.mjs.map +0 -1
  50. package/dist/data-transform-D8x5m1YV.d.mts.map +0 -1
  51. package/dist/planner-produced-postgres-migration-Dw_mPMKt.d.mts.map +0 -1
  52. package/dist/postgres-migration-DcfWGqhe.d.mts.map +0 -1
  53. package/dist/postgres-migration-EGSlO4jO.mjs.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"data-transform-Be_i_DBc.mjs","names":["runClosures: readonly DataTransformClosure[]","precheck: readonly SqlMigrationPlanOperationStep[]","execute: readonly SqlMigrationPlanOperationStep[]","postcheck: readonly SqlMigrationPlanOperationStep[]"],"sources":["../src/core/migrations/operations/data-transform.ts"],"sourcesContent":["/**\n * User-facing `dataTransform` factory for the Postgres migration authoring\n * surface. Invoked directly inside a `migration.ts` file via the\n * `PostgresMigration` instance method (`this.dataTransform(...)`), which\n * supplies the control adapter from the migration's injected stack:\n *\n * ```ts\n * import endContract from './end-contract.json' with { type: 'json' };\n *\n * class M extends Migration {\n * override get operations() {\n * return [\n * this.dataTransform(endContract, 'backfill emails', {\n * check: () => db.users.select('id').where(({ email }) => email.isNull()).limit(1),\n * run: () => db.users.update({ email: '' }).where(({ email }) => email.isNull()),\n * }),\n * ];\n * }\n * }\n * ```\n *\n * The factory accepts lazy closures (`() => SqlQueryPlan | Buildable`),\n * invokes each one, asserts that its `meta.storageHash` matches the\n * `contract` it was handed (→ `PN-MIG-2005` on mismatch), and lowers the\n * plan via the supplied control adapter to a serialized `{sql, params}`\n * payload.\n *\n * The factory then lowers the data transform to the unified migration-op\n * shape `{ precheck, execute, postcheck }`. The user's `check` plan is\n * wrapped twice with opposite truth values:\n *\n * - precheck `SELECT EXISTS (<check>) AS ok` asserts there is work to do\n * (precheck is short-circuited by the runner's pre-satisfied-skip path\n * when nothing remains to backfill).\n * - postcheck `SELECT NOT EXISTS (<check>) AS ok` asserts the work is\n * complete after the run steps execute.\n *\n * The `check` plan is therefore expected to be a **rowset query whose\n * presence of any row signals \"work remains\"** — typically `select('id')\n * .where(<violation predicate>).limit(1)`. Scalar/aggregate shapes\n * (`count(*)`, `bool_and(...)`) do not work under this contract: they\n * always return exactly one row, so `EXISTS` is always true and\n * `NOT EXISTS` is always false. (This is the same row-presence contract\n * the pre-unification runner relied on; the wrapping is just lifting it\n * into SQL.)\n *\n * Each `run` plan becomes an execute step. Because the `Step.params`\n * field threads through `driver.query(sql, params)`, the user's bound\n * values flow through the driver's parameter binder rather than being\n * inlined into the SQL text.\n *\n * The free factory remains usable standalone (tests, ad-hoc tooling,\n * non-class contexts) by passing the adapter explicitly as the fourth\n * argument.\n */\n\nimport type { Contract } from '@prisma-next/contract/types';\nimport { errorDataTransformContractMismatch } from '@prisma-next/errors/migration';\nimport type {\n SqlMigrationPlanOperation,\n SqlMigrationPlanOperationStep,\n} from '@prisma-next/family-sql/control';\nimport type { SqlControlAdapter } from '@prisma-next/family-sql/control-adapter';\nimport type { SerializedQueryPlan } from '@prisma-next/framework-components/control';\nimport type { SqlStorage } from '@prisma-next/sql-contract/types';\nimport type { SqlQueryPlan } from '@prisma-next/sql-relational-core/plan';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport type { PostgresPlanTargetDetails } from '../planner-target-details';\n\ninterface Buildable<R = unknown> {\n build(): SqlQueryPlan<R>;\n}\n\n/**\n * A single-closure producer of a SQL query plan. Shared between\n * `check` and each `run` entry.\n */\nexport type DataTransformClosure = () => SqlQueryPlan | Buildable;\n\nexport interface DataTransformOptions {\n /**\n * Optional opt-in routing identity. Presence opts the transform into\n * invariant-aware routing; absence means it is path-dependent and\n * not referenceable from refs.\n */\n readonly invariantId?: string;\n /**\n * Optional pre-flight query. `undefined` means \"no check\". When\n * supplied, the closure must return a **rowset query** whose\n * presence of any row signals \"violations remain\". Conventional\n * shape: `db.<table>.select('id').where(<violation>).limit(1)`.\n * Scalar/aggregate shapes do not satisfy this contract.\n */\n readonly check?: DataTransformClosure;\n /** One or more mutation queries to execute. */\n readonly run: DataTransformClosure | readonly DataTransformClosure[];\n}\n\nexport function dataTransform<TContract extends Contract<SqlStorage>>(\n contract: TContract,\n name: string,\n options: DataTransformOptions,\n adapter: SqlControlAdapter<'postgres'>,\n): SqlMigrationPlanOperation<PostgresPlanTargetDetails> {\n const runClosures: readonly DataTransformClosure[] = Array.isArray(options.run)\n ? options.run\n : [options.run as DataTransformClosure];\n\n const checkPlan = options.check ? invokeAndLower(options.check, contract, adapter, name) : null;\n const runPlans = runClosures.map((closure) => invokeAndLower(closure, contract, adapter, name));\n\n const precheck: readonly SqlMigrationPlanOperationStep[] = checkPlan\n ? [\n {\n description: `Check ${name} has work to do`,\n sql: `SELECT EXISTS (${checkPlan.sql}) AS ok`,\n params: checkPlan.params,\n },\n ]\n : [];\n\n const execute: readonly SqlMigrationPlanOperationStep[] = runPlans.map((plan) => ({\n description: `Run ${name}`,\n sql: plan.sql,\n params: plan.params,\n }));\n\n const postcheck: readonly SqlMigrationPlanOperationStep[] = checkPlan\n ? [\n {\n description: `Verify ${name} resolved all violations`,\n sql: `SELECT NOT EXISTS (${checkPlan.sql}) AS ok`,\n params: checkPlan.params,\n },\n ]\n : [];\n\n return {\n id: `data_migration.${name}`,\n label: `Data transform: ${name}`,\n operationClass: 'data',\n ...ifDefined('invariantId', options.invariantId),\n target: { id: 'postgres' },\n precheck,\n execute,\n postcheck,\n };\n}\n\nfunction invokeAndLower(\n closure: DataTransformClosure,\n contract: Contract<SqlStorage>,\n adapter: SqlControlAdapter<'postgres'>,\n name: string,\n): SerializedQueryPlan {\n const result = closure();\n const plan = isBuildable(result) ? result.build() : result;\n assertContractMatches(plan, contract, name);\n const lowered = adapter.lower(plan.ast, { contract });\n return { sql: lowered.sql, params: lowered.params };\n}\n\nfunction isBuildable(value: unknown): value is Buildable {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'build' in value &&\n typeof (value as { build: unknown }).build === 'function'\n );\n}\n\nfunction assertContractMatches(\n plan: SqlQueryPlan,\n contract: Contract<SqlStorage>,\n name: string,\n): void {\n if (plan.meta.storageHash !== contract.storage.storageHash) {\n throw errorDataTransformContractMismatch({\n dataTransformName: name,\n expected: contract.storage.storageHash,\n actual: plan.meta.storageHash,\n });\n }\n}\n"],"mappings":";;;;AAkGA,SAAgB,cACd,UACA,MACA,SACA,SACsD;CACtD,MAAMA,cAA+C,MAAM,QAAQ,QAAQ,IAAI,GAC3E,QAAQ,MACR,CAAC,QAAQ,IAA4B;CAEzC,MAAM,YAAY,QAAQ,QAAQ,eAAe,QAAQ,OAAO,UAAU,SAAS,KAAK,GAAG;CAC3F,MAAM,WAAW,YAAY,KAAK,YAAY,eAAe,SAAS,UAAU,SAAS,KAAK,CAAC;CAE/F,MAAMC,WAAqD,YACvD,CACE;EACE,aAAa,SAAS,KAAK;EAC3B,KAAK,kBAAkB,UAAU,IAAI;EACrC,QAAQ,UAAU;EACnB,CACF,GACD,EAAE;CAEN,MAAMC,UAAoD,SAAS,KAAK,UAAU;EAChF,aAAa,OAAO;EACpB,KAAK,KAAK;EACV,QAAQ,KAAK;EACd,EAAE;CAEH,MAAMC,YAAsD,YACxD,CACE;EACE,aAAa,UAAU,KAAK;EAC5B,KAAK,sBAAsB,UAAU,IAAI;EACzC,QAAQ,UAAU;EACnB,CACF,GACD,EAAE;AAEN,QAAO;EACL,IAAI,kBAAkB;EACtB,OAAO,mBAAmB;EAC1B,gBAAgB;EAChB,GAAG,UAAU,eAAe,QAAQ,YAAY;EAChD,QAAQ,EAAE,IAAI,YAAY;EAC1B;EACA;EACA;EACD;;AAGH,SAAS,eACP,SACA,UACA,SACA,MACqB;CACrB,MAAM,SAAS,SAAS;CACxB,MAAM,OAAO,YAAY,OAAO,GAAG,OAAO,OAAO,GAAG;AACpD,uBAAsB,MAAM,UAAU,KAAK;CAC3C,MAAM,UAAU,QAAQ,MAAM,KAAK,KAAK,EAAE,UAAU,CAAC;AACrD,QAAO;EAAE,KAAK,QAAQ;EAAK,QAAQ,QAAQ;EAAQ;;AAGrD,SAAS,YAAY,OAAoC;AACvD,QACE,OAAO,UAAU,YACjB,UAAU,QACV,WAAW,SACX,OAAQ,MAA6B,UAAU;;AAInD,SAAS,sBACP,MACA,UACA,MACM;AACN,KAAI,KAAK,KAAK,gBAAgB,SAAS,QAAQ,YAC7C,OAAM,mCAAmC;EACvC,mBAAmB;EACnB,UAAU,SAAS,QAAQ;EAC3B,QAAQ,KAAK,KAAK;EACnB,CAAC"}
@@ -1,7 +1,8 @@
1
+ import { t as PostgresPlanTargetDetails } from "./planner-target-details-DH-azLu-.mjs";
2
+ import { SqlMigrationPlanOperation } from "@prisma-next/family-sql/control";
1
3
  import { Contract } from "@prisma-next/contract/types";
2
4
  import { SqlStorage } from "@prisma-next/sql-contract/types";
3
5
  import { SqlControlAdapter } from "@prisma-next/family-sql/control-adapter";
4
- import { DataTransformOperation } from "@prisma-next/framework-components/control";
5
6
  import { SqlQueryPlan } from "@prisma-next/sql-relational-core/plan";
6
7
 
7
8
  //#region src/core/migrations/operations/data-transform.d.ts
@@ -21,18 +22,18 @@ interface DataTransformOptions {
21
22
  * not referenceable from refs.
22
23
  */
23
24
  readonly invariantId?: string;
24
- /** Optional pre-flight query. `undefined` means "no check". */
25
+ /**
26
+ * Optional pre-flight query. `undefined` means "no check". When
27
+ * supplied, the closure must return a **rowset query** whose
28
+ * presence of any row signals "violations remain". Conventional
29
+ * shape: `db.<table>.select('id').where(<violation>).limit(1)`.
30
+ * Scalar/aggregate shapes do not satisfy this contract.
31
+ */
25
32
  readonly check?: DataTransformClosure;
26
33
  /** One or more mutation queries to execute. */
27
34
  readonly run: DataTransformClosure | readonly DataTransformClosure[];
28
35
  }
29
- /**
30
- * Concrete Postgres flavor of `DataTransformOperation`, re-exported so the
31
- * `PostgresMigration.dataTransform` instance method can name it without
32
- * leaking the framework-components symbol into call sites.
33
- */
34
- type PostgresDataTransformOperation = DataTransformOperation;
35
- declare function dataTransform<TContract extends Contract<SqlStorage>>(contract: TContract, name: string, options: DataTransformOptions, adapter: SqlControlAdapter<'postgres'>): DataTransformOperation;
36
+ declare function dataTransform<TContract extends Contract<SqlStorage>>(contract: TContract, name: string, options: DataTransformOptions, adapter: SqlControlAdapter<'postgres'>): SqlMigrationPlanOperation<PostgresPlanTargetDetails>;
36
37
  //#endregion
37
- export { dataTransform as i, DataTransformOptions as n, PostgresDataTransformOperation as r, DataTransformClosure as t };
38
- //# sourceMappingURL=data-transform-D8x5m1YV.d.mts.map
38
+ export { DataTransformOptions as n, dataTransform as r, DataTransformClosure as t };
39
+ //# sourceMappingURL=data-transform-CrpmG4uJ.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"data-transform-CrpmG4uJ.d.mts","names":[],"sources":["../src/core/migrations/operations/data-transform.ts"],"sourcesContent":[],"mappings":";;;;;;;;;UAqEU;WACC,aAAa;;;;;;KAOZ,oBAAA,SAA6B,eAAe;UAEvC,oBAAA;;;;;;;;;;;;;;mBAcE;;gBAEH,gCAAgC;;iBAGhC,gCAAgC,SAAS,uBAC7C,kCAED,+BACA,gCACR,0BAA0B"}
@@ -1,2 +1,2 @@
1
- import { i as dataTransform } from "./data-transform-D8x5m1YV.mjs";
1
+ import { r as dataTransform } from "./data-transform-CrpmG4uJ.mjs";
2
2
  export { dataTransform };
@@ -1,3 +1,3 @@
1
- import { t as dataTransform } from "./data-transform-C83dy0vk.mjs";
1
+ import { t as dataTransform } from "./data-transform-Be_i_DBc.mjs";
2
2
 
3
3
  export { dataTransform };
@@ -4,8 +4,8 @@ import { CodecControlHooks, MigrationOperationPolicy, SqlPlannerConflict } from
4
4
  import { Result } from "@prisma-next/utils/result";
5
5
  import { Contract } from "@prisma-next/contract/types";
6
6
  import { SqlStorage, StorageTypeInstance } from "@prisma-next/sql-contract/types";
7
- import { SchemaIssue } from "@prisma-next/framework-components/control";
8
7
  import { TargetBoundComponentDescriptor } from "@prisma-next/framework-components/components";
8
+ import { SchemaIssue } from "@prisma-next/framework-components/control";
9
9
  import { SqlSchemaIR } from "@prisma-next/sql-schema-ir/types";
10
10
 
11
11
  //#region src/core/migrations/planner-strategies.d.ts
@@ -1,6 +1,6 @@
1
- import { i as dataTransform, n as DataTransformOptions, t as DataTransformClosure } from "./data-transform-D8x5m1YV.mjs";
1
+ import { n as DataTransformOptions, r as dataTransform, t as DataTransformClosure } from "./data-transform-CrpmG4uJ.mjs";
2
2
  import { n as ForeignKeySpec, r as Op, t as ColumnSpec } from "./shared-Bxkt8pNO.mjs";
3
- import { t as PostgresMigration } from "./postgres-migration-DcfWGqhe.mjs";
3
+ import { t as PostgresMigration } from "./postgres-migration-BFjbb25b.mjs";
4
4
  import { placeholder } from "@prisma-next/errors/migration";
5
5
  import { MigrationCLI } from "@prisma-next/cli/migration-cli";
6
6
 
@@ -1,6 +1,6 @@
1
1
  import { _ as dropColumn, a as addEnumValues, b as setDefault, c as renameType, d as addForeignKey, f as addPrimaryKey, g as alterColumnType, h as addColumn, i as dropIndex, l as createExtension, m as dropConstraint, n as dropTable, o as createEnumType, p as addUnique, r as createIndex, s as dropEnumType, t as createTable, u as createSchema, v as dropDefault, x as setNotNull, y as dropNotNull } from "./tables-BmdW_FWO.mjs";
2
- import { t as dataTransform } from "./data-transform-C83dy0vk.mjs";
3
- import { t as PostgresMigration } from "./postgres-migration-EGSlO4jO.mjs";
2
+ import { t as dataTransform } from "./data-transform-Be_i_DBc.mjs";
3
+ import { t as PostgresMigration } from "./postgres-migration-BS9vQW97.mjs";
4
4
  import { placeholder } from "@prisma-next/errors/migration";
5
5
  import { MigrationCLI } from "@prisma-next/cli/migration-cli";
6
6
 
package/dist/pack.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { t as CodecTypes } from "./codecs-CE5EUsNM.mjs";
1
+ import { t as CodecTypes } from "./codecs-B03dFv94.mjs";
2
2
 
3
3
  //#region src/core/descriptor-meta.d.ts
4
4
  declare const postgresTargetDescriptorMetaBase: {
@@ -1,7 +1,7 @@
1
1
  import { t as parsePostgresDefault } from "./default-normalizer-DNOpRoOF.mjs";
2
2
  import { t as normalizeSchemaNativeType } from "./native-type-normalizer-CInai_oY.mjs";
3
3
  import { n as postgresPlannerStrategies, t as planIssues } from "./issue-planner-CFjB0_oO.mjs";
4
- import { t as TypeScriptRenderablePostgresMigration } from "./planner-produced-postgres-migration-C0GNhHGw.mjs";
4
+ import { t as TypeScriptRenderablePostgresMigration } from "./planner-produced-postgres-migration-Bi-RWO4-.mjs";
5
5
  import { extractCodecControlHooks, plannerFailure } from "@prisma-next/family-sql/control";
6
6
  import { verifySqlSchema } from "@prisma-next/family-sql/schema-verify";
7
7
 
@@ -95,4 +95,4 @@ var PostgresMigrationPlanner = class {
95
95
 
96
96
  //#endregion
97
97
  export { createPostgresMigrationPlanner as t };
98
- //# sourceMappingURL=planner-B4ZSLHRI.mjs.map
98
+ //# sourceMappingURL=planner-Cm-ZLutk.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"planner-B4ZSLHRI.mjs","names":["DEFAULT_PLANNER_CONFIG: PlannerConfig","config: PlannerConfig"],"sources":["../src/core/migrations/planner.ts"],"sourcesContent":["import type { Contract } from '@prisma-next/contract/types';\nimport type {\n MigrationOperationPolicy,\n SqlMigrationPlannerPlanOptions,\n SqlPlannerFailureResult,\n} from '@prisma-next/family-sql/control';\nimport { extractCodecControlHooks, plannerFailure } from '@prisma-next/family-sql/control';\nimport { verifySqlSchema } from '@prisma-next/family-sql/schema-verify';\nimport type { TargetBoundComponentDescriptor } from '@prisma-next/framework-components/components';\nimport type {\n MigrationPlanner,\n MigrationPlanWithAuthoringSurface,\n MigrationScaffoldContext,\n SchemaIssue,\n} from '@prisma-next/framework-components/control';\nimport { parsePostgresDefault } from '../default-normalizer';\nimport { normalizeSchemaNativeType } from '../native-type-normalizer';\nimport { planIssues } from './issue-planner';\nimport { TypeScriptRenderablePostgresMigration } from './planner-produced-postgres-migration';\nimport { postgresPlannerStrategies } from './planner-strategies';\n\ntype PlannerFrameworkComponents = SqlMigrationPlannerPlanOptions extends {\n readonly frameworkComponents: infer T;\n}\n ? T\n : ReadonlyArray<unknown>;\n\ntype PlannerOptionsWithComponents = SqlMigrationPlannerPlanOptions & {\n readonly frameworkComponents: PlannerFrameworkComponents;\n};\n\ntype VerifySqlSchemaOptionsWithComponents = Parameters<typeof verifySqlSchema>[0] & {\n readonly frameworkComponents: PlannerFrameworkComponents;\n};\n\ninterface PlannerConfig {\n readonly defaultSchema: string;\n}\n\nconst DEFAULT_PLANNER_CONFIG: PlannerConfig = {\n defaultSchema: 'public',\n};\n\nexport function createPostgresMigrationPlanner(\n config: Partial<PlannerConfig> = {},\n): PostgresMigrationPlanner {\n return new PostgresMigrationPlanner({\n ...DEFAULT_PLANNER_CONFIG,\n ...config,\n });\n}\n\n/**\n * Result of `PostgresMigrationPlanner.plan()`. A discriminated union whose\n * success variant carries a `TypeScriptRenderablePostgresMigration` — a\n * migration object that both the CLI (via `renderTypeScript()`) and the\n * SQL-typed callers (via `operations`, `describe()`, etc.) consume\n * uniformly.\n */\nexport type PostgresPlanResult =\n | { readonly kind: 'success'; readonly plan: TypeScriptRenderablePostgresMigration }\n | SqlPlannerFailureResult;\n\n/**\n * Postgres migration planner — a thin wrapper over `planIssues`.\n *\n * `plan()` verifies the live schema against the target contract (producing\n * `SchemaIssue[]`) and delegates to `planIssues` with the unified\n * `postgresPlannerStrategies` list: enum-change, NOT-NULL backfill,\n * type-change, nullable-tightening, codec-hook storage types,\n * component-declared dependency installs, and shared-temp-default /\n * empty-table-guarded NOT-NULL add-column. The same strategy list runs for\n * `migration plan`, `db update`, and `db init`; behavior diverges purely on\n * `policy.allowedOperationClasses` (the data-safe strategies short-circuit\n * when `'data'` is excluded). The issue planner applies operation-class\n * policy gates and emits a single `PostgresOpFactoryCall[]` that drives both\n * the runtime-ops view (via `renderOps`) and the `renderTypeScript()`\n * authoring surface.\n */\nexport class PostgresMigrationPlanner implements MigrationPlanner<'sql', 'postgres'> {\n constructor(private readonly config: PlannerConfig) {}\n\n plan(options: {\n readonly contract: unknown;\n readonly schema: unknown;\n readonly policy: MigrationOperationPolicy;\n /**\n * The \"from\" contract (state the planner assumes the database starts\n * at), or `null` for reconciliation flows. Only `migration plan` ever\n * supplies a non-null value; `db update` / `db init` reconcile against\n * the live schema and pass `null`. When present alongside the\n * `'data'` operation class, strategies that need from/to column-shape\n * comparisons (unsafe type change, nullability tightening) activate.\n *\n * Typed as the framework `Contract | null` to satisfy the\n * `MigrationPlanner` interface contract; `planSql` narrows to the SQL\n * shape via `SqlMigrationPlannerPlanOptions`. Used to populate\n * `describe().from` on the produced plan as\n * `fromContract?.storage.storageHash ?? null`.\n */\n readonly fromContract: Contract | null;\n readonly schemaName?: string;\n readonly frameworkComponents: ReadonlyArray<TargetBoundComponentDescriptor<'sql', string>>;\n }): PostgresPlanResult {\n return this.planSql(options as SqlMigrationPlannerPlanOptions);\n }\n\n emptyMigration(context: MigrationScaffoldContext): MigrationPlanWithAuthoringSurface {\n return new TypeScriptRenderablePostgresMigration([], {\n from: context.fromHash,\n to: context.toHash,\n });\n }\n\n private planSql(options: SqlMigrationPlannerPlanOptions): PostgresPlanResult {\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 schemaIssues = this.collectSchemaIssues(options);\n const codecHooks = extractCodecControlHooks(options.frameworkComponents);\n const storageTypes = options.contract.storage.types ?? {};\n\n const result = planIssues({\n issues: schemaIssues,\n toContract: options.contract,\n // `fromContract` is only supplied by `migration plan`. It is `null` for\n // `db update` / `db init`, which means data-safety strategies needing\n // from/to comparisons (unsafe type change, nullable tightening) are\n // inapplicable there — reconciliation falls through to\n // `mapIssueToCall`'s direct destructive handlers.\n fromContract: options.fromContract,\n schemaName,\n codecHooks,\n storageTypes,\n schema: options.schema,\n policy: options.policy,\n frameworkComponents: options.frameworkComponents,\n strategies: postgresPlannerStrategies,\n });\n\n if (!result.ok) {\n return plannerFailure(result.failure);\n }\n\n return Object.freeze({\n kind: 'success' as const,\n plan: new TypeScriptRenderablePostgresMigration(result.value.calls, {\n from: options.fromContract?.storage.storageHash ?? null,\n to: options.contract.storage.storageHash,\n }),\n });\n }\n\n private ensureAdditivePolicy(policy: MigrationOperationPolicy) {\n if (!policy.allowedOperationClasses.includes('additive')) {\n return plannerFailure([\n {\n kind: 'unsupportedOperation',\n summary: 'Migration planner requires additive operations be allowed',\n why: 'The planner requires the \"additive\" operation class to be allowed in the policy.',\n },\n ]);\n }\n return null;\n }\n\n private collectSchemaIssues(options: PlannerOptionsWithComponents): readonly SchemaIssue[] {\n // `db init` uses additive-only policy and intentionally ignores extra\n // schema objects. Any reconciliation-capable policy (widening or\n // destructive) must inspect extras to reconcile strict equality.\n const allowed = options.policy.allowedOperationClasses;\n const strict = allowed.includes('widening') || allowed.includes('destructive');\n const verifyOptions: VerifySqlSchemaOptionsWithComponents = {\n contract: options.contract,\n schema: options.schema,\n strict,\n typeMetadataRegistry: new Map(),\n frameworkComponents: options.frameworkComponents,\n normalizeDefault: parsePostgresDefault,\n normalizeNativeType: normalizeSchemaNativeType,\n };\n const verifyResult = verifySqlSchema(verifyOptions);\n return verifyResult.schema.issues;\n }\n}\n"],"mappings":";;;;;;;;AAuCA,MAAMA,yBAAwC,EAC5C,eAAe,UAChB;AAED,SAAgB,+BACd,SAAiC,EAAE,EACT;AAC1B,QAAO,IAAI,yBAAyB;EAClC,GAAG;EACH,GAAG;EACJ,CAAC;;;;;;;;;;;;;;;;;;AA8BJ,IAAa,2BAAb,MAAqF;CACnF,YAAY,AAAiBC,QAAuB;EAAvB;;CAE7B,KAAK,SAqBkB;AACrB,SAAO,KAAK,QAAQ,QAA0C;;CAGhE,eAAe,SAAsE;AACnF,SAAO,IAAI,sCAAsC,EAAE,EAAE;GACnD,MAAM,QAAQ;GACd,IAAI,QAAQ;GACb,CAAC;;CAGJ,AAAQ,QAAQ,SAA6D;EAC3E,MAAM,aAAa,QAAQ,cAAc,KAAK,OAAO;EACrD,MAAM,eAAe,KAAK,qBAAqB,QAAQ,OAAO;AAC9D,MAAI,aACF,QAAO;EAGT,MAAM,eAAe,KAAK,oBAAoB,QAAQ;EACtD,MAAM,aAAa,yBAAyB,QAAQ,oBAAoB;EACxE,MAAM,eAAe,QAAQ,SAAS,QAAQ,SAAS,EAAE;EAEzD,MAAM,SAAS,WAAW;GACxB,QAAQ;GACR,YAAY,QAAQ;GAMpB,cAAc,QAAQ;GACtB;GACA;GACA;GACA,QAAQ,QAAQ;GAChB,QAAQ,QAAQ;GAChB,qBAAqB,QAAQ;GAC7B,YAAY;GACb,CAAC;AAEF,MAAI,CAAC,OAAO,GACV,QAAO,eAAe,OAAO,QAAQ;AAGvC,SAAO,OAAO,OAAO;GACnB,MAAM;GACN,MAAM,IAAI,sCAAsC,OAAO,MAAM,OAAO;IAClE,MAAM,QAAQ,cAAc,QAAQ,eAAe;IACnD,IAAI,QAAQ,SAAS,QAAQ;IAC9B,CAAC;GACH,CAAC;;CAGJ,AAAQ,qBAAqB,QAAkC;AAC7D,MAAI,CAAC,OAAO,wBAAwB,SAAS,WAAW,CACtD,QAAO,eAAe,CACpB;GACE,MAAM;GACN,SAAS;GACT,KAAK;GACN,CACF,CAAC;AAEJ,SAAO;;CAGT,AAAQ,oBAAoB,SAA+D;EAIzF,MAAM,UAAU,QAAQ,OAAO;EAC/B,MAAM,SAAS,QAAQ,SAAS,WAAW,IAAI,QAAQ,SAAS,cAAc;AAW9E,SADqB,gBATuC;GAC1D,UAAU,QAAQ;GAClB,QAAQ,QAAQ;GAChB;GACA,sCAAsB,IAAI,KAAK;GAC/B,qBAAqB,QAAQ;GAC7B,kBAAkB;GAClB,qBAAqB;GACtB,CACkD,CAC/B,OAAO"}
1
+ {"version":3,"file":"planner-Cm-ZLutk.mjs","names":["DEFAULT_PLANNER_CONFIG: PlannerConfig","config: PlannerConfig"],"sources":["../src/core/migrations/planner.ts"],"sourcesContent":["import type { Contract } from '@prisma-next/contract/types';\nimport type {\n MigrationOperationPolicy,\n SqlMigrationPlannerPlanOptions,\n SqlPlannerFailureResult,\n} from '@prisma-next/family-sql/control';\nimport { extractCodecControlHooks, plannerFailure } from '@prisma-next/family-sql/control';\nimport { verifySqlSchema } from '@prisma-next/family-sql/schema-verify';\nimport type { TargetBoundComponentDescriptor } from '@prisma-next/framework-components/components';\nimport type {\n MigrationPlanner,\n MigrationPlanWithAuthoringSurface,\n MigrationScaffoldContext,\n SchemaIssue,\n} from '@prisma-next/framework-components/control';\nimport { parsePostgresDefault } from '../default-normalizer';\nimport { normalizeSchemaNativeType } from '../native-type-normalizer';\nimport { planIssues } from './issue-planner';\nimport { TypeScriptRenderablePostgresMigration } from './planner-produced-postgres-migration';\nimport { postgresPlannerStrategies } from './planner-strategies';\n\ntype PlannerFrameworkComponents = SqlMigrationPlannerPlanOptions extends {\n readonly frameworkComponents: infer T;\n}\n ? T\n : ReadonlyArray<unknown>;\n\ntype PlannerOptionsWithComponents = SqlMigrationPlannerPlanOptions & {\n readonly frameworkComponents: PlannerFrameworkComponents;\n};\n\ntype VerifySqlSchemaOptionsWithComponents = Parameters<typeof verifySqlSchema>[0] & {\n readonly frameworkComponents: PlannerFrameworkComponents;\n};\n\ninterface PlannerConfig {\n readonly defaultSchema: string;\n}\n\nconst DEFAULT_PLANNER_CONFIG: PlannerConfig = {\n defaultSchema: 'public',\n};\n\nexport function createPostgresMigrationPlanner(\n config: Partial<PlannerConfig> = {},\n): PostgresMigrationPlanner {\n return new PostgresMigrationPlanner({\n ...DEFAULT_PLANNER_CONFIG,\n ...config,\n });\n}\n\n/**\n * Result of `PostgresMigrationPlanner.plan()`. A discriminated union whose\n * success variant carries a `TypeScriptRenderablePostgresMigration` — a\n * migration object that both the CLI (via `renderTypeScript()`) and the\n * SQL-typed callers (via `operations`, `describe()`, etc.) consume\n * uniformly.\n */\nexport type PostgresPlanResult =\n | { readonly kind: 'success'; readonly plan: TypeScriptRenderablePostgresMigration }\n | SqlPlannerFailureResult;\n\n/**\n * Postgres migration planner — a thin wrapper over `planIssues`.\n *\n * `plan()` verifies the live schema against the target contract (producing\n * `SchemaIssue[]`) and delegates to `planIssues` with the unified\n * `postgresPlannerStrategies` list: enum-change, NOT-NULL backfill,\n * type-change, nullable-tightening, codec-hook storage types,\n * component-declared dependency installs, and shared-temp-default /\n * empty-table-guarded NOT-NULL add-column. The same strategy list runs for\n * `migration plan`, `db update`, and `db init`; behavior diverges purely on\n * `policy.allowedOperationClasses` (the data-safe strategies short-circuit\n * when `'data'` is excluded). The issue planner applies operation-class\n * policy gates and emits a single `PostgresOpFactoryCall[]` that drives both\n * the runtime-ops view (via `renderOps`) and the `renderTypeScript()`\n * authoring surface.\n */\nexport class PostgresMigrationPlanner implements MigrationPlanner<'sql', 'postgres'> {\n constructor(private readonly config: PlannerConfig) {}\n\n plan(options: {\n readonly contract: unknown;\n readonly schema: unknown;\n readonly policy: MigrationOperationPolicy;\n /**\n * The \"from\" contract (state the planner assumes the database starts\n * at), or `null` for reconciliation flows. Only `migration plan` ever\n * supplies a non-null value; `db update` / `db init` reconcile against\n * the live schema and pass `null`. When present alongside the\n * `'data'` operation class, strategies that need from/to column-shape\n * comparisons (unsafe type change, nullability tightening) activate.\n *\n * Typed as the framework `Contract | null` to satisfy the\n * `MigrationPlanner` interface contract; `planSql` narrows to the SQL\n * shape via `SqlMigrationPlannerPlanOptions`. Used to populate\n * `describe().from` on the produced plan as\n * `fromContract?.storage.storageHash ?? null`.\n */\n readonly fromContract: Contract | null;\n readonly schemaName?: string;\n readonly frameworkComponents: ReadonlyArray<TargetBoundComponentDescriptor<'sql', string>>;\n }): PostgresPlanResult {\n return this.planSql(options as SqlMigrationPlannerPlanOptions);\n }\n\n emptyMigration(context: MigrationScaffoldContext): MigrationPlanWithAuthoringSurface {\n return new TypeScriptRenderablePostgresMigration([], {\n from: context.fromHash,\n to: context.toHash,\n });\n }\n\n private planSql(options: SqlMigrationPlannerPlanOptions): PostgresPlanResult {\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 schemaIssues = this.collectSchemaIssues(options);\n const codecHooks = extractCodecControlHooks(options.frameworkComponents);\n const storageTypes = options.contract.storage.types ?? {};\n\n const result = planIssues({\n issues: schemaIssues,\n toContract: options.contract,\n // `fromContract` is only supplied by `migration plan`. It is `null` for\n // `db update` / `db init`, which means data-safety strategies needing\n // from/to comparisons (unsafe type change, nullable tightening) are\n // inapplicable there — reconciliation falls through to\n // `mapIssueToCall`'s direct destructive handlers.\n fromContract: options.fromContract,\n schemaName,\n codecHooks,\n storageTypes,\n schema: options.schema,\n policy: options.policy,\n frameworkComponents: options.frameworkComponents,\n strategies: postgresPlannerStrategies,\n });\n\n if (!result.ok) {\n return plannerFailure(result.failure);\n }\n\n return Object.freeze({\n kind: 'success' as const,\n plan: new TypeScriptRenderablePostgresMigration(result.value.calls, {\n from: options.fromContract?.storage.storageHash ?? null,\n to: options.contract.storage.storageHash,\n }),\n });\n }\n\n private ensureAdditivePolicy(policy: MigrationOperationPolicy) {\n if (!policy.allowedOperationClasses.includes('additive')) {\n return plannerFailure([\n {\n kind: 'unsupportedOperation',\n summary: 'Migration planner requires additive operations be allowed',\n why: 'The planner requires the \"additive\" operation class to be allowed in the policy.',\n },\n ]);\n }\n return null;\n }\n\n private collectSchemaIssues(options: PlannerOptionsWithComponents): readonly SchemaIssue[] {\n // `db init` uses additive-only policy and intentionally ignores extra\n // schema objects. Any reconciliation-capable policy (widening or\n // destructive) must inspect extras to reconcile strict equality.\n const allowed = options.policy.allowedOperationClasses;\n const strict = allowed.includes('widening') || allowed.includes('destructive');\n const verifyOptions: VerifySqlSchemaOptionsWithComponents = {\n contract: options.contract,\n schema: options.schema,\n strict,\n typeMetadataRegistry: new Map(),\n frameworkComponents: options.frameworkComponents,\n normalizeDefault: parsePostgresDefault,\n normalizeNativeType: normalizeSchemaNativeType,\n };\n const verifyResult = verifySqlSchema(verifyOptions);\n return verifyResult.schema.issues;\n }\n}\n"],"mappings":";;;;;;;;AAuCA,MAAMA,yBAAwC,EAC5C,eAAe,UAChB;AAED,SAAgB,+BACd,SAAiC,EAAE,EACT;AAC1B,QAAO,IAAI,yBAAyB;EAClC,GAAG;EACH,GAAG;EACJ,CAAC;;;;;;;;;;;;;;;;;;AA8BJ,IAAa,2BAAb,MAAqF;CACnF,YAAY,AAAiBC,QAAuB;EAAvB;;CAE7B,KAAK,SAqBkB;AACrB,SAAO,KAAK,QAAQ,QAA0C;;CAGhE,eAAe,SAAsE;AACnF,SAAO,IAAI,sCAAsC,EAAE,EAAE;GACnD,MAAM,QAAQ;GACd,IAAI,QAAQ;GACb,CAAC;;CAGJ,AAAQ,QAAQ,SAA6D;EAC3E,MAAM,aAAa,QAAQ,cAAc,KAAK,OAAO;EACrD,MAAM,eAAe,KAAK,qBAAqB,QAAQ,OAAO;AAC9D,MAAI,aACF,QAAO;EAGT,MAAM,eAAe,KAAK,oBAAoB,QAAQ;EACtD,MAAM,aAAa,yBAAyB,QAAQ,oBAAoB;EACxE,MAAM,eAAe,QAAQ,SAAS,QAAQ,SAAS,EAAE;EAEzD,MAAM,SAAS,WAAW;GACxB,QAAQ;GACR,YAAY,QAAQ;GAMpB,cAAc,QAAQ;GACtB;GACA;GACA;GACA,QAAQ,QAAQ;GAChB,QAAQ,QAAQ;GAChB,qBAAqB,QAAQ;GAC7B,YAAY;GACb,CAAC;AAEF,MAAI,CAAC,OAAO,GACV,QAAO,eAAe,OAAO,QAAQ;AAGvC,SAAO,OAAO,OAAO;GACnB,MAAM;GACN,MAAM,IAAI,sCAAsC,OAAO,MAAM,OAAO;IAClE,MAAM,QAAQ,cAAc,QAAQ,eAAe;IACnD,IAAI,QAAQ,SAAS,QAAQ;IAC9B,CAAC;GACH,CAAC;;CAGJ,AAAQ,qBAAqB,QAAkC;AAC7D,MAAI,CAAC,OAAO,wBAAwB,SAAS,WAAW,CACtD,QAAO,eAAe,CACpB;GACE,MAAM;GACN,SAAS;GACT,KAAK;GACN,CACF,CAAC;AAEJ,SAAO;;CAGT,AAAQ,oBAAoB,SAA+D;EAIzF,MAAM,UAAU,QAAQ,OAAO;EAC/B,MAAM,SAAS,QAAQ,SAAS,WAAW,IAAI,QAAQ,SAAS,cAAc;AAW9E,SADqB,gBATuC;GAC1D,UAAU,QAAQ;GAClB,QAAQ,QAAQ;GAChB;GACA,sCAAsB,IAAI,KAAK;GAC/B,qBAAqB,QAAQ;GAC7B,kBAAkB;GAClB,qBAAqB;GACtB,CACkD,CAC/B,OAAO"}
@@ -1,4 +1,4 @@
1
- import { t as PostgresMigration } from "./postgres-migration-EGSlO4jO.mjs";
1
+ import { t as PostgresMigration } from "./postgres-migration-BS9vQW97.mjs";
2
2
  import { t as renderOps } from "./render-ops-D6_DHdOK.mjs";
3
3
  import { t as renderCallsToTypeScript } from "./render-typescript-Co3Emwgz.mjs";
4
4
  import { ifDefined } from "@prisma-next/utils/defined";
@@ -29,4 +29,4 @@ var TypeScriptRenderablePostgresMigration = class extends PostgresMigration {
29
29
 
30
30
  //#endregion
31
31
  export { TypeScriptRenderablePostgresMigration as t };
32
- //# sourceMappingURL=planner-produced-postgres-migration-C0GNhHGw.mjs.map
32
+ //# sourceMappingURL=planner-produced-postgres-migration-Bi-RWO4-.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"planner-produced-postgres-migration-C0GNhHGw.mjs","names":["#calls","#meta"],"sources":["../src/core/migrations/planner-produced-postgres-migration.ts"],"sourcesContent":["/**\n * Planner-produced Postgres migration.\n *\n * Returned by `PostgresMigrationPlanner.plan(...)` and `emptyMigration(...)`.\n * Holds the migration IR (`PostgresOpFactoryCall[]`) alongside\n * `MigrationMeta` and exposes both the runtime-ops view (`get operations`)\n * and the TypeScript authoring view (`renderTypeScript()`). Satisfies\n * `MigrationPlanWithAuthoringSurface` so the CLI can uniformly serialize any\n * planner result back to `migration.ts`.\n *\n * Extends the family-level `SqlMigration` alias rather than the target-local\n * migration base directly — mirrors Mongo's `PlannerProducedMongoMigration`\n * shape and keeps CLI wiring one step removed from target internals.\n *\n * Placeholder-bearing plans: `renderTypeScript()` always succeeds and embeds\n * `() => placeholder(\"slot\")` at each stub. `operations`, in contrast, is\n * _not safe to enumerate_ on a stub-bearing plan — `DataTransformCall.toOp()`\n * throws `PN-MIG-2001` because a planner-stubbed closure cannot be lowered\n * to a runtime op. Callers that know a plan may carry stubs must render to\n * `migration.ts`, let the user fill the slots, and re-load the edited\n * migration before enumerating ops. The walk-schema planner does not emit\n * `DataTransformCall`s today, so this asymmetry is invisible until the\n * issue-planner integration lands in Phase 2.\n */\n\nimport type { SqlMigrationPlanOperation } from '@prisma-next/family-sql/control';\nimport type { MigrationPlanWithAuthoringSurface } from '@prisma-next/framework-components/control';\nimport type { MigrationMeta } from '@prisma-next/migration-tools/migration';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport type { PostgresOpFactoryCall } from './op-factory-call';\nimport type { PostgresPlanTargetDetails } from './planner-target-details';\nimport { PostgresMigration } from './postgres-migration';\nimport { renderOps } from './render-ops';\nimport { renderCallsToTypeScript } from './render-typescript';\n\ntype Op = SqlMigrationPlanOperation<PostgresPlanTargetDetails>;\n\nexport class TypeScriptRenderablePostgresMigration\n extends PostgresMigration\n implements MigrationPlanWithAuthoringSurface\n{\n readonly #calls: readonly PostgresOpFactoryCall[];\n readonly #meta: MigrationMeta;\n\n constructor(calls: readonly PostgresOpFactoryCall[], meta: MigrationMeta) {\n super();\n this.#calls = calls;\n this.#meta = meta;\n }\n\n override get operations(): readonly Op[] {\n return renderOps(this.#calls);\n }\n\n override describe(): MigrationMeta {\n return this.#meta;\n }\n\n renderTypeScript(): string {\n return renderCallsToTypeScript(this.#calls, {\n from: this.#meta.from,\n to: this.#meta.to,\n ...ifDefined('labels', this.#meta.labels),\n });\n }\n}\n"],"mappings":";;;;;;AAqCA,IAAa,wCAAb,cACU,kBAEV;CACE,CAASA;CACT,CAASC;CAET,YAAY,OAAyC,MAAqB;AACxE,SAAO;AACP,QAAKD,QAAS;AACd,QAAKC,OAAQ;;CAGf,IAAa,aAA4B;AACvC,SAAO,UAAU,MAAKD,MAAO;;CAG/B,AAAS,WAA0B;AACjC,SAAO,MAAKC;;CAGd,mBAA2B;AACzB,SAAO,wBAAwB,MAAKD,OAAQ;GAC1C,MAAM,MAAKC,KAAM;GACjB,IAAI,MAAKA,KAAM;GACf,GAAG,UAAU,UAAU,MAAKA,KAAM,OAAO;GAC1C,CAAC"}
1
+ {"version":3,"file":"planner-produced-postgres-migration-Bi-RWO4-.mjs","names":["#calls","#meta"],"sources":["../src/core/migrations/planner-produced-postgres-migration.ts"],"sourcesContent":["/**\n * Planner-produced Postgres migration.\n *\n * Returned by `PostgresMigrationPlanner.plan(...)` and `emptyMigration(...)`.\n * Holds the migration IR (`PostgresOpFactoryCall[]`) alongside\n * `MigrationMeta` and exposes both the runtime-ops view (`get operations`)\n * and the TypeScript authoring view (`renderTypeScript()`). Satisfies\n * `MigrationPlanWithAuthoringSurface` so the CLI can uniformly serialize any\n * planner result back to `migration.ts`.\n *\n * Extends the family-level `SqlMigration` alias rather than the target-local\n * migration base directly — mirrors Mongo's `PlannerProducedMongoMigration`\n * shape and keeps CLI wiring one step removed from target internals.\n *\n * Placeholder-bearing plans: `renderTypeScript()` always succeeds and embeds\n * `() => placeholder(\"slot\")` at each stub. `operations`, in contrast, is\n * _not safe to enumerate_ on a stub-bearing plan — `DataTransformCall.toOp()`\n * throws `PN-MIG-2001` because a planner-stubbed closure cannot be lowered\n * to a runtime op. Callers that know a plan may carry stubs must render to\n * `migration.ts`, let the user fill the slots, and re-load the edited\n * migration before enumerating ops. The walk-schema planner does not emit\n * `DataTransformCall`s today, so this asymmetry is invisible until the\n * issue-planner integration lands in Phase 2.\n */\n\nimport type { SqlMigrationPlanOperation } from '@prisma-next/family-sql/control';\nimport type { MigrationPlanWithAuthoringSurface } from '@prisma-next/framework-components/control';\nimport type { MigrationMeta } from '@prisma-next/migration-tools/migration';\nimport { ifDefined } from '@prisma-next/utils/defined';\nimport type { PostgresOpFactoryCall } from './op-factory-call';\nimport type { PostgresPlanTargetDetails } from './planner-target-details';\nimport { PostgresMigration } from './postgres-migration';\nimport { renderOps } from './render-ops';\nimport { renderCallsToTypeScript } from './render-typescript';\n\ntype Op = SqlMigrationPlanOperation<PostgresPlanTargetDetails>;\n\nexport class TypeScriptRenderablePostgresMigration\n extends PostgresMigration\n implements MigrationPlanWithAuthoringSurface\n{\n readonly #calls: readonly PostgresOpFactoryCall[];\n readonly #meta: MigrationMeta;\n\n constructor(calls: readonly PostgresOpFactoryCall[], meta: MigrationMeta) {\n super();\n this.#calls = calls;\n this.#meta = meta;\n }\n\n override get operations(): readonly Op[] {\n return renderOps(this.#calls);\n }\n\n override describe(): MigrationMeta {\n return this.#meta;\n }\n\n renderTypeScript(): string {\n return renderCallsToTypeScript(this.#calls, {\n from: this.#meta.from,\n to: this.#meta.to,\n ...ifDefined('labels', this.#meta.labels),\n });\n }\n}\n"],"mappings":";;;;;;AAqCA,IAAa,wCAAb,cACU,kBAEV;CACE,CAASA;CACT,CAASC;CAET,YAAY,OAAyC,MAAqB;AACxE,SAAO;AACP,QAAKD,QAAS;AACd,QAAKC,OAAQ;;CAGf,IAAa,aAA4B;AACvC,SAAO,UAAU,MAAKD,MAAO;;CAG/B,AAAS,WAA0B;AACjC,SAAO,MAAKC;;CAGd,mBAA2B;AACzB,SAAO,wBAAwB,MAAKD,OAAQ;GAC1C,MAAM,MAAKC,KAAM;GACjB,IAAI,MAAKA,KAAM;GACf,GAAG,UAAU,UAAU,MAAKA,KAAM,OAAO;GAC1C,CAAC"}
@@ -1,6 +1,6 @@
1
1
  import { t as PostgresPlanTargetDetails } from "./planner-target-details-DH-azLu-.mjs";
2
2
  import { b as PostgresOpFactoryCall } from "./op-factory-call-C3bWXKSP.mjs";
3
- import { t as PostgresMigration } from "./postgres-migration-DcfWGqhe.mjs";
3
+ import { t as PostgresMigration } from "./postgres-migration-BFjbb25b.mjs";
4
4
  import { SqlMigrationPlanOperation } from "@prisma-next/family-sql/control";
5
5
  import { MigrationPlanWithAuthoringSurface } from "@prisma-next/framework-components/control";
6
6
  import { MigrationMeta } from "@prisma-next/migration-tools/migration";
@@ -17,4 +17,4 @@ declare class TypeScriptRenderablePostgresMigration extends PostgresMigration im
17
17
  }
18
18
  //#endregion
19
19
  export { TypeScriptRenderablePostgresMigration as t };
20
- //# sourceMappingURL=planner-produced-postgres-migration-Dw_mPMKt.d.mts.map
20
+ //# sourceMappingURL=planner-produced-postgres-migration-M3EfhWSS.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"planner-produced-postgres-migration-M3EfhWSS.d.mts","names":[],"sources":["../src/core/migrations/planner-produced-postgres-migration.ts"],"sourcesContent":[],"mappings":";;;;;;;;;KAmCK,EAAA,GAAK,0BAA0B;cAEvB,qCAAA,SACH,iBAAA,YACG;;8BAKiB,+BAA+B;6BAMvB;cAIf"}
@@ -1,5 +1,6 @@
1
+ import "./data-transform-CrpmG4uJ.mjs";
1
2
  import "./shared-Bxkt8pNO.mjs";
2
3
  import "./op-factory-call-C3bWXKSP.mjs";
3
- import "./postgres-migration-DcfWGqhe.mjs";
4
- import { t as TypeScriptRenderablePostgresMigration } from "./planner-produced-postgres-migration-Dw_mPMKt.mjs";
4
+ import "./postgres-migration-BFjbb25b.mjs";
5
+ import { t as TypeScriptRenderablePostgresMigration } from "./planner-produced-postgres-migration-M3EfhWSS.mjs";
5
6
  export { TypeScriptRenderablePostgresMigration };
@@ -1,3 +1,3 @@
1
- import { t as TypeScriptRenderablePostgresMigration } from "./planner-produced-postgres-migration-C0GNhHGw.mjs";
1
+ import { t as TypeScriptRenderablePostgresMigration } from "./planner-produced-postgres-migration-Bi-RWO4-.mjs";
2
2
 
3
3
  export { TypeScriptRenderablePostgresMigration };
@@ -1,11 +1,12 @@
1
+ import "./data-transform-CrpmG4uJ.mjs";
1
2
  import "./shared-Bxkt8pNO.mjs";
2
3
  import "./op-factory-call-C3bWXKSP.mjs";
3
- import "./postgres-migration-DcfWGqhe.mjs";
4
- import { t as TypeScriptRenderablePostgresMigration } from "./planner-produced-postgres-migration-Dw_mPMKt.mjs";
4
+ import "./postgres-migration-BFjbb25b.mjs";
5
+ import { t as TypeScriptRenderablePostgresMigration } from "./planner-produced-postgres-migration-M3EfhWSS.mjs";
5
6
  import { MigrationOperationPolicy, SqlPlannerFailureResult } from "@prisma-next/family-sql/control";
6
7
  import { Contract } from "@prisma-next/contract/types";
7
- import { MigrationPlanWithAuthoringSurface, MigrationPlanner, MigrationScaffoldContext } from "@prisma-next/framework-components/control";
8
8
  import { TargetBoundComponentDescriptor } from "@prisma-next/framework-components/components";
9
+ import { MigrationPlanWithAuthoringSurface, MigrationPlanner, MigrationScaffoldContext } from "@prisma-next/framework-components/control";
9
10
 
10
11
  //#region src/core/migrations/planner.d.ts
11
12
  interface PlannerConfig {
@@ -1 +1 @@
1
- {"version":3,"file":"planner.d.mts","names":[],"sources":["../src/core/migrations/planner.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;UAmCU,aAAA;;;iBAQM,8BAAA,UACN,QAAQ,iBACf;;AA3B2F;AAyB9F;;;;;AAgBY,KAAA,kBAAA,GAAkB;EAoBjB,SAAA,IAAA,EAAA,SAAA;EAC0B,SAAA,IAAA,EApBQ,qCAoBR;CAKlB,GAxBjB,uBAwBiB;;;;;;;;;;;;;;;;;cANR,wBAAA,YAAoC;;sBACV;;;;qBAKlB;;;;;;;;;;;;;;;2BAeM;;kCAEO,cAAc;MAC1C;0BAIoB,2BAA2B"}
1
+ {"version":3,"file":"planner.d.mts","names":[],"sources":["../src/core/migrations/planner.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;UAmCU,aAAA;;;iBAQM,8BAAA,UACN,QAAQ,iBACf;;;AA3B2F;AAyB9F;;;;AAE2B,KAcf,kBAAA,GAde;EAcf,SAAA,IAAA,EAAA,SAAkB;EAoBjB,SAAA,IAAA,EAnBkC,qCAmBT;CACC,GAnBnC,uBAmBmC;;;;;;;;;;;;;;;;;cAD1B,wBAAA,YAAoC;;sBACV;;;;qBAKlB;;;;;;;;;;;;;;;2BAeM;;kCAEO,cAAc;MAC1C;0BAIoB,2BAA2B"}
package/dist/planner.mjs CHANGED
@@ -1,4 +1,4 @@
1
1
  import "./issue-planner-CFjB0_oO.mjs";
2
- import { t as createPostgresMigrationPlanner } from "./planner-B4ZSLHRI.mjs";
2
+ import { t as createPostgresMigrationPlanner } from "./planner-Cm-ZLutk.mjs";
3
3
 
4
4
  export { createPostgresMigrationPlanner };
@@ -1,5 +1,6 @@
1
1
  import { t as PostgresPlanTargetDetails } from "./planner-target-details-DH-azLu-.mjs";
2
- import { n as DataTransformOptions, r as PostgresDataTransformOperation } from "./data-transform-D8x5m1YV.mjs";
2
+ import { n as DataTransformOptions } from "./data-transform-CrpmG4uJ.mjs";
3
+ import { SqlMigrationPlanOperation } from "@prisma-next/family-sql/control";
3
4
  import { Migration } from "@prisma-next/family-sql/migration";
4
5
  import { Contract } from "@prisma-next/contract/types";
5
6
  import { SqlStorage } from "@prisma-next/sql-contract/types";
@@ -43,8 +44,8 @@ declare abstract class PostgresMigration extends Migration<PostgresPlanTargetDet
43
44
  * supplies the stored control adapter. Authors call this from inside
44
45
  * `get operations()`; the adapter argument is hidden from the call site.
45
46
  */
46
- protected dataTransform<TContract extends Contract<SqlStorage>>(contract: TContract, name: string, options: DataTransformOptions): PostgresDataTransformOperation;
47
+ protected dataTransform<TContract extends Contract<SqlStorage>>(contract: TContract, name: string, options: DataTransformOptions): SqlMigrationPlanOperation<PostgresPlanTargetDetails>;
47
48
  }
48
49
  //#endregion
49
50
  export { PostgresMigration as t };
50
- //# sourceMappingURL=postgres-migration-DcfWGqhe.d.mts.map
51
+ //# sourceMappingURL=postgres-migration-BFjbb25b.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"postgres-migration-BFjbb25b.d.mts","names":[],"sources":["../src/core/migrations/postgres-migration.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;;;AA8BA;;;;;;;;;;;;;;;;;;uBAAsB,iBAAA,SAA0B,UAC9C;;;;;;;;qCAWmC;sBAEf;;;;;;4CAesB,SAAS,uBACvC,kCAED,uBACR,0BAA0B"}
@@ -1,5 +1,5 @@
1
1
  import { t as errorPostgresMigrationStackMissing } from "./errors-AFvEPZ1R.mjs";
2
- import { t as dataTransform } from "./data-transform-C83dy0vk.mjs";
2
+ import { t as dataTransform } from "./data-transform-Be_i_DBc.mjs";
3
3
  import { Migration } from "@prisma-next/family-sql/migration";
4
4
 
5
5
  //#region src/core/migrations/postgres-migration.ts
@@ -49,4 +49,4 @@ var PostgresMigration = class extends Migration {
49
49
 
50
50
  //#endregion
51
51
  export { PostgresMigration as t };
52
- //# sourceMappingURL=postgres-migration-EGSlO4jO.mjs.map
52
+ //# sourceMappingURL=postgres-migration-BS9vQW97.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"postgres-migration-BS9vQW97.mjs","names":["SqlMigration"],"sources":["../src/core/migrations/postgres-migration.ts"],"sourcesContent":["import type { Contract } from '@prisma-next/contract/types';\nimport type { SqlMigrationPlanOperation } from '@prisma-next/family-sql/control';\nimport type { SqlControlAdapter } from '@prisma-next/family-sql/control-adapter';\nimport { Migration as SqlMigration } from '@prisma-next/family-sql/migration';\nimport type { ControlStack } from '@prisma-next/framework-components/control';\nimport type { SqlStorage } from '@prisma-next/sql-contract/types';\nimport { errorPostgresMigrationStackMissing } from '../errors';\nimport { type DataTransformOptions, dataTransform } from './operations/data-transform';\nimport type { PostgresPlanTargetDetails } from './planner-target-details';\n\n/**\n * Target-owned base class for Postgres migrations.\n *\n * Fixes the `SqlMigration` generic to `PostgresPlanTargetDetails` and the\n * abstract `targetId` to the Postgres target-id string literal, so both\n * user-authored migrations and renderer-generated scaffolds (the output of\n * `renderCallsToTypeScript`) can extend `PostgresMigration` directly without\n * redeclaring target-local identity.\n *\n * Mirrors `MongoMigration` in `@prisma-next/family-mongo`: the renderer\n * emits `extends Migration` against a target-specific re-export of this\n * class from `@prisma-next/target-postgres/migration`, keeping the\n * authoring surface target-scoped rather than family-scoped.\n *\n * The constructor materializes a single Postgres `SqlControlAdapter` from\n * `stack.adapter.create(stack)` and stores it; the protected `dataTransform`\n * instance method forwards to the free `dataTransform` factory with that\n * stored adapter, so user migrations can write `this.dataTransform(...)`\n * without threading the adapter through every call.\n */\nexport abstract class PostgresMigration extends SqlMigration<\n PostgresPlanTargetDetails,\n 'postgres'\n> {\n readonly targetId = 'postgres' as const;\n\n /**\n * Materialized Postgres control adapter, created once per migration\n * instance from the injected stack. `undefined` only when the migration\n * was instantiated without a stack (test fixtures); `dataTransform`\n * throws in that case to surface the misuse.\n */\n protected readonly controlAdapter: SqlControlAdapter<'postgres'> | undefined;\n\n constructor(stack?: ControlStack<'sql', 'postgres'>) {\n super(stack);\n // The descriptor `create()` is typed as the wider `ControlAdapterInstance`;\n // the Postgres descriptor concretely returns a `SqlControlAdapter<'postgres'>`,\n // so the cast holds for any Postgres-target stack assembled at runtime.\n this.controlAdapter = stack?.adapter\n ? (stack.adapter.create(stack) as SqlControlAdapter<'postgres'>)\n : undefined;\n }\n\n /**\n * Instance-method wrapper around the free `dataTransform` factory that\n * supplies the stored control adapter. Authors call this from inside\n * `get operations()`; the adapter argument is hidden from the call site.\n */\n protected dataTransform<TContract extends Contract<SqlStorage>>(\n contract: TContract,\n name: string,\n options: DataTransformOptions,\n ): SqlMigrationPlanOperation<PostgresPlanTargetDetails> {\n if (!this.controlAdapter) {\n throw errorPostgresMigrationStackMissing();\n }\n return dataTransform(contract, name, options, this.controlAdapter);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AA8BA,IAAsB,oBAAtB,cAAgDA,UAG9C;CACA,AAAS,WAAW;;;;;;;CAQpB,AAAmB;CAEnB,YAAY,OAAyC;AACnD,QAAM,MAAM;AAIZ,OAAK,iBAAiB,OAAO,UACxB,MAAM,QAAQ,OAAO,MAAM,GAC5B;;;;;;;CAQN,AAAU,cACR,UACA,MACA,SACsD;AACtD,MAAI,CAAC,KAAK,eACR,OAAM,oCAAoC;AAE5C,SAAO,cAAc,UAAU,MAAM,SAAS,KAAK,eAAe"}
package/package.json CHANGED
@@ -1,33 +1,33 @@
1
1
  {
2
2
  "name": "@prisma-next/target-postgres",
3
- "version": "0.5.0-dev.44",
3
+ "version": "0.5.0-dev.46",
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
9
  "pathe": "^2.0.3",
10
- "@prisma-next/cli": "0.5.0-dev.44",
11
- "@prisma-next/errors": "0.5.0-dev.44",
12
- "@prisma-next/contract": "0.5.0-dev.44",
13
- "@prisma-next/family-sql": "0.5.0-dev.44",
14
- "@prisma-next/framework-components": "0.5.0-dev.44",
15
- "@prisma-next/migration-tools": "0.5.0-dev.44",
16
- "@prisma-next/ts-render": "0.5.0-dev.44",
17
- "@prisma-next/sql-errors": "0.5.0-dev.44",
18
- "@prisma-next/sql-contract": "0.5.0-dev.44",
19
- "@prisma-next/sql-operations": "0.5.0-dev.44",
20
- "@prisma-next/sql-schema-ir": "0.5.0-dev.44",
21
- "@prisma-next/utils": "0.5.0-dev.44",
22
- "@prisma-next/sql-relational-core": "0.5.0-dev.44"
10
+ "@prisma-next/cli": "0.5.0-dev.46",
11
+ "@prisma-next/contract": "0.5.0-dev.46",
12
+ "@prisma-next/errors": "0.5.0-dev.46",
13
+ "@prisma-next/family-sql": "0.5.0-dev.46",
14
+ "@prisma-next/migration-tools": "0.5.0-dev.46",
15
+ "@prisma-next/framework-components": "0.5.0-dev.46",
16
+ "@prisma-next/sql-contract": "0.5.0-dev.46",
17
+ "@prisma-next/sql-operations": "0.5.0-dev.46",
18
+ "@prisma-next/sql-errors": "0.5.0-dev.46",
19
+ "@prisma-next/ts-render": "0.5.0-dev.46",
20
+ "@prisma-next/sql-schema-ir": "0.5.0-dev.46",
21
+ "@prisma-next/utils": "0.5.0-dev.46",
22
+ "@prisma-next/sql-relational-core": "0.5.0-dev.46"
23
23
  },
24
24
  "devDependencies": {
25
25
  "tsdown": "0.18.4",
26
26
  "typescript": "5.9.3",
27
27
  "vitest": "4.0.17",
28
- "@prisma-next/tsconfig": "0.0.0",
28
+ "@prisma-next/test-utils": "0.0.1",
29
29
  "@prisma-next/tsdown": "0.0.0",
30
- "@prisma-next/test-utils": "0.0.1"
30
+ "@prisma-next/tsconfig": "0.0.0"
31
31
  },
32
32
  "files": [
33
33
  "dist",
@@ -28,3 +28,4 @@ export const PG_TIMETZ_CODEC_ID = 'pg/timetz@1' as const;
28
28
  export const PG_INTERVAL_CODEC_ID = 'pg/interval@1' as const;
29
29
  export const PG_JSON_CODEC_ID = 'pg/json@1' as const;
30
30
  export const PG_JSONB_CODEC_ID = 'pg/jsonb@1' as const;
31
+ export const PG_BYTEA_CODEC_ID = 'pg/bytea@1' as const;
@@ -19,6 +19,7 @@ import { type as arktype } from 'arktype';
19
19
  import {
20
20
  PG_BIT_CODEC_ID,
21
21
  PG_BOOL_CODEC_ID,
22
+ PG_BYTEA_CODEC_ID,
22
23
  PG_CHAR_CODEC_ID,
23
24
  PG_ENUM_CODEC_ID,
24
25
  PG_FLOAT_CODEC_ID,
@@ -502,6 +503,40 @@ const pgVarbitCodec = codec<
502
503
  },
503
504
  });
504
505
 
506
+ const pgByteaCodec = codec({
507
+ typeId: PG_BYTEA_CODEC_ID,
508
+ targetTypes: ['bytea'],
509
+ traits: ['equality'],
510
+ encode: (value: Uint8Array): Uint8Array => value,
511
+ decode: (wire: Uint8Array): Uint8Array =>
512
+ // Postgres node drivers commonly return Buffer instances (which extend
513
+ // Uint8Array) — normalize to a plain Uint8Array view so engine-agnostic
514
+ // consumers don't accidentally observe Buffer-specific APIs.
515
+ wire instanceof Uint8Array && wire.constructor === Uint8Array
516
+ ? wire
517
+ : new Uint8Array(wire.buffer, wire.byteOffset, wire.byteLength),
518
+ encodeJson: (value: Uint8Array): string => Buffer.from(value).toString('base64'),
519
+ decodeJson: (json): Uint8Array => {
520
+ if (typeof json !== 'string') {
521
+ throw new Error(`Expected base64 string for pg/bytea@1, got ${typeof json}`);
522
+ }
523
+ const decoded = Buffer.from(json, 'base64');
524
+ if (decoded.toString('base64') !== json) {
525
+ throw new Error(`Invalid base64 string for pg/bytea@1 (length: ${json.length})`);
526
+ }
527
+ return new Uint8Array(decoded);
528
+ },
529
+ meta: {
530
+ db: {
531
+ sql: {
532
+ postgres: {
533
+ nativeType: 'bytea',
534
+ },
535
+ },
536
+ },
537
+ },
538
+ });
539
+
505
540
  const pgEnumCodec = codec({
506
541
  typeId: PG_ENUM_CODEC_ID,
507
542
  targetTypes: ['enum'],
@@ -610,6 +645,7 @@ const codecs = defineCodecs()
610
645
  .add('bool', pgBoolCodec)
611
646
  .add('bit', pgBitCodec)
612
647
  .add('bit varying', pgVarbitCodec)
648
+ .add('bytea', pgByteaCodec)
613
649
  .add('interval', pgIntervalCodec)
614
650
  .add('enum', pgEnumCodec)
615
651
  .add('json', pgJsonCodec)
@@ -11,7 +11,7 @@
11
11
  * override get operations() {
12
12
  * return [
13
13
  * this.dataTransform(endContract, 'backfill emails', {
14
- * check: () => db.users.count().where(({ email }) => email.isNull()),
14
+ * check: () => db.users.select('id').where(({ email }) => email.isNull()).limit(1),
15
15
  * run: () => db.users.update({ email: '' }).where(({ email }) => email.isNull()),
16
16
  * }),
17
17
  * ];
@@ -23,21 +23,49 @@
23
23
  * invokes each one, asserts that its `meta.storageHash` matches the
24
24
  * `contract` it was handed (→ `PN-MIG-2005` on mismatch), and lowers the
25
25
  * plan via the supplied control adapter to a serialized `{sql, params}`
26
- * payload for `ops.json`. The free factory remains usable standalone
27
- * (tests, ad-hoc tooling, non-class contexts) by passing the adapter
28
- * explicitly as the fourth argument.
26
+ * payload.
27
+ *
28
+ * The factory then lowers the data transform to the unified migration-op
29
+ * shape `{ precheck, execute, postcheck }`. The user's `check` plan is
30
+ * wrapped twice with opposite truth values:
31
+ *
32
+ * - precheck `SELECT EXISTS (<check>) AS ok` asserts there is work to do
33
+ * (precheck is short-circuited by the runner's pre-satisfied-skip path
34
+ * when nothing remains to backfill).
35
+ * - postcheck `SELECT NOT EXISTS (<check>) AS ok` asserts the work is
36
+ * complete after the run steps execute.
37
+ *
38
+ * The `check` plan is therefore expected to be a **rowset query whose
39
+ * presence of any row signals "work remains"** — typically `select('id')
40
+ * .where(<violation predicate>).limit(1)`. Scalar/aggregate shapes
41
+ * (`count(*)`, `bool_and(...)`) do not work under this contract: they
42
+ * always return exactly one row, so `EXISTS` is always true and
43
+ * `NOT EXISTS` is always false. (This is the same row-presence contract
44
+ * the pre-unification runner relied on; the wrapping is just lifting it
45
+ * into SQL.)
46
+ *
47
+ * Each `run` plan becomes an execute step. Because the `Step.params`
48
+ * field threads through `driver.query(sql, params)`, the user's bound
49
+ * values flow through the driver's parameter binder rather than being
50
+ * inlined into the SQL text.
51
+ *
52
+ * The free factory remains usable standalone (tests, ad-hoc tooling,
53
+ * non-class contexts) by passing the adapter explicitly as the fourth
54
+ * argument.
29
55
  */
30
56
 
31
57
  import type { Contract } from '@prisma-next/contract/types';
32
58
  import { errorDataTransformContractMismatch } from '@prisma-next/errors/migration';
33
- import type { SqlControlAdapter } from '@prisma-next/family-sql/control-adapter';
34
59
  import type {
35
- DataTransformOperation,
36
- SerializedQueryPlan,
37
- } from '@prisma-next/framework-components/control';
60
+ SqlMigrationPlanOperation,
61
+ SqlMigrationPlanOperationStep,
62
+ } from '@prisma-next/family-sql/control';
63
+ import type { SqlControlAdapter } from '@prisma-next/family-sql/control-adapter';
64
+ import type { SerializedQueryPlan } from '@prisma-next/framework-components/control';
38
65
  import type { SqlStorage } from '@prisma-next/sql-contract/types';
39
66
  import type { SqlQueryPlan } from '@prisma-next/sql-relational-core/plan';
40
67
  import { ifDefined } from '@prisma-next/utils/defined';
68
+ import type { PostgresPlanTargetDetails } from '../planner-target-details';
41
69
 
42
70
  interface Buildable<R = unknown> {
43
71
  build(): SqlQueryPlan<R>;
@@ -56,37 +84,66 @@ export interface DataTransformOptions {
56
84
  * not referenceable from refs.
57
85
  */
58
86
  readonly invariantId?: string;
59
- /** Optional pre-flight query. `undefined` means "no check". */
87
+ /**
88
+ * Optional pre-flight query. `undefined` means "no check". When
89
+ * supplied, the closure must return a **rowset query** whose
90
+ * presence of any row signals "violations remain". Conventional
91
+ * shape: `db.<table>.select('id').where(<violation>).limit(1)`.
92
+ * Scalar/aggregate shapes do not satisfy this contract.
93
+ */
60
94
  readonly check?: DataTransformClosure;
61
95
  /** One or more mutation queries to execute. */
62
96
  readonly run: DataTransformClosure | readonly DataTransformClosure[];
63
97
  }
64
98
 
65
- /**
66
- * Concrete Postgres flavor of `DataTransformOperation`, re-exported so the
67
- * `PostgresMigration.dataTransform` instance method can name it without
68
- * leaking the framework-components symbol into call sites.
69
- */
70
- export type PostgresDataTransformOperation = DataTransformOperation;
71
-
72
99
  export function dataTransform<TContract extends Contract<SqlStorage>>(
73
100
  contract: TContract,
74
101
  name: string,
75
102
  options: DataTransformOptions,
76
103
  adapter: SqlControlAdapter<'postgres'>,
77
- ): DataTransformOperation {
104
+ ): SqlMigrationPlanOperation<PostgresPlanTargetDetails> {
78
105
  const runClosures: readonly DataTransformClosure[] = Array.isArray(options.run)
79
106
  ? options.run
80
107
  : [options.run as DataTransformClosure];
108
+
109
+ const checkPlan = options.check ? invokeAndLower(options.check, contract, adapter, name) : null;
110
+ const runPlans = runClosures.map((closure) => invokeAndLower(closure, contract, adapter, name));
111
+
112
+ const precheck: readonly SqlMigrationPlanOperationStep[] = checkPlan
113
+ ? [
114
+ {
115
+ description: `Check ${name} has work to do`,
116
+ sql: `SELECT EXISTS (${checkPlan.sql}) AS ok`,
117
+ params: checkPlan.params,
118
+ },
119
+ ]
120
+ : [];
121
+
122
+ const execute: readonly SqlMigrationPlanOperationStep[] = runPlans.map((plan) => ({
123
+ description: `Run ${name}`,
124
+ sql: plan.sql,
125
+ params: plan.params,
126
+ }));
127
+
128
+ const postcheck: readonly SqlMigrationPlanOperationStep[] = checkPlan
129
+ ? [
130
+ {
131
+ description: `Verify ${name} resolved all violations`,
132
+ sql: `SELECT NOT EXISTS (${checkPlan.sql}) AS ok`,
133
+ params: checkPlan.params,
134
+ },
135
+ ]
136
+ : [];
137
+
81
138
  return {
82
139
  id: `data_migration.${name}`,
83
140
  label: `Data transform: ${name}`,
84
141
  operationClass: 'data',
85
- name,
86
142
  ...ifDefined('invariantId', options.invariantId),
87
- source: 'migration.ts',
88
- check: options.check ? invokeAndLower(options.check, contract, adapter, name) : null,
89
- run: runClosures.map((closure) => invokeAndLower(closure, contract, adapter, name)),
143
+ target: { id: 'postgres' },
144
+ precheck,
145
+ execute,
146
+ postcheck,
90
147
  };
91
148
  }
92
149
 
@@ -1,14 +1,11 @@
1
1
  import type { Contract } from '@prisma-next/contract/types';
2
+ import type { SqlMigrationPlanOperation } from '@prisma-next/family-sql/control';
2
3
  import type { SqlControlAdapter } from '@prisma-next/family-sql/control-adapter';
3
4
  import { Migration as SqlMigration } from '@prisma-next/family-sql/migration';
4
5
  import type { ControlStack } from '@prisma-next/framework-components/control';
5
6
  import type { SqlStorage } from '@prisma-next/sql-contract/types';
6
7
  import { errorPostgresMigrationStackMissing } from '../errors';
7
- import {
8
- type DataTransformOptions,
9
- dataTransform,
10
- type PostgresDataTransformOperation,
11
- } from './operations/data-transform';
8
+ import { type DataTransformOptions, dataTransform } from './operations/data-transform';
12
9
  import type { PostgresPlanTargetDetails } from './planner-target-details';
13
10
 
14
11
  /**
@@ -64,7 +61,7 @@ export abstract class PostgresMigration extends SqlMigration<
64
61
  contract: TContract,
65
62
  name: string,
66
63
  options: DataTransformOptions,
67
- ): PostgresDataTransformOperation {
64
+ ): SqlMigrationPlanOperation<PostgresPlanTargetDetails> {
68
65
  if (!this.controlAdapter) {
69
66
  throw errorPostgresMigrationStackMissing();
70
67
  }