| Crates.io | butane_codegen |
| lib.rs | butane_codegen |
| version | 0.8.1 |
| created_at | 2020-12-29 22:34:03.981218+00 |
| updated_at | 2025-06-15 01:49:33.453068+00 |
| description | Macros for Butane. Do not use this crate directly -- use the butane crate. |
| homepage | |
| repository | https://github.com/Electron100/butane |
| max_upload_size | |
| id | 329007 |
| size | 75,338 |
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.
proc-macros)Models, declared with struct attributes define the database schema. For example the Post model for a blog might look like this:
#[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>,
}
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.
let mut post = Post::new(blog, title, body);
post.save(conn)?;
Changes to the instance are only applied to the database when saved:
post.published = true;
post.save(conn)?;
Queries are performed ergonomically with the query! macro.
let posts = query!(Post, published == true).limit(5).load(&conn)?;
For a detailed tutorial, see the Getting Started Guide.
Butane exposes several features to Cargo. By default, no backends are
enabled: you will want to enable sqlite and/or pg:
default: Turns on datetime, json and uuid.async: Turns on async support. This is automatically enabled for the pg backend, which is implemented on the tokio-postgres crate.async-adapter: Enables the use of async with the sqlite backend, which is not natively async.debug: Used in developing Butane, not expected to be enabled by consumers.deadpool: Connection pooling using deadpool.datetime: Support for timestamps (using chrono crate).fake: Support for the fake crate's generation of fake data.json: Support for storing structs as JSON, including using postgres' JSONB field type.log: Log certain warnings to the log crate facade (target "butane").pg: Support for PostgreSQL using postgres crate.r2d2: Connection pooling using r2d2.
(See butane::db::ConnectionManager).sqlite: Support for SQLite using rusqlite crate.sqlite-bundled: Bundles sqlite instead of using the system version.tls: Support for TLS when using PostgreSQL, using
postgres-native-tls crate.uuid: Support for UUIDs (using the uuid crate).This is a major release which adds Async support. Effort has been made to keep the sync experience as unchanged as possible. Async versions of many types have been added, but the sync ones generally retain their previous names.
In order to allow sync and async code to look as similar as possible for types and traits which do not otherwise need separate sync and async variants, several "Ops" traits have been introduced which contain methods split off from prior types and traits.
For example, if obj is an instance of
DataObject,
then you may call obj.save(conn) (sync) or obj.save(conn).await
(async). The save method no longer lives on DataObject. Instead,
you must use either butane::DataObjectOpsSync or
butane::DataObjectOpsAsync. Which trait is in scope will determine
whether the save method is sync or async.
The Ops traits are:
DataObjectOpsSync / DataObjectOpsAsync
(for use with DataObject)QueryOpsSync / QueryOpsAsync
(for use with Query,
less commonly needed directly if you use the query or
filter macros)ForeignKeyOpsSync /
ForeignKeyOpsAsync
(for use with ForeignKey)ManyOpsSync / ManyOpsAsync
(for use with Many)The ConnectionManager struct has moved from butane::db::r2 to
butane::db. It no longer implements ConnectionMethods as this was
unnecessary due to Deref. The butane::db::r2 module is no longer
public.
AutoPkReplace model fields like
#[auto]
pub id: i64
with
pub id: AutoPk<i64>
ObjectState is removedRemove any references to ObjectState or to the (previously automatically generated) state field on models.
Butane is young. The following features are currently missing, but planned
ForeignKey and Many.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:
It is more object-oriented, at the cost of flexibility.
Automatic migrations are prioritized.
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.
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
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
let posts = query!(Post, published == true).limit(5).load(&conn)?;
Which form is preferable is primarily an aesthetic judgement.
Differences between database backends are largely hidden.
Diesel is overall significantly more mature and full-featured.
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.