-
Alp Deniz Ogut authored895d8d6e
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() {