async-graphql/parser/src/parse/executable.rs

339 lines
9.6 KiB
Rust
Raw Normal View History

use super::*;
/// Parse a GraphQL query document.
///
/// # Errors
///
/// Fails if the query is not a valid GraphQL document.
pub fn parse_query<T: AsRef<str>>(input: T) -> Result<ExecutableDocument> {
let mut pc = PositionCalculator::new(input.as_ref());
Ok(parse_executable_document(
2020-09-08 08:30:29 +00:00
exactly_one(GraphQLParser::parse(
Rule::executable_document,
input.as_ref(),
)?),
&mut pc,
)?)
}
2020-09-08 08:30:29 +00:00
fn parse_executable_document(
pair: Pair<Rule>,
pc: &mut PositionCalculator,
) -> Result<ExecutableDocument> {
debug_assert_eq!(pair.as_rule(), Rule::executable_document);
Ok(ExecutableDocument {
definitions: pair
.into_inner()
.filter(|pair| pair.as_rule() != Rule::EOI)
.map(|pair| parse_executable_definition(pair, pc))
.collect::<Result<_>>()?,
})
}
2020-09-08 08:30:29 +00:00
fn parse_executable_definition(
pair: Pair<Rule>,
pc: &mut PositionCalculator,
) -> Result<ExecutableDefinition> {
debug_assert_eq!(pair.as_rule(), Rule::executable_definition);
let pair = exactly_one(pair.into_inner());
Ok(match pair.as_rule() {
2020-09-08 08:30:29 +00:00
Rule::operation_definition => {
ExecutableDefinition::Operation(parse_operation_definition(pair, pc)?)
}
Rule::fragment_definition => {
ExecutableDefinition::Fragment(parse_fragment_definition(pair, pc)?)
}
_ => unreachable!(),
})
}
fn parse_operation_definition(
pair: Pair<Rule>,
pc: &mut PositionCalculator,
) -> Result<Positioned<OperationDefinition>> {
debug_assert_eq!(pair.as_rule(), Rule::operation_definition);
let pos = pc.step(&pair);
let pair = exactly_one(pair.into_inner());
Ok(Positioned::new(
match pair.as_rule() {
Rule::named_operation_definition => parse_named_operation_definition(pair, pc)?,
Rule::selection_set => OperationDefinition {
ty: OperationType::Query,
name: None,
variable_definitions: Vec::new(),
directives: Vec::new(),
selection_set: parse_selection_set(pair, pc)?,
},
_ => unreachable!(),
},
pos,
))
}
fn parse_named_operation_definition(
pair: Pair<Rule>,
pc: &mut PositionCalculator,
) -> Result<OperationDefinition> {
debug_assert_eq!(pair.as_rule(), Rule::named_operation_definition);
let mut pairs = pair.into_inner();
let ty = parse_operation_type(pairs.next().unwrap(), pc)?;
let name = parse_if_rule(&mut pairs, Rule::name, |pair| parse_name(pair, pc))?;
2020-09-08 08:30:29 +00:00
let variable_definitions = parse_if_rule(&mut pairs, Rule::variable_definitions, |pair| {
parse_variable_definitions(pair, pc)
})?;
let directives = parse_opt_directives(&mut pairs, pc)?;
let selection_set = parse_selection_set(pairs.next().unwrap(), pc)?;
debug_assert_eq!(pairs.next(), None);
Ok(OperationDefinition {
ty: ty.node,
name,
variable_definitions: variable_definitions.unwrap_or_default(),
directives,
selection_set,
})
}
fn parse_variable_definitions(
pair: Pair<Rule>,
pc: &mut PositionCalculator,
) -> Result<Vec<Positioned<VariableDefinition>>> {
debug_assert_eq!(pair.as_rule(), Rule::variable_definitions);
pair.into_inner()
.map(|pair| parse_variable_definition(pair, pc))
.collect()
}
fn parse_variable_definition(
pair: Pair<Rule>,
pc: &mut PositionCalculator,
) -> Result<Positioned<VariableDefinition>> {
debug_assert_eq!(pair.as_rule(), Rule::variable_definition);
let pos = pc.step(&pair);
let mut pairs = pair.into_inner();
let variable = parse_variable(pairs.next().unwrap(), pc)?;
let var_type = parse_type(pairs.next().unwrap(), pc)?;
2020-09-08 08:30:29 +00:00
let default_value = parse_if_rule(&mut pairs, Rule::default_value, |pair| {
parse_default_value(pair, pc)
})?;
debug_assert_eq!(pairs.next(), None);
Ok(Positioned::new(
VariableDefinition {
name: variable,
var_type,
default_value,
},
pos,
))
}
2020-09-08 08:30:29 +00:00
fn parse_selection_set(
pair: Pair<Rule>,
pc: &mut PositionCalculator,
) -> Result<Positioned<SelectionSet>> {
debug_assert_eq!(pair.as_rule(), Rule::selection_set);
let pos = pc.step(&pair);
Ok(Positioned::new(
SelectionSet {
items: pair
.into_inner()
.map(|pair| parse_selection(pair, pc))
.collect::<Result<_>>()?,
},
pos,
))
}
fn parse_selection(pair: Pair<Rule>, pc: &mut PositionCalculator) -> Result<Positioned<Selection>> {
debug_assert_eq!(pair.as_rule(), Rule::selection);
let pos = pc.step(&pair);
let pair = exactly_one(pair.into_inner());
Ok(Positioned::new(
match pair.as_rule() {
Rule::field => Selection::Field(parse_field(pair, pc)?),
Rule::fragment_spread => Selection::FragmentSpread(parse_fragment_spread(pair, pc)?),
Rule::inline_fragment => Selection::InlineFragment(parse_inline_fragment(pair, pc)?),
_ => unreachable!(),
},
pos,
))
}
fn parse_field(pair: Pair<Rule>, pc: &mut PositionCalculator) -> Result<Positioned<Field>> {
debug_assert_eq!(pair.as_rule(), Rule::field);
let pos = pc.step(&pair);
let mut pairs = pair.into_inner();
let alias = parse_if_rule(&mut pairs, Rule::alias, |pair| parse_alias(pair, pc))?;
let name = parse_name(pairs.next().unwrap(), pc)?;
2020-09-08 08:30:29 +00:00
let arguments = parse_if_rule(&mut pairs, Rule::arguments, |pair| {
parse_arguments(pair, pc)
})?;
let directives = parse_opt_directives(&mut pairs, pc)?;
2020-09-08 08:30:29 +00:00
let selection_set = parse_if_rule(&mut pairs, Rule::selection_set, |pair| {
parse_selection_set(pair, pc)
})?;
debug_assert_eq!(pairs.next(), None);
Ok(Positioned::new(
Field {
alias,
name,
arguments: arguments.unwrap_or_default(),
directives,
selection_set: selection_set.unwrap_or_default(),
},
pos,
))
}
fn parse_alias(pair: Pair<Rule>, pc: &mut PositionCalculator) -> Result<Positioned<Name>> {
debug_assert_eq!(pair.as_rule(), Rule::alias);
parse_name(exactly_one(pair.into_inner()), pc)
}
fn parse_fragment_spread(
pair: Pair<Rule>,
pc: &mut PositionCalculator,
) -> Result<Positioned<FragmentSpread>> {
debug_assert_eq!(pair.as_rule(), Rule::fragment_spread);
let pos = pc.step(&pair);
let mut pairs = pair.into_inner();
let fragment_name = parse_name(pairs.next().unwrap(), pc)?;
let directives = parse_opt_directives(&mut pairs, pc)?;
debug_assert_eq!(pairs.next(), None);
Ok(Positioned::new(
FragmentSpread {
fragment_name,
directives,
},
pos,
))
}
fn parse_inline_fragment(
pair: Pair<Rule>,
pc: &mut PositionCalculator,
) -> Result<Positioned<InlineFragment>> {
debug_assert_eq!(pair.as_rule(), Rule::inline_fragment);
let pos = pc.step(&pair);
let mut pairs = pair.into_inner();
2020-09-08 08:30:29 +00:00
let type_condition = parse_if_rule(&mut pairs, Rule::type_condition, |pair| {
parse_type_condition(pair, pc)
})?;
let directives = parse_opt_directives(&mut pairs, pc)?;
let selection_set = parse_selection_set(pairs.next().unwrap(), pc)?;
debug_assert_eq!(pairs.next(), None);
Ok(Positioned::new(
InlineFragment {
type_condition,
directives,
selection_set,
},
pos,
))
}
fn parse_fragment_definition(
pair: Pair<Rule>,
pc: &mut PositionCalculator,
) -> Result<Positioned<FragmentDefinition>> {
debug_assert_eq!(pair.as_rule(), Rule::fragment_definition);
let pos = pc.step(&pair);
let mut pairs = pair.into_inner();
let name = parse_name(pairs.next().unwrap(), pc)?;
let type_condition = parse_type_condition(pairs.next().unwrap(), pc)?;
let directives = parse_opt_directives(&mut pairs, pc)?;
let selection_set = parse_selection_set(pairs.next().unwrap(), pc)?;
debug_assert_eq!(pairs.next(), None);
Ok(Positioned::new(
FragmentDefinition {
name,
type_condition,
directives,
selection_set,
},
pos,
))
}
fn parse_type_condition(
pair: Pair<Rule>,
pc: &mut PositionCalculator,
) -> Result<Positioned<TypeCondition>> {
debug_assert_eq!(pair.as_rule(), Rule::type_condition);
let pos = pc.step(&pair);
Ok(Positioned::new(
TypeCondition {
on: parse_name(exactly_one(pair.into_inner()), pc)?,
},
pos,
))
}
#[cfg(test)]
mod tests {
use super::*;
use std::fs;
#[test]
fn test_parser() {
for entry in fs::read_dir("tests/executables").unwrap() {
if let Ok(entry) = entry {
2020-09-08 08:30:29 +00:00
GraphQLParser::parse(
Rule::executable_document,
&fs::read_to_string(entry.path()).unwrap(),
)
.unwrap();
}
}
}
#[test]
fn test_parser_ast() {
for entry in fs::read_dir("tests/executables").unwrap() {
if let Ok(entry) = entry {
parse_query(fs::read_to_string(entry.path()).unwrap()).unwrap();
}
}
}
#[test]
fn test_parse_overflowing_int() {
let query_ok = format!("mutation {{ add(big: {}) }} ", std::i32::MAX);
let query_overflow = format!("mutation {{ add(big: {}0000) }} ", std::i32::MAX);
assert!(parse_query(query_ok).is_ok());
assert!(parse_query(query_overflow).is_ok());
}
}