Skip to content

[draft] graphql-parser: 0.2 -> 0.3 #395

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion graphql_client_codegen/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ edition = "2018"

[dependencies]
graphql-introspection-query = { version = "0.2.0", path = "../graphql-introspection-query" }
graphql-parser = "^0.2"
graphql-parser = "0.3"
heck = "0.3"
lazy_static = "1.3"
proc-macro2 = { version = "^1.0", features = [] }
Expand Down
94 changes: 61 additions & 33 deletions graphql_client_codegen/src/codegen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,20 @@ use selection::*;
use std::collections::BTreeMap;

/// The main code generation function.
pub(crate) fn response_for_query(
pub(crate) fn response_for_query<'a, 'b: 'a, 'schema: 'a, T>(
operation_id: OperationId,
options: &GraphQLClientCodegenOptions,
query: BoundQuery<'_>,
) -> Result<TokenStream, GeneralError> {
options: &'b GraphQLClientCodegenOptions,
query: BoundQuery<'a, 'a, 'schema, T>,
) -> Result<TokenStream, GeneralError>
where
T: graphql_parser::query::Text<'a> + std::default::Default,
{
let all_used_types = all_used_types(operation_id, &query);
let response_derives = render_derives(options.all_response_derives());
let variable_derives = render_derives(options.all_variable_derives());

let scalar_definitions = generate_scalar_definitions(&all_used_types, options, query);
let enum_definitions = enums::generate_enum_definitions(&all_used_types, options, query);
let scalar_definitions = generate_scalar_definitions(&all_used_types, options, &query);
let enum_definitions = enums::generate_enum_definitions(&all_used_types, options, &query);
let fragment_definitions =
generate_fragment_definitions(&all_used_types, &response_derives, options, &query);
let input_object_definitions = inputs::generate_input_object_definitions(
Expand Down Expand Up @@ -71,12 +74,15 @@ pub(crate) fn response_for_query(
Ok(q)
}

fn generate_variables_struct(
fn generate_variables_struct<'a, 'schema, T>(
operation_id: OperationId,
variable_derives: &impl quote::ToTokens,
options: &GraphQLClientCodegenOptions,
query: &BoundQuery<'_>,
) -> TokenStream {
query: &BoundQuery<'a, 'a, 'schema, T>,
) -> TokenStream
where
T: graphql_parser::query::Text<'a> + std::default::Default,
{
if operation_has_no_variables(operation_id, query.query) {
return quote!(
#variable_derives
Expand Down Expand Up @@ -127,11 +133,14 @@ fn generate_variables_struct(
variables_struct
}

fn generate_variable_struct_field(
variable: &ResolvedVariable,
fn generate_variable_struct_field<'a, 'schema, T>(
variable: &ResolvedVariable<'a, T>,
options: &GraphQLClientCodegenOptions,
query: &BoundQuery<'_>,
) -> TokenStream {
query: &BoundQuery<'a, '_, 'schema, T>,
) -> TokenStream
where
T: graphql_parser::query::Text<'a> + std::default::Default,
{
let snake_case_name = variable.name.to_snake_case();
let safe_name = shared::keyword_replace(&snake_case_name);
let ident = Ident::new(&safe_name, Span::call_site());
Expand All @@ -141,11 +150,14 @@ fn generate_variable_struct_field(
quote::quote!(#annotation pub #ident : #r#type)
}

fn generate_scalar_definitions<'a, 'schema: 'a>(
fn generate_scalar_definitions<'a: 'c, 'b: 'a, 'c, 'schema: 'a, T>(
all_used_types: &'a crate::query::UsedTypes,
options: &'a GraphQLClientCodegenOptions,
query: BoundQuery<'schema>,
) -> impl Iterator<Item = TokenStream> + 'a {
options: &'b GraphQLClientCodegenOptions,
query: &'c BoundQuery<'a, '_, 'schema, T>,
) -> impl Iterator<Item = TokenStream> + 'a
where
T: graphql_parser::query::Text<'a> + std::default::Default,
{
all_used_types
.scalars(query.schema)
.map(move |(_id, scalar)| {
Expand All @@ -172,11 +184,14 @@ fn render_derives<'a>(derives: impl Iterator<Item = &'a str>) -> impl quote::ToT
quote!(#[derive(#(#idents),*)])
}

fn render_variable_field_type(
variable: &ResolvedVariable,
fn render_variable_field_type<'a, 'schema, T>(
variable: &ResolvedVariable<'a, T>,
options: &GraphQLClientCodegenOptions,
query: &BoundQuery<'_>,
) -> TokenStream {
query: &BoundQuery<'a, '_, 'schema, T>,
) -> TokenStream
where
T: graphql_parser::query::Text<'a> + std::default::Default,
{
let normalized_name = options
.normalization()
.input_name(variable.type_name(query.schema));
Expand Down Expand Up @@ -224,24 +239,30 @@ fn decorate_type(ident: &Ident, qualifiers: &[GraphqlTypeQualifier]) -> TokenStr
qualified
}

fn generate_fragment_definitions<'a>(
fn generate_fragment_definitions<'a, 'schema, T>(
all_used_types: &'a UsedTypes,
response_derives: &'a impl quote::ToTokens,
options: &'a GraphQLClientCodegenOptions,
query: &'a BoundQuery<'a>,
) -> impl Iterator<Item = TokenStream> + 'a {
query: &'a BoundQuery<'a, '_, 'schema, T>,
) -> impl Iterator<Item = TokenStream> + 'a
where
T: graphql_parser::query::Text<'a> + std::default::Default,
{
all_used_types.fragment_ids().map(move |fragment_id| {
selection::render_fragment(fragment_id, options, query).render(&response_derives)
})
}

/// For default value constructors.
fn graphql_parser_value_to_literal(
value: &graphql_parser::query::Value,
fn graphql_parser_value_to_literal<'a, 'schema, T>(
value: &graphql_parser::query::Value<'a, T>,
ty: TypeId,
is_optional: bool,
query: &BoundQuery<'_>,
) -> TokenStream {
query: &BoundQuery<'a, '_, 'schema, T>,
) -> TokenStream
where
T: graphql_parser::query::Text<'a> + std::default::Default,
{
use graphql_parser::query::Value;

let inner = match value {
Expand All @@ -260,7 +281,10 @@ fn graphql_parser_value_to_literal(
let i = i.as_i64();
quote!(#i)
}
Value::Enum(en) => quote!(#en),
Value::Enum(en) => {
let en_string = en.as_ref().to_string();
quote!(#en_string)
}
Value::List(inner) => {
let elements = inner
.iter()
Expand Down Expand Up @@ -289,11 +313,15 @@ fn graphql_parser_value_to_literal(
}

/// For default value constructors.
fn render_object_literal(
object_map: &BTreeMap<String, graphql_parser::query::Value>,
// TODO object_map keys should be T::Value
fn render_object_literal<'a, 'schema, T>(
object_map: &BTreeMap<T::Value, graphql_parser::query::Value<'a, T>>,
input_id: InputId,
query: &BoundQuery<'_>,
) -> TokenStream {
query: &BoundQuery<'a, '_, 'schema, T>,
) -> TokenStream
where
T: graphql_parser::query::Text<'a> + std::default::Default,
{
let input = query.schema.get_input(input_id);
let constructor = Ident::new(&input.name, Span::call_site());
let fields: Vec<TokenStream> = input
Expand Down
11 changes: 7 additions & 4 deletions graphql_client_codegen/src/codegen/enums.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,14 @@ use quote::quote;
* Generated "variant_names" enum: pub enum AnEnum { where_, self_, Other(String), }
* Generated serialize line: "AnEnum::where_ => "where","
*/
pub(super) fn generate_enum_definitions<'a, 'schema: 'a>(
pub(super) fn generate_enum_definitions<'a, 'b: 'a, 'c, 'schema: 'a, T>(
all_used_types: &'a crate::query::UsedTypes,
options: &'a GraphQLClientCodegenOptions,
query: BoundQuery<'schema>,
) -> impl Iterator<Item = TokenStream> + 'a {
options: &'b GraphQLClientCodegenOptions,
query: &'c BoundQuery<'a, '_, 'schema, T>,
) -> impl Iterator<Item = TokenStream> + 'a
where
T: graphql_parser::query::Text<'a> + std::default::Default,
{
let derives = render_derives(
options
.all_response_derives()
Expand Down
9 changes: 6 additions & 3 deletions graphql_client_codegen/src/codegen/inputs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,15 @@ use heck::SnakeCase;
use proc_macro2::{Ident, Span, TokenStream};
use quote::quote;

pub(super) fn generate_input_object_definitions(
pub(super) fn generate_input_object_definitions<'a, 'schema, T>(
all_used_types: &UsedTypes,
options: &GraphQLClientCodegenOptions,
variable_derives: &impl quote::ToTokens,
query: &BoundQuery<'_>,
) -> Vec<TokenStream> {
query: &BoundQuery<'a, '_, 'schema, T>,
) -> Vec<TokenStream>
where
T: graphql_parser::query::Text<'a> + std::default::Default,
{
all_used_types
.inputs(query.schema)
.map(|(_input_id, input)| {
Expand Down
47 changes: 32 additions & 15 deletions graphql_client_codegen/src/codegen/selection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,14 @@ use proc_macro2::{Ident, Span, TokenStream};
use quote::quote;
use std::borrow::Cow;

pub(crate) fn render_response_data_fields<'a>(
pub(crate) fn render_response_data_fields<'a, 'b: 'a, 'query, 'schema, T>(
operation_id: OperationId,
options: &'a GraphQLClientCodegenOptions,
query: &'a BoundQuery<'a>,
) -> ExpandedSelection<'a> {
query: &'b BoundQuery<'a, 'query, 'schema, T>,
) -> ExpandedSelection<'a, 'query, 'schema, T>
where
T: graphql_parser::query::Text<'a> + std::default::Default,
{
let operation = query.query.get_operation(operation_id);
let mut expanded_selection = ExpandedSelection {
query,
Expand All @@ -49,11 +52,14 @@ pub(crate) fn render_response_data_fields<'a>(
expanded_selection
}

pub(super) fn render_fragment<'a>(
pub(super) fn render_fragment<'a, 'query, 'schema, T>(
fragment_id: ResolvedFragmentId,
options: &'a GraphQLClientCodegenOptions,
query: &'a BoundQuery<'a>,
) -> ExpandedSelection<'a> {
query: &'a BoundQuery<'a, 'query, 'schema, T>,
) -> ExpandedSelection<'a, 'query, 'schema, T>
where
T: graphql_parser::query::Text<'a> + std::default::Default,
{
let fragment = query.query.get_fragment(fragment_id);
let mut expanded_selection = ExpandedSelection {
query,
Expand Down Expand Up @@ -87,11 +93,14 @@ enum VariantSelection<'a> {

impl<'a> VariantSelection<'a> {
/// The second argument is the parent type id, so it can be excluded.
fn from_selection(
fn from_selection<T>(
selection: &'a Selection,
type_id: TypeId,
query: &BoundQuery<'a>,
) -> Option<VariantSelection<'a>> {
query: &BoundQuery<'a, 'a, '_, T>,
) -> Option<VariantSelection<'a>>
where
T: graphql_parser::query::Text<'a> + std::default::Default,
{
match selection {
Selection::InlineFragment(inline_fragment) => {
Some(VariantSelection::InlineFragment(inline_fragment))
Expand Down Expand Up @@ -119,13 +128,15 @@ impl<'a> VariantSelection<'a> {
}
}

fn calculate_selection<'a>(
context: &mut ExpandedSelection<'a>,
fn calculate_selection<'a, 'schema, T>(
context: &mut ExpandedSelection<'a, '_, 'schema, T>,
selection_set: &[SelectionId],
struct_id: ResponseTypeId,
type_id: TypeId,
options: &'a GraphQLClientCodegenOptions,
) {
) where
T: graphql_parser::query::Text<'a> + std::default::Default,
{
// If the selection only contains a fragment, replace the selection with
// that fragment.
if selection_set.len() == 1 {
Expand Down Expand Up @@ -467,16 +478,22 @@ pub(crate) struct ExpandedType<'a> {
name: Cow<'a, str>,
}

pub(crate) struct ExpandedSelection<'a> {
query: &'a BoundQuery<'a>,
pub(crate) struct ExpandedSelection<'a, 'query, 'schema, T>
where
T: graphql_parser::query::Text<'a> + std::default::Default,
{
query: &'a BoundQuery<'a, 'query, 'schema, T>,
types: Vec<ExpandedType<'a>>,
fields: Vec<ExpandedField<'a>>,
variants: Vec<ExpandedVariant<'a>>,
aliases: Vec<TypeAlias<'a>>,
options: &'a GraphQLClientCodegenOptions,
}

impl<'a> ExpandedSelection<'a> {
impl<'a, 'query, 'schema, T> ExpandedSelection<'a, 'query, 'schema, T>
where
T: graphql_parser::query::Text<'a> + std::default::Default,
{
pub(crate) fn schema(&self) -> &'a Schema {
self.query.schema
}
Expand Down
12 changes: 9 additions & 3 deletions graphql_client_codegen/src/generated_module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,21 @@ impl Display for OperationNotFound {
impl Error for OperationNotFound {}

/// This struct contains the parameters necessary to generate code for a given operation.
pub(crate) struct GeneratedModule<'a> {
pub(crate) struct GeneratedModule<'a, T>
where
T: graphql_parser::query::Text<'a> + std::default::Default,
{
pub operation: &'a str,
pub query_string: &'a str,
pub resolved_query: &'a crate::query::Query,
pub resolved_query: &'a crate::query::Query<'a, T>,
pub schema: &'a crate::schema::Schema,
pub options: &'a crate::GraphQLClientCodegenOptions,
}

impl<'a> GeneratedModule<'a> {
impl<'a, T> GeneratedModule<'a, T>
where
T: graphql_parser::query::Text<'a> + std::default::Default,
{
/// Generate the items for the variables and the response that will go inside the module.
fn build_impls(&self) -> Result<TokenStream, BoxError> {
Ok(crate::codegen::response_for_query(
Expand Down
13 changes: 8 additions & 5 deletions graphql_client_codegen/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ type CacheMap<T> = std::sync::Mutex<HashMap<std::path::PathBuf, T>>;

lazy_static! {
static ref SCHEMA_CACHE: CacheMap<schema::Schema> = CacheMap::default();
static ref QUERY_CACHE: CacheMap<(String, graphql_parser::query::Document)> =
static ref QUERY_CACHE: CacheMap<(String, graphql_parser::query::Document<'static, String>)> =
CacheMap::default();
}

Expand All @@ -73,7 +73,7 @@ pub fn generate_module_token_stream(
let schema_string = read_file(v.key())?;
let schema = match schema_extension {
"graphql" | "gql" => {
let s = graphql_parser::schema::parse_schema(&schema_string).map_err(|parser_error| GeneralError(format!("Parser error: {}", parser_error)))?;
let s: graphql_parser::schema::Document<'_, String> = graphql_parser::schema::parse_schema(&schema_string).map_err(|parser_error| GeneralError(format!("Parser error: {}", parser_error)))?;
schema::Schema::from(s)
}
"json" => {
Expand Down Expand Up @@ -192,10 +192,13 @@ fn read_file(path: &std::path::Path) -> Result<String, ReadFileError> {
}

/// In derive mode, build an error when the operation with the same name as the struct is not found.
fn derive_operation_not_found_error(
fn derive_operation_not_found_error<'a, T>(
ident: Option<&proc_macro2::Ident>,
query: &crate::query::Query,
) -> String {
query: &'a crate::query::Query<'a, T>,
) -> String
where
T: graphql_parser::query::Text<'a> + std::default::Default,
{
let operation_name = ident.map(ToString::to_string);
let struct_ident = operation_name.as_deref().unwrap_or("");

Expand Down
Loading