@prisma-next/target-postgres 0.12.0-dev.7 → 0.12.0-dev.71

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 (200) hide show
  1. package/dist/{codec-ids-DliyCWPY.d.mts → codec-ids-B1vOchLE.d.mts} +3 -2
  2. package/dist/codec-ids-B1vOchLE.d.mts.map +1 -0
  3. package/dist/{codec-ids-C5qzBqus.mjs → codec-ids-CTikp1if.mjs} +3 -2
  4. package/dist/codec-ids-CTikp1if.mjs.map +1 -0
  5. package/dist/codec-ids.d.mts +2 -2
  6. package/dist/codec-ids.mjs +2 -2
  7. package/dist/{codec-types-BF1DXTPs.d.mts → codec-types-CnFiNML4.d.mts} +8 -9
  8. package/dist/codec-types-CnFiNML4.d.mts.map +1 -0
  9. package/dist/codec-types.d.mts +2 -2
  10. package/dist/{codecs-DuP3d9Au.d.mts → codecs-CBpEv4s5.d.mts} +33 -35
  11. package/dist/codecs-CBpEv4s5.d.mts.map +1 -0
  12. package/dist/codecs.d.mts +1 -1
  13. package/dist/codecs.mjs +37 -2
  14. package/dist/codecs.mjs.map +1 -1
  15. package/dist/contract-free.d.mts +80 -0
  16. package/dist/contract-free.d.mts.map +1 -0
  17. package/dist/contract-free.mjs +117 -0
  18. package/dist/contract-free.mjs.map +1 -0
  19. package/dist/control.d.mts +1 -1
  20. package/dist/control.d.mts.map +1 -1
  21. package/dist/control.mjs +66 -40
  22. package/dist/control.mjs.map +1 -1
  23. package/dist/{data-transform-CRkv2T_U.mjs → data-transform-D25tLeYU.mjs} +1 -1
  24. package/dist/{data-transform-CRkv2T_U.mjs.map → data-transform-D25tLeYU.mjs.map} +1 -1
  25. package/dist/{data-transform-CAPmAdxS.d.mts → data-transform-DGOqcLrf.d.mts} +2 -2
  26. package/dist/{data-transform-CAPmAdxS.d.mts.map → data-transform-DGOqcLrf.d.mts.map} +1 -1
  27. package/dist/data-transform.d.mts +1 -1
  28. package/dist/data-transform.mjs +1 -1
  29. package/dist/ddl-77SyXgFt.mjs +30 -0
  30. package/dist/ddl-77SyXgFt.mjs.map +1 -0
  31. package/dist/ddl.d.mts +2 -0
  32. package/dist/ddl.mjs +2 -0
  33. package/dist/{default-normalizer-DaAhmzBV.mjs → default-normalizer-DyyCHQWs.mjs} +1 -1
  34. package/dist/{default-normalizer-DaAhmzBV.mjs.map → default-normalizer-DyyCHQWs.mjs.map} +1 -1
  35. package/dist/default-normalizer.mjs +1 -1
  36. package/dist/{descriptor-meta-Uu8QaClr.mjs → descriptor-meta-DKmj-IMN.mjs} +3 -2
  37. package/dist/descriptor-meta-DKmj-IMN.mjs.map +1 -0
  38. package/dist/{descriptor-meta-runtime-DMRX39kp.mjs → descriptor-meta-runtime-My8_s4cs.mjs} +2 -2
  39. package/dist/{descriptor-meta-runtime-DMRX39kp.mjs.map → descriptor-meta-runtime-My8_s4cs.mjs.map} +1 -1
  40. package/dist/{enum-planning-DRA9LaMU.mjs → enum-planning-BCyvlFHk.mjs} +0 -0
  41. package/dist/{enum-planning-DRA9LaMU.mjs.map → enum-planning-BCyvlFHk.mjs.map} +1 -1
  42. package/dist/enum-planning.d.mts +1 -1
  43. package/dist/enum-planning.mjs +1 -1
  44. package/dist/{errors-BbnITmAD.mjs → errors-CUk87ByX.mjs} +1 -1
  45. package/dist/{errors-BbnITmAD.mjs.map → errors-CUk87ByX.mjs.map} +1 -1
  46. package/dist/errors.d.mts.map +1 -1
  47. package/dist/errors.mjs +1 -1
  48. package/dist/{issue-planner-BtaL6OfW.mjs → issue-planner-SHnDHfoQ.mjs} +130 -28
  49. package/dist/issue-planner-SHnDHfoQ.mjs.map +1 -0
  50. package/dist/issue-planner.d.mts +1 -1
  51. package/dist/issue-planner.d.mts.map +1 -1
  52. package/dist/issue-planner.mjs +1 -1
  53. package/dist/migration.d.mts +7 -8
  54. package/dist/migration.d.mts.map +1 -1
  55. package/dist/migration.mjs +5 -4
  56. package/dist/migration.mjs.map +1 -1
  57. package/dist/{native-type-normalizer-BNEQ9VDs.mjs → native-type-normalizer-Bc9XJzWC.mjs} +1 -1
  58. package/dist/{native-type-normalizer-BNEQ9VDs.mjs.map → native-type-normalizer-Bc9XJzWC.mjs.map} +1 -1
  59. package/dist/native-type-normalizer.mjs +1 -1
  60. package/dist/nodes-779hmCfL.d.mts +40 -0
  61. package/dist/nodes-779hmCfL.d.mts.map +1 -0
  62. package/dist/nodes-DZk2JZG3.mjs +47 -0
  63. package/dist/nodes-DZk2JZG3.mjs.map +1 -0
  64. package/dist/op-factory-call-D2aAUhmS.mjs +1307 -0
  65. package/dist/op-factory-call-D2aAUhmS.mjs.map +1 -0
  66. package/dist/{op-factory-call-CDlImOF_.d.mts → op-factory-call-DMA86_2D.d.mts} +39 -14
  67. package/dist/op-factory-call-DMA86_2D.d.mts.map +1 -0
  68. package/dist/op-factory-call.d.mts +2 -2
  69. package/dist/op-factory-call.mjs +2 -2
  70. package/dist/pack.d.mts +5 -6
  71. package/dist/pack.d.mts.map +1 -1
  72. package/dist/pack.mjs +1 -1
  73. package/dist/planner-Bv5LV2A-.mjs +344 -0
  74. package/dist/planner-Bv5LV2A-.mjs.map +1 -0
  75. package/dist/{planner-ddl-builders-BNMfSE9r.mjs → planner-ddl-builders-DDyptTt5.mjs} +4 -28
  76. package/dist/planner-ddl-builders-DDyptTt5.mjs.map +1 -0
  77. package/dist/planner-ddl-builders.d.mts +6 -7
  78. package/dist/planner-ddl-builders.d.mts.map +1 -1
  79. package/dist/planner-ddl-builders.mjs +2 -2
  80. package/dist/{planner-identity-values-nhVj0hp-.mjs → planner-identity-values-BIpa5p2I.mjs} +1 -1
  81. package/dist/{planner-identity-values-nhVj0hp-.mjs.map → planner-identity-values-BIpa5p2I.mjs.map} +1 -1
  82. package/dist/planner-identity-values.mjs +1 -1
  83. package/dist/{planner-produced-postgres-migration-D02NOhVQ.d.mts → planner-produced-postgres-migration-B4EDvLdz.d.mts} +5 -4
  84. package/dist/planner-produced-postgres-migration-B4EDvLdz.d.mts.map +1 -0
  85. package/dist/{planner-produced-postgres-migration-D_nsXbhl.mjs → planner-produced-postgres-migration-NSEhWL0L.mjs} +8 -6
  86. package/dist/planner-produced-postgres-migration-NSEhWL0L.mjs.map +1 -0
  87. package/dist/planner-produced-postgres-migration.d.mts +1 -1
  88. package/dist/planner-produced-postgres-migration.mjs +1 -1
  89. package/dist/{planner-schema-lookup-CGxxYfnD.mjs → planner-schema-lookup-CiVaAQP-.mjs} +1 -1
  90. package/dist/{planner-schema-lookup-CGxxYfnD.mjs.map → planner-schema-lookup-CiVaAQP-.mjs.map} +1 -1
  91. package/dist/planner-schema-lookup.mjs +1 -1
  92. package/dist/{planner-sql-checks-CfEiTXoQ.mjs → planner-sql-checks-DAdhnI2c.mjs} +41 -30
  93. package/dist/planner-sql-checks-DAdhnI2c.mjs.map +1 -0
  94. package/dist/planner-sql-checks.d.mts.map +1 -1
  95. package/dist/planner-sql-checks.mjs +1 -1
  96. package/dist/{planner-target-details-a_wuOiYf.d.mts → planner-target-details-CIY6tLeo.d.mts} +2 -2
  97. package/dist/planner-target-details-CIY6tLeo.d.mts.map +1 -0
  98. package/dist/planner-target-details.d.mts +2 -2
  99. package/dist/planner-type-resolution-836DExFN.mjs +20 -0
  100. package/dist/planner-type-resolution-836DExFN.mjs.map +1 -0
  101. package/dist/planner.d.mts +7 -3
  102. package/dist/planner.d.mts.map +1 -1
  103. package/dist/planner.mjs +1 -1
  104. package/dist/{postgres-contract-serializer-BnOboPWs.mjs → postgres-contract-serializer-DYTyXjPf.mjs} +33 -24
  105. package/dist/postgres-contract-serializer-DYTyXjPf.mjs.map +1 -0
  106. package/dist/{postgres-enum-type-CSzsvXrO.d.mts → postgres-enum-type-BVn63a89.d.mts} +1 -1
  107. package/dist/{postgres-enum-type-CSzsvXrO.d.mts.map → postgres-enum-type-BVn63a89.d.mts.map} +1 -1
  108. package/dist/{postgres-enum-type-BMgyxNyy.mjs → postgres-enum-type-DPKqCBem.mjs} +1 -1
  109. package/dist/{postgres-enum-type-BMgyxNyy.mjs.map → postgres-enum-type-DPKqCBem.mjs.map} +1 -1
  110. package/dist/{postgres-migration-BatbEvU6.mjs → postgres-migration-COore9Mz.mjs} +23 -3
  111. package/dist/postgres-migration-COore9Mz.mjs.map +1 -0
  112. package/dist/{postgres-migration-DRY8V-bQ.d.mts → postgres-migration-DZ_gLUOW.d.mts} +25 -3
  113. package/dist/postgres-migration-DZ_gLUOW.d.mts.map +1 -0
  114. package/dist/{postgres-schema-BxAuNFX0.mjs → postgres-schema-BuxCxbvB.mjs} +29 -14
  115. package/dist/postgres-schema-BuxCxbvB.mjs.map +1 -0
  116. package/dist/{render-ops-XhICjX_P.mjs → render-ops-BpjstrKQ.mjs} +4 -3
  117. package/dist/{render-ops-XhICjX_P.mjs.map → render-ops-BpjstrKQ.mjs.map} +1 -1
  118. package/dist/render-ops.d.mts +3 -2
  119. package/dist/render-ops.d.mts.map +1 -1
  120. package/dist/render-ops.mjs +1 -1
  121. package/dist/{render-typescript-K125n-RZ.mjs → render-typescript-KMgosran.mjs} +5 -2
  122. package/dist/render-typescript-KMgosran.mjs.map +1 -0
  123. package/dist/render-typescript.mjs +1 -1
  124. package/dist/runtime.d.mts.map +1 -1
  125. package/dist/runtime.mjs +2 -2
  126. package/dist/{shared-Do_a5ymU.d.mts → shared-DarONYBZ.d.mts} +5 -5
  127. package/dist/{shared-Do_a5ymU.d.mts.map → shared-DarONYBZ.d.mts.map} +1 -1
  128. package/dist/{sql-utils-CggjWNij.mjs → sql-utils-DcfMz4MQ.mjs} +1 -1
  129. package/dist/{sql-utils-CggjWNij.mjs.map → sql-utils-DcfMz4MQ.mjs.map} +1 -1
  130. package/dist/sql-utils.mjs +1 -1
  131. package/dist/{types-O40IcFV9.d.mts → types-BDKkx8MA.d.mts} +1 -1
  132. package/dist/types-BDKkx8MA.d.mts.map +1 -0
  133. package/dist/types.d.mts +16 -11
  134. package/dist/types.d.mts.map +1 -1
  135. package/dist/types.mjs +2 -2
  136. package/package.json +21 -20
  137. package/src/contract-free/columns.ts +49 -0
  138. package/src/contract-free/control-bootstrap.ts +55 -0
  139. package/src/contract-free/ddl.ts +37 -0
  140. package/src/core/ast/table-source.ts +23 -0
  141. package/src/core/codec-ids.ts +1 -0
  142. package/src/core/codecs.ts +44 -0
  143. package/src/core/ddl/nodes.ts +72 -0
  144. package/src/core/descriptor-meta.ts +1 -0
  145. package/src/core/migrations/control-policy.ts +234 -0
  146. package/src/core/migrations/issue-planner.ts +81 -13
  147. package/src/core/migrations/op-factory-call.ts +289 -46
  148. package/src/core/migrations/operations/constraints.ts +79 -10
  149. package/src/core/migrations/operations/dependencies.ts +0 -17
  150. package/src/core/migrations/operations/shared.ts +3 -3
  151. package/src/core/migrations/operations/tables.ts +1 -39
  152. package/src/core/migrations/planner-ddl-builders.ts +4 -46
  153. package/src/core/migrations/planner-produced-postgres-migration.ts +11 -6
  154. package/src/core/migrations/planner-sql-checks.ts +9 -9
  155. package/src/core/migrations/planner-strategies.ts +149 -11
  156. package/src/core/migrations/planner-target-details.ts +2 -1
  157. package/src/core/migrations/planner.ts +66 -8
  158. package/src/core/migrations/postgres-migration.ts +41 -0
  159. package/src/core/migrations/render-ops.ts +7 -2
  160. package/src/core/migrations/render-typescript.ts +5 -1
  161. package/src/core/migrations/runner.ts +78 -50
  162. package/src/core/postgres-contract-serializer.ts +52 -46
  163. package/src/core/postgres-schema.ts +43 -25
  164. package/src/exports/contract-free.ts +7 -0
  165. package/src/exports/control.ts +6 -8
  166. package/src/exports/ddl.ts +7 -0
  167. package/src/exports/migration.ts +11 -2
  168. package/src/exports/op-factory-call.ts +2 -0
  169. package/src/exports/planner-ddl-builders.ts +0 -1
  170. package/dist/codec-ids-C5qzBqus.mjs.map +0 -1
  171. package/dist/codec-ids-DliyCWPY.d.mts.map +0 -1
  172. package/dist/codec-types-BF1DXTPs.d.mts.map +0 -1
  173. package/dist/codecs-DuP3d9Au.d.mts.map +0 -1
  174. package/dist/descriptor-meta-Uu8QaClr.mjs.map +0 -1
  175. package/dist/issue-planner-BtaL6OfW.mjs.map +0 -1
  176. package/dist/op-factory-call-CDlImOF_.d.mts.map +0 -1
  177. package/dist/op-factory-call-ewOd5q6L.mjs +0 -625
  178. package/dist/op-factory-call-ewOd5q6L.mjs.map +0 -1
  179. package/dist/planner-Bjz5pnLa.mjs +0 -177
  180. package/dist/planner-Bjz5pnLa.mjs.map +0 -1
  181. package/dist/planner-ddl-builders-BNMfSE9r.mjs.map +0 -1
  182. package/dist/planner-produced-postgres-migration-D02NOhVQ.d.mts.map +0 -1
  183. package/dist/planner-produced-postgres-migration-D_nsXbhl.mjs.map +0 -1
  184. package/dist/planner-sql-checks-CfEiTXoQ.mjs.map +0 -1
  185. package/dist/planner-target-details-a_wuOiYf.d.mts.map +0 -1
  186. package/dist/postgres-contract-serializer-BnOboPWs.mjs.map +0 -1
  187. package/dist/postgres-migration-BatbEvU6.mjs.map +0 -1
  188. package/dist/postgres-migration-DRY8V-bQ.d.mts.map +0 -1
  189. package/dist/postgres-schema-BxAuNFX0.mjs.map +0 -1
  190. package/dist/render-typescript-K125n-RZ.mjs.map +0 -1
  191. package/dist/statement-builders-DVI5IVAa.mjs +0 -131
  192. package/dist/statement-builders-DVI5IVAa.mjs.map +0 -1
  193. package/dist/statement-builders.d.mts +0 -51
  194. package/dist/statement-builders.d.mts.map +0 -1
  195. package/dist/statement-builders.mjs +0 -2
  196. package/dist/tables-DoA39Yqo.mjs +0 -516
  197. package/dist/tables-DoA39Yqo.mjs.map +0 -1
  198. package/dist/types-O40IcFV9.d.mts.map +0 -1
  199. package/src/core/migrations/statement-builders.ts +0 -183
  200. package/src/exports/statement-builders.ts +0 -8
@@ -1,21 +1,18 @@
1
1
  import type { CodecControlHooks } from '@prisma-next/family-sql/control';
2
2
  import type {
3
- ForeignKey,
4
3
  PostgresEnumStorageEntry,
5
- ReferentialAction,
6
4
  StorageColumn,
7
5
  StorageTable,
8
6
  StorageTypeInstance,
9
7
  } from '@prisma-next/sql-contract/types';
10
8
  import { escapeLiteral, quoteIdentifier } from '../sql-utils';
11
9
  import type { PostgresColumnDefault } from '../types';
12
- import { qualifyTableName } from './planner-sql-checks';
13
10
  import { resolveColumnTypeMetadata } from './planner-type-resolution';
14
11
 
15
12
  export function buildCreateTableSql(
16
13
  qualifiedTableName: string,
17
14
  table: StorageTable,
18
- codecHooks: Map<string, CodecControlHooks>,
15
+ codecHooks: ReadonlyMap<string, CodecControlHooks>,
19
16
  storageTypes: Record<string, StorageTypeInstance | PostgresEnumStorageEntry> = {},
20
17
  ): string {
21
18
  const columnDefinitions = Object.entries(table.columns).map(
@@ -80,7 +77,7 @@ function assertSafeDefaultExpression(expression: string): void {
80
77
  */
81
78
  export function buildColumnTypeSql(
82
79
  column: StorageColumn,
83
- codecHooks: Map<string, CodecControlHooks>,
80
+ codecHooks: ReadonlyMap<string, CodecControlHooks>,
84
81
  storageTypes: Record<string, StorageTypeInstance | PostgresEnumStorageEntry> = {},
85
82
  allowPseudoTypes = true,
86
83
  ): string {
@@ -116,7 +113,7 @@ export function buildColumnTypeSql(
116
113
 
117
114
  function expandParameterizedTypeSql(
118
115
  column: Pick<StorageColumn, 'nativeType' | 'codecId' | 'typeParams'>,
119
- codecHooks: Map<string, CodecControlHooks>,
116
+ codecHooks: ReadonlyMap<string, CodecControlHooks>,
120
117
  ): string | null {
121
118
  if (!column.typeParams) {
122
119
  return null;
@@ -200,7 +197,7 @@ export function buildAddColumnSql(
200
197
  qualifiedTableName: string,
201
198
  columnName: string,
202
199
  column: StorageColumn,
203
- codecHooks: Map<string, CodecControlHooks>,
200
+ codecHooks: ReadonlyMap<string, CodecControlHooks>,
204
201
  temporaryDefault?: string | null,
205
202
  storageTypes: Record<string, StorageTypeInstance | PostgresEnumStorageEntry> = {},
206
203
  ): string {
@@ -216,42 +213,3 @@ export function buildAddColumnSql(
216
213
  ].filter(Boolean);
217
214
  return parts.join(' ');
218
215
  }
219
-
220
- const REFERENTIAL_ACTION_SQL: Record<ReferentialAction, string> = {
221
- noAction: 'NO ACTION',
222
- restrict: 'RESTRICT',
223
- cascade: 'CASCADE',
224
- setNull: 'SET NULL',
225
- setDefault: 'SET DEFAULT',
226
- };
227
-
228
- export function buildForeignKeySql(
229
- schemaName: string,
230
- tableName: string,
231
- fkName: string,
232
- foreignKey: ForeignKey,
233
- ): string {
234
- let sql = `ALTER TABLE ${qualifyTableName(schemaName, tableName)}
235
- ADD CONSTRAINT ${quoteIdentifier(fkName)}
236
- FOREIGN KEY (${foreignKey.source.columns.map(quoteIdentifier).join(', ')})
237
- REFERENCES ${qualifyTableName(schemaName, foreignKey.target.tableName)} (${foreignKey.target.columns
238
- .map(quoteIdentifier)
239
- .join(', ')})`;
240
-
241
- if (foreignKey.onDelete !== undefined) {
242
- const action = REFERENTIAL_ACTION_SQL[foreignKey.onDelete];
243
- if (!action) {
244
- throw new Error(`Unknown referential action for onDelete: ${String(foreignKey.onDelete)}`);
245
- }
246
- sql += `\nON DELETE ${action}`;
247
- }
248
- if (foreignKey.onUpdate !== undefined) {
249
- const action = REFERENTIAL_ACTION_SQL[foreignKey.onUpdate];
250
- if (!action) {
251
- throw new Error(`Unknown referential action for onUpdate: ${String(foreignKey.onUpdate)}`);
252
- }
253
- sql += `\nON UPDATE ${action}`;
254
- }
255
-
256
- return sql;
257
- }
@@ -24,6 +24,7 @@
24
24
  */
25
25
 
26
26
  import type { SqlMigrationPlanOperation } from '@prisma-next/family-sql/control';
27
+ import type { Lowerer } from '@prisma-next/family-sql/control-adapter';
27
28
  import type {
28
29
  MigrationPlanWithAuthoringSurface,
29
30
  OpFactoryCall,
@@ -43,16 +44,23 @@ export class TypeScriptRenderablePostgresMigration
43
44
  readonly #calls: readonly OpFactoryCall[];
44
45
  readonly #meta: MigrationMeta;
45
46
  readonly #spaceId: string;
47
+ readonly #lowerer: Lowerer | undefined;
46
48
 
47
- constructor(calls: readonly OpFactoryCall[], meta: MigrationMeta, spaceId: string) {
49
+ constructor(
50
+ calls: readonly OpFactoryCall[],
51
+ meta: MigrationMeta,
52
+ spaceId: string,
53
+ lowerer?: Lowerer,
54
+ ) {
48
55
  super();
49
56
  this.#calls = calls;
50
57
  this.#meta = meta;
51
58
  this.#spaceId = spaceId;
59
+ this.#lowerer = lowerer;
52
60
  }
53
61
 
54
62
  override get operations(): readonly Op[] {
55
- return renderOps(this.#calls);
63
+ return renderOps(this.#calls, this.#lowerer);
56
64
  }
57
65
 
58
66
  override describe(): MigrationMeta {
@@ -69,9 +77,6 @@ export class TypeScriptRenderablePostgresMigration
69
77
  }
70
78
 
71
79
  renderTypeScript(): string {
72
- return renderCallsToTypeScript(this.#calls, {
73
- from: this.#meta.from,
74
- to: this.#meta.to,
75
- });
80
+ return renderCallsToTypeScript(this.#calls, { from: this.#meta.from, to: this.#meta.to });
76
81
  }
77
82
  }
@@ -20,11 +20,11 @@ import { resolveColumnTypeMetadata } from './planner-type-resolution';
20
20
  * site.
21
21
  */
22
22
  export function qualifyTableName(schema: string, table: string): string {
23
- return postgresCreateNamespace({ id: schema }).qualifyTable(table);
23
+ return postgresCreateNamespace({ id: schema, entries: { table: {} } }).qualifyTable(table);
24
24
  }
25
25
 
26
26
  export function toRegclassLiteral(schema: string, name: string): string {
27
- return postgresCreateNamespace({ id: schema }).regclassLiteral(name);
27
+ return postgresCreateNamespace({ id: schema, entries: { table: {} } }).regclassLiteral(name);
28
28
  }
29
29
 
30
30
  /**
@@ -43,7 +43,7 @@ export function constraintExistsCheck({
43
43
  table?: string;
44
44
  exists?: boolean;
45
45
  }): string {
46
- const namespace = postgresCreateNamespace({ id: schema });
46
+ const namespace = postgresCreateNamespace({ id: schema, entries: { table: {} } });
47
47
  const existsClause = exists ? 'EXISTS' : 'NOT EXISTS';
48
48
  const tableFilter = table
49
49
  ? `AND c.conrelid = to_regclass(${namespace.regclassLiteral(table)})`
@@ -68,7 +68,7 @@ export function columnExistsCheck({
68
68
  column: string;
69
69
  exists?: boolean;
70
70
  }): string {
71
- const namespace = postgresCreateNamespace({ id: schema });
71
+ const namespace = postgresCreateNamespace({ id: schema, entries: { table: {} } });
72
72
  const existsClause = exists ? '' : 'NOT ';
73
73
  return `SELECT ${existsClause}EXISTS (
74
74
  SELECT 1
@@ -90,7 +90,7 @@ export function columnNullabilityCheck({
90
90
  column: string;
91
91
  nullable: boolean;
92
92
  }): string {
93
- const namespace = postgresCreateNamespace({ id: schema });
93
+ const namespace = postgresCreateNamespace({ id: schema, entries: { table: {} } });
94
94
  const expected = nullable ? 'YES' : 'NO';
95
95
  return `SELECT EXISTS (
96
96
  SELECT 1
@@ -111,7 +111,7 @@ export function columnHasNoDefaultCheck(opts: {
111
111
  table: string;
112
112
  column: string;
113
113
  }): string {
114
- const namespace = postgresCreateNamespace({ id: opts.schema });
114
+ const namespace = postgresCreateNamespace({ id: opts.schema, entries: { table: {} } });
115
115
  return `SELECT NOT EXISTS (
116
116
  SELECT 1
117
117
  FROM information_schema.columns
@@ -282,7 +282,7 @@ export function columnTypeCheck({
282
282
  column: string;
283
283
  expectedType: string;
284
284
  }): string {
285
- const namespace = postgresCreateNamespace({ id: schema });
285
+ const namespace = postgresCreateNamespace({ id: schema, entries: { table: {} } });
286
286
  return `SELECT EXISTS (
287
287
  SELECT 1
288
288
  FROM pg_attribute a
@@ -307,7 +307,7 @@ export function columnDefaultExistsCheck({
307
307
  column: string;
308
308
  exists?: boolean;
309
309
  }): string {
310
- const namespace = postgresCreateNamespace({ id: schema });
310
+ const namespace = postgresCreateNamespace({ id: schema, entries: { table: {} } });
311
311
  const nullCheck = exists ? 'IS NOT NULL' : 'IS NULL';
312
312
  return `SELECT EXISTS (
313
313
  SELECT 1
@@ -325,7 +325,7 @@ export function tableHasPrimaryKeyCheck(
325
325
  exists: boolean,
326
326
  constraintName?: string,
327
327
  ): string {
328
- const namespace = postgresCreateNamespace({ id: schema });
328
+ const namespace = postgresCreateNamespace({ id: schema, entries: { table: {} } });
329
329
  const comparison = exists ? '' : 'NOT ';
330
330
  const constraintFilter = constraintName
331
331
  ? `AND c2.relname = '${escapeLiteral(constraintName)}'`
@@ -24,6 +24,7 @@ import type {
24
24
  MigrationOperationPolicy,
25
25
  SqlMigrationPlanOperation,
26
26
  } from '@prisma-next/family-sql/control';
27
+ import { resolveValueSetValues } from '@prisma-next/family-sql/control';
27
28
  import type { TargetBoundComponentDescriptor } from '@prisma-next/framework-components/components';
28
29
  import type { SchemaIssue } from '@prisma-next/framework-components/control';
29
30
  import { UNBOUND_NAMESPACE_ID } from '@prisma-next/framework-components/ir';
@@ -31,10 +32,11 @@ import {
31
32
  isPostgresEnumStorageEntry,
32
33
  type PostgresEnumStorageEntry,
33
34
  type SqlStorage,
34
- type StorageTable,
35
+ StorageTable,
35
36
  type StorageTypeInstance,
36
37
  } from '@prisma-next/sql-contract/types';
37
38
  import type { SqlSchemaIR } from '@prisma-next/sql-schema-ir/types';
39
+ import { blindCast } from '@prisma-next/utils/casts';
38
40
  import { PostgresEnumType } from '../postgres-enum-type';
39
41
  import { isPostgresSchema } from '../postgres-schema';
40
42
  import {
@@ -43,11 +45,13 @@ import {
43
45
  resolveDdlSchemaForNamespaceStorage,
44
46
  } from './enum-planning';
45
47
  import {
48
+ AddCheckConstraintCall,
46
49
  AddColumnCall,
47
50
  AddEnumValuesCall,
48
51
  AlterColumnTypeCall,
49
52
  CreateEnumTypeCall,
50
53
  DataTransformCall,
54
+ DropCheckConstraintCall,
51
55
  DropEnumTypeCall,
52
56
  type PostgresOpFactoryCall,
53
57
  RawSqlCall,
@@ -93,7 +97,7 @@ export function tableAt(
93
97
  ): StorageTable | undefined {
94
98
  // Namespace.tables is typed as Record<string, IRNode> at the interface level;
95
99
  // SQL family namespaces always hold StorageTable instances.
96
- return storage.namespaces[namespaceId]?.tables[tableName] as StorageTable | undefined;
100
+ return storage.namespaces[namespaceId]?.entries.table[tableName] as StorageTable | undefined;
97
101
  }
98
102
 
99
103
  /**
@@ -134,8 +138,8 @@ const DEFAULT_ENUM_NAMESPACE_ID = 'public';
134
138
 
135
139
  function namespaceHasEnum(storage: SqlStorage, namespaceId: string, typeName: string): boolean {
136
140
  const ns = storage.namespaces[namespaceId];
137
- if (!ns || !('enum' in ns) || ns.enum == null) return false;
138
- return (ns.enum as Record<string, PostgresEnumStorageEntry>)[typeName] !== undefined;
141
+ if (!isPostgresSchema(ns)) return false;
142
+ return ns.entries.type[typeName] !== undefined;
139
143
  }
140
144
 
141
145
  /**
@@ -166,7 +170,7 @@ function resolveColumnEnumNamespace(
166
170
 
167
171
  /**
168
172
  * Finds a type entry by explicit namespace coordinate. Namespace types (e.g.
169
- * Postgres enums) live under `storage.namespaces[nsId].enum`. Returns the
173
+ * Postgres enums) live under `storage.namespaces[nsId].entries.type`. Returns the
170
174
  * entry from the named namespace only — never scans other namespaces, so two
171
175
  * namespaces that hold an enum with the same name resolve independently.
172
176
  */
@@ -176,8 +180,12 @@ function locateNamespaceType(
176
180
  typeName: string,
177
181
  ): PostgresEnumStorageEntry | undefined {
178
182
  const ns = storage.namespaces[namespaceId];
179
- if (!ns || !('enum' in ns) || ns.enum == null) return undefined;
180
- return (ns.enum as Record<string, PostgresEnumStorageEntry>)[typeName];
183
+ const raw = ns?.entries['type']?.[typeName];
184
+ if (raw === undefined) return undefined;
185
+ return blindCast<
186
+ PostgresEnumStorageEntry,
187
+ 'postgres type slot carries PostgresEnumStorageEntry at the postgres target layer'
188
+ >(raw);
181
189
  }
182
190
 
183
191
  // ============================================================================
@@ -248,6 +256,7 @@ function buildColumnSpec(
248
256
  name: column,
249
257
  typeSql: buildColumnTypeSql(col, mutableHooks, mutableTypes),
250
258
  defaultSql: buildColumnDefaultSql(col.default, col),
259
+ columnDefault: col.default,
251
260
  nullable: overrides?.nullable ?? col.nullable,
252
261
  };
253
262
  }
@@ -436,7 +445,7 @@ function enumRebuildCallRecipe(
436
445
  // same-named enums in distinct namespaces keep their columns disjoint.
437
446
  const columnRefs: { namespaceId: string; table: string; column: string }[] = [];
438
447
  for (const [nsId, ns] of Object.entries(ctx.toContract.storage.namespaces)) {
439
- for (const [tableName, tableNode] of Object.entries(ns.tables)) {
448
+ for (const [tableName, tableNode] of Object.entries(ns.entries.table)) {
440
449
  const table = tableNode as StorageTable;
441
450
  for (const [columnName, column] of Object.entries(table.columns)) {
442
451
  if (
@@ -639,9 +648,10 @@ export const nativeEnumPlanCallStrategy: CallMigrationStrategy = (issues, ctx) =
639
648
  function collectPostgresEnumTypes(storage: SqlStorage): ReadonlyMap<string, PostgresEnumType> {
640
649
  const result = new Map<string, PostgresEnumType>();
641
650
  for (const [nsId, ns] of Object.entries(storage.namespaces)) {
642
- if (!('enum' in ns) || ns.enum == null) continue;
643
- const nsEnums = ns.enum as Record<string, unknown>;
644
- for (const [name, instance] of Object.entries(nsEnums).sort(([a], [b]) => a.localeCompare(b))) {
651
+ if (!isPostgresSchema(ns)) continue;
652
+ for (const [name, instance] of Object.entries(ns.entries.type).sort(([a], [b]) =>
653
+ a.localeCompare(b),
654
+ )) {
645
655
  if (instance instanceof PostgresEnumType) {
646
656
  result.set(enumCompoundKey(nsId, name), instance);
647
657
  }
@@ -650,6 +660,133 @@ function collectPostgresEnumTypes(storage: SqlStorage): ReadonlyMap<string, Post
650
660
  return result;
651
661
  }
652
662
 
663
+ /**
664
+ * Collects every check constraint from a table in the contract storage.
665
+ * Returns an empty array when the table has no checks or the table is absent.
666
+ */
667
+ function collectContractChecks(
668
+ storage: SqlStorage,
669
+ namespaceId: string,
670
+ tableName: string,
671
+ ): ReadonlyArray<{ name: string; column: string; permittedValues: readonly string[] }> {
672
+ const ns = storage.namespaces[namespaceId];
673
+ const tableRaw = ns?.entries.table[tableName];
674
+ if (!(tableRaw instanceof StorageTable)) return [];
675
+ const checks = tableRaw.checks;
676
+ if (!checks || checks.length === 0) return [];
677
+ return checks.map((c) => ({
678
+ name: c.name,
679
+ column: c.column,
680
+ permittedValues: resolveValueSetValues(
681
+ c.valueSet,
682
+ storage,
683
+ `check "${c.name}" on "${tableName}"`,
684
+ ),
685
+ }));
686
+ }
687
+
688
+ /**
689
+ * Compares two value arrays as unordered sets.
690
+ */
691
+ function checkValueSetsEqual(a: readonly string[], b: readonly string[]): boolean {
692
+ if (a.length !== b.length) return false;
693
+ const bSet = new Set(b);
694
+ return a.every((v) => bSet.has(v));
695
+ }
696
+
697
+ /**
698
+ * Plans check-constraint migrations for `enumType`-authored columns.
699
+ *
700
+ * Walks every namespace's tables in the target contract. For each table that
701
+ * carries `checks`, diffs the contract-expected checks against the live
702
+ * schema's checks:
703
+ *
704
+ * - Check in contract, absent from live DB → `AddCheckConstraintCall`.
705
+ * - Check in live DB, absent from contract → `DropCheckConstraintCall`.
706
+ * - Check on both sides but value sets differ → `DropCheckConstraintCall`
707
+ * then `AddCheckConstraintCall` (drop + recreate; a check predicate cannot
708
+ * be altered in place).
709
+ *
710
+ * Consumes `check_missing`, `check_removed`, and `check_mismatch` issues.
711
+ * Does not touch the native enum path (`nativeEnumPlanCallStrategy` is
712
+ * unchanged).
713
+ */
714
+ export const checkConstraintPlanCallStrategy: CallMigrationStrategy = (issues, ctx) => {
715
+ const calls: PostgresOpFactoryCall[] = [];
716
+ const handledIssueKeys = new Set<string>();
717
+
718
+ for (const [namespaceId, ns] of Object.entries(ctx.toContract.storage.namespaces)) {
719
+ for (const tableName of Object.keys(ns.entries.table)) {
720
+ const contractChecks = collectContractChecks(ctx.toContract.storage, namespaceId, tableName);
721
+ if (contractChecks.length === 0) continue;
722
+
723
+ const schemaTable = ctx.schema.tables[tableName];
724
+ const liveChecks = schemaTable?.checks ?? [];
725
+ const ddlSchema = resolveDdlSchemaForNamespace(ctx, namespaceId);
726
+
727
+ for (const contractCheck of contractChecks) {
728
+ const liveCheck = liveChecks.find((c) => c.name === contractCheck.name);
729
+ const issueKey = `${tableName}${contractCheck.name}`;
730
+ if (!liveCheck) {
731
+ calls.push(
732
+ new AddCheckConstraintCall(
733
+ ddlSchema,
734
+ tableName,
735
+ contractCheck.name,
736
+ contractCheck.column,
737
+ contractCheck.permittedValues,
738
+ ),
739
+ );
740
+ handledIssueKeys.add(issueKey);
741
+ } else if (!checkValueSetsEqual(contractCheck.permittedValues, liveCheck.permittedValues)) {
742
+ calls.push(
743
+ new DropCheckConstraintCall(ddlSchema, tableName, contractCheck.name),
744
+ new AddCheckConstraintCall(
745
+ ddlSchema,
746
+ tableName,
747
+ contractCheck.name,
748
+ contractCheck.column,
749
+ contractCheck.permittedValues,
750
+ ),
751
+ );
752
+ handledIssueKeys.add(issueKey);
753
+ }
754
+ // else: values match — no op needed, still consume the issue
755
+ else {
756
+ handledIssueKeys.add(issueKey);
757
+ }
758
+ }
759
+
760
+ // Emit drops for checks that are live but not in the contract.
761
+ for (const liveCheck of liveChecks) {
762
+ const inContract = contractChecks.some((c) => c.name === liveCheck.name);
763
+ if (!inContract) {
764
+ const issueKey = `${tableName}${liveCheck.name}`;
765
+ calls.push(new DropCheckConstraintCall(ddlSchema, tableName, liveCheck.name));
766
+ handledIssueKeys.add(issueKey);
767
+ }
768
+ }
769
+ }
770
+ }
771
+
772
+ if (calls.length === 0 && handledIssueKeys.size === 0) return { kind: 'no_match' };
773
+
774
+ const remaining = issues.filter((issue) => {
775
+ if (
776
+ issue.kind !== 'check_missing' &&
777
+ issue.kind !== 'check_removed' &&
778
+ issue.kind !== 'check_mismatch'
779
+ ) {
780
+ return true;
781
+ }
782
+ if (!issue.table || !issue.indexOrConstraint) return true;
783
+ const key = `${issue.table}${issue.indexOrConstraint}`;
784
+ return !handledIssueKeys.has(key);
785
+ });
786
+
787
+ return { kind: 'match', issues: remaining, calls };
788
+ };
789
+
653
790
  /**
654
791
  * Dispatches non-enum codec-typed storage types through their codec's
655
792
  * `planTypeOperations` hook (the authoritative source for codec-driven DDL
@@ -922,6 +1059,7 @@ export const postgresPlannerStrategies: readonly CallMigrationStrategy[] = [
922
1059
  typeChangeCallStrategy,
923
1060
  nullableTighteningCallStrategy,
924
1061
  nativeEnumPlanCallStrategy,
1062
+ checkConstraintPlanCallStrategy,
925
1063
  storageTypePlanCallStrategy,
926
1064
  notNullAddColumnCallStrategy,
927
1065
  ];
@@ -8,7 +8,8 @@ export type OperationClass =
8
8
  | 'primaryKey'
9
9
  | 'unique'
10
10
  | 'index'
11
- | 'foreignKey';
11
+ | 'foreignKey'
12
+ | 'checkConstraint';
12
13
 
13
14
  export interface PostgresPlanTargetDetails {
14
15
  readonly schema: string;
@@ -2,13 +2,17 @@ import type { Contract } from '@prisma-next/contract/types';
2
2
  import type {
3
3
  MigrationOperationPolicy,
4
4
  SqlMigrationPlannerPlanOptions,
5
+ SqlPlannerConflict,
5
6
  SqlPlannerFailureResult,
6
7
  } from '@prisma-next/family-sql/control';
7
8
  import {
8
9
  extractCodecControlHooks,
10
+ partitionCallsByControlPolicy,
11
+ partitionIssuesByControlPolicy,
9
12
  planFieldEventOperations,
10
13
  plannerFailure,
11
14
  } from '@prisma-next/family-sql/control';
15
+ import type { Lowerer } from '@prisma-next/family-sql/control-adapter';
12
16
  import { verifySqlSchema } from '@prisma-next/family-sql/schema-verify';
13
17
  import type { TargetBoundComponentDescriptor } from '@prisma-next/framework-components/components';
14
18
  import type {
@@ -18,10 +22,18 @@ import type {
18
22
  SchemaIssue,
19
23
  } from '@prisma-next/framework-components/control';
20
24
  import { UNBOUND_NAMESPACE_ID } from '@prisma-next/framework-components/ir';
25
+ import { blindCast } from '@prisma-next/utils/casts';
21
26
  import { parsePostgresDefault } from '../default-normalizer';
22
27
  import { normalizeSchemaNativeType } from '../native-type-normalizer';
28
+ import {
29
+ formatPostgresControlPolicySubjectLabel,
30
+ resolvePostgresCallControlPolicySubject,
31
+ resolvePostgresIssueControlPolicySubject,
32
+ resolvePostgresIssueCreationFactoryName,
33
+ } from './control-policy';
23
34
  import { createResolveExistingEnumValues } from './enum-planning';
24
35
  import { planIssues } from './issue-planner';
36
+ import type { PostgresOpFactoryCall } from './op-factory-call';
25
37
  import { TypeScriptRenderablePostgresMigration } from './planner-produced-postgres-migration';
26
38
  import { postgresPlannerStrategies } from './planner-strategies';
27
39
  import { verifyPostgresNamespacePresence } from './verify-postgres-namespaces';
@@ -40,8 +52,8 @@ type VerifySqlSchemaOptionsWithComponents = Parameters<typeof verifySqlSchema>[0
40
52
  readonly frameworkComponents: PlannerFrameworkComponents;
41
53
  };
42
54
 
43
- export function createPostgresMigrationPlanner(): PostgresMigrationPlanner {
44
- return new PostgresMigrationPlanner();
55
+ export function createPostgresMigrationPlanner(lowerer: Lowerer): PostgresMigrationPlanner {
56
+ return new PostgresMigrationPlanner(lowerer);
45
57
  }
46
58
 
47
59
  /**
@@ -52,7 +64,11 @@ export function createPostgresMigrationPlanner(): PostgresMigrationPlanner {
52
64
  * uniformly.
53
65
  */
54
66
  export type PostgresPlanResult =
55
- | { readonly kind: 'success'; readonly plan: TypeScriptRenderablePostgresMigration }
67
+ | {
68
+ readonly kind: 'success';
69
+ readonly plan: TypeScriptRenderablePostgresMigration;
70
+ readonly warnings?: readonly SqlPlannerConflict[];
71
+ }
56
72
  | SqlPlannerFailureResult;
57
73
 
58
74
  /**
@@ -72,6 +88,12 @@ export type PostgresPlanResult =
72
88
  * authoring surface.
73
89
  */
74
90
  export class PostgresMigrationPlanner implements MigrationPlanner<'sql', 'postgres'> {
91
+ readonly #lowerer: Lowerer | undefined;
92
+
93
+ constructor(lowerer?: Lowerer) {
94
+ this.#lowerer = lowerer;
95
+ }
96
+
75
97
  plan(options: {
76
98
  readonly contract: unknown;
77
99
  readonly schema: unknown;
@@ -114,6 +136,7 @@ export class PostgresMigrationPlanner implements MigrationPlanner<'sql', 'postgr
114
136
  to: context.toHash,
115
137
  },
116
138
  spaceId,
139
+ this.#lowerer,
117
140
  );
118
141
  }
119
142
 
@@ -131,8 +154,25 @@ export class PostgresMigrationPlanner implements MigrationPlanner<'sql', 'postgr
131
154
  const codecHooks = extractCodecControlHooks(options.frameworkComponents);
132
155
  const storageTypes = options.contract.storage.types ?? {};
133
156
 
134
- const result = planIssues({
157
+ // Input-side control-policy partition. `external` / `observed` subjects
158
+ // — and non-creation issues for `tolerated` subjects — are dropped from
159
+ // the planner's input entirely; the planner never observes them, never
160
+ // diffs them, never generates DDL for them. Suppression warnings are
161
+ // built directly from the suppressed partition (one per subject), so the
162
+ // user-visible message survives even when the planner would have failed
163
+ // to model the subject's live shape.
164
+ const issuePartition = partitionIssuesByControlPolicy({
135
165
  issues: schemaIssues,
166
+ contract: options.contract,
167
+ resolveControlPolicySubject: (issue) =>
168
+ resolvePostgresIssueControlPolicySubject(issue, options.contract),
169
+ resolveCreationFactoryName: resolvePostgresIssueCreationFactoryName,
170
+ formatSubjectLabel: (factoryName, subject) =>
171
+ formatPostgresControlPolicySubjectLabel(factoryName, subject, options.contract),
172
+ });
173
+
174
+ const result = planIssues({
175
+ issues: issuePartition.plannable,
136
176
  toContract: options.contract,
137
177
  // `fromContract` is only supplied by `migration plan`. It is `null` for
138
178
  // `db update` / `db init`, which means data-safety strategies needing
@@ -163,10 +203,26 @@ export class PostgresMigrationPlanner implements MigrationPlanner<'sql', 'postgr
163
203
  newContract: options.contract,
164
204
  codecHooks,
165
205
  });
166
- // Codec-emitted calls already conform to `OpFactoryCall` render +
167
- // toOp + importRequirements ride directly through the same emit path
168
- // as structural ops, no `RawSqlCall` wrap.
169
- const calls = [...result.value.calls, ...fieldEventOps];
206
+ // Codec hook ops are target-agnostic `OpFactoryCall`; Postgres planning
207
+ // lifts them at this integration boundary (see field-event-planner JSDoc).
208
+ const fieldEventPostgresCalls = blindCast<
209
+ readonly PostgresOpFactoryCall[],
210
+ 'Codec hook ops conform to PostgresOpFactoryCall at the app emitter boundary'
211
+ >(fieldEventOps);
212
+ const fieldEventPartition = partitionCallsByControlPolicy({
213
+ calls: fieldEventPostgresCalls,
214
+ contract: options.contract,
215
+ resolveControlPolicySubject: (call) =>
216
+ resolvePostgresCallControlPolicySubject(call, options.contract),
217
+ resolveFactoryName: (call) => call.factoryName,
218
+ formatSubjectLabel: (factoryName, subject) =>
219
+ formatPostgresControlPolicySubjectLabel(factoryName, subject, options.contract),
220
+ });
221
+ const calls = [...result.value.calls, ...fieldEventPartition.kept];
222
+ const warnings: SqlPlannerConflict[] = [
223
+ ...issuePartition.warnings,
224
+ ...fieldEventPartition.warnings,
225
+ ];
170
226
 
171
227
  return Object.freeze({
172
228
  kind: 'success' as const,
@@ -177,7 +233,9 @@ export class PostgresMigrationPlanner implements MigrationPlanner<'sql', 'postgr
177
233
  to: options.contract.storage.storageHash,
178
234
  },
179
235
  options.spaceId,
236
+ this.#lowerer,
180
237
  ),
238
+ ...(warnings.length > 0 ? { warnings: Object.freeze(warnings) } : {}),
181
239
  });
182
240
  }
183
241
 
@@ -3,8 +3,11 @@ import type { SqlMigrationPlanOperation } from '@prisma-next/family-sql/control'
3
3
  import type { SqlControlAdapter } from '@prisma-next/family-sql/control-adapter';
4
4
  import { Migration as SqlMigration } from '@prisma-next/family-sql/migration';
5
5
  import type { ControlStack } from '@prisma-next/framework-components/control';
6
+ import { UNBOUND_NAMESPACE_ID } from '@prisma-next/framework-components/ir';
6
7
  import type { SqlStorage } from '@prisma-next/sql-contract/types';
8
+ import type { DdlColumn, DdlTableConstraint } from '@prisma-next/sql-relational-core/ast';
7
9
  import { errorPostgresMigrationStackMissing } from '../errors';
10
+ import { CreateSchemaCall, CreateTableCall } from './op-factory-call';
8
11
  import { type DataTransformOptions, dataTransform } from './operations/data-transform';
9
12
  import type { PostgresPlanTargetDetails } from './planner-target-details';
10
13
 
@@ -67,4 +70,42 @@ export abstract class PostgresMigration extends SqlMigration<
67
70
  }
68
71
  return dataTransform(contract, name, options, this.controlAdapter);
69
72
  }
73
+
74
+ /**
75
+ * Emit a `CREATE TABLE` migration operation. Builds a typed DDL node from
76
+ * the supplied options and lowers it through the stored control adapter.
77
+ * Throws if no adapter is present (i.e. migration instantiated without a stack).
78
+ */
79
+ protected createTable(options: {
80
+ readonly schema?: string;
81
+ readonly table: string;
82
+ readonly ifNotExists?: boolean;
83
+ readonly columns: readonly DdlColumn[];
84
+ readonly constraints?: readonly DdlTableConstraint[];
85
+ }): SqlMigrationPlanOperation<PostgresPlanTargetDetails> {
86
+ if (!this.controlAdapter) {
87
+ throw errorPostgresMigrationStackMissing();
88
+ }
89
+ return new CreateTableCall(
90
+ options.schema ?? UNBOUND_NAMESPACE_ID,
91
+ options.table,
92
+ options.columns,
93
+ options.constraints,
94
+ ).toOp(this.controlAdapter);
95
+ }
96
+
97
+ /**
98
+ * Emit a `CREATE SCHEMA` migration operation. Builds a typed DDL node from
99
+ * the supplied options and lowers it through the stored control adapter.
100
+ * Throws if no adapter is present (i.e. migration instantiated without a stack).
101
+ */
102
+ protected createSchema(options: {
103
+ readonly schema: string;
104
+ readonly ifNotExists?: boolean;
105
+ }): SqlMigrationPlanOperation<PostgresPlanTargetDetails> {
106
+ if (!this.controlAdapter) {
107
+ throw errorPostgresMigrationStackMissing();
108
+ }
109
+ return new CreateSchemaCall(options.schema).toOp(this.controlAdapter);
110
+ }
70
111
  }