taitan_orm_parser/
field_def.rs

1use crate::{FieldAttrParser, KeywordsEscaper};
2use serde::{Deserialize, Serialize};
3use std::borrow::Cow;
4use syn::Field;
5use crate::info_parser::ParsedField;
6// struct $Ident {
7//   name: FieldType
8// }
9
10// condition
11// enum $Ident {
12//   A(Expr<Cow<'a, str>>)
13//   B(Option<Expr<i64>>)
14// }
15
16// index
17// enum $Ident {
18//    IdxName{ name: Cow<'a, str> }
19//    IdxNameAge{ name: String, age: i64 }
20// }
21
22//  _____________________________________________________________
23// | struct-field-name | inner rust type | is optional | lifetime
24//  -------------------------------------------------------------
25// | table-column-name | column type     | nullable | default | is generated | is auto-inc | is primary-key part|
26//  ------------------------------------------------------------------------------------------------------------
27//
28
29#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
30pub enum FieldName<'a> {
31    Named(Cow<'a, str>),
32    Unnamed { idx: usize, name: Cow<'a, str> },
33}
34
35impl<'a> Default for FieldName<'a> {
36    fn default() -> Self {
37        FieldName::Unnamed {
38            idx: 0,
39            name: Cow::Borrowed("e0"),
40        }
41    }
42}
43
44impl<'a> FieldName<'a> {
45    pub fn is_named(&self) -> bool {
46        matches!(self, FieldName::Named(_))
47    }
48    pub fn named<T: Into<Cow<'a, str>>>(name: T) -> Self {
49        FieldName::Named(name.into())
50    }
51    pub fn unnamed(idx: usize) -> Self {
52        FieldName::Unnamed { idx, name: Cow::Owned(format!("e{}", idx)) }
53    }
54    pub fn get_name(&self) -> &str {
55        match self {
56            FieldName::Named(name) => name,
57            FieldName::Unnamed { name, .. } => name,
58        }
59    }
60}
61
62
63// #[derive(Debug, PartialEq, Clone, Default)]
64// pub struct StructFieldDef<'a> {
65//     pub name: FieldName<'a>,
66//     pub rust_type: Cow<'a, str>,
67//     pub option_nest_level: usize,
68//     pub is_location_expr: bool,
69//     pub is_enum_variant: bool,
70//     pub lifetime: Option<Cow<'a, str>>,
71//     pub field: Option<Field>, // struct字段还原的时候Field最为方便
72// }
73
74// impl<'a> StructFieldDef<'a> {
75//     pub fn get_name(&self) -> Cow<'a, str> {
76//         match &self.name {
77//             FieldName::Named(n) => n.clone(),
78//             FieldName::Unnamed { idx: _, name } => name.clone(),
79//         }
80//     }
81//     pub fn is_option(&self) -> bool {
82//         self.option_nest_level > 0
83//     }
84// }
85
86// #[field(name = r_id, type = BIGINT, nullable = true, auto_inc = true)]
87#[derive(Debug, PartialEq, Clone, Default)]
88pub struct TableColumnDef<'a> {
89    pub name: Option<Cow<'a, str>>,
90    pub column_type: Option<Cow<'a, str>>,
91    pub default_value: Option<Cow<'a, str>>,
92    pub generated: Option<Cow<'a, str>>,
93    pub nullable: bool,
94    pub auto_inc: bool,
95}
96
97#[derive(Debug, PartialEq, Clone)]
98pub struct FieldDef<'a> {
99    pub struct_field: ParsedField<'a>,
100    pub table_column: TableColumnDef<'a>,
101}
102
103impl<'a> AsRef<FieldDef<'a>> for FieldDef<'a> {
104    fn as_ref(&self) -> &FieldDef<'a> {
105        self
106    }
107}
108
109impl FieldDef<'_> {
110    pub fn parse(
111        field: &Field,
112        is_enum_variant: bool,
113        unnamed_idx: Option<usize>,
114        external_column_name: Option<String>,
115    ) -> FieldDef<'_> {
116        let struct_field = ParsedField::parse(field, is_enum_variant, unnamed_idx);
117        let table_column = FieldAttrParser::parse(field, external_column_name);
118        FieldDef {
119            struct_field,
120            table_column,
121        }
122    }
123
124    pub fn is_optional(&self) -> bool {
125        self.struct_field.option_nest_level > 0
126    }
127
128    pub fn is_required(&self) -> bool {
129        self.struct_field.option_nest_level <= 0
130    }
131
132    pub fn is_location_expr(&self) -> bool {
133        self.struct_field.is_location_expr
134    }
135
136    pub fn origin_column_name(&self) -> &Cow<'_, str> {
137        match &self.table_column.name {
138            Some(column_name) => column_name,
139            None => match &self.struct_field.name {
140                FieldName::Named(name) => name,
141                FieldName::Unnamed { name, .. } => name,
142            },
143        }
144    }
145    pub fn column_name(&self, escaper: &dyn KeywordsEscaper) -> Cow<'_, str> {
146        let origin = match &self.table_column.name {
147            Some(column_name) => column_name,
148            None => match &self.struct_field.name {
149                FieldName::Named(name) => name,
150                FieldName::Unnamed { name, .. } => name,
151            },
152        };
153        escaper.escape(&origin)
154    }
155
156    pub fn column_name_upsert(&self, escaper: &dyn KeywordsEscaper) -> String {
157        let column_name = self.column_name(escaper);
158        escaper.gen_upsert_name(&column_name)
159    }
160}