14个版本
0.7.0 | 2024年7月17日 |
---|---|
0.6.1 | 2023年5月27日 |
0.5.1 | 2022年12月27日 |
0.5.0 | 2022年11月14日 |
0.1.0 | 2020年12月29日 |
#2763 in 数据库接口
167 每月下载次数
用于 4 个crate(其中2个直接使用)
265KB
6.5K SLoC
Butane
一个专注于简单性和Rust而非SQL的Rust实验性ORM。
Butane采用面向对象的方法进行数据库操作。它可以被视为一个对象持久化系统,而不仅仅是ORM -- 它由SQL数据库支持的事实对API消费者来说主要是实现细节。
特性
- 使用类似Rust语法的关联查询(通过
proc-macro
) - 无需编写SQL即可自动迁移(尽管必要时可以手动调整生成的SQL)
- 能够在Rust代码中嵌入迁移(因此库可以轻松捆绑其迁移)
- SQLite和PostgreSQL后端
- 无论数据库后端如何,都可以编写全部或几乎全部相同的代码
入门指南
模型,通过结构体属性声明数据库模式。例如,一个博客的Post模型可能看起来像这样
#[model]
#[derive(Default)]
struct Post {
id: AutoPk<i32>,
title: String,
body: String,
published: bool,
likes: i32,
tags: Many<Tag>,
blog: ForeignKey<Blog>,
byline: Option<String>,
}
一个对象是一个模型的实例。对象像普通结构体实例一样创建,但必须保存才能持久化。
let mut post = Post::new(blog, title, body);
post.save(conn)?;
只有在保存时才会将实例的更改应用到数据库中
post.published = true;
post.save(conn)?;
使用query!
宏进行查询,操作起来非常舒适。
let posts = query!(Post, published == true).limit(5).load(&conn)?;
有关详细教程,请参阅入门指南。
Cargo特性
Butane向Cargo公开了几个特性。默认情况下,没有启用任何后端:您可能需要启用sqlite
和/或pg
default
:启用datetime
、json
和uuid
。debug
:用于开发Butane,消费者不应启用。datetime
:支持时间戳(使用chrono
crate)。fake
:支持fake
包生成假数据。json
:支持将结构体存储为JSON,包括使用PostgreSQL的JSONB
字段类型。log
:将某些警告记录到log
包界面(目标"butane")。pg
:支持使用postgres
包的PostgreSQL。r2d2
:使用r2d2
支持连接池(请参阅butane::db::ConnectionManager
)。sqlite
:支持使用rusqlite
包的SQLite。sqlite-bundled
:捆绑sqlite而不是使用系统版本。tls
:使用PostgreSQL时支持TLS,使用postgres-native-tls
包。uuid
:支持UUID(使用uuid
包)。
限制
- Butane及其迁移系统特别期望拥有数据库。它可以与被其他消费者访问的现有数据库一起使用,但这不是设计目标,也没有从现有数据库模式推断butane模型的功能。
- API的易用性高于性能。这并不意味着Butane慢,而是当在简单、直接的API和尽可能小的开销之间做出选择时,API将获胜。
路线图
Butane还年轻。以下功能目前尚未提供,但计划中:
- 外键约束级联设置
- 增量对象保存
ForeignKey
和Many
的回引用。- 在迁移中支持字段/列重命名
- 预置/可重复使用的查询
- 基准测试和性能调整
- 支持其他数据库,如MySQL或SQL Server,目前没有明确计划,但欢迎贡献。
与Diesel的比较
Butane受到Diesel和Django的ORM的启发。如果您正在寻找成熟、性能良好且灵活的ORM,请使用Diesel。Butane不旨在比Diesel更好,但它做出了一些不同的决策,包括
-
它更加面向对象,但牺牲了灵活性。
-
优先考虑自动迁移。
-
Rust代码是真理的来源。模式是从Rust代码中模型的定义中理解的,而不是从数据库中推断出来的。
-
查询是通过在
proc-macro
调用内部使用DSL构建的,而不是通过将DSL方法/名称导入当前作用域来使用。对于Diesel,您可能写成use diesel_demo::schema::posts::dsl::*; let posts = posts.filter(published.eq(true)) .limit(5) .load::<Post>(&conn)?
而对于Butane,您将改写成
let posts = query!(Post, published == true).limit(5).load(&conn)?;
哪种形式更可取主要是一种审美判断。
-
数据库后端的差异在很大程度上被隐藏了。
-
Diesel在整体上显著更加成熟和功能丰富。
有关详细教程,请参阅入门指南。
许可协议
Butane可以在MIT许可或Apache License,版本2.0中选择其一进行许可。
除非您明确声明,否则您提交给Butane的任何有意贡献,如Apache-2.0许可证中定义,应作为上述双重许可,不附加任何额外条款或条件。
依赖项
~4-21MB
~309K SLoC