Latest Version docs Build Status

Butane

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.

Features

Getting Started

Models, declared with struct attributes define the database schema. For example the Post model for a blog might look like this:

``` rust

[model]

[derive(Default)]

struct Post { #[auto] id: i64, title: String, body: String, published: bool, likes: i32, tags: Many, blog: ForeignKey, byline: Option, } ```

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 ergonomically with the query! macro.

rust let posts = query!(Post, published == true).limit(5).load(&conn)?;

For a detailed tutorial, see the Getting Started Guide.

Cargo Features

Butane exposes several features to Cargo. By default, no backends are enabled: you will want to enable either sqlite or pg:

Limitations

Roadmap

Butane is young. The following features are currently missing, but planned

Comparison to Diesel

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:

  1. It is more object-oriented, at the cost of flexibility.
  2. Automatic migrations are prioritized.
  3. Rust code is the source of truth. The schema is understood from the definition of Models in Rust code, rather than inferred from the database.
  4. 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.

  5. Differences between database backends are largely hidden.
  6. Diesel is overall significantly more mature and full-featured.

For a detailed tutorial, see the getting started guide.

License

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.