Rust 异步 ORM 新选择:Toasty 初探

Rust 异步 ORM 新选择:Toasty 初探

2026年4月,Rust 生态迎来了一款新异步 ORM 框架 Toasty。为什么它如此收到 Rust 开发者的广泛关注呢?因为它是来自于鼎鼎大名的 Tokio 团队,该团队研发的 tokio(异步运行时)、tracing(日志库)、prost(pb 库)、axum(Web 框架)、loom(并发测试库) 等等,在 Rust 开发中都是必备的库之一。本文将从初探的角度,带着大家快速认识这款新框架。

Toasty 介绍

Toasty 是一个面向 Rust 编程语言的 ORM,它以易用性为首要目标。目前,它支持 SQL 数据库(SQLite、PostgreSQL、MySQL)和 NoSQL 数据库(DynamoDB)。Toasty 不会消除数据库的特性,而是可以通过 feature 引入相应数据库的特性。

与其他 ORM 不同,Toasty 并非单纯的"SQL 生成工具",而是定位为"应用级查询引擎",核心设计理念是让应用层 schema 与数据库 schema 完全解耦,将高层查询转换为不同数据库查询的最佳实践,同时简化 API 设计,减少 Rust 特性(如 trait、生命周期)的复杂使用,降低上手门槛。

需要注意的是,当前 Toasty 是处于预览版状态,大部分主要功能已经实现,功能足够完整,可以用于构建应用程序,但是 API 尚未稳定,未来仍可能存在破坏性变更,不推荐用于严谨的项目。

快速入门

这个示例将带你创建项目、定义模型以及运行第一个查询。

创建一个新项目

shell 复制代码
cargo new toasty-demo
cd toasty-demo

Cargo.toml 文件中添加以下依赖项:

toml 复制代码
[dependencies]
toasty = { version = "0.3", features = ["sqlite"] }
tokio = { version = "1", features = ["full"] }

sqlite feature 会启用 SQLite 驱动器。Toasty 还支持 postgresqlmysqldynamodb,在 features 中添加以使用不同的数据库。

定义模型

编辑 src/main.rs 并添加以下内容:

rust 复制代码
// 模型
#[derive(Debug, toasty::Model)]
struct User {
    #[key]
    #[auto]
    id: u64,

    name: String,

    #[unique]
    email: String,
}

#[tokio::main]
async fn main() -> toasty::Result<()> {
    // 构建 DB 处理器,并注册当前 crate 下的所有模型
    let mut db = toasty::Db::builder()
        .models(toasty::models!(crate::*))
        .connect("sqlite::memory:")
        .await?;

    // 基于模型创建数据表
    db.push_schema().await?;

    // 插入用户数据
    let user = toasty::create!(User {
        name: "Alice",
        email: "alice@example.com",
    })
    .exec(&mut db)
    .await?;

    println!("Created: {:?}", user.name);

    // 通过主键 ID 查询用户数据
    let found = User::get_by_id(&mut db, &user.id).await?;
    println!("Found: {:?}", found.email);

    Ok(())
}

运行它:

shell 复制代码
cargo run

你就能看到:

plaintext 复制代码
Created: "Alice"
Found: "alice@example.com"

CURD 操作

创建记录

rust 复制代码
// 使用宏
let user = toasty::create!(User {
    name: "Alice",
    email: "alice@example.com",
})
.exec(&mut db)
.await?;

// 链式操作
let user = User::create()
    .name("Alice")
    .email("alice@example.com")
    .exec(&mut db)
    .await?;

// 批量插入
let users = toasty::create!(User::[
    { name: "Alice", email: "alice@example.com" },
    { name: "Bob", email: "bob@example.com" },
    { name: "Carol", email: "carol@example.com" },
])
.exec(&mut db)
.await?;

查询记录

rust 复制代码
// 通过主键获取单条记录
let user = User::get_by_id(&mut db, &1).await?;
println!("Found: {}", user.name);

// 获取所有记录
let users = User::all().exec(&mut db).await?;
println!("Found: {:?}", users);

// 使用表达式进行条件查询
let users = User::filter(User::fields().name().eq("Alice"))
    .exec(&mut db)
    .await?;

// 使用链式表达式进行条件查询
let users = User::filter_by_name("Alice")
    .filter(User::fields().age().gt(25))
    .exec(&mut db)
    .await?;

这里 Toasty 构建一套 fields()gt() 等 API 的查询语法,其实是为了抹平 SQL 与 NoSQL 的语法差异,确保能正确转换到对应的数据库查询。

更新记录

rust 复制代码
user.update()
    .name("Alice Smith")
    .email("alice.smith@example.com")
    .exec(&mut db)
    .await?;

// 通过查询更新
User::filter_by_id(user_id)
    .update()
    .name("Bob")
    .exec(&mut db)
    .await?;

删除记录

rust 复制代码
user.delete().exec(&mut db).await?;

// 基于主键删除记录
User::delete_by_id(&mut db, user.id).await?;

// 通过查询删除记录
User::filter_by_email("alice@example.com")
    .delete()
    .exec(&mut db)
    .await?;

事务操作

rust 复制代码
let mut tx = db.transaction().await?;

toasty::create!(User { name: "Alice" }).exec(&mut tx).await?;
toasty::create!(User { name: "Bob" }).exec(&mut tx).await?;

tx.commit().await?;

总结

总得来说,Toasty 还是蛮有野心的,与其他的 ORM 框架不同,只关注于关系型数据库,Toasty 想要的是整合关系型数据库与非关系型数据库,提供一致性的访问 API。不过毕竟 Toasty 才刚起步,生态还处于建设当中,可以先持续关注着,未来可期。

相关推荐
程序员爱钓鱼5 小时前
Rust String 与 &str 详解:字符串所有权、借用与转换
前端·后端·rust
段一凡-华北理工大学17 小时前
向量数据库实战:选型、调优与落地~系列文章12:文本分块策略实战:chunk_size 怎么选?重叠多少?
开发语言·数据库·后端·oracle·rust·工业智能体·高炉智能化
大卫小东(Sheldon)1 天前
小鹤音形词典:一个用 Rust 写的离线编码查询桌面工具
ai·rust
就业发动机1 天前
我用 Tauri 做了一个约 1.5 MB 的开源屏幕标注工具:MarkerOn
vue.js·rust
2601_954526751 天前
【硬核架构】打破 IT 与 OT 的数据孤岛!基于 Rust 异步协程的工业 IoT 网关重构,兼谈顶级自动化智能仪表厂家选型指南
物联网·架构·rust
white_ant1 天前
17- 文本统计/处理工具使用指南
rust·个人开发·tauri
独孤留白1 天前
Rust 类型转换全景指南 —— 从引用转换到序列化
rust
独孤留白1 天前
从C到Rust:Trait TryFrom TryInto 可能失败的类型转换
rust
雨师@1 天前
python通过rust编写组件扩展自己的能力
python·rust
程序员爱钓鱼1 天前
Rust 切片 Slice 详解:安全访问连续数据
前端·后端·rust