@prisma-next/target-postgres 0.4.0-dev.9 → 0.5.0-dev.1

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 (195) hide show
  1. package/dist/codec-ids-CojIXVf9.mjs +29 -0
  2. package/dist/codec-ids-CojIXVf9.mjs.map +1 -0
  3. package/dist/codec-ids.d.mts +28 -0
  4. package/dist/codec-ids.d.mts.map +1 -0
  5. package/dist/codec-ids.mjs +3 -0
  6. package/dist/codec-types.d.mts +42 -0
  7. package/dist/codec-types.d.mts.map +1 -0
  8. package/dist/codec-types.mjs +3 -0
  9. package/dist/codecs-BoahtY_Q.mjs +385 -0
  10. package/dist/codecs-BoahtY_Q.mjs.map +1 -0
  11. package/dist/codecs-D-F2KJqt.d.mts +299 -0
  12. package/dist/codecs-D-F2KJqt.d.mts.map +1 -0
  13. package/dist/codecs.d.mts +2 -0
  14. package/dist/codecs.mjs +3 -0
  15. package/dist/control.d.mts +1 -9
  16. package/dist/control.d.mts.map +1 -1
  17. package/dist/control.mjs +23 -5101
  18. package/dist/control.mjs.map +1 -1
  19. package/dist/data-transform-CxFRBIUp.d.mts +32 -0
  20. package/dist/data-transform-CxFRBIUp.d.mts.map +1 -0
  21. package/dist/data-transform-VfEGzXWt.mjs +39 -0
  22. package/dist/data-transform-VfEGzXWt.mjs.map +1 -0
  23. package/dist/data-transform.d.mts +2 -0
  24. package/dist/data-transform.mjs +3 -0
  25. package/dist/default-normalizer-DNOpRoOF.mjs +131 -0
  26. package/dist/default-normalizer-DNOpRoOF.mjs.map +1 -0
  27. package/dist/default-normalizer.d.mts +19 -0
  28. package/dist/default-normalizer.d.mts.map +1 -0
  29. package/dist/default-normalizer.mjs +3 -0
  30. package/dist/{descriptor-meta-DkvCmY98.mjs → descriptor-meta-BVoVtyp-.mjs} +1 -1
  31. package/dist/{descriptor-meta-DkvCmY98.mjs.map → descriptor-meta-BVoVtyp-.mjs.map} +1 -1
  32. package/dist/errors-AFvEPZ1R.mjs +34 -0
  33. package/dist/errors-AFvEPZ1R.mjs.map +1 -0
  34. package/dist/errors.d.mts +27 -0
  35. package/dist/errors.d.mts.map +1 -0
  36. package/dist/errors.mjs +3 -0
  37. package/dist/issue-planner-CFjB0_oO.mjs +879 -0
  38. package/dist/issue-planner-CFjB0_oO.mjs.map +1 -0
  39. package/dist/issue-planner.d.mts +85 -0
  40. package/dist/issue-planner.d.mts.map +1 -0
  41. package/dist/issue-planner.mjs +3 -0
  42. package/dist/migration.d.mts +90 -0
  43. package/dist/migration.d.mts.map +1 -0
  44. package/dist/migration.mjs +24 -0
  45. package/dist/migration.mjs.map +1 -0
  46. package/dist/native-type-normalizer-CInai_oY.mjs +38 -0
  47. package/dist/native-type-normalizer-CInai_oY.mjs.map +1 -0
  48. package/dist/native-type-normalizer.d.mts +18 -0
  49. package/dist/native-type-normalizer.d.mts.map +1 -0
  50. package/dist/native-type-normalizer.mjs +3 -0
  51. package/dist/op-factory-call-BKlruaiC.mjs +605 -0
  52. package/dist/op-factory-call-BKlruaiC.mjs.map +1 -0
  53. package/dist/op-factory-call-C3bWXKSP.d.mts +304 -0
  54. package/dist/op-factory-call-C3bWXKSP.d.mts.map +1 -0
  55. package/dist/op-factory-call.d.mts +3 -0
  56. package/dist/op-factory-call.mjs +3 -0
  57. package/dist/pack.d.mts +1 -1
  58. package/dist/pack.mjs +1 -1
  59. package/dist/planner-CLUvVhUN.mjs +98 -0
  60. package/dist/planner-CLUvVhUN.mjs.map +1 -0
  61. package/dist/planner-ddl-builders-Dxvw1LHw.mjs +132 -0
  62. package/dist/planner-ddl-builders-Dxvw1LHw.mjs.map +1 -0
  63. package/dist/planner-ddl-builders.d.mts +22 -0
  64. package/dist/planner-ddl-builders.d.mts.map +1 -0
  65. package/dist/planner-ddl-builders.mjs +3 -0
  66. package/dist/planner-identity-values-Dju-o5GF.mjs +91 -0
  67. package/dist/planner-identity-values-Dju-o5GF.mjs.map +1 -0
  68. package/dist/planner-identity-values.d.mts +20 -0
  69. package/dist/planner-identity-values.d.mts.map +1 -0
  70. package/dist/planner-identity-values.mjs +3 -0
  71. package/dist/planner-produced-postgres-migration-CRRTno6Z.d.mts +20 -0
  72. package/dist/planner-produced-postgres-migration-CRRTno6Z.d.mts.map +1 -0
  73. package/dist/planner-produced-postgres-migration-DSSPq8QS.mjs +33 -0
  74. package/dist/planner-produced-postgres-migration-DSSPq8QS.mjs.map +1 -0
  75. package/dist/planner-produced-postgres-migration.d.mts +5 -0
  76. package/dist/planner-produced-postgres-migration.mjs +3 -0
  77. package/dist/planner-schema-lookup-B7lkypwn.mjs +29 -0
  78. package/dist/planner-schema-lookup-B7lkypwn.mjs.map +1 -0
  79. package/dist/planner-schema-lookup.d.mts +22 -0
  80. package/dist/planner-schema-lookup.d.mts.map +1 -0
  81. package/dist/planner-schema-lookup.mjs +3 -0
  82. package/dist/planner-sql-checks-7jkgm9TX.mjs +241 -0
  83. package/dist/planner-sql-checks-7jkgm9TX.mjs.map +1 -0
  84. package/dist/planner-sql-checks.d.mts +55 -0
  85. package/dist/planner-sql-checks.d.mts.map +1 -0
  86. package/dist/planner-sql-checks.mjs +3 -0
  87. package/dist/planner-target-details-DH-azLu-.d.mts +11 -0
  88. package/dist/planner-target-details-DH-azLu-.d.mts.map +1 -0
  89. package/dist/planner-target-details.d.mts +2 -0
  90. package/dist/planner-target-details.mjs +1 -0
  91. package/dist/planner.d.mts +68 -0
  92. package/dist/planner.d.mts.map +1 -0
  93. package/dist/planner.mjs +4 -0
  94. package/dist/postgres-migration-BjA3Zmts.d.mts +50 -0
  95. package/dist/postgres-migration-BjA3Zmts.d.mts.map +1 -0
  96. package/dist/postgres-migration-qtmtbONe.mjs +52 -0
  97. package/dist/postgres-migration-qtmtbONe.mjs.map +1 -0
  98. package/dist/render-ops-D6_DHdOK.mjs +8 -0
  99. package/dist/render-ops-D6_DHdOK.mjs.map +1 -0
  100. package/dist/render-ops.d.mts +11 -0
  101. package/dist/render-ops.d.mts.map +1 -0
  102. package/dist/render-ops.mjs +3 -0
  103. package/dist/render-typescript-1rF_SB4g.mjs +85 -0
  104. package/dist/render-typescript-1rF_SB4g.mjs.map +1 -0
  105. package/dist/render-typescript.d.mts +15 -0
  106. package/dist/render-typescript.d.mts.map +1 -0
  107. package/dist/render-typescript.mjs +3 -0
  108. package/dist/runtime.d.mts +15 -3
  109. package/dist/runtime.d.mts.map +1 -1
  110. package/dist/runtime.mjs +10 -1
  111. package/dist/runtime.mjs.map +1 -1
  112. package/dist/shared-Bxkt8pNO.d.mts +41 -0
  113. package/dist/shared-Bxkt8pNO.d.mts.map +1 -0
  114. package/dist/sql-utils-r-Lw535w.mjs +76 -0
  115. package/dist/sql-utils-r-Lw535w.mjs.map +1 -0
  116. package/dist/sql-utils.d.mts +59 -0
  117. package/dist/sql-utils.d.mts.map +1 -0
  118. package/dist/sql-utils.mjs +3 -0
  119. package/dist/statement-builders-BPnmt6wx.mjs +116 -0
  120. package/dist/statement-builders-BPnmt6wx.mjs.map +1 -0
  121. package/dist/statement-builders.d.mts +23 -0
  122. package/dist/statement-builders.d.mts.map +1 -0
  123. package/dist/statement-builders.mjs +3 -0
  124. package/dist/tables-BmdW_FWO.mjs +477 -0
  125. package/dist/tables-BmdW_FWO.mjs.map +1 -0
  126. package/dist/types-ClK03Ojd.d.mts +10 -0
  127. package/dist/types-ClK03Ojd.d.mts.map +1 -0
  128. package/dist/types.d.mts +2 -0
  129. package/dist/types.mjs +1 -0
  130. package/package.json +38 -19
  131. package/src/core/codec-ids.ts +30 -0
  132. package/src/core/codecs.ts +645 -0
  133. package/src/core/default-normalizer.ts +131 -0
  134. package/src/core/descriptor-meta.ts +1 -1
  135. package/src/core/errors.ts +33 -0
  136. package/src/core/json-schema-type-expression.ts +131 -0
  137. package/src/core/migrations/issue-planner.ts +832 -0
  138. package/src/core/migrations/op-factory-call.ts +858 -0
  139. package/src/core/migrations/operations/columns.ts +285 -0
  140. package/src/core/migrations/operations/constraints.ts +191 -0
  141. package/src/core/migrations/operations/data-transform.ts +119 -0
  142. package/src/core/migrations/operations/dependencies.ts +36 -0
  143. package/src/core/migrations/operations/enums.ts +113 -0
  144. package/src/core/migrations/operations/indexes.ts +61 -0
  145. package/src/core/migrations/operations/raw.ts +15 -0
  146. package/src/core/migrations/operations/shared.ts +67 -0
  147. package/src/core/migrations/operations/tables.ts +63 -0
  148. package/src/core/migrations/planner-ddl-builders.ts +1 -1
  149. package/src/core/migrations/planner-produced-postgres-migration.ts +67 -0
  150. package/src/core/migrations/planner-recipes.ts +1 -1
  151. package/src/core/migrations/planner-sql-checks.ts +1 -1
  152. package/src/core/migrations/planner-strategies.ts +592 -151
  153. package/src/core/migrations/planner-target-details.ts +0 -6
  154. package/src/core/migrations/planner.ts +65 -785
  155. package/src/core/migrations/postgres-migration.ts +73 -0
  156. package/src/core/migrations/render-ops.ts +9 -0
  157. package/src/core/migrations/render-typescript.ts +105 -0
  158. package/src/core/migrations/runner.ts +2 -4
  159. package/src/core/native-type-normalizer.ts +49 -0
  160. package/src/core/sql-utils.ts +104 -0
  161. package/src/exports/codec-ids.ts +1 -0
  162. package/src/exports/codec-types.ts +51 -0
  163. package/src/exports/codecs.ts +2 -0
  164. package/src/exports/control.ts +9 -142
  165. package/src/exports/data-transform.ts +1 -0
  166. package/src/exports/default-normalizer.ts +1 -0
  167. package/src/exports/errors.ts +1 -0
  168. package/src/exports/issue-planner.ts +1 -0
  169. package/src/exports/migration.ts +46 -0
  170. package/src/exports/native-type-normalizer.ts +1 -0
  171. package/src/exports/op-factory-call.ts +25 -0
  172. package/src/exports/planner-ddl-builders.ts +8 -0
  173. package/src/exports/planner-identity-values.ts +1 -0
  174. package/src/exports/planner-produced-postgres-migration.ts +1 -0
  175. package/src/exports/planner-schema-lookup.ts +6 -0
  176. package/src/exports/planner-sql-checks.ts +11 -0
  177. package/src/exports/planner-target-details.ts +1 -0
  178. package/src/exports/planner.ts +1 -0
  179. package/src/exports/render-ops.ts +1 -0
  180. package/src/exports/render-typescript.ts +1 -0
  181. package/src/exports/runtime.ts +19 -4
  182. package/src/exports/sql-utils.ts +7 -0
  183. package/src/exports/statement-builders.ts +7 -0
  184. package/src/exports/types.ts +1 -0
  185. package/dist/migration-builders.d.mts +0 -88
  186. package/dist/migration-builders.d.mts.map +0 -1
  187. package/dist/migration-builders.mjs +0 -3
  188. package/dist/operation-descriptors-CxymFSgK.mjs +0 -52
  189. package/dist/operation-descriptors-CxymFSgK.mjs.map +0 -1
  190. package/src/core/migrations/descriptor-planner.ts +0 -464
  191. package/src/core/migrations/operation-descriptors.ts +0 -166
  192. package/src/core/migrations/operation-resolver.ts +0 -929
  193. package/src/core/migrations/planner-reconciliation.ts +0 -798
  194. package/src/core/migrations/scaffolding.ts +0 -140
  195. package/src/exports/migration-builders.ts +0 -56
@@ -0,0 +1,73 @@
1
+ import type { Contract } from '@prisma-next/contract/types';
2
+ import type { SqlControlAdapter } from '@prisma-next/family-sql/control-adapter';
3
+ import { Migration as SqlMigration } from '@prisma-next/family-sql/migration';
4
+ import type { ControlStack } from '@prisma-next/framework-components/control';
5
+ import type { SqlStorage } from '@prisma-next/sql-contract/types';
6
+ import { errorPostgresMigrationStackMissing } from '../errors';
7
+ import {
8
+ type DataTransformOptions,
9
+ dataTransform,
10
+ type PostgresDataTransformOperation,
11
+ } from './operations/data-transform';
12
+ import type { PostgresPlanTargetDetails } from './planner-target-details';
13
+
14
+ /**
15
+ * Target-owned base class for Postgres migrations.
16
+ *
17
+ * Fixes the `SqlMigration` generic to `PostgresPlanTargetDetails` and the
18
+ * abstract `targetId` to the Postgres target-id string literal, so both
19
+ * user-authored migrations and renderer-generated scaffolds (the output of
20
+ * `renderCallsToTypeScript`) can extend `PostgresMigration` directly without
21
+ * redeclaring target-local identity.
22
+ *
23
+ * Mirrors `MongoMigration` in `@prisma-next/family-mongo`: the renderer
24
+ * emits `extends Migration` against a target-specific re-export of this
25
+ * class from `@prisma-next/target-postgres/migration`, keeping the
26
+ * authoring surface target-scoped rather than family-scoped.
27
+ *
28
+ * The constructor materializes a single Postgres `SqlControlAdapter` from
29
+ * `stack.adapter.create(stack)` and stores it; the protected `dataTransform`
30
+ * instance method forwards to the free `dataTransform` factory with that
31
+ * stored adapter, so user migrations can write `this.dataTransform(...)`
32
+ * without threading the adapter through every call.
33
+ */
34
+ export abstract class PostgresMigration extends SqlMigration<
35
+ PostgresPlanTargetDetails,
36
+ 'postgres'
37
+ > {
38
+ readonly targetId = 'postgres' as const;
39
+
40
+ /**
41
+ * Materialized Postgres control adapter, created once per migration
42
+ * instance from the injected stack. `undefined` only when the migration
43
+ * was instantiated without a stack (test fixtures); `dataTransform`
44
+ * throws in that case to surface the misuse.
45
+ */
46
+ protected readonly controlAdapter: SqlControlAdapter<'postgres'> | undefined;
47
+
48
+ constructor(stack?: ControlStack<'sql', 'postgres'>) {
49
+ super(stack);
50
+ // The descriptor `create()` is typed as the wider `ControlAdapterInstance`;
51
+ // the Postgres descriptor concretely returns a `SqlControlAdapter<'postgres'>`,
52
+ // so the cast holds for any Postgres-target stack assembled at runtime.
53
+ this.controlAdapter = stack?.adapter
54
+ ? (stack.adapter.create(stack) as SqlControlAdapter<'postgres'>)
55
+ : undefined;
56
+ }
57
+
58
+ /**
59
+ * Instance-method wrapper around the free `dataTransform` factory that
60
+ * supplies the stored control adapter. Authors call this from inside
61
+ * `get operations()`; the adapter argument is hidden from the call site.
62
+ */
63
+ protected dataTransform<TContract extends Contract<SqlStorage>>(
64
+ contract: TContract,
65
+ name: string,
66
+ options: DataTransformOptions,
67
+ ): PostgresDataTransformOperation {
68
+ if (!this.controlAdapter) {
69
+ throw errorPostgresMigrationStackMissing();
70
+ }
71
+ return dataTransform(contract, name, options, this.controlAdapter);
72
+ }
73
+ }
@@ -0,0 +1,9 @@
1
+ import type { SqlMigrationPlanOperation } from '@prisma-next/family-sql/control';
2
+ import type { PostgresOpFactoryCall } from './op-factory-call';
3
+ import type { PostgresPlanTargetDetails } from './planner-target-details';
4
+
5
+ type Op = SqlMigrationPlanOperation<PostgresPlanTargetDetails>;
6
+
7
+ export function renderOps(calls: readonly PostgresOpFactoryCall[]): Op[] {
8
+ return calls.map((c) => c.toOp());
9
+ }
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Polymorphic TypeScript emitter for the Postgres migration IR.
3
+ *
4
+ * Each `PostgresOpFactoryCall` renders itself via `renderTypeScript()` and
5
+ * declares its own `importRequirements()`; this file just composes the module
6
+ * source around those contributions. The design mirrors the Mongo target's
7
+ * `render-typescript.ts` deliberately — byte-for-byte alignment isn't required
8
+ * (different factory module specifiers, different base-class name) but the
9
+ * shape is, so future consolidation to a framework-level helper is mechanical.
10
+ */
11
+
12
+ import { detectScaffoldRuntime, shebangLineFor } from '@prisma-next/migration-tools/migration-ts';
13
+ import { type ImportRequirement, jsonToTsSource, renderImports } from '@prisma-next/ts-render';
14
+ import type { PostgresOpFactoryCall } from './op-factory-call';
15
+
16
+ export interface RenderMigrationMeta {
17
+ readonly from: string;
18
+ readonly to: string;
19
+ readonly kind?: string;
20
+ readonly labels?: readonly string[];
21
+ }
22
+
23
+ /**
24
+ * Always-present base imports for the rendered scaffold. Both come from
25
+ * `@prisma-next/target-postgres/migration` so an authored Postgres
26
+ * `migration.ts` only needs a single dependency for its base class and
27
+ * its CLI entrypoint:
28
+ *
29
+ * - `Migration` — the target-owned re-export fixes the `SqlMigration`
30
+ * generic to `PostgresPlanTargetDetails` and the abstract `targetId`
31
+ * to `'postgres'`, so user-authored migrations don't need to thread
32
+ * target-details or redeclare `targetId`.
33
+ * - `MigrationCLI` — the migration-file CLI entrypoint, re-exported from
34
+ * `@prisma-next/cli/migration-cli`. Loads `prisma-next.config.ts`,
35
+ * assembles a `ControlStack`, and instantiates the migration class.
36
+ * The migration file owns this dependency directly: pulling CLI
37
+ * machinery in at script run time is acceptable because the script's
38
+ * whole purpose is to be invoked from the project that owns the
39
+ * config.
40
+ */
41
+ const BASE_IMPORTS: readonly ImportRequirement[] = [
42
+ { moduleSpecifier: '@prisma-next/target-postgres/migration', symbol: 'Migration' },
43
+ { moduleSpecifier: '@prisma-next/target-postgres/migration', symbol: 'MigrationCLI' },
44
+ ];
45
+
46
+ export function renderCallsToTypeScript(
47
+ calls: ReadonlyArray<PostgresOpFactoryCall>,
48
+ meta: RenderMigrationMeta,
49
+ ): string {
50
+ const imports = buildImports(calls);
51
+ const operationsBody = calls.map((c) => c.renderTypeScript()).join(',\n');
52
+
53
+ return [
54
+ shebangLineFor(detectScaffoldRuntime()),
55
+ imports,
56
+ '',
57
+ 'export default class M extends Migration {',
58
+ buildDescribeMethod(meta),
59
+ ' override get operations() {',
60
+ ' return [',
61
+ indent(operationsBody, 6),
62
+ ' ];',
63
+ ' }',
64
+ '}',
65
+ '',
66
+ 'MigrationCLI.run(import.meta.url, M);',
67
+ '',
68
+ ].join('\n');
69
+ }
70
+
71
+ function buildImports(calls: ReadonlyArray<PostgresOpFactoryCall>): string {
72
+ const requirements: ImportRequirement[] = [...BASE_IMPORTS];
73
+ for (const call of calls) {
74
+ for (const req of call.importRequirements()) {
75
+ requirements.push(req);
76
+ }
77
+ }
78
+ return renderImports(requirements);
79
+ }
80
+
81
+ function buildDescribeMethod(meta: RenderMigrationMeta): string {
82
+ const lines: string[] = [];
83
+ lines.push(' override describe() {');
84
+ lines.push(' return {');
85
+ lines.push(` from: ${JSON.stringify(meta.from)},`);
86
+ lines.push(` to: ${JSON.stringify(meta.to)},`);
87
+ if (meta.kind) {
88
+ lines.push(` kind: ${JSON.stringify(meta.kind)},`);
89
+ }
90
+ if (meta.labels && meta.labels.length > 0) {
91
+ lines.push(` labels: ${jsonToTsSource(meta.labels)},`);
92
+ }
93
+ lines.push(' };');
94
+ lines.push(' }');
95
+ lines.push('');
96
+ return lines.join('\n');
97
+ }
98
+
99
+ function indent(text: string, spaces: number): string {
100
+ const pad = ' '.repeat(spaces);
101
+ return text
102
+ .split('\n')
103
+ .map((line) => (line.trim() ? `${pad}${line}` : line))
104
+ .join('\n');
105
+ }
@@ -1,7 +1,3 @@
1
- import {
2
- normalizeSchemaNativeType,
3
- parsePostgresDefault,
4
- } from '@prisma-next/adapter-postgres/control';
5
1
  import type { ContractMarkerRecord } from '@prisma-next/contract/types';
6
2
  import type {
7
3
  MigrationOperationPolicy,
@@ -22,6 +18,8 @@ import { SqlQueryError } from '@prisma-next/sql-errors';
22
18
  import { ifDefined } from '@prisma-next/utils/defined';
23
19
  import type { Result } from '@prisma-next/utils/result';
24
20
  import { ok, okVoid } from '@prisma-next/utils/result';
21
+ import { parsePostgresDefault } from '../default-normalizer';
22
+ import { normalizeSchemaNativeType } from '../native-type-normalizer';
25
23
  import type { PostgresPlanTargetDetails } from './planner-target-details';
26
24
  import {
27
25
  buildLedgerInsertStatement,
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Postgres native-type normalization.
3
+ *
4
+ * Lives in `target-postgres` because both the migration planner/runner (control
5
+ * plane) and the introspection adapter (control plane) need to normalize raw
6
+ * native-type strings to the same canonical form for comparison.
7
+ */
8
+
9
+ /**
10
+ * Lookup map for simple prefix-based type normalization.
11
+ *
12
+ * Using a Map for O(1) lookup instead of multiple startsWith checks.
13
+ */
14
+ const TYPE_PREFIX_MAP: ReadonlyMap<string, string> = new Map([
15
+ ['varchar', 'character varying'],
16
+ ['bpchar', 'character'],
17
+ ['varbit', 'bit varying'],
18
+ ]);
19
+
20
+ /**
21
+ * Normalizes a Postgres schema native type to its canonical form for comparison.
22
+ *
23
+ * Uses a pre-computed lookup map for simple prefix replacements (O(1))
24
+ * and handles complex temporal type normalization separately.
25
+ */
26
+ export function normalizeSchemaNativeType(nativeType: string): string {
27
+ const trimmed = nativeType.trim();
28
+
29
+ for (const [prefix, replacement] of TYPE_PREFIX_MAP) {
30
+ if (trimmed.startsWith(prefix)) {
31
+ return replacement + trimmed.slice(prefix.length);
32
+ }
33
+ }
34
+
35
+ if (trimmed.includes(' with time zone')) {
36
+ if (trimmed.startsWith('timestamp')) {
37
+ return `timestamptz${trimmed.slice(9).replace(' with time zone', '')}`;
38
+ }
39
+ if (trimmed.startsWith('time')) {
40
+ return `timetz${trimmed.slice(4).replace(' with time zone', '')}`;
41
+ }
42
+ }
43
+
44
+ if (trimmed.includes(' without time zone')) {
45
+ return trimmed.replace(' without time zone', '');
46
+ }
47
+
48
+ return trimmed;
49
+ }
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Shared SQL utility functions for the Postgres target.
3
+ *
4
+ * These functions handle safe SQL identifier and literal escaping
5
+ * with security validations to prevent injection and encoding issues.
6
+ *
7
+ * They live in `target-postgres` because both the control adapter (used at
8
+ * emit time) and the runtime adapter (used at execute time) need the same
9
+ * escaping/validation behavior, and the target package is the natural shared
10
+ * home that both adapters can depend on without crossing planes.
11
+ */
12
+
13
+ export class SqlEscapeError extends Error {
14
+ constructor(
15
+ message: string,
16
+ public readonly value: string,
17
+ public readonly kind: 'identifier' | 'literal',
18
+ ) {
19
+ super(message);
20
+ this.name = 'SqlEscapeError';
21
+ }
22
+ }
23
+
24
+ const MAX_IDENTIFIER_LENGTH = 63;
25
+
26
+ /**
27
+ * Validates and quotes a PostgreSQL identifier (table, column, type, schema names).
28
+ *
29
+ * Security validations:
30
+ * - Rejects null bytes which could cause truncation or unexpected behavior
31
+ * - Rejects empty identifiers
32
+ * - Warns on identifiers exceeding PostgreSQL's 63-character limit
33
+ *
34
+ * @throws {SqlEscapeError} If the identifier contains null bytes or is empty
35
+ */
36
+ export function quoteIdentifier(identifier: string): string {
37
+ if (identifier.length === 0) {
38
+ throw new SqlEscapeError('Identifier cannot be empty', identifier, 'identifier');
39
+ }
40
+ if (identifier.includes('\0')) {
41
+ throw new SqlEscapeError(
42
+ 'Identifier cannot contain null bytes',
43
+ identifier.replace(/\0/g, '\\0'),
44
+ 'identifier',
45
+ );
46
+ }
47
+ if (identifier.length > MAX_IDENTIFIER_LENGTH) {
48
+ console.warn(
49
+ `Identifier "${identifier.slice(0, 20)}..." exceeds PostgreSQL's ${MAX_IDENTIFIER_LENGTH}-character limit and will be truncated`,
50
+ );
51
+ }
52
+ return `"${identifier.replace(/"/g, '""')}"`;
53
+ }
54
+
55
+ /**
56
+ * Escapes a string literal for safe use in SQL statements.
57
+ *
58
+ * Security validations:
59
+ * - Rejects null bytes which could cause truncation or unexpected behavior
60
+ *
61
+ * Note: This assumes PostgreSQL's `standard_conforming_strings` is ON (default since PG 9.1).
62
+ * Backslashes are treated as literal characters, not escape sequences.
63
+ *
64
+ * @throws {SqlEscapeError} If the value contains null bytes
65
+ */
66
+ export function escapeLiteral(value: string): string {
67
+ if (value.includes('\0')) {
68
+ throw new SqlEscapeError(
69
+ 'Literal value cannot contain null bytes',
70
+ value.replace(/\0/g, '\\0'),
71
+ 'literal',
72
+ );
73
+ }
74
+ return value.replace(/'/g, "''");
75
+ }
76
+
77
+ /**
78
+ * Builds a qualified name (schema.object) with proper quoting.
79
+ */
80
+ export function qualifyName(schemaName: string, objectName: string): string {
81
+ return `${quoteIdentifier(schemaName)}.${quoteIdentifier(objectName)}`;
82
+ }
83
+
84
+ /**
85
+ * Validates that an enum value doesn't exceed PostgreSQL's label length limit.
86
+ *
87
+ * PostgreSQL enum labels have a maximum length of NAMEDATALEN-1 (63 bytes by default).
88
+ * Unlike identifiers, enum labels that exceed this limit cause an error rather than
89
+ * silent truncation.
90
+ *
91
+ * @param value - The enum value to validate
92
+ * @param enumTypeName - Name of the enum type (for error messages)
93
+ * @throws {SqlEscapeError} If the value exceeds the maximum length
94
+ */
95
+ export function validateEnumValueLength(value: string, enumTypeName: string): void {
96
+ if (value.length > MAX_IDENTIFIER_LENGTH) {
97
+ throw new SqlEscapeError(
98
+ `Enum value "${value.slice(0, 20)}..." for type "${enumTypeName}" exceeds PostgreSQL's ` +
99
+ `${MAX_IDENTIFIER_LENGTH}-character label limit`,
100
+ value,
101
+ 'literal',
102
+ );
103
+ }
104
+ }
@@ -0,0 +1 @@
1
+ export * from '../core/codec-ids';
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Codec type definitions for the Postgres target.
3
+ *
4
+ * This file exports type-only definitions for codec input/output types.
5
+ * These types are imported by generated `contract.d.ts` files for compile-time
6
+ * type inference.
7
+ *
8
+ * Lives in `target-postgres` because codec types describe the target's value
9
+ * space - both the control adapter (introspection / schema verification) and
10
+ * the runtime adapter (encode/decode) share the same definitions, and the
11
+ * target package is the natural home that both adapters depend on.
12
+ *
13
+ * Runtime codec implementations are provided by the runtime adapter's
14
+ * codec registry, which is built from `core/codecs.ts`.
15
+ */
16
+
17
+ import type { JsonValue } from '@prisma-next/contract/types';
18
+ import type { CodecTypes as CoreCodecTypes } from '../core/codecs';
19
+
20
+ export type CodecTypes = CoreCodecTypes;
21
+
22
+ export type { JsonValue };
23
+ export { dataTypes } from '../core/codecs';
24
+
25
+ type Branded<T, Shape extends Record<string, unknown>> = T & {
26
+ readonly [K in keyof Shape]: Shape[K];
27
+ };
28
+
29
+ type BrandedString<Shape extends Record<string, unknown>> = Branded<string, Shape>;
30
+
31
+ export type Char<N extends number> = BrandedString<{ __charLength: N }>;
32
+ export type Varchar<N extends number> = BrandedString<{ __varcharLength: N }>;
33
+ export type Numeric<P extends number, S extends number | undefined = undefined> = BrandedString<{
34
+ __numericPrecision: P;
35
+ __numericScale: S;
36
+ }>;
37
+ export type Bit<N extends number> = BrandedString<{ __bitLength: N }>;
38
+ export type VarBit<N extends number> = BrandedString<{ __varbitLength: N }>;
39
+ export type Timestamp<P extends number | undefined = undefined> = BrandedString<{
40
+ __timestampPrecision: P;
41
+ }>;
42
+ export type Timestamptz<P extends number | undefined = undefined> = BrandedString<{
43
+ __timestamptzPrecision: P;
44
+ }>;
45
+ export type Time<P extends number | undefined = undefined> = BrandedString<{ __timePrecision: P }>;
46
+ export type Timetz<P extends number | undefined = undefined> = BrandedString<{
47
+ __timetzPrecision: P;
48
+ }>;
49
+ export type Interval<P extends number | undefined = undefined> = BrandedString<{
50
+ __intervalPrecision: P;
51
+ }>;
@@ -0,0 +1,2 @@
1
+ export type { CodecTypes } from '../core/codecs';
2
+ export { codecDefinitions, dataTypes } from '../core/codecs';
@@ -1,86 +1,21 @@
1
- import {
2
- normalizeSchemaNativeType,
3
- parsePostgresDefault,
4
- } from '@prisma-next/adapter-postgres/control';
5
1
  import type { ColumnDefault, Contract } from '@prisma-next/contract/types';
6
2
  import type {
7
3
  SqlControlFamilyInstance,
8
4
  SqlControlTargetDescriptor,
9
5
  } from '@prisma-next/family-sql/control';
10
- import {
11
- collectInitDependencies,
12
- contractToSchemaIR,
13
- extractCodecControlHooks,
14
- } from '@prisma-next/family-sql/control';
15
- import { MigrationDescriptorArraySchema } from '@prisma-next/family-sql/operation-descriptors';
16
- import { verifySqlSchema } from '@prisma-next/family-sql/schema-verify';
6
+ import { contractToSchemaIR, extractCodecControlHooks } from '@prisma-next/family-sql/control';
17
7
  import type { TargetBoundComponentDescriptor } from '@prisma-next/framework-components/components';
18
8
  import type {
19
9
  ControlTargetInstance,
20
10
  MigrationRunner,
21
- OperationDescriptor,
22
11
  } from '@prisma-next/framework-components/control';
23
- import { sql } from '@prisma-next/sql-builder/runtime';
24
12
  import type { SqlStorage, StorageColumn } from '@prisma-next/sql-contract/types';
25
- import type { SqlOperationEntry } from '@prisma-next/sql-operations';
26
13
  import { ifDefined } from '@prisma-next/utils/defined';
27
- import { type } from 'arktype';
28
14
  import { postgresTargetDescriptorMeta } from '../core/descriptor-meta';
29
- import { planDescriptors } from '../core/migrations/descriptor-planner';
30
- import { resolveOperations } from '../core/migrations/operation-resolver';
31
15
  import { createPostgresMigrationPlanner } from '../core/migrations/planner';
32
16
  import { renderDefaultLiteral } from '../core/migrations/planner-ddl-builders';
33
17
  import type { PostgresPlanTargetDetails } from '../core/migrations/planner-target-details';
34
18
  import { createPostgresMigrationRunner } from '../core/migrations/runner';
35
- import { renderDescriptorTypeScript } from '../core/migrations/scaffolding';
36
-
37
- function parseDescriptors(descriptors: readonly OperationDescriptor[]) {
38
- const result = MigrationDescriptorArraySchema([...descriptors]);
39
- if (result instanceof type.errors) {
40
- throw new Error(`Invalid migration descriptors:\n${result.summary}`);
41
- }
42
- return result;
43
- }
44
-
45
- function collectQueryOperationTypes(
46
- frameworkComponents?: ReadonlyArray<TargetBoundComponentDescriptor<'sql', 'postgres'>>,
47
- ): Readonly<Record<string, SqlOperationEntry>> {
48
- const entries: Record<string, SqlOperationEntry> = {};
49
- if (!frameworkComponents) return entries;
50
- for (const component of frameworkComponents) {
51
- const ops = (
52
- component as {
53
- queryOperations?: () => ReadonlyArray<{ method: string } & SqlOperationEntry>;
54
- }
55
- ).queryOperations?.();
56
- if (!ops) continue;
57
- for (const { method, ...entry } of ops) {
58
- entries[method] = entry;
59
- }
60
- }
61
- return entries;
62
- }
63
-
64
- /**
65
- * Creates a SQL DSL client for migration authoring.
66
- * Only the fields used by the builder are populated — operations, codecs,
67
- * and types are unused by sql() and stubbed to satisfy the ExecutionContext type.
68
- */
69
- function createMigrationClient(
70
- toContract: Contract<SqlStorage>,
71
- frameworkComponents?: ReadonlyArray<TargetBoundComponentDescriptor<'sql', 'postgres'>>,
72
- ) {
73
- const queryOperationTypes = collectQueryOperationTypes(frameworkComponents);
74
- // sql() only reads contract, queryOperations.entries(), and applyMutationDefaults
75
- // from the context. The other fields are for runtime execution, not query building.
76
- return sql({
77
- context: {
78
- contract: toContract,
79
- queryOperations: { entries: () => queryOperationTypes },
80
- applyMutationDefaults: () => [],
81
- } as never,
82
- });
83
- }
84
19
 
85
20
  function buildNativeTypeExpander(
86
21
  frameworkComponents?: ReadonlyArray<TargetBoundComponentDescriptor<'sql', 'postgres'>>,
@@ -95,22 +30,15 @@ function buildNativeTypeExpander(
95
30
  readonly typeParams?: Record<string, unknown>;
96
31
  }) => {
97
32
  if (!input.typeParams) return input.nativeType;
98
-
99
- if (!input.codecId) {
100
- throw new Error(
101
- `Column declares typeParams for nativeType "${input.nativeType}" but has no codecId. ` +
102
- 'Ensure the column is associated with a codec.',
103
- );
104
- }
105
-
33
+ // Mirror `renderExpectedNativeType` in verify-sql-schema: when a codec
34
+ // has no `expandNativeType` hook (e.g. `pg/enum@1`, whose typeParams
35
+ // describe the value set rather than a DDL suffix), fall back to the
36
+ // bare native type rather than throwing. Throwing here would reject
37
+ // every plan involving an enum-/values-typed column as soon as its
38
+ // `typeRef` resolved to a `StorageTypeInstance` carrying typeParams.
39
+ if (!input.codecId) return input.nativeType;
106
40
  const hooks = codecHooks.get(input.codecId);
107
- if (!hooks?.expandNativeType) {
108
- throw new Error(
109
- `Column declares typeParams for nativeType "${input.nativeType}" ` +
110
- `but no expandNativeType hook is registered for codecId "${input.codecId}". ` +
111
- 'Ensure the extension providing this codec is included in extensionPacks.',
112
- );
113
- }
41
+ if (!hooks?.expandNativeType) return input.nativeType;
114
42
  return hooks.expandNativeType(input);
115
43
  };
116
44
  }
@@ -141,67 +69,6 @@ const postgresTargetDescriptor: SqlControlTargetDescriptor<'postgres', PostgresP
141
69
  frameworkComponents: frameworkComponents ?? [],
142
70
  });
143
71
  },
144
- planWithDescriptors(context) {
145
- const toContract = context.toContract as Contract<SqlStorage>;
146
- const fromContract = context.fromContract as Contract<SqlStorage> | null;
147
-
148
- // Synthesize schema IR from the fromContract (same as contractToSchema flow)
149
- const expander = buildNativeTypeExpander(context.frameworkComponents);
150
- const fromSchemaIR = contractToSchemaIR(fromContract, {
151
- annotationNamespace: 'pg',
152
- ...ifDefined('expandNativeType', expander),
153
- renderDefault: postgresRenderDefault,
154
- frameworkComponents: context.frameworkComponents ?? [],
155
- });
156
-
157
- // Collect schema issues via verifier
158
- const verifyResult = verifySqlSchema({
159
- contract: toContract,
160
- schema: fromSchemaIR,
161
- strict: true,
162
- typeMetadataRegistry: new Map(),
163
- frameworkComponents: context.frameworkComponents ?? [],
164
- normalizeDefault: parsePostgresDefault,
165
- normalizeNativeType: normalizeSchemaNativeType,
166
- });
167
-
168
- // Run descriptor planner
169
- const planResult = planDescriptors({
170
- issues: verifyResult.schema.issues,
171
- toContract,
172
- fromContract,
173
- });
174
- if (!planResult.ok) {
175
- return { ok: false as const, conflicts: planResult.failure };
176
- }
177
-
178
- return {
179
- ok: true as const,
180
- descriptors: planResult.value.descriptors,
181
- };
182
- },
183
-
184
- resolveDescriptors(descriptors, context) {
185
- const validated = parseDescriptors(descriptors);
186
- const codecHooks = context.frameworkComponents
187
- ? extractCodecControlHooks(context.frameworkComponents)
188
- : new Map();
189
- const dependencies = context.frameworkComponents
190
- ? collectInitDependencies(context.frameworkComponents)
191
- : [];
192
- const toContract = context.toContract as Contract<SqlStorage>;
193
- const db = createMigrationClient(toContract, context.frameworkComponents);
194
- return resolveOperations(validated, {
195
- toContract,
196
- schemaName: context.schemaName ?? 'public',
197
- codecHooks,
198
- dependencies,
199
- db,
200
- });
201
- },
202
- renderDescriptorTypeScript(descriptors, context) {
203
- return renderDescriptorTypeScript(descriptors, context);
204
- },
205
72
  },
206
73
  create(): ControlTargetInstance<'sql', 'postgres'> {
207
74
  return {
@@ -0,0 +1 @@
1
+ export { dataTransform } from '../core/migrations/operations/data-transform';
@@ -0,0 +1 @@
1
+ export { parsePostgresDefault } from '../core/default-normalizer';
@@ -0,0 +1 @@
1
+ export { errorPostgresMigrationStackMissing } from '../core/errors';
@@ -0,0 +1 @@
1
+ export { planIssues } from '../core/migrations/issue-planner';
@@ -0,0 +1,46 @@
1
+ // Re-exported so a Postgres `migration.ts` only needs the single
2
+ // `@prisma-next/target-postgres/migration` import for its base class
3
+ // and the CLI entrypoint, mirroring how `placeholder` is surfaced
4
+ // here. The renderer emits the entrypoint call as
5
+ // `MigrationCLI.run(import.meta.url, M)`.
6
+ export { MigrationCLI } from '@prisma-next/cli/migration-cli';
7
+ // Re-exported so user-edited migration.ts files only need to depend on
8
+ // `@prisma-next/target-postgres/migration` to fill in planner-emitted
9
+ // `placeholder("…")` slots, instead of pulling in `@prisma-next/errors`
10
+ // directly. The planner emits an import from this same module.
11
+ export { placeholder } from '@prisma-next/errors/migration';
12
+ export {
13
+ addColumn,
14
+ alterColumnType,
15
+ dropColumn,
16
+ dropDefault,
17
+ dropNotNull,
18
+ setDefault,
19
+ setNotNull,
20
+ } from '../core/migrations/operations/columns';
21
+ export {
22
+ addForeignKey,
23
+ addPrimaryKey,
24
+ addUnique,
25
+ dropConstraint,
26
+ } from '../core/migrations/operations/constraints';
27
+ export {
28
+ type DataTransformClosure,
29
+ type DataTransformOptions,
30
+ dataTransform,
31
+ } from '../core/migrations/operations/data-transform';
32
+ export { createExtension, createSchema } from '../core/migrations/operations/dependencies';
33
+ export {
34
+ addEnumValues,
35
+ createEnumType,
36
+ dropEnumType,
37
+ renameType,
38
+ } from '../core/migrations/operations/enums';
39
+ export { createIndex, dropIndex } from '../core/migrations/operations/indexes';
40
+ export { rawSql } from '../core/migrations/operations/raw';
41
+ export { createTable, dropTable } from '../core/migrations/operations/tables';
42
+ // Target-owned base class for migrations. Aliased to `Migration` so
43
+ // user-edited migration.ts files (and the renderer's scaffold) read as
44
+ // `class M extends Migration { … }` without having to thread the
45
+ // target-details generic or redeclare `targetId`.
46
+ export { PostgresMigration as Migration } from '../core/migrations/postgres-migration';
@@ -0,0 +1 @@
1
+ export { normalizeSchemaNativeType } from '../core/native-type-normalizer';