cido-macros 0.2.0

Macros for generating code that enables easier interfacing with cido
Documentation
use crate::parse::util::{Attributes, SqlSafeName};
use deluxe::ParseMetaItem;
use quote::format_ident;
use syn::{Ident, TypePath};

#[derive(Debug, Clone, ParseMetaItem)]
#[must_use]
pub(super) struct TransformerParseOptions {
  pub cidomap: TypePath,
  #[deluxe(default)]
  pub db: TransformerDbParseOptions,
  pub sql_name: Option<SqlSafeName>,
  #[deluxe(default)]
  pub gql: TransformerGraphqlParseOptions,
  #[deluxe(default)]
  pub cache_policy: CachePolicyParse,
  pub embed_generated_code: deluxe::Flag,
}

impl TransformerParseOptions {
  pub fn into_opts(
    self,
    name: &Ident,
    struct_type: super::StructType,
  ) -> super::TransformerOptions {
    super::TransformerOptions {
      cidomap: self.cidomap,
      embed_generated_code: self.embed_generated_code.is_set(),
      db_opts: super::TransformerDbOptions {
        // name: self.db.name.unwrap_or_else(|| format_ident!("{name}Db")),
        name: name.clone(),
        // attrs: if self.db.attrs.is_empty() {
        //   Attributes::try_from(quote::quote!(derive(Debug, Default, Clone))).unwrap()
        // } else {
        //   self.db.attrs
        // },
        attrs: Attributes::try_from(quote::quote!(derive(Debug, Default, Clone))).unwrap(),
        partition_max_rows: self
          .db
          .partition
          .max_rows
          .unwrap_or(super::DEFAULT_PART_MAX_ROWS),
        partition_max_bytes: self
          .db
          .partition
          .max_bytes
          .unwrap_or(super::DEFAULT_PART_MAX_BYTES),
      },
      sql_name: self
        .sql_name
        .unwrap_or_else(|| SqlSafeName::new(name.to_string())),
      graphql_opts: super::TransformerGraphqlOptions {
        // name: self
        //   .gql
        //   .name
        //   .clone()
        //   .unwrap_or_else(|| format_ident!("{name}Gql")),
        name: format_ident!("{name}Gql"),
        // gql_name: self
        //   .gql
        //   .gql_name
        //   .or_else(|| self.gql.name.clone())
        //   .unwrap_or_else(|| format_ident!("{name}Gql")),
        gql_name: format_ident!("{name}Gql"),
        loader_cache_size: self
          .gql
          .loader
          .cache_size
          .unwrap_or(super::DEFAULT_DATALOADER_CACHE_SIZE),
        loader_delay_ms: self
          .gql
          .loader
          .delay_ms
          .unwrap_or(super::DEFAULT_DATALOADER_DELAY_MS),
        loader_max_batch_size: self
          .gql
          .loader
          .max_batch_size
          .unwrap_or(super::DEFAULT_DATALOADER_BATCH_SIZE),
        max_return_items: self
          .gql
          .paging
          .max_return_items
          .unwrap_or(super::DEFAULT_MAX_LOAD_ITEMS),
        max_skip_items: self
          .gql
          .paging
          .max_skip_items
          .unwrap_or(super::DEFAULT_MAX_SKIP_ITEMS),
        attrs: Attributes::try_from(quote::quote!(derive(Debug, Default))).unwrap(),
      },

      cache_policy: match self.cache_policy {
        CachePolicyParse::Default => struct_type.default_cache_policy(),
        CachePolicyParse::Always => super::CachePolicy::Always,
        CachePolicyParse::Block => super::CachePolicy::Block,
        CachePolicyParse::Never => super::CachePolicy::Never,
        CachePolicyParse::Custom => super::CachePolicy::Custom,
        CachePolicyParse::Lru(LruOpts { size, max_size }) => {
          let size = size.max(1000);
          super::CachePolicy::Lru {
            size,
            max_size: max_size.unwrap_or_else(|| size + (size / 10)).max(size),
          }
        }
      },
    }
  }
}

#[derive(Debug, Clone, Default, ParseMetaItem)]
pub(super) struct TransformerDbParseOptions {
  // #[deluxe(with = deluxe::with::maybe_quoted)]
  // pub name: Option<Ident>,
  // #[deluxe(default)]
  // pub attrs: Attributes,
  #[deluxe(default)]
  pub partition: TransformerDbParsePartitionOptions,
}

#[derive(Debug, Default, Clone, ParseMetaItem)]
pub(super) struct TransformerDbParsePartitionOptions {
  pub max_rows: Option<u64>,
  pub max_bytes: Option<u64>,
}

#[derive(Debug, Default, Clone, ParseMetaItem)]
pub(super) struct TransformerGraphqlParseOptions {
  // #[deluxe(with = deluxe::with::maybe_quoted)]
  // pub name: Option<Ident>,
  // #[deluxe(with = deluxe::with::maybe_quoted)]
  // pub gql_name: Option<Ident>,
  #[deluxe(default)]
  pub loader: TransformerGraphqlParseLoaderOptions,
  #[deluxe(default)]
  pub paging: TransformerGraphqlParsePagingOptions,
  // #[deluxe(default)]
  // pub attrs: Attributes,
}

#[derive(Debug, Default, Clone, ParseMetaItem)]
pub(super) struct TransformerGraphqlParseLoaderOptions {
  pub cache_size: Option<usize>,
  pub delay_ms: Option<u64>,
  pub max_batch_size: Option<usize>,
}

#[derive(Debug, Clone, Default, ParseMetaItem)]
pub(super) struct TransformerGraphqlParsePagingOptions {
  pub max_return_items: Option<u64>,
  pub max_skip_items: Option<u64>,
}

#[derive(Clone, Debug, Default)]
pub enum CachePolicyParse {
  #[default]
  Default,
  Always,
  Lru(LruOpts),
  Block,
  Never,
  Custom,
}

impl ParseMetaItem for CachePolicyParse {
  fn parse_meta_item(
    input: syn::parse::ParseStream,
    mode: deluxe::ParseMode,
  ) -> deluxe::Result<Self> {
    let ident = deluxe::with::maybe_quoted::parse_meta_item::<Ident>(input, mode)?;
    let name = ident.to_string();
    match name.as_str() {
      "always" => Ok(Self::Always),
      "lru" => {
        let opts = LruOpts::parse_meta_item(input, mode)?;
        Ok(Self::Lru(opts))
      }
      "block" => Ok(Self::Block),
      "never" => Ok(Self::Never),
      "custom" => Ok(Self::Custom),
      _ => Err(crate::err(&ident, "Unknown cache policy")),
    }
  }
}

#[derive(ParseMetaItem, Default, Clone, Debug)]
pub struct LruOpts {
  size: usize,
  max_size: Option<usize>,
}