easy_sqlx_core/sql/schema/
table.rs

1use easy_sqlx_utils::value_parser::{parse_groups, parse_next, Array};
2use proc_macro2::Span;
3use quote::{quote, ToTokens};
4use syn::{parse::Parse, Error, Ident, LitStr, Token};
5use heck::ToSnakeCase;
6
7use super::{column::Column, index::Index};
8
9#[derive(Clone, Debug, Default)]
10pub struct TableSchema {
11    /// 表名称
12    pub name: String,
13    /// 表所属 schema
14    pub schema: Option<String>,
15    /// 说明信息
16    pub comment: Option<String>,
17    /// 索引
18    pub indexes: Option<Vec<Index>>,
19    /// 列
20    pub columns: Vec<Column>,
21
22    /// [控制字段]
23    /// 从另外一个表重命名,
24    /// 执行重命名的前提条件:1 该表不存在,2 from 指定的表必须存在
25    pub from: Option<String>,
26    /// [控制字段]
27    /// 删除并重建表,给出一个与该表关联的唯一重建标志
28    /// 当 重建标志 标志第一次出现时,该表将会重建
29    /// 重建会删除表内所有数据,请慎重使用
30    pub recreate: Option<String>,
31    /// [控制字段]
32    /// 删除没有关联 struct 字段的表中的列
33    pub trim_columns: bool,
34    /// [控制字段]
35    /// 删除未定义的索引
36    pub trim_indexes: bool,
37    /// [控制字段]
38    /// 是否生成增删改相关函数
39    /// true    不生成
40    /// false   生成
41    pub query_only: bool,
42}
43
44impl TableSchema {
45    pub fn name_with_schema(&self) -> String {
46        if let Some(schema) = &self.schema {
47            return format!("{schema}.{}", self.name.clone());
48        }
49        self.name.clone()
50    }
51
52    pub fn index_name_with_schema(&self, index_name: &String) -> String {
53        if let Some(schema) = &self.schema {
54            return format!("{schema}.{index_name}");
55        }
56        index_name.clone()
57    }
58
59    /// 检查索引列是否合法
60    /// 有效索引列为表中列的字段名称
61    pub fn check_indexes_columns(&self) -> syn::Result<()> {
62        if let Some(indexes) = self.indexes.as_ref() {
63            for index in indexes.iter() {
64                for col in index.columns.iter() {
65                    if self.find_column(col).is_none() {
66                        return Err(Error::new(
67                            Span::call_site(),
68                            format!("Index's column '{col}' is not exists in table columns"),
69                        ));
70                    }
71                }
72            }
73        }
74        Ok(())
75    }
76
77    pub fn find_column(&self, name: &String) -> Option<Column> {
78        self.columns
79            .iter()
80            .find(|col| {
81                if col.column.is_none() {
82                    col.name == *name
83                } else {
84                    col.column.as_ref().unwrap() == name
85                }
86            })
87            .map(|col| (*col).clone())
88    }
89
90    /// 合并 source 属性到当前 Table
91    pub fn assign(&mut self, source: TableSchema) -> syn::Result<()> {
92        if self.name.is_empty() && !source.name.is_empty() {
93            self.name = source.name.clone();
94        }
95
96        if self.comment.is_none() && !source.comment.is_none() {
97            self.comment = source.comment.clone();
98        }
99
100        if self.schema.is_none() && !source.schema.is_none() {
101            self.schema = source.schema.clone();
102        }
103
104        if self.recreate.is_none() {
105            self.recreate = source.recreate.clone();
106        }
107        if self.from.is_none() {
108            self.from = source.from.clone();
109        }
110        if !self.trim_columns {
111            self.trim_columns = source.trim_columns;
112        }
113
114        if !self.trim_indexes {
115            self.trim_indexes = source.trim_indexes;
116        }
117
118        self.query_only = source.query_only;
119
120        if let Some(src_indexes) = source.indexes {
121            for idx in src_indexes {
122                if self.indexes.is_none() {
123                    self.indexes = Some(vec![idx.to_owned()]);
124                } else {
125                    self.indexes.as_mut().unwrap().push(idx.to_owned());
126                }
127                // self.add_index(idx.to_owned())?;
128            }
129        }
130
131        // 列无需复制
132        Ok(())
133    }
134
135    /// 添加 index,如果 name 冲突则重新命名 name
136    pub fn add_index(&mut self, mut index: Index) -> syn::Result<()> {
137        // let name = index.get_name();
138        let (mut name, setted) = index.get_name(&self.name);
139        if self.indexes.is_none() {
140            index.name = name;
141            self.indexes = Some(vec![index]);
142        } else {
143            // 获取索引名称
144            let mut n = 0;
145            loop {
146                if self
147                    .indexes
148                    .as_ref()
149                    .unwrap()
150                    .iter()
151                    .find(|idx| (*idx).name == name) // 索引列表中的索引名称为已经设置,可以直接对比
152                    .is_none()
153                {
154                    break;
155                }
156                if setted {
157                    // 索引名称是设置的,不允许冲突
158                    return Err(syn::Error::new(
159                        Span::call_site(),
160                        format!("索引名称 {} 冲突", name),
161                    ));
162                }
163                n += 1;
164                (name, _) = index.get_name_with_index(&self.name, n);
165                // name = format!("{}_{}", index.name.clone(), n).to_string();
166            }
167            // 设置索引名称
168            index.name = name;
169            self.indexes.as_mut().unwrap().push(index);
170        }
171
172        Ok(())
173    }
174}
175
176impl ToTokens for TableSchema {
177    fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
178        let name = self.name.clone();
179        let comment = self.comment.clone().unwrap_or("".to_string());
180        let has_comment = !comment.is_empty();
181        let idxs = self.indexes.clone().unwrap_or(vec![]);
182        let has_idxs = !idxs.is_empty();
183        let schema = self.schema.clone().unwrap_or("".to_string());
184        let has_schema = !schema.is_empty();
185        let cols = self.columns.clone();
186        let from = self.from.clone().unwrap_or("".to_string());
187        let has_from = !from.is_empty();
188        let trim_columns = self.trim_columns;
189        let trim_indexes = self.trim_indexes;
190        let recreate = self.recreate.clone().unwrap_or("".to_string());
191        let has_recreate = !recreate.is_empty();
192        let query_only = self.query_only;
193        quote! {
194            easy_sqlx_core::sql::schema::table::TableSchema {
195                indexes: if #has_idxs { Some([#(#idxs), *].to_vec()) } else { None },
196                columns: [#(#cols), *].to_vec(),
197                name: #name.to_string(),
198                comment: if #has_comment { Some(#comment.to_string()) } else { None },
199                schema: if #has_schema { Some(#schema.to_string()) } else { None },
200                from: if #has_from { Some(#from.to_string()) } else { None },
201                recreate: if #has_recreate { Some(#recreate.to_string()) } else { None },
202                trim_columns: #trim_columns,
203                trim_indexes: #trim_indexes,
204                query_only: #query_only,
205                // raw_indexes: if #has_raw_idxs { Some([#(#raw_idxs), *].to_vec()) } else { None },
206            }
207        }
208        .to_tokens(tokens);
209    }
210}
211
212impl Parse for TableSchema {
213    fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
214        const EXPECTED_ATTRIBUTE: &str =
215            "unexpected attribute, expected any of: name, comment, schema, query_only, from, recreate, trim_columns, trim_indexes indexes[]";
216
217        let mut table = TableSchema::default();
218        let mut idxes = vec![];
219        while !input.is_empty() {
220            let ident = input.parse::<Ident>().map_err(|error| {
221                Error::new(error.span(), format!("{EXPECTED_ATTRIBUTE}, {error}"))
222            })?;
223            let attribute = &*ident.to_string();
224
225            match attribute {
226                "name" => {
227                    table.name = parse_next(input, || input.parse::<LitStr>())
228                        .map_err(|err| {
229                            Error::new(
230                                err.span(),
231                                format!("attribute {attribute} parse error, {err}"),
232                            )
233                        })?
234                        .value().to_snake_case();
235
236                }
237                "from" => {
238                    table.from = Some(
239                        parse_next(input, || input.parse::<LitStr>())
240                            .map_err(|err| {
241                                Error::new(
242                                    err.span(),
243                                    format!("attribute {attribute} parse error, {err}"),
244                                )
245                            })?
246                            .value(),
247                    );
248                }
249                "trim_columns" => {
250                    table.trim_columns = true;
251                }
252                "trim_indexes" => {
253                    table.trim_indexes = true;
254                }
255                "query_only" => {
256                    table.query_only = true;
257                }
258                "recreate" => {
259                    table.recreate = Some(
260                        parse_next(input, || input.parse::<LitStr>())
261                            .map_err(|err| {
262                                Error::new(
263                                    err.span(),
264                                    format!("attribute {attribute} parse error, {err}"),
265                                )
266                            })?
267                            .value(),
268                    );
269                }
270                "comment" => {
271                    table.comment = Some(
272                        parse_next(input, || input.parse::<LitStr>())
273                            .map_err(|err| {
274                                Error::new(
275                                    err.span(),
276                                    format!("attribute {attribute} parse error, {err}"),
277                                )
278                            })?
279                            .value(),
280                    );
281                }
282                "schema" => {
283                    table.schema = Some(
284                        parse_next(input, || input.parse::<LitStr>())
285                            .map_err(|err| {
286                                Error::new(
287                                    err.span(),
288                                    format!("attribute {attribute} parse error, {err}"),
289                                )
290                            })?
291                            .value(),
292                    );
293                }
294                "indexes" => {
295                    // parse_next(input, || input.parse::<LitStr>())
296                    //     .map_err(|err| {
297                    //         Error::new(
298                    //             err.span(),
299                    //             format!("attribute {attribute} parse error, {err}"),
300                    //         )
301                    //     })?
302                    //     .value();
303                    // parse_punctuated_within_parenthesis::<>(input);
304                    // let aaaa = parse_macro_input!(input.to_tokens() with Punctuated::<Index, syn::Token![,]>::parse_terminated);
305                    let indexes;
306                    syn::bracketed!(indexes in input); // [] 括住 索引
307
308                    // let args_parsed =
309                    //     syn::punctuated::Punctuated::<syn::Path, syn::Token![,]>::parse_terminated
310                    //         .parse(input.)
311                    //         .unwrap();
312
313                    let a: Array<'static, Index> = parse_groups(&indexes)?;
314
315                    for index in a.iter() {
316                        idxes.push(index.clone());
317                        // table.add_raw_index(index.clone())
318                    }
319
320                    // loop {
321                    //     if indexes.is_empty() {
322                    //         break;
323                    //     }
324                    // //     let index =
325                    // //         parse_next(input, || indexes.parse::<Index>()).map_err(|err| {
326                    // //             Error::new(
327                    // //                 err.span(),
328                    // //                 format!("attribute {attribute} parse error, {err}"),
329                    // //             )
330                    // //         })?;
331                    // //     idxes.push(index);
332                    // //     // let value = parser(input)?;
333                    // //     // punctuated.push_value(value);
334                    //     if indexes.is_empty() {
335                    //         break;
336                    //     }
337                    //     // let punct = input.parse()?;
338                    // //     // punctuated.push_punct(punct);
339                    // }
340                }
341                _ => {
342                    return Err(Error::new(ident.span(), EXPECTED_ATTRIBUTE));
343                }
344            }
345
346            if !input.is_empty() {
347                input.parse::<Token![,]>()?;
348            }
349        }
350
351        if !idxes.is_empty() {
352            // table.raw_indexes = Some(idxes);
353            table.indexes = Some(idxes);
354        }
355
356        Ok(table)
357    }
358}