diff --git a/trustfall_stubgen/src/edges_creator.rs b/trustfall_stubgen/src/edges_creator.rs index 812b2e52..e0ab27c1 100644 --- a/trustfall_stubgen/src/edges_creator.rs +++ b/trustfall_stubgen/src/edges_creator.rs @@ -4,6 +4,8 @@ use maplit::btreemap; use quote::quote; use trustfall::{Schema, SchemaAdapter, TryIntoStruct}; +use super::util::escaped_rust_name; + use super::{ root::RustFile, util::{ @@ -77,7 +79,10 @@ fn make_type_edge_resolver( edges: Vec<(String, Vec<(String, String)>)>, ) -> (proc_macro2::TokenStream, proc_macro2::TokenStream) { let lower_type_name = to_lower_snake_case(type_name); - let mod_name = syn::Ident::new(&lower_type_name, proc_macro2::Span::call_site()); + let mod_name = syn::Ident::new( + &escaped_rust_name(lower_type_name.clone()), + proc_macro2::Span::call_site(), + ); let mut arms = proc_macro2::TokenStream::new(); let mut edge_resolvers = proc_macro2::TokenStream::new(); @@ -135,9 +140,9 @@ fn make_edge_resolver_and_call( }, ); - let resolver_fn_name = to_lower_snake_case(edge_name); + let resolver_fn_name = escaped_rust_name(to_lower_snake_case(edge_name)); let resolver_fn_ident = syn::Ident::new(&resolver_fn_name, proc_macro2::Span::call_site()); - let conversion_fn_name = format!("as_{}", to_lower_snake_case(type_name)); + let conversion_fn_name = format!("as_{}", escaped_rust_name(to_lower_snake_case(type_name))); let conversion_fn_ident = syn::Ident::new(&conversion_fn_name, proc_macro2::Span::call_site()); let expect_msg = format!("conversion failed, vertex was not a {type_name}"); let todo_msg = format!("get neighbors along edge '{edge_name}' for type '{type_name}'"); diff --git a/trustfall_stubgen/src/entrypoints_creator.rs b/trustfall_stubgen/src/entrypoints_creator.rs index 931c62b3..c1a07610 100644 --- a/trustfall_stubgen/src/entrypoints_creator.rs +++ b/trustfall_stubgen/src/entrypoints_creator.rs @@ -4,7 +4,10 @@ use maplit::btreemap; use quote::quote; use trustfall::{Schema, SchemaAdapter, TryIntoStruct}; -use crate::edges_creator::{prepare_call_parameters, FnCall}; +use crate::{ + edges_creator::{prepare_call_parameters, FnCall}, + util::escaped_rust_name, +}; use super::{ root::RustFile, @@ -70,7 +73,7 @@ fn make_entrypoint_fn( }, ); - let entrypoint_fn_name = to_lower_snake_case(entrypoint); + let entrypoint_fn_name = escaped_rust_name(to_lower_snake_case(entrypoint)); let ident = syn::Ident::new(&entrypoint_fn_name, proc_macro2::Span::call_site()); let todo_msg = format!("implement resolving starting vertices for entrypoint edge '{entrypoint}'"); diff --git a/trustfall_stubgen/src/root.rs b/trustfall_stubgen/src/root.rs index 69d0362c..113ee08c 100644 --- a/trustfall_stubgen/src/root.rs +++ b/trustfall_stubgen/src/root.rs @@ -1,5 +1,5 @@ use std::{ - collections::{BTreeMap, BTreeSet}, + collections::{BTreeMap, BTreeSet, HashMap}, io::Write, path::Path, sync::{Arc, OnceLock}, @@ -10,7 +10,7 @@ use quote::quote; use regex::Regex; use trustfall::{Schema, SchemaAdapter, TryIntoStruct}; -use crate::util::parse_import; +use crate::util::{escaped_rust_name, parse_import, to_lower_snake_case, upper_case_variant_name}; use super::{ adapter_creator::make_adapter_file, edges_creator::make_edges_file, @@ -52,6 +52,9 @@ pub fn generate_rust_stub(schema: &str, target: &Path) -> anyhow::Result<()> { let mut entrypoint_match_arms = proc_macro2::TokenStream::new(); + ensure_no_vertex_name_conflicts(&querying_schema, schema_adapter.clone()); + ensure_no_field_name_conflicts_on_vertex_type(&querying_schema, schema_adapter.clone()); + make_vertex_file(&querying_schema, schema_adapter.clone(), &mut stub.vertex); make_entrypoints_file( &querying_schema, @@ -124,7 +127,6 @@ impl RustFile { static PATTERN: OnceLock = OnceLock::new(); let pattern = PATTERN.get_or_init(|| Regex::new("([^{])\n (pub|fn|use)").expect("invalid regex")); - let pretty_item = prettyplease::unparse(&syn::parse_str(&item.to_string()).expect("not valid Rust")); let postprocessed = pattern.replace_all(&pretty_item, "$1\n\n $2"); @@ -383,7 +385,7 @@ fn make_vertex_file( .collect(); rows.sort_unstable(); for row in rows { - let name = &row.name; + let name = &escaped_rust_name(upper_case_variant_name(&row.name)); let ident = syn::Ident::new(name.as_str(), proc_macro2::Span::call_site()); variants.extend(quote! { #ident(()), @@ -400,3 +402,86 @@ fn make_vertex_file( vertex_file.top_level_items.push(vertex); } + +fn ensure_no_vertex_name_conflicts(querying_schema: &Schema, adapter: Arc>) { + let query = r#" +{ + VertexType { + name @output + } +}"#; + let variables: BTreeMap = Default::default(); + + #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, serde::Deserialize)] + struct ResultRow { + name: String, + } + + let mut rows: Vec<_> = trustfall::execute_query(querying_schema, adapter, query, variables) + .expect("invalid query") + .map(|x| x.try_into_struct::().expect("invalid conversion")) + .collect(); + rows.sort_unstable(); + + let mut uniq: HashMap = HashMap::new(); + + for row in rows { + let name = row.name.clone(); + // we normalize to lower snake case here, however in vertex name we capitalize this name instead + // it doesn't really matter though because the important one is just to normalize to the same capitalization scheme + let converted = escaped_rust_name(to_lower_snake_case(&name)); + let v = uniq.insert(converted, name); + if let Some(v) = v { + panic!( + "cannot generate adapter for a schema containing both '{}' and '{}' vertices, consider renaming one of them", + v, &row.name + ); + } + } +} + +fn ensure_no_field_name_conflicts_on_vertex_type( + querying_schema: &Schema, + adapter: Arc>, +) { + let query = r#" +{ + VertexType { + name @output + edge_: edge @fold { + names: name @output + } + property_: property @fold { + names: name @output + } + } +}"#; + let variables: BTreeMap = Default::default(); + + #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, serde::Deserialize)] + struct ResultRow { + name: String, + edge_names: Vec, + property_names: Vec, + } + + let mut rows: Vec<_> = trustfall::execute_query(querying_schema, adapter, query, variables) + .expect("invalid query") + .map(|x| x.try_into_struct::().expect("invalid conversion")) + .collect(); + rows.sort_unstable(); + + for row in &rows { + let mut uniq: HashMap = HashMap::new(); + + for field_name in row.edge_names.iter().chain(row.property_names.iter()) { + let converted = escaped_rust_name(to_lower_snake_case(field_name)); + if let Some(v) = uniq.insert(converted, field_name.clone()) { + panic!( + "cannot generate adapter for a schema containing both '{}' and '{}' as field names on vertex '{}', consider renaming one of them", + v, &field_name, &row.name + ); + } + } + } +} diff --git a/trustfall_stubgen/src/tests.rs b/trustfall_stubgen/src/tests.rs index 14657116..18ac3226 100644 --- a/trustfall_stubgen/src/tests.rs +++ b/trustfall_stubgen/src/tests.rs @@ -153,3 +153,40 @@ fn test_schema(name: &str) { fn test_hackernews_schema() { test_schema("hackernews") } + +#[test] +fn test_use_reserved_rust_names_in_schema() { + test_schema("use_reserved_rust_names_in_schema"); +} + +#[test] +#[should_panic( + expected = "cannot generate adapter for a schema containing both 'Type' and 'Type_' vertices, consider renaming one of them" +)] +fn use_type_and_typeunderscore_edge_names() { + test_schema("use_type_and_typeunderscore_edge_names"); +} + +#[test] +#[should_panic( + expected = "cannot generate adapter for a schema containing both 'Type_' and 'Type' as field names on vertex 'Type', consider renaming one of them" +)] +fn vertextype_with_type_and_typeunderscore_edge_and_property() { + test_schema("vertextype_with_type_and_typeunderscore_edge_and_property"); +} + +#[test] +#[should_panic( + expected = "cannot generate adapter for a schema containing both 'Type' and 'Type_' as field names on vertex 'Type', consider renaming one of them" +)] +fn vertextype_with_type_and_typeunderscore_edges() { + test_schema("vertextype_with_type_and_typeunderscore_edges"); +} + +#[test] +#[should_panic( + expected = "cannot generate adapter for a schema containing both 'Type' and 'Type_' as field names on vertex 'Type', consider renaming one of them" +)] +fn vertextype_with_type_and_typeunderscore_properties() { + test_schema("vertextype_with_type_and_typeunderscore_properties"); +} diff --git a/trustfall_stubgen/src/util.rs b/trustfall_stubgen/src/util.rs index e9e302a4..311b06c5 100644 --- a/trustfall_stubgen/src/util.rs +++ b/trustfall_stubgen/src/util.rs @@ -17,6 +17,14 @@ pub(crate) fn to_lower_snake_case(value: &str) -> String { result } +pub(crate) fn upper_case_variant_name(value: &str) -> String { + let mut chars = value.chars(); + let first_char = chars.next().expect("unexpectedly got an empty string").to_ascii_uppercase(); + let rest_chars: String = chars.collect(); + + format!("{}{}", first_char, rest_chars) +} + pub(crate) fn property_resolver_fn_name(type_name: &str) -> String { let normalized_name = to_lower_snake_case(type_name); format!("resolve_{normalized_name}_property") @@ -138,3 +146,15 @@ pub(crate) fn field_value_to_rust_type( #base.#suffix } } + +pub fn escaped_rust_name(name: String) -> String { + // https://doc.rust-lang.org/reference/keywords.html + match name.as_str() { + "as" | "break" | "const" | "continue" | "crate" | "else" | "enum" | "extern" | "false" + | "fn" | "for" | "if" | "impl" | "in" | "let" | "loop" | "match" | "mod" | "move" + | "mut" | "pub" | "ref" | "return" | "self" | "Self" | "static" | "struct" | "super" + | "trait" | "true" | "type" | "unsafe" | "use" | "where" | "while" | "async" | "await" + | "dyn" | "try" | "macro_rules" | "union" | "'static" => name + "_", + _ => name, + } +} diff --git a/trustfall_stubgen/test_data/expected_outputs/use_reserved_rust_names_in_schema/adapter/adapter_impl.rs b/trustfall_stubgen/test_data/expected_outputs/use_reserved_rust_names_in_schema/adapter/adapter_impl.rs new file mode 100644 index 00000000..c9116da9 --- /dev/null +++ b/trustfall_stubgen/test_data/expected_outputs/use_reserved_rust_names_in_schema/adapter/adapter_impl.rs @@ -0,0 +1,241 @@ +use std::sync::{Arc, OnceLock}; + +use trustfall::{FieldValue, Schema, provider::{ContextIterator, ContextOutcomeIterator, EdgeParameters, ResolveEdgeInfo, ResolveInfo, VertexIterator, resolve_coercion_using_schema}}; + +use super::vertex::Vertex; + +static SCHEMA: OnceLock = OnceLock::new(); + +#[non_exhaustive] +#[derive(Debug)] +pub struct Adapter {} + +impl Adapter { + pub const SCHEMA_TEXT: &'static str = include_str!("./schema.graphql"); + + pub fn schema() -> &'static Schema { + SCHEMA + .get_or_init(|| { + Schema::parse(Self::SCHEMA_TEXT).expect("not a valid schema") + }) + } + + pub fn new() -> Self { + Self {} + } +} + +impl<'a> trustfall::provider::Adapter<'a> for Adapter { + type Vertex = Vertex; + + fn resolve_starting_vertices( + &self, + edge_name: &Arc, + parameters: &EdgeParameters, + resolve_info: &ResolveInfo, + ) -> VertexIterator<'a, Self::Vertex> { + match edge_name.as_ref() { + "const" => super::entrypoints::const_(resolve_info), + "const2" => super::entrypoints::const2(resolve_info), + "continue" => super::entrypoints::continue_(resolve_info), + "continue2" => super::entrypoints::continue2(resolve_info), + "dyn" => super::entrypoints::dyn_(resolve_info), + "dyn2" => super::entrypoints::dyn2(resolve_info), + "if" => super::entrypoints::if_(resolve_info), + "if2" => super::entrypoints::if2(resolve_info), + "mod" => super::entrypoints::mod_(resolve_info), + "mod2" => super::entrypoints::mod2(resolve_info), + "self" => super::entrypoints::self_(resolve_info), + "self2" => super::entrypoints::self2(resolve_info), + "type" => super::entrypoints::type_(resolve_info), + "type2" => super::entrypoints::type2(resolve_info), + "unsafe" => super::entrypoints::unsafe_(resolve_info), + "unsafe2" => super::entrypoints::unsafe2(resolve_info), + "where" => super::entrypoints::where_(resolve_info), + "where2" => super::entrypoints::where2(resolve_info), + _ => { + unreachable!( + "attempted to resolve starting vertices for unexpected edge name: {edge_name}" + ) + } + } + } + + fn resolve_property( + &self, + contexts: ContextIterator<'a, Self::Vertex>, + type_name: &Arc, + property_name: &Arc, + resolve_info: &ResolveInfo, + ) -> ContextOutcomeIterator<'a, Self::Vertex, FieldValue> { + match type_name.as_ref() { + "const2" => { + super::properties::resolve_const2_property( + contexts, + property_name.as_ref(), + resolve_info, + ) + } + "continue2" => { + super::properties::resolve_continue2_property( + contexts, + property_name.as_ref(), + resolve_info, + ) + } + "dyn2" => { + super::properties::resolve_dyn2_property( + contexts, + property_name.as_ref(), + resolve_info, + ) + } + "if2" => { + super::properties::resolve_if2_property( + contexts, + property_name.as_ref(), + resolve_info, + ) + } + "mod2" => { + super::properties::resolve_mod2_property( + contexts, + property_name.as_ref(), + resolve_info, + ) + } + "self2" => { + super::properties::resolve_self2_property( + contexts, + property_name.as_ref(), + resolve_info, + ) + } + "type2" => { + super::properties::resolve_type2_property( + contexts, + property_name.as_ref(), + resolve_info, + ) + } + "unsafe2" => { + super::properties::resolve_unsafe2_property( + contexts, + property_name.as_ref(), + resolve_info, + ) + } + "where2" => { + super::properties::resolve_where2_property( + contexts, + property_name.as_ref(), + resolve_info, + ) + } + _ => { + unreachable!( + "attempted to read property '{property_name}' on unexpected type: {type_name}" + ) + } + } + } + + fn resolve_neighbors( + &self, + contexts: ContextIterator<'a, Self::Vertex>, + type_name: &Arc, + edge_name: &Arc, + parameters: &EdgeParameters, + resolve_info: &ResolveEdgeInfo, + ) -> ContextOutcomeIterator<'a, Self::Vertex, VertexIterator<'a, Self::Vertex>> { + match type_name.as_ref() { + "const" => { + super::edges::resolve_const_edge( + contexts, + edge_name.as_ref(), + parameters, + resolve_info, + ) + } + "continue" => { + super::edges::resolve_continue_edge( + contexts, + edge_name.as_ref(), + parameters, + resolve_info, + ) + } + "dyn" => { + super::edges::resolve_dyn_edge( + contexts, + edge_name.as_ref(), + parameters, + resolve_info, + ) + } + "if" => { + super::edges::resolve_if_edge( + contexts, + edge_name.as_ref(), + parameters, + resolve_info, + ) + } + "mod" => { + super::edges::resolve_mod_edge( + contexts, + edge_name.as_ref(), + parameters, + resolve_info, + ) + } + "self" => { + super::edges::resolve_self_edge( + contexts, + edge_name.as_ref(), + parameters, + resolve_info, + ) + } + "type" => { + super::edges::resolve_type_edge( + contexts, + edge_name.as_ref(), + parameters, + resolve_info, + ) + } + "unsafe" => { + super::edges::resolve_unsafe_edge( + contexts, + edge_name.as_ref(), + parameters, + resolve_info, + ) + } + "where" => { + super::edges::resolve_where_edge( + contexts, + edge_name.as_ref(), + parameters, + resolve_info, + ) + } + _ => { + unreachable!( + "attempted to resolve edge '{edge_name}' on unexpected type: {type_name}" + ) + } + } + } + + fn resolve_coercion( + &self, + contexts: ContextIterator<'a, Self::Vertex>, + _type_name: &Arc, + coerce_to_type: &Arc, + _resolve_info: &ResolveInfo, + ) -> ContextOutcomeIterator<'a, Self::Vertex, bool> { + resolve_coercion_using_schema(contexts, Self::schema(), coerce_to_type.as_ref()) + } +} diff --git a/trustfall_stubgen/test_data/expected_outputs/use_reserved_rust_names_in_schema/adapter/edges.rs b/trustfall_stubgen/test_data/expected_outputs/use_reserved_rust_names_in_schema/adapter/edges.rs new file mode 100644 index 00000000..56ce26d7 --- /dev/null +++ b/trustfall_stubgen/test_data/expected_outputs/use_reserved_rust_names_in_schema/adapter/edges.rs @@ -0,0 +1,363 @@ +use trustfall::provider::{ContextIterator, ContextOutcomeIterator, EdgeParameters, ResolveEdgeInfo, VertexIterator}; + +use super::vertex::Vertex; + +pub(super) fn resolve_const_edge<'a>( + contexts: ContextIterator<'a, Vertex>, + edge_name: &str, + parameters: &EdgeParameters, + resolve_info: &ResolveEdgeInfo, +) -> ContextOutcomeIterator<'a, Vertex, VertexIterator<'a, Vertex>> { + match edge_name { + "const" => const_::const_(contexts, resolve_info), + _ => { + unreachable!( + "attempted to resolve unexpected edge '{edge_name}' on type 'const'" + ) + } + } +} + +mod const_ { + use trustfall::provider::{ + resolve_neighbors_with, ContextIterator, ContextOutcomeIterator, ResolveEdgeInfo, + VertexIterator, + }; + + use super::super::vertex::Vertex; + + pub(super) fn const_<'a>( + contexts: ContextIterator<'a, Vertex>, + _resolve_info: &ResolveEdgeInfo, + ) -> ContextOutcomeIterator<'a, Vertex, VertexIterator<'a, Vertex>> { + resolve_neighbors_with( + contexts, + |vertex| { + let vertex = vertex + .as_const_() + .expect("conversion failed, vertex was not a const"); + todo!("get neighbors along edge 'const' for type 'const'") + }, + ) + } +} + +pub(super) fn resolve_continue_edge<'a>( + contexts: ContextIterator<'a, Vertex>, + edge_name: &str, + parameters: &EdgeParameters, + resolve_info: &ResolveEdgeInfo, +) -> ContextOutcomeIterator<'a, Vertex, VertexIterator<'a, Vertex>> { + match edge_name { + "continue" => continue_::continue_(contexts, resolve_info), + _ => { + unreachable!( + "attempted to resolve unexpected edge '{edge_name}' on type 'continue'" + ) + } + } +} + +mod continue_ { + use trustfall::provider::{ + resolve_neighbors_with, ContextIterator, ContextOutcomeIterator, ResolveEdgeInfo, + VertexIterator, + }; + + use super::super::vertex::Vertex; + + pub(super) fn continue_<'a>( + contexts: ContextIterator<'a, Vertex>, + _resolve_info: &ResolveEdgeInfo, + ) -> ContextOutcomeIterator<'a, Vertex, VertexIterator<'a, Vertex>> { + resolve_neighbors_with( + contexts, + |vertex| { + let vertex = vertex + .as_continue_() + .expect("conversion failed, vertex was not a continue"); + todo!("get neighbors along edge 'continue' for type 'continue'") + }, + ) + } +} + +pub(super) fn resolve_dyn_edge<'a>( + contexts: ContextIterator<'a, Vertex>, + edge_name: &str, + parameters: &EdgeParameters, + resolve_info: &ResolveEdgeInfo, +) -> ContextOutcomeIterator<'a, Vertex, VertexIterator<'a, Vertex>> { + match edge_name { + "dyn" => dyn_::dyn_(contexts, resolve_info), + _ => { + unreachable!( + "attempted to resolve unexpected edge '{edge_name}' on type 'dyn'" + ) + } + } +} + +mod dyn_ { + use trustfall::provider::{ + resolve_neighbors_with, ContextIterator, ContextOutcomeIterator, ResolveEdgeInfo, + VertexIterator, + }; + + use super::super::vertex::Vertex; + + pub(super) fn dyn_<'a>( + contexts: ContextIterator<'a, Vertex>, + _resolve_info: &ResolveEdgeInfo, + ) -> ContextOutcomeIterator<'a, Vertex, VertexIterator<'a, Vertex>> { + resolve_neighbors_with( + contexts, + |vertex| { + let vertex = vertex + .as_dyn_() + .expect("conversion failed, vertex was not a dyn"); + todo!("get neighbors along edge 'dyn' for type 'dyn'") + }, + ) + } +} + +pub(super) fn resolve_if_edge<'a>( + contexts: ContextIterator<'a, Vertex>, + edge_name: &str, + parameters: &EdgeParameters, + resolve_info: &ResolveEdgeInfo, +) -> ContextOutcomeIterator<'a, Vertex, VertexIterator<'a, Vertex>> { + match edge_name { + "if" => if_::if_(contexts, resolve_info), + _ => { + unreachable!( + "attempted to resolve unexpected edge '{edge_name}' on type 'if'" + ) + } + } +} + +mod if_ { + use trustfall::provider::{ + resolve_neighbors_with, ContextIterator, ContextOutcomeIterator, ResolveEdgeInfo, + VertexIterator, + }; + + use super::super::vertex::Vertex; + + pub(super) fn if_<'a>( + contexts: ContextIterator<'a, Vertex>, + _resolve_info: &ResolveEdgeInfo, + ) -> ContextOutcomeIterator<'a, Vertex, VertexIterator<'a, Vertex>> { + resolve_neighbors_with( + contexts, + |vertex| { + let vertex = vertex + .as_if_() + .expect("conversion failed, vertex was not a if"); + todo!("get neighbors along edge 'if' for type 'if'") + }, + ) + } +} + +pub(super) fn resolve_mod_edge<'a>( + contexts: ContextIterator<'a, Vertex>, + edge_name: &str, + parameters: &EdgeParameters, + resolve_info: &ResolveEdgeInfo, +) -> ContextOutcomeIterator<'a, Vertex, VertexIterator<'a, Vertex>> { + match edge_name { + "mod" => mod_::mod_(contexts, resolve_info), + _ => { + unreachable!( + "attempted to resolve unexpected edge '{edge_name}' on type 'mod'" + ) + } + } +} + +mod mod_ { + use trustfall::provider::{ + resolve_neighbors_with, ContextIterator, ContextOutcomeIterator, ResolveEdgeInfo, + VertexIterator, + }; + + use super::super::vertex::Vertex; + + pub(super) fn mod_<'a>( + contexts: ContextIterator<'a, Vertex>, + _resolve_info: &ResolveEdgeInfo, + ) -> ContextOutcomeIterator<'a, Vertex, VertexIterator<'a, Vertex>> { + resolve_neighbors_with( + contexts, + |vertex| { + let vertex = vertex + .as_mod_() + .expect("conversion failed, vertex was not a mod"); + todo!("get neighbors along edge 'mod' for type 'mod'") + }, + ) + } +} + +pub(super) fn resolve_self_edge<'a>( + contexts: ContextIterator<'a, Vertex>, + edge_name: &str, + parameters: &EdgeParameters, + resolve_info: &ResolveEdgeInfo, +) -> ContextOutcomeIterator<'a, Vertex, VertexIterator<'a, Vertex>> { + match edge_name { + "self" => self_::self_(contexts, resolve_info), + _ => { + unreachable!( + "attempted to resolve unexpected edge '{edge_name}' on type 'self'" + ) + } + } +} + +mod self_ { + use trustfall::provider::{ + resolve_neighbors_with, ContextIterator, ContextOutcomeIterator, ResolveEdgeInfo, + VertexIterator, + }; + + use super::super::vertex::Vertex; + + pub(super) fn self_<'a>( + contexts: ContextIterator<'a, Vertex>, + _resolve_info: &ResolveEdgeInfo, + ) -> ContextOutcomeIterator<'a, Vertex, VertexIterator<'a, Vertex>> { + resolve_neighbors_with( + contexts, + |vertex| { + let vertex = vertex + .as_self_() + .expect("conversion failed, vertex was not a self"); + todo!("get neighbors along edge 'self' for type 'self'") + }, + ) + } +} + +pub(super) fn resolve_type_edge<'a>( + contexts: ContextIterator<'a, Vertex>, + edge_name: &str, + parameters: &EdgeParameters, + resolve_info: &ResolveEdgeInfo, +) -> ContextOutcomeIterator<'a, Vertex, VertexIterator<'a, Vertex>> { + match edge_name { + "type" => type_::type_(contexts, resolve_info), + _ => { + unreachable!( + "attempted to resolve unexpected edge '{edge_name}' on type 'type'" + ) + } + } +} + +mod type_ { + use trustfall::provider::{ + resolve_neighbors_with, ContextIterator, ContextOutcomeIterator, ResolveEdgeInfo, + VertexIterator, + }; + + use super::super::vertex::Vertex; + + pub(super) fn type_<'a>( + contexts: ContextIterator<'a, Vertex>, + _resolve_info: &ResolveEdgeInfo, + ) -> ContextOutcomeIterator<'a, Vertex, VertexIterator<'a, Vertex>> { + resolve_neighbors_with( + contexts, + |vertex| { + let vertex = vertex + .as_type_() + .expect("conversion failed, vertex was not a type"); + todo!("get neighbors along edge 'type' for type 'type'") + }, + ) + } +} + +pub(super) fn resolve_unsafe_edge<'a>( + contexts: ContextIterator<'a, Vertex>, + edge_name: &str, + parameters: &EdgeParameters, + resolve_info: &ResolveEdgeInfo, +) -> ContextOutcomeIterator<'a, Vertex, VertexIterator<'a, Vertex>> { + match edge_name { + "unsafe" => unsafe_::unsafe_(contexts, resolve_info), + _ => { + unreachable!( + "attempted to resolve unexpected edge '{edge_name}' on type 'unsafe'" + ) + } + } +} + +mod unsafe_ { + use trustfall::provider::{ + resolve_neighbors_with, ContextIterator, ContextOutcomeIterator, ResolveEdgeInfo, + VertexIterator, + }; + + use super::super::vertex::Vertex; + + pub(super) fn unsafe_<'a>( + contexts: ContextIterator<'a, Vertex>, + _resolve_info: &ResolveEdgeInfo, + ) -> ContextOutcomeIterator<'a, Vertex, VertexIterator<'a, Vertex>> { + resolve_neighbors_with( + contexts, + |vertex| { + let vertex = vertex + .as_unsafe_() + .expect("conversion failed, vertex was not a unsafe"); + todo!("get neighbors along edge 'unsafe' for type 'unsafe'") + }, + ) + } +} + +pub(super) fn resolve_where_edge<'a>( + contexts: ContextIterator<'a, Vertex>, + edge_name: &str, + parameters: &EdgeParameters, + resolve_info: &ResolveEdgeInfo, +) -> ContextOutcomeIterator<'a, Vertex, VertexIterator<'a, Vertex>> { + match edge_name { + "where" => where_::where_(contexts, resolve_info), + _ => { + unreachable!( + "attempted to resolve unexpected edge '{edge_name}' on type 'where'" + ) + } + } +} + +mod where_ { + use trustfall::provider::{ + resolve_neighbors_with, ContextIterator, ContextOutcomeIterator, ResolveEdgeInfo, + VertexIterator, + }; + + use super::super::vertex::Vertex; + + pub(super) fn where_<'a>( + contexts: ContextIterator<'a, Vertex>, + _resolve_info: &ResolveEdgeInfo, + ) -> ContextOutcomeIterator<'a, Vertex, VertexIterator<'a, Vertex>> { + resolve_neighbors_with( + contexts, + |vertex| { + let vertex = vertex + .as_where_() + .expect("conversion failed, vertex was not a where"); + todo!("get neighbors along edge 'where' for type 'where'") + }, + ) + } +} diff --git a/trustfall_stubgen/test_data/expected_outputs/use_reserved_rust_names_in_schema/adapter/entrypoints.rs b/trustfall_stubgen/test_data/expected_outputs/use_reserved_rust_names_in_schema/adapter/entrypoints.rs new file mode 100644 index 00000000..55872807 --- /dev/null +++ b/trustfall_stubgen/test_data/expected_outputs/use_reserved_rust_names_in_schema/adapter/entrypoints.rs @@ -0,0 +1,75 @@ +use trustfall::provider::{ResolveInfo, VertexIterator}; + +use super::vertex::Vertex; + +pub(super) fn const_<'a>(_resolve_info: &ResolveInfo) -> VertexIterator<'a, Vertex> { + todo!("implement resolving starting vertices for entrypoint edge 'const'") +} + +pub(super) fn const2<'a>(_resolve_info: &ResolveInfo) -> VertexIterator<'a, Vertex> { + todo!("implement resolving starting vertices for entrypoint edge 'const2'") +} + +pub(super) fn continue_<'a>(_resolve_info: &ResolveInfo) -> VertexIterator<'a, Vertex> { + todo!("implement resolving starting vertices for entrypoint edge 'continue'") +} + +pub(super) fn continue2<'a>(_resolve_info: &ResolveInfo) -> VertexIterator<'a, Vertex> { + todo!("implement resolving starting vertices for entrypoint edge 'continue2'") +} + +pub(super) fn dyn_<'a>(_resolve_info: &ResolveInfo) -> VertexIterator<'a, Vertex> { + todo!("implement resolving starting vertices for entrypoint edge 'dyn'") +} + +pub(super) fn dyn2<'a>(_resolve_info: &ResolveInfo) -> VertexIterator<'a, Vertex> { + todo!("implement resolving starting vertices for entrypoint edge 'dyn2'") +} + +pub(super) fn if_<'a>(_resolve_info: &ResolveInfo) -> VertexIterator<'a, Vertex> { + todo!("implement resolving starting vertices for entrypoint edge 'if'") +} + +pub(super) fn if2<'a>(_resolve_info: &ResolveInfo) -> VertexIterator<'a, Vertex> { + todo!("implement resolving starting vertices for entrypoint edge 'if2'") +} + +pub(super) fn mod_<'a>(_resolve_info: &ResolveInfo) -> VertexIterator<'a, Vertex> { + todo!("implement resolving starting vertices for entrypoint edge 'mod'") +} + +pub(super) fn mod2<'a>(_resolve_info: &ResolveInfo) -> VertexIterator<'a, Vertex> { + todo!("implement resolving starting vertices for entrypoint edge 'mod2'") +} + +pub(super) fn self_<'a>(_resolve_info: &ResolveInfo) -> VertexIterator<'a, Vertex> { + todo!("implement resolving starting vertices for entrypoint edge 'self'") +} + +pub(super) fn self2<'a>(_resolve_info: &ResolveInfo) -> VertexIterator<'a, Vertex> { + todo!("implement resolving starting vertices for entrypoint edge 'self2'") +} + +pub(super) fn type_<'a>(_resolve_info: &ResolveInfo) -> VertexIterator<'a, Vertex> { + todo!("implement resolving starting vertices for entrypoint edge 'type'") +} + +pub(super) fn type2<'a>(_resolve_info: &ResolveInfo) -> VertexIterator<'a, Vertex> { + todo!("implement resolving starting vertices for entrypoint edge 'type2'") +} + +pub(super) fn unsafe_<'a>(_resolve_info: &ResolveInfo) -> VertexIterator<'a, Vertex> { + todo!("implement resolving starting vertices for entrypoint edge 'unsafe'") +} + +pub(super) fn unsafe2<'a>(_resolve_info: &ResolveInfo) -> VertexIterator<'a, Vertex> { + todo!("implement resolving starting vertices for entrypoint edge 'unsafe2'") +} + +pub(super) fn where_<'a>(_resolve_info: &ResolveInfo) -> VertexIterator<'a, Vertex> { + todo!("implement resolving starting vertices for entrypoint edge 'where'") +} + +pub(super) fn where2<'a>(_resolve_info: &ResolveInfo) -> VertexIterator<'a, Vertex> { + todo!("implement resolving starting vertices for entrypoint edge 'where2'") +} diff --git a/trustfall_stubgen/test_data/expected_outputs/use_reserved_rust_names_in_schema/adapter/mod.rs b/trustfall_stubgen/test_data/expected_outputs/use_reserved_rust_names_in_schema/adapter/mod.rs new file mode 100644 index 00000000..ba4cb201 --- /dev/null +++ b/trustfall_stubgen/test_data/expected_outputs/use_reserved_rust_names_in_schema/adapter/mod.rs @@ -0,0 +1,11 @@ +mod adapter_impl; +mod vertex; +mod entrypoints; +mod properties; +mod edges; + +#[cfg(test)] +mod tests; + +pub use adapter_impl::Adapter; +pub use vertex::Vertex; diff --git a/trustfall_stubgen/test_data/expected_outputs/use_reserved_rust_names_in_schema/adapter/properties.rs b/trustfall_stubgen/test_data/expected_outputs/use_reserved_rust_names_in_schema/adapter/properties.rs new file mode 100644 index 00000000..e74c6807 --- /dev/null +++ b/trustfall_stubgen/test_data/expected_outputs/use_reserved_rust_names_in_schema/adapter/properties.rs @@ -0,0 +1,142 @@ +use trustfall::{FieldValue, provider::{ContextIterator, ContextOutcomeIterator, ResolveInfo}}; + +use super::vertex::Vertex; + +pub(super) fn resolve_const2_property<'a>( + contexts: ContextIterator<'a, Vertex>, + property_name: &str, + _resolve_info: &ResolveInfo, +) -> ContextOutcomeIterator<'a, Vertex, FieldValue> { + match property_name { + "const" => todo!("implement property 'const' in fn `resolve_const2_property()`"), + _ => { + unreachable!( + "attempted to read unexpected property '{property_name}' on type 'const2'" + ) + } + } +} + +pub(super) fn resolve_continue2_property<'a>( + contexts: ContextIterator<'a, Vertex>, + property_name: &str, + _resolve_info: &ResolveInfo, +) -> ContextOutcomeIterator<'a, Vertex, FieldValue> { + match property_name { + "continue" => { + todo!("implement property 'continue' in fn `resolve_continue2_property()`") + } + _ => { + unreachable!( + "attempted to read unexpected property '{property_name}' on type 'continue2'" + ) + } + } +} + +pub(super) fn resolve_dyn2_property<'a>( + contexts: ContextIterator<'a, Vertex>, + property_name: &str, + _resolve_info: &ResolveInfo, +) -> ContextOutcomeIterator<'a, Vertex, FieldValue> { + match property_name { + "dyn" => todo!("implement property 'dyn' in fn `resolve_dyn2_property()`"), + _ => { + unreachable!( + "attempted to read unexpected property '{property_name}' on type 'dyn2'" + ) + } + } +} + +pub(super) fn resolve_if2_property<'a>( + contexts: ContextIterator<'a, Vertex>, + property_name: &str, + _resolve_info: &ResolveInfo, +) -> ContextOutcomeIterator<'a, Vertex, FieldValue> { + match property_name { + "if" => todo!("implement property 'if' in fn `resolve_if2_property()`"), + _ => { + unreachable!( + "attempted to read unexpected property '{property_name}' on type 'if2'" + ) + } + } +} + +pub(super) fn resolve_mod2_property<'a>( + contexts: ContextIterator<'a, Vertex>, + property_name: &str, + _resolve_info: &ResolveInfo, +) -> ContextOutcomeIterator<'a, Vertex, FieldValue> { + match property_name { + "mod" => todo!("implement property 'mod' in fn `resolve_mod2_property()`"), + _ => { + unreachable!( + "attempted to read unexpected property '{property_name}' on type 'mod2'" + ) + } + } +} + +pub(super) fn resolve_self2_property<'a>( + contexts: ContextIterator<'a, Vertex>, + property_name: &str, + _resolve_info: &ResolveInfo, +) -> ContextOutcomeIterator<'a, Vertex, FieldValue> { + match property_name { + "self" => todo!("implement property 'self' in fn `resolve_self2_property()`"), + _ => { + unreachable!( + "attempted to read unexpected property '{property_name}' on type 'self2'" + ) + } + } +} + +pub(super) fn resolve_type2_property<'a>( + contexts: ContextIterator<'a, Vertex>, + property_name: &str, + _resolve_info: &ResolveInfo, +) -> ContextOutcomeIterator<'a, Vertex, FieldValue> { + match property_name { + "type" => todo!("implement property 'type' in fn `resolve_type2_property()`"), + _ => { + unreachable!( + "attempted to read unexpected property '{property_name}' on type 'type2'" + ) + } + } +} + +pub(super) fn resolve_unsafe2_property<'a>( + contexts: ContextIterator<'a, Vertex>, + property_name: &str, + _resolve_info: &ResolveInfo, +) -> ContextOutcomeIterator<'a, Vertex, FieldValue> { + match property_name { + "unsafe" => { + todo!("implement property 'unsafe' in fn `resolve_unsafe2_property()`") + } + _ => { + unreachable!( + "attempted to read unexpected property '{property_name}' on type 'unsafe2'" + ) + } + } +} + +pub(super) fn resolve_where2_property<'a>( + contexts: ContextIterator<'a, Vertex>, + property_name: &str, + _resolve_info: &ResolveInfo, +) -> ContextOutcomeIterator<'a, Vertex, FieldValue> { + match property_name { + "where" => todo!("implement property 'where' in fn `resolve_where2_property()`"), + _ => { + unreachable!( + "attempted to read unexpected property '{property_name}' on type 'where2'" + ) + } + } +} diff --git a/trustfall_stubgen/test_data/expected_outputs/use_reserved_rust_names_in_schema/adapter/schema.graphql b/trustfall_stubgen/test_data/expected_outputs/use_reserved_rust_names_in_schema/adapter/schema.graphql new file mode 100644 index 00000000..ab4c5cb5 --- /dev/null +++ b/trustfall_stubgen/test_data/expected_outputs/use_reserved_rust_names_in_schema/adapter/schema.graphql @@ -0,0 +1,136 @@ +schema { + query: RootSchemaQuery +} +directive @filter( + """ + Name of the filter operation to perform. + """ + op: String! + """ + List of string operands for the operator. + """ + value: [String!] +) on FIELD | INLINE_FRAGMENT +directive @tag( + """ + Name to apply to the given property field. + """ + name: String +) on FIELD +directive @output( + """ + What to designate the output field generated from this property field. + """ + name: String +) on FIELD +directive @optional on FIELD +directive @recurse( + """ + Recurse up to this many times on this edge. A depth of 1 produces the current + vertex and its immediate neighbors along the given edge. + """ + depth: Int! +) on FIELD +directive @fold on FIELD +directive @transform( + """ + Name of the transformation operation to perform. + """ + op: String! +) on FIELD + +""" +All the possible data types where querying can begin in this API. +""" +type RootSchemaQuery { + const: [const!]! + const2: [const2!]! + continue: [continue!]! + continue2: [continue2!]! + dyn: [dyn!]! + dyn2: [dyn2!]! + if: [if!]! + if2: [if2!]! + mod: [mod!]! + mod2: [mod2!]! + self: [self!]! + self2: [self2!]! + type: [type!]! + type2: [type2!]! + unsafe: [unsafe!]! + unsafe2: [unsafe2!]! + where: [where!]! + where2: [where2!]! +} + +type const { + const: [const!]! +} + +type continue { + continue: [continue!]! +} + +type if { + if: [if!]! +} + +type mod { + mod: [mod!]! +} + +type self { + self: [self!]! +} + +type type { + type: [type!]! +} + +type unsafe { + unsafe: [unsafe!]! +} + +type where { + where: [where!]! +} + +type dyn { + dyn: [dyn!]! +} + +type const2 { + const: Int! +} + +type continue2 { + continue: Int! +} + +type if2 { + if: Int! +} + +type mod2 { + mod: Int! +} + +type self2 { + self: Int! +} + +type type2 { + type: Int! +} + +type unsafe2 { + unsafe: Int! +} + +type where2 { + where: Int! +} + +type dyn2 { + dyn: Int! +} diff --git a/trustfall_stubgen/test_data/expected_outputs/use_reserved_rust_names_in_schema/adapter/tests.rs b/trustfall_stubgen/test_data/expected_outputs/use_reserved_rust_names_in_schema/adapter/tests.rs new file mode 100644 index 00000000..f1b35ecb --- /dev/null +++ b/trustfall_stubgen/test_data/expected_outputs/use_reserved_rust_names_in_schema/adapter/tests.rs @@ -0,0 +1,10 @@ +use trustfall::provider::check_adapter_invariants; + +use super::Adapter; + +#[test] +fn adapter_satisfies_trustfall_invariants() { + let adapter = Adapter::new(); + let schema = Adapter::schema(); + check_adapter_invariants(schema, adapter); +} diff --git a/trustfall_stubgen/test_data/expected_outputs/use_reserved_rust_names_in_schema/adapter/vertex.rs b/trustfall_stubgen/test_data/expected_outputs/use_reserved_rust_names_in_schema/adapter/vertex.rs new file mode 100644 index 00000000..9ea395ac --- /dev/null +++ b/trustfall_stubgen/test_data/expected_outputs/use_reserved_rust_names_in_schema/adapter/vertex.rs @@ -0,0 +1,22 @@ +#[non_exhaustive] +#[derive(Debug, Clone, trustfall::provider::TrustfallEnumVertex)] +pub enum Vertex { + Const(()), + Const2(()), + Continue(()), + Continue2(()), + Dyn(()), + Dyn2(()), + If(()), + If2(()), + Mod(()), + Mod2(()), + Self_(()), + Self2(()), + Type(()), + Type2(()), + Unsafe(()), + Unsafe2(()), + Where(()), + Where2(()), +} diff --git a/trustfall_stubgen/test_data/use_reserved_rust_names_in_schema.graphql b/trustfall_stubgen/test_data/use_reserved_rust_names_in_schema.graphql new file mode 100644 index 00000000..ab4c5cb5 --- /dev/null +++ b/trustfall_stubgen/test_data/use_reserved_rust_names_in_schema.graphql @@ -0,0 +1,136 @@ +schema { + query: RootSchemaQuery +} +directive @filter( + """ + Name of the filter operation to perform. + """ + op: String! + """ + List of string operands for the operator. + """ + value: [String!] +) on FIELD | INLINE_FRAGMENT +directive @tag( + """ + Name to apply to the given property field. + """ + name: String +) on FIELD +directive @output( + """ + What to designate the output field generated from this property field. + """ + name: String +) on FIELD +directive @optional on FIELD +directive @recurse( + """ + Recurse up to this many times on this edge. A depth of 1 produces the current + vertex and its immediate neighbors along the given edge. + """ + depth: Int! +) on FIELD +directive @fold on FIELD +directive @transform( + """ + Name of the transformation operation to perform. + """ + op: String! +) on FIELD + +""" +All the possible data types where querying can begin in this API. +""" +type RootSchemaQuery { + const: [const!]! + const2: [const2!]! + continue: [continue!]! + continue2: [continue2!]! + dyn: [dyn!]! + dyn2: [dyn2!]! + if: [if!]! + if2: [if2!]! + mod: [mod!]! + mod2: [mod2!]! + self: [self!]! + self2: [self2!]! + type: [type!]! + type2: [type2!]! + unsafe: [unsafe!]! + unsafe2: [unsafe2!]! + where: [where!]! + where2: [where2!]! +} + +type const { + const: [const!]! +} + +type continue { + continue: [continue!]! +} + +type if { + if: [if!]! +} + +type mod { + mod: [mod!]! +} + +type self { + self: [self!]! +} + +type type { + type: [type!]! +} + +type unsafe { + unsafe: [unsafe!]! +} + +type where { + where: [where!]! +} + +type dyn { + dyn: [dyn!]! +} + +type const2 { + const: Int! +} + +type continue2 { + continue: Int! +} + +type if2 { + if: Int! +} + +type mod2 { + mod: Int! +} + +type self2 { + self: Int! +} + +type type2 { + type: Int! +} + +type unsafe2 { + unsafe: Int! +} + +type where2 { + where: Int! +} + +type dyn2 { + dyn: Int! +} diff --git a/trustfall_stubgen/test_data/use_type_and_typeunderscore_edge_names.graphql b/trustfall_stubgen/test_data/use_type_and_typeunderscore_edge_names.graphql new file mode 100644 index 00000000..4f028239 --- /dev/null +++ b/trustfall_stubgen/test_data/use_type_and_typeunderscore_edge_names.graphql @@ -0,0 +1,56 @@ +schema { + query: RootSchemaQuery +} +directive @filter( + """ + Name of the filter operation to perform. + """ + op: String! + """ + List of string operands for the operator. + """ + value: [String!] +) on FIELD | INLINE_FRAGMENT +directive @tag( + """ + Name to apply to the given property field. + """ + name: String +) on FIELD +directive @output( + """ + What to designate the output field generated from this property field. + """ + name: String +) on FIELD +directive @optional on FIELD +directive @recurse( + """ + Recurse up to this many times on this edge. A depth of 1 produces the current + vertex and its immediate neighbors along the given edge. + """ + depth: Int! +) on FIELD +directive @fold on FIELD +directive @transform( + """ + Name of the transformation operation to perform. + """ + op: String! +) on FIELD + +""" +Stubgen should panic if you have a type called {keyword} and another type called {keyword}_ since we rename {keyword}'s to {keyword}_ ourselves. +""" +type RootSchemaQuery { + a: [Type!]! + b: [Type_!]! +} + +type Type { + num: Int! +} + +type Type_ { + num2: Int! +} diff --git a/trustfall_stubgen/test_data/vertextype_with_type_and_typeunderscore_edge_and_property.graphql b/trustfall_stubgen/test_data/vertextype_with_type_and_typeunderscore_edge_and_property.graphql new file mode 100644 index 00000000..1a2d0606 --- /dev/null +++ b/trustfall_stubgen/test_data/vertextype_with_type_and_typeunderscore_edge_and_property.graphql @@ -0,0 +1,52 @@ +schema { + query: RootSchemaQuery +} +directive @filter( + """ + Name of the filter operation to perform. + """ + op: String! + """ + List of string operands for the operator. + """ + value: [String!] +) on FIELD | INLINE_FRAGMENT +directive @tag( + """ + Name to apply to the given property field. + """ + name: String +) on FIELD +directive @output( + """ + What to designate the output field generated from this property field. + """ + name: String +) on FIELD +directive @optional on FIELD +directive @recurse( + """ + Recurse up to this many times on this edge. A depth of 1 produces the current + vertex and its immediate neighbors along the given edge. + """ + depth: Int! +) on FIELD +directive @fold on FIELD +directive @transform( + """ + Name of the transformation operation to perform. + """ + op: String! +) on FIELD + +""" +Stubgen should panic if you have a type called {keyword} and another type called {keyword}_ since we rename {keyword}'s to {keyword}_ ourselves. +""" +type RootSchemaQuery { + a: [Type!]! +} + +type Type { + Type: Int! + Type_: [Type!]! +} diff --git a/trustfall_stubgen/test_data/vertextype_with_type_and_typeunderscore_edges.graphql b/trustfall_stubgen/test_data/vertextype_with_type_and_typeunderscore_edges.graphql new file mode 100644 index 00000000..65b003c1 --- /dev/null +++ b/trustfall_stubgen/test_data/vertextype_with_type_and_typeunderscore_edges.graphql @@ -0,0 +1,52 @@ +schema { + query: RootSchemaQuery +} +directive @filter( + """ + Name of the filter operation to perform. + """ + op: String! + """ + List of string operands for the operator. + """ + value: [String!] +) on FIELD | INLINE_FRAGMENT +directive @tag( + """ + Name to apply to the given property field. + """ + name: String +) on FIELD +directive @output( + """ + What to designate the output field generated from this property field. + """ + name: String +) on FIELD +directive @optional on FIELD +directive @recurse( + """ + Recurse up to this many times on this edge. A depth of 1 produces the current + vertex and its immediate neighbors along the given edge. + """ + depth: Int! +) on FIELD +directive @fold on FIELD +directive @transform( + """ + Name of the transformation operation to perform. + """ + op: String! +) on FIELD + +""" +Stubgen should panic if you have a type called {keyword} and another type called {keyword}_ since we rename {keyword}'s to {keyword}_ ourselves. +""" +type RootSchemaQuery { + a: [Type!]! +} + +type Type { + Type: [Type!]! + Type_: [Type!]! +} diff --git a/trustfall_stubgen/test_data/vertextype_with_type_and_typeunderscore_properties.graphql b/trustfall_stubgen/test_data/vertextype_with_type_and_typeunderscore_properties.graphql new file mode 100644 index 00000000..8d75bae0 --- /dev/null +++ b/trustfall_stubgen/test_data/vertextype_with_type_and_typeunderscore_properties.graphql @@ -0,0 +1,52 @@ +schema { + query: RootSchemaQuery +} +directive @filter( + """ + Name of the filter operation to perform. + """ + op: String! + """ + List of string operands for the operator. + """ + value: [String!] +) on FIELD | INLINE_FRAGMENT +directive @tag( + """ + Name to apply to the given property field. + """ + name: String +) on FIELD +directive @output( + """ + What to designate the output field generated from this property field. + """ + name: String +) on FIELD +directive @optional on FIELD +directive @recurse( + """ + Recurse up to this many times on this edge. A depth of 1 produces the current + vertex and its immediate neighbors along the given edge. + """ + depth: Int! +) on FIELD +directive @fold on FIELD +directive @transform( + """ + Name of the transformation operation to perform. + """ + op: String! +) on FIELD + +""" +Stubgen should panic if you have a type called {keyword} and another type called {keyword}_ since we rename {keyword}'s to {keyword}_ ourselves. +""" +type RootSchemaQuery { + a: [Type!]! +} + +type Type { + Type: Int! + Type_: Int! +}