@@ -9,7 +9,7 @@ use graph::prelude::*;
9
9
use graph:: { components:: store:: EntityType , data:: graphql:: ObjectOrInterface } ;
10
10
11
11
use crate :: execution:: ast as a;
12
- use crate :: schema:: ast as sast;
12
+ use crate :: schema:: ast:: { self as sast, FilterOp } ;
13
13
14
14
use super :: prefetch:: SelectedAttributes ;
15
15
@@ -118,7 +118,7 @@ fn build_filter(
118
118
) -> Result < Option < EntityFilter > , QueryExecutionError > {
119
119
match field. argument_value ( "where" ) {
120
120
Some ( r:: Value :: Object ( object) ) => match build_filter_from_object ( entity, object, schema) {
121
- Ok ( filter) => Ok ( Some ( filter) ) ,
121
+ Ok ( filter) => Ok ( Some ( EntityFilter :: And ( filter) ) ) ,
122
122
Err ( e) => Err ( e) ,
123
123
} ,
124
124
Some ( r:: Value :: Null ) => Ok ( None ) ,
@@ -161,91 +161,164 @@ fn parse_change_block_filter(value: &r::Value) -> Result<BlockNumber, QueryExecu
161
161
}
162
162
}
163
163
164
+ /// Parses a GraphQL Filter Value into an EntityFilter.
165
+ fn build_entity_filter (
166
+ field_name : String ,
167
+ operation : FilterOp ,
168
+ store_value : Value ,
169
+ ) -> Result < EntityFilter , QueryExecutionError > {
170
+ return match operation {
171
+ FilterOp :: Not => Ok ( EntityFilter :: Not ( field_name, store_value) ) ,
172
+ FilterOp :: GreaterThan => Ok ( EntityFilter :: GreaterThan ( field_name, store_value) ) ,
173
+ FilterOp :: LessThan => Ok ( EntityFilter :: LessThan ( field_name, store_value) ) ,
174
+ FilterOp :: GreaterOrEqual => Ok ( EntityFilter :: GreaterOrEqual ( field_name, store_value) ) ,
175
+ FilterOp :: LessOrEqual => Ok ( EntityFilter :: LessOrEqual ( field_name, store_value) ) ,
176
+ FilterOp :: In => Ok ( EntityFilter :: In (
177
+ field_name,
178
+ list_values ( store_value, "_in" ) ?,
179
+ ) ) ,
180
+ FilterOp :: NotIn => Ok ( EntityFilter :: NotIn (
181
+ field_name,
182
+ list_values ( store_value, "_not_in" ) ?,
183
+ ) ) ,
184
+ FilterOp :: Contains => Ok ( EntityFilter :: Contains ( field_name, store_value) ) ,
185
+ FilterOp :: ContainsNoCase => Ok ( EntityFilter :: ContainsNoCase ( field_name, store_value) ) ,
186
+ FilterOp :: NotContains => Ok ( EntityFilter :: NotContains ( field_name, store_value) ) ,
187
+ FilterOp :: NotContainsNoCase => Ok ( EntityFilter :: NotContainsNoCase ( field_name, store_value) ) ,
188
+ FilterOp :: StartsWith => Ok ( EntityFilter :: StartsWith ( field_name, store_value) ) ,
189
+ FilterOp :: StartsWithNoCase => Ok ( EntityFilter :: StartsWithNoCase ( field_name, store_value) ) ,
190
+ FilterOp :: NotStartsWith => Ok ( EntityFilter :: NotStartsWith ( field_name, store_value) ) ,
191
+ FilterOp :: NotStartsWithNoCase => {
192
+ Ok ( EntityFilter :: NotStartsWithNoCase ( field_name, store_value) )
193
+ }
194
+ FilterOp :: EndsWith => Ok ( EntityFilter :: EndsWith ( field_name, store_value) ) ,
195
+ FilterOp :: EndsWithNoCase => Ok ( EntityFilter :: EndsWithNoCase ( field_name, store_value) ) ,
196
+ FilterOp :: NotEndsWith => Ok ( EntityFilter :: NotEndsWith ( field_name, store_value) ) ,
197
+ FilterOp :: NotEndsWithNoCase => Ok ( EntityFilter :: NotEndsWithNoCase ( field_name, store_value) ) ,
198
+ FilterOp :: Equal => Ok ( EntityFilter :: Equal ( field_name, store_value) ) ,
199
+ _ => unreachable ! ( ) ,
200
+ } ;
201
+ }
202
+
164
203
/// Parses a GraphQL input object into an EntityFilter, if present.
165
204
fn build_filter_from_object (
166
205
entity : ObjectOrInterface ,
167
206
object : & Object ,
168
207
schema : & ApiSchema ,
169
- ) -> Result < EntityFilter , QueryExecutionError > {
170
- Ok ( EntityFilter :: And ( {
171
- object
172
- . iter ( )
173
- . map ( |( key, value) | {
174
- // Special handling for _change_block input filter since its not a
175
- // standard entity filter that is based on entity structure/fields
176
- if key == "_change_block" {
177
- return match parse_change_block_filter ( value) {
178
- Ok ( block_number) => Ok ( EntityFilter :: ChangeBlockGte ( block_number) ) ,
179
- Err ( e) => Err ( e) ,
180
- } ;
181
- }
182
-
183
- use self :: sast:: FilterOp :: * ;
184
- let ( field_name, op) = sast:: parse_field_as_filter ( key) ;
185
-
186
- let field = sast:: get_field ( entity, & field_name) . ok_or_else ( || {
187
- QueryExecutionError :: EntityFieldError (
188
- entity. name ( ) . to_owned ( ) ,
189
- field_name. clone ( ) ,
190
- )
191
- } ) ?;
192
-
193
- let ty = & field. field_type ;
208
+ ) -> Result < Vec < EntityFilter > , QueryExecutionError > {
209
+ Ok ( object
210
+ . iter ( )
211
+ . map ( |( key, value) | {
212
+ // Special handling for _change_block input filter since its not a
213
+ // standard entity filter that is based on entity structure/fields
214
+ if key == "_change_block" {
215
+ return match parse_change_block_filter ( value) {
216
+ Ok ( block_number) => Ok ( EntityFilter :: ChangeBlockGte ( block_number) ) ,
217
+ Err ( e) => Err ( e) ,
218
+ } ;
219
+ }
220
+ use self :: sast:: FilterOp :: * ;
221
+ let ( field_name, op) = sast:: parse_field_as_filter ( key) ;
194
222
195
- Ok ( match op {
196
- Child => match value {
197
- DataValue :: Object ( obj) => {
198
- build_child_filter_from_object ( entity, field_name, obj, schema) ?
199
- }
200
- _ => {
201
- return Err ( QueryExecutionError :: AttributeTypeError (
202
- value. to_string ( ) ,
203
- ty. to_string ( ) ,
204
- ) )
205
- }
206
- } ,
223
+ Ok ( match op {
224
+ And => {
225
+ // AND input has a List of Objects
226
+ let filters = object
227
+ . iter ( )
228
+ . map ( |( _, value) | {
229
+ return match value {
230
+ // Iterate over the list and generate an EntityFilter from it
231
+ r:: Value :: List ( list) => Ok ( list
232
+ . iter ( )
233
+ . map ( |item| {
234
+ return match item {
235
+ r:: Value :: Object ( object) => Ok (
236
+ build_filter_from_object ( entity, object, schema) ?,
237
+ ) ,
238
+ _ => Err ( QueryExecutionError :: InvalidFilterError ) ,
239
+ } ;
240
+ } )
241
+ . collect :: < Result < Vec < Vec < EntityFilter > > , QueryExecutionError > > (
242
+ ) ?
243
+ // Flatten all different EntityFilters into one list
244
+ . into_iter ( )
245
+ . flatten ( )
246
+ . collect :: < Vec < EntityFilter > > ( ) ) ,
247
+ _ => Err ( QueryExecutionError :: InvalidFilterError ) ,
248
+ } ;
249
+ } )
250
+ . collect :: < Result < Vec < Vec < EntityFilter > > , QueryExecutionError > > ( ) ?
251
+ . into_iter ( )
252
+ // We iterate an object so all entity filters are flattened into one list
253
+ . flatten ( )
254
+ . collect :: < Vec < EntityFilter > > ( ) ;
255
+ return Ok ( EntityFilter :: And ( filters) ) ;
256
+ }
257
+ Or => {
258
+ // OR input has a List of Objects
259
+ let filters = object
260
+ . iter ( )
261
+ . map ( |( _, value) | {
262
+ return match value {
263
+ // Iterate over the list and generate an EntityFilter from it
264
+ r:: Value :: List ( list) => Ok ( list
265
+ . iter ( )
266
+ . map ( |item| {
267
+ return match item {
268
+ r:: Value :: Object ( object) => Ok (
269
+ build_filter_from_object ( entity, object, schema) ?,
270
+ ) ,
271
+ _ => Err ( QueryExecutionError :: InvalidFilterError ) ,
272
+ } ;
273
+ } )
274
+ . collect :: < Result < Vec < Vec < EntityFilter > > , QueryExecutionError > > (
275
+ ) ?
276
+ // Flatten all different EntityFilters into one list
277
+ . into_iter ( )
278
+ . flatten ( )
279
+ . collect :: < Vec < EntityFilter > > ( ) ) ,
280
+ _ => Err ( QueryExecutionError :: InvalidFilterError ) ,
281
+ } ;
282
+ } )
283
+ . collect :: < Result < Vec < Vec < EntityFilter > > , QueryExecutionError > > ( ) ?
284
+ . into_iter ( )
285
+ // We iterate an object so all entity filters are flattened into one list
286
+ . flatten ( )
287
+ . collect :: < Vec < EntityFilter > > ( ) ;
288
+ return Ok ( EntityFilter :: Or ( filters) ) ;
289
+ }
290
+ Child => match value {
291
+ DataValue :: Object ( obj) => {
292
+ build_child_filter_from_object ( entity, field_name, obj, schema) ?
293
+ }
207
294
_ => {
208
- let store_value = Value :: from_query_value ( value, ty) ?;
209
-
210
- match op {
211
- Not => EntityFilter :: Not ( field_name, store_value) ,
212
- GreaterThan => EntityFilter :: GreaterThan ( field_name, store_value) ,
213
- LessThan => EntityFilter :: LessThan ( field_name, store_value) ,
214
- GreaterOrEqual => EntityFilter :: GreaterOrEqual ( field_name, store_value) ,
215
- LessOrEqual => EntityFilter :: LessOrEqual ( field_name, store_value) ,
216
- In => EntityFilter :: In ( field_name, list_values ( store_value, "_in" ) ?) ,
217
- NotIn => EntityFilter :: NotIn (
218
- field_name,
219
- list_values ( store_value, "_not_in" ) ?,
220
- ) ,
221
- Contains => EntityFilter :: Contains ( field_name, store_value) ,
222
- ContainsNoCase => EntityFilter :: ContainsNoCase ( field_name, store_value) ,
223
- NotContains => EntityFilter :: NotContains ( field_name, store_value) ,
224
- NotContainsNoCase => {
225
- EntityFilter :: NotContainsNoCase ( field_name, store_value)
226
- }
227
- StartsWith => EntityFilter :: StartsWith ( field_name, store_value) ,
228
- StartsWithNoCase => {
229
- EntityFilter :: StartsWithNoCase ( field_name, store_value)
230
- }
231
- NotStartsWith => EntityFilter :: NotStartsWith ( field_name, store_value) ,
232
- NotStartsWithNoCase => {
233
- EntityFilter :: NotStartsWithNoCase ( field_name, store_value)
234
- }
235
- EndsWith => EntityFilter :: EndsWith ( field_name, store_value) ,
236
- EndsWithNoCase => EntityFilter :: EndsWithNoCase ( field_name, store_value) ,
237
- NotEndsWith => EntityFilter :: NotEndsWith ( field_name, store_value) ,
238
- NotEndsWithNoCase => {
239
- EntityFilter :: NotEndsWithNoCase ( field_name, store_value)
240
- }
241
- Equal => EntityFilter :: Equal ( field_name, store_value) ,
242
- _ => unreachable ! ( ) ,
243
- }
295
+ let field = sast:: get_field ( entity, & field_name) . ok_or_else ( || {
296
+ QueryExecutionError :: EntityFieldError (
297
+ entity. name ( ) . to_owned ( ) ,
298
+ field_name. clone ( ) ,
299
+ )
300
+ } ) ?;
301
+ let ty = & field. field_type ;
302
+ return Err ( QueryExecutionError :: AttributeTypeError (
303
+ value. to_string ( ) ,
304
+ ty. to_string ( ) ,
305
+ ) ) ;
244
306
}
245
- } )
307
+ } ,
308
+ _ => {
309
+ let field = sast:: get_field ( entity, & field_name) . ok_or_else ( || {
310
+ QueryExecutionError :: EntityFieldError (
311
+ entity. name ( ) . to_owned ( ) ,
312
+ field_name. clone ( ) ,
313
+ )
314
+ } ) ?;
315
+ let ty = & field. field_type ;
316
+ let store_value = Value :: from_query_value ( value, ty) ?;
317
+ return build_entity_filter ( field_name, op, store_value) ;
318
+ }
246
319
} )
247
- . collect :: < Result < Vec < EntityFilter > , QueryExecutionError > > ( ) ?
248
- } ) )
320
+ } )
321
+ . collect :: < Result < Vec < EntityFilter > , QueryExecutionError > > ( ) ? )
249
322
}
250
323
251
324
fn build_child_filter_from_object (
@@ -261,7 +334,11 @@ fn build_child_filter_from_object(
261
334
let child_entity = schema
262
335
. object_or_interface ( type_name)
263
336
. ok_or ( QueryExecutionError :: InvalidFilterError ) ?;
264
- let filter = Box :: new ( build_filter_from_object ( child_entity, object, schema) ?) ;
337
+ let filter = Box :: new ( EntityFilter :: And ( build_filter_from_object (
338
+ child_entity,
339
+ object,
340
+ schema,
341
+ ) ?) ) ;
265
342
let derived = field. is_derived ( ) ;
266
343
let attr = match derived {
267
344
true => sast:: get_derived_from_field ( child_entity, field)
0 commit comments