@prisma-next/target-postgres 0.12.0 → 0.13.0-dev.10
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-D9fJ4HP5.d.mts → codec-ids-B1vOchLE.d.mts} +3 -2
- package/dist/codec-ids-B1vOchLE.d.mts.map +1 -0
- package/dist/{codec-ids-C5qzBqus.mjs → codec-ids-CTikp1if.mjs} +3 -2
- package/dist/codec-ids-CTikp1if.mjs.map +1 -0
- package/dist/codec-ids.d.mts +2 -2
- package/dist/codec-ids.mjs +2 -2
- package/dist/{codec-types-CRlHq7Cz.d.mts → codec-types-CnFiNML4.d.mts} +8 -9
- package/dist/codec-types-CnFiNML4.d.mts.map +1 -0
- package/dist/codec-types.d.mts +2 -2
- package/dist/{codecs-Dud5KDNk.d.mts → codecs-CBpEv4s5.d.mts} +33 -35
- package/dist/codecs-CBpEv4s5.d.mts.map +1 -0
- package/dist/codecs.d.mts +1 -1
- package/dist/codecs.mjs +37 -2
- package/dist/codecs.mjs.map +1 -1
- package/dist/contract-free.d.mts +80 -0
- package/dist/contract-free.d.mts.map +1 -0
- package/dist/contract-free.mjs +117 -0
- package/dist/contract-free.mjs.map +1 -0
- package/dist/control.d.mts +1 -1
- package/dist/control.d.mts.map +1 -1
- package/dist/control.mjs +67 -41
- package/dist/control.mjs.map +1 -1
- package/dist/{data-transform-CdtGUWp2.mjs → data-transform-D25tLeYU.mjs} +1 -1
- package/dist/{data-transform-CdtGUWp2.mjs.map → data-transform-D25tLeYU.mjs.map} +1 -1
- package/dist/{data-transform-bmOKkygi.d.mts → data-transform-DGOqcLrf.d.mts} +2 -2
- package/dist/{data-transform-bmOKkygi.d.mts.map → data-transform-DGOqcLrf.d.mts.map} +1 -1
- package/dist/data-transform.d.mts +1 -1
- package/dist/data-transform.mjs +1 -1
- package/dist/ddl-77SyXgFt.mjs +30 -0
- package/dist/ddl-77SyXgFt.mjs.map +1 -0
- package/dist/ddl.d.mts +2 -0
- package/dist/ddl.mjs +2 -0
- package/dist/{default-normalizer-CRscvhS5.mjs → default-normalizer-DyyCHQWs.mjs} +1 -1
- package/dist/{default-normalizer-CRscvhS5.mjs.map → default-normalizer-DyyCHQWs.mjs.map} +1 -1
- package/dist/default-normalizer.mjs +1 -1
- package/dist/descriptor-meta-DKmj-IMN.mjs +14 -0
- package/dist/descriptor-meta-DKmj-IMN.mjs.map +1 -0
- package/dist/{descriptor-meta-DLA2xV6B.mjs → descriptor-meta-runtime-My8_s4cs.mjs} +82 -78
- package/dist/descriptor-meta-runtime-My8_s4cs.mjs.map +1 -0
- package/dist/{enum-planning-Dz0Ye3Lb.mjs → enum-planning-DTMrPLkN.mjs} +0 -0
- package/dist/enum-planning-DTMrPLkN.mjs.map +1 -0
- package/dist/enum-planning.d.mts +14 -8
- package/dist/enum-planning.d.mts.map +1 -1
- package/dist/enum-planning.mjs +2 -2
- package/dist/{errors--zafB5_n.mjs → errors-CUk87ByX.mjs} +1 -1
- package/dist/{errors--zafB5_n.mjs.map → errors-CUk87ByX.mjs.map} +1 -1
- package/dist/errors.d.mts.map +1 -1
- package/dist/errors.mjs +1 -1
- package/dist/{issue-planner-ByQhUzS4.mjs → issue-planner-B0A7RFN2.mjs} +130 -28
- package/dist/issue-planner-B0A7RFN2.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 +7 -8
- package/dist/migration.d.mts.map +1 -1
- package/dist/migration.mjs +5 -4
- package/dist/migration.mjs.map +1 -1
- package/dist/{native-type-normalizer-ClNPq__-.mjs → native-type-normalizer-Bc9XJzWC.mjs} +1 -1
- package/dist/{native-type-normalizer-ClNPq__-.mjs.map → native-type-normalizer-Bc9XJzWC.mjs.map} +1 -1
- package/dist/native-type-normalizer.mjs +1 -1
- package/dist/nodes-779hmCfL.d.mts +40 -0
- package/dist/nodes-779hmCfL.d.mts.map +1 -0
- package/dist/nodes-DZk2JZG3.mjs +47 -0
- package/dist/nodes-DZk2JZG3.mjs.map +1 -0
- package/dist/op-factory-call-Clp7Zr1z.mjs +1307 -0
- package/dist/op-factory-call-Clp7Zr1z.mjs.map +1 -0
- package/dist/{op-factory-call-Drccm_JD.d.mts → op-factory-call-DMA86_2D.d.mts} +39 -14
- package/dist/op-factory-call-DMA86_2D.d.mts.map +1 -0
- package/dist/op-factory-call.d.mts +2 -2
- package/dist/op-factory-call.mjs +2 -2
- package/dist/pack.d.mts +13 -12
- package/dist/pack.d.mts.map +1 -1
- package/dist/pack.mjs +1 -1
- package/dist/planner-DID7RZCQ.mjs +344 -0
- package/dist/planner-DID7RZCQ.mjs.map +1 -0
- package/dist/{planner-ddl-builders-BxRCSn_b.mjs → planner-ddl-builders-Cw2n2llW.mjs} +7 -30
- package/dist/planner-ddl-builders-Cw2n2llW.mjs.map +1 -0
- package/dist/planner-ddl-builders.d.mts +6 -7
- package/dist/planner-ddl-builders.d.mts.map +1 -1
- package/dist/planner-ddl-builders.mjs +2 -2
- package/dist/{planner-identity-values-ojX-6cPV.mjs → planner-identity-values-BIpa5p2I.mjs} +1 -1
- package/dist/{planner-identity-values-ojX-6cPV.mjs.map → planner-identity-values-BIpa5p2I.mjs.map} +1 -1
- package/dist/planner-identity-values.mjs +1 -1
- package/dist/{planner-produced-postgres-migration-p-VKkCia.d.mts → planner-produced-postgres-migration-B4EDvLdz.d.mts} +5 -4
- package/dist/planner-produced-postgres-migration-B4EDvLdz.d.mts.map +1 -0
- package/dist/{planner-produced-postgres-migration-N1yqYg20.mjs → planner-produced-postgres-migration-B8gZBPOR.mjs} +8 -6
- package/dist/planner-produced-postgres-migration-B8gZBPOR.mjs.map +1 -0
- package/dist/planner-produced-postgres-migration.d.mts +1 -1
- package/dist/planner-produced-postgres-migration.mjs +1 -1
- package/dist/{planner-schema-lookup-BGyukuzG.mjs → planner-schema-lookup-CiVaAQP-.mjs} +1 -1
- package/dist/{planner-schema-lookup-BGyukuzG.mjs.map → planner-schema-lookup-CiVaAQP-.mjs.map} +1 -1
- package/dist/planner-schema-lookup.mjs +1 -1
- package/dist/{planner-sql-checks-D3H-xOO1.mjs → planner-sql-checks-DRD5E8A1.mjs} +41 -30
- package/dist/planner-sql-checks-DRD5E8A1.mjs.map +1 -0
- package/dist/planner-sql-checks.d.mts.map +1 -1
- package/dist/planner-sql-checks.mjs +1 -1
- package/dist/{planner-target-details-CIj61DUj.d.mts → planner-target-details-CIY6tLeo.d.mts} +2 -2
- package/dist/planner-target-details-CIY6tLeo.d.mts.map +1 -0
- package/dist/planner-target-details.d.mts +2 -2
- package/dist/planner-type-resolution-836DExFN.mjs +20 -0
- package/dist/planner-type-resolution-836DExFN.mjs.map +1 -0
- package/dist/planner.d.mts +7 -3
- package/dist/planner.d.mts.map +1 -1
- package/dist/planner.mjs +1 -1
- package/dist/{postgres-contract-serializer-YJvjKrmo.mjs → postgres-contract-serializer-DCg7YaP3.mjs} +40 -24
- package/dist/postgres-contract-serializer-DCg7YaP3.mjs.map +1 -0
- package/dist/{postgres-enum-type-CNhPTDhy.d.mts → postgres-enum-type-BVn63a89.d.mts} +4 -1
- package/dist/postgres-enum-type-BVn63a89.d.mts.map +1 -0
- package/dist/{postgres-enum-type-DS-KLVRH.mjs → postgres-enum-type-DPKqCBem.mjs} +2 -1
- package/dist/postgres-enum-type-DPKqCBem.mjs.map +1 -0
- package/dist/{postgres-migration-uADmx0dW.mjs → postgres-migration-BCQEjFHK.mjs} +23 -3
- package/dist/postgres-migration-BCQEjFHK.mjs.map +1 -0
- package/dist/{postgres-migration-Fd4fQkBw.d.mts → postgres-migration-DZ_gLUOW.d.mts} +25 -3
- package/dist/postgres-migration-DZ_gLUOW.d.mts.map +1 -0
- package/dist/{postgres-schema-Bm7vjlOv.mjs → postgres-schema-BVTA2QH7.mjs} +41 -15
- package/dist/postgres-schema-BVTA2QH7.mjs.map +1 -0
- package/dist/{render-ops-BC2PtCkj.mjs → render-ops-BpjstrKQ.mjs} +4 -3
- package/dist/{render-ops-BC2PtCkj.mjs.map → render-ops-BpjstrKQ.mjs.map} +1 -1
- package/dist/render-ops.d.mts +3 -2
- package/dist/render-ops.d.mts.map +1 -1
- package/dist/render-ops.mjs +1 -1
- package/dist/{render-typescript-CPk7hhWH.mjs → render-typescript-KMgosran.mjs} +5 -2
- package/dist/render-typescript-KMgosran.mjs.map +1 -0
- package/dist/render-typescript.mjs +1 -1
- package/dist/runtime.d.mts.map +1 -1
- package/dist/runtime.mjs +3 -3
- package/dist/runtime.mjs.map +1 -1
- package/dist/{shared-ByhSooBS.d.mts → shared-DarONYBZ.d.mts} +5 -5
- package/dist/{shared-ByhSooBS.d.mts.map → shared-DarONYBZ.d.mts.map} +1 -1
- package/dist/{sql-utils-B_ruBD-M.mjs → sql-utils-DcfMz4MQ.mjs} +1 -1
- package/dist/{sql-utils-B_ruBD-M.mjs.map → sql-utils-DcfMz4MQ.mjs.map} +1 -1
- package/dist/sql-utils.mjs +1 -1
- package/dist/{types-D-XIpzHA.d.mts → types-BDKkx8MA.d.mts} +1 -1
- package/dist/types-BDKkx8MA.d.mts.map +1 -0
- package/dist/types.d.mts +18 -11
- package/dist/types.d.mts.map +1 -1
- package/dist/types.mjs +2 -2
- package/package.json +21 -20
- package/src/contract-free/columns.ts +49 -0
- package/src/contract-free/control-bootstrap.ts +55 -0
- package/src/contract-free/ddl.ts +37 -0
- package/src/core/ast/table-source.ts +23 -0
- package/src/core/authoring.ts +1 -1
- package/src/core/codec-ids.ts +1 -0
- package/src/core/codecs.ts +44 -0
- package/src/core/ddl/nodes.ts +72 -0
- package/src/core/descriptor-meta-runtime.ts +28 -0
- package/src/core/descriptor-meta.ts +3 -6
- package/src/core/migrations/control-policy.ts +234 -0
- package/src/core/migrations/enum-planning.ts +33 -29
- package/src/core/migrations/issue-planner.ts +81 -13
- package/src/core/migrations/op-factory-call.ts +289 -46
- package/src/core/migrations/operations/constraints.ts +79 -10
- package/src/core/migrations/operations/dependencies.ts +0 -17
- package/src/core/migrations/operations/shared.ts +3 -3
- package/src/core/migrations/operations/tables.ts +1 -39
- package/src/core/migrations/planner-ddl-builders.ts +7 -48
- package/src/core/migrations/planner-produced-postgres-migration.ts +11 -6
- package/src/core/migrations/planner-sql-checks.ts +9 -9
- package/src/core/migrations/planner-strategies.ts +149 -11
- package/src/core/migrations/planner-target-details.ts +2 -1
- package/src/core/migrations/planner.ts +66 -8
- package/src/core/migrations/postgres-migration.ts +41 -0
- package/src/core/migrations/render-ops.ts +7 -2
- package/src/core/migrations/render-typescript.ts +5 -1
- package/src/core/migrations/runner.ts +78 -50
- package/src/core/postgres-contract-serializer.ts +66 -46
- package/src/core/postgres-enum-type.ts +4 -0
- package/src/core/postgres-schema.ts +56 -19
- package/src/exports/contract-free.ts +7 -0
- package/src/exports/control.ts +15 -24
- package/src/exports/ddl.ts +7 -0
- package/src/exports/enum-planning.ts +0 -1
- package/src/exports/migration.ts +11 -2
- package/src/exports/op-factory-call.ts +2 -0
- package/src/exports/planner-ddl-builders.ts +0 -1
- package/src/exports/runtime.ts +2 -2
- package/dist/codec-ids-C5qzBqus.mjs.map +0 -1
- package/dist/codec-ids-D9fJ4HP5.d.mts.map +0 -1
- package/dist/codec-types-CRlHq7Cz.d.mts.map +0 -1
- package/dist/codecs-Dud5KDNk.d.mts.map +0 -1
- package/dist/descriptor-meta-DLA2xV6B.mjs.map +0 -1
- package/dist/enum-planning-Dz0Ye3Lb.mjs.map +0 -1
- package/dist/issue-planner-ByQhUzS4.mjs.map +0 -1
- package/dist/op-factory-call-B0WNg30h.mjs +0 -625
- package/dist/op-factory-call-B0WNg30h.mjs.map +0 -1
- package/dist/op-factory-call-Drccm_JD.d.mts.map +0 -1
- package/dist/planner-ClF0y0YR.mjs +0 -177
- package/dist/planner-ClF0y0YR.mjs.map +0 -1
- package/dist/planner-ddl-builders-BxRCSn_b.mjs.map +0 -1
- package/dist/planner-produced-postgres-migration-N1yqYg20.mjs.map +0 -1
- package/dist/planner-produced-postgres-migration-p-VKkCia.d.mts.map +0 -1
- package/dist/planner-sql-checks-D3H-xOO1.mjs.map +0 -1
- package/dist/planner-target-details-CIj61DUj.d.mts.map +0 -1
- package/dist/postgres-contract-serializer-YJvjKrmo.mjs.map +0 -1
- package/dist/postgres-enum-type-CNhPTDhy.d.mts.map +0 -1
- package/dist/postgres-enum-type-DS-KLVRH.mjs.map +0 -1
- package/dist/postgres-migration-Fd4fQkBw.d.mts.map +0 -1
- package/dist/postgres-migration-uADmx0dW.mjs.map +0 -1
- package/dist/postgres-schema-Bm7vjlOv.mjs.map +0 -1
- package/dist/render-typescript-CPk7hhWH.mjs.map +0 -1
- package/dist/statement-builders-vImtdfmM.mjs +0 -131
- package/dist/statement-builders-vImtdfmM.mjs.map +0 -1
- package/dist/statement-builders.d.mts +0 -51
- package/dist/statement-builders.d.mts.map +0 -1
- package/dist/statement-builders.mjs +0 -2
- package/dist/tables-Dcb2q9zV.mjs +0 -516
- package/dist/tables-Dcb2q9zV.mjs.map +0 -1
- package/dist/types-D-XIpzHA.d.mts.map +0 -1
- package/src/core/migrations/statement-builders.ts +0 -183
- package/src/exports/statement-builders.ts +0 -8
|
@@ -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
|
-
| {
|
|
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
|
-
|
|
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
|
|
167
|
-
//
|
|
168
|
-
|
|
169
|
-
|
|
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
|
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { SqlMigrationPlanOperation } from '@prisma-next/family-sql/control';
|
|
2
|
+
import type { Lowerer } from '@prisma-next/family-sql/control-adapter';
|
|
2
3
|
import type { OpFactoryCall } from '@prisma-next/framework-components/control';
|
|
4
|
+
import { blindCast } from '@prisma-next/utils/casts';
|
|
3
5
|
import type { PostgresPlanTargetDetails } from './planner-target-details';
|
|
4
6
|
|
|
5
7
|
type Op = SqlMigrationPlanOperation<PostgresPlanTargetDetails>;
|
|
@@ -23,9 +25,12 @@ function assertPostgresOp(
|
|
|
23
25
|
}
|
|
24
26
|
}
|
|
25
27
|
|
|
26
|
-
export function renderOps(calls: readonly OpFactoryCall[]): Op[] {
|
|
28
|
+
export function renderOps(calls: readonly OpFactoryCall[], lowerer?: Lowerer): Op[] {
|
|
27
29
|
return calls.map((c) => {
|
|
28
|
-
const op =
|
|
30
|
+
const op = blindCast<
|
|
31
|
+
{ toOp(lowerer?: Lowerer): ReturnType<OpFactoryCall['toOp']> },
|
|
32
|
+
'PG OpFactoryCall.toOp accepts an optional Lowerer; the framework interface omits it because not all targets need a lowerer — the PG target overrides with this extended signature'
|
|
33
|
+
>(c).toOp(lowerer);
|
|
29
34
|
assertPostgresOp(op, c.factoryName);
|
|
30
35
|
return op;
|
|
31
36
|
});
|
|
@@ -46,7 +46,7 @@ export function renderCallsToTypeScript(
|
|
|
46
46
|
meta: RenderMigrationMeta,
|
|
47
47
|
): string {
|
|
48
48
|
const imports = buildImports(calls);
|
|
49
|
-
const operationsBody = calls.map((c) => c
|
|
49
|
+
const operationsBody = calls.map((c) => renderCall(c)).join(',\n');
|
|
50
50
|
|
|
51
51
|
return [
|
|
52
52
|
shebangLineFor(detectScaffoldRuntime()),
|
|
@@ -66,6 +66,10 @@ export function renderCallsToTypeScript(
|
|
|
66
66
|
].join('\n');
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
+
function renderCall(call: OpFactoryCall): string {
|
|
70
|
+
return call.renderTypeScript();
|
|
71
|
+
}
|
|
72
|
+
|
|
69
73
|
function buildImports(calls: ReadonlyArray<OpFactoryCall>): string {
|
|
70
74
|
const requirements: ImportRequirement[] = [...BASE_IMPORTS];
|
|
71
75
|
for (const call of calls) {
|
|
@@ -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,
|
|
@@ -13,13 +13,12 @@ import type {
|
|
|
13
13
|
} from '@prisma-next/family-sql/control';
|
|
14
14
|
import { runnerFailure, runnerSuccess } from '@prisma-next/family-sql/control';
|
|
15
15
|
import { verifySqlSchema } from '@prisma-next/family-sql/schema-verify';
|
|
16
|
-
import type {
|
|
17
|
-
ControlDriverInstance,
|
|
18
|
-
MigrationRunnerResult,
|
|
19
|
-
} from '@prisma-next/framework-components/control';
|
|
16
|
+
import type { MigrationRunnerResult } from '@prisma-next/framework-components/control';
|
|
20
17
|
import { APP_SPACE_ID } from '@prisma-next/framework-components/control';
|
|
21
18
|
import { UNBOUND_NAMESPACE_ID } from '@prisma-next/framework-components/ir';
|
|
19
|
+
import type { SqlControlDriverInstance, SqlStorage } from '@prisma-next/sql-contract/types';
|
|
22
20
|
import { SqlQueryError } from '@prisma-next/sql-errors';
|
|
21
|
+
import type { LoweredStatement } from '@prisma-next/sql-relational-core/ast';
|
|
23
22
|
import { ifDefined } from '@prisma-next/utils/defined';
|
|
24
23
|
import type { Result } from '@prisma-next/utils/result';
|
|
25
24
|
import { notOk, ok, okVoid } from '@prisma-next/utils/result';
|
|
@@ -27,14 +26,6 @@ import { parsePostgresDefault } from '../default-normalizer';
|
|
|
27
26
|
import { normalizeSchemaNativeType } from '../native-type-normalizer';
|
|
28
27
|
import { createResolveExistingEnumValues } from './enum-planning';
|
|
29
28
|
import type { PostgresPlanTargetDetails } from './planner-target-details';
|
|
30
|
-
import {
|
|
31
|
-
buildLedgerInsertStatement,
|
|
32
|
-
buildMergeMarkerStatements,
|
|
33
|
-
ensureLedgerTableStatement,
|
|
34
|
-
ensureMarkerTableStatement,
|
|
35
|
-
ensurePrismaContractSchemaStatement,
|
|
36
|
-
type SqlStatement,
|
|
37
|
-
} from './statement-builders';
|
|
38
29
|
|
|
39
30
|
interface ApplyPlanSuccessValue {
|
|
40
31
|
readonly operationsExecuted: number;
|
|
@@ -107,7 +98,7 @@ class PostgresMigrationRunner implements SqlMigrationRunner<PostgresPlanTargetDe
|
|
|
107
98
|
if (!policyCheck.ok) return policyCheck;
|
|
108
99
|
|
|
109
100
|
await this.acquireLock(driver, lockKey);
|
|
110
|
-
const ensureResult = await this.ensureControlTables(driver);
|
|
101
|
+
const ensureResult = await this.ensureControlTables(driver, options.destinationContract);
|
|
111
102
|
if (!ensureResult.ok) return ensureResult;
|
|
112
103
|
const existingMarker = await this.family.readMarker({ driver, space });
|
|
113
104
|
|
|
@@ -165,8 +156,9 @@ class PostgresMigrationRunner implements SqlMigrationRunner<PostgresPlanTargetDe
|
|
|
165
156
|
isSelfEdge && applyValue.operationsExecuted === 0 && incomingIsSubsetOfExisting;
|
|
166
157
|
|
|
167
158
|
if (!isSelfEdgeNoOp) {
|
|
168
|
-
await this.upsertMarker(driver, options, existingMarker, space);
|
|
169
|
-
|
|
159
|
+
const markerResult = await this.upsertMarker(driver, options, existingMarker, space);
|
|
160
|
+
if (!markerResult.ok) return markerResult;
|
|
161
|
+
await this.recordLedgerEntries(driver, options, applyValue.executedOperations);
|
|
170
162
|
}
|
|
171
163
|
|
|
172
164
|
return runnerSuccess({
|
|
@@ -176,7 +168,7 @@ class PostgresMigrationRunner implements SqlMigrationRunner<PostgresPlanTargetDe
|
|
|
176
168
|
}
|
|
177
169
|
|
|
178
170
|
async execute(options: {
|
|
179
|
-
readonly driver:
|
|
171
|
+
readonly driver: SqlControlDriverInstance<string>;
|
|
180
172
|
readonly perSpaceOptions: ReadonlyArray<
|
|
181
173
|
SqlMigrationRunnerExecuteOptions<PostgresPlanTargetDetails>
|
|
182
174
|
>;
|
|
@@ -282,18 +274,22 @@ class PostgresMigrationRunner implements SqlMigrationRunner<PostgresPlanTargetDe
|
|
|
282
274
|
|
|
283
275
|
private async ensureControlTables(
|
|
284
276
|
driver: SqlMigrationRunnerExecuteOptions<PostgresPlanTargetDetails>['driver'],
|
|
277
|
+
contract: Contract<SqlStorage>,
|
|
285
278
|
): Promise<Result<void, SqlMigrationRunnerFailure>> {
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
279
|
+
const lowererContext = { contract };
|
|
280
|
+
const bootstrapQueries = this.family.bootstrapControlTableQueries();
|
|
281
|
+
const [schemaQuery, ...tableQueries] = bootstrapQueries;
|
|
282
|
+
if (schemaQuery === undefined) {
|
|
283
|
+
throw new Error('Postgres control-table bootstrap must include CREATE SCHEMA');
|
|
284
|
+
}
|
|
285
|
+
await this.executeStatement(driver, this.family.lowerAst(schemaQuery, lowererContext));
|
|
291
286
|
const legacyDetection = await this.detectLegacyMarkerShape(driver);
|
|
292
287
|
if (!legacyDetection.ok) {
|
|
293
288
|
return legacyDetection;
|
|
294
289
|
}
|
|
295
|
-
|
|
296
|
-
|
|
290
|
+
for (const query of tableQueries) {
|
|
291
|
+
await this.executeStatement(driver, this.family.lowerAst(query, lowererContext));
|
|
292
|
+
}
|
|
297
293
|
return okVoid();
|
|
298
294
|
}
|
|
299
295
|
|
|
@@ -594,43 +590,75 @@ class PostgresMigrationRunner implements SqlMigrationRunner<PostgresPlanTargetDe
|
|
|
594
590
|
options: SqlMigrationRunnerExecuteOptions<PostgresPlanTargetDetails>,
|
|
595
591
|
existingMarker: ContractMarkerRecord | null,
|
|
596
592
|
space: string,
|
|
597
|
-
): Promise<void
|
|
598
|
-
const
|
|
599
|
-
const writeStatements = buildMergeMarkerStatements({
|
|
600
|
-
space,
|
|
593
|
+
): Promise<Result<void, SqlMigrationRunnerFailure>> {
|
|
594
|
+
const destination = {
|
|
601
595
|
storageHash: options.plan.destination.storageHash,
|
|
602
596
|
profileHash:
|
|
603
597
|
options.plan.destination.profileHash ??
|
|
604
598
|
options.destinationContract.profileHash ??
|
|
605
599
|
options.plan.destination.storageHash,
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
600
|
+
invariants: options.plan.providedInvariants ?? [],
|
|
601
|
+
};
|
|
602
|
+
if (!existingMarker) {
|
|
603
|
+
await this.family.initMarker({ driver, space, destination });
|
|
604
|
+
return okVoid();
|
|
605
|
+
}
|
|
606
|
+
const updated = await this.family.updateMarker({
|
|
607
|
+
driver,
|
|
608
|
+
space,
|
|
609
|
+
expectedFrom: existingMarker.storageHash,
|
|
610
|
+
destination,
|
|
610
611
|
});
|
|
611
|
-
|
|
612
|
-
|
|
612
|
+
if (!updated) {
|
|
613
|
+
return runnerFailure(
|
|
614
|
+
'MARKER_CAS_FAILURE',
|
|
615
|
+
'Marker was modified by another process during migration execution.',
|
|
616
|
+
{
|
|
617
|
+
meta: {
|
|
618
|
+
space,
|
|
619
|
+
expectedStorageHash: existingMarker.storageHash,
|
|
620
|
+
destinationStorageHash: options.plan.destination.storageHash,
|
|
621
|
+
},
|
|
622
|
+
},
|
|
623
|
+
);
|
|
624
|
+
}
|
|
625
|
+
return okVoid();
|
|
613
626
|
}
|
|
614
627
|
|
|
615
|
-
private async
|
|
628
|
+
private async recordLedgerEntries(
|
|
616
629
|
driver: SqlMigrationRunnerExecuteOptions<PostgresPlanTargetDetails>['driver'],
|
|
617
630
|
options: SqlMigrationRunnerExecuteOptions<PostgresPlanTargetDetails>,
|
|
618
|
-
existingMarker: ContractMarkerRecord | null,
|
|
619
631
|
executedOperations: readonly SqlMigrationPlanOperation<PostgresPlanTargetDetails>[],
|
|
620
632
|
): Promise<void> {
|
|
621
|
-
const
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
633
|
+
const plan = options.plan;
|
|
634
|
+
const space = plan.spaceId;
|
|
635
|
+
const edges = options.migrationEdges;
|
|
636
|
+
const totalEdgeOps = edges.reduce((sum, edge) => sum + edge.operationCount, 0);
|
|
637
|
+
if (totalEdgeOps !== plan.operations.length) {
|
|
638
|
+
throw new Error(
|
|
639
|
+
`Ledger write: plan.operations length (${plan.operations.length}) does not match sum of migrationEdges operationCount (${totalEdgeOps})`,
|
|
640
|
+
);
|
|
641
|
+
}
|
|
642
|
+
// The ledger records the operations as executed — idempotency-skipped ops
|
|
643
|
+
// are substituted with skip records (empty `execute`) by `applyPlan`, so the
|
|
644
|
+
// journal reflects what actually ran rather than the raw plan.
|
|
645
|
+
let offset = 0;
|
|
646
|
+
for (const edge of edges) {
|
|
647
|
+
const edgeOps = executedOperations.slice(offset, offset + edge.operationCount);
|
|
648
|
+
offset += edge.operationCount;
|
|
649
|
+
await this.family.writeLedgerEntry({
|
|
650
|
+
driver,
|
|
651
|
+
space,
|
|
652
|
+
entry: {
|
|
653
|
+
edgeId: `${edge.from}->${edge.to}`,
|
|
654
|
+
from: edge.from,
|
|
655
|
+
to: edge.to,
|
|
656
|
+
migrationName: edge.dirName,
|
|
657
|
+
migrationHash: edge.migrationHash,
|
|
658
|
+
operations: edgeOps,
|
|
659
|
+
},
|
|
660
|
+
});
|
|
661
|
+
}
|
|
634
662
|
}
|
|
635
663
|
|
|
636
664
|
private async acquireLock(
|
|
@@ -660,7 +688,7 @@ class PostgresMigrationRunner implements SqlMigrationRunner<PostgresPlanTargetDe
|
|
|
660
688
|
|
|
661
689
|
private async executeStatement(
|
|
662
690
|
driver: SqlMigrationRunnerExecuteOptions<PostgresPlanTargetDetails>['driver'],
|
|
663
|
-
statement:
|
|
691
|
+
statement: LoweredStatement,
|
|
664
692
|
): Promise<void> {
|
|
665
693
|
if (statement.params.length > 0) {
|
|
666
694
|
await driver.query(statement.sql, statement.params);
|
|
@@ -14,12 +14,8 @@ import {
|
|
|
14
14
|
NamespaceBase,
|
|
15
15
|
UNBOUND_NAMESPACE_ID,
|
|
16
16
|
} from '@prisma-next/framework-components/ir';
|
|
17
|
-
import type {
|
|
18
|
-
|
|
19
|
-
SqlStorage,
|
|
20
|
-
SqlStorageTypeEntry,
|
|
21
|
-
StorageTable,
|
|
22
|
-
} from '@prisma-next/sql-contract/types';
|
|
17
|
+
import type { SqlNamespaceTablesInput, SqlStorage } from '@prisma-next/sql-contract/types';
|
|
18
|
+
import { blindCast } from '@prisma-next/utils/casts';
|
|
23
19
|
import type { JsonObject } from '@prisma-next/utils/json';
|
|
24
20
|
import type { Type } from 'arktype';
|
|
25
21
|
import { postgresAuthoringEntityTypes } from './authoring';
|
|
@@ -57,9 +53,8 @@ function collectEntityRegistryContributions(namespace: AuthoringEntityTypeNamesp
|
|
|
57
53
|
if (isAuthoringEntityTypeDescriptor(value)) {
|
|
58
54
|
if (isAuthoringEntityTypeFactoryOutput(value.output)) {
|
|
59
55
|
const { factory } = value.output;
|
|
60
|
-
entityTypeRegistry.set(
|
|
61
|
-
|
|
62
|
-
(raw) => factory(raw, POSTGRES_AUTHORING_CTX) as SqlStorageTypeEntry,
|
|
56
|
+
entityTypeRegistry.set(value.discriminator, (raw) =>
|
|
57
|
+
factory(raw, POSTGRES_AUTHORING_CTX),
|
|
63
58
|
);
|
|
64
59
|
}
|
|
65
60
|
if (value.validatorSchema !== undefined) {
|
|
@@ -91,22 +86,46 @@ export class PostgresContractSerializer extends SqlContractSerializerBase<Contra
|
|
|
91
86
|
if (raw instanceof NamespaceBase) {
|
|
92
87
|
return raw;
|
|
93
88
|
}
|
|
94
|
-
const hydrated =
|
|
95
|
-
|
|
96
|
-
tables
|
|
97
|
-
|
|
98
|
-
};
|
|
99
|
-
|
|
89
|
+
const hydrated = blindCast<
|
|
90
|
+
SqlNamespaceTablesInput,
|
|
91
|
+
'super.hydrateSqlNamespaceEntry returns the tables form when raw is not a NamespaceBase'
|
|
92
|
+
>(super.hydrateSqlNamespaceEntry(nsId, raw));
|
|
93
|
+
const { id, entries } = hydrated;
|
|
94
|
+
|
|
95
|
+
// Extract the postgres-specific `type` slot directly from raw input.
|
|
96
|
+
// The family base handles the `table` slot; the postgres target owns `type`.
|
|
97
|
+
const rawRecord = raw as Record<string, unknown>;
|
|
98
|
+
const rawEntries = rawRecord['entries'];
|
|
99
|
+
let typeSlot: Record<string, PostgresEnumType> | undefined;
|
|
100
|
+
if (rawEntries !== null && typeof rawEntries === 'object' && !Array.isArray(rawEntries)) {
|
|
101
|
+
const rawTypeSlot = (rawEntries as Record<string, unknown>)['type'];
|
|
102
|
+
if (rawTypeSlot !== null && typeof rawTypeSlot === 'object' && !Array.isArray(rawTypeSlot)) {
|
|
103
|
+
const enumFactory = this.entityTypeRegistry.get('postgres-enum');
|
|
104
|
+
typeSlot = Object.fromEntries(
|
|
105
|
+
Object.entries(rawTypeSlot as Record<string, unknown>).map(([name, entry]) => [
|
|
106
|
+
name,
|
|
107
|
+
blindCast<PostgresEnumType, 'postgres-enum factory returns PostgresEnumType'>(
|
|
108
|
+
enumFactory !== undefined ? enumFactory(entry) : entry,
|
|
109
|
+
),
|
|
110
|
+
]),
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
100
114
|
|
|
101
|
-
const
|
|
102
|
-
const
|
|
103
|
-
|
|
115
|
+
const valueSetSlot = entries.valueSet;
|
|
116
|
+
const hasValueSets = valueSetSlot !== undefined && Object.keys(valueSetSlot).length > 0;
|
|
117
|
+
const emptyTables = Object.keys(entries.table).length === 0;
|
|
118
|
+
const emptyTypes = !typeSlot || Object.keys(typeSlot).length === 0;
|
|
119
|
+
if (id === UNBOUND_NAMESPACE_ID && emptyTables && emptyTypes && !hasValueSets) {
|
|
104
120
|
return PostgresSchema.unbound;
|
|
105
121
|
}
|
|
106
122
|
return new PostgresSchema({
|
|
107
123
|
id,
|
|
108
|
-
|
|
109
|
-
|
|
124
|
+
entries: {
|
|
125
|
+
table: entries.table,
|
|
126
|
+
type: typeSlot ?? {},
|
|
127
|
+
...(hasValueSets ? { valueSet: valueSetSlot } : {}),
|
|
128
|
+
},
|
|
110
129
|
});
|
|
111
130
|
}
|
|
112
131
|
|
|
@@ -117,30 +136,18 @@ export class PostgresContractSerializer extends SqlContractSerializerBase<Contra
|
|
|
117
136
|
if (isPostgresSchema(ns)) {
|
|
118
137
|
namespacesJson[nsId] = this.serializePostgresNamespace(ns, ns.id === UNBOUND_NAMESPACE_ID);
|
|
119
138
|
} else {
|
|
120
|
-
// Family-level SqlUnboundNamespace or other family-built SQL
|
|
121
|
-
// namespaces haven't been promoted to a PostgresSchema instance
|
|
122
|
-
// yet (e.g. they came straight from the TS builder before a target
|
|
123
|
-
// `createNamespace` factory ran). Serialise them as postgres-schema /
|
|
124
|
-
// postgres-unbound-schema so the round-trip through
|
|
125
|
-
// deserializeContract hydrates them back into PostgresSchema
|
|
126
|
-
// instances.
|
|
127
139
|
const isUnboundSlot = nsId === UNBOUND_NAMESPACE_ID;
|
|
128
|
-
const nsEnums = (ns as { readonly enum?: Readonly<Record<string, unknown>> }).enum ?? {};
|
|
129
140
|
namespacesJson[nsId] = {
|
|
130
141
|
id: nsId,
|
|
131
142
|
kind: isUnboundSlot ? 'postgres-unbound-schema' : 'postgres-schema',
|
|
132
|
-
|
|
133
|
-
Object.
|
|
134
|
-
tableName,
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
typeName,
|
|
141
|
-
this.serializeJsonValue(entry) as JsonObject,
|
|
142
|
-
]),
|
|
143
|
-
),
|
|
143
|
+
entries: {
|
|
144
|
+
table: Object.fromEntries(
|
|
145
|
+
Object.entries(ns.entries.table).map(([tableName, table]) => [
|
|
146
|
+
tableName,
|
|
147
|
+
this.serializeJsonValue(table) as JsonObject,
|
|
148
|
+
]),
|
|
149
|
+
),
|
|
150
|
+
},
|
|
144
151
|
};
|
|
145
152
|
}
|
|
146
153
|
}
|
|
@@ -163,18 +170,31 @@ export class PostgresContractSerializer extends SqlContractSerializerBase<Contra
|
|
|
163
170
|
|
|
164
171
|
private serializePostgresNamespace(ns: PostgresSchema, isUnboundSlot: boolean): JsonObject {
|
|
165
172
|
const tablesOut: Record<string, JsonObject> = {};
|
|
166
|
-
for (const [tableName, table] of Object.entries(ns.
|
|
173
|
+
for (const [tableName, table] of Object.entries(ns.entries.table)) {
|
|
167
174
|
tablesOut[tableName] = this.serializeJsonValue(table) as JsonObject;
|
|
168
175
|
}
|
|
169
|
-
const
|
|
170
|
-
for (const [typeName, ty] of Object.entries(ns.
|
|
171
|
-
|
|
176
|
+
const typeOut: Record<string, JsonObject> = {};
|
|
177
|
+
for (const [typeName, ty] of Object.entries(ns.entries.type)) {
|
|
178
|
+
typeOut[typeName] = this.serializeJsonValue(ty) as JsonObject;
|
|
179
|
+
}
|
|
180
|
+
const valueSetEntries = ns.entries.valueSet;
|
|
181
|
+
const valueSetOut: Record<string, JsonObject> = {};
|
|
182
|
+
if (valueSetEntries !== undefined) {
|
|
183
|
+
for (const [valueSetName, valueSet] of Object.entries(valueSetEntries)) {
|
|
184
|
+
valueSetOut[valueSetName] = blindCast<
|
|
185
|
+
JsonObject,
|
|
186
|
+
'serializeJsonValue round-trips the value-set node through JSON, yielding a JsonObject'
|
|
187
|
+
>(this.serializeJsonValue(valueSet));
|
|
188
|
+
}
|
|
172
189
|
}
|
|
173
190
|
return {
|
|
174
191
|
id: ns.id,
|
|
175
192
|
kind: isUnboundSlot ? 'postgres-unbound-schema' : 'postgres-schema',
|
|
176
|
-
|
|
177
|
-
|
|
193
|
+
entries: {
|
|
194
|
+
table: tablesOut,
|
|
195
|
+
type: typeOut,
|
|
196
|
+
...(Object.keys(valueSetOut).length > 0 ? { valueSet: valueSetOut } : {}),
|
|
197
|
+
},
|
|
178
198
|
};
|
|
179
199
|
}
|
|
180
200
|
|
|
@@ -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
|
|