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 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 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 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 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 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 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 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 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 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 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 stream.into()
249}