@@ -5,10 +5,12 @@ import { ACTIONS_WITH_WRITE_PAYLOAD } from '../../constants';
55import {
66 FieldInfo ,
77 NestedWriteVisitor ,
8+ NestedWriteVisitorContext ,
89 PrismaWriteActionType ,
910 clone ,
1011 enumerate ,
1112 getFields ,
13+ getModelInfo ,
1214 getTypeDefInfo ,
1315 requireField ,
1416} from '../../cross' ;
@@ -61,7 +63,7 @@ class DefaultAuthHandler extends DefaultPrismaProxyHandler {
6163 private async preprocessWritePayload ( model : string , action : PrismaWriteActionType , args : any ) {
6264 const newArgs = clone ( args ) ;
6365
64- const processCreatePayload = ( model : string , data : any ) => {
66+ const processCreatePayload = ( model : string , data : any , context : NestedWriteVisitorContext ) => {
6567 const fields = getFields ( this . options . modelMeta , model ) ;
6668 for ( const fieldInfo of Object . values ( fields ) ) {
6769 if ( fieldInfo . isTypeDef ) {
@@ -82,24 +84,24 @@ class DefaultAuthHandler extends DefaultPrismaProxyHandler {
8284 const defaultValue = this . getDefaultValue ( fieldInfo ) ;
8385 if ( defaultValue !== undefined ) {
8486 // set field value extracted from `auth()`
85- this . setDefaultValueForModelData ( fieldInfo , model , data , defaultValue ) ;
87+ this . setDefaultValueForModelData ( fieldInfo , model , data , defaultValue , context ) ;
8688 }
8789 }
8890 } ;
8991
9092 // visit create payload and set default value to fields using `auth()` in `@default()`
9193 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 ) ;
9496 } ,
9597
96- upsert : ( model , data ) => {
97- processCreatePayload ( model , data . create ) ;
98+ upsert : ( model , data , context ) => {
99+ processCreatePayload ( model , data . create , context ) ;
98100 } ,
99101
100- createMany : ( model , args ) => {
102+ createMany : ( model , args , context ) => {
101103 for ( const item of enumerate ( args . data ) ) {
102- processCreatePayload ( model , item ) ;
104+ processCreatePayload ( model , item , context ) ;
103105 }
104106 } ,
105107 } ) ;
@@ -108,42 +110,82 @@ class DefaultAuthHandler extends DefaultPrismaProxyHandler {
108110 return newArgs ;
109111 }
110112
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+
113124 // 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+ }
116128
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
124144 ) ;
125- }
126- const relationField = requireField ( this . options . modelMeta , model , relFieldName ) ;
127145
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+ }
133155 }
134156
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 ;
141184 }
142- connect [ oppositeFkFieldName ] = authDefaultValue ;
143- } else {
144- // set default value directly
145- data [ fieldInfo . name ] = authDefaultValue ;
146185 }
186+
187+ // set default value directly
188+ data [ fieldInfo . name ] = authDefaultValue ;
147189 }
148190
149191 private getOppositeFkFieldName ( relationField : FieldInfo , fieldInfo : FieldInfo ) {
0 commit comments