actix_cloud_extra_macros/
lib.rs1#![cfg_attr(docsrs, feature(doc_cfg))]
2
3use proc_macro::TokenStream;
4use quote::quote;
5use syn::{Ident, ImplItem, ItemImpl, parse_macro_input, parse_quote};
6
7#[proc_macro_attribute]
22pub fn default_repo(attr: TokenStream, input: TokenStream) -> TokenStream {
23 let attr = parse_macro_input!(attr as Ident);
24 let mut input = parse_macro_input!(input as ItemImpl);
25 let func: Vec<String> = input
26 .items
27 .iter()
28 .map(|x| {
29 if let ImplItem::Fn(x) = x {
30 x.sig.ident.to_string()
31 } else {
32 String::new()
33 }
34 })
35 .collect();
36 let contains = |name: &str| func.iter().any(|x| x == name);
37 if !contains("find") {
38 input.items.push(parse_quote! {
39 pub async fn find<C>(
40 db: &C,
41 cond: actix_cloud_extra::api::Condition,
42 ) -> anyhow::Result<(Vec<#attr::Model>, u64)>
43 where
44 C: sea_orm::ConnectionTrait
45 {
46 cond.select_page(#attr::Entity::find(), db).await
47 }
48 });
49 }
50 if !contains("find_by_id") {
51 input.items.push(parse_quote! {
52 pub async fn find_by_id<C>(db: &C, id: &actix_cloud_extra::HyUuid) -> anyhow::Result<Option<#attr::Model>>
53 where
54 C: sea_orm::ConnectionTrait,
55 {
56 #attr::Entity::find_by_id(id.to_owned())
57 .one(db)
58 .await
59 .map_err(Into::into)
60 }
61 });
62 }
63 if !contains("delete_all") {
64 input.items.push(parse_quote! {
65 pub async fn delete_all<C>(db: &C) -> anyhow::Result<u64>
66 where
67 C: sea_orm::ConnectionTrait,
68 {
69 #attr::Entity::delete_many()
70 .exec(db)
71 .await
72 .map(|x| x.rows_affected)
73 .map_err(Into::into)
74 }
75 });
76 }
77 if !contains("delete") {
78 input.items.push(parse_quote! {
79 pub async fn delete<C>(db: &C, id: &actix_cloud_extra::HyUuid) -> anyhow::Result<u64>
80 where
81 C: sea_orm::ConnectionTrait,
82 {
83 #attr::Entity::delete_by_id(*id)
84 .exec(db)
85 .await
86 .map(|x| x.rows_affected)
87 .map_err(Into::into)
88 }
89 });
90 }
91 if !contains("count") {
92 input.items.push(parse_quote! {
93 pub async fn count<C>(
94 db: &C,
95 cond: actix_cloud_extra::api::Condition,
96 ) -> anyhow::Result<u64>
97 where
98 C: sea_orm::ConnectionTrait,
99 {
100 Ok(cond.build(#attr::Entity::find()).0.count(db).await?)
101 }
102 });
103 }
104
105 quote! {
106 #input
107 }
108 .into()
109}
110
111#[cfg(feature = "seaorm")]
112#[proc_macro_attribute]
131pub fn entity_timestamp(_: TokenStream, input: TokenStream) -> TokenStream {
132 let mut entity = syn::parse_macro_input!(input as syn::ItemImpl);
133 entity.items.push(syn::parse_quote!(
134 fn entity_timestamp(&self, e: &mut Self, insert: bool) {
135 let tm: sea_orm::ActiveValue<DateTime> =
136 sea_orm::ActiveValue::set(chrono::Utc::now().naive_utc());
137 if insert {
138 e.created_at = tm.clone();
139 e.updated_at = tm.clone();
140 } else {
141 e.updated_at = tm.clone();
142 }
143 }
144 ));
145 quote! {
146 #entity
147
148 impl actix_cloud_extra::entity::DefaultColumnTrait for Column {
149 fn get_created_at() -> impl sea_orm::ColumnTrait {
150 Self::CreatedAt
151 }
152
153 fn get_updated_at() -> impl sea_orm::ColumnTrait {
154 Self::UpdatedAt
155 }
156 }
157 }
158 .into()
159}
160
161#[cfg(feature = "seaorm")]
162#[proc_macro_attribute]
178pub fn entity_id(attr: TokenStream, input: TokenStream) -> TokenStream {
179 let attr = syn::parse_macro_input!(attr as syn::ExprCall);
180 let mut entity = syn::parse_macro_input!(input as syn::ItemImpl);
181 entity.items.push(syn::parse_quote!(
182 fn entity_id(&self, e: &mut Self, insert: bool) {
183 if insert && e.id.is_not_set() {
184 e.id = sea_orm::ActiveValue::set(#attr);
185 }
186 }
187 ));
188 quote! {
189 #entity
190 }
191 .into()
192}
193
194#[cfg(feature = "seaorm")]
195#[proc_macro_attribute]
213pub fn entity_behavior(_: TokenStream, input: TokenStream) -> TokenStream {
214 let mut entity = syn::parse_macro_input!(input as syn::ItemImpl);
215
216 entity.items.push(syn::parse_quote!(
217 async fn before_save<C>(self, _: &C, insert: bool) -> Result<Self, sea_orm::DbErr>
218 where
219 C: sea_orm::ConnectionTrait,
220 {
221 let mut new = self.clone();
222 self.entity_id(&mut new, insert);
223 self.entity_timestamp(&mut new, insert);
224 Ok(new)
225 }
226 ));
227 quote! {
228 #[async_trait::async_trait]
229 #entity
230 }
231 .into()
232}
233
234#[cfg(feature = "seaorm")]
235#[proc_macro_attribute]
254pub fn partial_entity(attr: TokenStream, input: TokenStream) -> TokenStream {
255 let attr = syn::parse_macro_input!(attr as syn::ExprPath);
256 let input = syn::parse_macro_input!(input as syn::ItemStruct);
257 let name = &input.ident;
258 let mut fields = Vec::new();
259 for i in &input.fields {
260 let field_name = &i.ident;
261 fields.push(quote!(#field_name: val.#field_name,));
262 }
263
264 quote! {
265 #input
266 impl From<#attr> for #name {
267 fn from(val: #attr) -> Self {
268 #name {
269 #(#fields)*
270 }
271 }
272 }
273 }
274 .into()
275}