axum_mongodb_core/
lib.rs

1/*!
2该库是axum-mongodb的核心库,主要提供其中宏相关的实现
3
4提供以下宏
5
6- [`Column`]:`#[derive(Column)]`Derive宏,用于收集结构体元信息
7
8- [`macro@main`]:`#[axum_mongodb::main]`属性宏,在main函数上使用,主要生成相关结构体,例如Servers、Server
9
10- [`macro@inject`]:`#[axum_mongodb::inject]`属性宏,用于axum handler上,主要作用是替换`DBServers`到`axum_mongodb::MongoDbServer<crate::Servers>`
11
12该库不支持直接使用,具体用法请查看[axum_mongodb](https://docs.rs/axum-mongodb/latest/axum_mongodb/)
13
14*/
15
16#[doc(hidden)]
17use proc_macro::TokenStream;
18mod column;
19pub(crate) mod column_meta;
20use column::collect_meta;
21use column_meta::COLUMN_META;
22
23#[doc(hidden)]
24use quote::quote;
25
26#[doc(hidden)]
27use syn::parse_macro_input;
28pub(crate) mod indexes;
29
30/**
31Column Derive宏,用于收集结构体元信息,以及初始化mongodb的索引
32
33每次修改索引时,默认不删除全部索引,但会尝试删除老的索引
34
35属性列表
36
37- dropIndexes:是否删除当前集合的全部索引,默认不删除
38
39- singleIndex:[单索引](https://www.mongodb.com/docs/manual/core/indexes/index-types/index-single/)
40
41- compoundIndex:[复合索引](https://www.mongodb.com/docs/manual/core/indexes/index-types/index-compound/)
42
43- multikeyIndex:[多键索引](https://www.mongodb.com/docs/manual/core/indexes/index-types/index-multikey/)
44
45
46# Example
47```rust
48#[derive(Debug, Clone, Column)]
49#[dropIndexes]
50struct User {
51    #[singleIndex(unique)]
52    name: String,
53    #[compoundIndex(unique, other_fields(name))]
54    age: i32,
55    #[multikeyIndex(unique, field_name = "age")]
56    address: String,
57}
58```
59 */
60#[proc_macro_derive(
61    Column,
62    attributes(dropIndexes, singleIndex, compoundIndex, multikeyIndex)
63)]
64pub fn column_derive(input: TokenStream) -> TokenStream {
65    let st = syn::parse_macro_input!(input as syn::DeriveInput);
66    let drop_indexes = st
67        .attrs
68        .iter()
69        .find(|attr| attr.path().is_ident("dropIndexes"));
70    let mut drop = false;
71    if drop_indexes.is_some() {
72        drop = true;
73    }
74    collect_meta(&st, drop)
75        .unwrap_or_else(|e| e.to_compile_error())
76        .into()
77}
78
79/**
80最主要的宏,为Server<T>实现[`axum::extract::FromRequestParts`]等
81# Example
82```rust
83#[tokio::main]
84#[axum_mongodb::main]
85async fn main() {
86    //...
87}
88```
89*/
90#[proc_macro_attribute]
91pub fn main(_attr: TokenStream, input: TokenStream) -> TokenStream {
92    let st = parse_macro_input!(input as syn::ItemFn);
93    let mut res = proc_macro2::TokenStream::new();
94    res.extend(quote!(
95        #[derive(Debug, Clone)]
96        pub struct Server<T>(mongodb::Collection<T>);
97
98        unsafe impl<T> Send for Server<T> {}
99        unsafe impl<T> Sync for Server<T> {}
100
101        impl<T> std::ops::Deref for Server<T> {
102            type Target = mongodb::Collection<T>;
103
104            fn deref(&self) -> &Self::Target {
105                &self.0
106            }
107        }
108
109        impl<T> AsRef<mongodb::Collection<T>> for Server<T> {
110            fn as_ref(&self) -> &mongodb::Collection<T> {
111                &self.0
112            }
113        }
114
115        #[axum_mongodb::async_trait]
116        impl<T> axum_mongodb::NewWithDb for Server<T>
117        where
118            Self: axum_mongodb::CollectionInit,
119        {
120            async fn new(db: mongodb::Database) -> Self {
121                //通过类型名称设置集合
122                let type_name = std::any::type_name::<T>();
123                let mut collection_name = type_name.split("::").last().unwrap().to_lowercase();
124                collection_name.push('s');
125                let collection = db.collection::<T>(&collection_name);
126                let res = Self(collection);
127                res.init().await;
128                res
129            }
130        }
131
132        #[axum_mongodb::inject_meta]
133        pub struct Servers {}
134
135        #[axum_mongodb::async_trait]
136        impl<S> axum::extract::FromRequestParts<S> for crate::Servers
137        where
138            S: Send + Sync,
139        {
140            type Rejection = std::convert::Infallible;
141            async fn from_request_parts(
142                parts: &mut axum::http::request::Parts,
143                _state: &S,
144            ) -> Result<Self, Self::Rejection> {
145                let dbs = parts
146                    .extensions
147                    .get::<axum_mongodb::MongoDbServer<Self>>()
148                    .expect("can not get MongoDbServer");
149                Ok(dbs.servers.clone())
150            }
151        }
152        #st
153    ));
154    res.into()
155}
156
157/// 用于宏内部,将收集到的元信息注入到结构体中
158#[proc_macro_attribute]
159pub fn inject_meta(_attr: TokenStream, input: TokenStream) -> TokenStream {
160    let st = parse_macro_input!(input as syn::ItemStruct);
161    column::inject_meta(&st)
162        .unwrap_or_else(|e| e.to_compile_error())
163        .into()
164}
165
166/**
167用于axum handler,用于替换extract类型,简化操作
168# Example
169```rust
170#[axum_mongodb::inject]
171async fn db_test(servers: DBServers) -> impl IntoResponse {
172    let db_name = servers.db.name();
173    Json(json!({
174        "db_name":db_name
175    }))
176}
177```
178*/
179#[proc_macro_attribute]
180pub fn inject(_attr: TokenStream, input: TokenStream) -> TokenStream {
181    let st = parse_macro_input!(input as syn::ItemFn);
182    column::inject(&st)
183        .unwrap_or_else(|e| e.to_compile_error())
184        .into()
185}