cido-macros 0.2.0

Macros for generating code that enables easier interfacing with cido
Documentation
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,
}