Skip to content

Chara-X/juniper

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 

Repository files navigation

juniper

Core idea

GraphQL: Recursively call the resolve function to piece together the result of the tree structure.

Example

struct Database {
    products: Vec<Product>,
}
struct Query {
    categories: Vec<Category>,
}
impl juniper::GraphQLType for Query {
    fn name(_info: &Self::TypeInfo) -> Option<&str> {
        Some("Query")
    }
    fn meta<'r>(
        info: &Self::TypeInfo,
        registry: &mut juniper::Registry<'r, juniper::DefaultScalarValue>,
    ) -> juniper::meta::MetaType<'r, juniper::DefaultScalarValue>
    where
        juniper::DefaultScalarValue: 'r,
    {
        let fields = &[
            registry.field::<String>("hello", info),
            registry.field::<Vec<Product>>("products", info),
            registry
                .field::<Option<Product>>("product", info)
                .argument(registry.arg::<String>("name", info)),
            registry.field::<Vec<Category>>("categories", info),
            registry
                .field::<Option<Category>>("category", info)
                .argument(registry.arg::<String>("name", info)),
        ];
        registry
            .build_object_type::<Query>(info, fields)
            .into_meta()
    }
}
impl juniper::GraphQLValue for Query {
    type Context = Database;
    type TypeInfo = ();
    fn type_name<'i>(&self, info: &'i Self::TypeInfo) -> Option<&'i str> {
        <Self as juniper::GraphQLType>::name(info)
    }
    fn resolve_field(
        &self,
        info: &Self::TypeInfo,
        field_name: &str,
        arguments: &juniper::Arguments<juniper::DefaultScalarValue>,
        executor: &juniper::Executor<Self::Context, juniper::DefaultScalarValue>,
    ) -> juniper::ExecutionResult<juniper::DefaultScalarValue> {
        match field_name {
            "products" => executor.resolve_with_ctx(info, &executor.context().products),
            "product" => {
                let name = arguments.get::<String>("name")?.unwrap();
                let product = executor.context().products.iter().find(|p| p.name == name);
                executor.resolve_with_ctx(info, &product)
            }
            "categories" => executor.resolve(info, &self.categories),
            "category" => {
                let name = arguments.get::<String>("name")?.unwrap();
                let category = self.categories.iter().find(|c| c.name == name);
                executor.resolve(info, &category)
            }
            _ => panic!(),
        }
    }
}
struct Product {
    name: String,
    price: f64,
    category_name: String,
}
impl juniper::GraphQLType for Product {
    fn name(_info: &Self::TypeInfo) -> Option<&str> {
        Some("Product")
    }
    fn meta<'r>(
        info: &Self::TypeInfo,
        registry: &mut juniper::Registry<'r, juniper::DefaultScalarValue>,
    ) -> juniper::meta::MetaType<'r, juniper::DefaultScalarValue>
    where
        juniper::DefaultScalarValue: 'r,
    {
        let fields = &[
            registry.field::<String>("name", info),
            registry.field::<f64>("price", info),
            registry.field::<String>("category_name", info),
        ];
        registry
            .build_object_type::<Product>(info, fields)
            .into_meta()
    }
}
impl juniper::GraphQLValue for Product {
    type Context = ();
    type TypeInfo = ();
    fn type_name<'i>(&self, _info: &'i Self::TypeInfo) -> Option<&'i str> {
        Some("Product")
    }
    fn resolve_field(
        &self,
        info: &Self::TypeInfo,
        field_name: &str,
        _arguments: &juniper::Arguments<juniper::DefaultScalarValue>,
        executor: &juniper::Executor<Self::Context, juniper::DefaultScalarValue>,
    ) -> juniper::ExecutionResult<juniper::DefaultScalarValue> {
        match field_name {
            "name" => executor.resolve_with_ctx(info, &self.name),
            "price" => executor.resolve_with_ctx(info, &self.price),
            "category_name" => executor.resolve_with_ctx(info, &self.category_name),
            _ => panic!(),
        }
    }
}
struct Category {
    name: String,
}
impl juniper::GraphQLType for Category {
    fn name(_info: &Self::TypeInfo) -> Option<&str> {
        Some("Category")
    }
    fn meta<'r>(
        info: &Self::TypeInfo,
        registry: &mut juniper::Registry<'r, juniper::DefaultScalarValue>,
    ) -> juniper::meta::MetaType<'r, juniper::DefaultScalarValue>
    where
        juniper::DefaultScalarValue: 'r,
    {
        let fields = &[
            registry.field::<String>("name", info),
            registry.field::<Vec<Product>>("products", info),
        ];
        registry
            .build_object_type::<Category>(info, fields)
            .into_meta()
    }
}
impl juniper::GraphQLValue for Category {
    type Context = Database;
    type TypeInfo = ();
    fn type_name<'i>(&self, _info: &'i Self::TypeInfo) -> Option<&'i str> {
        Some("Category")
    }
    fn resolve_field(
        &self,
        info: &Self::TypeInfo,
        field_name: &str,
        _arguments: &juniper::Arguments<juniper::DefaultScalarValue>,
        executor: &juniper::Executor<Self::Context, juniper::DefaultScalarValue>,
    ) -> juniper::ExecutionResult<juniper::DefaultScalarValue> {
        match field_name {
            "name" => executor.resolve_with_ctx(info, &self.name),
            "products" => {
                let products = executor
                    .context()
                    .products
                    .iter()
                    .filter(|p| p.category_name == self.name)
                    .collect::<Vec<_>>();
                executor.resolve_with_ctx(info, &products)
            }
            _ => panic!(),
        }
    }
}

About

Graphql executor

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages