#![allow(dead_code, unused_variables, unused_imports)] #[macro_use] extern crate juniper; #[macro_use] extern crate maplit; use assert_json_diff::assert_json_include; use juniper::{Executor, FieldResult, Variables, ID}; use juniper_from_schema::{graphql_schema, graphql_schema_from_file}; use serde_json::{self, json, Value}; use std::collections::HashMap; graphql_schema_from_file!("tests/schemas/complex_schema.graphql"); pub struct Query; impl QueryFields for Query { fn field_hero<'a>( &self, executor: &Executor<'a, Context>, trail: &QueryTrail<'a, Character, Walked>, episode: Option, ) -> FieldResult> { let hero = episode.and_then(|episode| { let luke = executor .context() .db .humans .get(&"1") .map(|h| Character::from(h.clone())); match episode { Episode::Newhope => luke, Episode::Empire => luke, Episode::Jedi => luke, } }); Ok(hero) } fn field_search<'a>( &self, executor: &Executor<'a, Context>, trail: &QueryTrail<'a, SearchResult, Walked>, text: Option, ) -> FieldResult>> { let results = text.map(|text| { executor .context() .db .humans .clone() .into_iter() .map(|(_, human)| human) .filter(|human| human.name.contains(&text)) .map(SearchResult::from) .collect::>() }); Ok(results) } } pub struct Mutation; impl MutationFields for Mutation { fn field_create_review<'a>( &self, executor: &Executor<'a, Context>, trail: &QueryTrail<'a, Review, Walked>, episode: Option, review: ReviewInput, ) -> FieldResult> { let review = Review { episode, stars: review.stars, commentary: review.commentary, favorite_color: review.favorite_color, }; // the fact that everything type checks is test enough, we don't need to actually insert // this review Ok(Some(review)) } } pub struct Review { episode: Option, stars: i32, commentary: Option, favorite_color: Option, } impl ReviewFields for Review { fn field_episode<'a>(&self, executor: &Executor<'a, Context>) -> FieldResult<&Option> { Ok(&self.episode) } fn field_stars<'a>(&self, executor: &Executor<'a, Context>) -> FieldResult<&i32> { Ok(&self.stars) } fn field_commentary<'a>( &self, executor: &Executor<'a, Context>, ) -> FieldResult<&Option> { Ok(&self.commentary) } fn field_favorite_color<'a>( &self, executor: &Executor<'a, Context>, _: &QueryTrail<'a, ColorInput, Walked>, ) -> FieldResult<&Option> { Ok(&self.favorite_color) } } #[derive(Clone)] pub struct Human { id: &'static str, name: String, } impl HumanFields for Human { fn field_id<'a>(&self, executor: &Executor<'a, Context>) -> FieldResult { Ok(ID::new(self.id)) } fn field_name<'a>(&self, executor: &Executor<'a, Context>) -> FieldResult<&String> { Ok(&self.name) } } #[derive(Clone)] pub struct Droid { id: &'static str, name: String, } impl DroidFields for Droid { fn field_id<'a>(&self, executor: &Executor<'a, Context>) -> FieldResult { Ok(ID::new(self.id)) } fn field_name<'a>(&self, executor: &Executor<'a, Context>) -> FieldResult<&String> { Ok(&self.name) } } pub struct Context { db: Db, } impl juniper::Context for Context {} pub struct Db { humans: HashMap<&'static str, Human>, } #[test] fn query_hero() { let value = run_query(r#"query { hero(episode: NEWHOPE) { id name } }"#); assert_json_include!( actual: value, expected: json!({ "hero": { "id": "1", "name": "Luke Skywalker", } }) ); let value = run_query(r#"query { hero(episode: EMPIRE) { id name } }"#); assert_json_include!( actual: value, expected: json!({ "hero": { "id": "1", "name": "Luke Skywalker", } }) ); let value = run_query(r#"query { hero(episode: JEDI) { id name } }"#); assert_json_include!( actual: value, expected: json!({ "hero": { "id": "1", "name": "Luke Skywalker", } }) ); } #[test] fn search() { let value = run_query( r#" query { search(text: "Luke") { ... on Human { id name } ... on Droid { id name } } } "#, ); assert_json_include!( actual: value, expected: json!({ "search": [ { "id": "1", "name": "Luke Skywalker" }, ] }) ); } fn run_query(query: &str) -> Value { let db = Db { humans: hashmap! { "1" => Human { id: "1", name: "Luke Skywalker".to_string() }, }, }; let ctx = Context { db }; let (res, _errors) = juniper::execute( query, None, &Schema::new(Query, Mutation), &Variables::new(), &ctx, ) .unwrap(); serde_json::from_str(&serde_json::to_string(&res).unwrap()).unwrap() }