1use darling::{FromDeriveInput, FromField, ast::Data, util::Ignored};
4use proc_macro::TokenStream;
5use proc_macro_error2::abort;
6use syn::{DeriveInput, Ident, parse_macro_input};
7use thiserror::Error;
8
9mod delete;
10mod fetch;
11mod insert;
12mod stream;
13mod update;
14
15#[proc_macro_error2::proc_macro_error]
17#[proc_macro_derive(Entity, attributes(orm))]
18pub fn derive_response(input: TokenStream) -> TokenStream {
19 let args = parse_macro_input!(input as DeriveInput);
20
21 match generate(args) {
22 Ok(stream) => stream,
23 Err(err) => err.write_errors().into(),
24 }
25}
26
27fn generate(args: DeriveInput) -> Result<TokenStream, GeneratorError> {
28 let args: EntityArgs = EntityArgs::from_derive_input(&args)?;
29 let ident = args.ident.clone();
30
31 let args = if let Ok(v) = EntityCtx::try_from(args) {
32 v
33 } else {
34 abort!(
35 ident,
36 "The `Entity` macro can only be applied to a struct with named fields"
37 )
38 };
39
40 let insert_stream = insert::generate_insert(&args);
41 let update_stream = update::generate_update(&args);
42 let stream_stream = stream::generate_stream(&args);
43 let delete_stream = delete::generate_delete(&args);
44 let get_by_id_stream = fetch::generate_fetch(&args);
45
46 let stream = quote::quote! {
47 #insert_stream
48 #update_stream
49 #stream_stream
50 #delete_stream
51 #get_by_id_stream
52 };
53
54 Ok(stream.into())
55}
56
57#[derive(Debug, Clone)]
58struct EntityCtx {
59 ident: Ident,
60 vis: syn::Visibility,
61 data: Vec<EntityFieldCtx>,
62 table: String,
63}
64
65impl EntityCtx {
66 fn pks(&self) -> impl Iterator<Item = &EntityFieldCtx> {
67 self.data.iter().filter(|field| field.pk)
68 }
69}
70
71impl TryFrom<EntityArgs> for EntityCtx {
72 type Error = ();
73
74 fn try_from(value: EntityArgs) -> Result<Self, Self::Error> {
75 let mut data = vec![];
76
77 for row in value.data.take_struct().ok_or(())? {
78 data.push(row.try_into()?);
79 }
80
81 Ok(Self {
82 ident: value.ident,
83 vis: value.vis,
84 data,
85 table: value.table,
86 })
87 }
88}
89
90#[derive(Debug, Clone)]
91struct EntityFieldCtx {
92 ident: Ident,
93 vis: syn::Visibility,
94 ty: syn::Type,
95 pk: bool,
96 generated: bool,
97 deref: bool,
98 default: bool,
99}
100
101impl TryFrom<EntityField> for EntityFieldCtx {
102 type Error = ();
103
104 fn try_from(value: EntityField) -> Result<Self, Self::Error> {
105 Ok(Self {
106 ident: value.ident.ok_or(())?,
107 vis: value.vis,
108 ty: value.ty,
109 pk: value.pk,
110 generated: value.generated,
111 deref: value.deref,
112 default: value.default,
113 })
114 }
115}
116
117#[derive(Debug, FromDeriveInput)]
118#[darling(attributes(orm), forward_attrs(doc))]
119struct EntityArgs {
120 ident: Ident,
121 vis: syn::Visibility,
122 data: Data<Ignored, EntityField>,
123 table: String,
124}
125
126#[derive(Debug, Clone, FromField)]
127#[darling(attributes(orm), forward_attrs(doc))]
128struct EntityField {
129 ident: Option<Ident>,
130 vis: syn::Visibility,
131 ty: syn::Type,
132 #[darling(default)]
133 pk: bool,
134 #[darling(default)]
135 generated: bool,
136 #[darling(default)]
137 default: bool,
138 #[darling(default)]
139 deref: bool,
140}
141
142#[derive(Debug, Error)]
143pub(crate) enum GeneratorError {
144 #[error("{0}")]
145 Syn(
146 #[source]
147 #[from]
148 syn::Error,
149 ),
150 #[error("{0}")]
151 Darling(
152 #[source]
153 #[from]
154 darling::Error,
155 ),
156}
157
158impl GeneratorError {
159 pub(crate) fn write_errors(self) -> proc_macro2::TokenStream {
160 match self {
161 Self::Syn(err) => err.to_compile_error(),
162 Self::Darling(err) => err.write_errors(),
163 }
164 }
165}