pub fn add_set<T: ObjectType + Send + Sync>(
        &mut self,
        ctx: &ContextSelectionSet<'a>,
        root: &'a T,
    ) -> Result<()> {
        for selection in &ctx.item.node.items {
            if ctx.is_skip(&selection.node.directives())? {
                continue;
            }

            match &selection.node {
                Selection::Field(field) => {
                    if field.node.name.node == "__typename" {
                        // Get the typename
                        let ctx_field = ctx.with_field(field);
                        let field_name = ctx_field
                            .item
                            .node
                            .response_key()
                            .node
                            .clone()
                            .into_string();
                        let typename = root.introspection_type_name().into_owned();

                        self.0.push(Box::pin(async move {
                            Ok((field_name, serde_json::Value::String(typename)))
                        }));
                        continue;
                    }

                    if ctx.is_ifdef(&field.node.directives) {
                        if let Some(MetaType::Object { fields, .. }) =
                            ctx.schema_env.registry.types.get(T::type_name().as_ref())
                        {
                            if !fields.contains_key(field.node.name.node.as_str()) {
                                continue;
                            }
                        }
                    }

                    self.0.push(Box::pin({
                        // TODO: investigate removing this
                        let ctx = ctx.clone();
                        async move {
                            let ctx_field = ctx.with_field(field);
                            let field_name = ctx_field
                                .item
                                .node
                                .response_key()
                                .node
                                .clone()
                                .into_string();

                            let resolve_info = ResolveInfo {
                                resolve_id: ctx_field.resolve_id,
                                path_node: ctx_field.path_node.as_ref().unwrap(),
                                context: &ctx_field,
                                parent_type: &T::type_name(),
                                return_type: match ctx_field
                                    .schema_env
                                    .registry
                                    .types
                                    .get(T::type_name().as_ref())
                                    .and_then(|ty| ty.field_by_name(field.node.name.node.as_str()))
                                    .map(|field| &field.ty)
                                {
                                    Some(ty) => &ty,
                                    None => {
                                        return Err(Error::Query {
                                            pos: field.pos,
                                            path: None,
                                            err: QueryError::FieldNotFound {
                                                field_name: field
                                                    .node
                                                    .name
                                                    .node
                                                    .clone()
                                                    .into_string(),
                                                object: T::type_name().to_string(),
                                            },
                                        })
                                    }
                                },
                            };

                            ctx_field
                                .query_env
                                .extensions
                                .lock()
                                .resolve_start(&resolve_info);

                            let res = root
                                .resolve_field(&ctx_field)
                                .map_ok(move |value| (field_name, value))
                                .await
                                .log_error(&ctx_field.query_env.extensions)?;

                            ctx_field
                                .query_env
                                .extensions
                                .lock()
                                .resolve_end(&resolve_info);
                            Ok(res)
                        }
                    }));
                }
                selection => {
                    let (type_condition, selection_set) = match selection {
                        Selection::Field(_) => unreachable!(),
                        Selection::FragmentSpread(spread) => {
                            let fragment = ctx
                                .query_env
                                .document
                                .fragments
                                .get(&spread.node.fragment_name.node);
                            let fragment = match fragment {
                                Some(fragment) => fragment,
                                None => {
                                    return Err(Error::Query {
                                        pos: spread.pos,
                                        path: None,
                                        err: QueryError::UnknownFragment {
                                            name: spread.node.fragment_name.to_string(),
                                        },
                                    })
                                }
                            };
                            (
                                Some(&fragment.node.type_condition),
                                &fragment.node.selection_set,
                            )
                        }
                        Selection::InlineFragment(fragment) => (
                            fragment.node.type_condition.as_ref(),
                            &fragment.node.selection_set,
                        ),
                    };
                    let type_condition =
                        type_condition.map(|condition| condition.node.on.node.as_str());

                    let introspection_type_name = root.introspection_type_name();

                    let applies_concrete_object = type_condition.map_or(false, |condition| {
                        introspection_type_name == condition
                            || ctx
                                .schema_env
                                .registry
                                .implements
                                .get(&*introspection_type_name)
                                .map_or(false, |interfaces| interfaces.contains(condition))
                    });
                    if applies_concrete_object {
                        // The fragment applies to the concrete object type.

                        // TODO: This solution isn't ideal. If there are two interfaces InterfaceA
                        // and InterfaceB and one type MyObj that implements both, then if you have
                        // a type condition for `InterfaceA` on an `InterfaceB` and when resolving,
                        // the `InterfaceB` is actually a `MyObj` then the contents of the fragment
                        // will be treated as a `MyObj` rather than an `InterfaceB`. Example:
                        //
                        // myObjAsInterfaceB {
                        //     ... on InterfaceA {
                        //         # here you can query MyObj fields even when you should only be
                        //         # able to query InterfaceA fields.
                        //     }
                        // }
                        root.collect_all_fields(&ctx.with_selection_set(selection_set), self)?;
                    } else if type_condition.map_or(true, |condition| T::type_name() == condition) {
                        // The fragment applies to an interface type.
                        self.add_set(&ctx.with_selection_set(selection_set), root)?;
                    }
                }
            }
        }
        Ok(())
    }
/// Add another set of fields to this set of fields using the given object.
Add another set of fields to this set of fields using the given object.
Add another set of fields to this set of fields using the given object .
pub fn add_set<T: ObjectType + Send + Sync>(
        &mut self,
        ctx: &ContextSelectionSet<'a>,
        root: &'a T,
    ) -> Result<()> {
        for selection in &ctx.item.node.items {
            if ctx.is_skip(&selection.node.directives())? {
                continue;
            }
            match &selection.node {
                Selection::Field(field) => {
                    if field.node.name.node == "__typename" {
                        // Get the typename
                        let ctx_field = ctx.with_field(field);
                        let field_name = ctx_field
                            .item
                            .node
                            .response_key()
                            .node
                            .clone()
                            .into_string();
                        let typename = root.introspection_type_name().into_owned();
                        self.0.push(Box::pin(async move {
                            Ok((field_name, serde_json::Value::String(typename)))
                        }));
                        continue;
                    }
                    if ctx.is_ifdef(&field.node.directives) {
                        if let Some(MetaType::Object { fields, .. }) =
                            ctx.schema_env.registry.types.get(T::type_name().as_ref())
                        {
                            if !fields.contains_key(field.node.name.node.as_str()) {
                                continue;
                            }
                        }
                    }
                    self.0.push(Box::pin({
                        // TODO: investigate removing this
                        let ctx = ctx.clone();
                        async move {
                            let ctx_field = ctx.with_field(field);
                            let field_name = ctx_field
                                .item
                                .node
                                .response_key()
                                .node
                                .clone()
                                .into_string();
                            let resolve_info = ResolveInfo {
                                resolve_id: ctx_field.resolve_id,
                                path_node: ctx_field.path_node.as_ref().unwrap(),
                                context: &ctx_field,
                                parent_type: &T::type_name(),
                                return_type: match ctx_field
                                    .schema_env
                                    .registry
                                    .types
                                    .get(T::type_name().as_ref())
                                    .and_then(|ty| ty.field_by_name(field.node.name.node.as_str()))
                                    .map(|field| &field.ty)
                                {
                                    Some(ty) => &ty,
                                    None => {
                                        return Err(Error::Query {
                                            pos: field.pos,
                                            path: None,
                                            err: QueryError::FieldNotFound {
                                                field_name: field
                                                    .node
                                                    .name
                                                    .node
                                                    .clone()
                                                    .into_string(),
                                                object: T::type_name().to_string(),
                                            },
                                        })
                                    }
                                },
                            };
                            ctx_field
                                .query_env
                                .extensions
                                .lock()
                                .resolve_start(&resolve_info);
                            let res = root
                                .resolve_field(&ctx_field)
                                .map_ok(move |value| (field_name, value))
                                .await
                                .log_error(&ctx_field.query_env.extensions)?;
                            ctx_field
                                .query_env
                                .extensions
                                .lock()
                                .resolve_end(&resolve_info);
                            Ok(res)
                        }
                    }));
                }
                selection => {
                    let (type_condition, selection_set) = match selection {
                        Selection::Field(_) => unreachable!(),
                        Selection::FragmentSpread(spread) => {
                            let fragment = ctx
                                .query_env
                                .document
                                .fragments
                                .get(&spread.node.fragment_name.node);
                            let fragment = match fragment {
                                Some(fragment) => fragment,
                                None => {
                                    return Err(Error::Query {
                                        pos: spread.pos,
                                        path: None,
                                        err: QueryError::UnknownFragment {
                                            name: spread.node.fragment_name.to_string(),
                                        },
                                    })
                                }
                            };
                            (
                                Some(&fragment.node.type_condition),
                                &fragment.node.selection_set,
                            )
                        }
                        Selection::InlineFragment(fragment) => (
                            fragment.node.type_condition.as_ref(),
                            &fragment.node.selection_set,
                        ),
                    };
                    let type_condition =
                        type_condition.map(|condition| condition.node.on.node.as_str());
                    let introspection_type_name = root.introspection_type_name();
                    let applies_concrete_object = type_condition.map_or(false, |condition| {
                        introspection_type_name == condition
                            || ctx
                                .schema_env
                                .registry
                                .implements
                                .get(&*introspection_type_name)
                                .map_or(false, |interfaces| interfaces.contains(condition))
                    });
                    if applies_concrete_object {
                        // The fragment applies to the concrete object type.
                        // TODO: This solution isn't ideal. If there are two interfaces InterfaceA
                        // and InterfaceB and one type MyObj that implements both, then if you have
                        // a type condition for `InterfaceA` on an `InterfaceB` and when resolving,
                        // the `InterfaceB` is actually a `MyObj` then the contents of the fragment
                        // will be treated as a `MyObj` rather than an `InterfaceB`. Example:
                        //
                        // myObjAsInterfaceB {
                        //     ... on InterfaceA {
                        //         # here you can query MyObj fields even when you should only be
                        //         # able to query InterfaceA fields.
                        //     }
                        // }
                        root.collect_all_fields(&ctx.with_selection_set(selection_set), self)?;
                    } else if type_condition.map_or(true, |condition| T::type_name() == condition) {
                        // The fragment applies to an interface type.
                        self.add_set(&ctx.with_selection_set(selection_set), root)?;
                    }
                }
            }
        }
        Ok(())
    }
pub fn add_set < T : ObjectType + Send + Sync > ( & mut self , ctx : & ContextSelectionSet < ' a > , root : & ' a T , ) -> Result < ( ) > { for selection in & ctx . item . node . items { if ctx . is_skip ( & selection . node . directives ( ) ) ? { continue ; } match & selection . node { Selection :: Field ( field ) => { if field . node . name . node == " " { // Get the typename let ctx_field = ctx . with_field ( field ) ; let field_name = ctx_field . item . node . response_key ( ) . node . clone ( ) . into_string ( ) ; let typename = root . introspection_type_name ( ) . into_owned ( ) ; self . 0 . push ( Box :: pin ( async move { Ok ( ( field_name , serde_json :: Value :: String ( typename ) ) ) } ) ) ; continue ; } if ctx . is_ifdef ( & field . node . directives ) { if let Some ( MetaType :: Object { fields , .. } ) = ctx . schema_env . registry . types . get ( T :: type_name ( ) . as_ref ( ) ) { if ! fields . contains_key ( field . node . name . node . as_str ( ) ) { continue ; } } } self . 0 . push ( Box :: pin ( { // TODO: investigate removing this let ctx = ctx . clone ( ) ; async move { let ctx_field = ctx . with_field ( field ) ; let field_name = ctx_field . item . node . response_key ( ) . node . clone ( ) . into_string ( ) ; let resolve_info = ResolveInfo { resolve_id : ctx_field . resolve_id , path_node : ctx_field . path_node . as_ref ( ) . unwrap ( ) , context : & ctx_field , parent_type : & T :: type_name ( ) , return_type : match ctx_field . schema_env . registry . types . get ( T :: type_name ( ) . as_ref ( ) ) . and_then ( | ty | ty . field_by_name ( field . node . name . node . as_str ( ) ) ) . map ( | field | & field . ty ) { Some ( ty ) => & ty , None => { return Err ( Error :: Query { pos : field . pos , path : None , err : QueryError :: FieldNotFound { field_name : field . node . name . node . clone ( ) . into_string ( ) , object : T :: type_name ( ) . to_string ( ) , } , } ) } } , } ; ctx_field . query_env . extensions . lock ( ) . resolve_start ( & resolve_info ) ; let res = root . resolve_field ( & ctx_field ) . map_ok ( move | value | ( field_name , value ) ) . await . log_error ( & ctx_field . query_env . extensions ) ? ; ctx_field . query_env . extensions . lock ( ) . resolve_end ( & resolve_info ) ; Ok ( res ) } } ) ) ; } selection => { let ( type_condition , selection_set ) = match selection { Selection :: Field ( _ ) => unreachable ! ( ) , Selection :: FragmentSpread ( spread ) => { let fragment = ctx . query_env . document . fragments . get ( & spread . node . fragment_name . node ) ; let fragment = match fragment { Some ( fragment ) => fragment , None => { return Err ( Error :: Query { pos : spread . pos , path : None , err : QueryError :: UnknownFragment { name : spread . node . fragment_name . to_string ( ) , } , } ) } } ; ( Some ( & fragment . node . type_condition ) , & fragment . node . selection_set , ) } Selection :: InlineFragment ( fragment ) => ( fragment . node . type_condition . as_ref ( ) , & fragment . node . selection_set , ) , } ; let type_condition = type_condition . map ( | condition | condition . node . on . node . as_str ( ) ) ; let introspection_type_name = root . introspection_type_name ( ) ; let applies_concrete_object = type_condition . map_or ( false , | condition | { introspection_type_name == condition || ctx . schema_env . registry . implements . get ( & * introspection_type_name ) . map_or ( false , | interfaces | interfaces . contains ( condition ) ) } ) ; if applies_concrete_object { // The fragment applies to the concrete object type. // TODO: This solution isn't ideal. If there are two interfaces InterfaceA // and InterfaceB and one type MyObj that implements both, then if you have // a type condition for `InterfaceA` on an `InterfaceB` and when resolving, // the `InterfaceB` is actually a `MyObj` then the contents of the fragment // will be treated as a `MyObj` rather than an `InterfaceB`. Example: // // myObjAsInterfaceB { //     ... on InterfaceA { //         # here you can query MyObj fields even when you should only be //         # able to query InterfaceA fields. //     } // } root . collect_all_fields ( & ctx . with_selection_set ( selection_set ) , self ) ? ; } else if type_condition . map_or ( true , | condition | T :: type_name ( ) == condition ) { // The fragment applies to an interface type. self . add_set ( & ctx . with_selection_set ( selection_set ) , root ) ? ; } } } } Ok ( ( ) ) }
Add another set of fields to this set of fields using the given object.
Add another set of fields to this set of fields using the given object .
&mut self
ctx
&ContextSelectionSet<'a>
root
&'a T
&mut self
ctx
&ContextSelectionSet<'a>
root
&'a T