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_many()
79 .filter(#attr::Column::Id.is_in(actix_cloud_extra::hyuuid::uuids2strings(id)))
80 .exec(db)
81 .await
82 .map(|x| x.rows_affected)
83 .map_err(Into::into)
84 }
85 });
86 }
87 if !contains("count") {
88 input.items.push(parse_quote! {
89 pub async fn count<C>(
90 db: &C,
91 cond: actix_cloud_extra::api::Condition,
92 ) -> anyhow::Result<u64>
93 where
94 C: sea_orm::ConnectionTrait,
95 {
96 Ok(cond.build(#attr::Entity::find()).0.count(db).await?)
97 }
98 });
99 }
100
101 quote! {
102 #input
103 }
104 .into()
105}
106
107#[cfg(feature = "seaorm")]
108#[proc_macro_attribute]
124pub fn entity_timestamp(_: TokenStream, input: TokenStream) -> TokenStream {
125 let mut entity = syn::parse_macro_input!(input as syn::ItemImpl);
126 entity.items.push(syn::parse_quote!(
127 fn entity_timestamp(&self, e: &mut Self, insert: bool) {
128 let tm: sea_orm::ActiveValue<DateTime> =
129 sea_orm::ActiveValue::set(chrono::Utc::now().naive_utc());
130 if insert {
131 e.created_at = tm.clone();
132 e.updated_at = tm.clone();
133 } else {
134 e.updated_at = tm.clone();
135 }
136 }
137 ));
138 quote! {
139 #entity
140
141 impl actix_cloud_extra::entity::DefaultColumnTrait for Column {
142 fn get_created_at() -> impl sea_orm::ColumnTrait {
143 Self::CreatedAt
144 }
145
146 fn get_updated_at() -> impl sea_orm::ColumnTrait {
147 Self::UpdatedAt
148 }
149 }
150 }
151 .into()
152}
153
154#[cfg(feature = "seaorm")]
155#[proc_macro_attribute]
170pub fn entity_id(attr: TokenStream, input: TokenStream) -> TokenStream {
171 let attr = syn::parse_macro_input!(attr as syn::ExprCall);
172 let mut entity = syn::parse_macro_input!(input as syn::ItemImpl);
173 entity.items.push(syn::parse_quote!(
174 fn entity_id(&self, e: &mut Self, insert: bool) {
175 if insert && e.id.is_not_set() {
176 e.id = sea_orm::ActiveValue::set(#attr);
177 }
178 }
179 ));
180 quote! {
181 #entity
182 }
183 .into()
184}
185
186#[cfg(feature = "seaorm")]
187#[proc_macro_attribute]
201pub fn entity_behavior(_: TokenStream, input: TokenStream) -> TokenStream {
202 let mut entity = syn::parse_macro_input!(input as syn::ItemImpl);
203
204 entity.items.push(syn::parse_quote!(
205 async fn before_save<C>(self, _: &C, insert: bool) -> Result<Self, sea_orm::DbErr>
206 where
207 C: sea_orm::ConnectionTrait,
208 {
209 let mut new = self.clone();
210 self.entity_id(&mut new, insert);
211 self.entity_timestamp(&mut new, insert);
212 Ok(new)
213 }
214 ));
215 quote! {
216 #[async_trait::async_trait]
217 #entity
218 }
219 .into()
220}
221
222#[cfg(feature = "seaorm")]
223#[proc_macro_attribute]
242pub fn partial_entity(attr: TokenStream, input: TokenStream) -> TokenStream {
243 let attr = syn::parse_macro_input!(attr as syn::ExprPath);
244 let input = syn::parse_macro_input!(input as syn::ItemStruct);
245 let name = &input.ident;
246 let mut fields = Vec::new();
247 for i in &input.fields {
248 let field_name = &i.ident;
249 fields.push(quote!(#field_name: self.#field_name,));
250 }
251
252 quote! {
253 #input
254 impl Into<#name> for #attr {
255 fn into(self) -> #name {
256 #name {
257 #(#fields)*
258 }
259 }
260 }
261 }
262 .into()
263}