@prisma-next/target-postgres 0.12.0-dev.2 → 0.12.0-dev.21

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 (150) hide show
  1. package/dist/{codec-ids-DliyCWPY.d.mts → codec-ids-BEVQ-gO4.d.mts} +1 -1
  2. package/dist/{codec-ids-DliyCWPY.d.mts.map → codec-ids-BEVQ-gO4.d.mts.map} +1 -1
  3. package/dist/codec-ids.d.mts +1 -1
  4. package/dist/{codec-types-BF1DXTPs.d.mts → codec-types-ClVgENiR.d.mts} +2 -2
  5. package/dist/{codec-types-BF1DXTPs.d.mts.map → codec-types-ClVgENiR.d.mts.map} +1 -1
  6. package/dist/codec-types.d.mts +1 -1
  7. package/dist/{codecs-DuP3d9Au.d.mts → codecs-BHrYhAZc.d.mts} +2 -2
  8. package/dist/{codecs-DuP3d9Au.d.mts.map → codecs-BHrYhAZc.d.mts.map} +1 -1
  9. package/dist/codecs.d.mts +1 -1
  10. package/dist/column-type-compatibility-Dzxz_CkP.mjs +11 -0
  11. package/dist/column-type-compatibility-Dzxz_CkP.mjs.map +1 -0
  12. package/dist/column-type-compatibility.d.mts +5 -0
  13. package/dist/column-type-compatibility.d.mts.map +1 -0
  14. package/dist/column-type-compatibility.mjs +2 -0
  15. package/dist/contract-free.d.mts +35 -0
  16. package/dist/contract-free.d.mts.map +1 -0
  17. package/dist/contract-free.mjs +97 -0
  18. package/dist/contract-free.mjs.map +1 -0
  19. package/dist/control.d.mts +1 -1
  20. package/dist/control.mjs +45 -25
  21. package/dist/control.mjs.map +1 -1
  22. package/dist/{data-transform-CRkv2T_U.mjs → data-transform-4QL41_vQ.mjs} +1 -1
  23. package/dist/{data-transform-CRkv2T_U.mjs.map → data-transform-4QL41_vQ.mjs.map} +1 -1
  24. package/dist/{data-transform-CAPmAdxS.d.mts → data-transform-C1ZpoMCt.d.mts} +2 -2
  25. package/dist/{data-transform-CAPmAdxS.d.mts.map → data-transform-C1ZpoMCt.d.mts.map} +1 -1
  26. package/dist/data-transform.d.mts +1 -1
  27. package/dist/data-transform.mjs +1 -1
  28. package/dist/ddl.d.mts +2 -0
  29. package/dist/ddl.mjs +2 -0
  30. package/dist/{default-normalizer-DaAhmzBV.mjs → default-normalizer-DFHtpCPH.mjs} +1 -1
  31. package/dist/{default-normalizer-DaAhmzBV.mjs.map → default-normalizer-DFHtpCPH.mjs.map} +1 -1
  32. package/dist/default-normalizer.mjs +1 -1
  33. package/dist/{descriptor-meta-Dvr_77Z3.mjs → descriptor-meta-BqATo5Dz.mjs} +3 -2
  34. package/dist/descriptor-meta-BqATo5Dz.mjs.map +1 -0
  35. package/dist/{descriptor-meta-runtime-ByjztWgs.mjs → descriptor-meta-runtime-BBL7VdnR.mjs} +2 -2
  36. package/dist/{descriptor-meta-runtime-ByjztWgs.mjs.map → descriptor-meta-runtime-BBL7VdnR.mjs.map} +1 -1
  37. package/dist/{enum-planning-DrNWCtCp.mjs → enum-planning-DHQE3zSH.mjs} +0 -0
  38. package/dist/{enum-planning-DrNWCtCp.mjs.map → enum-planning-DHQE3zSH.mjs.map} +1 -1
  39. package/dist/enum-planning.d.mts +1 -1
  40. package/dist/enum-planning.mjs +1 -1
  41. package/dist/{errors-BbnITmAD.mjs → errors-BhiZYTWZ.mjs} +1 -1
  42. package/dist/{errors-BbnITmAD.mjs.map → errors-BhiZYTWZ.mjs.map} +1 -1
  43. package/dist/errors.mjs +1 -1
  44. package/dist/{issue-planner-2RgYsjUJ.mjs → issue-planner-BrqTKeZa.mjs} +111 -24
  45. package/dist/issue-planner-BrqTKeZa.mjs.map +1 -0
  46. package/dist/issue-planner.d.mts +1 -1
  47. package/dist/issue-planner.d.mts.map +1 -1
  48. package/dist/issue-planner.mjs +1 -1
  49. package/dist/migration.d.mts +3 -3
  50. package/dist/migration.mjs +3 -3
  51. package/dist/{native-type-normalizer-BNEQ9VDs.mjs → native-type-normalizer-BUUe8USD.mjs} +1 -1
  52. package/dist/{native-type-normalizer-BNEQ9VDs.mjs.map → native-type-normalizer-BUUe8USD.mjs.map} +1 -1
  53. package/dist/native-type-normalizer.mjs +1 -1
  54. package/dist/nodes-BS8vS8gv.d.mts +38 -0
  55. package/dist/nodes-BS8vS8gv.d.mts.map +1 -0
  56. package/dist/nodes-BYSqasmC.mjs +42 -0
  57. package/dist/nodes-BYSqasmC.mjs.map +1 -0
  58. package/dist/{op-factory-call-CDlImOF_.d.mts → op-factory-call-B9mYdDex.d.mts} +3 -3
  59. package/dist/{op-factory-call-CDlImOF_.d.mts.map → op-factory-call-B9mYdDex.d.mts.map} +1 -1
  60. package/dist/{op-factory-call-C_K5ibAY.mjs → op-factory-call-D8XePTfV.mjs} +2 -2
  61. package/dist/{op-factory-call-C_K5ibAY.mjs.map → op-factory-call-D8XePTfV.mjs.map} +1 -1
  62. package/dist/op-factory-call.d.mts +1 -1
  63. package/dist/op-factory-call.mjs +1 -1
  64. package/dist/pack.d.mts +4 -2
  65. package/dist/pack.d.mts.map +1 -1
  66. package/dist/pack.mjs +1 -1
  67. package/dist/{planner-CC3r_uNJ.mjs → planner-C_fLowcn.mjs} +20 -13
  68. package/dist/planner-C_fLowcn.mjs.map +1 -0
  69. package/dist/{planner-ddl-builders-DgyqpFji.mjs → planner-ddl-builders-BcRMeGgx.mjs} +3 -3
  70. package/dist/{planner-ddl-builders-DgyqpFji.mjs.map → planner-ddl-builders-BcRMeGgx.mjs.map} +1 -1
  71. package/dist/planner-ddl-builders.d.mts +1 -1
  72. package/dist/planner-ddl-builders.mjs +1 -1
  73. package/dist/{planner-identity-values-nhVj0hp-.mjs → planner-identity-values-DmwlJe_z.mjs} +1 -1
  74. package/dist/{planner-identity-values-nhVj0hp-.mjs.map → planner-identity-values-DmwlJe_z.mjs.map} +1 -1
  75. package/dist/planner-identity-values.mjs +1 -1
  76. package/dist/{planner-produced-postgres-migration-D02NOhVQ.d.mts → planner-produced-postgres-migration-RdjC7aUC.d.mts} +3 -3
  77. package/dist/{planner-produced-postgres-migration-D02NOhVQ.d.mts.map → planner-produced-postgres-migration-RdjC7aUC.d.mts.map} +1 -1
  78. package/dist/{planner-produced-postgres-migration-D_nsXbhl.mjs → planner-produced-postgres-migration-x3hafaGC.mjs} +4 -4
  79. package/dist/{planner-produced-postgres-migration-D_nsXbhl.mjs.map → planner-produced-postgres-migration-x3hafaGC.mjs.map} +1 -1
  80. package/dist/planner-produced-postgres-migration.d.mts +1 -1
  81. package/dist/planner-produced-postgres-migration.mjs +1 -1
  82. package/dist/{planner-schema-lookup-CGxxYfnD.mjs → planner-schema-lookup-DLJbkU7-.mjs} +1 -1
  83. package/dist/{planner-schema-lookup-CGxxYfnD.mjs.map → planner-schema-lookup-DLJbkU7-.mjs.map} +1 -1
  84. package/dist/planner-schema-lookup.mjs +1 -1
  85. package/dist/{planner-sql-checks-BMu3fiMc.mjs → planner-sql-checks-lxWZQCFz.mjs} +3 -3
  86. package/dist/{planner-sql-checks-BMu3fiMc.mjs.map → planner-sql-checks-lxWZQCFz.mjs.map} +1 -1
  87. package/dist/planner-sql-checks.mjs +1 -1
  88. package/dist/{planner-target-details-a_wuOiYf.d.mts → planner-target-details-C1Ye0hb6.d.mts} +1 -1
  89. package/dist/{planner-target-details-a_wuOiYf.d.mts.map → planner-target-details-C1Ye0hb6.d.mts.map} +1 -1
  90. package/dist/planner-target-details.d.mts +1 -1
  91. package/dist/planner.d.mts +1 -1
  92. package/dist/planner.d.mts.map +1 -1
  93. package/dist/planner.mjs +1 -1
  94. package/dist/{postgres-contract-serializer-C0UtIDB8.mjs → postgres-contract-serializer-BYpK6TkY.mjs} +3 -3
  95. package/dist/{postgres-contract-serializer-C0UtIDB8.mjs.map → postgres-contract-serializer-BYpK6TkY.mjs.map} +1 -1
  96. package/dist/{postgres-enum-type-5MBoKsIj.d.mts → postgres-enum-type-Bl6THBPg.d.mts} +4 -1
  97. package/dist/postgres-enum-type-Bl6THBPg.d.mts.map +1 -0
  98. package/dist/{postgres-enum-type-DS-KLVRH.mjs → postgres-enum-type-CaGZ2mfI.mjs} +2 -1
  99. package/dist/postgres-enum-type-CaGZ2mfI.mjs.map +1 -0
  100. package/dist/{postgres-migration-BatbEvU6.mjs → postgres-migration-BDaWGYDu.mjs} +3 -3
  101. package/dist/{postgres-migration-BatbEvU6.mjs.map → postgres-migration-BDaWGYDu.mjs.map} +1 -1
  102. package/dist/{postgres-migration-DRY8V-bQ.d.mts → postgres-migration-DLZtVVDM.d.mts} +3 -3
  103. package/dist/{postgres-migration-DRY8V-bQ.d.mts.map → postgres-migration-DLZtVVDM.d.mts.map} +1 -1
  104. package/dist/{postgres-schema-vp5rvbYg.mjs → postgres-schema-Dky_Jff8.mjs} +3 -3
  105. package/dist/{postgres-schema-vp5rvbYg.mjs.map → postgres-schema-Dky_Jff8.mjs.map} +1 -1
  106. package/dist/{render-ops-XhICjX_P.mjs → render-ops-Da7bQcyv.mjs} +1 -1
  107. package/dist/{render-ops-XhICjX_P.mjs.map → render-ops-Da7bQcyv.mjs.map} +1 -1
  108. package/dist/render-ops.d.mts +1 -1
  109. package/dist/render-ops.mjs +1 -1
  110. package/dist/{render-typescript-K125n-RZ.mjs → render-typescript-DTpTcoNZ.mjs} +1 -1
  111. package/dist/{render-typescript-K125n-RZ.mjs.map → render-typescript-DTpTcoNZ.mjs.map} +1 -1
  112. package/dist/render-typescript.mjs +1 -1
  113. package/dist/runtime.mjs +2 -2
  114. package/dist/{shared-Do_a5ymU.d.mts → shared-wRIzOjdd.d.mts} +2 -2
  115. package/dist/{shared-Do_a5ymU.d.mts.map → shared-wRIzOjdd.d.mts.map} +1 -1
  116. package/dist/{sql-utils-CggjWNij.mjs → sql-utils-DR_F9aHR.mjs} +1 -1
  117. package/dist/{sql-utils-CggjWNij.mjs.map → sql-utils-DR_F9aHR.mjs.map} +1 -1
  118. package/dist/sql-utils.mjs +1 -1
  119. package/dist/{statement-builders-DVI5IVAa.mjs → statement-builders-Cd311EDF.mjs} +16 -4
  120. package/dist/statement-builders-Cd311EDF.mjs.map +1 -0
  121. package/dist/statement-builders.d.mts.map +1 -1
  122. package/dist/statement-builders.mjs +1 -1
  123. package/dist/{tables-C8RrPLUq.mjs → tables-Cuy4VIgu.mjs} +3 -3
  124. package/dist/{tables-C8RrPLUq.mjs.map → tables-Cuy4VIgu.mjs.map} +1 -1
  125. package/dist/{types-O40IcFV9.d.mts → types-DncetAjv.d.mts} +1 -1
  126. package/dist/types-DncetAjv.d.mts.map +1 -0
  127. package/dist/types.d.mts +2 -2
  128. package/dist/types.mjs +2 -2
  129. package/package.json +20 -17
  130. package/src/contract-free/control-bootstrap.ts +55 -0
  131. package/src/contract-free/ddl.ts +32 -0
  132. package/src/core/column-type-compatibility.ts +13 -0
  133. package/src/core/ddl/nodes.ts +59 -0
  134. package/src/core/descriptor-meta.ts +1 -0
  135. package/src/core/migrations/control-policy.ts +144 -0
  136. package/src/core/migrations/issue-planner.ts +12 -1
  137. package/src/core/migrations/planner.ts +23 -5
  138. package/src/core/migrations/runner.ts +66 -27
  139. package/src/core/migrations/statement-builders.ts +18 -3
  140. package/src/core/postgres-enum-type.ts +4 -0
  141. package/src/exports/column-type-compatibility.ts +1 -0
  142. package/src/exports/contract-free.ts +5 -0
  143. package/src/exports/ddl.ts +7 -0
  144. package/dist/descriptor-meta-Dvr_77Z3.mjs.map +0 -1
  145. package/dist/issue-planner-2RgYsjUJ.mjs.map +0 -1
  146. package/dist/planner-CC3r_uNJ.mjs.map +0 -1
  147. package/dist/postgres-enum-type-5MBoKsIj.d.mts.map +0 -1
  148. package/dist/postgres-enum-type-DS-KLVRH.mjs.map +0 -1
  149. package/dist/statement-builders-DVI5IVAa.mjs.map +0 -1
  150. package/dist/types-O40IcFV9.d.mts.map +0 -1
@@ -0,0 +1,144 @@
1
+ import type { Contract } from '@prisma-next/contract/types';
2
+ import type { ControlPolicySubject } from '@prisma-next/family-sql/control';
3
+ import { UNBOUND_NAMESPACE_ID } from '@prisma-next/framework-components/ir';
4
+ import {
5
+ isPostgresEnumStorageEntry,
6
+ type SqlStorage,
7
+ storageTableAt,
8
+ } from '@prisma-next/sql-contract/types';
9
+ import { ifDefined } from '@prisma-next/utils/defined';
10
+ import { isPostgresSchema } from '../postgres-schema';
11
+ import type { PostgresOpFactoryCall } from './op-factory-call';
12
+
13
+ /**
14
+ * Factory calls that create a whole, previously-absent top-level storage
15
+ * object. Used to decide whether `tolerated` permits a call (it only allows
16
+ * creating absent objects, never modifying existing ones).
17
+ *
18
+ * Deliberately an explicit, closed set rather than a `factoryName`
19
+ * create/alter/drop classification: it answers exactly one yes/no question
20
+ * and is fail-closed. Any call not listed here — including future or
21
+ * extension-contributed factories — is treated as NOT object-creation, so it
22
+ * is suppressed under `tolerated` rather than permissively emitted.
23
+ */
24
+ const OBJECT_CREATION_FACTORIES: ReadonlySet<string> = new Set<string>([
25
+ 'createTable',
26
+ 'createEnumType',
27
+ 'createSchema',
28
+ ]);
29
+
30
+ function createsNewTopLevelObject(call: PostgresOpFactoryCall): boolean {
31
+ return OBJECT_CREATION_FACTORIES.has(call.factoryName);
32
+ }
33
+
34
+ function ddlSchemaNameForNamespace(contract: Contract<SqlStorage>, namespaceId: string): string {
35
+ const namespace = contract.storage.namespaces[namespaceId];
36
+ return isPostgresSchema(namespace) ? namespace.ddlSchemaName(contract.storage) : namespaceId;
37
+ }
38
+
39
+ function resolveNamespaceIdForTable(
40
+ contract: Contract<SqlStorage>,
41
+ tableName: string,
42
+ ddlSchemaName: string | undefined,
43
+ ): string {
44
+ for (const namespaceId of Object.keys(contract.storage.namespaces)) {
45
+ const table = storageTableAt(contract.storage, namespaceId, tableName);
46
+ if (!table) continue;
47
+ if (
48
+ ddlSchemaName === undefined ||
49
+ ddlSchemaNameForNamespace(contract, namespaceId) === ddlSchemaName
50
+ ) {
51
+ return namespaceId;
52
+ }
53
+ }
54
+ return UNBOUND_NAMESPACE_ID;
55
+ }
56
+
57
+ function resolveNamespaceIdForDdlSchema(
58
+ contract: Contract<SqlStorage>,
59
+ ddlSchemaName: string,
60
+ ): string {
61
+ for (const namespaceId of Object.keys(contract.storage.namespaces)) {
62
+ const ns = contract.storage.namespaces[namespaceId];
63
+ if (isPostgresSchema(ns) && ns.ddlSchemaName(contract.storage) === ddlSchemaName) {
64
+ return namespaceId;
65
+ }
66
+ if (namespaceId === ddlSchemaName) {
67
+ return namespaceId;
68
+ }
69
+ }
70
+ return UNBOUND_NAMESPACE_ID;
71
+ }
72
+
73
+ interface PostgresCallFields {
74
+ readonly schemaName?: string;
75
+ readonly tableName?: string;
76
+ readonly columnName?: string;
77
+ readonly typeName?: string;
78
+ }
79
+
80
+ function postgresCallFields(call: PostgresOpFactoryCall): PostgresCallFields {
81
+ return {
82
+ ...ifDefined('schemaName', 'schemaName' in call ? call.schemaName : undefined),
83
+ ...ifDefined('tableName', 'tableName' in call ? call.tableName : undefined),
84
+ ...ifDefined('columnName', 'columnName' in call ? call.columnName : undefined),
85
+ ...ifDefined('typeName', 'typeName' in call ? call.typeName : undefined),
86
+ };
87
+ }
88
+
89
+ export function resolvePostgresCallControlPolicySubject(
90
+ call: PostgresOpFactoryCall,
91
+ contract: Contract<SqlStorage>,
92
+ ): ControlPolicySubject | undefined {
93
+ const callFields = postgresCallFields(call);
94
+ const createsNewObject = createsNewTopLevelObject(call);
95
+
96
+ if (call.factoryName === 'createSchema' && callFields.schemaName) {
97
+ return {
98
+ namespaceId: resolveNamespaceIdForDdlSchema(contract, callFields.schemaName),
99
+ createsNewObject,
100
+ };
101
+ }
102
+
103
+ if (callFields.typeName && call.factoryName !== 'addColumn') {
104
+ const namespaceId = callFields.schemaName
105
+ ? resolveNamespaceIdForDdlSchema(contract, callFields.schemaName)
106
+ : UNBOUND_NAMESPACE_ID;
107
+ const ns = contract.storage.namespaces[namespaceId];
108
+ const rawEnum =
109
+ ns && 'enum' in ns && ns.enum != null ? ns.enum[callFields.typeName] : undefined;
110
+ const controlPolicy = isPostgresEnumStorageEntry(rawEnum) ? rawEnum.control : undefined;
111
+ return {
112
+ namespaceId,
113
+ ...ifDefined('explicitNodeControlPolicy', controlPolicy),
114
+ typeName: callFields.typeName,
115
+ createsNewObject,
116
+ };
117
+ }
118
+
119
+ if (callFields.tableName) {
120
+ const namespaceId = resolveNamespaceIdForTable(
121
+ contract,
122
+ callFields.tableName,
123
+ callFields.schemaName,
124
+ );
125
+ const table = storageTableAt(contract.storage, namespaceId, callFields.tableName);
126
+ const tableControlPolicy = table?.control;
127
+ return {
128
+ namespaceId,
129
+ ...ifDefined('explicitNodeControlPolicy', tableControlPolicy),
130
+ table: callFields.tableName,
131
+ ...ifDefined('column', callFields.columnName),
132
+ createsNewObject,
133
+ };
134
+ }
135
+
136
+ if (callFields.schemaName) {
137
+ return {
138
+ namespaceId: resolveNamespaceIdForDdlSchema(contract, callFields.schemaName),
139
+ createsNewObject,
140
+ };
141
+ }
142
+
143
+ return undefined;
144
+ }
@@ -15,6 +15,7 @@ import type {
15
15
  SqlPlannerConflict,
16
16
  SqlPlannerConflictLocation,
17
17
  } from '@prisma-next/family-sql/control';
18
+ import { filterCallsByControlPolicy } from '@prisma-next/family-sql/control';
18
19
  import { arraysEqual } from '@prisma-next/family-sql/schema-verify';
19
20
  import type { TargetBoundComponentDescriptor } from '@prisma-next/framework-components/components';
20
21
  import type { SchemaIssue } from '@prisma-next/framework-components/control';
@@ -29,6 +30,7 @@ import type { SqlSchemaIR } from '@prisma-next/sql-schema-ir/types';
29
30
  import type { Result } from '@prisma-next/utils/result';
30
31
  import { notOk, ok } from '@prisma-next/utils/result';
31
32
  import { PostgresEnumType } from '../postgres-enum-type';
33
+ import { resolvePostgresCallControlPolicySubject } from './control-policy';
32
34
  import {
33
35
  AddColumnCall,
34
36
  AddForeignKeyCall,
@@ -927,5 +929,14 @@ export function planIssues(
927
929
  ...byCategory('foreignKey'),
928
930
  ];
929
931
 
930
- return ok({ calls });
932
+ const filtered = filterCallsByControlPolicy({
933
+ calls,
934
+ contract: options.toContract,
935
+ resolveControlPolicySubject: (call) =>
936
+ resolvePostgresCallControlPolicySubject(call, options.toContract),
937
+ });
938
+
939
+ return ok({
940
+ calls: filtered,
941
+ });
931
942
  }
@@ -6,6 +6,7 @@ import type {
6
6
  } from '@prisma-next/family-sql/control';
7
7
  import {
8
8
  extractCodecControlHooks,
9
+ filterCallsByControlPolicy,
9
10
  planFieldEventOperations,
10
11
  plannerFailure,
11
12
  } from '@prisma-next/family-sql/control';
@@ -18,10 +19,14 @@ import type {
18
19
  SchemaIssue,
19
20
  } from '@prisma-next/framework-components/control';
20
21
  import { UNBOUND_NAMESPACE_ID } from '@prisma-next/framework-components/ir';
22
+ import { blindCast } from '@prisma-next/utils/casts';
23
+ import { postgresColumnsCompatible } from '../column-type-compatibility';
21
24
  import { parsePostgresDefault } from '../default-normalizer';
22
25
  import { normalizeSchemaNativeType } from '../native-type-normalizer';
26
+ import { resolvePostgresCallControlPolicySubject } from './control-policy';
23
27
  import { createResolveExistingEnumValues } from './enum-planning';
24
28
  import { planIssues } from './issue-planner';
29
+ import type { PostgresOpFactoryCall } from './op-factory-call';
25
30
  import { TypeScriptRenderablePostgresMigration } from './planner-produced-postgres-migration';
26
31
  import { postgresPlannerStrategies } from './planner-strategies';
27
32
  import { verifyPostgresNamespacePresence } from './verify-postgres-namespaces';
@@ -52,7 +57,10 @@ export function createPostgresMigrationPlanner(): PostgresMigrationPlanner {
52
57
  * uniformly.
53
58
  */
54
59
  export type PostgresPlanResult =
55
- | { readonly kind: 'success'; readonly plan: TypeScriptRenderablePostgresMigration }
60
+ | {
61
+ readonly kind: 'success';
62
+ readonly plan: TypeScriptRenderablePostgresMigration;
63
+ }
56
64
  | SqlPlannerFailureResult;
57
65
 
58
66
  /**
@@ -163,10 +171,19 @@ export class PostgresMigrationPlanner implements MigrationPlanner<'sql', 'postgr
163
171
  newContract: options.contract,
164
172
  codecHooks,
165
173
  });
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];
174
+ // Codec hook ops are target-agnostic `OpFactoryCall`; Postgres planning
175
+ // lifts them at this integration boundary (see field-event-planner JSDoc).
176
+ const fieldEventPostgresCalls = blindCast<
177
+ readonly PostgresOpFactoryCall[],
178
+ 'Codec hook ops conform to PostgresOpFactoryCall at the app emitter boundary'
179
+ >(fieldEventOps);
180
+ const filteredFieldEvents = filterCallsByControlPolicy({
181
+ calls: fieldEventPostgresCalls,
182
+ contract: options.contract,
183
+ resolveControlPolicySubject: (call) =>
184
+ resolvePostgresCallControlPolicySubject(call, options.contract),
185
+ });
186
+ const calls = [...result.value.calls, ...filteredFieldEvents];
170
187
 
171
188
  return Object.freeze({
172
189
  kind: 'success' as const,
@@ -208,6 +225,7 @@ export class PostgresMigrationPlanner implements MigrationPlanner<'sql', 'postgr
208
225
  frameworkComponents: options.frameworkComponents,
209
226
  normalizeDefault: parsePostgresDefault,
210
227
  normalizeNativeType: normalizeSchemaNativeType,
228
+ columnsCompatible: postgresColumnsCompatible,
211
229
  resolveExistingEnumValues: createResolveExistingEnumValues(options.contract.storage),
212
230
  };
213
231
  const verifyResult = verifySqlSchema(verifyOptions);
@@ -1,4 +1,4 @@
1
- import type { ContractMarkerRecord } from '@prisma-next/contract/types';
1
+ import type { Contract, ContractMarkerRecord } from '@prisma-next/contract/types';
2
2
  import type {
3
3
  MigrationOperationPolicy,
4
4
  SqlControlFamilyInstance,
@@ -19,10 +19,12 @@ import type {
19
19
  } from '@prisma-next/framework-components/control';
20
20
  import { APP_SPACE_ID } from '@prisma-next/framework-components/control';
21
21
  import { UNBOUND_NAMESPACE_ID } from '@prisma-next/framework-components/ir';
22
+ import type { SqlStorage } from '@prisma-next/sql-contract/types';
22
23
  import { SqlQueryError } from '@prisma-next/sql-errors';
23
24
  import { ifDefined } from '@prisma-next/utils/defined';
24
25
  import type { Result } from '@prisma-next/utils/result';
25
26
  import { notOk, ok, okVoid } from '@prisma-next/utils/result';
27
+ import { postgresColumnsCompatible } from '../column-type-compatibility';
26
28
  import { parsePostgresDefault } from '../default-normalizer';
27
29
  import { normalizeSchemaNativeType } from '../native-type-normalizer';
28
30
  import { createResolveExistingEnumValues } from './enum-planning';
@@ -30,9 +32,6 @@ import type { PostgresPlanTargetDetails } from './planner-target-details';
30
32
  import {
31
33
  buildLedgerInsertStatement,
32
34
  buildMergeMarkerStatements,
33
- ensureLedgerTableStatement,
34
- ensureMarkerTableStatement,
35
- ensurePrismaContractSchemaStatement,
36
35
  type SqlStatement,
37
36
  } from './statement-builders';
38
37
 
@@ -107,7 +106,7 @@ class PostgresMigrationRunner implements SqlMigrationRunner<PostgresPlanTargetDe
107
106
  if (!policyCheck.ok) return policyCheck;
108
107
 
109
108
  await this.acquireLock(driver, lockKey);
110
- const ensureResult = await this.ensureControlTables(driver);
109
+ const ensureResult = await this.ensureControlTables(driver, options.destinationContract);
111
110
  if (!ensureResult.ok) return ensureResult;
112
111
  const existingMarker = await this.family.readMarker({ driver, space });
113
112
 
@@ -146,6 +145,7 @@ class PostgresMigrationRunner implements SqlMigrationRunner<PostgresPlanTargetDe
146
145
  frameworkComponents: options.frameworkComponents,
147
146
  normalizeDefault: parsePostgresDefault,
148
147
  normalizeNativeType: normalizeSchemaNativeType,
148
+ columnsCompatible: postgresColumnsCompatible,
149
149
  resolveExistingEnumValues: createResolveExistingEnumValues(
150
150
  options.destinationContract.storage,
151
151
  ),
@@ -166,7 +166,12 @@ class PostgresMigrationRunner implements SqlMigrationRunner<PostgresPlanTargetDe
166
166
 
167
167
  if (!isSelfEdgeNoOp) {
168
168
  await this.upsertMarker(driver, options, existingMarker, space);
169
- await this.recordLedgerEntry(driver, options, existingMarker, applyValue.executedOperations);
169
+ await this.recordLedgerEntries(
170
+ driver,
171
+ options,
172
+ existingMarker,
173
+ applyValue.executedOperations,
174
+ );
170
175
  }
171
176
 
172
177
  return runnerSuccess({
@@ -282,18 +287,22 @@ class PostgresMigrationRunner implements SqlMigrationRunner<PostgresPlanTargetDe
282
287
 
283
288
  private async ensureControlTables(
284
289
  driver: SqlMigrationRunnerExecuteOptions<PostgresPlanTargetDetails>['driver'],
290
+ contract: Contract<SqlStorage>,
285
291
  ): Promise<Result<void, SqlMigrationRunnerFailure>> {
286
- await this.executeStatement(driver, ensurePrismaContractSchemaStatement);
287
- // Pre-1.0 zero-range guardrail: detect a pre-cleanup single-row
288
- // marker table (no `space` column) and surface a structured failure
289
- // rather than silently auto-migrating it to the per-space shape.
290
- // See `specs/framework-mechanism.spec.md § 2`.
292
+ const lowererContext = { contract };
293
+ const bootstrapQueries = this.family.bootstrapControlTableQueries();
294
+ const [schemaQuery, ...tableQueries] = bootstrapQueries;
295
+ if (schemaQuery === undefined) {
296
+ throw new Error('Postgres control-table bootstrap must include CREATE SCHEMA');
297
+ }
298
+ await this.executeStatement(driver, this.family.lowerAst(schemaQuery, lowererContext));
291
299
  const legacyDetection = await this.detectLegacyMarkerShape(driver);
292
300
  if (!legacyDetection.ok) {
293
301
  return legacyDetection;
294
302
  }
295
- await this.executeStatement(driver, ensureMarkerTableStatement);
296
- await this.executeStatement(driver, ensureLedgerTableStatement);
303
+ for (const query of tableQueries) {
304
+ await this.executeStatement(driver, this.family.lowerAst(query, lowererContext));
305
+ }
297
306
  return okVoid();
298
307
  }
299
308
 
@@ -612,25 +621,55 @@ class PostgresMigrationRunner implements SqlMigrationRunner<PostgresPlanTargetDe
612
621
  await this.executeStatement(driver, statement);
613
622
  }
614
623
 
615
- private async recordLedgerEntry(
624
+ private async recordLedgerEntries(
616
625
  driver: SqlMigrationRunnerExecuteOptions<PostgresPlanTargetDetails>['driver'],
617
626
  options: SqlMigrationRunnerExecuteOptions<PostgresPlanTargetDetails>,
618
627
  existingMarker: ContractMarkerRecord | null,
619
628
  executedOperations: readonly SqlMigrationPlanOperation<PostgresPlanTargetDetails>[],
620
629
  ): Promise<void> {
621
- const ledgerStatement = buildLedgerInsertStatement({
622
- originStorageHash: existingMarker?.storageHash ?? null,
623
- originProfileHash: existingMarker?.profileHash ?? null,
624
- destinationStorageHash: options.plan.destination.storageHash,
625
- destinationProfileHash:
626
- options.plan.destination.profileHash ??
627
- options.destinationContract.profileHash ??
628
- options.plan.destination.storageHash,
629
- contractJsonBefore: existingMarker?.contractJson ?? null,
630
- contractJsonAfter: options.destinationContract,
631
- operations: executedOperations,
632
- });
633
- await this.executeStatement(driver, ledgerStatement);
630
+ const plan = options.plan;
631
+ const space = plan.spaceId;
632
+ const destinationProfileHash =
633
+ plan.destination.profileHash ??
634
+ options.destinationContract.profileHash ??
635
+ plan.destination.storageHash;
636
+ const edges = options.migrationEdges;
637
+ const totalEdgeOps = edges.reduce((sum, edge) => sum + edge.operationCount, 0);
638
+ if (totalEdgeOps !== plan.operations.length) {
639
+ throw new Error(
640
+ `Ledger write: plan.operations length (${plan.operations.length}) does not match sum of migrationEdges operationCount (${totalEdgeOps})`,
641
+ );
642
+ }
643
+ // The ledger records the operations as executed — idempotency-skipped ops
644
+ // are substituted with skip records (empty `execute`) by `applyPlan`, so the
645
+ // journal reflects what actually ran rather than the raw plan.
646
+ let offset = 0;
647
+ const lastIndex = edges.length - 1;
648
+ for (const [i, edge] of edges.entries()) {
649
+ const edgeOps = executedOperations.slice(offset, offset + edge.operationCount);
650
+ offset += edge.operationCount;
651
+ const isFirst = i === 0;
652
+ const isLast = i === lastIndex;
653
+ await this.executeStatement(
654
+ driver,
655
+ buildLedgerInsertStatement({
656
+ space,
657
+ migrationName: edge.dirName,
658
+ migrationHash: edge.migrationHash,
659
+ originStorageHash: edge.from === '' ? null : edge.from,
660
+ originProfileHash:
661
+ isFirst && existingMarker?.storageHash === edge.from
662
+ ? (existingMarker.profileHash ?? null)
663
+ : null,
664
+ destinationStorageHash: edge.to,
665
+ destinationProfileHash:
666
+ isLast && edge.to === plan.destination.storageHash ? destinationProfileHash : null,
667
+ contractJsonBefore: isFirst ? (existingMarker?.contractJson ?? null) : null,
668
+ contractJsonAfter: isLast ? options.destinationContract : null,
669
+ operations: edgeOps,
670
+ }),
671
+ );
672
+ }
634
673
  }
635
674
 
636
675
  private async acquireLock(
@@ -40,6 +40,9 @@ export const ensureLedgerTableStatement: SqlStatement = {
40
40
  sql: `create table if not exists prisma_contract.ledger (
41
41
  id bigserial primary key,
42
42
  created_at timestamptz not null default now(),
43
+ space text not null,
44
+ migration_name text not null,
45
+ migration_hash text not null,
43
46
  origin_core_hash text,
44
47
  origin_profile_hash text,
45
48
  destination_core_hash text not null,
@@ -138,6 +141,9 @@ export function buildMergeMarkerStatements(input: MergeMarkerInput): {
138
141
  }
139
142
 
140
143
  export interface LedgerInsertInput {
144
+ readonly space: string;
145
+ readonly migrationName: string;
146
+ readonly migrationHash: string;
141
147
  readonly originStorageHash?: string | null;
142
148
  readonly originProfileHash?: string | null;
143
149
  readonly destinationStorageHash: string;
@@ -150,6 +156,9 @@ export interface LedgerInsertInput {
150
156
  export function buildLedgerInsertStatement(input: LedgerInsertInput): SqlStatement {
151
157
  return {
152
158
  sql: `insert into prisma_contract.ledger (
159
+ space,
160
+ migration_name,
161
+ migration_hash,
153
162
  origin_core_hash,
154
163
  origin_profile_hash,
155
164
  destination_core_hash,
@@ -162,11 +171,17 @@ export function buildLedgerInsertStatement(input: LedgerInsertInput): SqlStateme
162
171
  $2,
163
172
  $3,
164
173
  $4,
165
- $5::jsonb,
166
- $6::jsonb,
167
- $7::jsonb
174
+ $5,
175
+ $6,
176
+ $7,
177
+ $8::jsonb,
178
+ $9::jsonb,
179
+ $10::jsonb
168
180
  )`,
169
181
  params: [
182
+ input.space,
183
+ input.migrationName,
184
+ input.migrationHash,
170
185
  input.originStorageHash ?? null,
171
186
  input.originProfileHash ?? null,
172
187
  input.destinationStorageHash,
@@ -1,3 +1,4 @@
1
+ import type { ControlPolicy } from '@prisma-next/contract/types';
1
2
  import { freezeNode } from '@prisma-next/framework-components/ir';
2
3
  import { SqlNode } from '@prisma-next/sql-contract/types';
3
4
 
@@ -18,6 +19,7 @@ export interface PostgresEnumTypeInput<
18
19
  */
19
20
  readonly nativeType?: string;
20
21
  readonly values: TValues;
22
+ readonly control?: ControlPolicy;
21
23
  }
22
24
 
23
25
  /** Codec id used by Postgres enum-typed columns (text wire format). */
@@ -64,6 +66,7 @@ export class PostgresEnumType<
64
66
  * dispatching through the prototype-only `codecBinding` accessor.
65
67
  */
66
68
  readonly codecId: typeof PG_ENUM_CODEC_ID = PG_ENUM_CODEC_ID;
69
+ declare readonly control?: ControlPolicy;
67
70
 
68
71
  constructor(input: PostgresEnumTypeInput<TName, TValues>) {
69
72
  super();
@@ -73,6 +76,7 @@ export class PostgresEnumType<
73
76
  // `TValues` literal tuple. Cast preserves the caller-supplied
74
77
  // tuple shape so inferred contract types retain literal narrowing.
75
78
  this.values = Object.freeze([...input.values] as unknown as TValues);
79
+ if (input.control !== undefined) this.control = input.control;
76
80
  freezeNode(this);
77
81
  }
78
82
 
@@ -0,0 +1 @@
1
+ export { postgresColumnsCompatible } from '../core/column-type-compatibility';
@@ -0,0 +1,5 @@
1
+ export {
2
+ buildControlTableBootstrapQueries,
3
+ buildSignMarkerBootstrapQueries,
4
+ } from '../contract-free/control-bootstrap';
5
+ export { createSchema, createTable } from '../contract-free/ddl';
@@ -0,0 +1,7 @@
1
+ export {
2
+ type AnyPostgresDdlNode,
3
+ PostgresCreateSchema,
4
+ PostgresCreateTable,
5
+ PostgresDdlNode,
6
+ type PostgresDdlVisitor,
7
+ } from '../core/ddl/nodes';
@@ -1 +0,0 @@
1
- {"version":3,"file":"descriptor-meta-Dvr_77Z3.mjs","names":[],"sources":["../src/core/descriptor-meta.ts"],"sourcesContent":["import type { CodecTypes } from '../exports/codec-types';\nimport {\n postgresAuthoringEntityTypes,\n postgresAuthoringFieldPresets,\n postgresAuthoringTypes,\n} from './authoring';\nimport { postgresTargetDescriptorMetaRuntime } from './descriptor-meta-runtime';\n\nconst postgresTargetDescriptorMetaBase = {\n ...postgresTargetDescriptorMetaRuntime,\n authoring: {\n type: postgresAuthoringTypes,\n field: postgresAuthoringFieldPresets,\n entityTypes: postgresAuthoringEntityTypes,\n },\n} as const;\n\nexport const postgresTargetDescriptorMeta: typeof postgresTargetDescriptorMetaBase & {\n readonly __codecTypes?: CodecTypes;\n} = postgresTargetDescriptorMetaBase;\n"],"mappings":";AAiBA,MAAa,+BAET;CAVF,GAAG;CACH,WAAW;EACT,MAAM;EACN,OAAO;EACP,aAAa;CACf;AAKE"}