use crate::{FieldAttrParser, KeywordsEscaper};
use serde::{Deserialize, Serialize};
use std::borrow::Cow;
use syn::Field;
use crate::info_parser::ParsedField;
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
pub enum FieldName<'a> {
Named(Cow<'a, str>),
Unnamed { idx: usize, name: Cow<'a, str> },
}
impl<'a> Default for FieldName<'a> {
fn default() -> Self {
FieldName::Unnamed {
idx: 0,
name: Cow::Borrowed("e0"),
}
}
}
impl<'a> FieldName<'a> {
pub fn is_named(&self) -> bool {
matches!(self, FieldName::Named(_))
}
pub fn named<T: Into<Cow<'a, str>>>(name: T) -> Self {
FieldName::Named(name.into())
}
pub fn unnamed(idx: usize) -> Self {
FieldName::Unnamed { idx, name: Cow::Owned(format!("e{}", idx)) }
}
pub fn get_name(&self) -> &str {
match self {
FieldName::Named(name) => name,
FieldName::Unnamed { name, .. } => name,
}
}
}
#[derive(Debug, PartialEq, Clone, Default)]
pub struct TableColumnDef<'a> {
pub name: Option<Cow<'a, str>>,
pub column_type: Option<Cow<'a, str>>,
pub default_value: Option<Cow<'a, str>>,
pub generated: Option<Cow<'a, str>>,
pub nullable: bool,
pub auto_inc: bool,
}
#[derive(Debug, PartialEq, Clone)]
pub struct FieldDef<'a> {
pub struct_field: ParsedField<'a>,
pub table_column: TableColumnDef<'a>,
}
impl<'a> AsRef<FieldDef<'a>> for FieldDef<'a> {
fn as_ref(&self) -> &FieldDef<'a> {
self
}
}
impl FieldDef<'_> {
pub fn parse(
field: &Field,
is_enum_variant: bool,
unnamed_idx: Option<usize>,
external_column_name: Option<String>,
) -> FieldDef<'_> {
let struct_field = ParsedField::parse(field, is_enum_variant, unnamed_idx);
let table_column = FieldAttrParser::parse(field, external_column_name);
FieldDef {
struct_field,
table_column,
}
}
pub fn is_optional(&self) -> bool {
self.struct_field.option_nest_level > 0
}
pub fn is_required(&self) -> bool {
self.struct_field.option_nest_level <= 0
}
pub fn is_location_expr(&self) -> bool {
self.struct_field.is_location_expr
}
pub fn origin_column_name(&self) -> &Cow<'_, str> {
match &self.table_column.name {
Some(column_name) => column_name,
None => match &self.struct_field.name {
FieldName::Named(name) => name,
FieldName::Unnamed { name, .. } => name,
},
}
}
pub fn column_name(&self, escaper: &dyn KeywordsEscaper) -> Cow<'_, str> {
let origin = match &self.table_column.name {
Some(column_name) => column_name,
None => match &self.struct_field.name {
FieldName::Named(name) => name,
FieldName::Unnamed { name, .. } => name,
},
};
escaper.escape(&origin)
}
pub fn column_name_upsert(&self, escaper: &dyn KeywordsEscaper) -> String {
let column_name = self.column_name(escaper);
escaper.gen_upsert_name(&column_name)
}
}