taitan_orm_macro/
lib.rs

1#![allow(dead_code)]
2#![forbid(unsafe_code)]
3use proc_macro::TokenStream;
4use quote::{format_ident, quote};
5use syn::{parse_macro_input, DeriveInput};
6use taitan_orm_parser::{ConditionDef, DatabaseType, EntityTraitImplGenerator, IndexEnum, IndexStructGenerator, InputParser, LocationEnumGenerator, LocationTraitImplGenerator, MutationStructGenerator, MutationTraitImplGenerator, OrderByStructGenerator, ParameterTraitImplGenerator, SelectedDefaultImplGenerator, SelectedStructGenerator, SelectedTraitImplGenerator, TableDef, TemplateArgTraitImplGenerator, TemplateTraitImplGenerator};
7use taitan_orm_askama::derive_askama_template;
8
9fn get_supported_database_types() -> Vec<DatabaseType> {
10    let mut supported_database_types: Vec<DatabaseType> = Vec::new();
11    #[cfg(feature = "sqlite")]
12    supported_database_types.push(DatabaseType::Sqlite);
13    #[cfg(feature = "mysql")]
14    supported_database_types.push(DatabaseType::MySql);
15    #[cfg(feature = "postgres")]
16    supported_database_types.push(DatabaseType::Postgres);
17
18    if supported_database_types.is_empty() {
19        panic!("The database type is empty, you should set features");
20    }
21
22    supported_database_types
23}
24
25#[proc_macro_derive(
26    Schema,
27    attributes(
28        debug,
29        table,
30        primary,
31        unique,
32        auto_increment,
33        generated,
34        field,
35        serde_struct,
36        index
37    )
38)]
39pub fn expand_schema_new_macro(input: TokenStream) -> TokenStream {
40    let derive_input = parse_macro_input!(input as DeriveInput);
41    let table_def = TableDef::parse(&derive_input);
42
43    // panic!("{:?}", table_def);
44
45    let index_generator = IndexStructGenerator::default();
46    let mut stream = TokenStream::new();
47    generate_param_impl(&mut stream, &table_def);
48    generate_entity_impl(&mut stream, &table_def);
49
50    let supported_database_types = get_supported_database_types();
51    let primary_stream: TokenStream = index_generator
52        .generate(&table_def, &IndexEnum::Primary, &supported_database_types)
53        .into();
54    stream.extend(primary_stream.clone());
55
56    for unique in &table_def.uniques {
57        let index_type = IndexEnum::Unique {
58            name: unique.name.to_string(),
59        };
60        let index_stream: TokenStream = index_generator
61            .generate(&table_def, &index_type, &supported_database_types)
62            .into();
63        stream.extend(index_stream);
64    }
65    for index in &table_def.indexes {
66        let index_type = IndexEnum::Index {
67            name: index.name.to_string(),
68        };
69        let index_stream: TokenStream = index_generator
70            .generate(&table_def, &index_type, &supported_database_types)
71            .into();
72        stream.extend(index_stream);
73    }
74    let mutation_generator = MutationStructGenerator::default();
75    let mutation_struct_stream: TokenStream = mutation_generator.generate(&table_def).into();
76    stream.extend(mutation_struct_stream);
77
78    let location_generator = LocationEnumGenerator::default();
79    let location_stream: TokenStream = location_generator.generate(&table_def).into();
80    stream.extend(location_stream);
81
82    let selected_generator = SelectedStructGenerator::default();
83    let selected_struct_stream: TokenStream = selected_generator.generate(&table_def).into();
84    stream.extend(selected_struct_stream);
85
86    let order_by_generator = OrderByStructGenerator::default();
87    let order_by_struct_stream: TokenStream = order_by_generator.generate(&table_def).into();
88    stream.extend(order_by_struct_stream);
89
90    // panic!("{}", stream);
91    stream.into()
92}
93
94
95fn generate_param_impl(stream: &mut TokenStream, table_def: &TableDef) {
96    let generator = ParameterTraitImplGenerator::default();
97    let supported_database_types = get_supported_database_types();
98    for database_type in supported_database_types {
99        let s: TokenStream = generator.gen_add_to_args(&database_type, &table_def).into();
100        stream.extend(s);
101    }
102}
103
104fn generate_enum_param_impl(stream: &mut TokenStream, cond_def: &ConditionDef) {
105    let generator = ParameterTraitImplGenerator::default();
106    let supported_database_types = get_supported_database_types();
107    for database_type in supported_database_types {
108        let s: TokenStream = generator.gen_enum_add_to_args(&database_type, &cond_def).into();
109        stream.extend(s);
110    }
111}
112
113#[proc_macro_derive(Parameter, attributes(field))]
114pub fn expand_param_macro(input: TokenStream) -> TokenStream {
115    let derive_input = parse_macro_input!(input as DeriveInput);
116    let is_enum = InputParser::is_enum(&derive_input.data);
117    if !is_enum {
118        let table_def = TableDef::parse(&derive_input);
119        let mut stream = TokenStream::new();
120        generate_param_impl(&mut stream, &table_def);
121        // panic!("{}", stream);
122        stream.into()
123    } else {
124        let cond_def = ConditionDef::parse(&derive_input);
125        let mut stream = TokenStream::new();
126        generate_enum_param_impl(&mut stream, &cond_def);
127        // panic!("{}", stream);
128        stream.into()
129    }
130
131}
132
133fn generate_template_arg_impl(stream: &mut TokenStream, table_def: &TableDef) {
134    let generator = TemplateArgTraitImplGenerator::default();
135    let supported_database_types = get_supported_database_types();
136    for database_type in supported_database_types {
137        let s: TokenStream = generator.gen_add_to_args(&database_type, &table_def).into();
138        stream.extend(s);
139    }
140}
141
142#[proc_macro_derive(TemplateArg, attributes(field))]
143pub fn expand_template_arg_macro(input: TokenStream) -> TokenStream {
144    let derive_input = parse_macro_input!(input as DeriveInput);
145    let table_def = TableDef::parse(&derive_input);
146    let mut stream = TokenStream::new();
147    generate_template_arg_impl(&mut stream, &table_def);
148    // panic!("{}", stream);
149    stream.into()
150}
151
152fn generate_template_new_impl(stream: &mut TokenStream, table_def: &TableDef) {
153    let generator = TemplateTraitImplGenerator::default();
154    let supported_database_types = get_supported_database_types();
155    for database_type in supported_database_types {
156        let s: TokenStream = generator.generate(&database_type, &table_def).into();
157        stream.extend(s);
158    }
159
160    // add impl TemplateSqlTrait
161    let struct_name = &table_def.struct_name;
162    let struct_ident = format_ident!("{}", &struct_name);
163    let s: TokenStream = quote! {
164        impl taitan_orm::traits::TemplateSqlTrait for #struct_ident {
165        }
166    }.into();
167    stream.extend(s);
168}
169
170#[proc_macro_derive(Template, attributes(template))]
171pub fn expand_template_new_macro(input: TokenStream) -> TokenStream {
172    let askama_template_impl: TokenStream = derive_askama_template(input.clone().into()).into();
173    let derive_input = parse_macro_input!(input as DeriveInput);
174    let table_def = TableDef::parse(&derive_input);
175    let mut stream = TokenStream::new();
176    stream.extend(askama_template_impl);
177    generate_template_new_impl(&mut stream, &table_def);
178    generate_template_arg_impl(&mut stream, &table_def);
179    // panic!("{}", stream);
180    stream.into()
181}
182
183fn generate_entity_impl(stream: &mut TokenStream, table_def: &TableDef) {
184    let generator = EntityTraitImplGenerator::default();
185    let supported_database_types = get_supported_database_types();
186    for database_type in supported_database_types {
187        let s: TokenStream = generator.generate(&database_type, &table_def).into();
188        stream.extend(s);
189    }
190}
191
192#[proc_macro_derive(Entity, attributes(field))]
193pub fn expand_entity_new_macro(input: TokenStream) -> TokenStream {
194    let derive_input = parse_macro_input!(input as DeriveInput);
195    let table_def = TableDef::parse(&derive_input);
196    let mut stream = TokenStream::new();
197    generate_entity_impl(&mut stream, &table_def);
198    // panic!("{}", stream);
199    stream.into()
200}
201
202#[proc_macro_derive(Location, attributes(table, field))]
203pub fn expand_location_new_macro(input: TokenStream) -> TokenStream {
204    let derive_input = parse_macro_input!(input as DeriveInput);
205    let condition_def = ConditionDef::parse(&derive_input);
206    let generator = LocationTraitImplGenerator::default();
207    let supported_database_types = get_supported_database_types();
208    let mut stream = TokenStream::new();
209    for database_type in supported_database_types {
210        let s: TokenStream = generator.generate(&database_type, &condition_def).into();
211        stream.extend(s);
212    }
213    // panic!("{}", stream);
214    stream.into()
215}
216
217#[proc_macro_derive(Mutation, attributes(field))]
218pub fn expand_mutation_new_macro(input: TokenStream) -> TokenStream {
219    let derive_input = parse_macro_input!(input as DeriveInput);
220    let table_def = TableDef::parse(&derive_input);
221    let generator = MutationTraitImplGenerator::default();
222    let supported_database_types = get_supported_database_types();
223    let mut stream = TokenStream::new();
224    for database_type in supported_database_types {
225        let s: TokenStream = generator.generate(&database_type, &table_def).into();
226        stream.extend(s);
227    }
228    // panic!("{}", stream);
229    stream.into()
230}
231
232#[proc_macro_derive(Selected, attributes(field))]
233pub fn expand_selected_new_macro(input: TokenStream) -> TokenStream {
234    let derive_input = parse_macro_input!(input as DeriveInput);
235    let table_def = TableDef::parse(&derive_input);
236    let generator = SelectedTraitImplGenerator::default();
237    let supported_database_types = get_supported_database_types();
238    let mut stream = TokenStream::new();
239    for database_type in supported_database_types {
240        let s: TokenStream = generator.generate(&database_type, &table_def).into();
241        stream.extend(s);
242    }
243    let default_generator = SelectedDefaultImplGenerator::default();
244    let default_stream: TokenStream = default_generator.generate(&table_def).into();
245    stream.extend(default_stream);
246
247    // panic!("{}", stream);
248    stream.into()
249}