Pascal Hertleif
2017-03-01
$ cargo new --bin diesel-example
$ cd diesel-example
$ echo "DATABASE_URL=test.db" > .env
Add to Cargo.toml
:
[dependencies]
diesel = { version = "0.10.1", features = ["sqlite"] }
diesel_codegen = { version = "0.10.1", features = ["sqlite"] }
dotenv = "0.8.0"
And you are good to go!
Write queries in Rust
Invalid queries are compile-time errors
let still_todo: Vec<Todo> =
todos
.filter(done.eq(false))
.limit(100)
.load(&connection)
.unwrap();
Not shown:
#[derive(Queryable)]
struct Todo { title: String, done: bool };
pub mod schema {
infer_schema!("dotenv:DATABASE_URL");
}
use schema::todos::dsl::{todos, done};
todos.select((id, title))
.filter(done.eq(false))
.limit(100)
todos.filter(done.eq(false)).limit(100)
SelectStatement<
(Integer, Text, Bool),
(todos::id, todos::title, todos::done),
todos::table,
NoDistinctClause,
WhereClause<Eq<todos::done, Bound<Bool, bool>>>,
NoOrderClause,
LimitClause<Bound<BigInt, i64>>
>
Diesel has i32::MAX
traits in its codebase last time I counted
Add methods to methods to query builder? Write a trait like FilterDsl
!
And implement generically:
impl<T, Predicate, ST> FilterDsl<Predicate> for T
Well, actually...
impl<T, Predicate, ST> FilterDsl<Predicate> for T where
Predicate: Expression<SqlType=Bool> + NonAggregate,
FilteredQuerySource<T, Predicate>: AsQuery<SqlType=ST>,
T: AsQuery<SqlType=ST> + NotFiltered
(Those constraints are all traits as well!)
Pro tip: Just search for what you think it should be called
There are
and ways to convert between them
table!
Macrotable! {
todos (id) {
id -> Integer,
title -> Text,
done -> Bool,
}
}
Never let your code and database schema diverge!
infer_schema!("dotenv:DATABASE_URL");
It basically generates the table!
macro calls for you.
diesel print-schema
prints the table!
macro calls infer_schema!
generates
(So you can e.g. put it in version control)
#[macro_use] extern crate diesel;
#[macro_use] extern crate diesel_codegen;
#[derive(Debug, Queryable)]
struct Todo {
id: i32,
title: String,
done: bool,
}
It Just Works™
Diesel Codegen provides custom derive implementations for
Queryable
,Identifiable
,Insertable
,AsChangeset
, andAssociations
.It also provides the macros
infer_schema!
,infer_table_from_schema!
, andembed_migrations!
.
#[derive(Identifiable, Queryable, Associations)]
#[has_many(posts)]
pub struct User { id: i32, name: String, }
#[derive(Identifiable, Queryable, Associations)]
#[belongs_to(User)]
pub struct Post { id: i32, user_id: i32, title: String, }
let user = try!(users::find(1).first(&connection));
let posts = Post::belonging_to(&user).load(&connection);
Read much more about this at docs.diesel.rs/diesel/associations/
Install it with
$ cargo install diesel
This makes it easy to
migrations/datetime-name/{up,down}.sql
Simple SQL files that change your database schema (e.g. CREATE TABLE
, DROP TABLE
)
diesel migration generate create_todos
diesel migration run
diesel migration revert
c
? Yes you can use Diesel in warp drivesMacros to implement traits for generic tuples of up to 52 elements
Enable query builder features depending on the used backend
RETURNING
clauseFor helper/converter functions
unix_epoch_decodes_correctly_with_timezone
queries_with_different_types_have_different_ids
Using diesel like a library
Examples in the API documentation are tests!
Secret sauce: include!("src/doctest_setup.rs");
Test roundtrips from Rust → DB → Rust
(With lots of macros, of course)
Invalid queries should not compile
So let's test that they return the expected errors!
The compiletest tool is also used by the Rust compiler and Clippy
Slides are available at git.io/diesel-adventure
License: CC BY-SA 4.0