1
1
/* eslint-disable @typescript-eslint/no-explicit-any */
2
2
import deepcopy from 'deepcopy' ;
3
- import deepmerge from 'deepmerge' ;
3
+ import deepmerge , { type ArrayMergeOptions } from 'deepmerge' ;
4
4
import { lowerCaseFirst } from 'lower-case-first' ;
5
5
import { DELEGATE_AUX_RELATION_PREFIX } from '../constants' ;
6
6
import {
@@ -11,7 +11,6 @@ import {
11
11
getIdFields ,
12
12
getModelInfo ,
13
13
isDelegateModel ,
14
- requireField ,
15
14
resolveField ,
16
15
} from '../cross' ;
17
16
import type { CrudContract , DbClientContract } from '../types' ;
@@ -204,7 +203,11 @@ export class DelegateProxyHandler extends DefaultPrismaProxyHandler {
204
203
}
205
204
206
205
if ( ! args . select ) {
206
+ // include base models upwards
207
207
this . injectBaseIncludeRecursively ( model , args ) ;
208
+
209
+ // include sub models downwards
210
+ this . injectConcreteIncludeRecursively ( model , args ) ;
208
211
}
209
212
}
210
213
@@ -302,6 +305,30 @@ export class DelegateProxyHandler extends DefaultPrismaProxyHandler {
302
305
this . injectBaseIncludeRecursively ( base . name , selectInclude . include [ baseRelationName ] ) ;
303
306
}
304
307
308
+ private injectConcreteIncludeRecursively ( model : string , selectInclude : any ) {
309
+ const modelInfo = getModelInfo ( this . options . modelMeta , model ) ;
310
+ if ( ! modelInfo ) {
311
+ return ;
312
+ }
313
+
314
+ // get sub models of this model
315
+ const subModels = Object . values ( this . options . modelMeta . models ) . filter ( ( m ) =>
316
+ m . baseTypes ?. includes ( modelInfo . name )
317
+ ) ;
318
+
319
+ for ( const subModel of subModels ) {
320
+ // include sub model relation field
321
+ const subRelationName = this . makeAuxRelationName ( subModel ) ;
322
+ if ( selectInclude . select ) {
323
+ selectInclude . include = { [ subRelationName ] : { } , ...selectInclude . select } ;
324
+ delete selectInclude . select ;
325
+ } else {
326
+ selectInclude . include = { [ subRelationName ] : { } , ...selectInclude . include } ;
327
+ }
328
+ this . injectConcreteIncludeRecursively ( subModel . name , selectInclude . include [ subRelationName ] ) ;
329
+ }
330
+ }
331
+
305
332
// #endregion
306
333
307
334
// #region create
@@ -1038,6 +1065,31 @@ export class DelegateProxyHandler extends DefaultPrismaProxyHandler {
1038
1065
return entity ;
1039
1066
}
1040
1067
1068
+ const upMerged = this . assembleUp ( model , entity ) ;
1069
+ const downMerged = this . assembleDown ( model , entity ) ;
1070
+
1071
+ // https://www.npmjs.com/package/deepmerge#arraymerge-example-combine-arrays
1072
+ const combineMerge = ( target : any [ ] , source : any [ ] , options : ArrayMergeOptions ) => {
1073
+ const destination = target . slice ( ) ;
1074
+ source . forEach ( ( item , index ) => {
1075
+ if ( typeof destination [ index ] === 'undefined' ) {
1076
+ destination [ index ] = options . cloneUnlessOtherwiseSpecified ( item , options ) ;
1077
+ } else if ( options . isMergeableObject ( item ) ) {
1078
+ destination [ index ] = deepmerge ( target [ index ] , item , options ) ;
1079
+ } else if ( target . indexOf ( item ) === - 1 ) {
1080
+ destination . push ( item ) ;
1081
+ }
1082
+ } ) ;
1083
+ return destination ;
1084
+ } ;
1085
+
1086
+ const result = deepmerge ( upMerged , downMerged , {
1087
+ arrayMerge : combineMerge ,
1088
+ } ) ;
1089
+ return result ;
1090
+ }
1091
+
1092
+ private assembleUp ( model : string , entity : any ) {
1041
1093
const result : any = { } ;
1042
1094
const base = this . getBaseModel ( model ) ;
1043
1095
@@ -1046,7 +1098,7 @@ export class DelegateProxyHandler extends DefaultPrismaProxyHandler {
1046
1098
const baseRelationName = this . makeAuxRelationName ( base ) ;
1047
1099
const baseData = entity [ baseRelationName ] ;
1048
1100
if ( baseData && typeof baseData === 'object' ) {
1049
- const baseAssembled = this . assembleHierarchy ( base . name , baseData ) ;
1101
+ const baseAssembled = this . assembleUp ( base . name , baseData ) ;
1050
1102
Object . assign ( result , baseAssembled ) ;
1051
1103
}
1052
1104
}
@@ -1063,9 +1115,9 @@ export class DelegateProxyHandler extends DefaultPrismaProxyHandler {
1063
1115
const fieldValue = entity [ field . name ] ;
1064
1116
if ( field . isDataModel ) {
1065
1117
if ( Array . isArray ( fieldValue ) ) {
1066
- result [ field . name ] = fieldValue . map ( ( item ) => this . assembleHierarchy ( field . type , item ) ) ;
1118
+ result [ field . name ] = fieldValue . map ( ( item ) => this . assembleUp ( field . type , item ) ) ;
1067
1119
} else {
1068
- result [ field . name ] = this . assembleHierarchy ( field . type , fieldValue ) ;
1120
+ result [ field . name ] = this . assembleUp ( field . type , fieldValue ) ;
1069
1121
}
1070
1122
} else {
1071
1123
result [ field . name ] = fieldValue ;
@@ -1076,66 +1128,39 @@ export class DelegateProxyHandler extends DefaultPrismaProxyHandler {
1076
1128
return result ;
1077
1129
}
1078
1130
1079
- // #endregion
1080
-
1081
- // #region backup
1082
-
1083
- private transformWhereHierarchy ( where : any , contextModel : ModelInfo , forModel : ModelInfo ) {
1084
- if ( ! where || typeof where !== 'object' ) {
1085
- return where ;
1086
- }
1087
-
1088
- let curr : ModelInfo | undefined = contextModel ;
1089
- const inheritStack : ModelInfo [ ] = [ ] ;
1090
- while ( curr ) {
1091
- inheritStack . unshift ( curr ) ;
1092
- curr = this . getBaseModel ( curr . name ) ;
1093
- }
1094
-
1095
- let result : any = { } ;
1096
- for ( const [ key , value ] of Object . entries ( where ) ) {
1097
- const fieldInfo = requireField ( this . options . modelMeta , contextModel . name , key ) ;
1098
- const fieldHierarchy = this . transformFieldHierarchy ( fieldInfo , value , contextModel , forModel , inheritStack ) ;
1099
- result = deepmerge ( result , fieldHierarchy ) ;
1100
- }
1101
-
1102
- return result ;
1103
- }
1104
-
1105
- private transformFieldHierarchy (
1106
- fieldInfo : FieldInfo ,
1107
- value : unknown ,
1108
- contextModel : ModelInfo ,
1109
- forModel : ModelInfo ,
1110
- inheritStack : ModelInfo [ ]
1111
- ) : any {
1112
- const fieldModel = fieldInfo . inheritedFrom ? this . getModelInfo ( fieldInfo . inheritedFrom ) : contextModel ;
1113
- if ( fieldModel === forModel ) {
1114
- return { [ fieldInfo . name ] : value } ;
1115
- }
1116
-
1117
- const fieldModelPos = inheritStack . findIndex ( ( m ) => m === fieldModel ) ;
1118
- const forModelPos = inheritStack . findIndex ( ( m ) => m === forModel ) ;
1131
+ private assembleDown ( model : string , entity : any ) {
1119
1132
const result : any = { } ;
1120
- let curr = result ;
1133
+ const modelInfo = getModelInfo ( this . options . modelMeta , model , true ) ;
1121
1134
1122
- if ( fieldModelPos > forModelPos ) {
1123
- // walk down hierarchy
1124
- for ( let i = forModelPos + 1 ; i <= fieldModelPos ; i ++ ) {
1125
- const rel = this . makeAuxRelationName ( inheritStack [ i ] ) ;
1126
- curr [ rel ] = { } ;
1127
- curr = curr [ rel ] ;
1135
+ if ( modelInfo . discriminator ) {
1136
+ // model is a delegate, merge sub model fields
1137
+ const subModelName = entity [ modelInfo . discriminator ] ;
1138
+ if ( subModelName ) {
1139
+ const subModel = getModelInfo ( this . options . modelMeta , subModelName , true ) ;
1140
+ const subRelationName = this . makeAuxRelationName ( subModel ) ;
1141
+ const subData = entity [ subRelationName ] ;
1142
+ if ( subData && typeof subData === 'object' ) {
1143
+ const subAssembled = this . assembleDown ( subModel . name , subData ) ;
1144
+ Object . assign ( result , subAssembled ) ;
1145
+ }
1128
1146
}
1129
- } else {
1130
- // walk up hierarchy
1131
- for ( let i = forModelPos - 1 ; i >= fieldModelPos ; i -- ) {
1132
- const rel = this . makeAuxRelationName ( inheritStack [ i ] ) ;
1133
- curr [ rel ] = { } ;
1134
- curr = curr [ rel ] ;
1147
+ }
1148
+
1149
+ for ( const field of Object . values ( modelInfo . fields ) ) {
1150
+ if ( field . name in entity ) {
1151
+ const fieldValue = entity [ field . name ] ;
1152
+ if ( field . isDataModel ) {
1153
+ if ( Array . isArray ( fieldValue ) ) {
1154
+ result [ field . name ] = fieldValue . map ( ( item ) => this . assembleDown ( field . type , item ) ) ;
1155
+ } else {
1156
+ result [ field . name ] = this . assembleDown ( field . type , fieldValue ) ;
1157
+ }
1158
+ } else {
1159
+ result [ field . name ] = fieldValue ;
1160
+ }
1135
1161
}
1136
1162
}
1137
1163
1138
- curr [ fieldInfo . name ] = value ;
1139
1164
return result ;
1140
1165
}
1141
1166
0 commit comments