juniper_relay_connection 0.1.1

Relay style pagination for Juniper.
Documentation
use super::*;
use juniper::{
    marker::IsOutputType, meta::MetaType, Arguments, DefaultScalarValue, ExecutionResult, Executor,
    GraphQLType, GraphQLValue, GraphQLValueAsync, Registry, ScalarValue,
};

impl<N, S> GraphQLType<S> for RelayConnectionEdge<N>
where
    N: GraphQLType<S> + RelayConnectionNode,
    N::Context: juniper::Context,
    S: ScalarValue,
{
    fn name(_info: &<N as GraphQLValue<S>>::TypeInfo) -> Option<&str> {
        Some(N::edge_type_name())
    }

    fn meta<'r>(
        info: &<N as GraphQLValue<S>>::TypeInfo,
        registry: &mut Registry<'r, S>,
    ) -> MetaType<'r, S>
    where
        DefaultScalarValue: 'r,
    {
        let fields = &[
            registry.field::<&N>("node", info),
            registry.field::<&String>("cursor", &()),
        ];
        registry.build_object_type::<Self>(info, fields).into_meta()
    }
}

impl<N, S> GraphQLValue<S> for RelayConnectionEdge<N>
where
    N: GraphQLType<S> + RelayConnectionNode,
    N::Context: juniper::Context,
    S: ScalarValue,
{
    type Context = N::Context;
    type TypeInfo = <N as GraphQLValue<S>>::TypeInfo;

    fn type_name<'i>(&self, info: &'i Self::TypeInfo) -> Option<&'i str> {
        <Self as GraphQLType<S>>::name(info)
    }

    fn concrete_type_name(&self, _context: &Self::Context, info: &Self::TypeInfo) -> String {
        self.type_name(info).unwrap_or("ConnectionEdge").to_string()
    }

    fn resolve_field(
        &self,
        info: &Self::TypeInfo,
        field_name: &str,
        _args: &Arguments<S>,
        executor: &Executor<Self::Context, S>,
    ) -> ExecutionResult<S> {
        match field_name {
            "node" => executor.resolve_with_ctx(info, &self.node),
            "cursor" => executor.resolve_with_ctx(&(), &self.cursor),
            _ => panic!("Field {} not found on type RelayConnectionEdge", field_name),
        }
    }
}

impl<N, S> GraphQLValueAsync<S> for RelayConnectionEdge<N>
where
    N: GraphQLType<S> + GraphQLValueAsync<S> + RelayConnectionNode + Sync + Send,
    N::TypeInfo: Sync,
    N::Context: juniper::Context + Sync,
    S: ScalarValue + Send + Sync,
{
    fn resolve_field_async<'a>(
        &'a self,
        info: &'a Self::TypeInfo,
        field_name: &'a str,
        _args: &Arguments<S>,
        executor: &'a Executor<Self::Context, S>,
    ) -> juniper::BoxFuture<'a, ExecutionResult<S>> {
        let f = async move {
            match field_name {
                "node" => executor.resolve_with_ctx_async(info, &self.node).await,
                "cursor" => executor.resolve_with_ctx(&(), &self.cursor),
                _ => panic!("Field {} not found on type RelayConnectionEdge", field_name),
            }
        };
        use ::juniper::futures::future;
        future::FutureExt::boxed(f)
    }
}

impl<N, S> IsOutputType<S> for RelayConnectionEdge<N>
where
    N: GraphQLType<S>,
    S: ScalarValue,
{
}

impl<N, S> GraphQLType<S> for RelayConnection<N>
where
    N: GraphQLType<S> + RelayConnectionNode,
    N::Context: juniper::Context,
    S: ScalarValue,
{
    fn name(_info: &<N as GraphQLValue<S>>::TypeInfo) -> Option<&str> {
        Some(N::connection_type_name())
    }

    fn meta<'r>(
        info: &<N as GraphQLValue<S>>::TypeInfo,
        registry: &mut Registry<'r, S>,
    ) -> MetaType<'r, S>
    where
        S: 'r,
    {
        let fields = &[
            registry.field::<&Vec<RelayConnectionEdge<N>>>("edges", info),
            registry.field::<&Vec<&N>>("nodes", info),
            registry.field::<&RelayConnectionPageInfo>("pageInfo", &()),
        ];
        registry.build_object_type::<Self>(info, fields).into_meta()
    }
}

impl<N, S> GraphQLValue<S> for RelayConnection<N>
where
    N: GraphQLType<S> + RelayConnectionNode,
    N::Context: juniper::Context,
    S: ScalarValue,
{
    type Context = N::Context;
    type TypeInfo = <N as GraphQLValue<S>>::TypeInfo;

    fn type_name<'i>(&self, info: &'i Self::TypeInfo) -> Option<&'i str> {
        <Self as GraphQLType<S>>::name(info)
    }

    fn concrete_type_name(&self, _context: &Self::Context, info: &Self::TypeInfo) -> String {
        self.type_name(info).unwrap_or("Connection").to_string()
    }

    fn resolve_field(
        &self,
        info: &Self::TypeInfo,
        field_name: &str,
        _args: &Arguments<S>,
        executor: &Executor<Self::Context, S>,
    ) -> ExecutionResult<S> {
        match field_name {
            "edges" => executor.resolve_with_ctx(info, &self.edges),
            "nodes" => {
                let nodes: Vec<&N> = self.edges.iter().map(|edge| &edge.node).collect();
                executor.resolve_with_ctx(info, &nodes)
            }
            "pageInfo" => executor.resolve_with_ctx(&(), &self.page_info),
            _ => panic!("Field {} not found on type RelayConnectionEdge", field_name),
        }
    }
}

impl<N, S> GraphQLValueAsync<S> for RelayConnection<N>
where
    N: GraphQLType<S> + GraphQLValueAsync<S> + RelayConnectionNode + Sync + Send,
    N::TypeInfo: Sync,
    N::Context: juniper::Context + Sync,
    S: ScalarValue + Send + Sync,
{
    fn resolve_field_async<'a>(
        &'a self,
        info: &'a Self::TypeInfo,
        field_name: &'a str,
        _args: &Arguments<S>,
        executor: &'a Executor<Self::Context, S>,
    ) -> juniper::BoxFuture<'a, ExecutionResult<S>> {
        let f = async move {
            match field_name {
                "edges" => executor.resolve_with_ctx_async(info, &self.edges).await,
                "nodes" => {
                    let nodes: Vec<&N> = self.edges.iter().map(|edge| &edge.node).collect();
                    executor.resolve_with_ctx_async(info, &nodes).await
                }
                "pageInfo" => executor.resolve_with_ctx(&(), &self.page_info),
                _ => panic!("Field {} not found on type RelayConnectionEdge", field_name),
            }
        };
        use ::juniper::futures::future;
        future::FutureExt::boxed(f)
    }
}

impl<N, S> IsOutputType<S> for RelayConnection<N>
where
    N: GraphQLType<S>,
    S: ScalarValue,
{
}