1use proc_macro::TokenStream;
2use quote::{format_ident, quote};
3use syn::{
4 parse_macro_input, Attribute, Field, Fields, Ident, ItemStruct, Meta, Type,
5};
6use syn::parse::Parser;
7
8#[proc_macro_derive(Model, attributes(model, key, autoincrement, unique, index, has_many, belongs_to, many_to_many))]
9pub fn derive_model(_input: TokenStream) -> TokenStream {
10 TokenStream::from(quote! {
11 compile_error!("dbkit: use #[model] instead of #[derive(Model)]");
12 })
13}
14
15#[proc_macro_attribute]
16pub fn model(attr: TokenStream, item: TokenStream) -> TokenStream {
17 let input = parse_macro_input!(item as ItemStruct);
18 let args = parse_macro_input!(attr with syn::punctuated::Punctuated::<Meta, syn::Token![,]>::parse_terminated);
19 let args = parse_model_args(args);
20 match expand_model(args, input) {
21 Ok(tokens) => tokens,
22 Err(err) => err.to_compile_error().into(),
23 }
24}
25
26#[derive(Debug, Clone, Copy, PartialEq, Eq)]
27enum RelationKind {
28 HasMany,
29 BelongsTo,
30 ManyToMany,
31}
32
33struct RelationInfo {
34 field: Field,
35 param_ident: Ident,
36 state_mod_ident: Ident,
37 child_type: Type,
38 kind: RelationKind,
39 belongs_to_key: Option<Ident>,
40 belongs_to_ref: Option<Ident>,
41 many_to_many_through: Option<Ident>,
42 many_to_many_left_key: Option<Ident>,
43 many_to_many_right_key: Option<Ident>,
44}
45
46struct ScalarFieldInfo {
47 field: Field,
48 ident: Ident,
49 ty: Type,
50 is_key: bool,
51 is_autoincrement: bool,
52}
53
54#[derive(Default)]
55struct ModelArgs {
56 table: Option<String>,
57 schema: Option<String>,
58}
59
60fn expand_model(args: ModelArgs, input: ItemStruct) -> syn::Result<TokenStream> {
61 if !input.generics.params.is_empty() {
62 return Err(syn::Error::new_spanned(
63 input.generics,
64 "dbkit: #[model] does not support generics yet",
65 ));
66 }
67
68 let struct_ident = input.ident;
69 let model_ident = format_ident!("{}Model", struct_ident);
70 let insert_ident = format_ident!("{}Insert", struct_ident);
71 let vis = input.vis;
72
73 let table_name = args
74 .table
75 .unwrap_or_else(|| to_snake_case(&struct_ident.to_string()));
76 let schema_name = args.schema;
77
78 let mut primary_keys: Vec<(Ident, Type)> = Vec::new();
79 let mut relation_fields = Vec::new();
80 let mut output_fields = Vec::new();
81 let mut insert_fields = Vec::new();
82 let mut scalar_fields = Vec::new();
83
84 let struct_attrs = filter_struct_attrs(&input.attrs);
85
86 let fields = match input.fields {
87 Fields::Named(named) => named.named,
88 _ => {
89 return Err(syn::Error::new_spanned(
90 struct_ident,
91 "dbkit: #[model] requires a struct with named fields",
92 ))
93 }
94 };
95
96 for field in fields {
97 let field_ident = field
98 .ident
99 .clone()
100 .ok_or_else(|| syn::Error::new_spanned(&field, "dbkit: unnamed field"))?;
101
102 let is_relation = has_attr(&field.attrs, "has_many")
103 || has_attr(&field.attrs, "belongs_to")
104 || has_attr(&field.attrs, "many_to_many");
105
106 let is_key = has_attr(&field.attrs, "key");
107 let is_autoincrement = has_attr(&field.attrs, "autoincrement");
108
109 if is_key {
110 primary_keys.push((field_ident.clone(), field.ty.clone()));
111 }
112
113 if is_relation {
114 let (kind, child_type) = relation_type(&field)?;
115 let state_mod_ident = format_ident!(
116 "{}_{}_state",
117 to_snake_case(&struct_ident.to_string()),
118 field_ident
119 );
120 let param_ident = format_ident!("{}Rel", to_camel_case(&field_ident.to_string()));
121 let (belongs_to_key, belongs_to_ref) = if kind == RelationKind::BelongsTo {
122 let (key, references) = parse_belongs_to_args(&field.attrs)?;
123 (Some(key), Some(references))
124 } else {
125 (None, None)
126 };
127 let (many_to_many_through, many_to_many_left_key, many_to_many_right_key) =
128 if kind == RelationKind::ManyToMany {
129 let (through, left_key, right_key) = parse_many_to_many_args(&field.attrs)?;
130 (Some(through), Some(left_key), Some(right_key))
131 } else {
132 (None, None, None)
133 };
134
135 relation_fields.push(RelationInfo {
136 field: field.clone(),
137 param_ident: param_ident.clone(),
138 state_mod_ident,
139 child_type,
140 kind,
141 belongs_to_key,
142 belongs_to_ref,
143 many_to_many_through,
144 many_to_many_left_key,
145 many_to_many_right_key,
146 });
147
148 let cleaned_field = Field {
149 attrs: filter_field_attrs(&field.attrs),
150 ty: syn::parse_quote!(#param_ident),
151 ..field
152 };
153 output_fields.push(cleaned_field);
154 continue;
155 }
156
157 let cleaned_field = Field {
158 attrs: filter_field_attrs(&field.attrs),
159 ..field.clone()
160 };
161 output_fields.push(cleaned_field.clone());
162
163 if !(is_key && is_autoincrement) {
164 insert_fields.push(cleaned_field.clone());
165 }
166
167 scalar_fields.push(ScalarFieldInfo {
168 field: cleaned_field,
169 ident: field_ident,
170 ty: field.ty.clone(),
171 is_key,
172 is_autoincrement,
173 });
174 }
175
176 let table_expr = if let Some(schema) = schema_name {
177 quote!(::dbkit::Table::new(#table_name).with_schema(#schema))
178 } else {
179 quote!(::dbkit::Table::new(#table_name))
180 };
181
182 if relation_fields
183 .iter()
184 .any(|rel| rel.kind == RelationKind::ManyToMany)
185 && primary_keys.len() != 1
186 {
187 return Err(syn::Error::new_spanned(
188 struct_ident,
189 "dbkit: many-to-many requires exactly one #[key] on the parent model",
190 ));
191 }
192
193 let generics_with_defaults = relation_fields
194 .iter()
195 .map(|rel| {
196 let ident = &rel.param_ident;
197 let state_mod = &rel.state_mod_ident;
198 quote!(#ident: #state_mod::State = ::dbkit::NotLoaded)
199 })
200 .collect::<Vec<_>>();
201
202 let impl_generics_params = relation_fields
203 .iter()
204 .map(|rel| {
205 let ident = &rel.param_ident;
206 let state_mod = &rel.state_mod_ident;
207 quote!(#ident: #state_mod::State)
208 })
209 .collect::<Vec<_>>();
210
211 let generic_idents = relation_fields
212 .iter()
213 .map(|rel| &rel.param_ident)
214 .collect::<Vec<_>>();
215
216 let struct_generics = if generics_with_defaults.is_empty() {
217 quote!()
218 } else {
219 quote!(<#(#generics_with_defaults),*>)
220 };
221
222 let impl_generics = if impl_generics_params.is_empty() {
223 quote!()
224 } else {
225 quote!(<#(#impl_generics_params),*>)
226 };
227
228 let struct_type_args = if generic_idents.is_empty() {
229 quote!()
230 } else {
231 quote!(<#(#generic_idents),*>)
232 };
233
234 let columns = output_fields
235 .iter()
236 .filter(|field| !is_relation_field(field, &relation_fields))
237 .map(|field| {
238 let ident = field.ident.as_ref().expect("field ident");
239 let name = ident.to_string();
240 let ty = option_inner_type(&field.ty).unwrap_or_else(|| field.ty.clone());
241 quote!(pub const #ident: ::dbkit::Column<#struct_ident, #ty> = ::dbkit::Column::new(Self::TABLE, #name);)
242 })
243 .collect::<Vec<_>>();
244
245 let column_refs = output_fields
246 .iter()
247 .filter(|field| !is_relation_field(field, &relation_fields))
248 .map(|field| {
249 let ident = field.ident.as_ref().expect("field ident");
250 quote!(Self::#ident.as_ref())
251 })
252 .collect::<Vec<_>>();
253
254 let columns_const = quote!(
255 pub const COLUMNS: &'static [::dbkit::ColumnRef] = &[#(#column_refs),*];
256 );
257
258 let primary_key_refs = primary_keys
259 .iter()
260 .map(|(ident, _)| quote!(Self::#ident.as_ref()))
261 .collect::<Vec<_>>();
262
263 let primary_keys_const = if primary_keys.is_empty() {
264 quote!(pub const PRIMARY_KEYS: &'static [::dbkit::ColumnRef] = &[];)
265 } else {
266 quote!(pub const PRIMARY_KEYS: &'static [::dbkit::ColumnRef] = &[#(#primary_key_refs),*];)
267 };
268
269 let insert_values = insert_fields.iter().map(|field| {
270 let ident = field.ident.as_ref().expect("field ident");
271 quote!(insert = insert.value(Self::#ident, values.#ident);)
272 });
273 let insert_field_idents = insert_fields
274 .iter()
275 .map(|field| field.ident.as_ref().expect("field ident"))
276 .collect::<Vec<_>>();
277
278 let active_ident = format_ident!("{}Active", struct_ident);
279
280 let active_fields = scalar_fields.iter().map(|field| {
281 let ident = &field.ident;
282 let vis = &field.field.vis;
283 let ty = option_inner_type(&field.ty).unwrap_or_else(|| field.ty.clone());
284 quote!(#vis #ident: ::dbkit::ActiveValue<#ty>)
285 });
286
287 let active_from_model = scalar_fields.iter().map(|field| {
288 let ident = &field.ident;
289 if option_inner_type(&field.ty).is_some() {
290 quote!(#ident: ::dbkit::ActiveValue::unchanged_option(#ident))
291 } else {
292 quote!(#ident: ::dbkit::ActiveValue::unchanged(#ident))
293 }
294 });
295
296 let active_destructure = scalar_fields
297 .iter()
298 .map(|field| field.ident.clone())
299 .collect::<Vec<_>>();
300
301 let active_insert_steps = scalar_fields.iter().map(|field| {
302 let ident = &field.ident;
303 let name = ident.to_string();
304 let ty = option_inner_type(&field.ty).unwrap_or_else(|| field.ty.clone());
305 let is_option = option_inner_type(&field.ty).is_some();
306 let required = !field.is_autoincrement && !is_option;
307 let required_check = if required {
308 quote!(return Err(::dbkit::Error::Decode(format!("missing required field: {}", #name)));)
309 } else {
310 quote!()
311 };
312 quote!(
313 match #ident {
314 ::dbkit::ActiveValue::Unset => {
315 #required_check
316 }
317 ::dbkit::ActiveValue::Set(value) => {
318 insert = insert.value(#struct_ident::#ident, value);
319 }
320 ::dbkit::ActiveValue::Unchanged(value) => {
321 insert = insert.value(#struct_ident::#ident, value);
322 }
323 ::dbkit::ActiveValue::UnchangedNull => {
324 insert = insert.value(#struct_ident::#ident, None::<#ty>);
325 }
326 ::dbkit::ActiveValue::Null => {
327 insert = insert.value(#struct_ident::#ident, None::<#ty>);
328 }
329 }
330 )
331 });
332
333 let active_insert_fn = quote!(
334 pub async fn insert(
335 self,
336 ex: &mut (impl ::dbkit::Executor + Send),
337 ) -> Result<#struct_ident, ::dbkit::Error> {
338 let Self { #(#active_destructure,)* } = self;
339 let mut insert = ::dbkit::Insert::new(#struct_ident::TABLE);
340 #(#active_insert_steps)*
341 let insert = insert.returning_all();
342 let row = ::dbkit::InsertExt::one(insert, ex).await?;
343 row.ok_or(::dbkit::Error::NotFound)
344 }
345 );
346
347 let pk_idents = primary_keys
348 .iter()
349 .map(|(ident, _)| ident.clone())
350 .collect::<Vec<_>>();
351
352 let active_update_fn = if !primary_keys.is_empty() {
353 let pk_vars = primary_keys
354 .iter()
355 .enumerate()
356 .map(|(idx, _)| format_ident!("pk_value_{}", idx))
357 .collect::<Vec<_>>();
358 let pk_extracts = primary_keys
359 .iter()
360 .zip(pk_vars.iter())
361 .map(|((ident, _), var)| {
362 let pk_name = ident.to_string();
363 quote!(
364 let #var = match #ident {
365 ::dbkit::ActiveValue::Set(value) | ::dbkit::ActiveValue::Unchanged(value) => value,
366 ::dbkit::ActiveValue::Null | ::dbkit::ActiveValue::Unset | ::dbkit::ActiveValue::UnchangedNull => {
367 return Err(::dbkit::Error::Decode(format!(
368 "missing required field: {}",
369 #pk_name
370 )));
371 }
372 };
373 )
374 });
375 let pk_filters = primary_keys
376 .iter()
377 .zip(pk_vars.iter())
378 .map(|((ident, _), var)| {
379 quote!(update = update.filter(#struct_ident::#ident.eq(#var));)
380 });
381 let update_steps = scalar_fields
382 .iter()
383 .filter(|field| !field.is_key)
384 .map(|field| {
385 let ident = &field.ident;
386 let ty = option_inner_type(&field.ty).unwrap_or_else(|| field.ty.clone());
387 quote!(
388 match #ident {
389 ::dbkit::ActiveValue::Unset => {}
390 ::dbkit::ActiveValue::Set(value) => {
391 update = update.set(#struct_ident::#ident, value);
392 any_set = true;
393 }
394 ::dbkit::ActiveValue::Unchanged(_) | ::dbkit::ActiveValue::UnchangedNull => {}
395 ::dbkit::ActiveValue::Null => {
396 update = update.set(#struct_ident::#ident, None::<#ty>);
397 any_set = true;
398 }
399 }
400 )
401 });
402 quote!(
403 pub async fn update(
404 self,
405 ex: &mut (impl ::dbkit::Executor + Send),
406 ) -> Result<#struct_ident, ::dbkit::Error> {
407 let Self { #(#active_destructure,)* } = self;
408 #(#pk_extracts)*
409 let mut update = ::dbkit::Update::new(#struct_ident::TABLE);
410 let mut any_set = false;
411 #(#update_steps)*
412 if !any_set {
413 return Err(::dbkit::Error::Decode("no fields set for update".to_string()));
414 }
415 #(#pk_filters)*
416 let update = update.returning_all();
417 let mut rows = ::dbkit::UpdateExt::all(update, ex).await?;
418 rows.pop().ok_or(::dbkit::Error::NotFound)
419 }
420 )
421 } else {
422 quote!()
423 };
424
425 let active_delete_fn = if !primary_keys.is_empty() {
426 let pk_vars = primary_keys
427 .iter()
428 .enumerate()
429 .map(|(idx, _)| format_ident!("pk_value_{}", idx))
430 .collect::<Vec<_>>();
431 let pk_extracts = primary_keys
432 .iter()
433 .zip(pk_vars.iter())
434 .map(|((ident, _), var)| {
435 let pk_name = ident.to_string();
436 quote!(
437 let #var = match #ident {
438 ::dbkit::ActiveValue::Set(value) | ::dbkit::ActiveValue::Unchanged(value) => value,
439 ::dbkit::ActiveValue::Null | ::dbkit::ActiveValue::Unset | ::dbkit::ActiveValue::UnchangedNull => {
440 return Err(::dbkit::Error::Decode(format!(
441 "missing required field: {}",
442 #pk_name
443 )));
444 }
445 };
446 )
447 });
448 let pk_filters = primary_keys
449 .iter()
450 .zip(pk_vars.iter())
451 .map(|((ident, _), var)| {
452 quote!(delete = delete.filter(#struct_ident::#ident.eq(#var));)
453 });
454 quote!(
455 pub async fn delete(
456 self,
457 ex: &mut (impl ::dbkit::Executor + Send),
458 ) -> Result<u64, ::dbkit::Error> {
459 let Self { #(#pk_idents,)* .. } = self;
460 #(#pk_extracts)*
461 let mut delete = ::dbkit::Delete::new(#struct_ident::TABLE);
462 #(#pk_filters)*
463 ::dbkit::DeleteExt::execute(delete, ex).await
464 }
465 )
466 } else {
467 quote!()
468 };
469
470 let active_save_flag_checks = scalar_fields.iter().map(|field| {
471 let ident = &field.ident;
472 quote!(
473 match &#ident {
474 ::dbkit::ActiveValue::Unchanged(_) | ::dbkit::ActiveValue::UnchangedNull => {
475 any_loaded = true;
476 }
477 ::dbkit::ActiveValue::Set(_) | ::dbkit::ActiveValue::Null => {
478 any_changed = true;
479 }
480 ::dbkit::ActiveValue::Unset => {}
481 }
482 )
483 });
484
485 let active_save_model_fields = scalar_fields.iter().map(|field| {
486 let ident = &field.ident;
487 let name = ident.to_string();
488 if option_inner_type(&field.ty).is_some() {
489 quote!(
490 #ident: match #ident {
491 ::dbkit::ActiveValue::Set(value) | ::dbkit::ActiveValue::Unchanged(value) => Some(value),
492 ::dbkit::ActiveValue::Null | ::dbkit::ActiveValue::UnchangedNull => None,
493 ::dbkit::ActiveValue::Unset => {
494 return Err(::dbkit::Error::Decode(format!(
495 "missing required field: {}",
496 #name
497 )));
498 }
499 },
500 )
501 } else {
502 quote!(
503 #ident: match #ident {
504 ::dbkit::ActiveValue::Set(value) | ::dbkit::ActiveValue::Unchanged(value) => value,
505 ::dbkit::ActiveValue::Null
506 | ::dbkit::ActiveValue::Unset
507 | ::dbkit::ActiveValue::UnchangedNull => {
508 return Err(::dbkit::Error::Decode(format!(
509 "missing required field: {}",
510 #name
511 )));
512 }
513 },
514 )
515 }
516 });
517
518 let active_save_relation_defaults = relation_fields.iter().map(|rel| {
519 let ident = rel.field.ident.as_ref().expect("field ident");
520 quote!(#ident: Default::default(),)
521 });
522
523 let active_save_update_branch = if !primary_keys.is_empty() {
524 quote!(return Self { #(#active_destructure,)* }.update(ex).await;)
525 } else {
526 quote!(
527 return Err(::dbkit::Error::Decode(
528 "update requires primary key".to_string(),
529 ));
530 )
531 };
532
533 let active_save_fn = quote!(
534 pub async fn save(
535 self,
536 ex: &mut (impl ::dbkit::Executor + Send),
537 ) -> Result<#struct_ident, ::dbkit::Error> {
538 let Self { #(#active_destructure,)* } = self;
539 let mut any_loaded = false;
540 let mut any_changed = false;
541 #(#active_save_flag_checks)*
542
543 if any_loaded {
544 if any_changed {
545 #active_save_update_branch
546 }
547 let model = #struct_ident {
548 #(#active_save_model_fields)*
549 #(#active_save_relation_defaults)*
550 };
551 return Ok(model);
552 }
553
554 Self { #(#active_destructure,)* }.insert(ex).await
555 }
556 );
557
558 let model_delete_impl = if !primary_keys.is_empty() {
559 let pk_filters = primary_keys.iter().map(|(ident, _)| {
560 quote!(delete = delete.filter(Self::#ident.eq(#ident));)
561 });
562 quote!(
563 impl #impl_generics ::dbkit::ModelDelete for #model_ident #struct_type_args {
564 fn delete<'e, E>(self, ex: &'e mut E) -> ::dbkit::executor::BoxFuture<'e, Result<u64, ::dbkit::Error>>
565 where
566 E: ::dbkit::Executor + Send + 'e,
567 {
568 let Self { #(#pk_idents,)* .. } = self;
569 let mut delete = ::dbkit::Delete::new(Self::TABLE);
570 #(#pk_filters)*
571 ::dbkit::DeleteExt::execute(delete, ex)
572 }
573 }
574 )
575 } else {
576 quote!()
577 };
578
579 let into_active_fn = quote!(
580 pub fn into_active(self) -> #active_ident {
581 let Self { #(#active_destructure,)* .. } = self;
582 #active_ident {
583 #(#active_from_model,)*
584 }
585 }
586 );
587
588 let primary_key_const = if primary_keys.len() == 1 {
589 let (ident, ty) = primary_keys
590 .first()
591 .expect("primary key length checked");
592 let name = ident.to_string();
593 Some(quote!(pub const PRIMARY_KEY: ::dbkit::Column<#struct_ident, #ty> = ::dbkit::Column::new(Self::TABLE, #name);))
594 } else {
595 None
596 };
597
598 let by_id_fn = if primary_keys.len() == 1 {
599 let (ident, ty) = primary_keys
600 .first()
601 .expect("primary key length checked");
602 Some(quote!(
603 pub fn by_id(id: #ty) -> ::dbkit::Select<#struct_ident> {
604 Self::query().filter(Self::#ident.eq(id)).limit(1)
605 }
606 ))
607 } else {
608 None
609 };
610
611 let any_state_ident = format_ident!("{}AnyState", struct_ident);
612
613 let relation_state_modules = relation_fields.iter().map(|rel| {
614 let state_mod = &rel.state_mod_ident;
615 let (sealed_impl, state_impl) = match rel.kind {
616 RelationKind::HasMany | RelationKind::ManyToMany => (
617 quote!(impl<T> Sealed for Vec<T> {}),
618 quote!(impl<T> State for Vec<T> {}),
619 ),
620 RelationKind::BelongsTo => (
621 quote!(impl<T> Sealed for Option<T> {}),
622 quote!(impl<T> State for Option<T> {}),
623 ),
624 };
625 quote!(
626 pub mod #state_mod {
627 mod sealed {
628 pub trait Sealed {}
629 impl Sealed for ::dbkit::NotLoaded {}
630 #sealed_impl
631 }
632 pub trait State: sealed::Sealed {}
633 impl State for ::dbkit::NotLoaded {}
634 #state_impl
635 }
636 )
637 });
638
639 let relation_methods = relation_fields.iter().map(|rel| {
640 let field_ident = rel.field.ident.as_ref().expect("field ident");
641 let method_ident = format_ident!("{}_loaded", field_ident);
642 let item_ident = format_ident!("{}Item", to_camel_case(&field_ident.to_string()));
643 let loaded_type: Type = match rel.kind {
644 RelationKind::HasMany | RelationKind::ManyToMany => syn::parse_quote!(Vec<#item_ident>),
645 RelationKind::BelongsTo => syn::parse_quote!(Option<#item_ident>),
646 };
647
648 let mut other_params = Vec::new();
649 let mut type_params = Vec::new();
650 for other in &relation_fields {
651 if other.field.ident == rel.field.ident {
652 type_params.push(quote!(#loaded_type));
653 } else {
654 let ident = &other.param_ident;
655 let state_mod = &other.state_mod_ident;
656 other_params.push(quote!(#ident: #state_mod::State));
657 type_params.push(quote!(#ident));
658 }
659 }
660
661 let mut impl_params = Vec::new();
662 impl_params.push(quote!(#item_ident));
663 impl_params.extend(other_params);
664
665 let impl_generics = if impl_params.is_empty() {
666 quote!()
667 } else {
668 quote!(<#(#impl_params),*>)
669 };
670 let type_args = if type_params.is_empty() {
671 quote!()
672 } else {
673 quote!(<#(#type_params),*>)
674 };
675
676 let (return_ty, body) = match rel.kind {
677 RelationKind::HasMany | RelationKind::ManyToMany => {
678 (quote!(&[#item_ident]), quote!(&self.#field_ident))
679 }
680 RelationKind::BelongsTo => {
681 (quote!(Option<&#item_ident>), quote!(self.#field_ident.as_ref()))
682 }
683 };
684
685 quote!(
686 impl #impl_generics #model_ident #type_args {
687 pub fn #method_ident(&self) -> #return_ty {
688 #body
689 }
690 }
691 )
692 });
693
694 let model_value_arms = output_fields
695 .iter()
696 .filter(|field| !is_relation_field(field, &relation_fields))
697 .map(|field| {
698 let ident = field.ident.as_ref().expect("field ident");
699 let name = ident.to_string();
700 quote!(#name => Some(self.#ident.clone().into()),)
701 });
702
703 let model_value_impl = quote!(
704 impl #impl_generics ::dbkit::ModelValue for #model_ident #struct_type_args {
705 fn column_value(&self, column: ::dbkit::ColumnRef) -> Option<::dbkit::Value> {
706 if column.table.name != Self::TABLE.name {
707 return None;
708 }
709 match column.name {
710 #(#model_value_arms)*
711 _ => None,
712 }
713 }
714 }
715 );
716
717 let from_row_generics = relation_fields.iter().map(|rel| {
718 let ident = &rel.param_ident;
719 let state_mod = &rel.state_mod_ident;
720 quote!(#ident: #state_mod::State + Default)
721 });
722
723 let from_row_impl_generics = if relation_fields.is_empty() {
724 quote!(<'r>)
725 } else {
726 quote!(<'r, #(#from_row_generics),*>)
727 };
728
729 let from_row_fields = output_fields.iter().map(|field| {
730 let ident = field.ident.as_ref().expect("field ident");
731 if is_relation_field(field, &relation_fields) {
732 quote!(#ident: Default::default())
733 } else {
734 let name = ident.to_string();
735 quote!(#ident: ::dbkit::sqlx::Row::try_get(row, #name)?)
736 }
737 });
738
739 let from_row_impl = quote!(
740 impl #from_row_impl_generics ::dbkit::sqlx::FromRow<'r, ::dbkit::sqlx::postgres::PgRow>
741 for #model_ident #struct_type_args
742 {
743 fn from_row(row: &'r ::dbkit::sqlx::postgres::PgRow) -> Result<Self, ::dbkit::sqlx::Error> {
744 Ok(Self {
745 #(#from_row_fields,)*
746 })
747 }
748 }
749 );
750
751 let joined_from_row_fields = output_fields.iter().map(|field| {
752 let ident = field.ident.as_ref().expect("field ident");
753 if is_relation_field(field, &relation_fields) {
754 quote!(#ident: Default::default())
755 } else {
756 let name = ident.to_string();
757 quote!(
758 #ident: {
759 let column = format!("{}{}", prefix, #name);
760 ::dbkit::sqlx::Row::try_get(row, column.as_str())?
761 }
762 )
763 }
764 });
765
766 let joined_pk_checks = if primary_keys.is_empty() {
767 if let Some(first_field) = scalar_fields.first() {
768 let name = first_field.ident.to_string();
769 let ty = option_inner_type(&first_field.ty).unwrap_or_else(|| first_field.ty.clone());
770 quote!(
771 let value: Option<#ty> = {
772 let column = format!("{}{}", prefix, #name);
773 ::dbkit::sqlx::Row::try_get(row, column.as_str())?
774 };
775 Ok(value.is_some())
776 )
777 } else {
778 quote!(Ok(false))
779 }
780 } else {
781 let checks = primary_keys.iter().map(|(ident, ty)| {
782 let name = ident.to_string();
783 let ty = option_inner_type(ty).unwrap_or_else(|| ty.clone());
784 quote!(
785 let value: Option<#ty> = {
786 let column = format!("{}{}", prefix, #name);
787 ::dbkit::sqlx::Row::try_get(row, column.as_str())?
788 };
789 if value.is_some() {
790 return Ok(true);
791 }
792 )
793 });
794 quote!(
795 #(#checks)*
796 Ok(false)
797 )
798 };
799
800 let joined_model_impl = quote!(
801 impl #from_row_impl_generics ::dbkit::JoinedModel for #model_ident #struct_type_args {
802 fn joined_columns() -> &'static [::dbkit::ColumnRef] {
803 Self::COLUMNS
804 }
805
806 fn joined_primary_keys() -> &'static [::dbkit::ColumnRef] {
807 Self::PRIMARY_KEYS
808 }
809
810 fn joined_from_row_prefixed(
811 row: &::dbkit::sqlx::postgres::PgRow,
812 prefix: &str,
813 ) -> Result<Self, ::dbkit::sqlx::Error> {
814 Ok(Self {
815 #(#joined_from_row_fields,)*
816 })
817 }
818
819 fn joined_row_has_pk(
820 row: &::dbkit::sqlx::postgres::PgRow,
821 prefix: &str,
822 ) -> Result<bool, ::dbkit::sqlx::Error> {
823 #joined_pk_checks
824 }
825 }
826 );
827
828 let set_relation_impls = relation_fields.iter().map(|rel| {
829 let field_ident = rel.field.ident.as_ref().expect("field ident");
830 let child_type = &rel.child_type;
831 let item_ident = format_ident!("{}Item", to_camel_case(&field_ident.to_string()));
832 let (value_ty, rel_ty) = match rel.kind {
833 RelationKind::HasMany => (
834 quote!(Vec<#item_ident>),
835 quote!(::dbkit::rel::HasMany<#struct_ident, #child_type>),
836 ),
837 RelationKind::ManyToMany => {
838 let through = rel
839 .many_to_many_through
840 .as_ref()
841 .expect("many-to-many through");
842 (
843 quote!(Vec<#item_ident>),
844 quote!(::dbkit::rel::ManyToMany<#struct_ident, #child_type, #through>),
845 )
846 }
847 RelationKind::BelongsTo => (
848 quote!(Option<#item_ident>),
849 quote!(::dbkit::rel::BelongsTo<#struct_ident, #child_type>),
850 ),
851 };
852
853 let mut other_params = Vec::new();
854 let mut type_params = Vec::new();
855 for other in &relation_fields {
856 if other.field.ident == rel.field.ident {
857 type_params.push(value_ty.clone());
858 } else {
859 let ident = &other.param_ident;
860 let state_mod = &other.state_mod_ident;
861 other_params.push(quote!(#ident: #state_mod::State));
862 type_params.push(quote!(#ident));
863 }
864 }
865
866 let mut impl_params = Vec::new();
867 impl_params.push(quote!(#item_ident));
868 impl_params.extend(other_params);
869
870 let impl_generics = if impl_params.is_empty() {
871 quote!()
872 } else {
873 quote!(<#(#impl_params),*>)
874 };
875 let type_args = if type_params.is_empty() {
876 quote!()
877 } else {
878 quote!(<#(#type_params),*>)
879 };
880
881 quote!(
882 impl #impl_generics ::dbkit::SetRelation<#rel_ty, #value_ty> for #model_ident #type_args {
883 fn set_relation(&mut self, _rel: #rel_ty, value: #value_ty) -> Result<(), ::dbkit::Error> {
884 self.#field_ident = value;
885 Ok(())
886 }
887 }
888 )
889 });
890
891 let get_relation_impls = relation_fields.iter().map(|rel| {
892 let field_ident = rel.field.ident.as_ref().expect("field ident");
893 let child_type = &rel.child_type;
894 let item_ident = format_ident!("{}Item", to_camel_case(&field_ident.to_string()));
895 let (value_ty, rel_ty) = match rel.kind {
896 RelationKind::HasMany => (
897 quote!(Vec<#item_ident>),
898 quote!(::dbkit::rel::HasMany<#struct_ident, #child_type>),
899 ),
900 RelationKind::ManyToMany => {
901 let through = rel
902 .many_to_many_through
903 .as_ref()
904 .expect("many-to-many through");
905 (
906 quote!(Vec<#item_ident>),
907 quote!(::dbkit::rel::ManyToMany<#struct_ident, #child_type, #through>),
908 )
909 }
910 RelationKind::BelongsTo => (
911 quote!(Option<#item_ident>),
912 quote!(::dbkit::rel::BelongsTo<#struct_ident, #child_type>),
913 ),
914 };
915
916 let mut other_params = Vec::new();
917 let mut type_params = Vec::new();
918 for other in &relation_fields {
919 if other.field.ident == rel.field.ident {
920 type_params.push(value_ty.clone());
921 } else {
922 let ident = &other.param_ident;
923 let state_mod = &other.state_mod_ident;
924 other_params.push(quote!(#ident: #state_mod::State));
925 type_params.push(quote!(#ident));
926 }
927 }
928
929 let mut impl_params = Vec::new();
930 impl_params.push(quote!(#item_ident));
931 impl_params.extend(other_params);
932
933 let impl_generics = if impl_params.is_empty() {
934 quote!()
935 } else {
936 quote!(<#(#impl_params),*>)
937 };
938 let type_args = if type_params.is_empty() {
939 quote!()
940 } else {
941 quote!(<#(#type_params),*>)
942 };
943
944 quote!(
945 impl #impl_generics ::dbkit::GetRelation<#rel_ty, #value_ty> for #model_ident #type_args {
946 fn get_relation(&self, _rel: #rel_ty) -> Option<&#value_ty> {
947 Some(&self.#field_ident)
948 }
949
950 fn get_relation_mut(&mut self, _rel: #rel_ty) -> Option<&mut #value_ty> {
951 Some(&mut self.#field_ident)
952 }
953 }
954 )
955 });
956
957 let load_method = quote!(
958 pub async fn load<Rel>(
959 self,
960 rel: Rel,
961 ex: &mut (impl ::dbkit::Executor + Send),
962 ) -> Result<<Self as ::dbkit::LoadRelation<Rel>>::Out, ::dbkit::Error>
963 where
964 Self: ::dbkit::LoadRelation<Rel>,
965 {
966 ::dbkit::LoadRelation::load_relation(self, rel, ex).await
967 }
968 );
969
970 let load_relation_impls = relation_fields.iter().map(|rel| {
971 let field_ident = rel.field.ident.as_ref().expect("field ident");
972 let child_type = &rel.child_type;
973 let rel_type = match rel.kind {
974 RelationKind::HasMany => quote!(::dbkit::rel::HasMany<#struct_ident, #child_type>),
975 RelationKind::BelongsTo => quote!(::dbkit::rel::BelongsTo<#struct_ident, #child_type>),
976 RelationKind::ManyToMany => {
977 let through = rel
978 .many_to_many_through
979 .as_ref()
980 .expect("many-to-many through");
981 quote!(::dbkit::rel::ManyToMany<#struct_ident, #child_type, #through>)
982 }
983 };
984 let loaded_type = match rel.kind {
985 RelationKind::HasMany | RelationKind::ManyToMany => quote!(Vec<#child_type>),
986 RelationKind::BelongsTo => quote!(Option<#child_type>),
987 };
988 let loader_fn = match rel.kind {
989 RelationKind::HasMany => quote!(::dbkit::runtime::load_selectin_has_many),
990 RelationKind::ManyToMany => quote!(::dbkit::runtime::load_selectin_many_to_many),
991 RelationKind::BelongsTo => quote!(::dbkit::runtime::load_selectin_belongs_to),
992 };
993
994 let mut other_params = Vec::new();
995 let mut type_params = Vec::new();
996 let mut out_params = Vec::new();
997 for other in &relation_fields {
998 if other.field.ident == rel.field.ident {
999 type_params.push(quote!(::dbkit::NotLoaded));
1000 out_params.push(loaded_type.clone());
1001 } else {
1002 let ident = &other.param_ident;
1003 let state_mod = &other.state_mod_ident;
1004 other_params.push(quote!(#ident: #state_mod::State + Send + 'static));
1005 type_params.push(quote!(#ident));
1006 out_params.push(quote!(#ident));
1007 }
1008 }
1009
1010 let impl_generics = if other_params.is_empty() {
1011 quote!()
1012 } else {
1013 quote!(<#(#other_params),*>)
1014 };
1015 let type_args = if type_params.is_empty() {
1016 quote!()
1017 } else {
1018 quote!(<#(#type_params),*>)
1019 };
1020 let out_type = if out_params.is_empty() {
1021 quote!(#model_ident)
1022 } else {
1023 quote!(#model_ident<#(#out_params),*>)
1024 };
1025 let out_construct = if out_params.is_empty() {
1026 quote!(#model_ident)
1027 } else {
1028 quote!(#model_ident::<#(#out_params),*>)
1029 };
1030
1031 let destructure_fields = output_fields.iter().map(|field| {
1032 let ident = field.ident.as_ref().expect("field ident");
1033 if ident == field_ident {
1034 quote!(#ident: _)
1035 } else {
1036 quote!(#ident)
1037 }
1038 });
1039
1040 let build_fields = output_fields.iter().map(|field| {
1041 let ident = field.ident.as_ref().expect("field ident");
1042 if ident == field_ident {
1043 quote!(#ident: Default::default())
1044 } else {
1045 quote!(#ident)
1046 }
1047 });
1048
1049 quote!(
1050 impl #impl_generics ::dbkit::LoadRelation<#rel_type> for #model_ident #type_args {
1051 type Out = #out_type;
1052
1053 fn load_relation<'e, E>(
1054 self,
1055 rel: #rel_type,
1056 ex: &'e mut E,
1057 ) -> ::dbkit::executor::BoxFuture<'e, Result<Self::Out, ::dbkit::Error>>
1058 where
1059 E: ::dbkit::Executor + Send + 'e,
1060 {
1061 Box::pin(async move {
1062 let Self { #(#destructure_fields,)* } = self;
1063 let mut out = #out_construct {
1064 #(#build_fields,)*
1065 };
1066 let mut rows = vec![out];
1067 #loader_fn(ex, &mut rows, rel, &::dbkit::load::NoLoad).await?;
1068 Ok(rows.pop().expect("loaded row"))
1069 })
1070 }
1071 }
1072 )
1073 });
1074
1075 let relation_consts = relation_fields.iter().filter_map(|rel| {
1076 let field_ident = rel.field.ident.as_ref().expect("field ident");
1077 let child_type = &rel.child_type;
1078 match rel.kind {
1079 RelationKind::HasMany => Some(quote!(
1080 pub const #field_ident: ::dbkit::rel::HasMany<#struct_ident, #child_type> =
1081 ::dbkit::rel::HasMany::new(
1082 <#child_type as ::dbkit::rel::BelongsToSpec<#struct_ident>>::PARENT_TABLE,
1083 <#child_type as ::dbkit::rel::BelongsToSpec<#struct_ident>>::CHILD_TABLE,
1084 <#child_type as ::dbkit::rel::BelongsToSpec<#struct_ident>>::PARENT_KEY,
1085 <#child_type as ::dbkit::rel::BelongsToSpec<#struct_ident>>::CHILD_KEY,
1086 );
1087 )),
1088 RelationKind::BelongsTo => {
1089 let key = rel.belongs_to_key.as_ref().expect("belongs_to key");
1090 let references = rel.belongs_to_ref.as_ref().expect("belongs_to references");
1091 Some(quote!(
1092 pub const #field_ident: ::dbkit::rel::BelongsTo<#struct_ident, #child_type> =
1093 ::dbkit::rel::BelongsTo::new(
1094 Self::TABLE,
1095 #child_type::TABLE,
1096 Self::#key.as_ref(),
1097 #child_type::#references.as_ref(),
1098 );
1099 ))
1100 }
1101 RelationKind::ManyToMany => {
1102 let through = rel
1103 .many_to_many_through
1104 .as_ref()
1105 .expect("many-to-many through");
1106 let left_key = rel
1107 .many_to_many_left_key
1108 .as_ref()
1109 .expect("many-to-many left_key");
1110 let right_key = rel
1111 .many_to_many_right_key
1112 .as_ref()
1113 .expect("many-to-many right_key");
1114 let parent_pk = primary_keys
1115 .first()
1116 .map(|(ident, _)| ident)
1117 .expect("many-to-many parent pk");
1118 Some(quote!(
1119 pub const #field_ident: ::dbkit::rel::ManyToMany<#struct_ident, #child_type, #through> =
1120 ::dbkit::rel::ManyToMany::new(
1121 Self::TABLE,
1122 #child_type::TABLE,
1123 #through::TABLE,
1124 Self::#parent_pk.as_ref(),
1125 #child_type::PRIMARY_KEY.as_ref(),
1126 #through::#left_key.as_ref(),
1127 #through::#right_key.as_ref(),
1128 );
1129 ))
1130 }
1131 }
1132 });
1133
1134 let belongs_to_specs = relation_fields.iter().filter_map(|rel| {
1135 if rel.kind != RelationKind::BelongsTo {
1136 return None;
1137 }
1138 let parent_type = &rel.child_type;
1139 let key = rel.belongs_to_key.as_ref().expect("belongs_to key");
1140 let references = rel.belongs_to_ref.as_ref().expect("belongs_to references");
1141 Some(quote!(
1142 impl #impl_generics ::dbkit::rel::BelongsToSpec<#parent_type> for #model_ident #struct_type_args {
1143 const CHILD_TABLE: ::dbkit::Table = Self::TABLE;
1144 const PARENT_TABLE: ::dbkit::Table = #parent_type::TABLE;
1145 const CHILD_KEY: ::dbkit::ColumnRef = Self::#key.as_ref();
1146 const PARENT_KEY: ::dbkit::ColumnRef = #parent_type::#references.as_ref();
1147 }
1148 ))
1149 });
1150
1151 let apply_load_impls = relation_fields.iter().flat_map(|rel| {
1152 let child_type = &rel.child_type;
1153 let rel_type = match rel.kind {
1154 RelationKind::HasMany => quote!(::dbkit::rel::HasMany<#struct_ident, #child_type>),
1155 RelationKind::BelongsTo => quote!(::dbkit::rel::BelongsTo<#struct_ident, #child_type>),
1156 RelationKind::ManyToMany => {
1157 let through = rel
1158 .many_to_many_through
1159 .as_ref()
1160 .expect("many-to-many through");
1161 quote!(::dbkit::rel::ManyToMany<#struct_ident, #child_type, #through>)
1162 }
1163 };
1164
1165 let loaded_child = quote!(<Nested as ::dbkit::load::ApplyLoad<#child_type>>::Out2);
1166 let loaded_param = match rel.kind {
1167 RelationKind::HasMany | RelationKind::ManyToMany => quote!(Vec<#loaded_child>),
1168 RelationKind::BelongsTo => quote!(Option<#loaded_child>),
1169 };
1170
1171 let mut out_params = Vec::new();
1172 for other in &relation_fields {
1173 if other.field.ident == rel.field.ident {
1174 out_params.push(loaded_param.clone());
1175 } else {
1176 let ident = &other.param_ident;
1177 out_params.push(quote!(#ident));
1178 }
1179 }
1180
1181 let model_type = if generic_idents.is_empty() {
1182 quote!(#model_ident)
1183 } else {
1184 quote!(#model_ident<#(#generic_idents),*>)
1185 };
1186 let out_type = if out_params.is_empty() {
1187 quote!(#model_ident)
1188 } else {
1189 quote!(#model_ident<#(#out_params),*>)
1190 };
1191
1192 let mut apply_generics = Vec::new();
1193 apply_generics.push(quote!(Nested));
1194 apply_generics.extend(impl_generics_params.iter().cloned());
1195 let apply_generics = if apply_generics.is_empty() {
1196 quote!()
1197 } else {
1198 quote!(<#(#apply_generics),*>)
1199 };
1200
1201 let mut items = Vec::new();
1202 for strategy in ["SelectIn", "Joined"] {
1203 let load_ty = if strategy == "SelectIn" {
1204 quote!(::dbkit::load::SelectIn<#rel_type, Nested>)
1205 } else {
1206 quote!(::dbkit::load::Joined<#rel_type, Nested>)
1207 };
1208 items.push(quote!(
1209 impl #apply_generics ::dbkit::load::ApplyLoad<#model_type> for #load_ty
1210 where
1211 Nested: ::dbkit::load::ApplyLoad<#child_type>,
1212 {
1213 type Out2 = #out_type;
1214 }
1215 ));
1216 }
1217 items.into_iter()
1218 });
1219
1220 let run_load_impls = relation_fields.iter().flat_map(|rel| {
1221 let child_type = &rel.child_type;
1222 let through = rel.many_to_many_through.as_ref();
1223 let rel_type = match rel.kind {
1224 RelationKind::HasMany => quote!(::dbkit::rel::HasMany<#struct_ident, #child_type>),
1225 RelationKind::BelongsTo => quote!(::dbkit::rel::BelongsTo<#struct_ident, #child_type>),
1226 RelationKind::ManyToMany => {
1227 let through = through.expect("many-to-many through");
1228 quote!(::dbkit::rel::ManyToMany<#struct_ident, #child_type, #through>)
1229 }
1230 };
1231
1232 let loaded_child = quote!(<Nested as ::dbkit::load::ApplyLoad<#child_type>>::Out2);
1233 let loaded_param = match rel.kind {
1234 RelationKind::HasMany | RelationKind::ManyToMany => quote!(Vec<#loaded_child>),
1235 RelationKind::BelongsTo => quote!(Option<#loaded_child>),
1236 };
1237
1238 let mut out_params = Vec::new();
1239 for other in &relation_fields {
1240 if other.field.ident == rel.field.ident {
1241 out_params.push(loaded_param.clone());
1242 } else {
1243 let ident = &other.param_ident;
1244 out_params.push(quote!(#ident));
1245 }
1246 }
1247
1248 let out_type = if out_params.is_empty() {
1249 quote!(#model_ident)
1250 } else {
1251 quote!(#model_ident<#(#out_params),*>)
1252 };
1253
1254 let mut apply_generics = Vec::new();
1255 apply_generics.push(quote!(Nested));
1256 for other in &relation_fields {
1257 if other.field.ident == rel.field.ident {
1258 continue;
1259 }
1260 let ident = &other.param_ident;
1261 let state_mod = &other.state_mod_ident;
1262 apply_generics.push(quote!(#ident: #state_mod::State + Send + 'static));
1263 }
1264 let apply_generics = if apply_generics.is_empty() {
1265 quote!()
1266 } else {
1267 quote!(<#(#apply_generics),*>)
1268 };
1269
1270 let (child_bounds, loader_fn) = match rel.kind {
1271 RelationKind::HasMany => (
1272 quote!(#loaded_child: ::dbkit::ModelValue + for<'r> ::dbkit::sqlx::FromRow<'r, ::dbkit::sqlx::postgres::PgRow> + Send + Unpin,),
1273 quote!(::dbkit::runtime::load_selectin_has_many),
1274 ),
1275 RelationKind::ManyToMany => {
1276 let through = through.expect("many-to-many through");
1277 (
1278 quote!(
1279 #loaded_child: ::dbkit::ModelValue + Clone + for<'r> ::dbkit::sqlx::FromRow<'r, ::dbkit::sqlx::postgres::PgRow> + Send + Unpin,
1280 #through: ::dbkit::ModelValue + for<'r> ::dbkit::sqlx::FromRow<'r, ::dbkit::sqlx::postgres::PgRow> + Send + Unpin,
1281 ),
1282 quote!(::dbkit::runtime::load_selectin_many_to_many),
1283 )
1284 }
1285 RelationKind::BelongsTo => (
1286 quote!(#loaded_child: ::dbkit::ModelValue + Clone + for<'r> ::dbkit::sqlx::FromRow<'r, ::dbkit::sqlx::postgres::PgRow> + Send + Unpin,),
1287 quote!(::dbkit::runtime::load_selectin_belongs_to),
1288 ),
1289 };
1290
1291 let joined_loader_fn = match rel.kind {
1292 RelationKind::HasMany => quote!(::dbkit::runtime::load_joined_has_many),
1293 RelationKind::ManyToMany => quote!(::dbkit::runtime::load_joined_many_to_many),
1294 RelationKind::BelongsTo => quote!(::dbkit::runtime::load_joined_belongs_to),
1295 };
1296
1297 let mut items = Vec::new();
1298 for (strategy, loader) in [
1299 ("SelectIn", loader_fn),
1300 ("Joined", joined_loader_fn),
1301 ] {
1302 let load_ty = if strategy == "SelectIn" {
1303 quote!(::dbkit::load::SelectIn<#rel_type, Nested>)
1304 } else {
1305 quote!(::dbkit::load::Joined<#rel_type, Nested>)
1306 };
1307 let out_bound = if strategy == "SelectIn" {
1308 quote!(::dbkit::ModelValue + ::dbkit::SetRelation<#rel_type, #loaded_param>)
1309 } else {
1310 quote!(::dbkit::GetRelation<#rel_type, #loaded_param>)
1311 };
1312
1313 items.push(quote!(
1314 impl #apply_generics ::dbkit::runtime::RunLoad<#out_type> for #load_ty
1315 where
1316 Nested: ::dbkit::load::ApplyLoad<#child_type> + ::dbkit::runtime::RunLoads<#loaded_child> + Sync,
1317 #out_type: #out_bound,
1318 #child_bounds
1319 {
1320 fn run<'e, E>(
1321 &'e self,
1322 ex: &'e mut E,
1323 rows: &'e mut [#out_type],
1324 ) -> ::dbkit::executor::BoxFuture<'e, Result<(), ::dbkit::Error>>
1325 where
1326 E: ::dbkit::Executor + Send + 'e,
1327 {
1328 #loader(ex, rows, self.rel.clone(), &self.nested)
1329 }
1330 }
1331 ));
1332 }
1333 items.into_iter()
1334 });
1335
1336 let output = quote! {
1337 #(#struct_attrs)*
1338 #[derive(Debug, Clone)]
1339 #vis struct #model_ident #struct_generics {
1340 #(#output_fields,)*
1341 }
1342
1343 #vis type #struct_ident = #model_ident;
1344
1345 #(#relation_state_modules)*
1346
1347 #vis trait #any_state_ident {}
1348 impl #impl_generics #any_state_ident for #model_ident #struct_type_args {}
1349
1350 impl #impl_generics #model_ident #struct_type_args {
1351 pub const TABLE: ::dbkit::Table = #table_expr;
1352 #(#columns)*
1353 #columns_const
1354 #primary_key_const
1355 #primary_keys_const
1356 #(#relation_consts)*
1357
1358 pub fn query() -> ::dbkit::Select<#struct_ident> {
1359 ::dbkit::Select::new(Self::TABLE)
1360 }
1361
1362 #by_id_fn
1363
1364 pub fn insert(values: #insert_ident) -> ::dbkit::Insert<#struct_ident> {
1365 let mut insert = ::dbkit::Insert::new(Self::TABLE);
1366 #(#insert_values)*
1367 insert
1368 }
1369
1370 pub fn insert_many(values: Vec<#insert_ident>) -> ::dbkit::Insert<#struct_ident> {
1371 let mut insert = ::dbkit::Insert::new(Self::TABLE);
1372 for value in values {
1373 insert = insert.row(|row| {
1374 let mut row = row;
1375 #(
1376 row = row.value(Self::#insert_field_idents, value.#insert_field_idents);
1377 )*
1378 row
1379 });
1380 }
1381 insert
1382 }
1383
1384 pub fn update() -> ::dbkit::Update<#struct_ident> {
1385 ::dbkit::Update::new(Self::TABLE)
1386 }
1387
1388 pub fn delete() -> ::dbkit::Delete {
1389 ::dbkit::Delete::new(Self::TABLE)
1390 }
1391
1392 pub fn new_active() -> #active_ident {
1393 #active_ident::new()
1394 }
1395
1396 #into_active_fn
1397 #load_method
1398 }
1399
1400 #[derive(Debug, Clone)]
1401 #vis struct #insert_ident {
1402 #(#insert_fields,)*
1403 }
1404
1405 #[derive(Debug, Clone, Default)]
1406 #vis struct #active_ident {
1407 #(#active_fields,)*
1408 }
1409
1410 impl #active_ident {
1411 pub fn new() -> Self {
1412 Self::default()
1413 }
1414
1415 #active_insert_fn
1416 #active_update_fn
1417 #active_delete_fn
1418 #active_save_fn
1419 }
1420
1421 #(#relation_methods)*
1422 #model_value_impl
1423 #from_row_impl
1424 #joined_model_impl
1425 #(#set_relation_impls)*
1426 #(#get_relation_impls)*
1427 #(#load_relation_impls)*
1428 #(#belongs_to_specs)*
1429 #(#apply_load_impls)*
1430 #(#run_load_impls)*
1431 #model_delete_impl
1432 };
1433
1434 Ok(output.into())
1435}
1436
1437fn parse_model_args(args: syn::punctuated::Punctuated<Meta, syn::Token![,]>) -> ModelArgs {
1438 let mut out = ModelArgs::default();
1439 for meta in args {
1440 if let Meta::NameValue(nv) = meta {
1441 if nv.path.is_ident("table") {
1442 if let Some(value) = extract_lit_str(&nv.value) {
1443 out.table = Some(value);
1444 }
1445 } else if nv.path.is_ident("schema") {
1446 if let Some(value) = extract_lit_str(&nv.value) {
1447 out.schema = Some(value);
1448 }
1449 }
1450 }
1451 }
1452 out
1453}
1454
1455fn parse_belongs_to_args(attrs: &[Attribute]) -> syn::Result<(Ident, Ident)> {
1456 for attr in attrs {
1457 if !attr.path().is_ident("belongs_to") {
1458 continue;
1459 }
1460 let args = attr.parse_args_with(
1461 syn::punctuated::Punctuated::<Meta, syn::Token![,]>::parse_terminated,
1462 )?;
1463 let mut key = None;
1464 let mut references = None;
1465 for meta in args {
1466 if let Meta::NameValue(nv) = meta {
1467 if nv.path.is_ident("key") {
1468 key = extract_ident(&nv.value);
1469 } else if nv.path.is_ident("references") {
1470 references = extract_ident(&nv.value);
1471 }
1472 }
1473 }
1474 if let (Some(key), Some(references)) = (key, references) {
1475 return Ok((key, references));
1476 }
1477 }
1478 Err(syn::Error::new(
1479 proc_macro2::Span::call_site(),
1480 "dbkit: #[belongs_to] requires key = <field> and references = <field>",
1481 ))
1482}
1483
1484fn parse_many_to_many_args(attrs: &[Attribute]) -> syn::Result<(Ident, Ident, Ident)> {
1485 for attr in attrs {
1486 if !attr.path().is_ident("many_to_many") {
1487 continue;
1488 }
1489 let args = attr.parse_args_with(
1490 syn::punctuated::Punctuated::<Meta, syn::Token![,]>::parse_terminated,
1491 )?;
1492 let mut through = None;
1493 let mut left_key = None;
1494 let mut right_key = None;
1495 for meta in args {
1496 if let Meta::NameValue(nv) = meta {
1497 if nv.path.is_ident("through") {
1498 through = extract_ident(&nv.value);
1499 } else if nv.path.is_ident("left_key") {
1500 left_key = extract_ident(&nv.value);
1501 } else if nv.path.is_ident("right_key") {
1502 right_key = extract_ident(&nv.value);
1503 }
1504 }
1505 }
1506 if let (Some(through), Some(left_key), Some(right_key)) = (through, left_key, right_key) {
1507 return Ok((through, left_key, right_key));
1508 }
1509 }
1510 Err(syn::Error::new(
1511 proc_macro2::Span::call_site(),
1512 "dbkit: #[many_to_many] requires through = <Model>, left_key = <field>, right_key = <field>",
1513 ))
1514}
1515
1516fn extract_lit_str(expr: &syn::Expr) -> Option<String> {
1517 if let syn::Expr::Lit(syn::ExprLit {
1518 lit: syn::Lit::Str(lit),
1519 ..
1520 }) = expr
1521 {
1522 Some(lit.value())
1523 } else {
1524 None
1525 }
1526}
1527
1528fn extract_ident(expr: &syn::Expr) -> Option<Ident> {
1529 if let syn::Expr::Path(path) = expr {
1530 path.path.get_ident().cloned()
1531 } else {
1532 None
1533 }
1534}
1535
1536fn option_inner_type(ty: &Type) -> Option<Type> {
1537 let path = match ty {
1538 Type::Path(path) => path,
1539 _ => return None,
1540 };
1541 let segment = path.path.segments.last()?;
1542 if segment.ident != "Option" {
1543 return None;
1544 }
1545 let args = match &segment.arguments {
1546 syn::PathArguments::AngleBracketed(args) => args,
1547 _ => return None,
1548 };
1549 let inner = args.args.first()?;
1550 match inner {
1551 syn::GenericArgument::Type(inner_ty) => Some(inner_ty.clone()),
1552 _ => None,
1553 }
1554}
1555
1556fn has_attr(attrs: &[Attribute], name: &str) -> bool {
1557 attrs.iter().any(|attr| attr.path().is_ident(name))
1558}
1559
1560fn filter_struct_attrs(attrs: &[Attribute]) -> Vec<Attribute> {
1561 let mut kept = Vec::new();
1562 for attr in attrs {
1563 if is_model_attr(attr) {
1564 continue;
1565 }
1566 if attr.path().is_ident("derive") {
1567 if let Ok(mut paths) = attr.parse_args_with(
1568 syn::punctuated::Punctuated::<syn::Path, syn::Token![,]>::parse_terminated,
1569 ) {
1570 paths = paths
1571 .into_iter()
1572 .filter(|path| {
1573 !path
1574 .segments
1575 .last()
1576 .map(|seg| seg.ident == "Model")
1577 .unwrap_or(false)
1578 })
1579 .collect();
1580 if paths.is_empty() {
1581 continue;
1582 }
1583 let new_attr = quote!(#[derive(#paths)]);
1584 let parsed = syn::Attribute::parse_outer
1585 .parse2(new_attr)
1586 .expect("derive attr");
1587 kept.extend(parsed);
1588 continue;
1589 }
1590 }
1591 kept.push(attr.clone());
1592 }
1593 kept
1594}
1595
1596fn filter_field_attrs(attrs: &[Attribute]) -> Vec<Attribute> {
1597 attrs
1598 .iter()
1599 .filter(|attr| !is_field_orm_attr(attr))
1600 .cloned()
1601 .collect()
1602}
1603
1604fn is_field_orm_attr(attr: &Attribute) -> bool {
1605 let name = attr.path().get_ident().map(|ident| ident.to_string());
1606 matches!(
1607 name.as_deref(),
1608 Some("key")
1609 | Some("autoincrement")
1610 | Some("unique")
1611 | Some("index")
1612 | Some("has_many")
1613 | Some("belongs_to")
1614 | Some("many_to_many")
1615 )
1616}
1617
1618fn is_model_attr(attr: &Attribute) -> bool {
1619 attr.path().is_ident("model")
1620}
1621
1622fn relation_type(field: &Field) -> syn::Result<(RelationKind, Type)> {
1623 let kind = if has_attr(&field.attrs, "has_many") {
1624 RelationKind::HasMany
1625 } else if has_attr(&field.attrs, "belongs_to") {
1626 RelationKind::BelongsTo
1627 } else if has_attr(&field.attrs, "many_to_many") {
1628 RelationKind::ManyToMany
1629 } else {
1630 return Err(syn::Error::new_spanned(
1631 field,
1632 "dbkit: missing relation attribute",
1633 ));
1634 };
1635
1636 let child_type = match &field.ty {
1637 Type::Path(path) => {
1638 let segment = path
1639 .path
1640 .segments
1641 .last()
1642 .ok_or_else(|| syn::Error::new_spanned(&field.ty, "dbkit: invalid type"))?;
1643 let expected = match kind {
1644 RelationKind::HasMany => "HasMany",
1645 RelationKind::BelongsTo => "BelongsTo",
1646 RelationKind::ManyToMany => "ManyToMany",
1647 };
1648 if segment.ident != expected {
1649 return Err(syn::Error::new_spanned(
1650 &segment.ident,
1651 format!("dbkit: expected {} marker type", expected),
1652 ));
1653 }
1654 match &segment.arguments {
1655 syn::PathArguments::AngleBracketed(args) => {
1656 let ty = args.args.iter().find_map(|arg| match arg {
1657 syn::GenericArgument::Type(ty) => Some(ty.clone()),
1658 _ => None,
1659 });
1660 ty.ok_or_else(|| syn::Error::new_spanned(&segment, "dbkit: missing type"))?
1661 }
1662 _ => {
1663 return Err(syn::Error::new_spanned(
1664 &segment.arguments,
1665 "dbkit: expected generic argument",
1666 ))
1667 }
1668 }
1669 }
1670 _ => {
1671 return Err(syn::Error::new_spanned(
1672 &field.ty,
1673 "dbkit: relation marker must be a type path",
1674 ))
1675 }
1676 };
1677
1678 Ok((kind, child_type))
1679}
1680
1681fn is_relation_field(field: &Field, rels: &[RelationInfo]) -> bool {
1682 rels.iter()
1683 .any(|rel| rel.field.ident == field.ident)
1684}
1685
1686fn to_snake_case(name: &str) -> String {
1687 let mut out = String::new();
1688 for (idx, ch) in name.chars().enumerate() {
1689 if ch.is_uppercase() {
1690 if idx > 0 {
1691 out.push('_');
1692 }
1693 for lower in ch.to_lowercase() {
1694 out.push(lower);
1695 }
1696 } else {
1697 out.push(ch);
1698 }
1699 }
1700 out
1701}
1702
1703fn to_camel_case(name: &str) -> String {
1704 let mut out = String::new();
1705 let mut uppercase_next = true;
1706 for ch in name.chars() {
1707 if ch == '_' {
1708 uppercase_next = true;
1709 continue;
1710 }
1711 if uppercase_next {
1712 for up in ch.to_uppercase() {
1713 out.push(up);
1714 }
1715 uppercase_next = false;
1716 } else {
1717 out.push(ch);
1718 }
1719 }
1720 out
1721}
1722
1723