use deluxe::{ExtractAttributes, ParseMetaItem};
use proc_macro2::TokenStream;
use quote::format_ident;
use syn::{Expr, Field, Ident, Path, Type, Visibility};
#[derive(Debug)]
pub struct CidomapStruct {
pub name: Ident,
pub vis: Visibility,
pub opts: CidomapOptions,
pub fields: Vec<CidomapField>,
}
impl CidomapStruct {
pub fn parse(args: TokenStream, input: TokenStream) -> deluxe::Result<Self> {
let cidomap_options = deluxe::parse2::<CidomapOptionsParse>(args)?.into();
let t = syn::parse2::<syn::ItemStruct>(input)?;
super::ensure_generics_zero(&t.generics)?;
if t.semi_token.is_some() {
return Err(crate::err(
&t,
"Only structs with named fields are supported",
));
}
let mut fields = Vec::with_capacity(t.fields.len());
for mut field in t.fields {
field
.ident
.as_ref()
.ok_or_else(|| crate::err(&field, "Unnamed fields are not supported"))?;
let graphql = GraphqlField::extract_attributes(&mut field)?;
fields.push(CidomapField { field, graphql });
}
let this = Self {
name: t.ident.clone(),
vis: t.vis,
opts: cidomap_options,
fields,
};
Ok(this)
}
}
#[derive(Debug)]
pub struct CidomapField {
pub field: Field,
pub graphql: GraphqlField,
}
#[derive(Debug)]
pub struct CidomapOptions {
pub gql: GraphqlStructDef,
pub config: CidomapStructDef,
pub embed_generated_code: bool,
}
impl From<CidomapOptionsParse> for CidomapOptions {
fn from(p: CidomapOptionsParse) -> Self {
Self {
gql: p.gql,
config: p.config,
embed_generated_code: p.embed_generated_code.is_set(),
}
}
}
#[derive(Debug, ParseMetaItem)]
pub struct CidomapOptionsParse {
#[deluxe(default)]
pub gql: GraphqlStructDef,
pub config: CidomapStructDef,
pub embed_generated_code: deluxe::Flag,
}
#[derive(Debug, ParseMetaItem)]
pub struct CidomapStructDef {
#[deluxe(with = deluxe::with::maybe_quoted)]
pub start_block: Expr,
#[deluxe(with = deluxe::with::maybe_quoted)]
pub max_block: Option<Expr>,
#[deluxe(default = 1)]
pub max_processing_order: u8,
pub initial_filters: Path,
pub init: Option<Path>,
pub create: Option<Path>,
pub error: Option<Type>,
pub network: Type,
pub events: Type,
}
#[derive(Debug, ParseMetaItem, Default)]
pub struct GraphqlStructDef {
#[deluxe(default)]
pub extensions: Vec<Type>,
#[deluxe(default)]
pub single: PrePostFixes,
#[deluxe(default)]
pub multiple: PrePostFixes,
#[deluxe(default)]
pub history: PrePostFixes,
}
#[derive(Debug, ParseMetaItem, Default)]
pub struct PrePostFixes {
#[deluxe(with = deluxe::with::maybe_quoted)]
pub prefix: Option<Ident>,
#[deluxe(with = deluxe::with::maybe_quoted)]
pub suffix: Option<Ident>,
}
impl PrePostFixes {
pub fn apply_default_name(&self, name: &Ident) -> Option<Ident> {
match (&self.prefix, &self.suffix) {
(None, None) => None,
(None, Some(suffix)) => Some(format_ident!("{name}{suffix}")),
(Some(prefix), None) => Some(format_ident!("{prefix}{name}")),
(Some(prefix), Some(suffix)) => Some(format_ident!("{prefix}{name}{suffix}")),
}
}
}
#[derive(Debug, ExtractAttributes)]
#[deluxe(attributes(gql))]
pub struct GraphqlField {
pub id: Option<Type>,
#[deluxe(default)]
pub single: FnOptions,
#[deluxe(default)]
pub multiple: FnOptions,
#[deluxe(default)]
pub history: FnOptions,
#[deluxe(with = deluxe::with::maybe_quoted)]
pub to_id_borrow: Option<Expr>,
}
#[derive(Debug, Default, ParseMetaItem)]
pub struct FnOptions {
pub name: Option<Ident>,
#[deluxe(with = deluxe::with::maybe_quoted)]
pub complexity: Option<Expr>,
}