taitan_orm_parser/info_parser/
parsed_field.rs

1use crate::info_parser::option_parser::OptionParser;
2use crate::info_parser::TypeParser;
3use crate::{FieldName, LifetimeParser};
4use case::CaseExt;
5use quote::{format_ident, quote, ToTokens};
6use std::borrow::Cow;
7use syn::Field;
8
9#[derive(Debug, PartialEq, Clone)]
10pub struct ParsedField<'a> {
11    pub name: FieldName<'a>,
12    pub rust_type: Cow<'a, str>,
13    pub option_nest_level: usize,
14    pub is_location_expr: bool,
15    pub is_enum_variant: bool,
16    pub lifetime: Option<Cow<'a, str>>,
17    pub origin_field: Field,
18}
19
20#[derive(Debug, Clone, Copy)]
21pub enum FieldTokenType {
22    InnerMostType,    // primary/unique
23    InnerVariantExpr, // index使用
24    NestedOptionType, // mutation/selected使用, Option<Option<T>>
25    VariantExpr,      // Location使用
26}
27impl<'a> ParsedField<'a> {
28    pub fn parse(field: &Field, is_enum_variant: bool, unnamed_idx: Option<usize>) -> Self {
29        let field_name = if let Some(ident) = field.clone().ident {
30            FieldName::Named(Cow::Owned(ident.to_string()))
31        } else {
32            FieldName::unnamed(unnamed_idx.unwrap())
33        };
34        Self::new(&field, field_name, is_enum_variant)
35    }
36    pub fn new(
37        origin_field: &Field,
38        field_name: FieldName<'a>,
39        is_enum_variant: bool,
40    ) -> ParsedField<'a> {
41        let (field_type, option_nest_level) =
42            OptionParser::get_nested_option_inner_type(&origin_field.ty);
43        let field_type_str = field_type.to_token_stream().to_string();
44        let is_location_expr = TypeParser::is_location_expr(&field_type);
45        let lifetime =
46            LifetimeParser::get_lifetime(&origin_field.ty).map(|l| Cow::Owned(l.to_string()));
47        ParsedField {
48            name: field_name.clone(),
49            rust_type: Cow::Owned(field_type_str.clone()),
50            is_enum_variant,
51            is_location_expr,
52            lifetime,
53            option_nest_level,
54            origin_field: origin_field.clone(),
55        }
56    }
57
58    pub fn get_name(&self) -> Cow<'a, str> {
59        match &self.name {
60            FieldName::Named(n) => n.clone(),
61            FieldName::Unnamed { idx: _, name } => name.clone(),
62        }
63    }
64    pub fn is_option(&self) -> bool {
65        self.option_nest_level > 0
66    }
67    pub fn to_token_stream(&self, token_type: FieldTokenType) -> proc_macro2::TokenStream {
68        let field_name = &self.name.get_name();
69        let field_ident = format_ident!("{}", field_name);
70        let ty = &self.origin_field.ty;
71        let vis = &self.origin_field.vis;
72        let attrs = &self.origin_field.attrs;
73        let (inner_type, _) = OptionParser::get_nested_option_inner_type(ty);
74        return match token_type {
75            FieldTokenType::InnerMostType => {
76                quote! {
77                    #(#attrs)*
78                    #vis #field_ident :#inner_type
79                }
80            }
81            FieldTokenType::NestedOptionType => {
82                quote! {
83                    #(#attrs)*
84                    #vis #field_ident :std::option::Option<std::option::Option<#inner_type>>
85                }
86            }
87            FieldTokenType::InnerVariantExpr => {
88                quote! {
89                    #(#attrs)*
90                    #field_ident : taitan_orm::op::Expr<#inner_type>
91                }
92            }
93            FieldTokenType::VariantExpr => {
94                let enum_variant_name = format_ident!("{}", field_name.to_camel());
95                quote! {
96                    #enum_variant_name (
97                        #(#attrs)*
98                        taitan_orm::op::Expr<#inner_type>
99                    )
100                }
101            }
102        };
103    }
104}