use super::DerivedField;
use crate::parse::{Conversion, deps::*};
use heck::ToLowerCamelCase;
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
use std::cell::RefCell;
use syn::Type;
pub static COMPARISON_OPERATOR_SUFFIXES: &[&str] = &[
"eq",
"not",
"gt",
"lt",
"gte",
"lte",
"in",
"not_in",
"contains",
"contains_nocase",
"not_contains",
"not_contains_nocase",
"starts_with",
"starts_with_nocase",
"not_starts_with",
"not_starts_with_nocase",
"ends_with",
"ends_with_nocase",
"not_ends_with",
"not_ends_with_nocase",
];
impl crate::codegen::CodegenWrapper<super::TransformerStruct> {
pub(crate) fn impl_graphql(&self) -> syn::Result<TokenStream> {
let self_name = self.struct_name();
if self.id_field().graphql_config.hidden {
return Err(syn::Error::new_spanned(
&self.id_field().field,
"id field cannot be hidden in the GraphQL interface",
));
}
let graphql_output_ty_name = self.graphql_output_name();
let graphql_input_ty_name = self.graphql_input_name();
let graphql_name_str = graphql_output_ty_name.to_string();
let graphql_comparison_name = format_ident!("{}Comparison", self_name);
let graphql_filter_name = format_ident!("{}Filter", self_name);
let graphql_order_by_name = format_ident!("{}OrderBy", self_name);
let output_name = self.struct_opts.graphql_opts.gql_name.to_string();
let derived_field_impls = self.impl_derived_fields();
let impls = self.impl_static_fields()?;
let loader_configs = self.generate_loader_config();
let comparison_impl = self.generate_comparison()?;
let filter_impl = self.generate_filter()?;
let selected_fields_impl = self.generate_selected_fields();
let query_builder_getters = self.generate_nested_query_builder_getters()?;
let block_ty = quote!(<<<Self::Transformer as ::cido::__internal::Transformer>::Cidomap as ::cido::__internal::Cidomap>::Network as ::cido::__internal::Network>::BlockNumber);
let block_funcs = if self.is_entity() {
quote! {
fn __set_block_number(
&mut self,
range: <#block_ty as ::cido::__internal::BlockNumber>::Range,
) {
self.__block_number_range = range;
}
fn __get_start_block(&self) -> #block_ty {
use ::cido::__internal::BlockNumberRange;
self.__block_number_range.bounds().0
}
}
} else {
quote! {
fn __set_block_number(
&mut self,
range: <#block_ty as ::cido::__internal::BlockNumber>::Range,
) {
use ::cido::__internal::BlockNumberRange;
self.__block_number = range.bounds().0;
}
fn __get_start_block(&self) -> #block_ty {
self.__block_number
}
}
};
let query_context = quote! {
fn __get_query_context(&self) -> ::cido::__internal::GraphqlQueryBuilder<#self_name> {
::core::default::Default::default()
}
};
let max_return_items = self.struct_opts.graphql_opts.max_return_items;
let max_skip_items = self.struct_opts.graphql_opts.max_skip_items;
let id_field = self.id_field();
let id_field_name = id_field.graphql_output_name();
let id_field_name_str = id_field.graphql_sdl_output_name();
let id_field_ty = id_field.graphql_output_type();
Ok(quote! {
#[allow(non_snake_case)]
#[::cido::__internal::async_graphql::Object(name = #output_name)]
impl #graphql_output_ty_name {
#(#derived_field_impls)*
#(#impls)*
}
impl #graphql_output_ty_name {
#( #query_builder_getters )*
}
impl ::cido::__internal::GraphqlInputType for #graphql_input_ty_name {
type Filter = #graphql_filter_name;
type Where = #graphql_comparison_name;
type OrderByVariant = #graphql_order_by_name;
type Transformer = #self_name;
}
impl ::cido::__internal::GraphqlOutputType for #graphql_output_ty_name {
type Transformer = #self_name;
type Id = #id_field_ty;
const MAX_RETURNED_ITEMS: u64 = #max_return_items;
const MAX_SKIP_ITEMS: u64 = #max_skip_items;
fn graphql_type_name() -> ::std::borrow::Cow<'static, str> {
::std::borrow::Cow::Borrowed(#graphql_name_str)
}
#selected_fields_impl
fn set_id(&mut self, id: Self::Id) {
self.#id_field_name = id;
}
fn get_id(&self) -> &Self::Id {
&self.#id_field_name
}
fn only_select_id(ctx: &::cido::__internal::async_graphql::Context<'_>) -> bool {
let number_of_select_fields = ctx.field()
.selection_set()
.take(2)
.count();
number_of_select_fields == 1 && ctx.look_ahead().field(#id_field_name_str).exists()
}
#query_context
#block_funcs
fn __get_query_block(&self) -> <<<Self::Transformer as Transformer>::Cidomap as ::cido::__internal::Cidomap>::Network as ::cido::__internal::Network>::BlockNumber {
self.__query_block
}
fn __set_query_block(&mut self, block: <<<Self::Transformer as Transformer>::Cidomap as ::cido::__internal::Cidomap>::Network as ::cido::__internal::Network>::BlockNumber) {
self.__query_block = block;
}
}
impl ::cido::__internal::ToDbFilter for #self_name {
type Filter = #graphql_comparison_name;
fn to_db_filter(self) -> Self::Filter {
<#graphql_comparison_name as ::core::default::Default>::default()
}
}
impl ::cido::__internal::ToGraphqlFilter for #self_name {
type Filter = #graphql_filter_name;
fn to_graphql_filter(self) -> Self::Filter {
<#graphql_filter_name as ::core::default::Default>::default()
}
}
#comparison_impl
#filter_impl
#loader_configs
})
}
fn generate_loader_config(&self) -> TokenStream {
let cache_size = self.struct_opts.graphql_opts.loader_cache_size;
let max_batch = self.struct_opts.graphql_opts.loader_max_batch_size;
let delay = self.struct_opts.graphql_opts.loader_delay_ms;
let name = self.struct_name();
quote! {
impl ::cido::__internal::LoaderConfig for #name {
const CACHE_SIZE: usize = #cache_size;
const MAX_BATCH_SIZE: usize = #max_batch;
const DELAY: ::core::time::Duration = ::core::time::Duration::from_millis(#delay);
}
}
}
fn generate_selected_fields(&self) -> TokenStream {
let selected_fields = self
.fields
.iter()
.enumerate()
.filter_map(|(idx, f)| {
if !f.graphql_config.hidden && !f.id {
let name = f.graphql_sdl_output_name();
let idx = idx + 1;
Some(quote! {
if ctx.look_ahead().field(#name).exists() {
vec.push(&descriptor.fields[#idx]);
}
})
} else {
None
}
})
.collect::<Vec<_>>();
quote! {
fn selected_fields<'ctx>(ctx: &::cido::__internal::async_graphql::Context<'ctx>) -> ::std::vec::Vec<&'static ::cido::__internal::ColDescription> {
let descriptor = <Self::Transformer as ::cido::__internal::Transformer>::table_descriptor();
let mut vec = ::std::vec::Vec::new();
vec.push(descriptor.id_field);
::cido::__internal::tracing::trace!(fields = ?ctx.look_ahead().selection_fields());
#(#selected_fields)*
vec
}
}
}
fn impl_derived_fields(&self) -> Vec<TokenStream> {
let mut derived_graphql_fns: Vec<TokenStream> = vec![];
for df in &self.derived {
let derived_graphql_fn = self.impl_derive_field(df);
derived_graphql_fns.push(derived_graphql_fn);
}
derived_graphql_fns
}
fn impl_derive_field(&self, df: &DerivedField) -> TokenStream {
let self_name = self.struct_name();
let field_name = &df.name;
let lookup_typ = &df.ty;
let lookup_transformer_ty =
quote! {<#lookup_typ as ::cido::__internal::ToTransformer>::Transformer};
let lookup_field = df.field_lookup.to_string();
let id_field = &self.id_field().name;
let graphql_input_ty = quote! { <<#lookup_transformer_ty as ::cido::__internal::Transformer>::GraphqlInput as ::cido::__internal::GraphqlInputType> };
let order_by_struct_ty =
quote! { ::cido::__internal::GraphqlOrderBy<#graphql_input_ty::OrderByVariant> };
let filter_struct_ty = quote! { #graphql_input_ty::Filter };
let mut aliases = Vec::new();
let complexity = df
.complexity
.as_ref()
.map(|expr| quote! { #[graphql(complexity = #expr)]})
.unwrap_or_default();
for alias in &df.alias {
aliases.push(quote! {
#[allow(clippy::too_many_arguments)]
#complexity
pub async fn #alias<'ctx>(
&self,
ctx: &::cido::__internal::async_graphql::Context<'ctx>,
order_by: ::std::option::Option<#order_by_struct_ty>,
order_direction: ::std::option::Option<::cido::__internal::GraphqlOrderDirection>,
first: ::std::option::Option<u64>,
skip: ::std::option::Option<u64>,
#[graphql(name="where")]
filter: ::std::option::Option<#filter_struct_ty>,
) -> ::cido::__internal::async_graphql::Result<<#lookup_typ as ::cido::__internal::ToGraphql>::Graphql> {
self.#field_name(ctx, order_by, order_direction, first, skip, filter).await
}
});
}
#[allow(clippy::collapsible_else_if)]
let call_fn = if self.is_entity() {
if df.multiple {
quote! {
<::std::vec::Vec<#self_name> as ::cido::__internal::DerivedMap<_, #lookup_typ>>::derived_entity_map(
ctx,
&self.#id_field,
self.__query_block(),
None,
builder,
field_description,
).await
}
} else {
quote! {
<#self_name as ::cido::__internal::DerivedMap<_, #lookup_typ>>::derived_entity_map(
ctx,
&self.#id_field,
self.__query_block(),
None,
builder,
field_description,
).await
}
}
} else {
if df.multiple {
quote! {
<::std::vec::Vec<#self_name> as ::cido::__internal::DerivedMap<_, #lookup_typ>>::derived_event_map(
ctx,
&self.#id_field,
self.__query_block(),
builder,
field_description,
).await
}
} else {
quote! {
<#self_name as ::cido::__internal::DerivedMap<_, #lookup_typ>>::derived_event_map(
ctx,
&self.#id_field,
self.__query_block(),
builder,
field_description,
).await
}
}
};
quote! {
#(#aliases)*
#[allow(clippy::too_many_arguments)]
#complexity
pub async fn #field_name<'ctx>(
&self,
ctx: &::cido::__internal::async_graphql::Context<'ctx>,
#[graphql(default_with = "::core::option::Option::Some(0)")]
skip: ::std::option::Option<u64>,
#[graphql(default_with = "::core::option::Option::Some(100)")]
first: ::std::option::Option<u64>,
order_by: ::std::option::Option<#order_by_struct_ty>,
order_direction: ::std::option::Option<::cido::__internal::GraphqlOrderDirection>,
#[graphql(name="where")]
filter: ::std::option::Option<#filter_struct_ty>,
) -> ::cido::__internal::async_graphql::Result<<#lookup_typ as ::cido::__internal::ToGraphql>::Graphql> {
let filter = match filter {
::core::option::Option::None => ::core::option::Option::None,
::core::option::Option::Some(filter) => ::core::option::Option::Some(::cido::__internal::TryMapFilter::try_map(filter)?),
};
let network = ctx.data::<::std::sync::Arc<<<#lookup_transformer_ty as ::cido::__internal::Transformer>::Cidomap as ::cido::__internal::Cidomap>::Network>>()?;
let builder = ::cido::__internal::GraphqlQueryBuilder::<#lookup_transformer_ty>::new(
filter.map(::std::sync::Arc::new),
::std::option::Option::None,
order_by.map(::std::sync::Arc::new),
order_direction.map(::std::sync::Arc::new).unwrap_or_default(),
::cido::__internal::GraphqlPagination::new(first, skip)?,
);
let descriptor = <#lookup_transformer_ty as ::cido::__internal::Transformer>::table_descriptor();
let field_description = descriptor
.fields
.iter()
.find(|f| f.name == #lookup_field)
.ok_or_else(|| {
::cido::__internal::async_graphql::Error::new(::std::format!(
"Invalid field: {} on type {}",
#lookup_field,
::std::any::type_name::<#lookup_transformer_ty>()
))
})?;
#call_fn
}
}
}
fn impl_static_fields(&self) -> syn::Result<Vec<TokenStream>> {
let mut graphql_impls = vec![];
for f in &self.fields {
if !f.graphql_config.hidden {
let mut graphql_ts = TokenStream::new();
let complexity = f
.graphql_config
.complexity
.as_ref()
.map(|expr| quote! { #[graphql(complexity = #expr)] })
.unwrap_or_default();
if let Some(ee) = f.entity_or_event {
let entity_graphql_fn = Self::create_relational_query(
f.graphql_output_name(),
f.alias.iter(),
&f.field.ty,
complexity,
ee.is_entity(),
f.sql_config.nullable,
)?;
graphql_ts.extend(entity_graphql_fn);
graphql_impls.push(graphql_ts);
} else {
let field_name = &f.name;
let output_field_name = f.graphql_sdl_output_name();
let (output_type, output) = match (
f.graphql_config.output_type.as_ref(),
&f.graphql_config.field_to_output,
) {
(Some(output_type), Conversion::From(e)) => (
quote! { #output_type },
quote! { let #field_name = &self.#field_name; #e },
),
(None, Conversion::Identity) => (
{
let ty = f.graphql_sdl_output_type();
quote! { &#ty }
},
quote! { &self.#field_name },
),
(None, Conversion::From(e)) => (
{
let ty = f.graphql_sdl_output_type();
quote! { #ty }
},
quote! { let #field_name = &self.#field_name; #e },
),
(Some(ty), Conversion::Identity) => (
quote! { ::cido::__internal::async_graphql::Result<#ty> },
quote! { self.#field_name.parse::<#ty>().map_err(|e| ::cido::__internal::async_graphql::Error::custom(e)) },
),
};
f.alias.iter().for_each(|alias| {
let graphql_name = alias.to_string();
graphql_ts.extend(quote! {
#complexity
#[graphql(name = #graphql_name)]
pub async fn #alias(&self) -> #output_type {
#output
}
});
});
let graphql_fn = quote! {
#complexity
#[graphql(name = #output_field_name)]
pub async fn #field_name(&self) -> #output_type {
#output
}
};
graphql_ts.extend(graphql_fn);
graphql_impls.push(graphql_ts);
}
}
}
let self_name = self.struct_name();
let block_ty = quote!(<<<#self_name as ::cido::__internal::Transformer>::Cidomap as ::cido::__internal::Cidomap>::Network as ::cido::__internal::Network>::BlockNumber);
if self.is_entity() {
let start_block = quote! {
#[graphql(name = "__startBlockNumber")]
pub async fn __start_block_number(&self) -> #block_ty {
use ::cido::__internal::BlockNumberRange;
self.__block_number_range.bounds().0
}
};
graphql_impls.push(start_block);
let end_block = quote! {
#[graphql(name = "__endBlockNumber")]
pub async fn __end_block_number(&self) -> ::core::option::Option<#block_ty> {
use ::cido::__internal::BlockNumberRange;
self.__block_number_range.bounds().1
}
};
graphql_impls.push(end_block);
} else {
let block_nr = quote! {
#[graphql(name = "__blockNumber")]
pub async fn __block_number(&self) -> &#block_ty {
&self.__block_number
}
};
graphql_impls.push(block_nr);
}
Ok(graphql_impls)
}
fn create_relational_query<'a>(
name: &syn::Ident,
aliases: impl Iterator<Item = &'a syn::Ident>,
ty: &Type,
complexity: TokenStream,
is_entity: bool,
is_optional: bool,
) -> syn::Result<TokenStream> {
let _transformer_ty = quote! { <#ty as ::cido::__internal::ToTransformer>::Transformer };
let aliases_fn = aliases.map(|alias| {
let alias_str = alias.to_string();
quote! {
#complexity
#[graphql(name = #alias_str)]
pub async fn #alias<'ctx>(
&self,
ctx: &::cido::__internal::async_graphql::Context<'ctx>,
) -> ::cido::__internal::async_graphql::Result<<#ty as ::cido::__internal::ToGraphql>::Graphql> {
self.#name(ctx).await
}
}
}).collect::<Vec<_>>();
let get_results = if is_entity {
quote! {
<#ty as ::cido::__internal::TypeMap<_>>::map_entity_type(
ctx,
self.__query_block(),
None,
&self.#name,
qb
).await
}
} else {
quote! {
<#ty as ::cido::__internal::TypeMap<_>>::map_event_type(
ctx,
self.__query_block(),
&self.#name,
qb
).await
}
};
let graphql_name = name.to_string();
let _only_id = if is_optional {
quote! {
match &self.#name {
::core::option::Option::Some(val) => {
return ::std::result::Result::Ok(<<#ty as ::cido::__internal::ToGraphql>::Graphql as ::cido::__internal::FromId<_>>::from(::core::clone::Clone::clone(val)));
},
::core::option::Option::None => {
return ::std::result::Result::Ok(::core::option::Option::None);
}
}
}
} else {
quote! {
return ::std::result::Result::Ok(<<#ty as ::cido::__internal::ToGraphql>::Graphql as ::cido::__internal::FromId<_>>::from(::core::clone::Clone::clone(&self.#name)));
}
};
let query_builder_getter_name = format_ident!("__{}", name);
Ok(quote! {
#(#aliases_fn)*
#complexity
#[graphql(name = #graphql_name)]
pub async fn #name<'ctx>(
&self,
ctx: &::cido::__internal::async_graphql::Context<'ctx>,
) -> ::cido::__internal::async_graphql::Result<<#ty as ::cido::__internal::ToGraphql>::Graphql> {
let qb = self.#query_builder_getter_name();
let descriptor = <<#ty as ::cido::__internal::ToTransformer>::Transformer as ::cido::__internal::Transformer>::table_descriptor();
#get_results
}
})
}
fn generate_filter(&self) -> syn::Result<TokenStream> {
let self_name = self.struct_name();
let filter_ident = format_ident!("{}Filter", self_name);
let filter_ident_name = filter_ident.to_string();
let fields_definitions = RefCell::new(vec![]);
let filter_field_to_value = RefCell::new(vec![]);
let parse_filter_field = RefCell::new(vec![]);
let input_fields = RefCell::new(vec![]);
let is_empty = RefCell::new(vec![]);
for f in &self.fields {
if !f.graphql_config.hidden {
let field_name = f.graphql_output_name();
let field_name_str = field_name.to_string();
let field_name_with_underscore = format_ident!("{}_", field_name);
let field_name_str_with_underscore = format!("{}_", field_name_str);
let field_name_camel_case = f.graphql_comparison_sdl_name_string();
let field_name_camel_case_with_underscore = format!("{}_", field_name_camel_case);
let is_nested_ty = f.entity_or_event.is_some();
let handle_normal_alias =
|comparison_ty: &TokenStream, comparison_field_ty: &TokenStream| {
let mut fields_definitions = fields_definitions.borrow_mut();
let mut filter_field_to_value = filter_field_to_value.borrow_mut();
let mut parse_filter_field = parse_filter_field.borrow_mut();
let mut input_fields = input_fields.borrow_mut();
let mut is_empty = is_empty.borrow_mut();
f.alias.iter().for_each(|alias| {
let alias_str = alias.to_string();
let alias_name_camel_case = alias_str.to_lower_camel_case();
fields_definitions.push(quote! {pub #alias: #comparison_field_ty, });
filter_field_to_value.push(quote! {
if let ::std::option::Option::Some(val) = self.#alias.as_ref() {
<#comparison_ty as ::cido::__internal::Filter>::to_value(val, #alias_name_camel_case, &mut map);
}
});
parse_filter_field.push(quote! {
this.#alias = <#comparison_ty as ::cido::__internal::Filter>::parse::<::std::option::Option<Self>>(#alias_name_camel_case, &obj).map_err(::cido::__internal::async_graphql::InputValueError::propagate)?;
});
COMPARISON_OPERATOR_SUFFIXES.iter().for_each(|suf| {
let name = if (*suf) != "eq" { format!("{}_{}", alias_name_camel_case, suf) } else {
alias_name_camel_case.clone()
};
input_fields.push(quote! {
if let ::std::option::Option::Some(val) = <#comparison_ty as ::cido::__internal::Filter>::match_operator(#name, #suf, registry) {
map.insert(::std::borrow::ToOwned::to_owned(#name), val);
};
});
});
is_empty.push(quote! {
if let ::std::option::Option::Some(val) = &self.#alias {
if !<#comparison_ty as ::cido::__internal::Filter>::is_empty(val) {
return false;
}
}
});
});
};
let handle_nest_alias = |comparison_ty: &TokenStream, comparison_field_ty: &TokenStream| {
let mut fields_definitions = fields_definitions.borrow_mut();
let mut filter_field_to_value = filter_field_to_value.borrow_mut();
let mut parse_filter_field = parse_filter_field.borrow_mut();
let mut input_fields = input_fields.borrow_mut();
let mut is_empty = is_empty.borrow_mut();
f.alias.iter().for_each(|alias| {
let alias = format_ident!("{}_", alias);
let alias_str = alias.to_string();
let alias_name_camel_case = alias_str.to_lower_camel_case();
fields_definitions.push(quote! {pub #alias: #comparison_field_ty, });
filter_field_to_value.push(quote! {
map.insert(
::cido::__internal::async_graphql::Name::new(#alias_str),
::cido::__internal::async_graphql::InputType::to_value(&self.#alias),
);
});
parse_filter_field.push(quote! {
this.#alias = ::cido::__internal::async_graphql::InputType::parse(obj.get(#alias_name_camel_case).cloned()).map_err(::cido::__internal::async_graphql::InputValueError::propagate)?;
});
input_fields.push(quote! {
map.insert(
::std::borrow::ToOwned::to_owned(#alias_str),
::cido::__internal::async_graphql::registry::MetaInputValue {
name: #alias_str.to_string(),
description: ::std::option::Option::None,
ty: <#comparison_field_ty as ::cido::__internal::async_graphql::InputType>::create_type_info(registry),
default_value: ::std::option::Option::None,
visible: ::std::option::Option::None,
is_secret: false,
inaccessible: false,
tags: ::std::vec::Vec::new(),
directive_invocations: ::std::vec::Vec::new(),
deprecation: cido::__internal::async_graphql::registry::Deprecation::NoDeprecated,
},
);
});
is_empty.push(quote! {
if let ::std::option::Option::Some(val) = &self.#alias {
if !<#comparison_ty as ::cido::__internal::Filter>::is_empty(val) {
return false;
}
}
});
});
};
let handle_normal_field =
|comparison_ty: &TokenStream, comparison_field_ty: &TokenStream| {
let mut fields_definitions = fields_definitions.borrow_mut();
let mut filter_field_to_value = filter_field_to_value.borrow_mut();
let mut parse_filter_field = parse_filter_field.borrow_mut();
let mut input_fields = input_fields.borrow_mut();
let mut is_empty = is_empty.borrow_mut();
fields_definitions.push(quote! {pub #field_name: #comparison_field_ty, });
filter_field_to_value.push(quote! {
if let ::std::option::Option::Some(val) = self.#field_name.as_ref() {
<#comparison_ty as ::cido::__internal::Filter>::to_value(val, #field_name_camel_case, &mut map);
}
});
parse_filter_field.push(quote! {
this.#field_name = <#comparison_ty as ::cido::__internal::Filter>::parse::<::std::option::Option<Self>>(#field_name_camel_case, &obj).map_err(::cido::__internal::async_graphql::InputValueError::propagate)?;
});
COMPARISON_OPERATOR_SUFFIXES.iter().for_each(|suf| {
let (name, suf) = if (*suf) != "eq" { (format!("{}_{}", field_name_camel_case, suf), *suf) } else {
(field_name_camel_case.clone(), "")
};
input_fields.push(quote! {
if let ::std::option::Option::Some(val) = <#comparison_ty as ::cido::__internal::Filter>::match_operator(#name, #suf, registry) {
map.insert(::std::borrow::ToOwned::to_owned(#name), val);
};
});
});
is_empty.push(quote! {
if let ::std::option::Option::Some(val) = &self.#field_name {
if !<#comparison_ty as ::cido::__internal::Filter>::is_empty(val) {
return false;
}
}
});
};
if is_nested_ty {
let id_comparison_ty = {
let input_ty = f.graphql_input_type();
quote! {
<#input_ty as ::cido::__internal::ToNestedGraphqlNestedIdFilter>::Filter
}
};
let id_comparison_field_ty = quote! { ::std::option::Option<#id_comparison_ty> };
let full_comparison_ty = {
let ty = f
.graphql_config
.comparison
.as_ref()
.unwrap_or_else(|| &f.field.ty);
quote! { ::std::boxed::Box<<#ty as ::cido::__internal::ToGraphqlFilter>::Filter> }
};
let full_comparison_field_ty = quote! { ::std::option::Option<#full_comparison_ty> };
handle_normal_field(&id_comparison_ty, &id_comparison_field_ty);
handle_normal_alias(&id_comparison_ty, &id_comparison_field_ty);
handle_nest_alias(&full_comparison_ty, &full_comparison_field_ty);
let mut fields_definitions = fields_definitions.borrow_mut();
let mut filter_field_to_value = filter_field_to_value.borrow_mut();
let mut parse_filter_field = parse_filter_field.borrow_mut();
let mut input_fields = input_fields.borrow_mut();
let mut is_empty = is_empty.borrow_mut();
fields_definitions
.push(quote! {pub #field_name_with_underscore: #full_comparison_field_ty, });
filter_field_to_value.push(quote! {
map.insert(
::cido::__internal::async_graphql::Name::new(#field_name_camel_case_with_underscore),
::cido::__internal::async_graphql::InputType::to_value(&self.#field_name_with_underscore),
);
});
parse_filter_field.push(quote! {
this.#field_name_with_underscore = ::cido::__internal::async_graphql::InputType::parse(obj.get(#field_name_camel_case_with_underscore).cloned()).map_err(::cido::__internal::async_graphql::InputValueError::propagate)?;
});
input_fields.push(quote! {
map.insert(
::std::borrow::ToOwned::to_owned(#field_name_str_with_underscore),
::cido::__internal::async_graphql::registry::MetaInputValue {
name: #field_name_camel_case_with_underscore.to_string(),
description: ::std::option::Option::None,
ty: <#full_comparison_field_ty as ::cido::__internal::async_graphql::InputType>::create_type_info(registry),
default_value: ::std::option::Option::None,
visible: ::std::option::Option::None,
is_secret: false,
inaccessible: false,
tags: ::std::vec::Vec::new(),
directive_invocations: ::std::vec::Vec::new(),
deprecation: cido::__internal::async_graphql::registry::Deprecation::NoDeprecated,
},
);
});
is_empty.push(quote! {
if let ::std::option::Option::Some(val) = &self.#field_name_with_underscore {
if !<#full_comparison_ty as ::cido::__internal::Filter>::is_empty(val) {
return false;
}
}
});
} else {
let comparison_ty = {
let input_ty = f.graphql_input_type();
quote! { <#input_ty as ::cido::__internal::ToGraphqlFilter>::Filter }
};
let comparison_field_ty = quote! { ::std::option::Option<#comparison_ty> };
handle_normal_field(&comparison_ty, &comparison_field_ty);
handle_normal_alias(&comparison_ty, &comparison_field_ty);
}
}
}
let mut fields_definitions = fields_definitions.into_inner();
let mut filter_field_to_value = filter_field_to_value.into_inner();
let mut parse_filter_field = parse_filter_field.into_inner();
let mut input_fields = input_fields.into_inner();
let mut is_empty = is_empty.into_inner();
let or_and_filter_ty =
quote!(::core::option::Option<::std::vec::Vec<::core::option::Option<#filter_ident>>>);
fields_definitions.push(quote! {
pub _change_block: ::core::option::Option<::cido::__internal::BlockChangedFilter>,
pub or: #or_and_filter_ty,
pub and: #or_and_filter_ty,
});
filter_field_to_value.push(quote! {
map.insert(
::cido::__internal::async_graphql::Name::new("_change_block"),
::cido::__internal::async_graphql::InputType::to_value(&self._change_block),
);
map.insert(
::cido::__internal::async_graphql::Name::new("or"),
::cido::__internal::async_graphql::InputType::to_value(&self.or),
);
map.insert(
::cido::__internal::async_graphql::Name::new("and"),
::cido::__internal::async_graphql::InputType::to_value(&self.and),
);
});
parse_filter_field.push(quote! {
this._change_block = ::cido::__internal::async_graphql::InputType::parse(obj.get("_change_block").cloned()).map_err(::cido::__internal::async_graphql::InputValueError::propagate)?;
this.or = ::cido::__internal::async_graphql::InputType::parse(obj.get("or").cloned()).map_err(::cido::__internal::async_graphql::InputValueError::propagate)?;
this.and = ::cido::__internal::async_graphql::InputType::parse(obj.get("and").cloned()).map_err(::cido::__internal::async_graphql::InputValueError::propagate)?;
});
input_fields.push(quote! {
map.insert(
::std::borrow::ToOwned::to_owned("_change_block"),
::cido::__internal::async_graphql::registry::MetaInputValue {
name: "_change_block".to_string(),
description: ::std::option::Option::Some("Filter for the block changed event.".into()),
ty: <::core::option::Option<::cido::__internal::BlockChangedFilter> as ::cido::__internal::async_graphql::InputType>::create_type_info(registry),
default_value: ::std::option::Option::None,
visible: ::std::option::Option::None,
is_secret: false,
inaccessible: false,
tags: ::std::vec::Vec::new(),
directive_invocations: ::std::vec::Vec::new(),
deprecation: cido::__internal::async_graphql::registry::Deprecation::NoDeprecated,
},
);
map.insert(
::std::borrow::ToOwned::to_owned("or"),
::cido::__internal::async_graphql::registry::MetaInputValue {
name: "or".to_string(),
description: ::std::option::Option::None,
ty: <#or_and_filter_ty as ::cido::__internal::async_graphql::InputType>::create_type_info(registry),
default_value: ::std::option::Option::None,
visible: ::std::option::Option::None,
is_secret: false,
inaccessible: false,
tags: ::std::vec::Vec::new(),
directive_invocations: ::std::vec::Vec::new(),
deprecation: cido::__internal::async_graphql::registry::Deprecation::NoDeprecated,
},
);
map.insert(
::std::borrow::ToOwned::to_owned("and"),
::cido::__internal::async_graphql::registry::MetaInputValue {
name: "and".to_string(),
description: ::std::option::Option::None,
ty: <#or_and_filter_ty as ::cido::__internal::async_graphql::InputType>::create_type_info(registry),
default_value: ::std::option::Option::None,
visible: ::std::option::Option::None,
is_secret: false,
inaccessible: false,
tags: ::std::vec::Vec::new(),
directive_invocations: ::std::vec::Vec::new(),
deprecation: cido::__internal::async_graphql::registry::Deprecation::NoDeprecated,
},
);
});
is_empty.push(quote! {
if let ::std::option::Option::Some(val) = &self._change_block {
return false;
}
if let ::std::option::Option::Some(val) = &self.or {
if !val.is_empty() {
return false;
}
}
if let ::std::option::Option::Some(val) = &self.and {
if !val.is_empty() {
return false;
}
}
});
Ok(quote! {
#[allow(non_snake_case)]
#[derive(::core::fmt::Debug, ::core::default::Default, ::core::clone::Clone)]
pub struct #filter_ident {
#(#fields_definitions)*
}
impl ::cido::__internal::Filter for #filter_ident {
type Primitive = #filter_ident;
type Primitives = ::std::option::Option<#filter_ident>;
fn is_empty(&self) -> bool {
#(#is_empty)*
true
}
fn primitive_type_info(registry: &mut ::cido::__internal::async_graphql::registry::Registry) -> ::std::string::String {
<::core::option::Option<Self::Primitive> as ::cido::__internal::async_graphql::InputType>::create_type_info(registry)
}
fn primitives_type_info(registry: &mut ::cido::__internal::async_graphql::registry::Registry) -> ::std::string::String {
<Self::Primitives as ::cido::__internal::async_graphql::InputType>::create_type_info(registry)
}
fn match_operator(
_name: &'static str,
_op: &'static str,
_registry: &mut ::cido::__internal::async_graphql::registry::Registry,
) -> ::std::option::Option<::cido::__internal::async_graphql::registry::MetaInputValue> {
::std::option::Option::None
}
fn parse<T: ::cido::__internal::async_graphql::InputType>(
_field_name: &'static str,
_obj: &::cido::__internal::async_graphql::indexmap::IndexMap<::cido::__internal::async_graphql::Name, ::cido::__internal::async_graphql::Value>,
) -> ::std::result::Result<::std::option::Option<Self>, ::cido::__internal::async_graphql::InputValueError<T>> {
::std::result::Result::Ok(::std::option::Option::None)
}
fn merge(&mut self, other: Self) {}
fn to_value(
&self,
_field_name: &'static str,
_map: &mut ::cido::__internal::async_graphql::indexmap::IndexMap<::cido::__internal::async_graphql::Name, ::cido::__internal::async_graphql::Value>,
) {}
}
impl ::cido::__internal::async_graphql::InputType for #filter_ident {
type RawValueType = Self;
fn type_name() -> ::std::borrow::Cow<'static, str> {
::std::borrow::Cow::Borrowed(#filter_ident_name)
}
fn create_type_info(
registry: &mut ::cido::__internal::async_graphql::registry::Registry,
) -> ::std::string::String {
registry.create_input_type::<Self, _>(
::cido::__internal::async_graphql::registry::MetaTypeId::InputObject,
|registry| ::cido::__internal::async_graphql::registry::MetaType::InputObject {
name: <Self as ::cido::__internal::async_graphql::InputType>::type_name().into_owned(),
description: ::std::option::Option::None,
input_fields: {
let mut map = ::cido::__internal::async_graphql::indexmap::IndexMap::new();
#(#input_fields)*
map
},
visible: ::std::option::Option::None,
rust_typename: ::std::option::Option::Some(::std::any::type_name::<Self>()),
oneof: false,
inaccessible: false,
tags: ::std::vec::Vec::new(),
directive_invocations: ::std::vec::Vec::new(),
},
)
}
fn parse(
value: ::core::option::Option<::cido::__internal::async_graphql::Value>,
) -> ::cido::__internal::async_graphql::InputValueResult<Self> {
if let ::core::option::Option::Some(value) = value {
match value {
::cido::__internal::async_graphql::Value::Object(obj) => {
let mut this = <#filter_ident as ::core::default::Default>::default();
#(#parse_filter_field)*
if ::cido::__internal::Filter::is_empty(&this) {
return ::core::result::Result::Err(::cido::__internal::async_graphql::InputValueError::custom(
::std::format!("No fields set on {}", #filter_ident_name),
));
}
::cido::__internal::async_graphql::Result::Ok(this)
},
value => ::cido::__internal::async_graphql::Result::Err(::cido::__internal::async_graphql::InputValueError::expected_type(
value,
)),
}
} else {
::cido::__internal::async_graphql::Result::Err(::cido::__internal::async_graphql::InputValueError::expected_type(
value.unwrap_or_default(),
))
}
}
fn to_value(&self) -> ::cido::__internal::async_graphql::Value {
let mut map = ::cido::__internal::async_graphql::indexmap::IndexMap::new();
#(#filter_field_to_value)*
::cido::__internal::async_graphql::Value::Object(map)
}
fn as_raw_value(&self) -> ::std::option::Option<&Self::RawValueType> {
::std::option::Option::Some(self)
}
}
impl ::cido::__internal::async_graphql::InputObjectType for #filter_ident {}
})
}
fn generate_comparison(&self) -> syn::Result<TokenStream> {
let self_name = self.struct_name();
let filter_ident = format_ident!("{}Filter", self_name);
let comparison_ident = format_ident!("{}Comparison", self_name);
let fields_definitions = RefCell::new(vec![]);
let try_from_filter = RefCell::new(vec![]);
let is_empty = RefCell::new(vec![]);
let is_only_filter_id = RefCell::new(vec![]);
let id_field = self.id_field();
let id_ty = id_field.db_type();
let id_filter_ty = quote! {<#id_ty as ::cido::__internal::ToDbFilter>::Filter};
let id_field_name = id_field.graphql_input_name();
for f in &self.fields {
if !f.graphql_config.hidden {
let field_name = f.graphql_output_name();
let field_name_with_underscore = format_ident!("{}_", field_name);
let is_nested_ty = f.entity_or_event.is_some();
let handle_normal_alias =
|comparison_ty: &TokenStream, comparison_field_ty: &TokenStream| {
let mut fields_definitions = fields_definitions.borrow_mut();
let mut try_from_filter = try_from_filter.borrow_mut();
let mut is_empty = is_empty.borrow_mut();
let mut is_only_filter_id = is_only_filter_id.borrow_mut();
f.alias.iter().for_each(|alias| {
fields_definitions.push(quote! {pub #alias: #comparison_field_ty, });
let mapper = match &f.graphql_config.input_to_field {
Conversion::From(mapper) => {
quote! {
#alias: match filter.#alias {
::core::option::Option::Some(val) => ::core::option::Option::Some(val.try_map(#mapper).map_err(|e| ::cido::__internal::async_graphql::Error::new_with_source(::std::format!("{:?}", e)))?),
::core::option::Option::None => ::core::option::Option::None,
},
}
},
Conversion::Identity => quote! {
#alias: filter.#alias,
},
};
try_from_filter.push(mapper);
if f.id {
is_only_filter_id.push(quote! {
if let ::std::option::Option::Some(val) = &self.#field_name {
if !<#comparison_ty as ::cido::__internal::Filter>::is_empty(val) {
filter_by_id = true;
}
}
});
} else {
is_only_filter_id.push(quote! {
if let ::std::option::Option::Some(val) = &self.#field_name {
if !<#comparison_ty as ::cido::__internal::Filter>::is_empty(val) {
return false;
}
}
});
}
is_empty.push(quote! {
if let ::std::option::Option::Some(val) = &self.#field_name {
if !<#comparison_ty as ::cido::__internal::Filter>::is_empty(val) {
return false;
}
}
});
});
};
let handle_nest_alias = |comparison_ty: &TokenStream, comparison_field_ty: &TokenStream| {
let mut fields_definitions = fields_definitions.borrow_mut();
let mut try_from_filter = try_from_filter.borrow_mut();
let mut is_empty = is_empty.borrow_mut();
let mut is_only_filter_id = is_only_filter_id.borrow_mut();
f.alias.iter().for_each(|alias| {
let alias = syn::parse_str::<syn::Ident>(&format!("{}_", alias)).expect("still valid identifier");
fields_definitions.push(quote! {pub #alias: #comparison_field_ty, });
try_from_filter.push(quote! {
#alias: match filter.#alias {
::core::option::Option::Some(val) => ::core::option::Option::Some(::cido::__internal::TryMapFilter::try_map(val).map_err(|e| ::cido::__internal::async_graphql::Error::new_with_source(::std::format!("{:?}", e)))?),
::core::option::Option::None => ::core::option::Option::None,
},
});
if f.id {
is_only_filter_id.push(quote! {
if let ::std::option::Option::Some(val) = &self.#field_name {
if !<#comparison_ty as ::cido::__internal::ComplexFilter>::is_only_filter_by_id(val) {
filter_by_id = true;
}
}
});
} else {
is_only_filter_id.push(quote! {
if let ::std::option::Option::Some(val) = &self.#field_name {
if !<#comparison_ty as ::cido::__internal::ComplexFilter>::is_only_filter_by_id(val) {
return false;
}
}
});
}
is_empty.push(quote! {
if let ::std::option::Option::Some(val) = &self.#field_name {
if !<#comparison_ty as ::cido::__internal::ComplexFilter>::is_empty(val) {
return false;
}
}
});
});
};
let handle_normal_field =
|comparison_ty: &TokenStream,
comparison_field_ty: &TokenStream,
filter_ty: Option<&TokenStream>| {
let mut fields_definitions = fields_definitions.borrow_mut();
let mut try_from_filter = try_from_filter.borrow_mut();
let mut is_empty = is_empty.borrow_mut();
let mut is_only_filter_id = is_only_filter_id.borrow_mut();
fields_definitions.push(quote! {pub #field_name: #comparison_field_ty, });
let mapper = if let Some(filter_ty) = filter_ty {
match &f.graphql_config.input_to_field {
Conversion::From(mapper) => {
quote! {
#field_name: match filter.#field_name {
::core::option::Option::Some(val) => {
let tmp: #filter_ty = val.try_into()?;
::core::option::Option::Some(tmp.try_map(#mapper).map_err(|e| ::cido::__internal::async_graphql::Error::new_with_source(::std::format!("{:?}", e)))?)
},
::core::option::Option::None => ::core::option::Option::None,
},
}
}
Conversion::Identity => quote! {
#field_name: match filter.#field_name {
::core::option::Option::Some(val) => {
let tmp: #filter_ty = val.try_into()?;
::core::option::Option::Some(tmp)
},
::core::option::Option::None => ::core::option::Option::None,
},
},
}
} else {
match &f.graphql_config.input_to_field {
Conversion::From(mapper) => {
quote! {
#field_name: match filter.#field_name {
::core::option::Option::Some(val) => ::core::option::Option::Some(val.try_map(#mapper).map_err(|e| ::cido::__internal::async_graphql::Error::new_with_source(::std::format!("{:?}", e)))?),
::core::option::Option::None => ::core::option::Option::None,
},
}
}
Conversion::Identity => {
if f.id {
quote! {
#field_name: filter.#field_name.map(::core::convert::Into::into),
}
} else {
quote! {
#field_name: filter.#field_name,
}
}
}
}
};
try_from_filter.push(mapper);
if f.id {
is_only_filter_id.push(quote! {
if let ::std::option::Option::Some(val) = &self.#field_name {
if !<#comparison_ty as ::cido::__internal::Filter>::is_empty(val) {
filter_by_id = true;
}
}
});
} else {
is_only_filter_id.push(quote! {
if let ::std::option::Option::Some(val) = &self.#field_name {
if !<#comparison_ty as ::cido::__internal::Filter>::is_empty(val) {
return false;
}
}
});
}
is_empty.push(quote! {
if let ::std::option::Option::Some(val) = &self.#field_name {
if !<#comparison_ty as ::cido::__internal::Filter>::is_empty(val) {
return false;
}
}
});
};
if is_nested_ty {
let id_filter_ty = {
let input_ty = f.graphql_input_type();
quote! { <#input_ty as ::cido::__internal::ToGraphqlFilter>::Filter }
};
let id_comparison_ty = {
let db_ty = f.db_type();
quote! { <#db_ty as ::cido::__internal::ToDbFilter>::Filter }
};
let id_comparison_field_ty = quote! { ::std::option::Option<#id_comparison_ty> };
handle_normal_field(
&id_comparison_ty,
&id_comparison_field_ty,
Some(&id_filter_ty),
);
handle_normal_alias(&id_comparison_ty, &id_comparison_field_ty);
let full_comparison_ty = {
let comparison_ty = f
.graphql_config
.comparison
.as_ref()
.unwrap_or_else(|| &f.field.ty);
quote! { ::std::sync::Arc<<#comparison_ty as ::cido::__internal::ToDbFilter>::Filter> }
};
let full_comparison_field_ty = quote! { ::std::option::Option<#full_comparison_ty> };
handle_nest_alias(&full_comparison_ty, &full_comparison_field_ty);
let mut fields_definitions = fields_definitions.borrow_mut();
let mut try_from_filter = try_from_filter.borrow_mut();
let mut is_empty = is_empty.borrow_mut();
let mut is_only_filter_id = is_only_filter_id.borrow_mut();
fields_definitions
.push(quote! {pub #field_name_with_underscore: #full_comparison_field_ty, });
try_from_filter.push(quote! {
#field_name_with_underscore: match filter.#field_name_with_underscore {
::core::option::Option::Some(val) => ::core::option::Option::Some(::cido::__internal::TryMapFilter::try_map(val).map_err(|e| ::cido::__internal::async_graphql::Error::new_with_source(::std::format!("{:?}", e)))?),
::core::option::Option::None => ::core::option::Option::None,
},
});
if f.id {
is_only_filter_id.push(quote! {
if let ::std::option::Option::Some(val) = &self.#field_name_with_underscore {
if !<#full_comparison_ty as ::cido::__internal::ComplexFilter>::is_only_filter_by_id(val) {
filter_by_id = true;
}
}
});
} else {
is_only_filter_id.push(quote! {
if let ::std::option::Option::Some(val) = &self.#field_name_with_underscore {
if !<#full_comparison_ty as ::cido::__internal::ComplexFilter>::is_only_filter_by_id(val) {
return false;
}
}
});
}
is_empty.push(quote! {
if let ::std::option::Option::Some(val) = &self.#field_name_with_underscore {
if !<#full_comparison_ty as ::cido::__internal::ComplexFilter>::is_empty(val) {
return false;
}
}
});
} else {
let comparison_ty = {
let db_ty = f.db_type();
quote! { <#db_ty as ::cido::__internal::ToDbFilter>::Filter }
};
let comparison_field_ty = quote! { ::std::option::Option<#comparison_ty> };
handle_normal_field(&comparison_ty, &comparison_field_ty, None);
handle_normal_alias(&comparison_ty, &comparison_field_ty);
}
}
}
let multiple_matcher = self.generate_multiple_where_matcher().into_iter();
let history_matcher = self.generate_history_where_matcher().into_iter();
let multiple_query = self.generate_multiple_where_clause()?.into_iter();
let history_query = self.generate_history_where_clause()?.into_iter();
let fields_definitions = fields_definitions.into_inner();
let try_from_filter = try_from_filter.into_inner();
let is_empty = is_empty.into_inner();
let is_only_filter_id = is_only_filter_id.into_inner();
let res = quote! {
#[allow(non_snake_case)]
#[derive(::core::fmt::Debug, ::core::default::Default, ::core::clone::Clone)]
pub struct #comparison_ident {
#(#fields_definitions)*
}
impl ::cido::__internal::TryMapFilter<#filter_ident> for #comparison_ident {
fn try_map(filter: #filter_ident) -> ::std::result::Result<#comparison_ident, ::cido::__internal::async_graphql::Error> {
::core::result::Result::Ok(Self {
#(#try_from_filter)*
})
}
}
impl ::cido::__internal::TryMapFilter<#filter_ident> for ::std::boxed::Box<#comparison_ident> {
fn try_map(filter: #filter_ident) -> ::std::result::Result<::std::boxed::Box<#comparison_ident>, ::cido::__internal::async_graphql::Error> {
::core::result::Result::Ok(::std::boxed::Box::new(
#comparison_ident {
#(#try_from_filter)*
}
))
}
}
impl ::cido::__internal::TryMapFilter<::std::boxed::Box<#filter_ident>> for ::std::boxed::Box<#comparison_ident> {
fn try_map(filter: ::std::boxed::Box<#filter_ident>) -> ::std::result::Result<::std::boxed::Box<#comparison_ident>, ::cido::__internal::async_graphql::Error> {
::core::result::Result::Ok(::std::boxed::Box::new(
#comparison_ident {
#(#try_from_filter)*
}
))
}
}
impl ::cido::__internal::TryMapFilter<#filter_ident> for ::std::sync::Arc<#comparison_ident> {
fn try_map(filter: #filter_ident) -> ::std::result::Result<::std::sync::Arc<#comparison_ident>, ::cido::__internal::async_graphql::Error> {
::core::result::Result::Ok(::std::sync::Arc::new(
#comparison_ident {
#(#try_from_filter)*
}
))
}
}
impl ::cido::__internal::TryMapFilter<::std::boxed::Box<#filter_ident>> for ::std::sync::Arc<#comparison_ident> {
fn try_map(filter: ::std::boxed::Box<#filter_ident>) -> ::std::result::Result<::std::sync::Arc<#comparison_ident>, ::cido::__internal::async_graphql::Error> {
::core::result::Result::Ok(::std::sync::Arc::new(
#comparison_ident {
#(#try_from_filter)*
}
))
}
}
impl ::cido::__internal::RootWhere for #comparison_ident {
type BlockNumber = <
<<#self_name as ::cido::__internal::Transformer>::Cidomap as ::cido::__internal::Cidomap>::Network as ::cido::__internal::Network
>::BlockNumber;
type IdFilter = #id_filter_ty;
fn from_id(id: ::std::option::Option<#id_filter_ty>) -> Self {
Self {
#id_field_name: id,
..<Self as ::core::default::Default>::default()
}
}
fn apply<'b, 'ctx: 'b, O>(
&'b self,
ctx: &'ctx ::cido::__internal::async_graphql::Context<'ctx>,
mut builder: ::cido::__internal::QueryBuilder<'b, O>,
block_number: Self::BlockNumber
) -> ::cido::__internal::futures::future::BoxFuture<'b,
::core::result::Result<::cido::__internal::QueryBuilder<'b, O>, ::cido::__internal::async_graphql::Error>
>
where
O: ::core::marker::Send + 'b
{
use ::cido::__internal::futures::future::FutureExt;
async move {
if ::cido::__internal::ComplexFilter::is_empty(self) {
return ::core::result::Result::Ok(builder);
}
let mut and = true;
#(#multiple_query)*
::core::result::Result::Ok(builder)
}.boxed()
}
fn apply_history<'b, 'ctx: 'b, O>(
&'b self,
ctx: &'ctx ::cido::__internal::async_graphql::Context<'ctx>,
mut builder: ::cido::__internal::QueryBuilder<'b, O>,
start_block: Self::BlockNumber,
end_block: Self::BlockNumber,
) -> ::cido::__internal::futures::future::BoxFuture<'b,
::core::result::Result<::cido::__internal::QueryBuilder<'b, O>, ::cido::__internal::async_graphql::Error>
>
where
O: ::core::marker::Send + 'b
{
use ::cido::__internal::futures::future::FutureExt;
use ::cido::__internal::BlockNumberRange;
async move {
if ::cido::__internal::ComplexFilter::is_empty(self) {
return ::core::result::Result::Ok(builder);
}
let mut and = true;
#(#history_query)*
::core::result::Result::Ok(builder)
}.boxed()
}
}
impl ::cido::__internal::ComplexFilter for #comparison_ident {
type Transformer = #self_name;
type NestedIdFilter = #id_filter_ty;
fn id_filter(&self) -> ::std::option::Option<&Self::NestedIdFilter> {
self.#id_field_name.as_ref()
}
fn apply_filter<'q, O>(
&'q self,
field: &str,
mut builder: ::cido::__internal::QueryBuilder<'q, O>,
block_number: <<<Self::Transformer as ::cido::__internal::Transformer>::Cidomap as ::cido::__internal::Cidomap>::Network as ::cido::__internal::Network>::BlockNumber,
) -> ::core::result::Result<::cido::__internal::QueryBuilder<'q, O>, ::cido::__internal::async_graphql::Error>
where
O: ::core::marker::Send + 'q
{
let descriptor = <Self::Transformer as ::cido::__internal::Transformer>::table_descriptor();
let resolver = descriptor.table_resolver();
let table = resolver.get_table_for_block_number(block_number);
builder = builder.sub_select()
.id_field::<Self::Transformer>() .from(&table) .filter_by_blocknumber::<Self::Transformer>(block_number)
.finalize();
let mut and = true;
#(#multiple_matcher)*
let _ = and;
::core::result::Result::Ok(builder)
}
fn apply_history_filter<'q, O>(
&'q self,
field: &str,
mut builder: ::cido::__internal::QueryBuilder<'q, O>,
start_block: <<<Self::Transformer as ::cido::__internal::Transformer>::Cidomap as ::cido::__internal::Cidomap>::Network as ::cido::__internal::Network>::BlockNumber,
end_block: <<<Self::Transformer as ::cido::__internal::Transformer>::Cidomap as ::cido::__internal::Cidomap>::Network as ::cido::__internal::Network>::BlockNumber,
) -> ::core::result::Result<::cido::__internal::QueryBuilder<'q, O>, ::cido::__internal::async_graphql::Error>
where
O: ::core::marker::Send + 'q
{
use ::cido::__internal::BlockNumberRange;
let descriptor = <Self::Transformer as ::cido::__internal::Transformer>::table_descriptor();
let resolver = descriptor.table_resolver();
let range = <<<Self::Transformer as ::cido::__internal::Transformer>::Cidomap as ::cido::__internal::Cidomap>::Network as ::cido::__internal::Network>::BlockNumberRange::new(
start_block,
::core::option::Option::Some(end_block),
);
let table = resolver.get_tables_for_range(&range);
builder = builder.sub_select()
.id_field::<Self::Transformer>()
.from(&table)
.filter_by_blocknumber_range::<Self::Transformer>(start_block, end_block)
.finalize();
let mut and = true;
#(#history_matcher)*
let _ = and;
::core::result::Result::Ok(builder)
}
fn is_only_filter_by_id(&self) -> bool {
let mut filter_by_id = false;
#(#is_only_filter_id)*
filter_by_id
}
fn is_empty(&self) -> bool {
#(#is_empty)*
true
}
}
};
Ok(res)
}
fn generate_nested_query_builder_getters(&self) -> syn::Result<Vec<TokenStream>> {
let mut impls = Vec::new();
for f in &self.fields {
if (!f.graphql_config.hidden) && f.entity_or_event.is_some() {
let field_name = f.graphql_output_name();
let field_name_with_underscore = format_ident!("{}_", field_name);
let getter_name = format_ident!("__{}", field_name);
let field_ty = &f.field.ty;
let field_ty = quote! {
<#field_ty as ::cido::__internal::ToTransformer>::Transformer
};
impls.push(quote! {
pub fn #getter_name(&self) -> ::cido::__internal::GraphqlQueryBuilder<#field_ty> {
use ::cido::__internal::GraphqlOutputType;
let query_builder = self.__get_query_context();
let ::cido::__internal::GraphqlQueryBuilder {
comparison,
..
} = query_builder;
::cido::__internal::GraphqlQueryBuilder::new(
comparison.as_ref().map(|qb| {
qb.#field_name_with_underscore.clone()
}).flatten(),
comparison.as_ref().map(|qb| {
qb.#field_name.clone()
}).flatten().map(::std::sync::Arc::new),
::std::option::Option::None,
::core::default::Default::default(),
::core::default::Default::default(),
)
}
});
}
}
Ok(impls)
}
fn generate_multiple_where_matcher(&self) -> impl IntoIterator<Item = TokenStream> {
self
.fields
.iter()
.filter_map(|f| {
if !f.graphql_config.hidden {
let sql_name = f.sql_config.name.as_str();
let simple_matcher = quote! {
if and {
builder.push(" AND ");
}
::cido::__internal::Filter::apply_filter(f, #sql_name, builder.get_inner_mut())?;
and = true;
};
let field_name = f.graphql_output_name();
let field_name_with_underscore = format_ident!("{}_", field_name);
let get_complex_where_clause = |comparison_ty: &TokenStream, fty: &TokenStream| -> (TokenStream, TokenStream) {
let matcher = quote! { <<<#comparison_ty as ::cido::__internal::Transformer>::GraphqlInput as ::cido::__internal::GraphqlInputType>::Where as ::cido::__internal::ComplexFilter> };
let nested_select = format!("{sql_name} IN ( ");
let collection_nested_select = format!("{sql_name} <@ array( ");
let complex_where_clause_matcher = quote! {
if #matcher::is_only_filter_by_id(f) {
<#matcher::NestedIdFilter as ::cido::__internal::Filter>::apply_filter(#matcher::id_filter(f).unwrap(), #sql_name, builder.get_inner_mut())?;
} else {
if <<#fty as ::cido::__internal::ToDbFilter>::Filter as ::cido::__internal::Filter>::is_collection() {
builder.push(#collection_nested_select);
} else {
builder.push(#nested_select); }
builder = #matcher::apply_filter(f, #sql_name, builder, block_number)?;
builder.push(" ) "); }
};
(matcher, complex_where_clause_matcher)
};
if let Some(original_comparison_ty) = f.graphql_config.comparison.as_ref() {
let is_nested_ty = f.entity_or_event.is_some();
if is_nested_ty {
let fty = {
let ty = &f.field.ty;
quote! { <#ty as ::cido::__internal::ToIdentifiable>::Identifiable }
};
let comparison_ty = {
quote! { <#original_comparison_ty as ::cido::__internal::ToTransformer>::Transformer }
};
let (matcher, complex_where_clause_matcher) = get_complex_where_clause(&comparison_ty, &fty);
let aliases = f.alias.iter().map(|alias| {
let alias_with_underscore = format_ident!("{}_", alias);
quote! {
if let ::std::option::Option::Some(f) = &self.#alias_with_underscore {
if !#matcher::is_empty(f) {
if and {
builder.push(" AND ");
}
and = true;
#complex_where_clause_matcher
}
}
if let ::std::option::Option::Some(f) = &self.#alias {
if !::cido::__internal::Filter::is_empty(f) {
#simple_matcher
}
}
}
}).collect::<Vec<_>>();
Some(quote! {
if let ::std::option::Option::Some(f) = &self.#field_name_with_underscore {
if !#matcher::is_empty(f) {
if and {
builder.push(" AND ");
}
and = true;
#complex_where_clause_matcher
}
}
if let ::std::option::Option::Some(f) = &self.#field_name {
if !::cido::__internal::Filter::is_empty(f) {
#simple_matcher
}
}
#(#aliases)*
})
} else {
let fty = {
let ty = &f.field.ty;
quote! { #ty }
};
let comparison_ty = {
quote! { #original_comparison_ty }
};
let (matcher, complex_where_clause_matcher) = get_complex_where_clause(&comparison_ty, &fty);
let aliases = f.alias.iter().map(|alias| {
quote! {
if let ::std::option::Option::Some(f) = &self.#alias {
if !#matcher::is_empty(f) {
if and {
builder.push(" AND ");
}
and = true;
#complex_where_clause_matcher
}
}
}
}).collect::<Vec<_>>();
Some(quote! {
if let ::std::option::Option::Some(f) = &self.#field_name {
if !#matcher::is_empty(f) {
if and {
builder.push(" AND ");
}
and = true;
#complex_where_clause_matcher
}
}
#(#aliases)*
})
}
} else {
let aliases = f.alias.iter().map(|alias| {
quote! {
if let ::std::option::Option::Some(f) = &self.#alias {
if !::cido::__internal::Filter::is_empty(f) {
#simple_matcher
}
}
}
}).collect::<Vec<_>>();
Some(quote! {
if let ::std::option::Option::Some(f) = &self.#field_name {
if !::cido::__internal::Filter::is_empty(f) {
#simple_matcher
}
}
#(#aliases)*
})
}
} else {
None
}
})
.collect::<Vec<_>>()
}
fn generate_history_where_matcher(&self) -> impl IntoIterator<Item = TokenStream> {
self
.fields
.iter()
.filter_map(|f| {
if !f.graphql_config.hidden {
let sql_name = f.sql_config.name.as_str();
let simple_matcher = quote! {
if and {
builder.push(" AND ");
}
::cido::__internal::Filter::apply_filter(f, #sql_name, builder.get_inner_mut())?;
and = true;
};
let field_name = f.graphql_output_name();
let field_name_with_underscore = format_ident!("{}_", field_name);
let get_complex_where_clause = |comparison_ty: &TokenStream, fty: &TokenStream| -> (TokenStream, TokenStream) {
let matcher = quote! { <<<#comparison_ty as ::cido::__internal::Transformer>::GraphqlInput as ::cido::__internal::GraphqlInputType>::Where as ::cido::__internal::ComplexFilter> };
let nested_select = format!("{sql_name} IN ( ");
let collection_nested_select = format!("{sql_name} <@ array( ");
let complex_where_clause_matcher = quote! {
if #matcher::is_only_filter_by_id(f) {
<#matcher::NestedIdFilter as ::cido::__internal::Filter>::apply_filter(#matcher::id_filter(f).unwrap(), #sql_name, builder.get_inner_mut())?;
} else {
if <<#fty as ::cido::__internal::ToDbFilter>::Filter as ::cido::__internal::Filter>::is_collection() {
builder.push(#collection_nested_select);
} else {
builder.push(#nested_select);
}
builder = #matcher::apply_history_filter(f, #sql_name, builder, start_block, end_block)?;
builder.push(" ) ");
}
};
(matcher, complex_where_clause_matcher)
};
if let Some(comparison_ty) = f.graphql_config.comparison.as_ref() {
let is_nested_ty = f.entity_or_event.is_some();
if is_nested_ty {
let fty = {
let ty = &f.field.ty;
quote! { <#ty as ::cido::__internal::ToIdentifiable>::Identifiable }
};
let comparison_ty = {
quote! { <#comparison_ty as ::cido::__internal::ToTransformer>::Transformer }
};
let (matcher, complex_where_clause_matcher) = get_complex_where_clause(&comparison_ty, &fty);
let aliases = f.alias.iter().map(|alias| {
let alias_with_underscore = format_ident!("{}_", alias);
quote! {
if let ::std::option::Option::Some(f) = &self.#alias_with_underscore {
if !#matcher::is_empty(f) {
if and {
builder.push(" AND ");
}
and = true;
#complex_where_clause_matcher
}
}
if let ::std::option::Option::Some(f) = &self.#alias {
if !::cido::__internal::Filter::is_empty(f) {
#simple_matcher
}
}
}
}).collect::<Vec<_>>();
Some(quote! {
if let ::std::option::Option::Some(f) = &self.#field_name_with_underscore {
if !#matcher::is_empty(f) {
if and {
builder.push(" AND ");
}
and = true;
#complex_where_clause_matcher
}
}
if let ::std::option::Option::Some(f) = &self.#field_name {
if !::cido::__internal::Filter::is_empty(f) {
#simple_matcher
}
}
#(#aliases)*
})
} else {
let fty = {
let ty = &f.field.ty;
quote! { #ty }
};
let comparison_ty = {
quote! { #comparison_ty }
};
let (matcher, complex_where_clause_matcher) = get_complex_where_clause(&comparison_ty, &fty);
let aliases = f.alias.iter().map(|alias| {
quote! {
if let ::std::option::Option::Some(f) = &self.#alias {
if !#matcher::is_empty(f) {
if and {
builder.push(" AND ");
}
and = true;
#complex_where_clause_matcher
}
}
}
}).collect::<Vec<_>>();
Some(quote! {
if let ::std::option::Option::Some(f) = &self.#field_name {
if !#matcher::is_empty(f) {
if and {
builder.push(" AND ");
}
and = true;
#complex_where_clause_matcher
}
}
#(#aliases)*
})
}
} else {
let aliases = f.alias.iter().map(|alias| {
quote! {
if let ::std::option::Option::Some(f) = &self.#alias {
if !::cido::__internal::Filter::is_empty(f) {
#simple_matcher
}
}
}
}).collect::<Vec<_>>();
Some(quote! {
if let ::std::option::Option::Some(f) = &self.#field_name {
if !::cido::__internal::Filter::is_empty(f) {
#simple_matcher
}
}
#(#aliases)*
})
}
} else {
None
}
})
.collect::<Vec<_>>()
}
fn generate_multiple_where_clause(&self) -> syn::Result<impl IntoIterator<Item = TokenStream>> {
self
.fields
.iter()
.map(|f| {
if !f.graphql_config.hidden {
let sql_name = f.sql_config.name.as_str();
let field_name = f.graphql_output_name();
let field_name_with_underscore = format_ident!("{}_", field_name);
let simple_where_clause_matcher = quote! {
if and {
builder.push(" AND ");
}
::cido::__internal::Filter::apply_filter(f, #sql_name, builder.get_inner_mut())?;
and = true;
};
let get_complex_where_clause = |comparison_ty: &TokenStream, fty: &TokenStream| -> (TokenStream, TokenStream) {
let matcher = quote! { <<<#comparison_ty as ::cido::__internal::Transformer>::GraphqlInput as ::cido::__internal::GraphqlInputType>::Where as ::cido::__internal::ComplexFilter> };
let nested_select = format!("{sql_name} IN ( ");
let collection_nested_select = format!("{sql_name} <@ array( ");
let complex_where_clause = quote! {
if #matcher::is_only_filter_by_id(f) {
<#matcher::NestedIdFilter as ::cido::__internal::Filter>::apply_filter(#matcher::id_filter(f).unwrap(), #sql_name, builder.get_inner_mut())?;
} else {
let descriptor = <#comparison_ty as ::cido::__internal::Transformer>::table_descriptor();
let resolver = descriptor.table_resolver();
let table = resolver.get_table_for_block_number(block_number);
if <<#fty as ::cido::__internal::ToDbFilter>::Filter as ::cido::__internal::Filter>::is_collection() {
builder.push(#collection_nested_select);
} else {
builder.push(#nested_select);
}
builder = #matcher::apply_filter(f, #sql_name, builder, block_number)?;
builder.push(" ) ");
}
};
(matcher, complex_where_clause)
};
if let Some(comparison_ty) = f.graphql_config.comparison.as_ref() {
let is_nested_ty = f.entity_or_event.is_some();
if is_nested_ty {
let fty = {
let ty = &f.field.ty;
quote! { <#ty as ::cido::__internal::ToIdentifiable>::Identifiable }
};
let comparison_ty = quote! { <#comparison_ty as ::cido::__internal::ToTransformer>::Transformer };
let (matcher, complex_where_clause_matcher) = get_complex_where_clause(&comparison_ty, &fty);
Ok(Some(quote! {
if let ::std::option::Option::Some(f) = &self.#field_name {
if !::cido::__internal::Filter::is_empty(f) {
#simple_where_clause_matcher
}
}
if let ::std::option::Option::Some(f) = &self.#field_name_with_underscore {
if !#matcher::is_empty(&f) {
if and {
builder.push(" AND ");
}
and = true;
#complex_where_clause_matcher
}
}
}))
} else {
let fty = {
let ty = &f.field.ty;
quote! { #ty }
};
let comparison_ty = quote! { #comparison_ty };
let (matcher, complex_where_clause_matcher) = get_complex_where_clause(&comparison_ty, &fty);
Ok(Some(quote! {
if let ::std::option::Option::Some(f) = &self.#field_name {
if !#matcher::is_empty(&f) {
if and {
builder.push(" AND ");
}
and = true;
#complex_where_clause_matcher
}
}
}))
}
} else {
Ok(Some(quote! {
if let ::std::option::Option::Some(f) = &self.#field_name {
if !::cido::__internal::Filter::is_empty(f) {
#simple_where_clause_matcher
}
}
}))
}
} else {
Ok(None)
}
})
.collect::<Result<Vec<_>, _>>().map(|iter| iter.into_iter().flatten())
}
fn generate_history_where_clause(&self) -> syn::Result<impl IntoIterator<Item = TokenStream>> {
self
.fields
.iter()
.map(|f| {
if !f.graphql_config.hidden {
let sql_name = f.sql_config.name.as_str();
let field_name = f.graphql_output_name();
let field_name_with_underscore = format_ident!("{}_", field_name);
let simple_where_clause_matcher = quote! {
if and {
builder.push(" AND ");
}
::cido::__internal::Filter::apply_filter(field_cmp, #sql_name, builder.get_inner_mut())?;
and = true;
};
let get_complex_where_clause = |comparison_ty: &TokenStream, fty: &TokenStream| -> TokenStream {
let matcher = quote! { <<<#comparison_ty as ::cido::__internal::Transformer>::GraphqlInput as ::cido::__internal::GraphqlInputType>::Where as ::cido::__internal::ComplexFilter> };
let nested_select = format!("{sql_name} IN ( ");
let collection_nested_select = format!("{sql_name} <@ array( ");
quote! {
if #matcher::is_only_filter_by_id(field_cmp) {
<#matcher::NestedIdFilter as ::cido::__internal::Filter>::apply_filter(#matcher::id_filter(field_cmp).unwrap(), #sql_name, builder.get_inner_mut())?;
} else {
let descriptor = <#comparison_ty as ::cido::__internal::Transformer>::table_descriptor();
let resolver = descriptor.table_resolver();
let range = <<<#comparison_ty as ::cido::__internal::Transformer>::Cidomap as ::cido::__internal::Cidomap>::Network as ::cido::__internal::Network>::BlockNumberRange::new(
start_block,
::core::option::Option::Some(end_block),
);
let table = resolver.get_tables_for_range(&range);
if <<#fty as ::cido::__internal::ToDbFilter>::Filter as ::cido::__internal::Filter>::is_collection() {
builder.push(#collection_nested_select);
} else {
builder.push(#nested_select);
}
builder = #matcher::apply_history_filter(field_cmp, #sql_name, builder, start_block, end_block)?;
builder.push(" ) ");
}
}
};
if let Some(comparison_ty) = f.graphql_config.comparison.as_ref() {
let is_nested_ty = f.entity_or_event.is_some();
if is_nested_ty {
let fty = {
let ty = &f.field.ty;
quote! { <#ty as ::cido::__internal::ToIdentifiable>::Identifiable }
};
let comparison_ty = quote! { <#comparison_ty as ::cido::__internal::ToTransformer>::Transformer };
let complex_where_clause_matcher = get_complex_where_clause(&comparison_ty, &fty);
Ok(Some(quote! {
if let ::std::option::Option::Some(field_cmp) = &self.#field_name {
#simple_where_clause_matcher
}
if let ::std::option::Option::Some(field_cmp) = &self.#field_name_with_underscore {
if and {
builder.push(" AND ");
}
and = true;
#complex_where_clause_matcher
}
}))
} else {
let fty = {
let ty = &f.field.ty;
quote! { #ty }
};
let comparison_ty = quote! { #comparison_ty };
let complex_where_clause_matcher = get_complex_where_clause(&comparison_ty, &fty);
Ok(Some(quote! {
if let ::std::option::Option::Some(field_cmp) = &self.#field_name {
if and {
builder.push(" AND ");
}
and = true;
#complex_where_clause_matcher
}
}))
}
} else {
Ok(Some(quote! {
if let ::std::option::Option::Some(field_cmp) = &self.#field_name {
#simple_where_clause_matcher
}
}))
}
} else {
Ok(None)
}
})
.collect::<Result<Vec<_>, _>>().map(|iter| iter.into_iter().flatten())
}
}