@prisma/orm-family-mongo 8.0.0-rc.2-dev.3 → 8.0.0-rc.20-dev.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -5
- package/dist/authoring-entity-types-UA5sY_Xm-DeYf_cYq.mjs +87 -0
- package/dist/authoring-entity-types-UA5sY_Xm-DeYf_cYq.mjs.map +1 -0
- package/dist/{canonicalization-hooks-DF3Z6sjO.mjs → canonicalization-hooks-CRVM-Kqh-Qi-VmEVg.mjs} +4 -3
- package/dist/canonicalization-hooks-CRVM-Kqh-Qi-VmEVg.mjs.map +1 -0
- package/dist/codec.d.mts +1 -1
- package/dist/codec.mjs +1 -1
- package/dist/{config-types-CFDf9ivE.mjs → config-types-DYTCUpAs.mjs} +5 -5
- package/dist/config-types-DYTCUpAs.mjs.map +1 -0
- package/dist/contract-builder-BHzQQk70.mjs +965 -0
- package/dist/contract-builder-BHzQQk70.mjs.map +1 -0
- package/dist/{contract-builder-DB8nguDE.d.mts → contract-builder-ClL-xMK2.d.mts} +271 -89
- package/dist/contract-builder-ClL-xMK2.d.mts.map +1 -0
- package/dist/contract-prisma6__provider.d.mts +35 -0
- package/dist/contract-prisma6__provider.d.mts.map +1 -0
- package/dist/contract-prisma6__provider.mjs +1202 -0
- package/dist/contract-prisma6__provider.mjs.map +1 -0
- package/dist/contract-psl.d.mts +152 -28
- package/dist/contract-psl.d.mts.map +1 -1
- package/dist/contract-psl.mjs +3 -2
- package/dist/contract-psl__provider.mjs +74 -44
- package/dist/contract-psl__provider.mjs.map +1 -1
- package/dist/contract-ts.d.mts +2 -2
- package/dist/contract-ts.mjs +2 -2
- package/dist/contract-ts__config-types.mjs +1 -1
- package/dist/contract-ts__contract-builder.d.mts +2 -2
- package/dist/contract-ts__contract-builder.mjs +1 -1
- package/dist/contract.d.mts +3 -3
- package/dist/contract.mjs +3 -3
- package/dist/contract__canonicalization-hooks.mjs +1 -1
- package/dist/contract__data-type.d.mts +37 -0
- package/dist/contract__data-type.d.mts.map +1 -0
- package/dist/contract__data-type.mjs +2 -0
- package/dist/contract__entity-kinds.d.mts +1 -1
- package/dist/contract__entity-kinds.mjs +1 -1
- package/dist/{control-C7-kthr1.d.mts → control-4pC8N2Rb.d.mts} +32 -19
- package/dist/control-4pC8N2Rb.d.mts.map +1 -0
- package/dist/{control-CClR5JMr.mjs → control-BQMBG11d.mjs} +19 -2
- package/dist/control-BQMBG11d.mjs.map +1 -0
- package/dist/{control-BbZQqmxo.mjs → control-B_pPN58L.mjs} +195 -87
- package/dist/control-B_pPN58L.mjs.map +1 -0
- package/dist/{control-Cj81sPbj.d.mts → control-CvQSMuxa.d.mts} +29 -6
- package/dist/control-CvQSMuxa.d.mts.map +1 -0
- package/dist/{control-adapter-Db5pT77b.d.mts → control-adapter-Bh_ZraGM--5JDb99k.d.mts} +48 -4
- package/dist/control-adapter-Bh_ZraGM--5JDb99k.d.mts.map +1 -0
- package/dist/control-adapter-CndDiTXW.d.mts +1 -0
- package/dist/dist-B8f-pfcT.mjs +1031 -0
- package/dist/dist-B8f-pfcT.mjs.map +1 -0
- package/dist/dist-Bgk36iLI.mjs +53 -0
- package/dist/dist-Bgk36iLI.mjs.map +1 -0
- package/dist/{dist-C7Ykq48Q.mjs → dist-CO2arS1K.mjs} +3 -1
- package/dist/dist-CO2arS1K.mjs.map +1 -0
- package/dist/{dist-Dyp05u64.mjs → dist-gmGbjhmk.mjs} +56 -32
- package/dist/dist-gmGbjhmk.mjs.map +1 -0
- package/dist/dist-xk_0xOR-.mjs +28 -0
- package/dist/dist-xk_0xOR-.mjs.map +1 -0
- package/dist/emitter.d.mts +2 -4
- package/dist/emitter.d.mts.map +1 -1
- package/dist/emitter.mjs +1 -1
- package/dist/{entity-kinds-B4KNTF8z-DPIuUuuB.mjs → entity-kinds-BQBtfVet-B-Px7NHp.mjs} +35 -18
- package/dist/entity-kinds-BQBtfVet-B-Px7NHp.mjs.map +1 -0
- package/dist/{execution-D5XyZ5XS.mjs → execution-CgP1Sdbr.mjs} +6 -3
- package/dist/execution-CgP1Sdbr.mjs.map +1 -0
- package/dist/{execution-CKnUiOfm.d.mts → execution-tPmN5pge.d.mts} +6 -2
- package/dist/execution-tPmN5pge.d.mts.map +1 -0
- package/dist/{exports-Bx-hlnZ3.mjs → exports-BAimNKOs.mjs} +31 -21
- package/dist/exports-BAimNKOs.mjs.map +1 -0
- package/dist/exports-BHQVApAg.mjs +86 -0
- package/dist/exports-BHQVApAg.mjs.map +1 -0
- package/dist/family.d.mts +11 -10
- package/dist/family.mjs +10 -9
- package/dist/family__control-adapter.d.mts +3 -2
- package/dist/family__control.d.mts +2 -2
- package/dist/family__control.mjs +3 -3
- package/dist/family__ir.d.mts +2 -2
- package/dist/family__ir.mjs +3 -3
- package/dist/family__migration.d.mts +1 -1
- package/dist/family__migration.mjs +1 -1
- package/dist/family__pack.d.mts +1 -1
- package/dist/family__pack.mjs +4 -2
- package/dist/family__pack.mjs.map +1 -1
- package/dist/family__runtime.d.mts +3 -3
- package/dist/family__runtime.mjs +3 -2
- package/dist/family__schema-verify.d.mts +1 -1
- package/dist/family__schema-verify.mjs +1 -1
- package/dist/{field-accessor-0oUt6RZC-B_Z30uAA.mjs → field-accessor-0oUt6RZC-CrJVzQiS.mjs} +2 -2
- package/dist/{field-accessor-0oUt6RZC-B_Z30uAA.mjs.map → field-accessor-0oUt6RZC-CrJVzQiS.mjs.map} +1 -1
- package/dist/{field-accessor-DHsAPiW3-BdYCspQC.d.mts → field-accessor-CmxCw9xP-C6jMngbK.d.mts} +35 -24
- package/dist/field-accessor-CmxCw9xP-C6jMngbK.d.mts.map +1 -0
- package/dist/index-9DDQlC5U.d.mts +87 -0
- package/dist/index-9DDQlC5U.d.mts.map +1 -0
- package/dist/{index-BR0ue13b.d.mts → index-BdXzdXGE.d.mts} +14 -8
- package/dist/index-BdXzdXGE.d.mts.map +1 -0
- package/dist/index-BhIiYIXu.d.mts +845 -0
- package/dist/index-BhIiYIXu.d.mts.map +1 -0
- package/dist/index-CQG5l2o9.d.mts +67 -0
- package/dist/index-CQG5l2o9.d.mts.map +1 -0
- package/dist/{index-DAOkcTCK.d.mts → index-FeVOOdZ0.d.mts} +9 -8
- package/dist/index-FeVOOdZ0.d.mts.map +1 -0
- package/dist/index-YY1SU_7o.d.mts +366 -0
- package/dist/index-YY1SU_7o.d.mts.map +1 -0
- package/dist/{index-DxoO-ywI.d.mts → index-rANtsIZG.d.mts} +9 -5
- package/dist/{index-DxoO-ywI.d.mts.map → index-rANtsIZG.d.mts.map} +1 -1
- package/dist/interpreter-BfHdPd7T-DGqi2_Um.mjs +2186 -0
- package/dist/interpreter-BfHdPd7T-DGqi2_Um.mjs.map +1 -0
- package/dist/{ir-CQrenTYt.d.mts → ir-BLC0t6_x.d.mts} +5 -27
- package/dist/ir-BLC0t6_x.d.mts.map +1 -0
- package/dist/{ir-Ch2aPr7a.mjs → ir-DGm0HXbP.mjs} +3 -8
- package/dist/ir-DGm0HXbP.mjs.map +1 -0
- package/dist/lowering.d.mts +1 -1
- package/dist/{migration-dcM7u4HG.mjs → migration-DnQ7_A_B.mjs} +4 -4
- package/dist/migration-DnQ7_A_B.mjs.map +1 -0
- package/dist/{migration-CNDQv5yB.d.mts → migration-YQVmgFU8.d.mts} +7 -7
- package/dist/{migration-CNDQv5yB.d.mts.map → migration-YQVmgFU8.d.mts.map} +1 -1
- package/dist/{mongo-contract-serializer-Cx7Fae8e-C8ZYPXpc.mjs → mongo-contract-serializer-Zx1rvil3-BywiKCpn.mjs} +27 -8
- package/dist/mongo-contract-serializer-Zx1rvil3-BywiKCpn.mjs.map +1 -0
- package/dist/{mongo-contract-view-AnejqfrQ-BaCFT0xm.d.mts → mongo-contract-view-AnejqfrQ-Wj_ulq2L.d.mts} +3 -3
- package/dist/{mongo-contract-view-AnejqfrQ-BaCFT0xm.d.mts.map → mongo-contract-view-AnejqfrQ-Wj_ulq2L.d.mts.map} +1 -1
- package/dist/{mongo-contract-view-rcWzby6f-wRBCUnBt.mjs → mongo-contract-view-D5yu2LrY-DCAZYJ4q.mjs} +4 -4
- package/dist/{mongo-contract-view-rcWzby6f-wRBCUnBt.mjs.map → mongo-contract-view-D5yu2LrY-DCAZYJ4q.mjs.map} +1 -1
- package/dist/mongo-data-type-DzyzU4LF-C1ydFXgE.mjs +53 -0
- package/dist/mongo-data-type-DzyzU4LF-C1ydFXgE.mjs.map +1 -0
- package/dist/{mongo-value-set-tNn9-pun-dJYx_rVD.d.mts → mongo-value-set-DEd7WLCT-B2Ar2GkJ.d.mts} +20 -4
- package/dist/mongo-value-set-DEd7WLCT-B2Ar2GkJ.d.mts.map +1 -0
- package/dist/orm.d.mts +154 -96
- package/dist/orm.d.mts.map +1 -1
- package/dist/orm.mjs +670 -148
- package/dist/orm.mjs.map +1 -1
- package/dist/pack-qw77Jt2G.d.mts +58 -0
- package/dist/pack-qw77Jt2G.d.mts.map +1 -0
- package/dist/query-ast.d.mts +5 -5
- package/dist/query-ast.mjs +3 -3
- package/dist/query-ast__control.d.mts +4 -4
- package/dist/query-ast__control.mjs +2 -2
- package/dist/query-ast__execution.d.mts +2 -2
- package/dist/query-ast__execution.mjs +1 -1
- package/dist/query-builder.d.mts +4 -836
- package/dist/query-builder.mjs +2 -2
- package/dist/query-builder__contract-free.d.mts +6 -6
- package/dist/query-builder__contract-free.mjs +3 -3
- package/dist/{query-plan-C0-Yu8hf-DdilEdW6.d.mts → query-plan-3fs1HokF-CrNsr-Wx.d.mts} +10 -4
- package/dist/{query-plan-C0-Yu8hf-DdilEdW6.d.mts.map → query-plan-3fs1HokF-CrNsr-Wx.d.mts.map} +1 -1
- package/dist/runtime-B5fNQHQZ.mjs +16 -0
- package/dist/runtime-B5fNQHQZ.mjs.map +1 -0
- package/dist/runtime-yZA30qM2.d.mts +11 -0
- package/dist/runtime-yZA30qM2.d.mts.map +1 -0
- package/dist/runtime.d.mts +74 -87
- package/dist/runtime.d.mts.map +1 -1
- package/dist/runtime.mjs +133 -67
- package/dist/runtime.mjs.map +1 -1
- package/dist/schema-ir.d.mts +2 -2
- package/dist/schema-ir.mjs +2 -2
- package/dist/{schema-verify-DJGr28XW.d.mts → schema-verify-CVOG6EZx.d.mts} +5 -5
- package/dist/{schema-verify-DJGr28XW.d.mts.map → schema-verify-CVOG6EZx.d.mts.map} +1 -1
- package/dist/value.d.mts +2 -2
- package/dist/value.mjs +1 -1
- package/dist/{verify-mongo-schema-De0FG2Rm-CCzwnNPY.mjs → verify-mongo-schema-CeQP5N4k-CNOctppM.mjs} +9 -26
- package/dist/verify-mongo-schema-CeQP5N4k-CNOctppM.mjs.map +1 -0
- package/dist/wire.d.mts +3 -3
- package/dist/wire.mjs +14 -2
- package/dist/wire.mjs.map +1 -1
- package/package.json +24 -21
- package/dist/authoring-entity-types-BGtkMyoN-D32kzx28.mjs +0 -176
- package/dist/authoring-entity-types-BGtkMyoN-D32kzx28.mjs.map +0 -1
- package/dist/canonicalization-hooks-DF3Z6sjO.mjs.map +0 -1
- package/dist/config-types-CFDf9ivE.mjs.map +0 -1
- package/dist/contract-builder-BFq0gOMV.mjs +0 -634
- package/dist/contract-builder-BFq0gOMV.mjs.map +0 -1
- package/dist/contract-builder-DB8nguDE.d.mts.map +0 -1
- package/dist/control-BbZQqmxo.mjs.map +0 -1
- package/dist/control-C7-kthr1.d.mts.map +0 -1
- package/dist/control-CClR5JMr.mjs.map +0 -1
- package/dist/control-Cj81sPbj.d.mts.map +0 -1
- package/dist/control-adapter-Db5pT77b.d.mts.map +0 -1
- package/dist/dist-C7Ykq48Q.mjs.map +0 -1
- package/dist/dist-Czwqx_i3.mjs +0 -58
- package/dist/dist-Czwqx_i3.mjs.map +0 -1
- package/dist/dist-DHrEJnhK.mjs +0 -236
- package/dist/dist-DHrEJnhK.mjs.map +0 -1
- package/dist/dist-Dyp05u64.mjs.map +0 -1
- package/dist/entity-kinds-B4KNTF8z-DPIuUuuB.mjs.map +0 -1
- package/dist/execution-CKnUiOfm.d.mts.map +0 -1
- package/dist/execution-D5XyZ5XS.mjs.map +0 -1
- package/dist/exports-Bx-hlnZ3.mjs.map +0 -1
- package/dist/exports-C4RGBGzZ.mjs +0 -156
- package/dist/exports-C4RGBGzZ.mjs.map +0 -1
- package/dist/field-accessor-DHsAPiW3-BdYCspQC.d.mts.map +0 -1
- package/dist/index-BR0ue13b.d.mts.map +0 -1
- package/dist/index-Cd2zLiU6.d.mts +0 -128
- package/dist/index-Cd2zLiU6.d.mts.map +0 -1
- package/dist/index-DAOkcTCK.d.mts.map +0 -1
- package/dist/index-Dv2PNMiG.d.mts +0 -53
- package/dist/index-Dv2PNMiG.d.mts.map +0 -1
- package/dist/index-wKMm41HC.d.mts +0 -30
- package/dist/index-wKMm41HC.d.mts.map +0 -1
- package/dist/interpreter-BxbUTQ3k-ClR98Ned.mjs +0 -1091
- package/dist/interpreter-BxbUTQ3k-ClR98Ned.mjs.map +0 -1
- package/dist/ir-CQrenTYt.d.mts.map +0 -1
- package/dist/ir-Ch2aPr7a.mjs.map +0 -1
- package/dist/migration-dcM7u4HG.mjs.map +0 -1
- package/dist/mongo-contract-serializer-Cx7Fae8e-C8ZYPXpc.mjs.map +0 -1
- package/dist/mongo-value-set-tNn9-pun-dJYx_rVD.d.mts.map +0 -1
- package/dist/pack-D9aLY50F.d.mts +0 -44
- package/dist/pack-D9aLY50F.d.mts.map +0 -1
- package/dist/query-builder.d.mts.map +0 -1
- package/dist/runtime-DPkRW4iu.d.mts +0 -1
- package/dist/verify-mongo-schema-De0FG2Rm-CCzwnNPY.mjs.map +0 -1
|
@@ -0,0 +1,965 @@
|
|
|
1
|
+
import { i as MongoCollectionOptions, o as MongoIndex } from "./entity-kinds-BQBtfVet-B-Px7NHp.mjs";
|
|
2
|
+
import { t as assertMongoFieldTypeParams } from "./mongo-data-type-DzyzU4LF-C1ydFXgE.mjs";
|
|
3
|
+
import { M as unsupportedStoredNameReason, S as mongoContractRefusalsOf, g as deriveCollectionValidators, s as applyPolymorphicScopeToMongoIndex, u as buildMongoStorage, w as mongoValueSetsOf } from "./dist-B8f-pfcT.mjs";
|
|
4
|
+
import { t as contractError } from "./contract-errors-BCN6RVI5-kMurtAbI.mjs";
|
|
5
|
+
import { assembleDataTypes } from "@prisma/orm-framework/components/codec";
|
|
6
|
+
import { blindCast } from "@prisma/orm-framework/utils/casts";
|
|
7
|
+
import { UNBOUND_NAMESPACE_ID } from "@prisma/orm-framework/components/ir";
|
|
8
|
+
import { crossRef } from "@prisma/orm-framework/contract/types";
|
|
9
|
+
import { buildExecutionSection, computeProfileHash } from "@prisma/orm-framework/contract/hashing";
|
|
10
|
+
import { bindEnumType, composePackAuthoringNamespace, createEntityHelpersFromNamespace, createFieldHelpersFromNamespace, encodeEnumTypeMembers, enumType as enumType$1, isEnumTypeHandle, member, resolveToOneRelationNullable } from "@prisma/orm-framework/contract-authoring";
|
|
11
|
+
import { assertNoCrossRegistryCollisions, assertTypeAliasesValid, instantiateAuthoringFieldPreset, validateAuthoringHelperArguments } from "@prisma/orm-framework/components/authoring";
|
|
12
|
+
import { ifDefined } from "@prisma/orm-framework/utils/defined";
|
|
13
|
+
import { assembleGeneratorFunctions, createGeneratorHelpers } from "@prisma/orm-framework/components/components";
|
|
14
|
+
import { extractCodecLookup } from "@prisma/orm-framework/components/control";
|
|
15
|
+
import { canonicalStringify } from "@prisma/orm-framework/utils/canonical-stringify";
|
|
16
|
+
//#region ../../../2-mongo-family/2-authoring/contract-ts/dist/contract-builder.mjs
|
|
17
|
+
const LIST_THE_CODEC_PACK = "List the pack that provides the codec in `extensions` in defineContract.";
|
|
18
|
+
function codecRefusalError(subject, meta, codecId, refusal) {
|
|
19
|
+
if (refusal.kind === "unknownCodec") return contractError("CONTRACT.CODEC_DESCRIPTOR_MISSING", `${subject} ${refusal.reason}`, {
|
|
20
|
+
fix: LIST_THE_CODEC_PACK,
|
|
21
|
+
meta: {
|
|
22
|
+
...meta,
|
|
23
|
+
codecId
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
return contractError("CONTRACT.PACK_CONTRIBUTION_INVALID", `${subject} ${refusal.reason}`, {
|
|
27
|
+
fix: "Use a codec whose data type is a MongoDB data type, declared with mongoDataType.",
|
|
28
|
+
meta: {
|
|
29
|
+
...meta,
|
|
30
|
+
codecId,
|
|
31
|
+
dataType: refusal.dataType,
|
|
32
|
+
reason: "data-type-not-mongo"
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
function refusalError(refusal) {
|
|
37
|
+
switch (refusal.kind) {
|
|
38
|
+
case "embeddedModelHasVariants": return contractError("CONTRACT.RELATION_INVALID", `Relation "${refusal.modelName}.${refusal.relationName}" ${refusal.reason}`, { meta: {
|
|
39
|
+
modelName: refusal.modelName,
|
|
40
|
+
relationName: refusal.relationName,
|
|
41
|
+
reason: "embedded-model-has-variants"
|
|
42
|
+
} });
|
|
43
|
+
case "enumBsonType": return codecRefusalError(`enumType("${refusal.enumName}")`, { enumName: refusal.enumName }, refusal.codecId, refusal.refusal);
|
|
44
|
+
case "enumNotListable": return contractError("CONTRACT.ENUM_INVALID", `enumType("${refusal.enumName}") codec "${refusal.codecId}" ${refusal.reason}`, { meta: {
|
|
45
|
+
enumName: refusal.enumName,
|
|
46
|
+
codecId: refusal.codecId,
|
|
47
|
+
reason: "not-listable-by-validator"
|
|
48
|
+
} });
|
|
49
|
+
case "enumMemberNotListable": return contractError("CONTRACT.ENUM_INVALID", `enumType("${refusal.enumName}") member "${refusal.member}" ${refusal.reason}`, { meta: {
|
|
50
|
+
enumName: refusal.enumName,
|
|
51
|
+
member: refusal.member,
|
|
52
|
+
codecId: refusal.codecId,
|
|
53
|
+
reason: "member-not-listable-by-validator"
|
|
54
|
+
} });
|
|
55
|
+
case "fieldBsonType": {
|
|
56
|
+
const { owner } = refusal;
|
|
57
|
+
const label = owner.kind === "model" ? "Model" : "Value object";
|
|
58
|
+
const ownerMeta = owner.kind === "model" ? { modelName: owner.name } : { valueObjectName: owner.name };
|
|
59
|
+
return codecRefusalError(`${label} "${owner.name}" field "${refusal.fieldName}"`, {
|
|
60
|
+
...ownerMeta,
|
|
61
|
+
fieldName: refusal.fieldName
|
|
62
|
+
}, refusal.codecId, refusal.refusal);
|
|
63
|
+
}
|
|
64
|
+
case "documentId": return contractError("CONTRACT.COLLECTION_INVALID", `Model "${refusal.modelName}" field "${refusal.fieldName}" ${refusal.reason}`, { meta: {
|
|
65
|
+
modelName: refusal.modelName,
|
|
66
|
+
fieldName: refusal.fieldName,
|
|
67
|
+
collection: refusal.collection,
|
|
68
|
+
codecId: refusal.codecId,
|
|
69
|
+
bsonTypes: refusal.forbidden,
|
|
70
|
+
reason: "document-id-bson-type"
|
|
71
|
+
} });
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Throws the first part of the built contract that its collection validators cannot describe, as decided by `mongoContractRefusalsOf`.
|
|
76
|
+
*/
|
|
77
|
+
function assertCollectionValidatorSources(input) {
|
|
78
|
+
const [first] = mongoContractRefusalsOf(input);
|
|
79
|
+
if (first !== void 0) throw refusalError(first);
|
|
80
|
+
}
|
|
81
|
+
function stableStringify(value) {
|
|
82
|
+
if (Array.isArray(value)) return `[${value.map(stableStringify).join(",")}]`;
|
|
83
|
+
if (value && typeof value === "object") return `{${Object.entries(value).sort(([left], [right]) => left.localeCompare(right)).map(([key, entry]) => `${JSON.stringify(key)}:${stableStringify(entry)}`).join(",")}}`;
|
|
84
|
+
return JSON.stringify(value);
|
|
85
|
+
}
|
|
86
|
+
const MONGO_RESERVED_HELPER_KEYS = [
|
|
87
|
+
"field",
|
|
88
|
+
"gen",
|
|
89
|
+
"index",
|
|
90
|
+
"model",
|
|
91
|
+
"rel",
|
|
92
|
+
"valueObject"
|
|
93
|
+
];
|
|
94
|
+
function buildFieldPreset(helperPath, descriptor, args) {
|
|
95
|
+
validateAuthoringHelperArguments(helperPath, descriptor.args, args);
|
|
96
|
+
const preset = instantiateAuthoringFieldPreset(descriptor, args);
|
|
97
|
+
const unsupported = [
|
|
98
|
+
...preset.default !== void 0 ? ["default"] : [],
|
|
99
|
+
...preset.id ? ["id"] : [],
|
|
100
|
+
...preset.unique ? ["unique"] : []
|
|
101
|
+
];
|
|
102
|
+
if (unsupported.length > 0) throw contractError("CONTRACT.PACK_CONTRIBUTION_INVALID", `Field preset "${helperPath}" contributes ${unsupported.join(", ")}, which Mongo does not support. Mongo supports presets that set a codec and execution defaults only.`, { meta: {
|
|
103
|
+
helperPath,
|
|
104
|
+
reason: "preset-contribution-unsupported",
|
|
105
|
+
contribution: unsupported
|
|
106
|
+
} });
|
|
107
|
+
return createFieldBuilder({
|
|
108
|
+
type: {
|
|
109
|
+
kind: "scalar",
|
|
110
|
+
codecId: preset.descriptor.codecId,
|
|
111
|
+
...normalizeOptionalTypeParams(preset.descriptor.typeParams)
|
|
112
|
+
},
|
|
113
|
+
nullable: preset.nullable,
|
|
114
|
+
many: false
|
|
115
|
+
}, void 0, preset.executionDefaults);
|
|
116
|
+
}
|
|
117
|
+
function composeMongoFieldHelpers(fieldNamespace) {
|
|
118
|
+
const presetHelpers = createFieldHelpersFromNamespace(fieldNamespace, ({ helperPath, descriptor }) => (...args) => buildFieldPreset(helperPath, descriptor, args));
|
|
119
|
+
const collisions = Object.keys(presetHelpers).filter((name) => Object.hasOwn(field, name));
|
|
120
|
+
if (collisions.length > 0) throw contractError("CONTRACT.PACK_CONTRIBUTION_INVALID", `Pack-contributed field preset(s) ${collisions.map((c) => `"${c}"`).join(", ")} collide with the built-in Mongo field helper(s) of the same name.`, { meta: {
|
|
121
|
+
reason: "core-field-helper-collision",
|
|
122
|
+
contribution: collisions
|
|
123
|
+
} });
|
|
124
|
+
return {
|
|
125
|
+
...field,
|
|
126
|
+
...presetHelpers
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
/** The context an entity helper's factory runs in. The builder reads no written values, so its data types carry no authoring entries. */
|
|
130
|
+
function entityContextOf(familyId, targetId, components) {
|
|
131
|
+
const codecLookup = extractCodecLookup(components);
|
|
132
|
+
return {
|
|
133
|
+
family: familyId,
|
|
134
|
+
target: targetId,
|
|
135
|
+
codecLookup,
|
|
136
|
+
dataTypes: {
|
|
137
|
+
entries: {},
|
|
138
|
+
lookup: assembleDataTypes(components).lookup,
|
|
139
|
+
dataTypeOfCodec: (codecId) => codecLookup.descriptorFor(codecId)?.dataType
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
function composeMongoAuthoringHelpers(family, target, extensions) {
|
|
144
|
+
const components = [
|
|
145
|
+
family,
|
|
146
|
+
target,
|
|
147
|
+
...Object.values(extensions ?? {})
|
|
148
|
+
];
|
|
149
|
+
const entityNamespace = composePackAuthoringNamespace(components, "entityTypes");
|
|
150
|
+
const fieldNamespace = composePackAuthoringNamespace(components, "field");
|
|
151
|
+
assertNoCrossRegistryCollisions({}, fieldNamespace, entityNamespace);
|
|
152
|
+
const collisions = Object.keys(entityNamespace).filter((name) => MONGO_RESERVED_HELPER_KEYS.includes(name));
|
|
153
|
+
if (collisions.length > 0) throw contractError("CONTRACT.PACK_CONTRIBUTION_INVALID", `Pack-contributed entity type(s) ${collisions.map((c) => `"${c}"`).join(", ")} collide with the reserved built-in helper key(s) on the Mongo composed helpers surface. Reserved keys: ${MONGO_RESERVED_HELPER_KEYS.map((k) => `"${k}"`).join(", ")}.`, { meta: {
|
|
154
|
+
reason: "reserved-helper-key-collision",
|
|
155
|
+
contribution: collisions
|
|
156
|
+
} });
|
|
157
|
+
return blindCast({
|
|
158
|
+
...createEntityHelpersFromNamespace(entityNamespace, { ctx: entityContextOf(family.familyId, target.targetId, components) }),
|
|
159
|
+
field: composeMongoFieldHelpers(fieldNamespace),
|
|
160
|
+
gen: createGeneratorHelpers(components),
|
|
161
|
+
index,
|
|
162
|
+
model,
|
|
163
|
+
rel,
|
|
164
|
+
valueObject
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
function createFieldBuilder(spec, enumHandle, executionDefaults, storedName, generatorCalls) {
|
|
168
|
+
function many(options) {
|
|
169
|
+
return createFieldBuilder({
|
|
170
|
+
type: spec.type,
|
|
171
|
+
nullable: spec.nullable,
|
|
172
|
+
many: { elementNullable: options?.elementsNullable ?? false }
|
|
173
|
+
}, enumHandle, executionDefaults, storedName, generatorCalls);
|
|
174
|
+
}
|
|
175
|
+
function withGeneratorCall(phase, call) {
|
|
176
|
+
if (generatorCalls?.[phase] !== void 0 || executionDefaults?.[phase] !== void 0) throw contractError("CONTRACT.DEFAULT_INVALID", `.${phase}() is called on a field that already generates a value ${phase === "onCreate" ? "on create" : "on update"}. Set each phase once, and do not combine .${phase}() with a field preset, type alias or alias constant that sets it.`, { meta: {
|
|
177
|
+
reason: "generator-phase-set-twice",
|
|
178
|
+
phase
|
|
179
|
+
} });
|
|
180
|
+
return createFieldBuilder(spec, enumHandle, blindCast(executionDefaults), storedName, {
|
|
181
|
+
...generatorCalls,
|
|
182
|
+
[phase]: call
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
return {
|
|
186
|
+
__kind: "field",
|
|
187
|
+
...ifDefined("__executionDefaults", executionDefaults),
|
|
188
|
+
...ifDefined("__generatorCalls", generatorCalls),
|
|
189
|
+
onCreate: (call) => withGeneratorCall("onCreate", call),
|
|
190
|
+
onUpdate: (call) => withGeneratorCall("onUpdate", call),
|
|
191
|
+
__type: spec.type,
|
|
192
|
+
__nullable: spec.nullable,
|
|
193
|
+
__many: spec.many,
|
|
194
|
+
__enumHandle: blindCast(enumHandle),
|
|
195
|
+
__storedName: blindCast(storedName),
|
|
196
|
+
optional: blindCast(() => createFieldBuilder({
|
|
197
|
+
type: spec.type,
|
|
198
|
+
nullable: true,
|
|
199
|
+
many: spec.many
|
|
200
|
+
}, enumHandle, executionDefaults, storedName, generatorCalls)),
|
|
201
|
+
many: blindCast(many),
|
|
202
|
+
mongo: ({ field }) => createFieldBuilder(spec, enumHandle, executionDefaults, field, generatorCalls)
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
function normalizeOptionalTypeParams(typeParams) {
|
|
206
|
+
if (!typeParams) return {};
|
|
207
|
+
return { typeParams };
|
|
208
|
+
}
|
|
209
|
+
function createScalarFieldBuilder(codecId, options) {
|
|
210
|
+
return createFieldBuilder({
|
|
211
|
+
type: blindCast({
|
|
212
|
+
kind: "scalar",
|
|
213
|
+
codecId,
|
|
214
|
+
...normalizeOptionalTypeParams(options?.typeParams)
|
|
215
|
+
}),
|
|
216
|
+
nullable: false,
|
|
217
|
+
many: false
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
function vectorField(options) {
|
|
221
|
+
return createScalarFieldBuilder("mongo/vector@1", options);
|
|
222
|
+
}
|
|
223
|
+
const field = {
|
|
224
|
+
scalar: createScalarFieldBuilder,
|
|
225
|
+
objectId() {
|
|
226
|
+
return createScalarFieldBuilder("mongo/objectId@1");
|
|
227
|
+
},
|
|
228
|
+
string() {
|
|
229
|
+
return createScalarFieldBuilder("mongo/string@1");
|
|
230
|
+
},
|
|
231
|
+
double() {
|
|
232
|
+
return createScalarFieldBuilder("mongo/double@1");
|
|
233
|
+
},
|
|
234
|
+
int32() {
|
|
235
|
+
return createScalarFieldBuilder("mongo/int32@1");
|
|
236
|
+
},
|
|
237
|
+
bool() {
|
|
238
|
+
return createScalarFieldBuilder("mongo/bool@1");
|
|
239
|
+
},
|
|
240
|
+
date() {
|
|
241
|
+
return createScalarFieldBuilder("mongo/date@1");
|
|
242
|
+
},
|
|
243
|
+
int64() {
|
|
244
|
+
return createScalarFieldBuilder("mongo/int64@1");
|
|
245
|
+
},
|
|
246
|
+
int64Number() {
|
|
247
|
+
return createScalarFieldBuilder("mongo/int64Number@1");
|
|
248
|
+
},
|
|
249
|
+
decimal128() {
|
|
250
|
+
return createScalarFieldBuilder("mongo/decimal128@1");
|
|
251
|
+
},
|
|
252
|
+
binary() {
|
|
253
|
+
return createScalarFieldBuilder("mongo/binary@1");
|
|
254
|
+
},
|
|
255
|
+
json() {
|
|
256
|
+
return createScalarFieldBuilder("mongo/json@1");
|
|
257
|
+
},
|
|
258
|
+
bson() {
|
|
259
|
+
return createScalarFieldBuilder("mongo/bson@1");
|
|
260
|
+
},
|
|
261
|
+
vector: vectorField,
|
|
262
|
+
valueObject(valueObjectName) {
|
|
263
|
+
return createFieldBuilder({
|
|
264
|
+
type: blindCast({
|
|
265
|
+
kind: "valueObject",
|
|
266
|
+
name: resolveValueObjectName(valueObjectName)
|
|
267
|
+
}),
|
|
268
|
+
nullable: false,
|
|
269
|
+
many: false
|
|
270
|
+
});
|
|
271
|
+
},
|
|
272
|
+
namedType(handle) {
|
|
273
|
+
return createFieldBuilder({
|
|
274
|
+
type: blindCast({
|
|
275
|
+
kind: "scalar",
|
|
276
|
+
codecId: handle.codecId
|
|
277
|
+
}),
|
|
278
|
+
nullable: false,
|
|
279
|
+
many: false
|
|
280
|
+
}, handle);
|
|
281
|
+
}
|
|
282
|
+
};
|
|
283
|
+
function index(fields, options) {
|
|
284
|
+
return {
|
|
285
|
+
fields,
|
|
286
|
+
...options ? { options } : {}
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
function createFieldReference(modelName, fieldName) {
|
|
290
|
+
return {
|
|
291
|
+
__kind: "fieldRef",
|
|
292
|
+
modelName,
|
|
293
|
+
fieldName
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
function isFieldReference(value) {
|
|
297
|
+
return typeof value === "object" && value !== null && "__kind" in value && value.__kind === "fieldRef";
|
|
298
|
+
}
|
|
299
|
+
function resolveModelName(value) {
|
|
300
|
+
return typeof value === "string" ? value : value.__name;
|
|
301
|
+
}
|
|
302
|
+
function resolveValueObjectName(value) {
|
|
303
|
+
return typeof value === "string" ? value : value.__name;
|
|
304
|
+
}
|
|
305
|
+
function normalizeStringList(value) {
|
|
306
|
+
return typeof value === "string" ? [value] : [...value];
|
|
307
|
+
}
|
|
308
|
+
function normalizeTargetField(targetModelName, value) {
|
|
309
|
+
if (!isFieldReference(value)) return value;
|
|
310
|
+
if (value.modelName !== targetModelName) throw contractError("CONTRACT.RELATION_INVALID", `Relation target "${targetModelName}" cannot reference field "${value.modelName}.${value.fieldName}".`, { meta: {
|
|
311
|
+
modelName: targetModelName,
|
|
312
|
+
reason: "cross-model-field-reference",
|
|
313
|
+
referencedModel: value.modelName,
|
|
314
|
+
referencedField: value.fieldName
|
|
315
|
+
} });
|
|
316
|
+
return value.fieldName;
|
|
317
|
+
}
|
|
318
|
+
function normalizeTargetFields(targetModelName, value) {
|
|
319
|
+
if (typeof value === "string") return [value];
|
|
320
|
+
if (isFieldReference(value)) return [normalizeTargetField(targetModelName, value)];
|
|
321
|
+
return value.map((entry) => normalizeTargetField(targetModelName, entry));
|
|
322
|
+
}
|
|
323
|
+
function createRelationBuilder(spec) {
|
|
324
|
+
return {
|
|
325
|
+
__kind: "relation",
|
|
326
|
+
__to: spec.to,
|
|
327
|
+
__cardinality: spec.cardinality,
|
|
328
|
+
__on: spec.on,
|
|
329
|
+
__nullable: spec.nullable
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
function createReferenceRelationBuilder(target, cardinality, options, nullable) {
|
|
333
|
+
const targetModelName = resolveModelName(target);
|
|
334
|
+
return createRelationBuilder({
|
|
335
|
+
to: blindCast(targetModelName),
|
|
336
|
+
cardinality,
|
|
337
|
+
on: {
|
|
338
|
+
localFields: blindCast(normalizeStringList(options.from)),
|
|
339
|
+
targetFields: blindCast(normalizeTargetFields(targetModelName, options.to))
|
|
340
|
+
},
|
|
341
|
+
nullable
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
function createEmbedRelationBuilder(target, cardinality) {
|
|
345
|
+
return createRelationBuilder({
|
|
346
|
+
to: blindCast(resolveModelName(target)),
|
|
347
|
+
cardinality,
|
|
348
|
+
on: void 0,
|
|
349
|
+
nullable: void 0
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
function hasOne(target, options) {
|
|
353
|
+
if (!options) return createEmbedRelationBuilder(target, "1:1");
|
|
354
|
+
return createReferenceRelationBuilder(target, "1:1", options, true);
|
|
355
|
+
}
|
|
356
|
+
function hasMany(target, options) {
|
|
357
|
+
if (!options) return createEmbedRelationBuilder(target, "1:N");
|
|
358
|
+
return createReferenceRelationBuilder(target, "1:N", options, void 0);
|
|
359
|
+
}
|
|
360
|
+
function belongsTo(target, options) {
|
|
361
|
+
return createReferenceRelationBuilder(target, "N:1", options, options.optional);
|
|
362
|
+
}
|
|
363
|
+
const rel = {
|
|
364
|
+
belongsTo,
|
|
365
|
+
hasMany,
|
|
366
|
+
hasOne
|
|
367
|
+
};
|
|
368
|
+
function valueObject(name, input) {
|
|
369
|
+
return {
|
|
370
|
+
__kind: "valueObject",
|
|
371
|
+
__name: name,
|
|
372
|
+
__fields: input.fields
|
|
373
|
+
};
|
|
374
|
+
}
|
|
375
|
+
function model(name, input) {
|
|
376
|
+
return {
|
|
377
|
+
__kind: "model",
|
|
378
|
+
__name: name,
|
|
379
|
+
__fields: input.fields,
|
|
380
|
+
__relations: blindCast(input.relations ?? {}),
|
|
381
|
+
__indexes: input.indexes,
|
|
382
|
+
__collectionOptions: input.collectionOptions,
|
|
383
|
+
__controlPolicy: input.controlPolicy,
|
|
384
|
+
__collection: blindCast(input.collection),
|
|
385
|
+
__owner: blindCast(input.owner ? resolveModelName(input.owner) : void 0),
|
|
386
|
+
__base: blindCast(input.base ? resolveModelName(input.base) : void 0),
|
|
387
|
+
__storageRelations: blindCast(input.storageRelations),
|
|
388
|
+
__discriminator: blindCast(input.discriminator ? { field: input.discriminator.field } : void 0),
|
|
389
|
+
__variants: blindCast(input.discriminator?.variants),
|
|
390
|
+
ref(fieldName) {
|
|
391
|
+
return createFieldReference(name, fieldName);
|
|
392
|
+
}
|
|
393
|
+
};
|
|
394
|
+
}
|
|
395
|
+
function validateTargetPackRef(family, target) {
|
|
396
|
+
if (family.familyId !== "mongo") throw contractError("CONTRACT.PACK_FAMILY_MISMATCH", `defineContract only accepts Mongo family packs. Received family "${family.familyId}".`, { meta: {
|
|
397
|
+
packId: family.id,
|
|
398
|
+
packFamilyId: family.familyId,
|
|
399
|
+
contractFamilyId: "mongo"
|
|
400
|
+
} });
|
|
401
|
+
if (target.familyId !== family.familyId) throw contractError("CONTRACT.PACK_FAMILY_MISMATCH", `target pack "${target.id}" targets family "${target.familyId}" but contract family is "${family.familyId}".`, { meta: {
|
|
402
|
+
packId: target.id,
|
|
403
|
+
packFamilyId: target.familyId,
|
|
404
|
+
contractFamilyId: family.familyId
|
|
405
|
+
} });
|
|
406
|
+
}
|
|
407
|
+
function validateExtensionPackRefs(target, extensions) {
|
|
408
|
+
if (!extensions) return;
|
|
409
|
+
for (const packRef of Object.values(extensions)) {
|
|
410
|
+
if (packRef.kind !== "extension") throw contractError("CONTRACT.PACK_REF_INVALID", `defineContract only accepts extension pack refs in extensions. Received kind "${packRef.kind}".`, { meta: {
|
|
411
|
+
packId: packRef.id,
|
|
412
|
+
kind: packRef.kind
|
|
413
|
+
} });
|
|
414
|
+
if (packRef.familyId !== target.familyId) throw contractError("CONTRACT.PACK_FAMILY_MISMATCH", `extension pack "${packRef.id}" targets family "${packRef.familyId}" but contract target family is "${target.familyId}".`, { meta: {
|
|
415
|
+
packId: packRef.id,
|
|
416
|
+
packFamilyId: packRef.familyId,
|
|
417
|
+
contractFamilyId: target.familyId
|
|
418
|
+
} });
|
|
419
|
+
if (packRef.targetId && packRef.targetId !== target.targetId) throw contractError("CONTRACT.PACK_TARGET_MISMATCH", `extension pack "${packRef.id}" targets "${packRef.targetId}" but contract target is "${target.targetId}".`, { meta: {
|
|
420
|
+
packId: packRef.id,
|
|
421
|
+
packTargetId: packRef.targetId,
|
|
422
|
+
contractTargetId: target.targetId
|
|
423
|
+
} });
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
function isContractScaffold(value) {
|
|
427
|
+
if (typeof value !== "object" || value === null) return false;
|
|
428
|
+
return "family" in value && "target" in value;
|
|
429
|
+
}
|
|
430
|
+
function buildContractField(builder) {
|
|
431
|
+
const valueSet = builder.__enumHandle ? {
|
|
432
|
+
plane: "domain",
|
|
433
|
+
entityKind: "enum",
|
|
434
|
+
namespaceId: UNBOUND_NAMESPACE_ID,
|
|
435
|
+
entityName: builder.__enumHandle.enumName
|
|
436
|
+
} : void 0;
|
|
437
|
+
return {
|
|
438
|
+
type: builder.__type,
|
|
439
|
+
nullable: builder.__nullable,
|
|
440
|
+
many: builder.__many,
|
|
441
|
+
...ifDefined("valueSet", valueSet)
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
function storedNameOf(fieldName, fieldBuilder) {
|
|
445
|
+
return fieldBuilder.__storedName ?? fieldName;
|
|
446
|
+
}
|
|
447
|
+
function buildStorageFields(modelName, fields) {
|
|
448
|
+
const storageFields = {};
|
|
449
|
+
const fieldsByStoredName = /* @__PURE__ */ new Map();
|
|
450
|
+
for (const [fieldName, fieldBuilder] of Object.entries(fields)) {
|
|
451
|
+
const storedName = storedNameOf(fieldName, fieldBuilder);
|
|
452
|
+
const unsupported = unsupportedStoredNameReason(storedName);
|
|
453
|
+
if (unsupported !== void 0) throw contractError("CONTRACT.ARGUMENT_INVALID", `Model "${modelName}" field "${fieldName}" ${unsupported}. Give it another stored name.`, { meta: {
|
|
454
|
+
modelName,
|
|
455
|
+
fieldName,
|
|
456
|
+
reason: "stored-name-unsupported"
|
|
457
|
+
} });
|
|
458
|
+
const existingField = fieldsByStoredName.get(storedName);
|
|
459
|
+
if (existingField !== void 0) throw contractError("CONTRACT.NAME_DUPLICATE", `Model "${modelName}" stores both "${existingField}" and "${fieldName}" as "${storedName}".`, { meta: {
|
|
460
|
+
kind: "field",
|
|
461
|
+
name: storedName,
|
|
462
|
+
first: existingField,
|
|
463
|
+
second: fieldName
|
|
464
|
+
} });
|
|
465
|
+
fieldsByStoredName.set(storedName, fieldName);
|
|
466
|
+
storageFields[fieldName] = { field: storedName };
|
|
467
|
+
}
|
|
468
|
+
return storageFields;
|
|
469
|
+
}
|
|
470
|
+
function storedFieldNameIn(fields, fieldName) {
|
|
471
|
+
const fieldBuilder = Object.hasOwn(fields, fieldName) ? fields[fieldName] : void 0;
|
|
472
|
+
return fieldBuilder === void 0 ? fieldName : storedNameOf(fieldName, fieldBuilder);
|
|
473
|
+
}
|
|
474
|
+
function buildFields(fields) {
|
|
475
|
+
const builtFields = {};
|
|
476
|
+
for (const [fieldName, fieldBuilder] of Object.entries(fields)) builtFields[fieldName] = buildContractField(fieldBuilder);
|
|
477
|
+
return builtFields;
|
|
478
|
+
}
|
|
479
|
+
function toOneRelationNullable(modelName, relationName, relationBuilder, on, fields) {
|
|
480
|
+
const location = `Relation "${modelName}.${relationName}"`;
|
|
481
|
+
const ownsForeignKey = relationBuilder.__cardinality !== "1:1";
|
|
482
|
+
const localFields = ownsForeignKey ? on.localFields.map((fieldName) => {
|
|
483
|
+
const localField = fields[fieldName];
|
|
484
|
+
if (localField === void 0) throw contractError("CONTRACT.RELATION_INVALID", `${location} joins on local field "${fieldName}", which model "${modelName}" does not declare`, { meta: {
|
|
485
|
+
modelName,
|
|
486
|
+
relationName,
|
|
487
|
+
fieldName,
|
|
488
|
+
reason: "local-field-unknown"
|
|
489
|
+
} });
|
|
490
|
+
return localField;
|
|
491
|
+
}) : [];
|
|
492
|
+
const { nullable, contradiction } = resolveToOneRelationNullable({
|
|
493
|
+
declaredNullable: relationBuilder.__nullable,
|
|
494
|
+
localFieldNullability: localFields.map((localField) => localField.__nullable === true),
|
|
495
|
+
ownsReference: ownsForeignKey
|
|
496
|
+
});
|
|
497
|
+
if (contradiction !== void 0) throw contractError("CONTRACT.RELATION_INVALID", !ownsForeignKey ? `${location} is required but does not own the foreign key, so nothing in storage guarantees the related document exists` : contradiction === "declared-optional" ? `${location} is optional but every local field it joins on is required` : `${location} is required but a local field it joins on is nullable`, { meta: {
|
|
498
|
+
modelName,
|
|
499
|
+
relationName,
|
|
500
|
+
reason: "to-one-nullability-mismatch"
|
|
501
|
+
} });
|
|
502
|
+
return nullable;
|
|
503
|
+
}
|
|
504
|
+
function buildRelation(modelName, relationName, relationBuilder, fields) {
|
|
505
|
+
const to = crossRef(relationBuilder.__to, UNBOUND_NAMESPACE_ID);
|
|
506
|
+
const on = relationBuilder.__on;
|
|
507
|
+
if (on === void 0) return {
|
|
508
|
+
to,
|
|
509
|
+
cardinality: relationBuilder.__cardinality
|
|
510
|
+
};
|
|
511
|
+
if (relationBuilder.__cardinality === "1:N") return {
|
|
512
|
+
to,
|
|
513
|
+
cardinality: "1:N",
|
|
514
|
+
on
|
|
515
|
+
};
|
|
516
|
+
return {
|
|
517
|
+
to,
|
|
518
|
+
cardinality: relationBuilder.__cardinality,
|
|
519
|
+
nullable: toOneRelationNullable(modelName, relationName, relationBuilder, on, fields),
|
|
520
|
+
on
|
|
521
|
+
};
|
|
522
|
+
}
|
|
523
|
+
function buildRelations(modelName, relations, fields) {
|
|
524
|
+
const builtRelations = {};
|
|
525
|
+
for (const [relationName, relationBuilder] of Object.entries(relations)) builtRelations[relationName] = buildRelation(modelName, relationName, relationBuilder, fields);
|
|
526
|
+
return builtRelations;
|
|
527
|
+
}
|
|
528
|
+
function buildValueObjects(valueObjects) {
|
|
529
|
+
const builtValueObjects = {};
|
|
530
|
+
for (const valueObjectBuilder of Object.values(valueObjects ?? {})) {
|
|
531
|
+
if (valueObjectBuilder.__name in builtValueObjects) throw contractError("CONTRACT.NAME_DUPLICATE", `Duplicate value object name "${valueObjectBuilder.__name}" in defineContract().`, { meta: {
|
|
532
|
+
kind: "valueObject",
|
|
533
|
+
name: valueObjectBuilder.__name
|
|
534
|
+
} });
|
|
535
|
+
for (const [fieldName, fieldBuilder] of Object.entries(valueObjectBuilder.__fields)) if (fieldBuilder.__storedName !== void 0) throw contractError("CONTRACT.ARGUMENT_INVALID", `Value object "${valueObjectBuilder.__name}" field "${fieldName}" sets .mongo({ field }), but a field of a value object is stored under its own name.`, { meta: {
|
|
536
|
+
valueObjectName: valueObjectBuilder.__name,
|
|
537
|
+
fieldName,
|
|
538
|
+
reason: "value-object-field-stored-name"
|
|
539
|
+
} });
|
|
540
|
+
builtValueObjects[valueObjectBuilder.__name] = { fields: buildFields(valueObjectBuilder.__fields) };
|
|
541
|
+
}
|
|
542
|
+
return builtValueObjects;
|
|
543
|
+
}
|
|
544
|
+
function buildModels(models) {
|
|
545
|
+
const builtModels = {};
|
|
546
|
+
for (const modelBuilder of Object.values(models ?? {})) {
|
|
547
|
+
if (modelBuilder.__name in builtModels) throw contractError("CONTRACT.NAME_DUPLICATE", `Duplicate model name "${modelBuilder.__name}" in defineContract().`, { meta: {
|
|
548
|
+
kind: "model",
|
|
549
|
+
name: modelBuilder.__name
|
|
550
|
+
} });
|
|
551
|
+
assertUniqueDiscriminatorValues(modelBuilder);
|
|
552
|
+
const storage = {
|
|
553
|
+
...modelBuilder.__collection ? { collection: modelBuilder.__collection } : {},
|
|
554
|
+
fields: buildStorageFields(modelBuilder.__name, modelBuilder.__fields),
|
|
555
|
+
...modelBuilder.__storageRelations ? { relations: modelBuilder.__storageRelations } : {}
|
|
556
|
+
};
|
|
557
|
+
builtModels[modelBuilder.__name] = {
|
|
558
|
+
fields: buildFields(modelBuilder.__fields),
|
|
559
|
+
relations: buildRelations(modelBuilder.__name, modelBuilder.__relations, modelBuilder.__fields),
|
|
560
|
+
storage,
|
|
561
|
+
...modelBuilder.__owner ? { owner: modelBuilder.__owner } : {},
|
|
562
|
+
...modelBuilder.__base ? { base: crossRef(modelBuilder.__base, UNBOUND_NAMESPACE_ID) } : {},
|
|
563
|
+
...modelBuilder.__discriminator ? { discriminator: modelBuilder.__discriminator } : {},
|
|
564
|
+
...modelBuilder.__variants ? { variants: Object.fromEntries(Object.entries(modelBuilder.__variants).map(([variantName, { value }]) => [value, crossRef(variantName, UNBOUND_NAMESPACE_ID)])) } : {}
|
|
565
|
+
};
|
|
566
|
+
}
|
|
567
|
+
return builtModels;
|
|
568
|
+
}
|
|
569
|
+
function assertUniqueDiscriminatorValues(modelBuilder) {
|
|
570
|
+
const variantNamesByValue = /* @__PURE__ */ new Map();
|
|
571
|
+
for (const [variantName, { value }] of Object.entries(modelBuilder.__variants ?? {})) {
|
|
572
|
+
const existingVariant = variantNamesByValue.get(value);
|
|
573
|
+
if (existingVariant !== void 0) throw contractError("CONTRACT.ARGUMENT_INVALID", `Discriminator value "${value}" is used by both "${existingVariant}" and "${variantName}" on base model "${modelBuilder.__name}".`, { meta: {
|
|
574
|
+
modelName: modelBuilder.__name,
|
|
575
|
+
value,
|
|
576
|
+
variants: [existingVariant, variantName],
|
|
577
|
+
reason: "duplicate-discriminator-value"
|
|
578
|
+
} });
|
|
579
|
+
variantNamesByValue.set(value, variantName);
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
function deriveRoots(models) {
|
|
583
|
+
const roots = {};
|
|
584
|
+
for (const modelBuilder of Object.values(models ?? {})) {
|
|
585
|
+
if (!modelBuilder.__collection || modelBuilder.__owner || modelBuilder.__base) continue;
|
|
586
|
+
roots[modelBuilder.__collection] = crossRef(modelBuilder.__name, UNBOUND_NAMESPACE_ID);
|
|
587
|
+
}
|
|
588
|
+
return roots;
|
|
589
|
+
}
|
|
590
|
+
function normalizeRoots(roots) {
|
|
591
|
+
const normalizedRoots = {};
|
|
592
|
+
for (const [rootName, rootValue] of Object.entries(roots ?? {})) normalizedRoots[rootName] = crossRef(resolveModelName(rootValue), UNBOUND_NAMESPACE_ID);
|
|
593
|
+
return normalizedRoots;
|
|
594
|
+
}
|
|
595
|
+
function storedIndexKey(fields, key) {
|
|
596
|
+
const scope = key.match(/^(.+)\.\$\*\*$/)?.[1];
|
|
597
|
+
if (scope !== void 0) return `${storedFieldNameIn(fields, scope)}.$**`;
|
|
598
|
+
return key === "$**" ? key : storedFieldNameIn(fields, key);
|
|
599
|
+
}
|
|
600
|
+
function toStorageIndex(index, fields) {
|
|
601
|
+
const input = { keys: Object.entries(index.fields).map(([field, direction]) => ({
|
|
602
|
+
field: storedIndexKey(fields, field),
|
|
603
|
+
direction
|
|
604
|
+
})) };
|
|
605
|
+
if (index.options) {
|
|
606
|
+
for (const [key, value] of Object.entries(index.options)) if (value !== void 0) input[key] = value;
|
|
607
|
+
}
|
|
608
|
+
return new MongoIndex(blindCast(input));
|
|
609
|
+
}
|
|
610
|
+
function toStorageCollectionOptions(opts) {
|
|
611
|
+
return new MongoCollectionOptions({
|
|
612
|
+
...opts.capped ? { capped: {
|
|
613
|
+
size: opts.size ?? 0,
|
|
614
|
+
...opts.max != null && { max: opts.max }
|
|
615
|
+
} } : {},
|
|
616
|
+
...ifDefined("storageEngine", opts.storageEngine),
|
|
617
|
+
...ifDefined("indexOptionDefaults", opts.indexOptionDefaults),
|
|
618
|
+
...ifDefined("collation", opts.collation),
|
|
619
|
+
...ifDefined("timeseries", opts.timeseries),
|
|
620
|
+
...opts.clusteredIndex !== void 0 && { clusteredIndex: opts.clusteredIndex.name !== void 0 ? { name: opts.clusteredIndex.name } : {} },
|
|
621
|
+
...ifDefined("expireAfterSeconds", opts.expireAfterSeconds),
|
|
622
|
+
...ifDefined("changeStreamPreAndPostImages", opts.changeStreamPreAndPostImages)
|
|
623
|
+
});
|
|
624
|
+
}
|
|
625
|
+
function findMissingIndexField(index, modelFields) {
|
|
626
|
+
for (const fieldName of Object.keys(index.fields)) {
|
|
627
|
+
const wildcardMatch = fieldName.match(/^(.+)\.\$\*\*$/);
|
|
628
|
+
const lookupName = wildcardMatch ? wildcardMatch[1] : fieldName;
|
|
629
|
+
if (lookupName === void 0 || lookupName.length === 0) continue;
|
|
630
|
+
if (lookupName === "$**") continue;
|
|
631
|
+
if (!Object.hasOwn(modelFields, lookupName)) return lookupName;
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
function resolveVariantScope(modelBuilder, modelsByName) {
|
|
635
|
+
if (!modelBuilder.__base) return void 0;
|
|
636
|
+
const baseBuilder = modelsByName[modelBuilder.__base];
|
|
637
|
+
if (!baseBuilder) return void 0;
|
|
638
|
+
const discriminatorField = baseBuilder.__discriminator?.field;
|
|
639
|
+
const variantValue = baseBuilder.__variants?.[modelBuilder.__name]?.value;
|
|
640
|
+
if (!discriminatorField || variantValue === void 0) return void 0;
|
|
641
|
+
return {
|
|
642
|
+
discriminatorField: storedFieldNameIn(baseBuilder.__fields, discriminatorField),
|
|
643
|
+
discriminatorValue: variantValue
|
|
644
|
+
};
|
|
645
|
+
}
|
|
646
|
+
function scopeVariantIndex(storageIndex, scope, variantName, authoredIndex) {
|
|
647
|
+
const result = applyPolymorphicScopeToMongoIndex(storageIndex, scope);
|
|
648
|
+
if (result.kind === "conflict") {
|
|
649
|
+
const indexLabel = authoredIndex ? canonicalStringify(authoredIndex) : "<unknown>";
|
|
650
|
+
throw contractError("CONTRACT.INDEX_INVALID", `Variant model "${variantName}" index ${indexLabel} conflicts with discriminator scope: ${result.reason}`, { meta: {
|
|
651
|
+
variantName,
|
|
652
|
+
indexLabel,
|
|
653
|
+
reason: result.reason
|
|
654
|
+
} });
|
|
655
|
+
}
|
|
656
|
+
return result.index;
|
|
657
|
+
}
|
|
658
|
+
function buildCollections(models) {
|
|
659
|
+
const intermediate = {};
|
|
660
|
+
const declaredIndexOwners = /* @__PURE__ */ new Map();
|
|
661
|
+
const modelMap = models ?? {};
|
|
662
|
+
const modelsByName = {};
|
|
663
|
+
for (const builder of Object.values(modelMap)) modelsByName[builder.__name] = builder;
|
|
664
|
+
for (const modelBuilder of Object.values(modelMap)) {
|
|
665
|
+
if (!modelBuilder.__collection) {
|
|
666
|
+
if (modelBuilder.__indexes && modelBuilder.__indexes.length > 0) throw contractError("CONTRACT.COLLECTION_INVALID", `Model "${modelBuilder.__name}" defines indexes but has no collection to attach them to.`, { meta: {
|
|
667
|
+
modelName: modelBuilder.__name,
|
|
668
|
+
reason: "indexes-without-collection"
|
|
669
|
+
} });
|
|
670
|
+
if (modelBuilder.__collectionOptions) throw contractError("CONTRACT.COLLECTION_INVALID", `Model "${modelBuilder.__name}" defines collectionOptions but has no collection to attach them to.`, { meta: {
|
|
671
|
+
modelName: modelBuilder.__name,
|
|
672
|
+
reason: "collectionOptions-without-collection"
|
|
673
|
+
} });
|
|
674
|
+
if (modelBuilder.__controlPolicy) throw contractError("CONTRACT.COLLECTION_INVALID", `Model "${modelBuilder.__name}" defines controlPolicy but has no collection to attach it to.`, { meta: {
|
|
675
|
+
modelName: modelBuilder.__name,
|
|
676
|
+
reason: "controlPolicy-without-collection"
|
|
677
|
+
} });
|
|
678
|
+
continue;
|
|
679
|
+
}
|
|
680
|
+
const existingCollection = intermediate[modelBuilder.__collection] ?? {};
|
|
681
|
+
const existingIndexes = existingCollection.indexes ?? [];
|
|
682
|
+
if (existingCollection.options && modelBuilder.__collectionOptions) throw contractError("CONTRACT.COLLECTION_INVALID", `Collection "${modelBuilder.__collection}" has collectionOptions declared by multiple models. Author collectionOptions on a single model per collection.`, { meta: {
|
|
683
|
+
modelName: modelBuilder.__name,
|
|
684
|
+
collection: modelBuilder.__collection,
|
|
685
|
+
reason: "collectionOptions-declared-by-multiple-models"
|
|
686
|
+
} });
|
|
687
|
+
if (existingCollection.control !== void 0 && modelBuilder.__controlPolicy) throw contractError("CONTRACT.COLLECTION_INVALID", `Collection "${modelBuilder.__collection}" has controlPolicy declared by multiple models. Author controlPolicy on a single model per collection.`, { meta: {
|
|
688
|
+
modelName: modelBuilder.__name,
|
|
689
|
+
collection: modelBuilder.__collection,
|
|
690
|
+
reason: "controlPolicy-declared-by-multiple-models"
|
|
691
|
+
} });
|
|
692
|
+
for (const collectionIndex of modelBuilder.__indexes ?? []) {
|
|
693
|
+
const missingField = findMissingIndexField(collectionIndex, modelBuilder.__fields);
|
|
694
|
+
if (missingField !== void 0) {
|
|
695
|
+
const indexSignature = canonicalStringify(collectionIndex);
|
|
696
|
+
throw contractError("CONTRACT.FIELD_UNKNOWN", `Model "${modelBuilder.__name}" index ${indexSignature} references unknown field "${missingField}".`, { meta: {
|
|
697
|
+
modelName: modelBuilder.__name,
|
|
698
|
+
fieldName: missingField,
|
|
699
|
+
indexSignature
|
|
700
|
+
} });
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
const polymorphicScope = resolveVariantScope(modelBuilder, modelsByName);
|
|
704
|
+
const rawStorageIndexes = (modelBuilder.__indexes ?? []).map((authored) => toStorageIndex(authored, modelBuilder.__fields));
|
|
705
|
+
const storageIndexes = polymorphicScope ? rawStorageIndexes.map((idx, i) => scopeVariantIndex(idx, polymorphicScope, modelBuilder.__name, modelBuilder.__indexes?.[i])) : rawStorageIndexes;
|
|
706
|
+
for (let i = 0; i < storageIndexes.length; i++) {
|
|
707
|
+
const storageIndex = storageIndexes[i];
|
|
708
|
+
if (storageIndex === void 0) continue;
|
|
709
|
+
const indexSignature = stableStringify(storageIndex);
|
|
710
|
+
const collectionIndexKey = `${modelBuilder.__collection}:${indexSignature}`;
|
|
711
|
+
const firstOwner = declaredIndexOwners.get(collectionIndexKey);
|
|
712
|
+
if (firstOwner) {
|
|
713
|
+
const authoredIndex = modelBuilder.__indexes?.[i];
|
|
714
|
+
const reportedSignature = authoredIndex ? canonicalStringify(authoredIndex) : indexSignature;
|
|
715
|
+
throw contractError("CONTRACT.NAME_DUPLICATE", `Collection "${modelBuilder.__collection}" defines duplicate index ${reportedSignature}. First declared on model "${firstOwner}" and duplicated on model "${modelBuilder.__name}".`, { meta: {
|
|
716
|
+
kind: "index",
|
|
717
|
+
name: reportedSignature,
|
|
718
|
+
collection: modelBuilder.__collection,
|
|
719
|
+
first: firstOwner,
|
|
720
|
+
second: modelBuilder.__name
|
|
721
|
+
} });
|
|
722
|
+
}
|
|
723
|
+
declaredIndexOwners.set(collectionIndexKey, modelBuilder.__name);
|
|
724
|
+
}
|
|
725
|
+
const storageOptions = modelBuilder.__collectionOptions ? toStorageCollectionOptions(modelBuilder.__collectionOptions) : void 0;
|
|
726
|
+
const controlPatch = modelBuilder.__controlPolicy !== void 0 ? { control: modelBuilder.__controlPolicy } : {};
|
|
727
|
+
intermediate[modelBuilder.__collection] = storageIndexes.length > 0 ? {
|
|
728
|
+
...existingCollection,
|
|
729
|
+
indexes: [...existingIndexes, ...storageIndexes],
|
|
730
|
+
...storageOptions ? { options: storageOptions } : {},
|
|
731
|
+
...controlPatch
|
|
732
|
+
} : storageOptions ? {
|
|
733
|
+
...existingCollection,
|
|
734
|
+
options: storageOptions,
|
|
735
|
+
...controlPatch
|
|
736
|
+
} : Object.keys(controlPatch).length > 0 ? {
|
|
737
|
+
...existingCollection,
|
|
738
|
+
...controlPatch
|
|
739
|
+
} : existingCollection;
|
|
740
|
+
}
|
|
741
|
+
return intermediate;
|
|
742
|
+
}
|
|
743
|
+
function executionDefaultError(modelName, fieldName, reason, message) {
|
|
744
|
+
return contractError("CONTRACT.DEFAULT_INVALID", `Field "${modelName}.${fieldName}" ${message}`, { meta: {
|
|
745
|
+
modelName,
|
|
746
|
+
fieldName,
|
|
747
|
+
reason
|
|
748
|
+
} });
|
|
749
|
+
}
|
|
750
|
+
function hasExecutionDefaults(fieldBuilder) {
|
|
751
|
+
const phases = fieldBuilder.__executionDefaults;
|
|
752
|
+
const calls = fieldBuilder.__generatorCalls;
|
|
753
|
+
return phases?.onCreate !== void 0 || phases?.onUpdate !== void 0 || calls?.onCreate !== void 0 || calls?.onUpdate !== void 0;
|
|
754
|
+
}
|
|
755
|
+
/**
|
|
756
|
+
* The phases a field generates: a preset's, with the generators its `.onCreate(...)` and `.onUpdate(...)` calls resolve to for its codec.
|
|
757
|
+
*/
|
|
758
|
+
function executionDefaultsOf(fieldBuilder, modelName, fieldName, generatorFunctions) {
|
|
759
|
+
const calls = fieldBuilder.__generatorCalls;
|
|
760
|
+
if (calls === void 0) return fieldBuilder.__executionDefaults;
|
|
761
|
+
const type = fieldBuilder.__type;
|
|
762
|
+
const codecId = type.kind === "scalar" ? type.codecId : void 0;
|
|
763
|
+
const phases = { ...fieldBuilder.__executionDefaults };
|
|
764
|
+
for (const phase of ["onCreate", "onUpdate"]) {
|
|
765
|
+
const call = calls[phase];
|
|
766
|
+
if (call === void 0) continue;
|
|
767
|
+
const resolution = type.kind === "scalar" ? generatorFunctions.resolve(call, {
|
|
768
|
+
codecId: type.codecId,
|
|
769
|
+
typeParams: type.typeParams,
|
|
770
|
+
length: void 0
|
|
771
|
+
}) : void 0;
|
|
772
|
+
if (resolution?.ok === true) {
|
|
773
|
+
phases[phase] = resolution.generator;
|
|
774
|
+
continue;
|
|
775
|
+
}
|
|
776
|
+
const meta = {
|
|
777
|
+
modelName,
|
|
778
|
+
fieldName,
|
|
779
|
+
codecId,
|
|
780
|
+
function: call.name
|
|
781
|
+
};
|
|
782
|
+
if (resolution?.reason === "unknown-function") throw contractError("CONTRACT.DEFAULT_INVALID", `Field "${modelName}.${fieldName}": no pack in the contract declares the generator function "${call.name}".`, { meta: {
|
|
783
|
+
...meta,
|
|
784
|
+
reason: "generator-unknown"
|
|
785
|
+
} });
|
|
786
|
+
throw contractError("CONTRACT.DEFAULT_INVALID", resolution?.reason === "refused" ? `Field "${modelName}.${fieldName}": ${resolution.message}` : `Field "${modelName}.${fieldName}": ${call.name}() does not apply to ${codecId === void 0 ? "the field's type" : `codec "${codecId}"`}.`, { meta: {
|
|
787
|
+
...meta,
|
|
788
|
+
reason: "generator-not-applicable"
|
|
789
|
+
} });
|
|
790
|
+
}
|
|
791
|
+
return phases;
|
|
792
|
+
}
|
|
793
|
+
function assertNoValueObjectExecutionDefaults(valueObjects) {
|
|
794
|
+
for (const valueObjectBuilder of Object.values(valueObjects ?? {})) for (const [fieldName, fieldBuilder] of Object.entries(valueObjectBuilder.__fields)) if (hasExecutionDefaults(fieldBuilder)) throw executionDefaultError(valueObjectBuilder.__name, fieldName, "executionDefaults-on-value-object", "has executionDefaults, but it belongs to a value object. Generated values are only supported on model fields.");
|
|
795
|
+
}
|
|
796
|
+
function buildExecutionDefaults(models, generatorFunctions) {
|
|
797
|
+
const modelBuilders = Object.values(models ?? {});
|
|
798
|
+
const collectionByModelName = new Map(modelBuilders.map((modelBuilder) => [modelBuilder.__name, modelBuilder.__collection]));
|
|
799
|
+
const byRef = /* @__PURE__ */ new Map();
|
|
800
|
+
const defaults = [];
|
|
801
|
+
for (const modelBuilder of modelBuilders) for (const [fieldName, fieldBuilder] of Object.entries(modelBuilder.__fields)) {
|
|
802
|
+
if (!hasExecutionDefaults(fieldBuilder)) continue;
|
|
803
|
+
const modelName = modelBuilder.__name;
|
|
804
|
+
const phases = executionDefaultsOf(fieldBuilder, modelName, fieldName, generatorFunctions);
|
|
805
|
+
if (phases === void 0) continue;
|
|
806
|
+
if (fieldBuilder.__nullable) throw executionDefaultError(modelName, fieldName, "nullable-with-executionDefaults", "generates a value on write, so it cannot be optional; remove .optional().");
|
|
807
|
+
if (fieldBuilder.__many) throw executionDefaultError(modelName, fieldName, "many-with-executionDefaults", "generates a value on write, so it cannot be a list; remove .many().");
|
|
808
|
+
if (modelBuilder.__base !== void 0) {
|
|
809
|
+
const collection = modelBuilder.__collection ?? collectionByModelName.get(modelBuilder.__base);
|
|
810
|
+
throw executionDefaultError(modelName, fieldName, "executionDefaults-on-variant", `has executionDefaults, but "${modelName}" is a variant of "${modelBuilder.__base}". Execution defaults apply to every document in collection "${collection}", so declare them on the base model.`);
|
|
811
|
+
}
|
|
812
|
+
const entry = modelBuilder.__collection;
|
|
813
|
+
if (entry === void 0) throw executionDefaultError(modelName, fieldName, "executionDefaults-without-collection", "has executionDefaults, but its model has no collection. Generated values are only supported on fields of a model stored in a collection.");
|
|
814
|
+
const storedName = storedNameOf(fieldName, fieldBuilder);
|
|
815
|
+
const refKey = JSON.stringify([entry, storedName]);
|
|
816
|
+
const phasesKey = canonicalStringify(phases);
|
|
817
|
+
const existing = byRef.get(refKey);
|
|
818
|
+
if (existing !== void 0) {
|
|
819
|
+
if (existing.phasesKey !== phasesKey) throw executionDefaultError(modelName, fieldName, "executionDefaults-conflict", `has different executionDefaults than "${existing.modelName}.${existing.fieldName}", which is stored in the same collection "${entry}". Use the same executionDefaults on both models.`);
|
|
820
|
+
continue;
|
|
821
|
+
}
|
|
822
|
+
byRef.set(refKey, {
|
|
823
|
+
modelName,
|
|
824
|
+
fieldName,
|
|
825
|
+
phasesKey
|
|
826
|
+
});
|
|
827
|
+
defaults.push({
|
|
828
|
+
ref: {
|
|
829
|
+
namespace: UNBOUND_NAMESPACE_ID,
|
|
830
|
+
entry,
|
|
831
|
+
field: storedName
|
|
832
|
+
},
|
|
833
|
+
...phases
|
|
834
|
+
});
|
|
835
|
+
}
|
|
836
|
+
return defaults;
|
|
837
|
+
}
|
|
838
|
+
function buildContractFromDefinition(definition) {
|
|
839
|
+
validateTargetPackRef(definition.family, definition.target);
|
|
840
|
+
validateExtensionPackRefs(definition.target, definition.extensions);
|
|
841
|
+
const builtModels = buildModels(definition.models);
|
|
842
|
+
const builtValueObjects = buildValueObjects(definition.valueObjects);
|
|
843
|
+
const roots = definition.roots ? normalizeRoots(definition.roots) : deriveRoots(definition.models);
|
|
844
|
+
const capabilities = {};
|
|
845
|
+
const collections = buildCollections(definition.models);
|
|
846
|
+
assertNoValueObjectExecutionDefaults(definition.valueObjects);
|
|
847
|
+
const components = [
|
|
848
|
+
definition.family,
|
|
849
|
+
definition.target,
|
|
850
|
+
...Object.values(definition.extensions ?? {})
|
|
851
|
+
];
|
|
852
|
+
const generatorFunctions = assembleGeneratorFunctions(components);
|
|
853
|
+
const codecLookup = extractCodecLookup(components);
|
|
854
|
+
assertTypeAliasesValid(composePackAuthoringNamespace(components, "type"), {
|
|
855
|
+
generatorFunctions,
|
|
856
|
+
paramsSchemaOf: (codecId) => codecLookup.descriptorFor(codecId)?.paramsSchema,
|
|
857
|
+
fieldLength: () => void 0
|
|
858
|
+
});
|
|
859
|
+
const execution = buildExecutionSection({
|
|
860
|
+
target: definition.target.targetId,
|
|
861
|
+
targetFamily: definition.family.familyId,
|
|
862
|
+
defaults: buildExecutionDefaults(definition.models, generatorFunctions)
|
|
863
|
+
});
|
|
864
|
+
const lookups = {
|
|
865
|
+
codecLookup,
|
|
866
|
+
dataTypeLookup: assembleDataTypes(components).lookup
|
|
867
|
+
};
|
|
868
|
+
assertMongoFieldTypeParams({ [UNBOUND_NAMESPACE_ID]: {
|
|
869
|
+
models: builtModels,
|
|
870
|
+
valueObjects: builtValueObjects
|
|
871
|
+
} }, lookups);
|
|
872
|
+
const builtEnums = {};
|
|
873
|
+
for (const [enumName, handle] of Object.entries(definition.enums ?? {})) builtEnums[enumName] = {
|
|
874
|
+
codecId: handle.codecId,
|
|
875
|
+
members: encodeEnumTypeMembers(handle, codecLookup, "the field")
|
|
876
|
+
};
|
|
877
|
+
const storageValueSets = mongoValueSetsOf(builtEnums);
|
|
878
|
+
for (const [enumName, handle] of Object.entries(definition.enums ?? {})) if (enumName !== handle.enumName) throw contractError("CONTRACT.ENUM_INVALID", `enum declaration key "${enumName}" must match enumType name "${handle.enumName}". Aliases are not supported.`, { meta: {
|
|
879
|
+
enumName: handle.enumName,
|
|
880
|
+
declaredKey: enumName,
|
|
881
|
+
reason: "declaration-key-mismatch"
|
|
882
|
+
} });
|
|
883
|
+
const hasEnums = Object.keys(builtEnums).length > 0;
|
|
884
|
+
for (const [modelName, modelBuilder] of Object.entries(definition.models ?? {})) for (const [fieldName, fieldBuilder] of Object.entries(modelBuilder.__fields)) {
|
|
885
|
+
const handle = fieldBuilder.__enumHandle;
|
|
886
|
+
if (handle && !(handle.enumName in builtEnums)) throw contractError("CONTRACT.ENUM_UNKNOWN", `Model "${modelName}" field "${fieldName}" references enum "${handle.enumName}" which is not declared in defineContract({ enums: { ... } }).`, { meta: {
|
|
887
|
+
modelName,
|
|
888
|
+
fieldName,
|
|
889
|
+
enumName: handle.enumName
|
|
890
|
+
} });
|
|
891
|
+
}
|
|
892
|
+
const controlPolicies = {
|
|
893
|
+
collections: Object.fromEntries(Object.entries(collections).map(([name, collection]) => [name, collection.control])),
|
|
894
|
+
defaultControlPolicy: definition.defaultControlPolicy
|
|
895
|
+
};
|
|
896
|
+
assertCollectionValidatorSources({
|
|
897
|
+
models: builtModels,
|
|
898
|
+
valueObjects: builtValueObjects,
|
|
899
|
+
enums: builtEnums,
|
|
900
|
+
lookups,
|
|
901
|
+
controlPolicies
|
|
902
|
+
});
|
|
903
|
+
const validators = deriveCollectionValidators({
|
|
904
|
+
models: builtModels,
|
|
905
|
+
lookups,
|
|
906
|
+
valueObjects: builtValueObjects,
|
|
907
|
+
valueSets: storageValueSets,
|
|
908
|
+
controlPolicies
|
|
909
|
+
});
|
|
910
|
+
const storage = buildMongoStorage({
|
|
911
|
+
collections: Object.fromEntries(Object.entries(collections).map(([name, collection]) => [name, {
|
|
912
|
+
...collection,
|
|
913
|
+
...ifDefined("validator", validators[name])
|
|
914
|
+
}])),
|
|
915
|
+
valueSets: storageValueSets
|
|
916
|
+
});
|
|
917
|
+
return blindCast({
|
|
918
|
+
target: definition.target.targetId,
|
|
919
|
+
targetFamily: definition.family.familyId,
|
|
920
|
+
...ifDefined("defaultControlPolicy", definition.defaultControlPolicy),
|
|
921
|
+
roots,
|
|
922
|
+
domain: { namespaces: { [UNBOUND_NAMESPACE_ID]: {
|
|
923
|
+
models: builtModels,
|
|
924
|
+
...Object.keys(builtValueObjects).length > 0 ? { valueObjects: builtValueObjects } : {},
|
|
925
|
+
...hasEnums ? { enum: builtEnums } : {}
|
|
926
|
+
} } },
|
|
927
|
+
storage,
|
|
928
|
+
capabilities,
|
|
929
|
+
extensions: definition.extensions ?? {},
|
|
930
|
+
profileHash: computeProfileHash({
|
|
931
|
+
target: definition.target.targetId,
|
|
932
|
+
targetFamily: definition.family.familyId,
|
|
933
|
+
capabilities
|
|
934
|
+
}),
|
|
935
|
+
meta: {},
|
|
936
|
+
...ifDefined("execution", execution)
|
|
937
|
+
});
|
|
938
|
+
}
|
|
939
|
+
/** Implementation. */
|
|
940
|
+
function buildBoundContract(family, target, definition, factory) {
|
|
941
|
+
const full = {
|
|
942
|
+
...definition,
|
|
943
|
+
family,
|
|
944
|
+
target
|
|
945
|
+
};
|
|
946
|
+
if (factory !== void 0) {
|
|
947
|
+
const built = factory(composeMongoAuthoringHelpers(family, target, definition.extensions));
|
|
948
|
+
return buildContractFromDefinition({
|
|
949
|
+
...full,
|
|
950
|
+
...ifDefined("models", built.models),
|
|
951
|
+
...ifDefined("valueObjects", built.valueObjects),
|
|
952
|
+
...ifDefined("roots", built.roots)
|
|
953
|
+
});
|
|
954
|
+
}
|
|
955
|
+
return buildContractFromDefinition(full);
|
|
956
|
+
}
|
|
957
|
+
function defineContract(definition, factory) {
|
|
958
|
+
if (!isContractScaffold(definition)) throw contractError("CONTRACT.ARGUMENT_INVALID", "defineContract expects a contract definition object. Define your contract with defineContract({ family, target, models, ... }).");
|
|
959
|
+
if (factory !== void 0) return buildBoundContract(definition.family, definition.target, definition, factory);
|
|
960
|
+
return buildBoundContract(definition.family, definition.target, definition);
|
|
961
|
+
}
|
|
962
|
+
//#endregion
|
|
963
|
+
export { field as a, member as c, valueObject as d, enumType$1 as i, model as l, buildBoundContract as n, index as o, defineContract as r, isEnumTypeHandle as s, bindEnumType as t, rel as u };
|
|
964
|
+
|
|
965
|
+
//# sourceMappingURL=contract-builder-BHzQQk70.mjs.map
|