@@ -118,8 +118,13 @@ export default class DataModelValidator implements AstValidator<DataModel> {
118118 }
119119
120120 if ( ! fields || ! references ) {
121- if ( accept ) {
122- accept ( 'error' , `Both "fields" and "references" must be provided` , { node : relAttr } ) ;
121+ if ( this . isSelfRelation ( field , name ) ) {
122+ // self relations are partial
123+ // https://www.prisma.io/docs/concepts/components/prisma-schema/relations/self-relations
124+ } else {
125+ if ( accept ) {
126+ accept ( 'error' , `Both "fields" and "references" must be provided` , { node : relAttr } ) ;
127+ }
123128 }
124129 } else {
125130 // validate "fields" and "references" typing consistency
@@ -157,6 +162,33 @@ export default class DataModelValidator implements AstValidator<DataModel> {
157162 return { attr : relAttr , name, fields, references, valid } ;
158163 }
159164
165+ private isSelfRelation ( field : DataModelField , relationName ?: string ) {
166+ if ( field . type . reference ?. ref === field . $container ) {
167+ // field directly references back to its type
168+ return true ;
169+ }
170+
171+ if ( relationName ) {
172+ // field's relation points to another type, and that type's opposite relation field
173+ // points back
174+ const oppositeModelFields = field . type . reference ?. ref ?. fields as DataModelField [ ] ;
175+ if ( oppositeModelFields ) {
176+ for ( const oppositeField of oppositeModelFields ) {
177+ const { name : oppositeRelationName } = this . parseRelation ( oppositeField ) ;
178+ if (
179+ oppositeRelationName === relationName &&
180+ oppositeField . type . reference ?. ref === field . $container
181+ ) {
182+ // found an opposite relation field that points back to this field's type
183+ return true ;
184+ }
185+ }
186+ }
187+ }
188+
189+ return false ;
190+ }
191+
160192 private validateRelationField ( field : DataModelField , accept : ValidationAcceptor ) {
161193 const thisRelation = this . parseRelation ( field , accept ) ;
162194 if ( ! thisRelation . valid ) {
@@ -180,15 +212,20 @@ export default class DataModelValidator implements AstValidator<DataModel> {
180212 ) ;
181213 return ;
182214 } else if ( oppositeFields . length > 1 ) {
183- oppositeFields . forEach ( ( f ) =>
184- accept (
185- 'error' ,
186- `Fields ${ oppositeFields . map ( ( f ) => '"' + f . name + '"' ) . join ( ', ' ) } on model "${
187- oppositeModel . name
188- } " refer to the same relation to model "${ field . $container . name } "`,
189- { node : f }
190- )
191- ) ;
215+ oppositeFields . forEach ( ( f ) => {
216+ if ( this . isSelfRelation ( f ) ) {
217+ // self relations are partial
218+ // https://www.prisma.io/docs/concepts/components/prisma-schema/relations/self-relations
219+ } else {
220+ accept (
221+ 'error' ,
222+ `Fields ${ oppositeFields . map ( ( f ) => '"' + f . name + '"' ) . join ( ', ' ) } on model "${
223+ oppositeModel . name
224+ } " refer to the same relation to model "${ field . $container . name } "`,
225+ { node : f }
226+ ) ;
227+ }
228+ } ) ;
192229 return ;
193230 }
194231
0 commit comments