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]
17pub fn default_viewer(attr: TokenStream, input: TokenStream) -> TokenStream {
18 let attr = parse_macro_input!(attr as Ident);
19 let mut input = parse_macro_input!(input as ItemImpl);
20 let func: Vec<String> = input
21 .items
22 .iter()
23 .map(|x| {
24 if let ImplItem::Fn(x) = x {
25 x.sig.ident.to_string()
26 } else {
27 String::new()
28 }
29 })
30 .collect();
31 let contains = |name: &str| func.iter().any(|x| x == name);
32 if !contains("find") {
33 input.items.push(parse_quote! {
34 pub async fn find<C>(
35 db: &C,
36 cond: actix_cloud_extra::api::Condition,
37 ) -> anyhow::Result<(Vec<#attr::Model>, u64)>
38 where
39 C: sea_orm::ConnectionTrait
40 {
41 cond.select_page(#attr::Entity::find(), db).await
42 }
43 });
44 }
45 if !contains("find_by_id") {
46 input.items.push(parse_quote! {
47 pub async fn find_by_id<C>(db: &C, id: &actix_cloud_extra::HyUuid) -> anyhow::Result<Option<#attr::Model>>
48 where
49 C: sea_orm::ConnectionTrait,
50 {
51 #attr::Entity::find_by_id(id.to_owned())
52 .one(db)
53 .await
54 .map_err(Into::into)
55 }
56 });
57 }
58 if !contains("delete_all") {
59 input.items.push(parse_quote! {
60 pub async fn delete_all<C>(db: &C) -> anyhow::Result<u64>
61 where
62 C: sea_orm::ConnectionTrait,
63 {
64 #attr::Entity::delete_many()
65 .exec(db)
66 .await
67 .map(|x| x.rows_affected)
68 .map_err(Into::into)
69 }
70 });
71 }
72 if !contains("delete") {
73 input.items.push(parse_quote! {
74 pub async fn delete<C>(db: &C, id: &actix_cloud_extra::HyUuid) -> anyhow::Result<u64>
75 where
76 C: sea_orm::ConnectionTrait,
77 {
78 #attr::Entity::delete_by_id(*id)
79 .exec(db)
80 .await
81 .map(|x| x.rows_affected)
82 .map_err(Into::into)
83 }
84 });
85 }
86 if !contains("count") {
87 input.items.push(parse_quote! {
88 pub async fn count<C>(
89 db: &C,
90 cond: actix_cloud_extra::api::Condition,
91 ) -> anyhow::Result<u64>
92 where
93 C: sea_orm::ConnectionTrait,
94 {
95 Ok(cond.build(#attr::Entity::find()).0.count(db).await?)
96 }
97 });
98 }
99
100 quote! {
101 #input
102 }
103 .into()
104}
105
106#[cfg(feature = "seaorm")]
107#[proc_macro_attribute]
123pub fn entity_timestamp(_: TokenStream, input: TokenStream) -> TokenStream {
124 let mut entity = syn::parse_macro_input!(input as syn::ItemImpl);
125 entity.items.push(syn::parse_quote!(
126 fn entity_timestamp(&self, e: &mut Self, insert: bool) {
127 let tm: sea_orm::ActiveValue<DateTime> =
128 sea_orm::ActiveValue::set(chrono::Utc::now().naive_utc());
129 if insert {
130 e.created_at = tm.clone();
131 e.updated_at = tm.clone();
132 } else {
133 e.updated_at = tm.clone();
134 }
135 }
136 ));
137 quote! {
138 #entity
139
140 impl actix_cloud_extra::entity::DefaultColumnTrait for Column {
141 fn get_created_at() -> impl sea_orm::ColumnTrait {
142 Self::CreatedAt
143 }
144
145 fn get_updated_at() -> impl sea_orm::ColumnTrait {
146 Self::UpdatedAt
147 }
148 }
149 }
150 .into()
151}
152
153#[cfg(feature = "seaorm")]
154#[proc_macro_attribute]
169pub fn entity_id(attr: TokenStream, input: TokenStream) -> TokenStream {
170 let attr = syn::parse_macro_input!(attr as syn::ExprCall);
171 let mut entity = syn::parse_macro_input!(input as syn::ItemImpl);
172 entity.items.push(syn::parse_quote!(
173 fn entity_id(&self, e: &mut Self, insert: bool) {
174 if insert && e.id.is_not_set() {
175 e.id = sea_orm::ActiveValue::set(#attr);
176 }
177 }
178 ));
179 quote! {
180 #entity
181 }
182 .into()
183}
184
185#[cfg(feature = "seaorm")]
186#[proc_macro_attribute]
200pub fn entity_behavior(_: TokenStream, input: TokenStream) -> TokenStream {
201 let mut entity = syn::parse_macro_input!(input as syn::ItemImpl);
202
203 entity.items.push(syn::parse_quote!(
204 async fn before_save<C>(self, _: &C, insert: bool) -> Result<Self, sea_orm::DbErr>
205 where
206 C: sea_orm::ConnectionTrait,
207 {
208 let mut new = self.clone();
209 self.entity_id(&mut new, insert);
210 self.entity_timestamp(&mut new, insert);
211 Ok(new)
212 }
213 ));
214 quote! {
215 #[async_trait::async_trait]
216 #entity
217 }
218 .into()
219}
220
221#[cfg(feature = "seaorm")]
222#[proc_macro_attribute]
241pub fn partial_entity(attr: TokenStream, input: TokenStream) -> TokenStream {
242 let attr = syn::parse_macro_input!(attr as syn::ExprPath);
243 let input = syn::parse_macro_input!(input as syn::ItemStruct);
244 let name = &input.ident;
245 let mut fields = Vec::new();
246 for i in &input.fields {
247 let field_name = &i.ident;
248 fields.push(quote!(#field_name: self.#field_name,));
249 }
250
251 quote! {
252 #input
253 impl Into<#name> for #attr {
254 fn into(self) -> #name {
255 #name {
256 #(#fields)*
257 }
258 }
259 }
260 }
261 .into()
262}