dbkit_derive/
lib.rs

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// (unused helper removed)
1724
1725// (intentionally removed unused AnyState helpers)