easy_sqlx_core/sql/schema/
column.rs

1use easy_sqlx_utils::value_parser::parse_next;
2use proc_macro2::Span;
3use quote::{quote, ToTokens};
4use syn::{parse::Parse, Error, Ident, LitInt, LitStr, Token};
5// use tools::macros::value_parser::parse_next;
6
7use crate::sql::utils::quote::Quoter;
8
9use super::types::types::SqlType;
10
11#[derive(Clone, Debug, PartialEq)]
12pub enum FieldOperator {
13    None,    // 无操作
14    Max,     // 最大值
15    Min,     // 最小值
16    Average, // 平均值
17    Sum,     // 合计值
18}
19
20impl Default for FieldOperator {
21    fn default() -> Self {
22        Self::None
23    }
24}
25
26impl FieldOperator {
27    fn wrap(fn_name: &str, field: &String, return_field_name: &String) -> String {
28        format!(
29            "{}({}) as {}",
30            fn_name,
31            &field,
32            if return_field_name.is_empty() {
33                &field
34            } else {
35                &return_field_name
36            }
37        )
38    }
39    pub fn wrap_fn(&self, field: String, return_field_name: String) -> String {
40        match self {
41            FieldOperator::Max => Self::wrap("max", &field, &return_field_name),
42            FieldOperator::Min => Self::wrap("min", &field, &return_field_name),
43            FieldOperator::Average => Self::wrap("avg", &field, &return_field_name),
44            FieldOperator::Sum => Self::wrap("sum", &field, &return_field_name),
45            _ => {
46                if return_field_name.is_empty() {
47                    field
48                } else {
49                    format!("{field} as {return_field_name}")
50                }
51            }
52        }
53    }
54}
55
56#[derive(Clone, Debug, Default)]
57pub struct Column {
58    /// 结构体字段名称
59    pub name: String,
60
61    /// 数据库字段名称
62    pub column: Option<String>,
63    /// 数据库字段的数据类型,用于没有合适的类型时,可以自定义
64    pub col_type: Option<String>,
65    /// 数据库数据类型
66    pub typ: SqlType,
67
68    /// [控制字段]
69    /// 是否忽略该字段,
70    /// 在解析定义时,如果是 true 则不向列表中添加该列
71    pub ignore: bool,
72    /// 主键 pk
73    pub pk: bool,
74    /// 自增类型 autoincr
75    pub autoincr: bool,
76    /// 说明信息
77    pub comment: Option<String>,
78
79    /// 是否可为空 null | not-null
80    pub nullable: bool,
81
82    // 默认值 default(值)
83    pub default: Option<String>,
84
85    /// [控制字段]
86    /// 从另外一个字段重命名,
87    /// 执行重命名的前提条件:1 该字段不存在,2 from 指定的字段必须存在
88    /// 重命名后如果字段属性不一致,则执行修改操作
89    pub from: Option<String>,
90
91    /// [控制字段]
92    /// 如果字段更新失败, replace 为 true 时,则删除旧字段并添加新字段
93    /// 注意:删除旧字段会连带字段中的数据一起删除,并且不能恢复
94    pub replace: bool,
95    // /// [代码生成控制]
96    // /// 数据类型使用的 Option 数量
97    // pub rust_type_options: isize,
98    /// 生成对 sql 字段操作 如 max min ...
99    pub field_operator: FieldOperator,
100}
101
102impl PartialEq for Column {
103    fn eq(&self, other: &Self) -> bool {
104        self.is_name_equal(other)
105        // self.name == other.name
106            // && self.column == other.column
107            // && self.col_type == other.col_type
108            && self.typ == other.typ
109            // && self.ignore == other.ignore
110            // && self.pk == other.pk // 主键不参与对比的原因是,不允许更改主键
111            && self.autoincr == other.autoincr
112            // && self.comment == other.comment
113            && self.nullable == other.nullable
114            && self.default == other.default
115    }
116}
117
118impl Eq for Column {}
119
120impl Column {
121    pub fn is_name_equal(&self, col: &Column) -> bool {
122        if let Some(s_col) = &self.column {
123            if let Some(o_col) = &col.column {
124                s_col.to_uppercase() == o_col.to_uppercase()
125            } else {
126                s_col.to_uppercase() == col.name.to_uppercase()
127            }
128        } else {
129            if let Some(o_col) = &col.column {
130                self.name.to_uppercase() == o_col.to_uppercase()
131            } else {
132                self.name.to_uppercase() == col.name.to_uppercase()
133            }
134        }
135    }
136
137    pub fn get_column_name(&self) -> String {
138        if let Some(name) = self.column.clone() {
139            name
140        } else {
141            self.name.clone()
142        }
143    }
144
145    pub fn get_query_column_name(&self, quoter: &Quoter) -> String {
146        // 获取数据库中的字段名称
147        let field = if let Some(name) = self.column.clone() {
148            if name != self.name {
149                name
150            } else {
151                "".to_string()
152            }
153        } else {
154            "".to_string()
155        };
156
157        if field.is_empty() {
158            self.field_operator
159                .wrap_fn(quoter.quote(&self.name), "".to_string())
160        } else {
161            self.field_operator
162                .wrap_fn(quoter.quote(&field), quoter.quote(&self.name))
163        }
164        // if let Some(name) = self.column.clone() {
165        //     if name != self.name {}
166        //     format!("{name} as {}", self.name)
167        // } else {
168        //     self.name.clone()
169        // }
170    }
171
172    pub fn max(&self) -> Self {
173        let mut f = self.clone();
174        f.field_operator = FieldOperator::Max;
175        f
176    }
177
178    pub fn min(&self) -> Self {
179        let mut f = self.clone();
180        f.field_operator = FieldOperator::Min;
181        f
182    }
183
184    // pub fn average(&self) -> Self {
185    //     let mut f = self.clone();
186    //     f.field_operator = FieldOperator::Average;
187    //     f
188    // }
189
190    // pub fn sum(&self) -> Self {
191    //     let mut f = self.clone();
192    //     f.field_operator = FieldOperator::Sum;
193    //     f
194    // }
195
196    pub fn assign(&mut self, source: &Column) {
197        if !self.pk {
198            self.pk = source.pk;
199        }
200        if !self.autoincr {
201            self.autoincr = source.autoincr;
202        }
203        if self.column.is_none() && source.column.is_some() {
204            self.column = source.column.clone();
205        }
206        if self.col_type.is_none() && source.col_type.is_some() {
207            self.col_type = source.col_type.clone();
208        }
209        if self.comment.is_none() && source.comment.is_some() {
210            self.comment = source.comment.clone();
211        }
212        if self.default.is_none() && source.default.is_some() {
213            self.default = source.default.clone();
214        }
215        if self.from.is_some() {
216            self.from = source.from.clone();
217        }
218        if !self.replace {
219            self.replace = source.replace;
220        }
221        // self.typ = source.typ.clone();
222    }
223}
224
225impl ToTokens for Column {
226    fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
227        let ignore = self.ignore;
228        let name = self.name.clone();
229        let col_name = self.column.clone().unwrap_or("".to_string());
230        let has_col_name = !col_name.is_empty();
231
232        // let mut has_col_type = self.col_type.is_some();
233        let col_type = self.col_type.clone().unwrap_or("".to_string());
234        let has_col_type = !col_type.is_empty();
235        let typ = self.typ.to_token_stream();
236        let pk = self.pk;
237        let autoincr = self.autoincr;
238        let nullable = self.nullable;
239        // TokenStream::new().a
240        // let mut has_comment = self.comment.is_some();
241        let comment = self.comment.clone().unwrap_or("".to_string());
242        let has_comment = !comment.is_empty();
243
244        let default = self.default.clone().unwrap_or("".to_string());
245        let has_default = !default.is_empty();
246
247        let from = self.from.clone().unwrap_or("".to_string());
248        let has_from = !from.is_empty();
249
250        let replace = self.replace;
251
252        // let col_type =
253        // let has_len2 = self.len2.is_some();
254        // let len2 = self.len2.unwrap_or(0);
255        // let len = self.len.clone();
256        quote! {
257            easy_sqlx_core::sql::schema::column::Column {
258                ignore: #ignore,
259                pk: #pk,
260                autoincr: #autoincr,
261                nullable: #nullable,
262                name: #name.to_string(),
263                column: if #has_col_name { Some(#col_name.to_string()) } else { None },
264                col_type: if #has_col_type { Some(#col_type.to_string()) } else { None },
265                typ: #typ,
266                comment: if #has_comment { Some(#comment.to_string()) } else { None },
267                default: if #has_default { Some(#default.to_string()) } else { None },
268                from: if #has_from { Some(#from.to_string()) } else { None },
269                replace: #replace,
270                // typ:
271                // len2: if #has_len2 { Some(#len2) } else { None },
272                ..Default::default()
273            }
274        }
275        .to_tokens(tokens);
276    }
277}
278
279// pub fn parse_next<T: FnOnce() -> Result<R, syn::Error>, R: Sized>(
280//     input: ParseStream,
281//     next: T,
282// ) -> Result<R, syn::Error> {
283//     input.parse::<Token![=]>()?;
284//     next()
285// }
286
287impl Parse for Column {
288    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
289        const EXPECTED_ATTRIBUTE: &str =
290            "unexpected attribute, expected any of: ignore, pk, column, len, col_type, autoincr, comment, default, from, replace";
291
292        let mut column = Column::default();
293
294        while !input.is_empty() {
295            let ident = input.parse::<Ident>().map_err(|error| {
296                Error::new(error.span(), format!("{EXPECTED_ATTRIBUTE}, {error}"))
297            })?;
298            let attribute = &*ident.to_string();
299
300            // for attr in attrs {
301            //     match attr.path().get_ident() {
302            //         Some(ident) if ident == #attr_name => {
303            //             return Some(syn::parse2::<Self>(attr.into_token_stream())).transpose()
304            //         }
305            //         // Ignore other attributes
306            //         _ => {},
307            //     }
308            // }
309
310            match attribute {
311                "ignore" => {
312                    column.ignore = true;
313                }
314                "pk" => {
315                    column.pk = true;
316                }
317                "autoincr" => {
318                    column.autoincr = true;
319                }
320                "col_type" => {
321                    column.col_type = Some(
322                        parse_next(input, || input.parse::<LitStr>())
323                            .map_err(|err| {
324                                Error::new(
325                                    err.span(),
326                                    format!("attribute {attribute} parse error, {err}"),
327                                )
328                            })?
329                            .value(),
330                    );
331                }
332                "from" => {
333                    column.from = Some(
334                        parse_next(input, || input.parse::<LitStr>())
335                            .map_err(|err| {
336                                Error::new(
337                                    err.span(),
338                                    format!("attribute {attribute} parse error, {err}"),
339                                )
340                            })?
341                            .value(),
342                    );
343                }
344                "replace" => {
345                    column.replace = true;
346                }
347                "len" => {
348                    column.typ.len = Some(
349                        parse_next(input, || input.parse::<LitInt>())
350                            .map_err(|err| {
351                                Error::new(
352                                    err.span(),
353                                    format!("attribute {attribute} parse error, {err}"),
354                                )
355                            })?
356                            .base10_digits()
357                            .parse()
358                            .map_err(|err| {
359                                Error::new(
360                                    Span::call_site(),
361                                    format!("attribute {attribute} parse error, {err}"),
362                                )
363                            })?,
364                        // .value(),
365                    );
366                }
367                "column" => {
368                    // let info_stream;
369                    // parenthesized!(info_stream in input);
370                    // column.column = parse_string(info_stream, "", "").map(|str| Some(str))?;
371                    // parse_next(input, || {
372                    //     Ok(())
373                    // });
374                    // input.parse::<Token![=]>();
375                    // parse_next(input, || Ok(()))?;
376                    column.column = Some(
377                        parse_next(input, || input.parse::<LitStr>())
378                            .map_err(|err| {
379                                Error::new(
380                                    err.span(),
381                                    format!("attribute {attribute} parse error, {err}"),
382                                )
383                            })?
384                            .value(),
385                    );
386                }
387                "comment" => {
388                    column.comment = Some(
389                        parse_next(input, || input.parse::<LitStr>())
390                            .map_err(|err| {
391                                Error::new(
392                                    err.span(),
393                                    format!("attribute {attribute} parse error, {err}"),
394                                )
395                            })?
396                            .value(),
397                    );
398                }
399                _ => {
400                    return Err(Error::new(ident.span(), EXPECTED_ATTRIBUTE));
401                }
402            }
403
404            if !input.is_empty() {
405                input.parse::<Token![,]>()?;
406            }
407        }
408
409        Ok(column)
410    }
411}