1
use proc_macro2::{Ident, Span, TokenStream};
2
use quote::quote;
3
use syn::{Attribute, Generics, Visibility};
4

            
5
use super::entity::CanyonEntity;
6

            
7
/// Builds the TokenStream that contains the user defined struct
8
3
pub fn generate_user_struct(canyon_entity: &CanyonEntity) -> TokenStream {
9
3
    let fields = &canyon_entity.get_attrs_as_token_stream();
10

            
11
3
    let struct_name: &Ident = &canyon_entity.struct_name;
12
3
    let struct_visibility: &Visibility = &canyon_entity.vis;
13
3
    let struct_generics: &Generics = &canyon_entity.generics;
14
3
    let struct_attrs: &Vec<Attribute> = &canyon_entity.attrs;
15

            
16
3
    quote! {
17
        #(#struct_attrs)*
18
        #struct_visibility struct #struct_name #struct_generics {
19
            #(#fields),*
20
        }
21
    }
22
3
}
23

            
24
/// Auto-generated enum to represent every field of the related type
25
/// as a variant of an enum that it's named with the concatenation
26
/// of the type identifier + Field
27
///
28
/// The idea it's to have a representation of the field name as an enum
29
/// variant, avoiding to let the user passing around Strings and instead,
30
/// passing variants of a concrete enumeration type, that when required,
31
/// will be called though macro code to obtain the &str representation
32
/// of the field name.
33
3
pub fn generate_enum_with_fields(canyon_entity: &CanyonEntity) -> TokenStream {
34
3
    let ty = &canyon_entity.struct_name;
35
3
    let struct_name = canyon_entity.struct_name.to_string();
36
3
    let enum_name = Ident::new((struct_name + "Field").as_str(), Span::call_site());
37

            
38
3
    let fields_names = &canyon_entity.get_fields_as_enum_variants();
39
3
    let match_arms_str = &canyon_entity.create_match_arm_for_get_variant_as_str(&enum_name);
40

            
41
3
    let visibility = &canyon_entity.vis;
42
3
    let generics = &canyon_entity.generics;
43

            
44
3
    quote! {
45
        #[derive(Clone, Debug)]
46
        #[allow(non_camel_case_types)]
47
        #[allow(unused_variables)]
48
        #[allow(dead_code)]
49
        /// Auto-generated enum to represent every field of the related type
50
        /// as a variant of an enum that it's named with the concatenation
51
        /// of the type identifier + Field
52
        ///
53
        /// The idea it's to have a representation of the field name as an enum
54
        /// variant, avoiding the user to have to pass around Strings and instead,
55
        /// passing variants of a concrete enumeration type, that when required,
56
        /// will be called though macro code to obtain the &str representation
57
        /// of the field name.
58
        ///
59
        /// That's particularly useful in Canyon when working with queries being constructed
60
        /// through the [`QueryBuilder`], when one of the methods requires to get
61
        /// a column name (which is the name of some field of the type) as a parameter
62
        ///
63
        /// ```
64
        /// pub struct League {
65
        ///     id: i32,
66
        ///     name: String
67
        /// }
68
        ///
69
        /// #[derive(Debug)]
70
        /// #[allow(non_camel_case_types)]
71
        /// pub enum LeagueField {
72
        ///     id(i32),
73
        ///     name(String)
74
        /// }
75
        /// ```
76
        #visibility enum #enum_name #generics {
77
            #(#fields_names),*
78
        }
79

            
80
        impl #generics canyon_sql::crud::bounds::FieldIdentifier<#ty> for #generics #enum_name #generics {
81
            fn as_str(&self) -> &'static str {
82
                match *self {
83
                    #(#match_arms_str),*
84
                }
85
            }
86
        }
87
    }
88
3
}
89

            
90
/// Autogenerated Rust Enum type that contains as many variants
91
/// with inner value as fields has the structure to which it relates
92
///
93
/// The type of the inner value `(Enum::Variant(SomeType))` is the same
94
/// that the field that the variant represents
95
3
pub fn generate_enum_with_fields_values(canyon_entity: &CanyonEntity) -> TokenStream {
96
3
    let ty = &canyon_entity.struct_name;
97
3
    let struct_name = canyon_entity.struct_name.to_string();
98
3
    let enum_name = Ident::new((struct_name + "FieldValue").as_str(), Span::call_site());
99

            
100
3
    let fields_names = &canyon_entity.get_fields_as_enum_variants_with_value();
101
3
    let match_arms = &canyon_entity.create_match_arm_for_relate_fields_with_values(&enum_name);
102

            
103
3
    let visibility = &canyon_entity.vis;
104

            
105
3
    quote! {
106
        #[derive(Debug)]
107
        #[allow(non_camel_case_types)]
108
        #[allow(unused_variables)]
109
        #[allow(dead_code)]
110
        /// Auto-generated enumeration to represent each field of the related
111
        /// type as a variant, which can support and contain a value of the field data type.
112
        ///
113
        /// ```
114
        /// pub struct League {
115
        ///     id: i32,
116
        ///     name: String,
117
        ///     opt: Option<String>
118
        /// }
119
        ///
120
        /// #[derive(Debug)]
121
        /// #[allow(non_camel_case_types)]
122
        /// pub enum LeagueFieldValue {
123
        ///     id(i32),
124
        ///     name(String)
125
        ///     opt(Option<String>)
126
        /// }
127
        /// ```
128
        #visibility enum #enum_name<'a> {
129
            #(#fields_names),*
130
        }
131

            
132
        impl<'a> canyon_sql::crud::bounds::FieldValueIdentifier<'a, #ty> for #enum_name<'a> {
133
            fn value(self) -> (&'static str, &'a dyn QueryParameter<'a>) {
134
                match self {
135
                    #(#match_arms),*
136
                }
137
            }
138
        }
139
    }
140
3
}