use std::collections::HashSet;
use deluxe::{ExtractAttributes, ParseAttributes, ParseMetaItem};
use heck::ToLowerCamelCase;
use proc_macro2::TokenStream;
use quote::format_ident;
use syn::{Ident, Type, Visibility, spanned::Spanned};
use crate::parse::util::{Attributes, SqlSafeName};
#[derive(Debug, Clone)]
pub struct OrderBy {
pub name: Ident,
pub variants: Vec<OrderByVariant>,
pub attrs: Attributes,
pub vis: Visibility,
pub embed_generated_code: bool,
}
impl OrderBy {
pub fn parse(input: TokenStream) -> deluxe::Result<Self> {
let d = syn::parse2::<syn::DeriveInput>(input)?;
let event_options = OrderByOptionsParse::parse_attributes(&d)?;
let mut has_default = false;
let mut has_id = false;
let mut has_block_number = false;
let variant_parse = match d.data {
syn::Data::Enum(e) => e
.variants
.into_iter()
.map(|mut v| {
(
Some(v.ident.clone()),
None,
OrderByVariantParse::extract_attributes(&mut v),
)
})
.collect::<Vec<_>>(),
syn::Data::Struct(s) => s
.fields
.into_iter()
.map(|mut f| {
(
f.ident.clone(),
Some(f.span()),
OrderByVariantParse::extract_attributes(&mut f),
)
})
.collect::<Vec<_>>(),
syn::Data::Union(u) => {
return Err(crate::err(&u.union_token, "Unions are not supported"));
}
};
let mut variants = Vec::new();
for (ident, span, variant) in variant_parse {
let v = variant?;
let Some(ident) = ident else {
return Err(crate::parse::err_span(
span.unwrap(),
"Tuple structs are not supported",
));
};
if v.default.is_set() && has_default {
return Err(crate::parse::err_span(
v.default.span(),
"Only one default attribute allowed",
));
}
if v.id.is_set() && has_id {
return Err(crate::parse::err_span(
v.id.span(),
"Only one id attribute allowed",
));
}
if v.block_number.is_set() && has_block_number {
return Err(crate::parse::err_span(
v.block_number.span(),
"Only one block_number attribute allowed",
));
}
has_default |= v.default.is_set();
has_id |= v.id.is_set();
has_block_number |= v.block_number.is_set();
variants.push(OrderByVariant {
name: v.name.unwrap_or_else(|| ident.clone()),
sql_name: v.sql_name,
graphql_name: v
.graphql_name
.unwrap_or_else(|| format_ident!("{}", ident.to_string().to_lower_camel_case())),
graphql_type: v.graphql_type,
attrs: v.attrs,
aliases: v.aliases,
default: v.default.is_set(),
id: v.id.is_set(),
hidden: v.hidden.is_set(),
entity_event: false,
is_block_number: v.block_number.is_set(),
});
}
if has_id && !has_default {
for v in &mut variants {
if v.id {
v.default = true;
break;
}
}
}
Ok(Self {
name: event_options
.name
.unwrap_or_else(|| format_ident!("{}OrderBy", d.ident)),
variants,
attrs: event_options.attrs,
vis: d.vis,
embed_generated_code: event_options.embed_generated_code.is_set(),
})
}
}
#[derive(Debug, ParseAttributes)]
#[deluxe(attributes(orderby))]
pub struct OrderByOptionsParse {
#[deluxe(alias = rename)]
pub name: Option<Ident>,
#[deluxe(default)]
pub attrs: Attributes,
pub embed_generated_code: deluxe::Flag,
}
#[derive(Debug, Clone)]
#[allow(clippy::struct_excessive_bools)]
pub struct OrderByVariant {
pub name: Ident,
pub sql_name: SqlSafeName,
pub graphql_name: Ident,
pub graphql_type: Option<Type>,
pub attrs: Attributes,
pub aliases: HashSet<Ident>,
pub default: bool,
pub id: bool,
pub hidden: bool,
pub entity_event: bool,
pub is_block_number: bool,
}
#[derive(Debug, ExtractAttributes, ParseMetaItem)]
#[deluxe(attributes(orderby))]
pub struct OrderByVariantParse {
pub name: Option<Ident>,
pub sql_name: SqlSafeName,
pub graphql_name: Option<Ident>,
pub graphql_type: Option<Type>,
#[deluxe(default)]
pub attrs: Attributes,
#[deluxe(append)]
pub aliases: HashSet<Ident>,
pub default: deluxe::Flag,
pub id: deluxe::Flag,
pub hidden: deluxe::Flag,
pub block_number: deluxe::Flag,
}