An experimental ORM for Rust with a focus on simplicity and on writing Rust, not SQL
Butane takes an object-oriented approach to database operations. It may be thought of as much as an object-persistence system as an ORM -- the fact that it is backed by a SQL database is mostly an implementation detail to the API consumer.
Models, declared with struct attributes define the database schema. For example the Post model for a blog might look like this:
``` rust
struct Post {
#[auto]
id: i64,
title: String,
body: String,
published: bool,
likes: i32,
tags: Many
An object is an instance of a model. An object is created like a normal struct instance, but must be saved in order to be persisted.
rust
let mut post = Post::new(blog, title, body);
post.save(conn)?;
Changes to the instance are only applied to the database when saved:
rust
post.published = true;
post.save(conn)?;
Queries are performed ergonmically with the query!
macro.
rust
let posts = query!(Post, published == true).limit(5).load(&conn)?;
For a detailed tutorial, see the Getting Started Guide.
Butane exposes several featues to Cargo. By default, no backends are
enabled: you will want to enabled either sqlite
or pg
:
* default
: Turns on datetime
and uuid
.
* debug
: Used in developing Butane, not expected to be enabled by consumers.
* datetime
: Support for timestamps (using chrono::NaiveDateTime
).
* log
: Log certain warnings to the log
crate facade (target "butane").
* pg
: Support for PostgreSQL.
* r2d2
: R2D2 support (propane::db::ConnectionManager
).
* sqlite
: Support for SQLite.
* sqlite-bundled
: Bundles sqlite instead of using the system version.
* tls
: Support for TLS when using PostgreSQL.
* uuid
: Support for UUIDs (using the uuid
crate).
Butane is young. The following features are currently missing, but planned
* Foreign key constraints
* Incremental object save
* Backreferences for ForeignKey
and Many
.
* Field/column rename support in migrations
* Prepared/reusable queries
* Benchmarking and performance tuning
* Support for other databases such as MySQL or SQL Server are not
explicitly planned, but contributions are welcome.
Butane is inspired by Diesel and by Django's ORM. If you're looking for a mature, performant, and flexible ORM, go use Diesel. Butane doesn't aim to be better than Diesel, but makes some different decisions, including:
Queries are constructed using a DSL inside a proc-macro invocation rather than by importing dsl methods/names to use into the current scope. For Diesel, you might write
rust
use diesel_demo::schema::posts::dsl::*;
let posts = posts.filter(published.eq(true))
.limit(5)
.load::<Post>(&conn)?
whereas for Butane, you would instead write
rust
let posts = query!(Post, published == true).limit(5).load(&conn)?;
Which form is preferable is primarily an aesthetic judgement.
For a detailed tutorial, see the getting started guide.
Butane is licensed under either of the MIT license or the Apache License, Version 2.0 at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in Butane by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.