宣布 Toasty:Rust 的异步 ORM

宣布 Toasty:Rust 的异步 ORM


Toasty 是一个为 Rust 编程语言设计的异步 ORM , 旨在简化使用过程 。 Toasty 支持 SQL 和 NoSQL 数据库 , 包括 DynamoDB 和 Cassandra(即将支持) 。

Toasty 目前处于开发初期阶段 , 可以被视为“预览版”(尚未准备好用于实际生产环境) 。 它还未在 crates.io 上发布 。 我之所以现在宣布它 , 是因为我已经将 GitHub 仓库公开 , 并计划在公开环境中继续开发 , 希望能够获得反馈意见 。
使用 Toasty 的项目首先需要创建一个 schema 文件 , 以定义应用程序的数据模型 。 例如 , 下面是 hello-toasty/schema.toasty 文件的内容:
rustCopy codemodel User {
   #[key

   #[auto

   id: Id

   name: String

   #[unique

   email: String

   todos: [Todo


   moto: Option<String>model Todo {
   #[key

   #[auto

   id: Id

   #[index

   user_id: Id<User>

   #[relation(key = user_id references = id)

   user: User

   title: String

使用 Toasty 的 CLI 工具 , 您可以生成处理该数据模型所需的所有 Rust 代码 。 上面 schema 文件生成的代码可以在 这里 查看 。
之后 , 您可以轻松地操作数据模型:
rustCopy code// 创建一个新用户 , 并为他们添加一些待办事项 。 User::create()
   .name(\"John Doe\")
   .email(\"john@example.com\")
   .todo(Todo::create().title(\"Make pizza\"))
   .todo(Todo::create().title(\"Finish Toasty\"))
   .todo(Todo::create().title(\"Sleep\"))
   .exec(&db)
   .await?;// 从数据库中加载用户let user = User::find_by_email(\"john@example.com\").get(&db).await?// 加载并遍历用户的待办事项let mut todos = user.todos().all(&db).await.unwrap();while let Some(todo) = todos.next().await {
   let todo = todo.unwrap();
   println!(\"{:#?\" todo);

为什么需要 ORM?从历史上看 , Rust 一直被定位为系统级编程语言 。 在服务器端 , Rust 在数据库、代理和其他基础设施级应用程序等场景中发展得最快 。 然而 , 与一些已经在基础设施级应用中采用 Rust 的团队交谈时 , 不难发现他们开始更多地将 Rust 用于更高层次的应用场景 , 比如传统的 Web 应用 。
一般的共识是 , 当性能不是最关键的考量时 , 应尽可能提高生产效率 。 我同意这一观点 。 在构建 Web 应用时 , 性能是次要的 , 生产效率才是关键 。 那么 , 为什么在性能要求较低的场景下 , 团队却越来越多地选择使用 Rust 呢?这是因为一旦掌握了 Rust , 你就会变得非常高效 。
生产效率是一个复杂且多维度的问题 。 尽管我们都知道 Rust 的编辑-编译-测试循环可能会有些慢 , 但这种摩擦感被更少的错误、生产问题以及长期维护上的稳健性所抵消(Rust 的借用检查器鼓励更具可维护性的代码) 。 此外 , 由于 Rust 能很好地适应多种场景 , 无论是基础设施级服务器应用 , 更高层次的 Web 应用 , 甚至是客户端应用(通过 WASM 运行在浏览器端 , 以及原生运行在 iOS、MacOS、Windows 等平台上) , Rust 具有出色的代码复用能力 。 内部库可以一次编写 , 便能在所有这些上下文中复用 。
因此 , 尽管 Rust 可能不是原型开发的最优选择 , 但对于长期项目 , 它的竞争力非常强 。
那么 , 为什么需要一个 ORM?功能齐全的库生态对于特定用例的生产效率至关重要 。 Rust 有一个充满活力的生态系统 , 但历史上更侧重于基础设施级应用 。 针对更高层次 Web 应用的库相对较少(尽管近年来这种情况有所改变) 。 此外 , 现有的许多库通常为了性能而牺牲了易用性 。 在 Rust 的生态系统中存在一个空白点:许多团队反映 , 当前 Rust 的 ORM 库在使用上的摩擦感很大(有的团队甚至选择实现自己的数据库抽象库来应对这种摩擦) 。 Toasty 旨在填补这一空白 , 专注于更高层次的应用场景 , 并优先考虑易用性 , 而不是性能最大化 。
什么样的 ORM 才算易用?当然 , 这就是所谓的“百万美元问题” 。 Rust 社区仍在探索如何设计易用的库 。 Rust 的 traits 和生命周期特性非常强大 , 既能提高性能 , 也能实现有趣的模式(例如 typestate 模式) 。 然而 , 过度使用这些特性也会导致难以使用的库 。
因此 , 在构建 Toasty 时 , 我尽量谨慎地使用这些特性 , 注重最小化 traits 和生命周期的使用 。 下面这段代码是从 Toasty 生成的代码中摘取的 , 我预计这是 95% 的 Toasty 用户可能会遇到的最复杂的类型签名 。
rustCopy codepub fn find_by_email<'a>(
\temail: impl stmt::IntoExpr<'a String>) -> FindByEmail<'a> {

\tlet expr = User::EMAIL.eq(email);
\tlet query = Query::from_expr(expr);
\tFindByEmail { query

其中确实包含了一个生命周期 , 以避免在查询构建器中复制数据 。 根据用户反馈 , 我可能会完全去掉生命周期 。
易用性的另一个方面是减少样板代码 。 Rust 已经在这方面有一个非常出色的功能:过程宏 。 大多数人可能已经使用过 Serde , 因此应该了解它的优势 。 然而 , 对于 Toasty , 我选择暂时不使用过程宏 , 至少在初期不使用 。
过程宏会在构建时生成大量隐藏代码 。 对于像 Serde 这样的库 , 这并不是问题 , 因为 Serde 宏生成的是公共 trait(Serialize 和 Deserialize)的实现 。 Serde 用户实际上不需要了解这些 trait 的实现细节 。
而 Toasty 的情况有所不同 。 Toasty 会生成大量您将直接使用的公共方法和类型 。 在 “Hello Toasty” 示例中 , Toasty 生成了 User::find_by_email 方法 。 与过程宏不同 , 我选择了显式代码生成步骤 , Toasty 会将代码生成到文件中 , 您可以打开并阅读 。 Toasty 会尽量使生成的代码保持可读性 , 以便更容易发现生成的方法 。 这种可发现性将使库更加易用 。
Toasty 目前仍处于开发早期阶段 , API 将根据您的反馈不断演变 。 最终 , 如果您在使用过程中遇到摩擦 , 请告诉我 , 我会努力改进 。
支持 SQL 和 NoSQLToasty 支持 SQL 和 NoSQL 数据库 。 截至目前 , 这意味着支持 Sqlite 和 DynamoDB , 尽管增加对其他 SQL 数据库的支持应该相对容易 。 我也计划很快添加对 Cassandra 的支持 , 但也希望其他人能为不同数据库的实现做出贡献 。
需要明确的是 , Toasty 虽然同时支持 SQL 和 NoSQL 数据库 , 但并不会抽象掉目标数据库 。 一个使用 SQL 数据库编写的应用程序无法直接运行在 NoSQL 数据库上 。 相反 , Toasty 也不会抽象掉 NoSQL 数据库 , 您需要理解如何建模 schema 才能充分利用目标数据库 。 我的观察是 , 大多数数据库库在处理不同的后台数据存储时 , 其核心功能基本一致:数据到结构体的映射以及执行基本的 Get、Insert 和 Update 查询 。
Toasty 从这一标准功能集入手 , 并在可选的基础上暴露数据库特定的功能 。 它还将通过对生成的查询方法进行选择 , 帮助您避免在目标数据库上执行低效查询 。
下一步您应该尝试使用 Toasty , 运行示例并进行实验 。 目前 , Toasty 仍在积极开发中 , 尚未准备好投入实际使用 。 下一步的目标是填补现有的功能空白 。 我计划在明年年底之前(更现实的时间点)让 Toasty 准备好投入生产使用 。
此外 , Toasty 试图以当前的方式同时支持 SQL 和 NoSQL 是一种新的尝试(据我所知) 。 如果您了解类似的尝试 , 特别是过去的尝试中遇到的困难 , 我非常乐意听取您的意见 。 我也知道 , 许多人对数据库、ORM 等方面有强烈的观点 , 我期待这些讨论 。 可以在 Tokio Discord 的 #toasty 频道讨论 。 另外 , 也可以在 Github 仓库 上创建问题 , 提出功能建议或讨论 API 设计和方向 。
【宣布 Toasty:Rust 的异步 ORM】——Carl Lerche

    推荐阅读