@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.
- package/dist/{codec-ids-DliyCWPY.d.mts → codec-ids-BEVQ-gO4.d.mts} +1 -1
- package/dist/{codec-ids-DliyCWPY.d.mts.map → codec-ids-BEVQ-gO4.d.mts.map} +1 -1
- package/dist/codec-ids.d.mts +1 -1
- package/dist/{codec-types-BF1DXTPs.d.mts → codec-types-ClVgENiR.d.mts} +2 -2
- package/dist/{codec-types-BF1DXTPs.d.mts.map → codec-types-ClVgENiR.d.mts.map} +1 -1
- package/dist/codec-types.d.mts +1 -1
- package/dist/{codecs-DuP3d9Au.d.mts → codecs-BHrYhAZc.d.mts} +2 -2
- package/dist/{codecs-DuP3d9Au.d.mts.map → codecs-BHrYhAZc.d.mts.map} +1 -1
- package/dist/codecs.d.mts +1 -1
- package/dist/column-type-compatibility-Dzxz_CkP.mjs +11 -0
- package/dist/column-type-compatibility-Dzxz_CkP.mjs.map +1 -0
- package/dist/column-type-compatibility.d.mts +5 -0
- package/dist/column-type-compatibility.d.mts.map +1 -0
- package/dist/column-type-compatibility.mjs +2 -0
- package/dist/contract-free.d.mts +35 -0
- package/dist/contract-free.d.mts.map +1 -0
- package/dist/contract-free.mjs +97 -0
- package/dist/contract-free.mjs.map +1 -0
- package/dist/control.d.mts +1 -1
- package/dist/control.mjs +45 -25
- package/dist/control.mjs.map +1 -1
- package/dist/{data-transform-CRkv2T_U.mjs → data-transform-4QL41_vQ.mjs} +1 -1
- package/dist/{data-transform-CRkv2T_U.mjs.map → data-transform-4QL41_vQ.mjs.map} +1 -1
- package/dist/{data-transform-CAPmAdxS.d.mts → data-transform-C1ZpoMCt.d.mts} +2 -2
- package/dist/{data-transform-CAPmAdxS.d.mts.map → data-transform-C1ZpoMCt.d.mts.map} +1 -1
- package/dist/data-transform.d.mts +1 -1
- package/dist/data-transform.mjs +1 -1
- package/dist/ddl.d.mts +2 -0
- package/dist/ddl.mjs +2 -0
- package/dist/{default-normalizer-DaAhmzBV.mjs → default-normalizer-DFHtpCPH.mjs} +1 -1
- package/dist/{default-normalizer-DaAhmzBV.mjs.map → default-normalizer-DFHtpCPH.mjs.map} +1 -1
- package/dist/default-normalizer.mjs +1 -1
- package/dist/{descriptor-meta-Dvr_77Z3.mjs → descriptor-meta-BqATo5Dz.mjs} +3 -2
- package/dist/descriptor-meta-BqATo5Dz.mjs.map +1 -0
- package/dist/{descriptor-meta-runtime-ByjztWgs.mjs → descriptor-meta-runtime-BBL7VdnR.mjs} +2 -2
- package/dist/{descriptor-meta-runtime-ByjztWgs.mjs.map → descriptor-meta-runtime-BBL7VdnR.mjs.map} +1 -1
- package/dist/{enum-planning-DrNWCtCp.mjs → enum-planning-DHQE3zSH.mjs} +0 -0
- package/dist/{enum-planning-DrNWCtCp.mjs.map → enum-planning-DHQE3zSH.mjs.map} +1 -1
- package/dist/enum-planning.d.mts +1 -1
- package/dist/enum-planning.mjs +1 -1
- package/dist/{errors-BbnITmAD.mjs → errors-BhiZYTWZ.mjs} +1 -1
- package/dist/{errors-BbnITmAD.mjs.map → errors-BhiZYTWZ.mjs.map} +1 -1
- package/dist/errors.mjs +1 -1
- package/dist/{issue-planner-2RgYsjUJ.mjs → issue-planner-BrqTKeZa.mjs} +111 -24
- package/dist/issue-planner-BrqTKeZa.mjs.map +1 -0
- package/dist/issue-planner.d.mts +1 -1
- package/dist/issue-planner.d.mts.map +1 -1
- package/dist/issue-planner.mjs +1 -1
- package/dist/migration.d.mts +3 -3
- package/dist/migration.mjs +3 -3
- package/dist/{native-type-normalizer-BNEQ9VDs.mjs → native-type-normalizer-BUUe8USD.mjs} +1 -1
- package/dist/{native-type-normalizer-BNEQ9VDs.mjs.map → native-type-normalizer-BUUe8USD.mjs.map} +1 -1
- package/dist/native-type-normalizer.mjs +1 -1
- package/dist/nodes-BS8vS8gv.d.mts +38 -0
- package/dist/nodes-BS8vS8gv.d.mts.map +1 -0
- package/dist/nodes-BYSqasmC.mjs +42 -0
- package/dist/nodes-BYSqasmC.mjs.map +1 -0
- package/dist/{op-factory-call-CDlImOF_.d.mts → op-factory-call-B9mYdDex.d.mts} +3 -3
- package/dist/{op-factory-call-CDlImOF_.d.mts.map → op-factory-call-B9mYdDex.d.mts.map} +1 -1
- package/dist/{op-factory-call-C_K5ibAY.mjs → op-factory-call-D8XePTfV.mjs} +2 -2
- package/dist/{op-factory-call-C_K5ibAY.mjs.map → op-factory-call-D8XePTfV.mjs.map} +1 -1
- package/dist/op-factory-call.d.mts +1 -1
- package/dist/op-factory-call.mjs +1 -1
- package/dist/pack.d.mts +4 -2
- package/dist/pack.d.mts.map +1 -1
- package/dist/pack.mjs +1 -1
- package/dist/{planner-CC3r_uNJ.mjs → planner-C_fLowcn.mjs} +20 -13
- package/dist/planner-C_fLowcn.mjs.map +1 -0
- package/dist/{planner-ddl-builders-DgyqpFji.mjs → planner-ddl-builders-BcRMeGgx.mjs} +3 -3
- package/dist/{planner-ddl-builders-DgyqpFji.mjs.map → planner-ddl-builders-BcRMeGgx.mjs.map} +1 -1
- package/dist/planner-ddl-builders.d.mts +1 -1
- package/dist/planner-ddl-builders.mjs +1 -1
- package/dist/{planner-identity-values-nhVj0hp-.mjs → planner-identity-values-DmwlJe_z.mjs} +1 -1
- package/dist/{planner-identity-values-nhVj0hp-.mjs.map → planner-identity-values-DmwlJe_z.mjs.map} +1 -1
- package/dist/planner-identity-values.mjs +1 -1
- package/dist/{planner-produced-postgres-migration-D02NOhVQ.d.mts → planner-produced-postgres-migration-RdjC7aUC.d.mts} +3 -3
- package/dist/{planner-produced-postgres-migration-D02NOhVQ.d.mts.map → planner-produced-postgres-migration-RdjC7aUC.d.mts.map} +1 -1
- package/dist/{planner-produced-postgres-migration-D_nsXbhl.mjs → planner-produced-postgres-migration-x3hafaGC.mjs} +4 -4
- package/dist/{planner-produced-postgres-migration-D_nsXbhl.mjs.map → planner-produced-postgres-migration-x3hafaGC.mjs.map} +1 -1
- package/dist/planner-produced-postgres-migration.d.mts +1 -1
- package/dist/planner-produced-postgres-migration.mjs +1 -1
- package/dist/{planner-schema-lookup-CGxxYfnD.mjs → planner-schema-lookup-DLJbkU7-.mjs} +1 -1
- package/dist/{planner-schema-lookup-CGxxYfnD.mjs.map → planner-schema-lookup-DLJbkU7-.mjs.map} +1 -1
- package/dist/planner-schema-lookup.mjs +1 -1
- package/dist/{planner-sql-checks-BMu3fiMc.mjs → planner-sql-checks-lxWZQCFz.mjs} +3 -3
- package/dist/{planner-sql-checks-BMu3fiMc.mjs.map → planner-sql-checks-lxWZQCFz.mjs.map} +1 -1
- package/dist/planner-sql-checks.mjs +1 -1
- package/dist/{planner-target-details-a_wuOiYf.d.mts → planner-target-details-C1Ye0hb6.d.mts} +1 -1
- package/dist/{planner-target-details-a_wuOiYf.d.mts.map → planner-target-details-C1Ye0hb6.d.mts.map} +1 -1
- package/dist/planner-target-details.d.mts +1 -1
- package/dist/planner.d.mts +1 -1
- package/dist/planner.d.mts.map +1 -1
- package/dist/planner.mjs +1 -1
- package/dist/{postgres-contract-serializer-C0UtIDB8.mjs → postgres-contract-serializer-BYpK6TkY.mjs} +3 -3
- package/dist/{postgres-contract-serializer-C0UtIDB8.mjs.map → postgres-contract-serializer-BYpK6TkY.mjs.map} +1 -1
- package/dist/{postgres-enum-type-5MBoKsIj.d.mts → postgres-enum-type-Bl6THBPg.d.mts} +4 -1
- package/dist/postgres-enum-type-Bl6THBPg.d.mts.map +1 -0
- package/dist/{postgres-enum-type-DS-KLVRH.mjs → postgres-enum-type-CaGZ2mfI.mjs} +2 -1
- package/dist/postgres-enum-type-CaGZ2mfI.mjs.map +1 -0
- package/dist/{postgres-migration-BatbEvU6.mjs → postgres-migration-BDaWGYDu.mjs} +3 -3
- package/dist/{postgres-migration-BatbEvU6.mjs.map → postgres-migration-BDaWGYDu.mjs.map} +1 -1
- package/dist/{postgres-migration-DRY8V-bQ.d.mts → postgres-migration-DLZtVVDM.d.mts} +3 -3
- package/dist/{postgres-migration-DRY8V-bQ.d.mts.map → postgres-migration-DLZtVVDM.d.mts.map} +1 -1
- package/dist/{postgres-schema-vp5rvbYg.mjs → postgres-schema-Dky_Jff8.mjs} +3 -3
- package/dist/{postgres-schema-vp5rvbYg.mjs.map → postgres-schema-Dky_Jff8.mjs.map} +1 -1
- package/dist/{render-ops-XhICjX_P.mjs → render-ops-Da7bQcyv.mjs} +1 -1
- package/dist/{render-ops-XhICjX_P.mjs.map → render-ops-Da7bQcyv.mjs.map} +1 -1
- package/dist/render-ops.d.mts +1 -1
- package/dist/render-ops.mjs +1 -1
- package/dist/{render-typescript-K125n-RZ.mjs → render-typescript-DTpTcoNZ.mjs} +1 -1
- package/dist/{render-typescript-K125n-RZ.mjs.map → render-typescript-DTpTcoNZ.mjs.map} +1 -1
- package/dist/render-typescript.mjs +1 -1
- package/dist/runtime.mjs +2 -2
- package/dist/{shared-Do_a5ymU.d.mts → shared-wRIzOjdd.d.mts} +2 -2
- package/dist/{shared-Do_a5ymU.d.mts.map → shared-wRIzOjdd.d.mts.map} +1 -1
- package/dist/{sql-utils-CggjWNij.mjs → sql-utils-DR_F9aHR.mjs} +1 -1
- package/dist/{sql-utils-CggjWNij.mjs.map → sql-utils-DR_F9aHR.mjs.map} +1 -1
- package/dist/sql-utils.mjs +1 -1
- package/dist/{statement-builders-DVI5IVAa.mjs → statement-builders-Cd311EDF.mjs} +16 -4
- package/dist/statement-builders-Cd311EDF.mjs.map +1 -0
- package/dist/statement-builders.d.mts.map +1 -1
- package/dist/statement-builders.mjs +1 -1
- package/dist/{tables-C8RrPLUq.mjs → tables-Cuy4VIgu.mjs} +3 -3
- package/dist/{tables-C8RrPLUq.mjs.map → tables-Cuy4VIgu.mjs.map} +1 -1
- package/dist/{types-O40IcFV9.d.mts → types-DncetAjv.d.mts} +1 -1
- package/dist/types-DncetAjv.d.mts.map +1 -0
- package/dist/types.d.mts +2 -2
- package/dist/types.mjs +2 -2
- package/package.json +20 -17
- package/src/contract-free/control-bootstrap.ts +55 -0
- package/src/contract-free/ddl.ts +32 -0
- package/src/core/column-type-compatibility.ts +13 -0
- package/src/core/ddl/nodes.ts +59 -0
- package/src/core/descriptor-meta.ts +1 -0
- package/src/core/migrations/control-policy.ts +144 -0
- package/src/core/migrations/issue-planner.ts +12 -1
- package/src/core/migrations/planner.ts +23 -5
- package/src/core/migrations/runner.ts +66 -27
- package/src/core/migrations/statement-builders.ts +18 -3
- package/src/core/postgres-enum-type.ts +4 -0
- package/src/exports/column-type-compatibility.ts +1 -0
- package/src/exports/contract-free.ts +5 -0
- package/src/exports/ddl.ts +7 -0
- package/dist/descriptor-meta-Dvr_77Z3.mjs.map +0 -1
- package/dist/issue-planner-2RgYsjUJ.mjs.map +0 -1
- package/dist/planner-CC3r_uNJ.mjs.map +0 -1
- package/dist/postgres-enum-type-5MBoKsIj.d.mts.map +0 -1
- package/dist/postgres-enum-type-DS-KLVRH.mjs.map +0 -1
- package/dist/statement-builders-DVI5IVAa.mjs.map +0 -1
- 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
|
-
|
|
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
|
-
| {
|
|
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
|
|
167
|
-
//
|
|
168
|
-
|
|
169
|
-
|
|
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.
|
|
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
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
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
|
-
|
|
296
|
-
|
|
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
|
|
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
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
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
|
|
166
|
-
$6
|
|
167
|
-
$7
|
|
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';
|
|
@@ -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"}
|