/// Ensures that a value matches the expected return type.
Ensures that a value matches the expected return type.
Ensures that a value matches the expected return type .
fn complete_value<'a, R>(
    ctx: &ExecutionContext<'a, R>,
    field: &'a q::Field,
    field_type: &'a s::Type,
    fields: Vec<&'a q::Field>,
    resolved_value: q::Value,
) -> Result<q::Value, Vec<QueryExecutionError>>
where
    R: Resolver,
{
    match field_type {
        // Fail if the field type is non-null but the value is null
        s::Type::NonNullType(inner_type) => {
            return match complete_value(ctx, field, inner_type, fields, resolved_value)? {
                q::Value::Null => Err(vec![QueryExecutionError::NonNullError(
                    field.position,
                    field.name.to_string(),
                )]),
                v => Ok(v),
            };
        }
        // If the resolved value is null, return null
        _ if resolved_value == q::Value::Null => {
            return Ok(resolved_value);
        }
        // Complete list values
        s::Type::ListType(inner_type) => {
            match resolved_value {
                // Complete list values individually
                q::Value::List(values) => {
                    let mut errors = Vec::new();
                    let mut out = Vec::with_capacity(values.len());
                    for value in values.into_iter() {
                        match complete_value(ctx, field, inner_type, fields.clone(), value) {
                            Ok(value) => out.push(value),
                            Err(errs) => errors.extend(errs),
                        }
                    }
                    match errors.is_empty() {
                        true => Ok(q::Value::List(out)),
                        false => Err(errors),
                    }
                }
                // Return field error if the resolved value for the list is not a list
                _ => Err(vec![QueryExecutionError::ListValueError(
                    field.position,
                    field.name.to_string(),
                )]),
            }
        }
        s::Type::NamedType(name) => {
            let named_type = sast::get_named_type(&ctx.schema.document, name).unwrap();
            match named_type {
                // Complete scalar values
                s::TypeDefinition::Scalar(scalar_type) => {
                    resolved_value.coerce(scalar_type).ok_or_else(|| {
                        vec![QueryExecutionError::ScalarCoercionError(
                            field.position.clone(),
                            field.name.to_owned(),
                            resolved_value.clone(),
                            scalar_type.name.to_owned(),
                        )]
                    })
                }
                // Complete enum values
                s::TypeDefinition::Enum(enum_type) => {
                    resolved_value.coerce(enum_type).ok_or_else(|| {
                        vec![QueryExecutionError::EnumCoercionError(
                            field.position.clone(),
                            field.name.to_owned(),
                            resolved_value.clone(),
                            enum_type.name.to_owned(),
                            enum_type
                                .values
                                .iter()
                                .map(|value| value.name.to_owned())
                                .collect(),
                        )]
                    })
                }
                // Complete object types recursively
                s::TypeDefinition::Object(object_type) => execute_selection_set(
                    ctx,
                    &merge_selection_sets(fields),
                    object_type,
                    &Some(resolved_value),
                ),
                // Resolve interface types using the resolved value and complete the value recursively
                s::TypeDefinition::Interface(_) => {
                    let object_type = resolve_abstract_type(ctx, named_type, &resolved_value)?;
                    execute_selection_set(
                        ctx,
                        &merge_selection_sets(fields),
                        object_type,
                        &Some(resolved_value),
                    )
                }
                // Resolve union types using the resolved value and complete the value recursively
                s::TypeDefinition::Union(_) => {
                    let object_type = resolve_abstract_type(ctx, named_type, &resolved_value)?;
                    execute_selection_set(
                        ctx,
                        &merge_selection_sets(fields),
                        object_type,
                        &Some(resolved_value),
                    )
                }
                s::TypeDefinition::InputObject(_) => {
                    unreachable!("input objects are never resolved")
                }
            }
        }
    }
}
fn complete_value < ' a , R > ( ctx : & ExecutionContext < ' a , R > , field : & ' a q :: Field , field_type : & ' a s :: Type , fields : Vec < & ' a q :: Field > , resolved_value : q :: Value , ) -> Result < q :: Value , Vec < QueryExecutionError > > where R : Resolver , { match field_type { // Fail if the field type is non-null but the value is null s :: Type :: NonNullType ( inner_type ) => { return match complete_value ( ctx , field , inner_type , fields , resolved_value ) ? { q :: Value :: Null => Err ( vec ! [ QueryExecutionError NonNullError ( field position field name to_string ( ) ) ] ) , v => Ok ( v ) , } ; } // If the resolved value is null, return null _ if resolved_value == q :: Value :: Null => { return Ok ( resolved_value ) ; } // Complete list values s :: Type :: ListType ( inner_type ) => { match resolved_value { // Complete list values individually q :: Value :: List ( values ) => { let mut errors = Vec :: new ( ) ; let mut out = Vec :: with_capacity ( values . len ( ) ) ; for value in values . into_iter ( ) { match complete_value ( ctx , field , inner_type , fields . clone ( ) , value ) { Ok ( value ) => out . push ( value ) , Err ( errs ) => errors . extend ( errs ) , } } match errors . is_empty ( ) { true => Ok ( q :: Value :: List ( out ) ) , false => Err ( errors ) , } } // Return field error if the resolved value for the list is not a list _ => Err ( vec ! [ QueryExecutionError ListValueError ( field position field name to_string ( ) ) ] ) , } } s :: Type :: NamedType ( name ) => { let named_type = sast :: get_named_type ( & ctx . schema . document , name ) . unwrap ( ) ; match named_type { // Complete scalar values s :: TypeDefinition :: Scalar ( scalar_type ) => { resolved_value . coerce ( scalar_type ) . ok_or_else ( | | { vec ! [ QueryExecutionError ScalarCoercionError ( field position clone ( ) field name to_owned ( ) resolved_value clone ( ) scalar_type name to_owned ( ) ) ] } ) } // Complete enum values s :: TypeDefinition :: Enum ( enum_type ) => { resolved_value . coerce ( enum_type ) . ok_or_else ( | | { vec ! [ QueryExecutionError EnumCoercionError ( field position clone ( ) field name to_owned ( ) resolved_value clone ( ) enum_type name to_owned ( ) enum_type values iter ( ) map ( value value name to_owned ( ) ) collect ( ) ) ] } ) } // Complete object types recursively s :: TypeDefinition :: Object ( object_type ) => execute_selection_set ( ctx , & merge_selection_sets ( fields ) , object_type , & Some ( resolved_value ) , ) , // Resolve interface types using the resolved value and complete the value recursively s :: TypeDefinition :: Interface ( _ ) => { let object_type = resolve_abstract_type ( ctx , named_type , & resolved_value ) ? ; execute_selection_set ( ctx , & merge_selection_sets ( fields ) , object_type , & Some ( resolved_value ) , ) } // Resolve union types using the resolved value and complete the value recursively s :: TypeDefinition :: Union ( _ ) => { let object_type = resolve_abstract_type ( ctx , named_type , & resolved_value ) ? ; execute_selection_set ( ctx , & merge_selection_sets ( fields ) , object_type , & Some ( resolved_value ) , ) } s :: TypeDefinition :: InputObject ( _ ) => { unreachable ! ( " " ) } } } } }
Ensures that a value matches the expected return type.
Ensures that a value matches the expected return type .
ctx
&ExecutionContext<'a, R>
field
&'a q::Field
field_type
&'a s::Type
fields
Vec<&'a q::Field>
resolved_value
q::Value