use syn::{DeriveInput, Result};
pub(super) struct FieldInfo {
pub table: Option<String>,
pub column: String,
}
pub(super) struct FieldAttr {
pub is_id: bool,
pub table: Option<String>,
pub column: Option<String>,
}
impl syn::parse::Parse for FieldAttr {
fn parse(input: syn::parse::ParseStream) -> Result<Self> {
let mut is_id = false;
let mut table = None;
let mut column = None;
loop {
if input.is_empty() {
break;
}
if input.peek(syn::Ident) {
let ident: syn::Ident = input.parse()?;
if ident == "id" {
is_id = true;
if input.peek(syn::Token![,]) {
let _: syn::Token![,] = input.parse()?;
}
continue;
}
let _: syn::Token![=] = input.parse()?;
let value: syn::LitStr = input.parse()?;
if ident == "table" {
table = Some(value.value());
} else if ident == "column" {
column = Some(value.value());
}
}
if input.peek(syn::Token![,]) {
let _: syn::Token![,] = input.parse()?;
} else {
break;
}
}
Ok(FieldAttr {
is_id,
table,
column,
})
}
}
pub(super) fn get_table_name(input: &DeriveInput) -> Result<String> {
for attr in &input.attrs {
if attr.path().is_ident("orm") {
if let Ok(nested) = attr.parse_args::<syn::MetaNameValue>() {
if nested.path.is_ident("table") {
if let syn::Expr::Lit(syn::ExprLit {
lit: syn::Lit::Str(lit),
..
}) = &nested.value
{
return Ok(lit.value());
}
}
}
}
}
Err(syn::Error::new_spanned(
input,
"Model requires #[orm(table = \"table_name\")] attribute",
))
}
pub(super) fn get_field_info(field: &syn::Field, _default_table: &str) -> FieldInfo {
let mut table: Option<String> = None;
let mut column: Option<String> = None;
for attr in &field.attrs {
if attr.path().is_ident("orm") {
if let syn::Meta::List(meta_list) = &attr.meta {
let tokens = meta_list.tokens.clone();
if let Ok(parsed) = syn::parse2::<FieldAttr>(tokens) {
if parsed.table.is_some() {
table = parsed.table;
}
if parsed.column.is_some() {
column = parsed.column;
}
}
}
if let Ok(nested) = attr.parse_args::<syn::MetaNameValue>() {
if nested.path.is_ident("column") {
if let syn::Expr::Lit(syn::ExprLit {
lit: syn::Lit::Str(lit),
..
}) = &nested.value
{
column = Some(lit.value());
}
} else if nested.path.is_ident("table") {
if let syn::Expr::Lit(syn::ExprLit {
lit: syn::Lit::Str(lit),
..
}) = &nested.value
{
table = Some(lit.value());
}
}
}
}
}
FieldInfo {
table,
column: column.unwrap_or_else(|| field.ident.as_ref().unwrap().to_string()),
}
}
pub(super) fn is_id_field(field: &syn::Field) -> bool {
for attr in &field.attrs {
if attr.path().is_ident("orm") {
if let syn::Meta::List(meta_list) = &attr.meta {
let tokens = meta_list.tokens.clone();
if let Ok(parsed) = syn::parse2::<FieldAttr>(tokens) {
if parsed.is_id {
return true;
}
}
}
}
}
false
}