graphql_utils.rs 7.74 KiB
use crate::api_model::SortOrder;
use graphql_parser::query::parse_query;
use graphql_parser::query::Definition;
use graphql_parser::query::Field;
use graphql_parser::query::OperationDefinition;
use graphql_parser::query::Selection;
use graphql_parser::query::SelectionSet;
use graphql_parser::query::Text;
use graphql_parser::query::Value;
use std::convert::TryFrom;
use warp::http::status::StatusCode;
use crate::error::Error;
use crate::error::Result;
use std::collections::HashMap;
#[derive(Debug)]
pub struct QueryASTNode {
    pub item_type: Option<String>,
    pub arguments: Arguments,
    pub properties: Vec<String>,
    pub edges: HashMap<String, QueryASTNode>,
impl QueryASTNode {
    fn new() -> Self {
        QueryASTNode {
            item_type: None,
            arguments: Arguments::new(),
            properties: Vec::new(),
            edges: HashMap::new(),
fn parse_query_recursive(selection_set: SelectionSet<String>) -> Result<QueryASTNode> {
    let mut result = QueryASTNode::new();
    for selection in selection_set.items {
        if let Selection::Field(field) = selection {
            if field_is_property(&field) {
                result.properties.push(field.name);
            } else {
                let mut edge_ast_node = parse_query_recursive(field.selection_set)?;
                for (arg_name, arg_value) in field.arguments {
                    edge_ast_node.arguments.add_arg(arg_name, arg_value)?;
                result.edges.insert(field.name, edge_ast_node);
    Ok(result)
pub fn parse_graphql_query(query_string: &str) -> Result<QueryASTNode> {
    // TODO Only returns first Query
    // TODO error handling
    let parsed = match parse_query::<String>(query_string) {
        Ok(res) => res,
        Err(err) => {
            return Err(Error {
                code: StatusCode::BAD_REQUEST,
                msg: format!("Invalid GraphQL query {}", err).to_owned(),
            });
    if parsed.definitions.len() > 1 {
        panic!("graphQL only supports queries");
7172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
let def = parsed.definitions.first().ok_or_else(|| Error { code: StatusCode::BAD_REQUEST, msg: "Attempted to parse empty query".to_owned(), })?; if let Definition::Operation(OperationDefinition::Query(top_level_query)) = def.to_owned() { if top_level_query.selection_set.items.len() > 1 { panic!("graphQL supports a single query"); } // println!("{:}", top_level_query); let query = top_level_query .selection_set .items .first() .unwrap() .to_owned(); if let Selection::Field(field) = query { let mut result = parse_query_recursive(field.selection_set)?; result.item_type = Some(field.name); for (arg_name, arg_value) in field.arguments { result.arguments.add_arg(arg_name, arg_value)?; } Ok(result) } else { panic!("Fragments are not supported") } } else { panic!("Selectionsets/Mutations/Subscriptions are not supported"); } } pub fn field_is_property(field: &Field<String>) -> bool { field.selection_set.items.is_empty() } // pub enum Filter { // EQ {property: String, value: String}, // NE {property: String, value: String}, // LT {property: String, value: String}, // GT {property: String, value: String}, // // Box needed, cant do recursive memory allocation // AND {left: Box<Filter>, right: Box<Filter>}, // OR {left: Box<Filter>, right: Box<Filter>} // } #[derive(Debug)] pub struct Arguments { pub limit: Option<u32>, pub offset: Option<u32>, pub sort_order: Option<SortOrder>, pub sort_property: Option<String>, //pub filters: Vec<Filter>, } impl Arguments { fn new() -> Arguments { Arguments { limit: None, offset: None, sort_order: None, sort_property: None, } } fn add_arg<'a, T: Text<'a>>( &mut self, arg_name: String, arg_value: Value<'a, T>, ) -> Result<()> { match arg_name.as_str() {