From b08c67cbf112469b79a614ed764bb4ce5501351c Mon Sep 17 00:00:00 2001 From: hanahsa Date: Fri, 11 Apr 2025 21:16:38 +1000 Subject: [PATCH] fragment variables --- src/query/ast.rs | 2 + src/query/format.rs | 10 ++++ src/query/grammar.rs | 56 +++++++++++++++---- .../queries/fragment_spread_arguments.graphql | 7 +++ tests/queries/fragment_variables.graphql | 3 + tests/query_roundtrips.rs | 8 +++ 6 files changed, 74 insertions(+), 12 deletions(-) create mode 100644 tests/queries/fragment_spread_arguments.graphql create mode 100644 tests/queries/fragment_variables.graphql diff --git a/src/query/ast.rs b/src/query/ast.rs index 1be1c7f..ffc5a82 100644 --- a/src/query/ast.rs +++ b/src/query/ast.rs @@ -43,6 +43,7 @@ pub enum Definition<'a, T: Text<'a>> { pub struct FragmentDefinition<'a, T: Text<'a>> { pub position: Pos, pub name: T::Value, + pub variable_definitions: Vec>, pub type_condition: TypeCondition<'a, T>, pub directives: Vec>, pub selection_set: SelectionSet<'a, T>, @@ -118,6 +119,7 @@ pub struct Field<'a, T: Text<'a>> { pub struct FragmentSpread<'a, T: Text<'a>> { pub position: Pos, pub fragment_name: T::Value, + pub arguments: Vec<(T::Value, Value<'a, T>)>, pub directives: Vec>, } diff --git a/src/query/format.rs b/src/query/format.rs index 872dd3d..de0e978 100644 --- a/src/query/format.rs +++ b/src/query/format.rs @@ -54,6 +54,15 @@ impl<'a, T: Text<'a>> Displayable for FragmentDefinition<'a, T> { f.indent(); f.write("fragment "); f.write(self.name.as_ref()); + if !self.variable_definitions.is_empty() { + f.write("("); + self.variable_definitions[0].display(f); + for var in &self.variable_definitions[1..] { + f.write(", "); + var.display(f); + } + f.write(")"); + } f.write(" "); self.type_condition.display(f); format_directives(&self.directives, f); @@ -322,6 +331,7 @@ impl<'a, T: Text<'a>> Displayable for FragmentSpread<'a, T> { f.indent(); f.write("..."); f.write(self.fragment_name.as_ref()); + format_arguments(&self.arguments, f); format_directives(&self.directives, f); f.endline(); } diff --git a/src/query/grammar.rs b/src/query/grammar.rs index cf31bec..49d66ca 100644 --- a/src/query/grammar.rs +++ b/src/query/grammar.rs @@ -67,12 +67,20 @@ where }, ) .map(Selection::InlineFragment) - .or((position(), name::<'a, S>(), parser(directives)) - .map(|(position, fragment_name, directives)| FragmentSpread { - position, - fragment_name, - directives, - }) + .or(( + position(), + name::<'a, S>(), + parser(arguments), + parser(directives), + ) + .map( + |(position, fragment_name, arguments, directives)| FragmentSpread { + position, + fragment_name, + arguments, + directives, + }, + ) .map(Selection::FragmentSpread)), )) .parse_stream(input) @@ -219,17 +227,41 @@ pub fn fragment_definition<'a, T: Text<'a>>( ( position().skip(ident("fragment")), name::<'a, T>(), + optional( + punct("(") + .with(many1( + ( + position(), + punct("$").with(name::<'a, T>()).skip(punct(":")), + parser(parse_type), + optional(punct("=").with(parser(default_value))), + ) + .map(|(position, name, var_type, default_value)| { + VariableDefinition { + position, + name, + var_type, + default_value, + } + }), + )) + .skip(punct(")")), + ) + .map(|vars| vars.unwrap_or_default()), ident("on").with(name::<'a, T>()).map(TypeCondition::On), parser(directives), parser(selection_set), ) .map( - |(position, name, type_condition, directives, selection_set)| FragmentDefinition { - position, - name, - type_condition, - directives, - selection_set, + |(position, name, variable_definitions, type_condition, directives, selection_set)| { + FragmentDefinition { + position, + name, + variable_definitions, + type_condition, + directives, + selection_set, + } }, ) .parse_stream(input) diff --git a/tests/queries/fragment_spread_arguments.graphql b/tests/queries/fragment_spread_arguments.graphql new file mode 100644 index 0000000..d896b6f --- /dev/null +++ b/tests/queries/fragment_spread_arguments.graphql @@ -0,0 +1,7 @@ +query { + node { + id + ...something(arg: "test") + ...somethingElse(arg2: $var) + } +} diff --git a/tests/queries/fragment_variables.graphql b/tests/queries/fragment_variables.graphql new file mode 100644 index 0000000..8a6abc8 --- /dev/null +++ b/tests/queries/fragment_variables.graphql @@ -0,0 +1,3 @@ +fragment frag($arg: String!) on Friend { + node +} diff --git a/tests/query_roundtrips.rs b/tests/query_roundtrips.rs index 7451f20..9eb3bb0 100644 --- a/tests/query_roundtrips.rs +++ b/tests/query_roundtrips.rs @@ -152,6 +152,10 @@ fn fragment_spread() { roundtrip_default("fragment_spread"); } #[test] +fn fragment_spread_arguments() { + roundtrip_default("fragment_spread_arguments"); +} +#[test] fn minimal_mutation() { roundtrip_default("minimal_mutation"); } @@ -160,6 +164,10 @@ fn fragment() { roundtrip_default("fragment"); } #[test] +fn fragment_variables() { + roundtrip_default("fragment_variables"); +} +#[test] fn directive_args() { roundtrip_default("directive_args"); }