Skip to content

Commit b0026b7

Browse files
committed
graphql: Coerce arguments when constructing the query
1 parent 66a6aaa commit b0026b7

File tree

11 files changed

+224
-298
lines changed

11 files changed

+224
-298
lines changed

graphql/src/execution/ast.rs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::{collections::HashSet, ops::Deref};
33
use graph::{
44
components::store::EntityType,
55
data::graphql::{DocumentExt, ObjectOrInterface},
6-
prelude::{q, r, s, QueryExecutionError, Schema},
6+
prelude::{anyhow, q, r, s, QueryExecutionError, Schema, ValueMap},
77
};
88
use graphql_parser::Pos;
99

@@ -231,6 +231,25 @@ impl Field {
231231
}
232232
}
233233

234+
impl ValueMap for Field {
235+
fn get_required<T: graph::prelude::TryFromValue>(&self, key: &str) -> Result<T, anyhow::Error> {
236+
self.argument_value(key)
237+
.ok_or_else(|| anyhow!("Required field `{}` not set", key))
238+
.and_then(|value| T::try_from_value(value).map_err(|e| e.into()))
239+
}
240+
241+
fn get_optional<T: graph::prelude::TryFromValue>(
242+
&self,
243+
key: &str,
244+
) -> Result<Option<T>, anyhow::Error> {
245+
self.argument_value(key)
246+
.map_or(Ok(None), |value| match value {
247+
r::Value::Null => Ok(None),
248+
_ => T::try_from_value(value).map(Some).map_err(Into::into),
249+
})
250+
}
251+
}
252+
234253
/// A set of object types, generated from resolving interfaces into the
235254
/// object types that implement them, and possibly narrowing further when
236255
/// expanding fragments with type conitions

graphql/src/execution/execution.rs

Lines changed: 20 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ use lazy_static::lazy_static;
99
use stable_hash::crypto::SetHasher;
1010
use stable_hash::prelude::*;
1111
use stable_hash::utils::stable_hash;
12-
use std::collections::HashMap;
1312
use std::time::Instant;
1413
use std::{borrow::ToOwned, collections::HashSet};
1514

@@ -25,7 +24,6 @@ use crate::introspection::{
2524
};
2625
use crate::prelude::*;
2726
use crate::schema::ast as sast;
28-
use crate::values::coercion;
2927

3028
lazy_static! {
3129
// Comma separated subgraph ids to cache queries for.
@@ -554,19 +552,15 @@ fn execute_field(
554552
field: &a::Field,
555553
field_definition: &s::Field,
556554
) -> Result<r::Value, Vec<QueryExecutionError>> {
557-
coerce_argument_values(&ctx.query.schema, object_type, field)
558-
.and_then(|argument_values| {
559-
resolve_field_value(
560-
ctx,
561-
object_type,
562-
field_value,
563-
field,
564-
field_definition,
565-
&field_definition.field_type,
566-
&argument_values,
567-
)
568-
})
569-
.and_then(|value| complete_value(ctx, field, &field_definition.field_type, value))
555+
resolve_field_value(
556+
ctx,
557+
object_type,
558+
field_value,
559+
field,
560+
field_definition,
561+
&field_definition.field_type,
562+
)
563+
.and_then(|value| complete_value(ctx, field, &field_definition.field_type, value))
570564
}
571565

572566
/// Resolves the value of a field.
@@ -577,7 +571,6 @@ fn resolve_field_value(
577571
field: &a::Field,
578572
field_definition: &s::Field,
579573
field_type: &s::Type,
580-
argument_values: &HashMap<&str, r::Value>,
581574
) -> Result<r::Value, Vec<QueryExecutionError>> {
582575
match field_type {
583576
s::Type::NonNullType(inner_type) => resolve_field_value(
@@ -587,7 +580,6 @@ fn resolve_field_value(
587580
field,
588581
field_definition,
589582
inner_type.as_ref(),
590-
argument_values,
591583
),
592584

593585
s::Type::NamedType(ref name) => resolve_field_value_for_named_type(
@@ -597,7 +589,6 @@ fn resolve_field_value(
597589
field,
598590
field_definition,
599591
name,
600-
argument_values,
601592
),
602593

603594
s::Type::ListType(inner_type) => resolve_field_value_for_list_type(
@@ -607,7 +598,6 @@ fn resolve_field_value(
607598
field,
608599
field_definition,
609600
inner_type.as_ref(),
610-
argument_values,
611601
),
612602
}
613603
}
@@ -620,7 +610,6 @@ fn resolve_field_value_for_named_type(
620610
field: &a::Field,
621611
field_definition: &s::Field,
622612
type_name: &str,
623-
argument_values: &HashMap<&str, r::Value>,
624613
) -> Result<r::Value, Vec<QueryExecutionError>> {
625614
// Try to resolve the type name into the actual type
626615
let named_type = ctx
@@ -631,13 +620,10 @@ fn resolve_field_value_for_named_type(
631620
.ok_or_else(|| QueryExecutionError::NamedTypeError(type_name.to_string()))?;
632621
match named_type {
633622
// Let the resolver decide how the field (with the given object type) is resolved
634-
s::TypeDefinition::Object(t) => ctx.resolver.resolve_object(
635-
field_value,
636-
field,
637-
field_definition,
638-
t.into(),
639-
argument_values,
640-
),
623+
s::TypeDefinition::Object(t) => {
624+
ctx.resolver
625+
.resolve_object(field_value, field, field_definition, t.into())
626+
}
641627

642628
// Let the resolver decide how values in the resolved object value
643629
// map to values of GraphQL enums
@@ -647,16 +633,13 @@ fn resolve_field_value_for_named_type(
647633
// map to values of GraphQL scalars
648634
s::TypeDefinition::Scalar(t) => {
649635
ctx.resolver
650-
.resolve_scalar_value(object_type, field, t, field_value, argument_values)
636+
.resolve_scalar_value(object_type, field, t, field_value)
651637
}
652638

653-
s::TypeDefinition::Interface(i) => ctx.resolver.resolve_object(
654-
field_value,
655-
field,
656-
field_definition,
657-
i.into(),
658-
argument_values,
659-
),
639+
s::TypeDefinition::Interface(i) => {
640+
ctx.resolver
641+
.resolve_object(field_value, field, field_definition, i.into())
642+
}
660643

661644
s::TypeDefinition::Union(_) => Err(QueryExecutionError::Unimplemented("unions".to_owned())),
662645

@@ -673,7 +656,6 @@ fn resolve_field_value_for_list_type(
673656
field: &a::Field,
674657
field_definition: &s::Field,
675658
inner_type: &s::Type,
676-
argument_values: &HashMap<&str, r::Value>,
677659
) -> Result<r::Value, Vec<QueryExecutionError>> {
678660
match inner_type {
679661
s::Type::NonNullType(inner_type) => resolve_field_value_for_list_type(
@@ -683,7 +665,6 @@ fn resolve_field_value_for_list_type(
683665
field,
684666
field_definition,
685667
inner_type,
686-
argument_values,
687668
),
688669

689670
s::Type::NamedType(ref type_name) => {
@@ -699,13 +680,7 @@ fn resolve_field_value_for_list_type(
699680
// is resolved into a entities based on the (potential) parent object
700681
s::TypeDefinition::Object(t) => ctx
701682
.resolver
702-
.resolve_objects(
703-
field_value,
704-
field,
705-
field_definition,
706-
t.into(),
707-
argument_values,
708-
)
683+
.resolve_objects(field_value, field, field_definition, t.into())
709684
.map_err(|e| vec![e]),
710685

711686
// Let the resolver decide how values in the resolved object value
@@ -722,13 +697,7 @@ fn resolve_field_value_for_list_type(
722697

723698
s::TypeDefinition::Interface(t) => ctx
724699
.resolver
725-
.resolve_objects(
726-
field_value,
727-
field,
728-
field_definition,
729-
t.into(),
730-
argument_values,
731-
)
700+
.resolve_objects(field_value, field, field_definition, t.into())
732701
.map_err(|e| vec![e]),
733702

734703
s::TypeDefinition::Union(_) => Err(vec![QueryExecutionError::Unimplemented(
@@ -892,42 +861,3 @@ fn resolve_abstract_type<'a>(
892861
)]
893862
})
894863
}
895-
896-
/// Coerces argument values into GraphQL values.
897-
pub fn coerce_argument_values<'a>(
898-
schema: &ApiSchema,
899-
ty: impl Into<ObjectOrInterface<'a>>,
900-
field: &a::Field,
901-
) -> Result<HashMap<&'a str, r::Value>, Vec<QueryExecutionError>> {
902-
let mut coerced_values = HashMap::new();
903-
let mut errors = vec![];
904-
905-
let resolver = |name: &str| schema.document().get_named_type(name);
906-
907-
for argument_def in sast::get_argument_definitions(ty, &field.name)
908-
.into_iter()
909-
.flatten()
910-
{
911-
let value = field.argument_value(&argument_def.name).cloned();
912-
match coercion::coerce_input_value(value, &argument_def, &resolver) {
913-
Ok(Some(value)) => {
914-
if argument_def.name == "text".to_string() {
915-
coerced_values.insert(
916-
argument_def.name.as_str(),
917-
r::Value::Object(Object::from_iter(vec![(field.name.clone(), value)])),
918-
);
919-
} else {
920-
coerced_values.insert(&argument_def.name, value);
921-
}
922-
}
923-
Ok(None) => {}
924-
Err(e) => errors.push(e),
925-
}
926-
}
927-
928-
if errors.is_empty() {
929-
Ok(coerced_values)
930-
} else {
931-
Err(errors)
932-
}
933-
}

0 commit comments

Comments
 (0)