@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.
- package/dist/{codec-ids-CojIXVf9.mjs → codec-ids-ckQX9Kcg.mjs} +3 -2
- package/dist/{codec-ids-CojIXVf9.mjs.map → codec-ids-ckQX9Kcg.mjs.map} +1 -1
- package/dist/codec-ids.d.mts +2 -1
- package/dist/codec-ids.d.mts.map +1 -1
- package/dist/codec-ids.mjs +2 -2
- package/dist/codec-types.d.mts +1 -1
- package/dist/codec-types.mjs +1 -1
- package/dist/{codecs-CE5EUsNM.d.mts → codecs-B03dFv94.d.mts} +11 -1
- package/dist/codecs-B03dFv94.d.mts.map +1 -0
- package/dist/{codecs-dzZ_dMpK.mjs → codecs-D0oXyJIH.mjs} +18 -3
- package/dist/codecs-D0oXyJIH.mjs.map +1 -0
- package/dist/codecs.d.mts +1 -1
- package/dist/codecs.mjs +1 -1
- package/dist/control.mjs +6 -56
- package/dist/control.mjs.map +1 -1
- package/dist/{data-transform-C83dy0vk.mjs → data-transform-Be_i_DBc.mjs} +22 -5
- package/dist/data-transform-Be_i_DBc.mjs.map +1 -0
- package/dist/{data-transform-D8x5m1YV.d.mts → data-transform-CrpmG4uJ.d.mts} +12 -11
- package/dist/data-transform-CrpmG4uJ.d.mts.map +1 -0
- package/dist/data-transform.d.mts +1 -1
- package/dist/data-transform.mjs +1 -1
- package/dist/issue-planner.d.mts +1 -1
- package/dist/migration.d.mts +2 -2
- package/dist/migration.mjs +2 -2
- package/dist/pack.d.mts +1 -1
- package/dist/{planner-B4ZSLHRI.mjs → planner-Cm-ZLutk.mjs} +2 -2
- package/dist/{planner-B4ZSLHRI.mjs.map → planner-Cm-ZLutk.mjs.map} +1 -1
- package/dist/{planner-produced-postgres-migration-C0GNhHGw.mjs → planner-produced-postgres-migration-Bi-RWO4-.mjs} +2 -2
- package/dist/{planner-produced-postgres-migration-C0GNhHGw.mjs.map → planner-produced-postgres-migration-Bi-RWO4-.mjs.map} +1 -1
- package/dist/{planner-produced-postgres-migration-Dw_mPMKt.d.mts → planner-produced-postgres-migration-M3EfhWSS.d.mts} +2 -2
- package/dist/planner-produced-postgres-migration-M3EfhWSS.d.mts.map +1 -0
- package/dist/planner-produced-postgres-migration.d.mts +3 -2
- package/dist/planner-produced-postgres-migration.mjs +1 -1
- package/dist/planner.d.mts +4 -3
- package/dist/planner.d.mts.map +1 -1
- package/dist/planner.mjs +1 -1
- package/dist/{postgres-migration-DcfWGqhe.d.mts → postgres-migration-BFjbb25b.d.mts} +4 -3
- package/dist/postgres-migration-BFjbb25b.d.mts.map +1 -0
- package/dist/{postgres-migration-EGSlO4jO.mjs → postgres-migration-BS9vQW97.mjs} +2 -2
- package/dist/postgres-migration-BS9vQW97.mjs.map +1 -0
- package/package.json +16 -16
- package/src/core/codec-ids.ts +1 -0
- package/src/core/codecs.ts +36 -0
- package/src/core/migrations/operations/data-transform.ts +78 -21
- package/src/core/migrations/postgres-migration.ts +3 -6
- package/src/core/migrations/runner.ts +16 -121
- package/dist/codecs-CE5EUsNM.d.mts.map +0 -1
- package/dist/codecs-dzZ_dMpK.mjs.map +0 -1
- package/dist/data-transform-C83dy0vk.mjs.map +0 -1
- package/dist/data-transform-D8x5m1YV.d.mts.map +0 -1
- package/dist/planner-produced-postgres-migration-Dw_mPMKt.d.mts.map +0 -1
- package/dist/postgres-migration-DcfWGqhe.d.mts.map +0 -1
- 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
|
-
/**
|
|
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 {
|
|
38
|
-
//# sourceMappingURL=data-transform-
|
|
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 {
|
|
1
|
+
import { r as dataTransform } from "./data-transform-CrpmG4uJ.mjs";
|
|
2
2
|
export { dataTransform };
|
package/dist/data-transform.mjs
CHANGED
package/dist/issue-planner.d.mts
CHANGED
|
@@ -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
|
package/dist/migration.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
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-
|
|
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
|
|
package/dist/migration.mjs
CHANGED
|
@@ -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-
|
|
3
|
-
import { t as PostgresMigration } from "./postgres-migration-
|
|
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,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-
|
|
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-
|
|
98
|
+
//# sourceMappingURL=planner-Cm-ZLutk.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"planner-
|
|
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-
|
|
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-
|
|
32
|
+
//# sourceMappingURL=planner-produced-postgres-migration-Bi-RWO4-.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"planner-produced-postgres-migration-
|
|
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-
|
|
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-
|
|
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-
|
|
4
|
-
import { t as TypeScriptRenderablePostgresMigration } from "./planner-produced-postgres-migration-
|
|
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-
|
|
1
|
+
import { t as TypeScriptRenderablePostgresMigration } from "./planner-produced-postgres-migration-Bi-RWO4-.mjs";
|
|
2
2
|
|
|
3
3
|
export { TypeScriptRenderablePostgresMigration };
|
package/dist/planner.d.mts
CHANGED
|
@@ -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-
|
|
4
|
-
import { t as TypeScriptRenderablePostgresMigration } from "./planner-produced-postgres-migration-
|
|
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 {
|
package/dist/planner.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"planner.d.mts","names":[],"sources":["../src/core/migrations/planner.ts"],"sourcesContent":[],"mappings":"
|
|
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,5 +1,6 @@
|
|
|
1
1
|
import { t as PostgresPlanTargetDetails } from "./planner-target-details-DH-azLu-.mjs";
|
|
2
|
-
import { n as DataTransformOptions
|
|
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):
|
|
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-
|
|
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-
|
|
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-
|
|
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.
|
|
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.
|
|
11
|
-
"@prisma-next/
|
|
12
|
-
"@prisma-next/
|
|
13
|
-
"@prisma-next/family-sql": "0.5.0-dev.
|
|
14
|
-
"@prisma-next/
|
|
15
|
-
"@prisma-next/
|
|
16
|
-
"@prisma-next/
|
|
17
|
-
"@prisma-next/sql-
|
|
18
|
-
"@prisma-next/sql-
|
|
19
|
-
"@prisma-next/
|
|
20
|
-
"@prisma-next/sql-schema-ir": "0.5.0-dev.
|
|
21
|
-
"@prisma-next/utils": "0.5.0-dev.
|
|
22
|
-
"@prisma-next/sql-relational-core": "0.5.0-dev.
|
|
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/
|
|
28
|
+
"@prisma-next/test-utils": "0.0.1",
|
|
29
29
|
"@prisma-next/tsdown": "0.0.0",
|
|
30
|
-
"@prisma-next/
|
|
30
|
+
"@prisma-next/tsconfig": "0.0.0"
|
|
31
31
|
},
|
|
32
32
|
"files": [
|
|
33
33
|
"dist",
|
package/src/core/codec-ids.ts
CHANGED
|
@@ -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;
|
package/src/core/codecs.ts
CHANGED
|
@@ -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.
|
|
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
|
|
27
|
-
*
|
|
28
|
-
*
|
|
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
|
-
|
|
36
|
-
|
|
37
|
-
} from '@prisma-next/
|
|
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
|
-
/**
|
|
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
|
-
):
|
|
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
|
-
|
|
88
|
-
|
|
89
|
-
|
|
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
|
-
):
|
|
64
|
+
): SqlMigrationPlanOperation<PostgresPlanTargetDetails> {
|
|
68
65
|
if (!this.controlAdapter) {
|
|
69
66
|
throw errorPostgresMigrationStackMissing();
|
|
70
67
|
}
|