use proc_macro::TokenStream;
use proc_macro2::Span;
use quote::{format_ident, quote};
use syn::{Error, ItemImpl, ItemTrait, parse_macro_input};
fn pluralize_single(word: &str) -> String {
if word.is_empty() {
return String::new();
}
let lower = word.to_lowercase();
let irregular: &[(&str, &str)] = &[
("child", "children"),
("person", "people"),
("man", "men"),
("woman", "women"),
("mouse", "mice"),
("goose", "geese"),
("foot", "feet"),
("tooth", "teeth"),
("ox", "oxen"),
("datum", "data"),
("index", "indices"),
("matrix", "matrices"),
("vertex", "vertices"),
("appendix", "appendices"),
("criterion", "criteria"),
("phenomenon", "phenomena"),
("medium", "media"),
("curriculum", "curricula"),
("die", "dice"),
];
for &(singular, plural) in irregular {
if lower == singular {
if word.chars().next().unwrap().is_uppercase() {
let mut chars = plural.chars();
let first = chars.next().unwrap().to_uppercase().to_string();
return format!("{}{}", first, chars.as_str());
}
return plural.to_string();
}
}
let uncountable = [
"sheep",
"fish",
"deer",
"species",
"series",
"aircraft",
"offspring",
"moose",
];
if uncountable.contains(&lower.as_str()) {
return word.to_string();
}
let fe_to_ves = ["knife", "life", "wife", "midwife"];
if fe_to_ves.contains(&lower.as_str()) {
let stem = &word[..word.len() - 2];
return format!("{}ves", stem);
}
let f_to_ves = [
"leaf", "half", "wolf", "shelf", "self", "calf", "loaf", "thief", "sheaf", "elf", "scarf",
];
if f_to_ves.contains(&lower.as_str()) {
let stem = &word[..word.len() - 1];
return format!("{}ves", stem);
}
if lower.ends_with("sis") || lower.ends_with("xis") {
return format!("{}es", &word[..word.len() - 2]);
}
let us_to_i = [
"focus", "radius", "fungus", "cactus", "stimulus", "syllabus", "nucleus", "alumnus",
];
if us_to_i.contains(&lower.as_str()) {
return format!("{}i", &word[..word.len() - 2]);
}
let o_to_oes = [
"hero", "potato", "tomato", "echo", "torpedo", "veto", "embargo", "volcano", "mosquito",
"cargo",
];
if o_to_oes.contains(&lower.as_str()) {
return format!("{}es", word);
}
if word.ends_with('y') && word.len() > 1 {
let second_last = word.chars().nth(word.len() - 2).unwrap();
if !"aeiou".contains(second_last) {
return format!("{}ies", &word[..word.len() - 1]);
}
}
if word.ends_with('s')
|| word.ends_with('x')
|| word.ends_with('z')
|| word.ends_with("ch")
|| word.ends_with("sh")
{
return format!("{}es", word);
}
format!("{}s", word)
}
fn to_plural(word: &str) -> String {
if word.is_empty() {
return String::new();
}
if let Some(pos) = word.rfind('_') {
let prefix = &word[..pos];
let last = &word[pos + 1..];
format!("{}_{}", prefix, pluralize_single(last))
} else {
pluralize_single(word)
}
}
pub fn uow_action_impl(args: TokenStream, input: TokenStream) -> TokenStream {
enum ItemType {
Trait(ItemTrait),
Impl(ItemImpl),
}
fn create_orphan_action(
entity_ident: &syn::Ident,
entity_snake_ident: &syn::Ident,
function_ident: &syn::Ident,
item_type: &ItemType,
thread_safe: bool,
) -> proc_macro2::TokenStream {
let create_entity_repo = format_ident!("create_{}_repository", entity_snake_ident);
match item_type {
ItemType::Trait(_) => {
quote! {
fn #function_ident(&self, #entity_snake_ident: &#entity_ident) -> Result<#entity_ident>;
}
}
ItemType::Impl(_) => {
if thread_safe {
quote! {
fn #function_ident(&self, #entity_snake_ident: &#entity_ident) -> Result<#entity_ident> {
use common::entities::#entity_ident;
use common::types::EntityId;
use common::direct_access::repository_factory;
let borrowed_transaction = self.transaction.lock().unwrap();
let mut repo = repository_factory::write::#create_entity_repo(
&borrowed_transaction.as_ref().expect("Transaction not started"),
)?;
let mut event_buffer = self.event_buffer.lock().unwrap();
let #entity_snake_ident = repo.create_orphan(&mut event_buffer, #entity_snake_ident)?;
Ok(#entity_snake_ident)
}
}
} else {
quote! {
fn #function_ident(&self, #entity_snake_ident: &#entity_ident) -> Result<#entity_ident> {
use common::entities::#entity_ident;
use common::types::EntityId;
use common::direct_access::repository_factory;
use std::borrow::Borrow;
let borrowed_transaction = self.transaction.borrow();
let mut repo = repository_factory::write::#create_entity_repo(
&borrowed_transaction.as_ref().expect("Transaction not started"),
)?;
let mut event_buffer = self.event_buffer.borrow_mut();
let #entity_snake_ident = repo.create_orphan(&mut event_buffer, #entity_snake_ident)?;
Ok(#entity_snake_ident)
}
}
}
}
}
}
fn create_action(
entity_ident: &syn::Ident,
entity_snake_ident: &syn::Ident,
function_ident: &syn::Ident,
item_type: &ItemType,
thread_safe: bool,
) -> proc_macro2::TokenStream {
let create_entity_repo = format_ident!("create_{}_repository", entity_snake_ident);
match item_type {
ItemType::Trait(_) => {
quote! {
fn #function_ident(&self, #entity_snake_ident: &#entity_ident, owner_id: EntityId, index: i32) -> Result<#entity_ident>;
}
}
ItemType::Impl(_) => {
if thread_safe {
quote! {
fn #function_ident(&self, #entity_snake_ident: &#entity_ident, owner_id: EntityId, index: i32) -> Result<#entity_ident> {
use common::entities::#entity_ident;
use common::types::EntityId;
use common::direct_access::repository_factory;
let borrowed_transaction = self.transaction.lock().unwrap();
let mut repo = repository_factory::write::#create_entity_repo(
&borrowed_transaction.as_ref().expect("Transaction not started"),
)?;
let mut event_buffer = self.event_buffer.lock().unwrap();
let #entity_snake_ident = repo.create(&mut event_buffer, #entity_snake_ident, owner_id, index)?;
Ok(#entity_snake_ident)
}
}
} else {
quote! {
fn #function_ident(&self, #entity_snake_ident: &#entity_ident, owner_id: EntityId, index: i32) -> Result<#entity_ident> {
use common::entities::#entity_ident;
use common::types::EntityId;
use common::direct_access::repository_factory;
use std::borrow::Borrow;
let borrowed_transaction = self.transaction.borrow();
let mut repo = repository_factory::write::#create_entity_repo(
&borrowed_transaction.as_ref().expect("Transaction not started"),
)?;
let mut event_buffer = self.event_buffer.borrow_mut();
let #entity_snake_ident = repo.create(&mut event_buffer, #entity_snake_ident, owner_id, index)?;
Ok(#entity_snake_ident)
}
}
}
}
}
}
fn create_orphan_multi_action(
entity_ident: &syn::Ident,
entity_snake_ident: &syn::Ident,
function_ident: &syn::Ident,
item_type: &ItemType,
thread_safe: bool,
) -> proc_macro2::TokenStream {
let create_entity_repo = format_ident!("create_{}_repository", entity_snake_ident);
let entity_snake_ident_str = entity_snake_ident.to_string();
let entity_snake_ident_plural = format_ident!("{}", to_plural(&entity_snake_ident_str));
match item_type {
ItemType::Trait(_) => {
quote! {
fn #function_ident(&self, #entity_snake_ident_plural: &[#entity_ident]) -> Result<Vec<#entity_ident>>;
}
}
ItemType::Impl(_) => {
if thread_safe {
quote! {
fn #function_ident(&self, #entity_snake_ident_plural: &[#entity_ident]) -> Result<Vec<#entity_ident>> {
use common::entities::#entity_ident;
use common::types::EntityId;
use common::direct_access::repository_factory;
let borrowed_transaction = self.transaction.lock().unwrap();
let mut repo = repository_factory::write::#create_entity_repo(
&borrowed_transaction.as_ref().expect("Transaction not started"),
)?;
let mut event_buffer = self.event_buffer.lock().unwrap();
let #entity_snake_ident_plural = repo.create_orphan_multi(&mut event_buffer, #entity_snake_ident_plural)?;
Ok(#entity_snake_ident_plural)
}
}
} else {
quote! {
fn #function_ident(&self, #entity_snake_ident_plural: &[#entity_ident]) -> Result<Vec<#entity_ident>> {
use common::entities::#entity_ident;
use common::types::EntityId;
use common::direct_access::repository_factory;
use std::borrow::Borrow;
let borrowed_transaction = self.transaction.borrow();
let mut repo = repository_factory::write::#create_entity_repo(
&borrowed_transaction.as_ref().expect("Transaction not started"),
)?;
let mut event_buffer = self.event_buffer.borrow_mut();
let #entity_snake_ident_plural = repo.create_orphan_multi(&mut event_buffer, #entity_snake_ident_plural)?;
Ok(#entity_snake_ident_plural)
}
}
}
}
}
}
fn create_multi_action(
entity_ident: &syn::Ident,
entity_snake_ident: &syn::Ident,
function_ident: &syn::Ident,
item_type: &ItemType,
thread_safe: bool,
) -> proc_macro2::TokenStream {
let create_entity_repo = format_ident!("create_{}_repository", entity_snake_ident);
let entity_snake_ident_str = entity_snake_ident.to_string();
let entity_snake_ident_plural = format_ident!("{}", to_plural(&entity_snake_ident_str));
match item_type {
ItemType::Trait(_) => {
quote! {
fn #function_ident(&self, #entity_snake_ident_plural: &[#entity_ident], owner_id: EntityId, index: i32) -> Result<Vec<#entity_ident>>;
}
}
ItemType::Impl(_) => {
if thread_safe {
quote! {
fn #function_ident(&self, #entity_snake_ident_plural: &[#entity_ident], owner_id: EntityId, index: i32) -> Result<Vec<#entity_ident>> {
use common::entities::#entity_ident;
use common::types::EntityId;
use common::direct_access::repository_factory;
let borrowed_transaction = self.transaction.lock().unwrap();
let mut repo = repository_factory::write::#create_entity_repo(
&borrowed_transaction.as_ref().expect("Transaction not started"),
)?;
let mut event_buffer = self.event_buffer.lock().unwrap();
let #entity_snake_ident_plural = repo.create_multi(&mut event_buffer, #entity_snake_ident_plural, owner_id, index)?;
Ok(#entity_snake_ident_plural)
}
}
} else {
quote! {
fn #function_ident(&self, #entity_snake_ident_plural: &[#entity_ident], owner_id: EntityId, index: i32) -> Result<Vec<#entity_ident>> {
use common::entities::#entity_ident;
use common::types::EntityId;
use common::direct_access::repository_factory;
use std::borrow::Borrow;
let borrowed_transaction = self.transaction.borrow();
let mut repo = repository_factory::write::#create_entity_repo(
&borrowed_transaction.as_ref().expect("Transaction not started"),
)?;
let mut event_buffer = self.event_buffer.borrow_mut();
let #entity_snake_ident_plural = repo.create_multi(&mut event_buffer, #entity_snake_ident_plural, owner_id, index)?;
Ok(#entity_snake_ident_plural)
}
}
}
}
}
}
fn get_action(
entity_ident: &syn::Ident,
entity_snake_ident: &syn::Ident,
function_ident: &syn::Ident,
item_type: &ItemType,
thread_safe: bool,
) -> proc_macro2::TokenStream {
let create_entity_repo = format_ident!("create_{}_repository", entity_snake_ident);
match item_type {
ItemType::Trait(_) => {
quote! {
fn #function_ident(&self, id: &EntityId) -> Result<Option<#entity_ident>>;
}
}
ItemType::Impl(_) => {
if thread_safe {
quote! {
fn #function_ident(&self, id: &EntityId) -> Result<Option<#entity_ident>> {
use common::entities::#entity_ident;
use common::types::EntityId;
use common::direct_access::repository_factory;
let borrowed_transaction = self.transaction.lock().unwrap();
let repo = repository_factory::write::#create_entity_repo(
&borrowed_transaction.as_ref().expect("Transaction not started"),
)?;
let #entity_snake_ident = repo.get(id)?;
Ok(#entity_snake_ident)
}
}
} else {
quote! {
fn #function_ident(&self, id: &EntityId) -> Result<Option<#entity_ident>> {
use common::entities::#entity_ident;
use common::types::EntityId;
use common::direct_access::repository_factory;
use std::borrow::Borrow;
let borrowed_transaction = self.transaction.borrow();
let repo = repository_factory::write::#create_entity_repo(
&borrowed_transaction.as_ref().expect("Transaction not started"),
)?;
let #entity_snake_ident = repo.get(id)?;
Ok(#entity_snake_ident)
}
}
}
}
}
}
fn update_action(
entity_ident: &syn::Ident,
entity_snake_ident: &syn::Ident,
function_ident: &syn::Ident,
item_type: &ItemType,
thread_safe: bool,
) -> proc_macro2::TokenStream {
let create_entity_repo = format_ident!("create_{}_repository", entity_snake_ident);
match item_type {
ItemType::Trait(_) => {
quote! {
fn #function_ident(&self, #entity_snake_ident: &#entity_ident) -> Result<#entity_ident>;
}
}
ItemType::Impl(_) => {
if thread_safe {
quote! {
fn #function_ident(&self, #entity_snake_ident: &#entity_ident) -> Result<#entity_ident> {
use common::entities::#entity_ident;
use common::types::EntityId;
use common::direct_access::repository_factory;
let borrowed_transaction = self.transaction.lock().unwrap();
let mut repo = repository_factory::write::#create_entity_repo(
&borrowed_transaction.as_ref().expect("Transaction not started"),
)?;
let mut event_buffer = self.event_buffer.lock().unwrap();
let #entity_snake_ident = repo.update(&mut event_buffer, #entity_snake_ident)?;
Ok(#entity_snake_ident)
}
}
} else {
quote! {
fn #function_ident(&self, #entity_snake_ident: &#entity_ident) -> Result<#entity_ident> {
use common::entities::#entity_ident;
use common::types::EntityId;
use common::direct_access::repository_factory;
use std::borrow::Borrow;
let borrowed_transaction = self.transaction.borrow();
let mut repo = repository_factory::write::#create_entity_repo(
&borrowed_transaction.as_ref().expect("Transaction not started"),
)?;
let mut event_buffer = self.event_buffer.borrow_mut();
let #entity_snake_ident = repo.update(&mut event_buffer, #entity_snake_ident)?;
Ok(#entity_snake_ident)
}
}
}
}
}
}
fn update_with_relationships_action(
entity_ident: &syn::Ident,
entity_snake_ident: &syn::Ident,
function_ident: &syn::Ident,
item_type: &ItemType,
thread_safe: bool,
) -> proc_macro2::TokenStream {
let create_entity_repo = format_ident!("create_{}_repository", entity_snake_ident);
match item_type {
ItemType::Trait(_) => {
quote! {
fn #function_ident(&self, #entity_snake_ident: &#entity_ident) -> Result<#entity_ident>;
}
}
ItemType::Impl(_) => {
if thread_safe {
quote! {
fn #function_ident(&self, #entity_snake_ident: &#entity_ident) -> Result<#entity_ident> {
use common::entities::#entity_ident;
use common::types::EntityId;
use common::direct_access::repository_factory;
let borrowed_transaction = self.transaction.lock().unwrap();
let mut repo = repository_factory::write::#create_entity_repo(
&borrowed_transaction.as_ref().expect("Transaction not started"),
)?;
let mut event_buffer = self.event_buffer.lock().unwrap();
let #entity_snake_ident = repo.update_with_relationships(&mut event_buffer, #entity_snake_ident)?;
Ok(#entity_snake_ident)
}
}
} else {
quote! {
fn #function_ident(&self, #entity_snake_ident: &#entity_ident) -> Result<#entity_ident> {
use common::entities::#entity_ident;
use common::types::EntityId;
use common::direct_access::repository_factory;
use std::borrow::Borrow;
let borrowed_transaction = self.transaction.borrow();
let mut repo = repository_factory::write::#create_entity_repo(
&borrowed_transaction.as_ref().expect("Transaction not started"),
)?;
let mut event_buffer = self.event_buffer.borrow_mut();
let #entity_snake_ident = repo.update_with_relationships(&mut event_buffer, #entity_snake_ident)?;
Ok(#entity_snake_ident)
}
}
}
}
}
}
fn update_with_relationships_multi_action(
entity_ident: &syn::Ident,
entity_snake_ident: &syn::Ident,
function_ident: &syn::Ident,
item_type: &ItemType,
thread_safe: bool,
) -> proc_macro2::TokenStream {
let create_entity_repo = format_ident!("create_{}_repository", entity_snake_ident);
let entity_snake_ident_str = entity_snake_ident.to_string();
let entity_snake_ident_plural = format_ident!("{}", to_plural(&entity_snake_ident_str));
match item_type {
ItemType::Trait(_) => {
quote! {
fn #function_ident(&self, #entity_snake_ident_plural: &[#entity_ident]) -> Result<Vec<#entity_ident>>;
}
}
ItemType::Impl(_) => {
if thread_safe {
quote! {
fn #function_ident(&self, #entity_snake_ident_plural: &[#entity_ident]) -> Result<Vec<#entity_ident>> {
use common::entities::#entity_ident;
use common::types::EntityId;
use std::borrow::Borrow;
use common::direct_access::repository_factory;
let borrowed_transaction = self.transaction.lock().unwrap();
let mut repo = repository_factory::write::#create_entity_repo(
&borrowed_transaction.as_ref().expect("Transaction not started"),
)?;
let mut event_buffer = self.event_buffer.lock().unwrap();
let #entity_snake_ident_plural = repo.update_with_relationships_multi(&mut event_buffer, #entity_snake_ident_plural)?;
Ok(#entity_snake_ident_plural)
}
}
} else {
quote! {
fn #function_ident(&self, #entity_snake_ident_plural: &[#entity_ident]) -> Result<Vec<#entity_ident>> {
use common::entities::#entity_ident;
use common::types::EntityId;
use std::borrow::Borrow;
use common::direct_access::repository_factory;
let borrowed_transaction = self.transaction.borrow();
let mut repo = repository_factory::write::#create_entity_repo(
&borrowed_transaction.as_ref().expect("Transaction not started"),
)?;
let mut event_buffer = self.event_buffer.borrow_mut();
let #entity_snake_ident_plural = repo.update_with_relationships_multi(&mut event_buffer, #entity_snake_ident_plural)?;
Ok(#entity_snake_ident_plural)
}
}
}
}
}
}
fn remove_action(
_entity_ident: &syn::Ident,
entity_snake_ident: &syn::Ident,
function_ident: &syn::Ident,
item_type: &ItemType,
thread_safe: bool,
) -> proc_macro2::TokenStream {
let create_entity_repo = format_ident!("create_{}_repository", entity_snake_ident);
match item_type {
ItemType::Trait(_) => {
quote! {
fn #function_ident(&self, id: &EntityId) -> Result<()>;
}
}
ItemType::Impl(_) => {
if thread_safe {
quote! {
fn #function_ident(&self, id: &EntityId) -> Result<()> {
use common::types::EntityId;
use common::direct_access::repository_factory;
let borrowed_transaction = self.transaction.lock().unwrap();
let mut repo = repository_factory::write::#create_entity_repo(
&borrowed_transaction.as_ref().expect("Transaction not started"),
)?;
let mut event_buffer = self.event_buffer.lock().unwrap();
repo.remove(&mut event_buffer, id)?;
Ok(())
}
}
} else {
quote! {
fn #function_ident(&self, id: &EntityId) -> Result<()> {
use common::types::EntityId;
use common::direct_access::repository_factory;
use std::borrow::Borrow;
let borrowed_transaction = self.transaction.borrow();
let mut repo = repository_factory::write::#create_entity_repo(
&borrowed_transaction.as_ref().expect("Transaction not started"),
)?;
let mut event_buffer = self.event_buffer.borrow_mut();
repo.remove(&mut event_buffer, id)?;
Ok(())
}
}
}
}
}
}
fn get_multi_action(
entity_ident: &syn::Ident,
entity_snake_ident: &syn::Ident,
function_ident: &syn::Ident,
item_type: &ItemType,
thread_safe: bool,
) -> proc_macro2::TokenStream {
let create_entity_repo = format_ident!("create_{}_repository", entity_snake_ident);
match item_type {
ItemType::Trait(_) => {
quote! {
fn #function_ident(&self, ids: &[EntityId]) -> Result<Vec<Option<#entity_ident>>>;
}
}
ItemType::Impl(_) => {
if thread_safe {
quote! {
fn #function_ident(&self, ids: &[EntityId]) -> Result<Vec<Option<#entity_ident>>> {
use common::entities::#entity_ident;
use common::types::EntityId;
use common::direct_access::repository_factory;
let borrowed_transaction = self.transaction.lock().unwrap();
let repo = repository_factory::write::#create_entity_repo(
&borrowed_transaction.as_ref().expect("Transaction not started"),
)?;
let value = repo.get_multi(ids)?;
Ok(value)
}
}
} else {
quote! {
fn #function_ident(&self, ids: &[EntityId]) -> Result<Vec<Option<#entity_ident>>> {
use common::entities::#entity_ident;
use common::types::EntityId;
use common::direct_access::repository_factory;
use std::borrow::Borrow;
let borrowed_transaction = self.transaction.borrow();
let repo = repository_factory::write::#create_entity_repo(
&borrowed_transaction.as_ref().expect("Transaction not started"),
)?;
let value = repo.get_multi(ids)?;
Ok(value)
}
}
}
}
}
}
fn get_all_action(
entity_ident: &syn::Ident,
entity_snake_ident: &syn::Ident,
function_ident: &syn::Ident,
item_type: &ItemType,
thread_safe: bool,
) -> proc_macro2::TokenStream {
let create_entity_repo = format_ident!("create_{}_repository", entity_snake_ident);
match item_type {
ItemType::Trait(_) => {
quote! {
fn #function_ident(&self) -> Result<Vec<#entity_ident>>;
}
}
ItemType::Impl(_) => {
if thread_safe {
quote! {
fn #function_ident(&self) -> Result<Vec<#entity_ident>> {
use common::entities::#entity_ident;
use common::direct_access::repository_factory;
let borrowed_transaction = self.transaction.lock().unwrap();
let repo = repository_factory::write::#create_entity_repo(
&borrowed_transaction.as_ref().expect("Transaction not started"),
)?;
let value = repo.get_all()?;
Ok(value)
}
}
} else {
quote! {
fn #function_ident(&self) -> Result<Vec<#entity_ident>> {
use common::entities::#entity_ident;
use common::direct_access::repository_factory;
use std::borrow::Borrow;
let borrowed_transaction = self.transaction.borrow();
let repo = repository_factory::write::#create_entity_repo(
&borrowed_transaction.as_ref().expect("Transaction not started"),
)?;
let value = repo.get_all()?;
Ok(value)
}
}
}
}
}
}
fn update_multi_action(
entity_ident: &syn::Ident,
entity_snake_ident: &syn::Ident,
function_ident: &syn::Ident,
item_type: &ItemType,
thread_safe: bool,
) -> proc_macro2::TokenStream {
let create_entity_repo = format_ident!("create_{}_repository", entity_snake_ident);
let entity_snake_ident_str = entity_snake_ident.to_string();
let entity_snake_ident_plural = format_ident!("{}", to_plural(&entity_snake_ident_str));
match item_type {
ItemType::Trait(_) => {
quote! {
fn #function_ident(&self, #entity_snake_ident_plural: &[#entity_ident]) -> Result<Vec<#entity_ident>>;
}
}
ItemType::Impl(_) => {
if thread_safe {
quote! {
fn #function_ident(&self, #entity_snake_ident_plural: &[#entity_ident]) -> Result<Vec<#entity_ident>> {
use common::entities::#entity_ident;
use common::types::EntityId;
use std::borrow::Borrow;
use common::direct_access::repository_factory;
let borrowed_transaction = self.transaction.lock().unwrap();
let mut repo = repository_factory::write::#create_entity_repo(
&borrowed_transaction.as_ref().expect("Transaction not started"),
)?;
let mut event_buffer = self.event_buffer.lock().unwrap();
let #entity_snake_ident_plural = repo.update_multi(&mut event_buffer, #entity_snake_ident_plural)?;
Ok(#entity_snake_ident_plural)
}
}
} else {
quote! {
fn #function_ident(&self, #entity_snake_ident_plural: &[#entity_ident]) -> Result<Vec<#entity_ident>> {
use common::entities::#entity_ident;
use common::types::EntityId;
use std::borrow::Borrow;
use common::direct_access::repository_factory;
let borrowed_transaction = self.transaction.borrow();
let mut repo = repository_factory::write::#create_entity_repo(
&borrowed_transaction.as_ref().expect("Transaction not started"),
)?;
let mut event_buffer = self.event_buffer.borrow_mut();
let #entity_snake_ident_plural = repo.update_multi(&mut event_buffer, #entity_snake_ident_plural)?;
Ok(#entity_snake_ident_plural)
}
}
}
}
}
}
fn remove_multi_action(
_entity_ident: &syn::Ident,
entity_snake_ident: &syn::Ident,
function_ident: &syn::Ident,
item_type: &ItemType,
thread_safe: bool,
) -> proc_macro2::TokenStream {
let create_entity_repo = format_ident!("create_{}_repository", entity_snake_ident);
match item_type {
ItemType::Trait(_) => {
quote! {
fn #function_ident(&self, ids: &[EntityId]) -> Result<()>;
}
}
ItemType::Impl(_) => {
if thread_safe {
quote! {
fn #function_ident(&self, ids: &[EntityId]) -> Result<()> {
use common::types::EntityId;
use common::direct_access::repository_factory;
let borrowed_transaction = self.transaction.lock().unwrap();
let mut repo = repository_factory::write::#create_entity_repo(
&borrowed_transaction.as_ref().expect("Transaction not started"),
)?;
let mut event_buffer = self.event_buffer.lock().unwrap();
repo.remove_multi(&mut event_buffer, ids)?;
Ok(())
}
}
} else {
quote! {
fn #function_ident(&self, ids: &[EntityId]) -> Result<()> {
use common::types::EntityId;
use common::direct_access::repository_factory;
use std::borrow::Borrow;
let borrowed_transaction = self.transaction.borrow();
let mut repo = repository_factory::write::#create_entity_repo(
&borrowed_transaction.as_ref().expect("Transaction not started"),
)?;
let mut event_buffer = self.event_buffer.borrow_mut();
repo.remove_multi(&mut event_buffer, ids)?;
Ok(())
}
}
}
}
}
}
fn get_ro_action(
entity_ident: &syn::Ident,
entity_snake_ident: &syn::Ident,
function_ident: &syn::Ident,
item_type: &ItemType,
thread_safe: bool,
) -> proc_macro2::TokenStream {
let create_entity_repo = format_ident!("create_{}_repository", entity_snake_ident);
match item_type {
ItemType::Trait(_) => {
quote! {
fn #function_ident(&self, id: &EntityId) -> Result<Option<#entity_ident>>;
}
}
ItemType::Impl(_) => {
if thread_safe {
quote! {
fn #function_ident(&self, id: &EntityId) -> Result<Option<#entity_ident>> {
use common::entities::#entity_ident;
use common::types::EntityId;
use common::direct_access::repository_factory;
use std::borrow::Borrow;
let borrowed_transaction = self.transaction.lock().unwrap();
let repo = repository_factory::read::#create_entity_repo(
&borrowed_transaction.as_ref().expect("Transaction not started"),
)?;
let #entity_snake_ident = repo.get(id)?;
Ok(#entity_snake_ident)
}
}
} else {
quote! {
fn #function_ident(&self, id: &EntityId) -> Result<Option<#entity_ident>> {
use common::entities::#entity_ident;
use common::types::EntityId;
use common::direct_access::repository_factory;
use std::borrow::Borrow;
let borrowed_transaction = self.transaction.borrow();
let repo = repository_factory::read::#create_entity_repo(
&borrowed_transaction.as_ref().expect("Transaction not started"),
)?;
let #entity_snake_ident = repo.get(id)?;
Ok(#entity_snake_ident)
}
}
}
}
}
}
fn get_multi_ro_action(
entity_ident: &syn::Ident,
entity_snake_ident: &syn::Ident,
function_ident: &syn::Ident,
item_type: &ItemType,
thread_safe: bool,
) -> proc_macro2::TokenStream {
let create_entity_repo = format_ident!("create_{}_repository", entity_snake_ident);
match item_type {
ItemType::Trait(_) => {
quote! {
fn #function_ident(&self, ids: &[EntityId]) -> Result<Vec<Option<#entity_ident>>>;
}
}
ItemType::Impl(_) => {
if thread_safe {
quote! {
fn #function_ident(&self, ids: &[EntityId]) -> Result<Vec<Option<#entity_ident>>> {
use common::entities::#entity_ident;
use common::types::EntityId;
use common::direct_access::repository_factory;
let borrowed_transaction = self.transaction.lock().unwrap();
let repo = repository_factory::read::#create_entity_repo(
&borrowed_transaction.as_ref().expect("Transaction not started"),
)?;
let value = repo.get_multi(ids)?;
Ok(value)
}
}
} else {
quote! {
fn #function_ident(&self, ids: &[EntityId]) -> Result<Vec<Option<#entity_ident>>> {
use common::entities::#entity_ident;
use common::types::EntityId;
use common::direct_access::repository_factory;
use std::borrow::Borrow;
let borrowed_transaction = self.transaction.borrow();
let repo = repository_factory::read::#create_entity_repo(
&borrowed_transaction.as_ref().expect("Transaction not started"),
)?;
let value = repo.get_multi(ids)?;
Ok(value)
}
}
}
}
}
}
fn get_all_ro_action(
entity_ident: &syn::Ident,
entity_snake_ident: &syn::Ident,
function_ident: &syn::Ident,
item_type: &ItemType,
thread_safe: bool,
) -> proc_macro2::TokenStream {
let create_entity_repo = format_ident!("create_{}_repository", entity_snake_ident);
match item_type {
ItemType::Trait(_) => {
quote! {
fn #function_ident(&self) -> Result<Vec<#entity_ident>>;
}
}
ItemType::Impl(_) => {
if thread_safe {
quote! {
fn #function_ident(&self) -> Result<Vec<#entity_ident>> {
use common::entities::#entity_ident;
use common::direct_access::repository_factory;
let borrowed_transaction = self.transaction.lock().unwrap();
let repo = repository_factory::read::#create_entity_repo(
&borrowed_transaction.as_ref().expect("Transaction not started"),
)?;
let value = repo.get_all()?;
Ok(value)
}
}
} else {
quote! {
fn #function_ident(&self) -> Result<Vec<#entity_ident>> {
use common::entities::#entity_ident;
use common::direct_access::repository_factory;
use std::borrow::Borrow;
let borrowed_transaction = self.transaction.borrow();
let repo = repository_factory::read::#create_entity_repo(
&borrowed_transaction.as_ref().expect("Transaction not started"),
)?;
let value = repo.get_all()?;
Ok(value)
}
}
}
}
}
}
fn get_relationship_action(
entity_ident: &syn::Ident,
entity_snake_ident: &syn::Ident,
function_ident: &syn::Ident,
item_type: &ItemType,
thread_safe: bool,
) -> proc_macro2::TokenStream {
let create_entity_repo = format_ident!("create_{}_repository", entity_snake_ident);
let relationship_field_type = format_ident!("{}RelationshipField", entity_ident);
match item_type {
ItemType::Trait(_) => {
quote! {
fn #function_ident(
&self,
id: &EntityId,
field: &common::direct_access::#entity_snake_ident::#relationship_field_type,
) -> Result<Vec<EntityId>>;
}
}
ItemType::Impl(_) => {
if thread_safe {
quote! {
fn #function_ident(
&self,
id: &EntityId,
field: &common::direct_access::#entity_snake_ident::#relationship_field_type,
) -> Result<Vec<EntityId>> {
use common::types::EntityId;
use common::direct_access::repository_factory;
use common::direct_access::#entity_snake_ident::#relationship_field_type;
let borrowed_transaction = self.transaction.lock().unwrap();
let mut repo = repository_factory::write::#create_entity_repo(
&borrowed_transaction.as_ref().expect("Transaction not started"),
)?;
let value = repo.get_relationship(id, field)?;
Ok(value)
}
}
} else {
quote! {
fn #function_ident(
&self,
id: &EntityId,
field: &common::direct_access::#entity_snake_ident::#relationship_field_type,
) -> Result<Vec<EntityId>> {
use common::types::EntityId;
use common::direct_access::repository_factory;
use common::direct_access::#entity_snake_ident::#relationship_field_type;
use std::borrow::Borrow;
let borrowed_transaction = self.transaction.borrow();
let mut repo = repository_factory::write::#create_entity_repo(
&borrowed_transaction.as_ref().expect("Transaction not started"),
)?;
let value = repo.get_relationship(id, field)?;
Ok(value)
}
}
}
}
}
}
fn get_relationships_from_right_ids_action(
entity_ident: &syn::Ident,
entity_snake_ident: &syn::Ident,
function_ident: &syn::Ident,
item_type: &ItemType,
thread_safe: bool,
) -> proc_macro2::TokenStream {
let create_entity_repo = format_ident!("create_{}_repository", entity_snake_ident);
let relationship_field_type = format_ident!("{}RelationshipField", entity_ident);
match item_type {
ItemType::Trait(_) => {
quote! {
fn #function_ident(
&self,
field: &common::direct_access::#entity_snake_ident::#relationship_field_type,
right_ids: &[EntityId],
) -> Result<Vec<(EntityId, Vec<EntityId>)>>;
}
}
ItemType::Impl(_) => {
if thread_safe {
quote! {
fn #function_ident(
&self,
field: &common::direct_access::#entity_snake_ident::#relationship_field_type,
right_ids: &[EntityId],
) -> Result<Vec<(EntityId, Vec<EntityId>)>> {
use common::types::EntityId;
use common::direct_access::repository_factory;
use common::direct_access::#entity_snake_ident::#relationship_field_type;
let borrowed_transaction = self.transaction.lock().unwrap();
let repo = repository_factory::write::#create_entity_repo(
&borrowed_transaction.as_ref().expect("Transaction not started"),
)?;
let value = repo.get_relationships_from_right_ids(field, right_ids)?;
Ok(value)
}
}
} else {
quote! {
fn #function_ident(
&self,
field: &common::direct_access::#entity_snake_ident::#relationship_field_type,
right_ids: &[EntityId],
) -> Result<Vec<(EntityId, Vec<EntityId>)>> {
use common::types::EntityId;
use common::direct_access::repository_factory;
use common::direct_access::#entity_snake_ident::#relationship_field_type;
use std::borrow::Borrow;
let borrowed_transaction = self.transaction.borrow();
let repo = repository_factory::write::#create_entity_repo(
&borrowed_transaction.as_ref().expect("Transaction not started"),
)?;
let value = repo.get_relationships_from_right_ids(field, right_ids)?;
Ok(value)
}
}
}
}
}
}
fn get_relationship_ro_action(
entity_ident: &syn::Ident,
entity_snake_ident: &syn::Ident,
function_ident: &syn::Ident,
item_type: &ItemType,
thread_safe: bool,
) -> proc_macro2::TokenStream {
let create_entity_repo = format_ident!("create_{}_repository", entity_snake_ident);
let relationship_field_type = format_ident!("{}RelationshipField", entity_ident);
match item_type {
ItemType::Trait(_) => {
quote! {
fn #function_ident(
&self,
id: &EntityId,
field: &common::direct_access::#entity_snake_ident::#relationship_field_type,
) -> Result<Vec<EntityId>>;
}
}
ItemType::Impl(_) => {
if thread_safe {
quote! {
fn #function_ident(
&self,
id: &EntityId,
field: &common::direct_access::#entity_snake_ident::#relationship_field_type,
) -> Result<Vec<EntityId>> {
use common::types::EntityId;
use common::direct_access::repository_factory;
use common::direct_access::#entity_snake_ident::#relationship_field_type;
let borrowed_transaction = self.transaction.lock().unwrap();
let repo = repository_factory::read::#create_entity_repo(
&borrowed_transaction.as_ref().expect("Transaction not started"),
)?;
let value = repo.get_relationship(id, field)?;
Ok(value)
}
}
} else {
quote! {
fn #function_ident(
&self,
id: &EntityId,
field: &common::direct_access::#entity_snake_ident::#relationship_field_type,
) -> Result<Vec<EntityId>> {
use common::types::EntityId;
use common::direct_access::repository_factory;
use common::direct_access::#entity_snake_ident::#relationship_field_type;
use std::borrow::Borrow;
let borrowed_transaction = self.transaction.borrow();
let repo = repository_factory::read::#create_entity_repo(
&borrowed_transaction.as_ref().expect("Transaction not started"),
)?;
let value = repo.get_relationship(id, field)?;
Ok(value)
}
}
}
}
}
}
fn get_relationships_from_right_ids_ro_action(
entity_ident: &syn::Ident,
entity_snake_ident: &syn::Ident,
function_ident: &syn::Ident,
item_type: &ItemType,
thread_safe: bool,
) -> proc_macro2::TokenStream {
let create_entity_repo = format_ident!("create_{}_repository", entity_snake_ident);
let relationship_field_type = format_ident!("{}RelationshipField", entity_ident);
match item_type {
ItemType::Trait(_) => {
quote! {
fn #function_ident(
&self,
field: &common::direct_access::#entity_snake_ident::#relationship_field_type,
right_ids: &[EntityId],
) -> Result<Vec<(EntityId, Vec<EntityId>)>>;
}
}
ItemType::Impl(_) => {
if thread_safe {
quote! {
fn #function_ident(
&self,
field: &common::direct_access::#entity_snake_ident::#relationship_field_type,
right_ids: &[EntityId],
) -> Result<Vec<(EntityId, Vec<EntityId>)>> {
use common::types::EntityId;
use common::direct_access::repository_factory;
use common::direct_access::#entity_snake_ident::#relationship_field_type;
let borrowed_transaction = self.transaction.lock().unwrap();
let repo = repository_factory::read::#create_entity_repo(
&borrowed_transaction.as_ref().expect("Transaction not started"),
)?;
let value = repo.get_relationships_from_right_ids(field, right_ids)?;
Ok(value)
}
}
} else {
quote! {
fn #function_ident(
&self,
field: &common::direct_access::#entity_snake_ident::#relationship_field_type,
right_ids: &[EntityId],
) -> Result<Vec<(EntityId, Vec<EntityId>)>> {
use common::types::EntityId;
use common::direct_access::repository_factory;
use common::direct_access::#entity_snake_ident::#relationship_field_type;
use std::borrow::Borrow;
let borrowed_transaction = self.transaction.borrow();
let repo = repository_factory::read::#create_entity_repo(
&borrowed_transaction.as_ref().expect("Transaction not started"),
)?;
let value = repo.get_relationships_from_right_ids(field, right_ids)?;
Ok(value)
}
}
}
}
}
}
fn set_relationship_action(
entity_ident: &syn::Ident,
entity_snake_ident: &syn::Ident,
function_ident: &syn::Ident,
item_type: &ItemType,
thread_safe: bool,
) -> proc_macro2::TokenStream {
let create_entity_repo = format_ident!("create_{}_repository", entity_snake_ident);
let relationship_field_type = format_ident!("{}RelationshipField", entity_ident);
match item_type {
ItemType::Trait(_) => {
quote! {
fn #function_ident(
&self,
id: &EntityId,
field: &common::direct_access::#entity_snake_ident::#relationship_field_type,
right_ids: &[EntityId],
) -> Result<()>;
}
}
ItemType::Impl(_) => {
if thread_safe {
quote! {
fn #function_ident(
&self,
id: &EntityId,
field: &common::direct_access::#entity_snake_ident::#relationship_field_type,
right_ids: &[EntityId],
) -> Result<()> {
use common::types::EntityId;
use common::direct_access::repository_factory;
use common::direct_access::#entity_snake_ident::#relationship_field_type;
let borrowed_transaction = self.transaction.lock().unwrap();
let mut repo = repository_factory::write::#create_entity_repo(
&borrowed_transaction.as_ref().expect("Transaction not started"),
)?;
let mut event_buffer = self.event_buffer.lock().unwrap();
repo.set_relationship(&mut event_buffer, id, field, right_ids)?;
Ok(())
}
}
} else {
quote! {
fn #function_ident(
&self,
id: &EntityId,
field: &common::direct_access::#entity_snake_ident::#relationship_field_type,
right_ids: &[EntityId],
) -> Result<()> {
use common::types::EntityId;
use common::direct_access::repository_factory;
use common::direct_access::#entity_snake_ident::#relationship_field_type;
use std::borrow::Borrow;
let borrowed_transaction = self.transaction.borrow();
let mut repo = repository_factory::write::#create_entity_repo(
&borrowed_transaction.as_ref().expect("Transaction not started"),
)?;
let mut event_buffer = self.event_buffer.borrow_mut();
repo.set_relationship(&mut event_buffer, id, field, right_ids)?;
Ok(())
}
}
}
}
}
}
fn set_relationship_multi_action(
entity_ident: &syn::Ident,
entity_snake_ident: &syn::Ident,
function_ident: &syn::Ident,
item_type: &ItemType,
thread_safe: bool,
) -> proc_macro2::TokenStream {
let create_entity_repo = format_ident!("create_{}_repository", entity_snake_ident);
let relationship_field_type = format_ident!("{}RelationshipField", entity_ident);
match item_type {
ItemType::Trait(_) => {
quote! {
fn #function_ident(
&self,
field: &common::direct_access::#entity_snake_ident::#relationship_field_type,
relationships: Vec<(EntityId, Vec<EntityId>)>,
) -> Result<()>;
}
}
ItemType::Impl(_) => {
if thread_safe {
quote! {
fn #function_ident(
&self,
field: &common::direct_access::#entity_snake_ident::#relationship_field_type,
relationships: Vec<(EntityId, Vec<EntityId>)>,
) -> Result<()> {
use common::types::EntityId;
use common::direct_access::repository_factory;
use common::direct_access::#entity_snake_ident::#relationship_field_type;
let borrowed_transaction = self.transaction.lock().unwrap();
let mut repo = repository_factory::write::#create_entity_repo(
&borrowed_transaction.as_ref().expect("Transaction not started"),
)?;
let mut event_buffer = self.event_buffer.lock().unwrap();
repo.set_relationship_multi(&mut event_buffer, field, relationships)?;
Ok(())
}
}
} else {
quote! {
fn #function_ident(
&self,
field: &common::direct_access::#entity_snake_ident::#relationship_field_type,
relationships: Vec<(EntityId, Vec<EntityId>)>,
) -> Result<()> {
use common::types::EntityId;
use common::direct_access::repository_factory;
use common::direct_access::#entity_snake_ident::#relationship_field_type;
use std::borrow::Borrow;
let borrowed_transaction = self.transaction.borrow();
let mut repo = repository_factory::write::#create_entity_repo(
&borrowed_transaction.as_ref().expect("Transaction not started"),
)?;
let mut event_buffer = self.event_buffer.borrow_mut();
repo.set_relationship_multi(&mut event_buffer, field, relationships)?;
Ok(())
}
}
}
}
}
}
fn move_relationship_action(
entity_ident: &syn::Ident,
entity_snake_ident: &syn::Ident,
function_ident: &syn::Ident,
item_type: &ItemType,
thread_safe: bool,
) -> proc_macro2::TokenStream {
let create_entity_repo = format_ident!("create_{}_repository", entity_snake_ident);
let relationship_field_type = format_ident!("{}RelationshipField", entity_ident);
match item_type {
ItemType::Trait(_) => {
quote! {
fn #function_ident(
&self,
id: &EntityId,
field: &common::direct_access::#entity_snake_ident::#relationship_field_type,
ids_to_move: &[EntityId],
new_index: i32,
) -> Result<Vec<EntityId>>;
}
}
ItemType::Impl(_) => {
if thread_safe {
quote! {
fn #function_ident(
&self,
id: &EntityId,
field: &common::direct_access::#entity_snake_ident::#relationship_field_type,
ids_to_move: &[EntityId],
new_index: i32,
) -> Result<Vec<EntityId>> {
use common::types::EntityId;
use common::direct_access::repository_factory;
use common::direct_access::#entity_snake_ident::#relationship_field_type;
let borrowed_transaction = self.transaction.lock().unwrap();
let mut repo = repository_factory::write::#create_entity_repo(
&borrowed_transaction.as_ref().expect("Transaction not started"),
)?;
let mut event_buffer = self.event_buffer.lock().unwrap();
Ok(repo.move_relationship_ids(&mut event_buffer, id, field, ids_to_move, new_index)?)
}
}
} else {
quote! {
fn #function_ident(
&self,
id: &EntityId,
field: &common::direct_access::#entity_snake_ident::#relationship_field_type,
ids_to_move: &[EntityId],
new_index: i32,
) -> Result<Vec<EntityId>> {
use common::types::EntityId;
use common::direct_access::repository_factory;
use common::direct_access::#entity_snake_ident::#relationship_field_type;
use std::borrow::Borrow;
let borrowed_transaction = self.transaction.borrow();
let mut repo = repository_factory::write::#create_entity_repo(
&borrowed_transaction.as_ref().expect("Transaction not started"),
)?;
let mut event_buffer = self.event_buffer.borrow_mut();
Ok(repo.move_relationship_ids(&mut event_buffer, id, field, ids_to_move, new_index)?)
}
}
}
}
}
}
fn snapshot_action(
_entity_ident: &syn::Ident,
entity_snake_ident: &syn::Ident,
function_ident: &syn::Ident,
item_type: &ItemType,
thread_safe: bool,
) -> proc_macro2::TokenStream {
let create_entity_repo = format_ident!("create_{}_repository", entity_snake_ident);
match item_type {
ItemType::Trait(_) => {
quote! {
fn #function_ident(&self, ids: &[EntityId]) -> Result<common::snapshot::EntityTreeSnapshot>;
}
}
ItemType::Impl(_) => {
if thread_safe {
quote! {
fn #function_ident(&self, ids: &[EntityId]) -> Result<common::snapshot::EntityTreeSnapshot> {
use common::types::EntityId;
use common::direct_access::repository_factory;
let borrowed_transaction = self.transaction.lock().unwrap();
let repo = repository_factory::write::#create_entity_repo(
&borrowed_transaction.as_ref().expect("Transaction not started"),
)?;
let snapshot = repo.snapshot(ids)?;
Ok(snapshot)
}
}
} else {
quote! {
fn #function_ident(&self, ids: &[EntityId]) -> Result<common::snapshot::EntityTreeSnapshot> {
use common::types::EntityId;
use common::direct_access::repository_factory;
use std::borrow::Borrow;
let borrowed_transaction = self.transaction.borrow();
let repo = repository_factory::write::#create_entity_repo(
&borrowed_transaction.as_ref().expect("Transaction not started"),
)?;
let snapshot = repo.snapshot(ids)?;
Ok(snapshot)
}
}
}
}
}
}
fn restore_action(
_entity_ident: &syn::Ident,
entity_snake_ident: &syn::Ident,
function_ident: &syn::Ident,
item_type: &ItemType,
thread_safe: bool,
) -> proc_macro2::TokenStream {
let create_entity_repo = format_ident!("create_{}_repository", entity_snake_ident);
match item_type {
ItemType::Trait(_) => {
quote! {
fn #function_ident(&self, snap: &common::snapshot::EntityTreeSnapshot) -> Result<()>;
}
}
ItemType::Impl(_) => {
if thread_safe {
quote! {
fn #function_ident(&self, snap: &common::snapshot::EntityTreeSnapshot) -> Result<()> {
use common::direct_access::repository_factory;
let borrowed_transaction = self.transaction.lock().unwrap();
let mut repo = repository_factory::write::#create_entity_repo(
&borrowed_transaction.as_ref().expect("Transaction not started"),
)?;
let mut event_buffer = self.event_buffer.lock().unwrap();
repo.restore(&mut event_buffer, snap)?;
Ok(())
}
}
} else {
quote! {
fn #function_ident(&self, snap: &common::snapshot::EntityTreeSnapshot) -> Result<()> {
use common::direct_access::repository_factory;
use std::borrow::Borrow;
let borrowed_transaction = self.transaction.borrow();
let mut repo = repository_factory::write::#create_entity_repo(
&borrowed_transaction.as_ref().expect("Transaction not started"),
)?;
let mut event_buffer = self.event_buffer.borrow_mut();
repo.restore(&mut event_buffer, snap)?;
Ok(())
}
}
}
}
}
}
let args = parse_macro_input!(args with syn::punctuated::Punctuated::<syn::Meta, syn::Token![,]>::parse_terminated);
let mut entity_name = None;
let mut action = None;
let mut thread_safe = false;
for arg in args.iter() {
if let syn::Meta::NameValue(nv) = arg {
if nv.path.is_ident("entity")
&& let syn::Expr::Lit(expr_lit) = &nv.value
&& let syn::Lit::Str(litstr) = &expr_lit.lit
{
entity_name = Some(litstr.value());
}
if nv.path.is_ident("action")
&& let syn::Expr::Lit(expr_lit) = &nv.value
&& let syn::Lit::Str(litstr) = &expr_lit.lit
{
action = Some(litstr.value());
}
if nv.path.is_ident("thread_safe")
&& let syn::Expr::Lit(expr_lit) = &nv.value
&& let syn::Lit::Bool(litbool) = &expr_lit.lit
{
thread_safe = litbool.value();
}
} else if let syn::Meta::Path(path) = arg
&& path.is_ident("thread_safe")
{
thread_safe = true;
}
}
let entity_name = match entity_name {
Some(e) => e,
None => {
let err = match args.first() {
Some(first) => Error::new_spanned(first, "Missing 'entity' argument"),
None => Error::new(Span::call_site(), "Missing 'entity' argument"),
};
return err.to_compile_error().into();
}
};
let action = match action {
Some(a) => a,
None => {
let err = match args.first() {
Some(first) => Error::new_spanned(first, "Missing 'action' argument"),
None => Error::new(Span::call_site(), "Missing 'action' argument"),
};
return err.to_compile_error().into();
}
};
let item_type = if let Ok(item_trait) = syn::parse::<ItemTrait>(input.clone()) {
ItemType::Trait(item_trait)
} else {
ItemType::Impl(parse_macro_input!(input as ItemImpl))
};
let entity_name_snake_case = heck::AsSnakeCase(&entity_name).to_string();
let function_name = match action.as_str() {
"CreateOrphan" => format!("create_orphan_{}", entity_name_snake_case),
"CreateOrphanMulti" => format!("create_orphan_{}_multi", entity_name_snake_case),
"Create" => format!("create_{}", entity_name_snake_case),
"CreateMulti" => format!("create_{}_multi", entity_name_snake_case),
"Get" => format!("get_{}", entity_name_snake_case),
"GetMulti" => format!("get_{}_multi", entity_name_snake_case),
"GetAll" => format!("get_all_{}", entity_name_snake_case),
"Update" => format!("update_{}", entity_name_snake_case),
"UpdateMulti" => format!("update_{}_multi", entity_name_snake_case),
"UpdateWithRelationships" => {
format!("update_{}_with_relationships", entity_name_snake_case)
}
"UpdateWithRelationshipsMulti" => {
format!("update_{}_with_relationships_multi", entity_name_snake_case)
}
"Remove" => format!("remove_{}", entity_name_snake_case),
"RemoveMulti" => format!("remove_{}_multi", entity_name_snake_case),
"GetRO" => format!("get_{}", entity_name_snake_case),
"GetMultiRO" => format!("get_{}_multi", entity_name_snake_case),
"GetAllRO" => format!("get_all_{}", entity_name_snake_case),
"GetRelationship" => format!("get_{}_relationship", entity_name_snake_case),
"GetRelationshipRO" => format!("get_{}_relationship", entity_name_snake_case),
"GetRelationshipsFromRightIds" => {
format!(
"get_{}_relationships_from_right_ids",
entity_name_snake_case
)
}
"GetRelationshipsFromRightIdsRO" => {
format!(
"get_{}_relationships_from_right_ids",
entity_name_snake_case
)
}
"SetRelationship" => format!("set_{}_relationship", entity_name_snake_case),
"SetRelationshipMulti" => format!("set_{}_relationship_multi", entity_name_snake_case),
"MoveRelationship" => format!("move_{}_relationship", entity_name_snake_case),
"Snapshot" => format!("snapshot_{}", entity_name_snake_case),
"Restore" => format!("restore_{}", entity_name_snake_case),
_ => {
let err = match args.first() {
Some(first) => Error::new_spanned(first, "Unknown action"),
None => Error::new(Span::call_site(), "Unknown action"),
};
return err.to_compile_error().into();
}
};
let function_ident = syn::Ident::new(&function_name, proc_macro2::Span::call_site());
let entity_ident = syn::Ident::new(&entity_name, proc_macro2::Span::call_site());
let entity_snake_ident =
syn::Ident::new(&entity_name_snake_case, proc_macro2::Span::call_site());
let method_tokens = match action.as_str() {
"CreateOrphan" => create_orphan_action(
&entity_ident,
&entity_snake_ident,
&function_ident,
&item_type,
thread_safe,
),
"CreateOrphanMulti" => create_orphan_multi_action(
&entity_ident,
&entity_snake_ident,
&function_ident,
&item_type,
thread_safe,
),
"Create" => create_action(
&entity_ident,
&entity_snake_ident,
&function_ident,
&item_type,
thread_safe,
),
"CreateMulti" => create_multi_action(
&entity_ident,
&entity_snake_ident,
&function_ident,
&item_type,
thread_safe,
),
"Get" => get_action(
&entity_ident,
&entity_snake_ident,
&function_ident,
&item_type,
thread_safe,
),
"GetMulti" => get_multi_action(
&entity_ident,
&entity_snake_ident,
&function_ident,
&item_type,
thread_safe,
),
"GetAll" => get_all_action(
&entity_ident,
&entity_snake_ident,
&function_ident,
&item_type,
thread_safe,
),
"Update" => update_action(
&entity_ident,
&entity_snake_ident,
&function_ident,
&item_type,
thread_safe,
),
"UpdateMulti" => update_multi_action(
&entity_ident,
&entity_snake_ident,
&function_ident,
&item_type,
thread_safe,
),
"UpdateWithRelationships" => update_with_relationships_action(
&entity_ident,
&entity_snake_ident,
&function_ident,
&item_type,
thread_safe,
),
"UpdateWithRelationshipsMulti" => update_with_relationships_multi_action(
&entity_ident,
&entity_snake_ident,
&function_ident,
&item_type,
thread_safe,
),
"Remove" => remove_action(
&entity_ident,
&entity_snake_ident,
&function_ident,
&item_type,
thread_safe,
),
"RemoveMulti" => remove_multi_action(
&entity_ident,
&entity_snake_ident,
&function_ident,
&item_type,
thread_safe,
),
"GetRO" => get_ro_action(
&entity_ident,
&entity_snake_ident,
&function_ident,
&item_type,
thread_safe,
),
"GetMultiRO" => get_multi_ro_action(
&entity_ident,
&entity_snake_ident,
&function_ident,
&item_type,
thread_safe,
),
"GetAllRO" => get_all_ro_action(
&entity_ident,
&entity_snake_ident,
&function_ident,
&item_type,
thread_safe,
),
"GetRelationship" => get_relationship_action(
&entity_ident,
&entity_snake_ident,
&function_ident,
&item_type,
thread_safe,
),
"GetRelationshipRO" => get_relationship_ro_action(
&entity_ident,
&entity_snake_ident,
&function_ident,
&item_type,
thread_safe,
),
"GetRelationshipsFromRightIds" => get_relationships_from_right_ids_action(
&entity_ident,
&entity_snake_ident,
&function_ident,
&item_type,
thread_safe,
),
"GetRelationshipsFromRightIdsRO" => get_relationships_from_right_ids_ro_action(
&entity_ident,
&entity_snake_ident,
&function_ident,
&item_type,
thread_safe,
),
"SetRelationship" => set_relationship_action(
&entity_ident,
&entity_snake_ident,
&function_ident,
&item_type,
thread_safe,
),
"SetRelationshipMulti" => set_relationship_multi_action(
&entity_ident,
&entity_snake_ident,
&function_ident,
&item_type,
thread_safe,
),
"MoveRelationship" => move_relationship_action(
&entity_ident,
&entity_snake_ident,
&function_ident,
&item_type,
thread_safe,
),
"Snapshot" => snapshot_action(
&entity_ident,
&entity_snake_ident,
&function_ident,
&item_type,
thread_safe,
),
"Restore" => restore_action(
&entity_ident,
&entity_snake_ident,
&function_ident,
&item_type,
thread_safe,
),
_ => unreachable!(),
};
let item_impl = match item_type {
ItemType::Trait(mut item_trait) => {
item_trait
.items
.push(syn::TraitItem::Verbatim(method_tokens));
quote!(#item_trait)
}
ItemType::Impl(mut item_impl) => {
item_impl.items.push(syn::ImplItem::Verbatim(method_tokens));
quote!(#item_impl)
}
};
quote!(#item_impl).into()
}