1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
/*!
# axum-mongodb
[](https://github.com/yexiyue/axum-mongodb)
[](https://crates.io/crates/axum-mongodb)
**axum-mongodb** 是一个为 [Axum](https://github.com/tokio-rs/axum) Web 框架量身打造的库,旨在提供一种简洁且优雅的 MongoDB 集成方案。本库的设计灵感来源于著名的 JavaScript 框架 [Nest.js](https://nestjs.com/),致力于简化并提升 Axum 项目中对 MongoDB 数据库的操作效率。
### 功能亮点
- **基于状态管理的数据库连接**
- **便捷的 CRUD 操作封装**
### 安装
在 `Cargo.toml` 中添加 axum-mongodb 依赖:
```toml
[dependencies]
axum-mongodb = "1.0.3"
```
或者通过 `cargo add` 命令快速安装:
```bash
cargo add axum-mongodb
```
### 使用教程
#### 1. 初始化数据库连接
在项目的入口点(如 `lib.rs`)中使用 `axum_mongodb::main` 属性宏来设置 MongoDB 连接和初始化数据库服务。
```rust
use anyhow::Result;
use axum::{response::IntoResponse, routing::get, Router};
use axum_mongodb::preload::*;
use mongodb::{options::ClientOptions, Client};
use tokio::net::TcpListener;
// ...
#[axum_mongodb::main]
pub async fn start() -> Result<()> {
// 解析并创建 MongoDB 客户端配置
let client_options = ClientOptions::parse("mongodb://mongodb:password@localhost:21045/admin").await?;
let client = Client::with_options(client_options)?;
let db = client.database("todo");
// 创建 MongoDB 服务器状态实例
let mongodb_server = MongoDbServer::<Servers>::new(db).await;
// 构建 Axum 应用,并注入 MongoDB 状态到全局路由
let app = Router::new()
.route("/", get(hello_world))
.merge(todos_router())
.with_state(mongodb_server);
// 启动服务器监听
let listener = TcpListener::bind("127.0.0.1:8080").await.unwrap();
tracing::info!("Listening on http://{}", listener.local_addr().unwrap());
axum::serve(listener, app).await.unwrap();
Ok(())
}
async fn hello_world() -> impl IntoResponse {
"hello world"
}
```
#### 2. 定义数据模型
利用 `axum_mongodb::Column` Derive 宏装饰你的结构体以支持与 MongoDB 的交互:
```rust
use anyhow::Result;
use axum_mongodb::futures::TryStreamExt;
use bson::{self, doc, oid::ObjectId};
use mongodb::{results::{DeleteResult, InsertOneResult, UpdateResult},};
use serde::{Deserialize, Serialize};
#[derive(Debug, Column, Deserialize, Serialize, Clone)]
pub struct Todo {
#[serde(
serialize_with = "bson::serde_helpers::serialize_object_id_as_hex_string",
rename = "_id"
)]
id: ObjectId,
description: String,
completed: bool,
create_time: chrono::DateTime<chrono::Local>,
update_time: chrono::Local,
}
impl Server<Todo> {
pub async fn create_todo(&self, description: String) -> Result<InsertOneResult> {
Ok(self
.insert_one(
Todo {
id: ObjectId::new(),
description,
completed: false,
create_time: chrono::Local::now(),
update_time: chrono::Local::now(),
},
None,
)
.await?)
}
// ... 其他CRUD方法实现
}
```
#### 3. 在 Axum handler 中使用
在处理函数中注入 `Server<Todo>` 实例,并调用相应的方法完成数据库操作:
```rust
use axum::{extract::Path, response::IntoResponse, Json};
use serde::Deserialize;
use super::Todo;
use crate::Server;
#[derive(Debug, Deserialize)]
pub struct TodoQuery {
pub description: String,
pub completed: Option<bool>,
}
pub async fn create_todo(todo: Server<Todo>, Json(TodoQuery { description, .. }): Json<TodoQuery>) -> impl IntoResponse {
let res = todo.create_todo(description).await.unwrap();
Json(res)
}
```
#### 4. 注册路由
定义并组合相关路由,将 MongoDB 服务状态注入到路由模块中:
```rust
mod controller;
use controller::{create_todo, delete_todo, get_todo, get_todos, update_todo};
use axum::{
routing::{get, post},
Router,
};
use axum_mongodb::MongoDbServer;
pub use server::Todo;
pub fn todos_router() -> Router<MongoDbServer<Servers>> {
Router::new()
.route("/todos", post(create_todo).get(get_todos))
.route("/todos/:id", get(get_todo).put(update_todo).delete(delete_todo))
}
```
### 示例代码与文档
完整的示例代码可参考 [axum-mongodb-example](https://github.com/yexiyue/axum-mongodb/blob/master/examples/axum/src/lib.rs)。同时,你可以查阅 [API 文档](https://apifox.com/apidoc/shared-6bef1065-5c3e-42a8-bf10-73e21f671fe1) 以获得更详细的信息和示例说明。
### 更多信息
请访问项目主页或查看仓库中的文档以获取更多关于如何在您的 Axum 项目中高效地集成和使用 MongoDB 的细节及高级功能。
*/
#[doc(hidden)]
pub use axum::async_trait;
pub use axum_mongodb_core::{inject, main, Column};
#[doc(hidden)]
pub use axum_mongodb_core::inject_meta;
#[doc(hidden)]
pub use futures;
#[doc(hidden)]
pub use mongodb;
mod mongodb_server;
pub use mongodb_server::MongoDbServer;
pub mod preload {
//! 重新导出常用的结构体和宏
#[doc(hidden)]
pub use crate::CollectionInit;
pub use crate::MongoDbServer;
#[doc(hidden)]
pub use crate::NewWithDb;
pub use axum_mongodb_core::{inject, main, Column};
pub struct DBServers;
}
#[doc(hidden)]
#[async_trait]
pub trait NewWithDb {
async fn new(db: mongodb::Database) -> Self;
}
#[doc(hidden)]
#[async_trait]
pub trait CollectionInit {
async fn init(&self);
}
#[doc(hidden)]
pub struct CreateIndexOptions {
pub keys: mongodb::bson::Document,
pub unique: bool,
pub name: Option<String>,
}