pub mod graphiql;
use serde::de::Deserialize;
use serde::ser::{self, Serialize, SerializeMap};
use ast::InputValue;
use executor::ExecutionError;
use value::{DefaultScalarValue, ScalarRefValue, ScalarValue};
use {FieldError, GraphQLError, GraphQLType, RootNode, Value, Variables};
#[derive(Deserialize, Clone, Serialize, PartialEq, Debug)]
pub struct GraphQLRequest<S = DefaultScalarValue>
where
    S: ScalarValue,
{
    query: String,
    #[serde(rename = "operationName")]
    operation_name: Option<String>,
    #[serde(bound(deserialize = "InputValue<S>: Deserialize<'de> + Serialize"))]
    variables: Option<InputValue<S>>,
}
impl<S> GraphQLRequest<S>
where
    S: ScalarValue,
{
     
    fn operation_name(&self) -> Option<&str> {
        self.operation_name.as_ref().map(|oper_name| &**oper_name)
    }
    fn variables(&self) -> Variables<S> {
        self.variables
            .as_ref()
            .and_then(|iv| {
                iv.to_object_value().map(|o| {
                    o.into_iter()
                        .map(|(k, v)| (k.to_owned(), v.clone()))
                        .collect()
                })
            }).unwrap_or_default()
    }
    
    pub fn new(
        query: String,
        operation_name: Option<String>,
        variables: Option<InputValue<S>>,
    ) -> Self {
        GraphQLRequest {
            query: query,
            operation_name: operation_name,
            variables: variables,
        }
    }
    
    
    
    
    pub fn execute<'a, CtxT, QueryT, MutationT>(
        &'a self,
        root_node: &'a RootNode<QueryT, MutationT, S>,
        context: &CtxT,
    ) -> GraphQLResponse<'a, S>
    where
        S: ScalarValue,
        QueryT: GraphQLType<S, Context = CtxT>,
        MutationT: GraphQLType<S, Context = CtxT>,
        for<'b> &'b S: ScalarRefValue<'b>,
    {
        GraphQLResponse(::execute(
            &self.query,
            self.operation_name(),
            root_node,
            &self.variables(),
            context,
        ))
    }
}
pub struct GraphQLResponse<'a, S = DefaultScalarValue>(
    Result<(Value<S>, Vec<ExecutionError<S>>), GraphQLError<'a>>,
);
impl<'a, S> GraphQLResponse<'a, S>
where
    S: ScalarValue,
{
    
    pub fn error(error: FieldError<S>) -> Self {
        GraphQLResponse(Ok((Value::null(), vec![ExecutionError::at_origin(error)])))
    }
    
    
    
    
    pub fn is_ok(&self) -> bool {
        self.0.is_ok()
    }
}
impl<'a, T> Serialize for GraphQLResponse<'a, T>
where
    T: Serialize + ScalarValue,
    Value<T>: Serialize,
    ExecutionError<T>: Serialize,
    GraphQLError<'a>: Serialize,
{
    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
    where
        S: ser::Serializer,
    {
        match self.0 {
            Ok((ref res, ref err)) => {
                let mut map = serializer.serialize_map(None)?;
                map.serialize_key("data")?;
                map.serialize_value(res)?;
                if !err.is_empty() {
                    map.serialize_key("errors")?;
                    map.serialize_value(err)?;
                }
                map.end()
            }
            Err(ref err) => {
                let mut map = serializer.serialize_map(Some(1))?;
                map.serialize_key("errors")?;
                map.serialize_value(err)?;
                map.end()
            }
        }
    }
}
#[cfg(any(test, feature = "expose-test-schema"))]
#[allow(missing_docs)]
pub mod tests {
    use serde_json;
    use serde_json::Value as Json;
    
    
    #[derive(Debug)]
    pub struct TestResponse {
        pub status_code: i32,
        pub body: Option<String>,
        pub content_type: String,
    }
    
    
    pub trait HTTPIntegration {
        fn get(&self, url: &str) -> TestResponse;
        fn post(&self, url: &str, body: &str) -> TestResponse;
    }
    #[allow(missing_docs)]
    pub fn run_http_test_suite<T: HTTPIntegration>(integration: &T) {
        println!("Running HTTP Test suite for integration");
        println!("  - test_simple_get");
        test_simple_get(integration);
        println!("  - test_encoded_get");
        test_encoded_get(integration);
        println!("  - test_get_with_variables");
        test_get_with_variables(integration);
        println!("  - test_simple_post");
        test_simple_post(integration);
        println!("  - test_batched_post");
        test_batched_post(integration);
        println!("  - test_invalid_json");
        test_invalid_json(integration);
        println!("  - test_invalid_field");
        test_invalid_field(integration);
        println!("  - test_duplicate_keys");
        test_duplicate_keys(integration);
    }
    fn unwrap_json_response(response: &TestResponse) -> Json {
        serde_json::from_str::<Json>(
            response
                .body
                .as_ref()
                .expect("No data returned from request"),
        ).expect("Could not parse JSON object")
    }
    fn test_simple_get<T: HTTPIntegration>(integration: &T) {
        
        let response = integration.get("/?query=%7Bhero%7Bname%7D%7D");
        assert_eq!(response.status_code, 200);
        assert_eq!(response.content_type.as_str(), "application/json");
        assert_eq!(
            unwrap_json_response(&response),
            serde_json::from_str::<Json>(r#"{"data": {"hero": {"name": "R2-D2"}}}"#)
                .expect("Invalid JSON constant in test")
        );
    }
    fn test_encoded_get<T: HTTPIntegration>(integration: &T) {
        
        let response = integration.get(
            "/?query=query%20%7B%20human(id%3A%20%221000%22)%20%7B%20id%2C%20name%2C%20appearsIn%2C%20homePlanet%20%7D%20%7D");
        assert_eq!(response.status_code, 200);
        assert_eq!(response.content_type.as_str(), "application/json");
        assert_eq!(
            unwrap_json_response(&response),
            serde_json::from_str::<Json>(
                r#"{
                    "data": {
                        "human": {
                            "appearsIn": [
                                "NEW_HOPE",
                                "EMPIRE",
                                "JEDI"
                                ],
                                "homePlanet": "Tatooine",
                                "name": "Luke Skywalker",
                                "id": "1000"
                            }
                        }
                    }"#
            ).expect("Invalid JSON constant in test")
        );
    }
    fn test_get_with_variables<T: HTTPIntegration>(integration: &T) {
        
        
        let response = integration.get(
            "/?query=query(%24id%3A%20String!)%20%7B%20human(id%3A%20%24id)%20%7B%20id%2C%20name%2C%20appearsIn%2C%20homePlanet%20%7D%20%7D&variables=%7B%20%22id%22%3A%20%221000%22%20%7D");
        assert_eq!(response.status_code, 200);
        assert_eq!(response.content_type, "application/json");
        assert_eq!(
            unwrap_json_response(&response),
            serde_json::from_str::<Json>(
                r#"{
                    "data": {
                        "human": {
                            "appearsIn": [
                                "NEW_HOPE",
                                "EMPIRE",
                                "JEDI"
                                ],
                                "homePlanet": "Tatooine",
                                "name": "Luke Skywalker",
                                "id": "1000"
                            }
                        }
                    }"#
            ).expect("Invalid JSON constant in test")
        );
    }
    fn test_simple_post<T: HTTPIntegration>(integration: &T) {
        let response = integration.post("/", r#"{"query": "{hero{name}}"}"#);
        assert_eq!(response.status_code, 200);
        assert_eq!(response.content_type, "application/json");
        assert_eq!(
            unwrap_json_response(&response),
            serde_json::from_str::<Json>(r#"{"data": {"hero": {"name": "R2-D2"}}}"#)
                .expect("Invalid JSON constant in test")
        );
    }
    fn test_batched_post<T: HTTPIntegration>(integration: &T) {
        let response = integration.post(
            "/",
            r#"[{"query": "{hero{name}}"}, {"query": "{hero{name}}"}]"#,
        );
        assert_eq!(response.status_code, 200);
        assert_eq!(response.content_type, "application/json");
        assert_eq!(
            unwrap_json_response(&response),
            serde_json::from_str::<Json>(
                r#"[{"data": {"hero": {"name": "R2-D2"}}}, {"data": {"hero": {"name": "R2-D2"}}}]"#
            ).expect("Invalid JSON constant in test")
        );
    }
    fn test_invalid_json<T: HTTPIntegration>(integration: &T) {
        let response = integration.get("/?query=blah");
        assert_eq!(response.status_code, 400);
        let response = integration.post("/", r#"blah"#);
        assert_eq!(response.status_code, 400);
    }
    fn test_invalid_field<T: HTTPIntegration>(integration: &T) {
        
        let response = integration.get("/?query=%7Bhero%blah%7D%7D");
        assert_eq!(response.status_code, 400);
        let response = integration.post("/", r#"{"query": "{hero{blah}}"}"#);
        assert_eq!(response.status_code, 400);
    }
    fn test_duplicate_keys<T: HTTPIntegration>(integration: &T) {
        
        let response = integration.get("/?query=%7B%22query%22%3A%20%22%7Bhero%7Bname%7D%7D%22%2C%20%22query%22%3A%20%22%7Bhero%7Bname%7D%7D%22%7D");
        assert_eq!(response.status_code, 400);
        let response = integration.post("/", r#"
            {"query": "{hero{name}}", "query": "{hero{name}}"}
        "#);
        assert_eq!(response.status_code, 400);
    }
}