1+ use std:: ops:: Deref ;
12use std:: sync:: OnceLock ;
23use apollo_compiler:: ast:: { FieldDefinition , Name } ;
3- use apollo_compiler:: schema:: { Component , ExtendedType , InterfaceType , ObjectType } ;
4+ use apollo_compiler:: schema:: { Component , ExtendedType , InterfaceType , ObjectType , UnionType } ;
45use indexmap:: IndexMap ;
6+ use apollo_compiler:: Schema ;
57use crate :: next:: Unstructured ;
68
79pub ( crate ) mod extended_type;
@@ -71,8 +73,12 @@ macro_rules! field_access {
7173field_access ! ( ObjectType ) ;
7274field_access ! ( InterfaceType ) ;
7375
74- pub ( crate ) trait TypeHasFields {
76+ pub ( crate ) trait Selectable {
77+
78+ fn name ( & self ) -> & Name ;
7579 fn fields ( & self ) -> & IndexMap < Name , Component < FieldDefinition > > ;
80+
81+ fn random_specialization < ' a > ( & self , u : & mut Unstructured , schema : & ' a Schema ) -> arbitrary:: Result < Option < & ' a ExtendedType > > ;
7682 fn random_field ( & self , u : & mut Unstructured ) -> arbitrary:: Result < & Component < FieldDefinition > > {
7783 // Types always have at least one field
7884 let fields = self . fields ( ) . values ( ) . collect :: < Vec < _ > > ( ) ;
@@ -81,25 +87,106 @@ pub(crate) trait TypeHasFields {
8187
8288}
8389
84- impl TypeHasFields for ObjectType {
90+ impl Selectable for ObjectType {
91+ fn name ( & self ) -> & Name {
92+ & self . name
93+ }
94+
95+
96+
8597 fn fields ( & self ) -> & IndexMap < Name , Component < FieldDefinition > > {
8698 & self . fields
8799 }
100+
101+ fn random_specialization < ' a > ( & self , _u : & mut Unstructured , _schema : & ' a Schema ) -> arbitrary:: Result < Option < & ' a ExtendedType > > {
102+ Ok ( None )
103+ }
88104}
89105
90- impl TypeHasFields for InterfaceType {
106+ impl Selectable for & UnionType {
107+ fn name ( & self ) -> & Name {
108+ & self . name
109+ }
110+
111+ fn fields ( & self ) -> & IndexMap < Name , Component < FieldDefinition > > {
112+ static EMPTY : OnceLock < IndexMap < Name , Component < FieldDefinition > > > = OnceLock :: new ( ) ;
113+ & EMPTY . get_or_init ( ||Default :: default ( ) )
114+ }
115+
116+ fn random_specialization < ' a > ( & self , u : & mut Unstructured , schema : & ' a Schema ) -> arbitrary:: Result < Option < & ' a ExtendedType > > {
117+ let members = self . members . iter ( ) . map ( |name| schema. types . get ( & name. name ) ) . collect :: < Vec < _ > > ( ) ;
118+ if members. is_empty ( ) {
119+ Ok ( None )
120+ }
121+ else {
122+ Ok ( members[ u. choose_index ( members. len ( ) ) ?] )
123+ }
124+ }
125+ }
126+
127+ impl Selectable for InterfaceType {
128+ fn name ( & self ) -> & Name {
129+ & self . name
130+ }
131+
91132 fn fields ( & self ) -> & IndexMap < Name , Component < FieldDefinition > > {
92133 & self . fields
93134 }
135+
136+ fn random_specialization < ' a > ( & self , u : & mut Unstructured , schema : & ' a Schema ) -> arbitrary:: Result < Option < & ' a ExtendedType > > {
137+ // An interface specialization is either an object or another interface that implements this interface
138+ let implements = schema
139+ . types
140+ . values ( )
141+ . filter ( |ty| {
142+ match ty {
143+ ExtendedType :: Object ( o) => o. implements_interfaces . contains ( & self . name ) ,
144+ ExtendedType :: Interface ( i) => i. implements_interfaces . contains ( & self . name ) ,
145+ _=> return false ,
146+ }
147+ } )
148+ . collect :: < Vec < _ > > ( ) ;
149+ if implements. is_empty ( ) {
150+ Ok ( None )
151+ }
152+ else {
153+ Ok ( Some ( implements[ u. choose_index ( implements. len ( ) ) ?] ) )
154+ }
155+
156+
157+ }
94158}
95159
96- impl TypeHasFields for ExtendedType {
160+
161+ impl Selectable for ExtendedType {
162+ fn name ( & self ) -> & Name {
163+ match self {
164+ ExtendedType :: Scalar ( scalar) => { & scalar. name }
165+ ExtendedType :: Object ( object_type) => { & object_type. name }
166+ ExtendedType :: Interface ( interface_type) => { & interface_type. name }
167+ ExtendedType :: Union ( union_type) => { & union_type. name }
168+ ExtendedType :: Enum ( enum_type) => { & enum_type. name }
169+ ExtendedType :: InputObject ( input_object) => { & input_object. name }
170+ }
171+ }
172+
173+
174+
97175 fn fields ( & self ) -> & IndexMap < Name , Component < FieldDefinition > > {
98176 static EMPTY : OnceLock < IndexMap < Name , Component < FieldDefinition > > > = OnceLock :: new ( ) ;
99177 match self {
100- ExtendedType :: Object ( t) => t. fields ( ) ,
101- ExtendedType :: Interface ( t) => t. fields ( ) ,
178+ ExtendedType :: Object ( t) => & t. fields ,
179+ ExtendedType :: Interface ( t) => & t. fields ,
102180 _ => & EMPTY . get_or_init ( ||Default :: default ( ) ) ,
103181 }
104182 }
183+
184+ fn random_specialization < ' a > ( & self , u : & mut Unstructured , schema : & ' a Schema ) -> arbitrary:: Result < Option < & ' a ExtendedType > > {
185+ match self {
186+ ExtendedType :: Object ( object_type) => { object_type. deref ( ) . random_specialization ( u, schema) }
187+ ExtendedType :: Interface ( interface_type) => { interface_type. deref ( ) . random_specialization ( u, schema) }
188+ ExtendedType :: Union ( union_type) => { union_type. deref ( ) . random_specialization ( u, schema) }
189+ _ => Ok ( None )
190+ }
191+ }
105192}
0 commit comments