easy_sqlx_core/sql/schema/
column.rs1use easy_sqlx_utils::value_parser::parse_next;
2use proc_macro2::Span;
3use quote::{quote, ToTokens};
4use syn::{parse::Parse, Error, Ident, LitInt, LitStr, Token};
5use crate::sql::utils::quote::Quoter;
8
9use super::types::types::SqlType;
10
11#[derive(Clone, Debug, PartialEq)]
12pub enum FieldOperator {
13 None, Max, Min, Average, Sum, }
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 pub name: String,
60
61 pub column: Option<String>,
63 pub col_type: Option<String>,
65 pub typ: SqlType,
67
68 pub ignore: bool,
72 pub pk: bool,
74 pub autoincr: bool,
76 pub comment: Option<String>,
78
79 pub nullable: bool,
81
82 pub default: Option<String>,
84
85 pub from: Option<String>,
90
91 pub replace: bool,
95 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.typ == other.typ
109 && self.autoincr == other.autoincr
112 && 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 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 }
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 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 }
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 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 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 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 ..Default::default()
273 }
274 }
275 .to_tokens(tokens);
276 }
277}
278
279impl 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 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 );
366 }
367 "column" => {
368 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}