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#[proc_macro_attribute]
108pub fn default_column(_: TokenStream, input: TokenStream) -> TokenStream {
109 let entity = syn::parse_macro_input!(input as syn::ItemStruct);
110
111 quote! {
112 #entity
113
114 impl actix_cloud_extra::entity::DefaultColumnTrait for Column {
115 fn get_created_at() -> impl sea_orm::ColumnTrait {
116 Self::CreatedAt
117 }
118
119 fn get_updated_at() -> impl sea_orm::ColumnTrait {
120 Self::UpdatedAt
121 }
122 }
123 }
124 .into()
125}
126
127#[cfg(feature = "seaorm")]
128#[proc_macro_attribute]
144pub fn entity_timestamp(_: TokenStream, input: TokenStream) -> TokenStream {
145 let mut entity = syn::parse_macro_input!(input as syn::ItemImpl);
146 entity.items.push(syn::parse_quote!(
147 fn entity_timestamp(&self, e: &mut Self, insert: bool) {
148 let tm: sea_orm::ActiveValue<i64> =
149 sea_orm::ActiveValue::set(chrono::Utc::now().timestamp_millis());
150 if insert {
151 e.created_at = tm.clone();
152 e.updated_at = tm.clone();
153 } else {
154 e.updated_at = tm.clone();
155 }
156 }
157 ));
158 quote! {
159 #entity
160 }
161 .into()
162}
163
164#[cfg(feature = "seaorm")]
165#[proc_macro_attribute]
180pub fn entity_id(attr: TokenStream, input: TokenStream) -> TokenStream {
181 let attr = syn::parse_macro_input!(attr as syn::ExprCall);
182 let mut entity = syn::parse_macro_input!(input as syn::ItemImpl);
183 entity.items.push(syn::parse_quote!(
184 fn entity_id(&self, e: &mut Self, insert: bool) {
185 if insert && e.id.is_not_set() {
186 e.id = sea_orm::ActiveValue::set(#attr);
187 }
188 }
189 ));
190 quote! {
191 #entity
192 }
193 .into()
194}
195
196#[cfg(feature = "seaorm")]
197#[proc_macro_attribute]
211pub fn entity_behavior(_: TokenStream, input: TokenStream) -> TokenStream {
212 let mut entity = syn::parse_macro_input!(input as syn::ItemImpl);
213
214 entity.items.push(syn::parse_quote!(
215 async fn before_save<C>(self, _: &C, insert: bool) -> Result<Self, sea_orm::DbErr>
216 where
217 C: sea_orm::ConnectionTrait,
218 {
219 let mut new = self.clone();
220 self.entity_id(&mut new, insert);
221 self.entity_timestamp(&mut new, insert);
222 Ok(new)
223 }
224 ));
225 quote! {
226 #[async_trait::async_trait]
227 #entity
228 }
229 .into()
230}
231
232#[cfg(feature = "seaorm")]
233#[proc_macro_attribute]
252pub fn partial_entity(attr: TokenStream, input: TokenStream) -> TokenStream {
253 let attr = syn::parse_macro_input!(attr as syn::ExprPath);
254 let input = syn::parse_macro_input!(input as syn::ItemStruct);
255 let name = &input.ident;
256 let mut fields = Vec::new();
257 for i in &input.fields {
258 let field_name = &i.ident;
259 fields.push(quote!(#field_name: self.#field_name,));
260 }
261
262 quote! {
263 #input
264 impl Into<#name> for #attr {
265 fn into(self) -> #name {
266 #name {
267 #(#fields)*
268 }
269 }
270 }
271 }
272 .into()
273}