toql_derive/to_tokens/tree_insert.rs
1use crate::parsed::{
2 field::{
3 field_kind::FieldKind,
4 join_field::JoinSelection,
5 merge_field::MergeSelection,
6 regular_field::{RegularSelection, SqlTarget},
7 },
8 parsed_struct::ParsedStruct,
9};
10use proc_macro2::TokenStream;
11
12pub(crate) fn to_tokens(parsed_struct: &ParsedStruct, tokens: &mut TokenStream) {
13 let mut insert_columns_code = Vec::new(); // For fields
14 let mut insert_values_code = Vec::new();
15
16 let mut dispatch_columns_code = Vec::new(); // for joins
17 let mut dispatch_values_code = Vec::new();
18
19 for field in &parsed_struct.fields {
20 if field.skip_mut {
21 continue;
22 }
23 let field_name_ident = &field.field_name;
24 let field_base_type = &field.field_base_type;
25 let field_query_name = &field.toql_query_name;
26
27 match &field.kind {
28 FieldKind::Skipped => {}
29 FieldKind::Regular(regular_kind) => {
30 if regular_kind.key && parsed_struct.auto_key {
31 continue;
32 }
33 match regular_kind.sql_target {
34 SqlTarget::Column(ref sql_column) => insert_columns_code.push(quote!(
35 e.push_literal(#sql_column);
36 e.push_literal(", ");
37 )),
38 SqlTarget::Expression(_) => {
39 continue;
40 }
41 }
42 insert_values_code.push( match regular_kind.selection {
43 RegularSelection::SelectNullable => {
44 // Option<Option<T>> (toql selectable of nullable column)
45 quote!(
46 if let Some(field) = &self . #field_name_ident {
47 values.push_arg(toql::sql_arg::SqlArg::from(field.as_ref()));
48 values.push_literal(", ");
49 } else {
50 values.push_literal("DEFAULT, ");
51 }
52 )
53 }
54 RegularSelection::PreselectNullable=> {
55 // Option<T> selected (nullable column)
56 quote!(
57 values.push_arg( toql::sql_arg::SqlArg::from(self . #field_name_ident.as_ref()));
58 values.push_literal(", ");
59 )
60 }
61 RegularSelection::Select => {
62 // Option<T> (toql selectable)
63 quote!(
64 if let Some(field) = &self . #field_name_ident {
65 values.push_arg( toql::sql_arg::SqlArg::from(field));
66 values.push_literal(", ");
67 } else {
68 values.push_literal("DEFAULT, ");
69 }
70 )
71 }
72 RegularSelection::Preselect => {
73 // selected field
74 quote!(
75 values.push_arg(toql::sql_arg::SqlArg::from(&self . #field_name_ident));
76 values.push_literal(", ");
77 )
78 }
79 });
80 }
81
82 FieldKind::Join(join_kind) => {
83 if join_kind.key && parsed_struct.auto_key {
84 continue;
85 }
86
87 dispatch_columns_code.push(quote!(
88 #field_query_name => {
89 return Ok(<#field_base_type as toql::tree::tree_insert::TreeInsert>::columns(descendents)?);
90 }
91 ));
92
93 dispatch_values_code.push(
94 match join_kind.selection {
95 JoinSelection::SelectLeft => {
96 // Option<Option<T>
97 quote!(
98 #field_query_name => {
99 if let Some(f) = self. #field_name_ident .as_ref() {
100 if let Some(f) = f .as_ref() {
101 toql::tree::tree_insert::TreeInsert::values(f, descendents, roles, should_insert, values)?
102 }
103 }
104 }
105 ) },
106 JoinSelection::SelectInner | JoinSelection::PreselectLeft => {
107 // Option<T>
108 quote!(
109 #field_query_name => {
110 if let Some(f) = self. #field_name_ident .as_ref() {
111 toql::tree::tree_insert::TreeInsert::values(f, descendents, roles, should_insert, values)?
112 }
113 }
114 ) },
115 JoinSelection::PreselectInner => {
116 // T
117 quote!(
118 #field_query_name => {
119 toql::tree::tree_insert::TreeInsert::
120 values(& self. #field_name_ident, descendents, roles, should_insert, values)?
121 }
122 )}
123 }
124 );
125 let columns_map_code = &join_kind.columns_map_code;
126 let default_self_column_code = &join_kind.default_self_column_code;
127
128 // Add if columns should not be skipped
129
130 if !join_kind.partial_table {
131 insert_columns_code.push(quote!(
132 for other_column in <<#field_base_type as toql::keyed::Keyed>::Key as toql::key::Key>::columns() {
133 #default_self_column_code;
134 let self_column = #columns_map_code;
135 e.push_literal(self_column);
136 e.push_literal(", ");
137 }
138 ));
139
140 insert_values_code.push(
141 match join_kind.selection {
142 JoinSelection::SelectLeft => { // Option<Option<T>>
143 quote!(
144 if let Some(field) = &self. #field_name_ident {
145 if let Some(f) = field {
146 toql :: key :: Key :: params(& toql :: keyed :: Keyed :: key(f))
147 .iter()
148 .for_each(|p| {
149 values.push_arg(p.to_owned());
150 values.push_literal(", ");
151 });
152 } else {
153 <<#field_base_type as toql::keyed::Keyed>::Key as toql::key::Key>::columns()
154 .iter().for_each(|_| {
155 values.push_arg(toql::sql_arg::SqlArg::Null);
156 values.push_literal(", ");});
157
158 }
159 } else {
160 <<#field_base_type as toql::keyed::Keyed>::Key as toql::key::Key>::columns().iter().for_each(|_| { values.push_literal("DEFAULT, ");});
161 }
162
163 )
164 },
165 JoinSelection::PreselectLeft => { // #[toql(preselect)] Option<T>
166 // TODO Option wrapping
167 quote!(
168 if let Some(f) = &self. #field_name_ident {
169 toql :: key :: Key :: params(& toql :: keyed :: Keyed :: key(f))
170 .iter()
171 .for_each(|p| {
172 values.push_arg(p.to_owned());
173 values.push_literal(", ");
174 });
175 } else {
176 <<#field_base_type as toql::keyed::Keyed>::Key as toql::key::Key>::columns()
177 .iter().for_each(|_| {
178 values.push_arg(toql::sql_arg::SqlArg::Null);
179 values.push_literal(", ");
180 });
181 }
182 )
183 },
184
185 JoinSelection::SelectInner => { // Option<T> selectable
186 quote!(
187 if let Some(field) = &self. #field_name_ident {
188 toql :: key :: Key :: params(& toql :: keyed :: Keyed :: key(field))
189 .iter()
190 .for_each(|p| {
191 values.push_arg(p.to_owned());
192 values.push_literal(", ");
193 });
194 } else {
195 <<#field_base_type as toql::keyed::Keyed>::Key as toql::key::Key>::columns()
196 .iter().for_each(|_| {values.push_literal("DEFAULT, ");});
197 }
198 )
199 },
200 JoinSelection::PreselectInner => { // T
201 quote!(
202 &toql::key::Key::params( &toql::keyed::Keyed::key(&self. #field_name_ident))
203 .into_iter() .for_each(|a| {values.push_arg(a); values.push_literal(", " );});
204 )
205 }
206 }
207 );
208 }
209 }
210 FieldKind::Merge(merge_kind) => {
211 dispatch_columns_code.push(
212 quote!(
213 #field_query_name => {
214 return Ok(<#field_base_type as toql::tree::tree_insert::TreeInsert>::columns( descendents)?);
215 }
216 )
217 );
218 dispatch_values_code.push(
219 match merge_kind.selection {
220 MergeSelection::Preselect => {
221 // Vec<T>
222 quote!(
223 #field_query_name => {
224 for f in &self. #field_name_ident{
225 toql::tree::tree_insert::TreeInsert::values(f, descendents.clone(), roles, should_insert, values)?
226 }
227 }
228 )
229 }
230 MergeSelection::Select => {
231 // Option<Vec<T>>
232 quote!(
233 #field_query_name => {
234 if let Some (fs) = self. #field_name_ident .as_ref(){
235 for f in fs {
236 toql::tree::tree_insert::TreeInsert::values(f, descendents.clone(), roles, should_insert, values)?
237 }
238 }
239 }
240 )
241 },
242 }
243 );
244 }
245 };
246 }
247 let struct_name_ident = &parsed_struct.struct_name;
248 let struct_name = parsed_struct.struct_name.to_string();
249 let role_assert = if let Some(role_expr_string) = &parsed_struct.roles.insert {
250 quote!(
251 let role_expr = toql::role_expr_macro::role_expr!(#role_expr_string);
252 if !toql::role_validator::RoleValidator::is_valid(roles, &role_expr) {
253 return Err( toql::sql_builder::sql_builder_error::SqlBuilderError::RoleRequired(role_expr.to_string(), format!("mapper `{}`", #struct_name) ).into())
254 }
255 )
256 } else {
257 quote!()
258 };
259
260 let mods = quote! {
261 impl toql::tree::tree_insert::TreeInsert for #struct_name_ident {
262
263 #[allow(unused_mut)]
264 fn columns<'a, I>( mut descendents: I)
265 -> std::result::Result<toql::sql_expr::SqlExpr, toql::error::ToqlError>
266 where I: Iterator<Item = toql::query::field_path::FieldPath<'a>>
267 {
268
269 let mut e = toql::sql_expr::SqlExpr::new();
270 match descendents.next() {
271 Some(d) => match d.as_str() {
272 #(#dispatch_columns_code),*
273 f @ _ => {
274 return Err(
275 toql::sql_builder::sql_builder_error::SqlBuilderError::FieldMissing(f.to_string()).into());
276 }
277 },
278 None => {
279 e.push_literal("(");
280 #(#insert_columns_code)*
281 e.pop_literals(2);
282 e.push_literal(")");
283 }
284 }
285 Ok(e)
286 }
287 #[allow(unused_mut, unused_variables)]
288 fn values<'a,'b, I, J>(&self,
289 mut descendents: I,
290 roles: &std::collections::HashSet<String>,
291 mut should_insert: &mut J,
292 values: &mut toql::sql_expr::SqlExpr
293 ) -> std::result::Result<(), toql::error::ToqlError>
294 where I: Iterator<Item = toql::query::field_path::FieldPath<'a>> + Clone,
295 J: Iterator<Item =&'b bool >
296 {
297
298 match descendents.next() {
299 Some(d) => match d.as_str() {
300 #(#dispatch_values_code),*
301 f @ _ => {
302 return Err(
303 toql::sql_builder::sql_builder_error::SqlBuilderError::FieldMissing(f.to_string()).into());
304 }
305 },
306 None => {
307 if !*should_insert.next().unwrap_or(&false) {
308 return Ok(())
309 }
310
311 #role_assert
312
313 values.push_literal("(");
314 #(#insert_values_code)*
315 values.pop_literals(2);
316 values.push_literal("), ");
317 }
318 }
319 Ok(())
320 }
321 }
322
323 impl toql::tree::tree_insert::TreeInsert for &#struct_name_ident {
324
325 #[allow(unused_mut)]
326 fn columns<'a, I>( mut descendents: I)
327 -> std::result::Result<toql::sql_expr::SqlExpr, toql::error::ToqlError>
328 where I: Iterator<Item = toql::query::field_path::FieldPath<'a>> {
329 <#struct_name_ident as toql::tree::tree_insert::TreeInsert>::columns(descendents)
330 }
331 #[allow(unused_mut)]
332 fn values<'a,'b, I, J>(&self,
333 mut descendents: I,
334 roles: &std::collections::HashSet<String>,
335 mut should_insert: &mut J,
336 values: &mut toql::sql_expr::SqlExpr
337 ) -> std::result::Result<(), toql::error::ToqlError>
338 where I: Iterator<Item = toql::query::field_path::FieldPath<'a>> + Clone,
339 J: Iterator<Item =&'b bool >
340 {
341 <#struct_name_ident as toql::tree::tree_insert::TreeInsert>::values(self, descendents, roles, should_insert, values)
342 }
343 }
344 impl toql::tree::tree_insert::TreeInsert for &mut #struct_name_ident {
345
346 #[allow(unused_mut)]
347 fn columns<'a, I>( mut descendents: I)
348 -> std::result::Result<toql::sql_expr::SqlExpr, toql::error::ToqlError>
349 where I: Iterator<Item = toql::query::field_path::FieldPath<'a>> {
350 <#struct_name_ident as toql::tree::tree_insert::TreeInsert>::columns(descendents)
351 }
352 #[allow(unused_mut)]
353 fn values<'a,'b, I, J>(&self,
354 mut descendents: I ,
355 roles: &std::collections::HashSet<String>,
356 mut should_insert: &mut J,
357 values: &mut toql::sql_expr::SqlExpr
358 ) -> std::result::Result<(), toql::error::ToqlError>
359 where I: Iterator<Item = toql::query::field_path::FieldPath<'a>> + Clone,
360 J: Iterator<Item =&'b bool >
361 {
362 <#struct_name_ident as toql::tree::tree_insert::TreeInsert>::values(self, descendents, roles, should_insert, values)
363 }
364 }
365
366
367 };
368
369 log::debug!("Source code for `{}`:\n{}", struct_name, mods.to_string());
370 tokens.extend(mods);
371}