easy_sqlx_core/sql/schema/
table.rs1use 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 pub name: String,
13 pub schema: Option<String>,
15 pub comment: Option<String>,
17 pub indexes: Option<Vec<Index>>,
19 pub columns: Vec<Column>,
21
22 pub from: Option<String>,
26 pub recreate: Option<String>,
31 pub trim_columns: bool,
34 pub trim_indexes: bool,
37 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 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 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 }
129 }
130
131 Ok(())
133 }
134
135 pub fn add_index(&mut self, mut index: Index) -> syn::Result<()> {
137 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 let mut n = 0;
145 loop {
146 if self
147 .indexes
148 .as_ref()
149 .unwrap()
150 .iter()
151 .find(|idx| (*idx).name == name) .is_none()
153 {
154 break;
155 }
156 if setted {
157 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 }
167 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 }
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 let indexes;
306 syn::bracketed!(indexes in input); let a: Array<'static, Index> = parse_groups(&indexes)?;
314
315 for index in a.iter() {
316 idxes.push(index.clone());
317 }
319
320 }
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.indexes = Some(idxes);
354 }
355
356 Ok(table)
357 }
358}