use crate::utils::modql_field::{ModqlFieldProp, ModqlFieldsAndSkips};
use crate::utils::{get_struct_fields, modql_field};
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, DeriveInput, Field};
pub fn derive_sqlite_from_row_inner(input: TokenStream) -> TokenStream {
let ast = parse_macro_input!(input as DeriveInput);
let fields = get_struct_fields(&ast);
let struct_name = &ast.ident;
let ModqlFieldsAndSkips {
modql_fields,
skipped_fields,
} = modql_field::get_modql_field_props_and_skips(fields);
let mfields_slice: Vec<&ModqlFieldProp> = modql_fields.iter().collect();
let fn_sqlite_from_row_quote = impl_fn_sqlite_from_row(&mfields_slice, &skipped_fields);
let fn_sqlite_from_row_partial_quote = impl_fn_sqlite_from_row_partial(&mfields_slice, &skipped_fields);
let output = quote! {
impl modql::SqliteFromRow for #struct_name {
#fn_sqlite_from_row_quote
#fn_sqlite_from_row_partial_quote
}
};
output.into()
}
fn impl_fn_sqlite_from_row(mfield_props: &[&ModqlFieldProp], skipped_fields: &[&Field]) -> proc_macro2::TokenStream {
let getters_quotes = mfield_props.iter().map(|mf| {
let ident = mf.ident;
let col_name = &mf.prop_name;
quote! {
#ident: val.get(#col_name)?,
}
});
let skipped_fields_quotes = skipped_fields.iter().map(|field| {
let ident = field.ident.as_ref().unwrap();
quote! {
#ident: Default::default(),
}
});
let output = quote! {
fn sqlite_from_row(val: &rusqlite::Row<'_>) -> rusqlite::Result<Self> {
let entity = Self {
#(#getters_quotes)*
#(#skipped_fields_quotes)*
};
Ok(entity)
}
};
output
}
fn impl_fn_sqlite_from_row_partial(
mfield_props: &[&ModqlFieldProp],
skipped_fields: &[&Field],
) -> proc_macro2::TokenStream {
let getters_quotes = mfield_props.iter().map(|mf| {
let ident = mf.ident;
let col_name = &mf.prop_name;
if mf.is_option {
quote! {
#ident: if prop_names.contains(&#col_name) { val.get(#col_name)? } else { None },
}
}
else {
quote! {
#ident: val.get(#col_name)?,
}
}
});
let skipped_fields_quotes = skipped_fields.iter().map(|field| {
let ident = field.ident.as_ref().unwrap();
quote! {
#ident: Default::default(),
}
});
let output = quote! {
fn sqlite_from_row_partial(val: &rusqlite::Row<'_>, prop_names: &[&str]) -> rusqlite::Result<Self> {
let entity = Self {
#(#getters_quotes)*
#(#skipped_fields_quotes)*
};
Ok(entity)
}
};
output
}