@@ -5,10 +5,12 @@ import { ACTIONS_WITH_WRITE_PAYLOAD } from '../../constants';
5
5
import {
6
6
FieldInfo ,
7
7
NestedWriteVisitor ,
8
+ NestedWriteVisitorContext ,
8
9
PrismaWriteActionType ,
9
10
clone ,
10
11
enumerate ,
11
12
getFields ,
13
+ getModelInfo ,
12
14
getTypeDefInfo ,
13
15
requireField ,
14
16
} from '../../cross' ;
@@ -61,7 +63,7 @@ class DefaultAuthHandler extends DefaultPrismaProxyHandler {
61
63
private async preprocessWritePayload ( model : string , action : PrismaWriteActionType , args : any ) {
62
64
const newArgs = clone ( args ) ;
63
65
64
- const processCreatePayload = ( model : string , data : any ) => {
66
+ const processCreatePayload = ( model : string , data : any , context : NestedWriteVisitorContext ) => {
65
67
const fields = getFields ( this . options . modelMeta , model ) ;
66
68
for ( const fieldInfo of Object . values ( fields ) ) {
67
69
if ( fieldInfo . isTypeDef ) {
@@ -82,24 +84,24 @@ class DefaultAuthHandler extends DefaultPrismaProxyHandler {
82
84
const defaultValue = this . getDefaultValue ( fieldInfo ) ;
83
85
if ( defaultValue !== undefined ) {
84
86
// set field value extracted from `auth()`
85
- this . setDefaultValueForModelData ( fieldInfo , model , data , defaultValue ) ;
87
+ this . setDefaultValueForModelData ( fieldInfo , model , data , defaultValue , context ) ;
86
88
}
87
89
}
88
90
} ;
89
91
90
92
// visit create payload and set default value to fields using `auth()` in `@default()`
91
93
const visitor = new NestedWriteVisitor ( this . options . modelMeta , {
92
- create : ( model , data ) => {
93
- processCreatePayload ( model , data ) ;
94
+ create : ( model , data , context ) => {
95
+ processCreatePayload ( model , data , context ) ;
94
96
} ,
95
97
96
- upsert : ( model , data ) => {
97
- processCreatePayload ( model , data . create ) ;
98
+ upsert : ( model , data , context ) => {
99
+ processCreatePayload ( model , data . create , context ) ;
98
100
} ,
99
101
100
- createMany : ( model , args ) => {
102
+ createMany : ( model , args , context ) => {
101
103
for ( const item of enumerate ( args . data ) ) {
102
- processCreatePayload ( model , item ) ;
104
+ processCreatePayload ( model , item , context ) ;
103
105
}
104
106
} ,
105
107
} ) ;
@@ -108,42 +110,82 @@ class DefaultAuthHandler extends DefaultPrismaProxyHandler {
108
110
return newArgs ;
109
111
}
110
112
111
- private setDefaultValueForModelData ( fieldInfo : FieldInfo , model : string , data : any , authDefaultValue : unknown ) {
112
- if ( fieldInfo . isForeignKey && fieldInfo . relationField && fieldInfo . relationField in data ) {
113
+ private setDefaultValueForModelData (
114
+ fieldInfo : FieldInfo ,
115
+ model : string ,
116
+ data : any ,
117
+ authDefaultValue : unknown ,
118
+ context : NestedWriteVisitorContext
119
+ ) {
120
+ if ( fieldInfo . isForeignKey ) {
121
+ // if the field being inspected is a fk field, there are several cases we should not
122
+ // set the default value or should not set directly
123
+
113
124
// if the field is a fk, and the relation field is already set, we should not override it
114
- return ;
115
- }
125
+ if ( fieldInfo . relationField && fieldInfo . relationField in data ) {
126
+ return ;
127
+ }
116
128
117
- if ( fieldInfo . isForeignKey && ! isUnsafeMutate ( model , data , this . options . modelMeta ) ) {
118
- // if the field is a fk, and the create payload is not unsafe, we need to translate
119
- // the fk field setting to a `connect` of the corresponding relation field
120
- const relFieldName = fieldInfo . relationField ;
121
- if ( ! relFieldName ) {
122
- throw new Error (
123
- `Field \`${ fieldInfo . name } \` is a foreign key field but no corresponding relation field is found`
129
+ if ( context . field ?. backLink && context . nestingPath . length > 1 ) {
130
+ // if the fk field is in a creation context where its implied by the parent,
131
+ // we should not set the default value, e.g.:
132
+ //
133
+ // ```
134
+ // parent.create({ data: { child: { create: {} } } })
135
+ // ```
136
+ //
137
+ // event if child's fk to parent has a default value, we should not set default
138
+ // value here
139
+
140
+ // fetch parent model from the parent context
141
+ const parentModel = getModelInfo (
142
+ this . options . modelMeta ,
143
+ context . nestingPath [ context . nestingPath . length - 2 ] . model
124
144
) ;
125
- }
126
- const relationField = requireField ( this . options . modelMeta , model , relFieldName ) ;
127
145
128
- // construct a `{ connect: { ... } }` payload
129
- let connect = data [ relationField . name ] ?. connect ;
130
- if ( ! connect ) {
131
- connect = { } ;
132
- data [ relationField . name ] = { connect } ;
146
+ if ( parentModel ) {
147
+ // get the opposite side of the relation for the current create context
148
+ const oppositeRelationField = requireField ( this . options . modelMeta , model , context . field . backLink ) ;
149
+ if ( parentModel . name === oppositeRelationField . type ) {
150
+ // if the opposite side matches the parent model, it means we currently in a creation context
151
+ // that implicitly sets this fk field
152
+ return ;
153
+ }
154
+ }
133
155
}
134
156
135
- // sets the opposite fk field to value `authDefaultValue`
136
- const oppositeFkFieldName = this . getOppositeFkFieldName ( relationField , fieldInfo ) ;
137
- if ( ! oppositeFkFieldName ) {
138
- throw new Error (
139
- `Cannot find opposite foreign key field for \`${ fieldInfo . name } \` in relation field \`${ relFieldName } \``
140
- ) ;
157
+ if ( ! isUnsafeMutate ( model , data , this . options . modelMeta ) ) {
158
+ // if the field is a fk, and the create payload is not unsafe, we need to translate
159
+ // the fk field setting to a `connect` of the corresponding relation field
160
+ const relFieldName = fieldInfo . relationField ;
161
+ if ( ! relFieldName ) {
162
+ throw new Error (
163
+ `Field \`${ fieldInfo . name } \` is a foreign key field but no corresponding relation field is found`
164
+ ) ;
165
+ }
166
+ const relationField = requireField ( this . options . modelMeta , model , relFieldName ) ;
167
+
168
+ // construct a `{ connect: { ... } }` payload
169
+ let connect = data [ relationField . name ] ?. connect ;
170
+ if ( ! connect ) {
171
+ connect = { } ;
172
+ data [ relationField . name ] = { connect } ;
173
+ }
174
+
175
+ // sets the opposite fk field to value `authDefaultValue`
176
+ const oppositeFkFieldName = this . getOppositeFkFieldName ( relationField , fieldInfo ) ;
177
+ if ( ! oppositeFkFieldName ) {
178
+ throw new Error (
179
+ `Cannot find opposite foreign key field for \`${ fieldInfo . name } \` in relation field \`${ relFieldName } \``
180
+ ) ;
181
+ }
182
+ connect [ oppositeFkFieldName ] = authDefaultValue ;
183
+ return ;
141
184
}
142
- connect [ oppositeFkFieldName ] = authDefaultValue ;
143
- } else {
144
- // set default value directly
145
- data [ fieldInfo . name ] = authDefaultValue ;
146
185
}
186
+
187
+ // set default value directly
188
+ data [ fieldInfo . name ] = authDefaultValue ;
147
189
}
148
190
149
191
private getOppositeFkFieldName ( relationField : FieldInfo , fieldInfo : FieldInfo ) {
0 commit comments