https://github.com/killercup/presentation-diesel-adventure
https://github.com/killercup/presentation-diesel-adventure
diesel presentation rust slides sql
Last synced: 8 months ago
JSON representation
- Host: GitHub
- URL: https://github.com/killercup/presentation-diesel-adventure
- Owner: killercup
- Created: 2017-03-01T15:28:41.000Z (over 8 years ago)
- Default Branch: master
- Last Pushed: 2017-03-01T17:07:52.000Z (over 8 years ago)
- Last Synced: 2025-01-01T08:15:11.389Z (10 months ago)
- Topics: diesel, presentation, rust, slides, sql
- Language: CSS
- Homepage: https://killercup.github.io/presentation-diesel-adventure/index.html
- Size: 1.49 MB
- Stars: 3
- Watchers: 3
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: Readme.md
Awesome Lists containing this project
README
---
title: Diesel – Type-safe SQL
author: Pascal Hertleif
date: 2017-03-01
---## Pascal Hertleif
- Web stuff by day, Rust by night!
- Coorganizer of [Rust Cologne]
- {[twitter],[github]}.com/killercup[Rust Cologne]: http://rust.cologne/
[twitter]: https://twitter.com/killercup
[github]: https://github.com/killercup# First off
## [diesel.rs](http://diesel.rs)
{ style="padding: 5px" }
## Requires Rust 1.15
## Supported Backends
- Postgres
- SQLite
- MySQL# Getting started
---
```sh
$ cargo new --bin diesel-example
$ cd diesel-example
$ echo "DATABASE_URL=test.db" > .env
```Add to `Cargo.toml`:
```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!
# Query Builder
---
Write queries in Rust
Invalid queries are compile-time errors
## Basic Usage
```rust
let still_todo: Vec =
todos
.filter(done.eq(false))
.limit(100)
.load(&connection)
.unwrap();
```---
Not shown:
```rust
#[derive(Queryable)]
struct Todo { title: String, done: bool };pub mod schema {
infer_schema!("dotenv:DATABASE_URL");
}use schema::todos::dsl::{todos, done};
```---
- [Tell me more about this DSL](#dsl)
- [What kind of sorcery is `infer_schema!`?!](#infer_schema)# DSL {#dsl}
## Idea
1. Create zero-sized structs for table and its columns
2. Implement traits on these structs
3. ???
4. PROFIT!## Intuitive Methods
- `todos.select((id, title))`
- `.filter(done.eq(false))`
- `.limit(100)`## Each method returns a new, nested type.
`todos.filter(done.eq(false)).limit(100)`
```rust
SelectStatement<
(Integer, Text, Bool),
(todos::id, todos::title, todos::done),
todos::table,
NoDistinctClause,
WhereClause>>,
NoOrderClause,
LimitClause>
>
```---
- [That sounds like a lot of boilerplate…](#table)
- [Is this what makes it fast?](#perf)# Traits for Everything {#traits}
---
Diesel has `i32::MAX` traits in its codebase last time I counted
---
Add methods to methods to query builder? Write a trait like [`FilterDsl`](http://docs.diesel.rs/diesel/prelude/trait.FilterDsl.html)!
And implement generically:
```rust
impl FilterDsl for T
```---
Well, actually...
```rust
impl FilterDsl for T where
Predicate: Expression + NonAggregate,
FilteredQuerySource: AsQuery,
T: AsQuery + NotFiltered
```(Those constraints are all traits as well!)
## Using rustdoc to Create Mazes
**[docs.diesel.rs](http://docs.diesel.rs)**
Pro tip: Just search for what you think it should be called
---
- [Do I need to implement these traits myself?](#derive)
- [What's with the `SqlType`?](#mapping-types)# A Duality of Types {#mapping-types}
---
There are
- SQL types
- Rust typesand ways to convert between them
---
- Your schema contains SQL types
- Your application's structs contain Rust types---
- `FromSql`, `ToSql`
- Can map 1:1 like [`Float`](http://docs.diesel.rs/diesel/types/struct.Float.html)
- Or not, like [`Timestamp`](http://docs.diesel.rs/diesel/types/struct.Timestamp.html)---
- [Do I need to implement these conversions myself?](#derive)
# The `table!` Macro {#table}
---
```rust
table! {
todos (id) {
id -> Integer,
title -> Text,
done -> Bool,
}
}
```---
[Let's see what we end up with](file:///Users/pascal/Projekte/diesel-demo/target/doc/diesel_demo/schema/todos/index.html)
---
- [Those don't look like Rust types](#mapping-types)
- [Do I have to type that?](#infer_schema)# The Amazing Schema Inference {#infer_schema}
---
Never let your code and database schema diverge!
`infer_schema!("dotenv:DATABASE_URL");`
---
It basically generates the [`table!`](#table) macro calls for you.
---
- You need to have a database running on your dev machine
- The schema needs to be the same as in production---
`diesel print-schema`
prints the `table!` macro calls `infer_schema!` generates
(So you can e.g. put it in version control)
---
- [How do you manage migrations](#migrations)
- [Oh, what's that `diesel` tool?](#cli)# Derive ALL the Traits {#derive}
---
[Did I tell you about our Lord and Savior, Macros 1.1?](https://blog.rust-lang.org/2017/02/02/Rust-1.15.html)
---
```rust
#[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`][queryable], [`Identifiable`][identifiable],
> [`Insertable`][insertable], [`AsChangeset`][as-changeset], and [`Associations`][associations].
>
> It also provides the macros [`infer_schema!`][infer-schema],
> [`infer_table_from_schema!`][infer-table-from-schema], and
> [`embed_migrations!`][embed-migrations].
>
> – [diesel_codegen Readme](https://github.com/diesel-rs/diesel/tree/6a6f5835a40efd515dfc774d4b1d335cc87dd4da/diesel_codegen)[queryable]: http://docs.diesel.rs/diesel/query_source/trait.Queryable.html
[identifiable]: http://docs.diesel.rs/diesel/associations/trait.Identifiable.html
[insertable]: http://docs.diesel.rs/diesel/prelude/trait.Insertable.html
[as-changeset]: http://docs.diesel.rs/diesel/query_builder/trait.AsChangeset.html
[associations]: http://docs.diesel.rs/diesel/associations/index.html
[infer-schema]: http://docs.diesel.rs/diesel/macro.infer_schema!.html
[infer-table-from-schema]: http://docs.diesel.rs/diesel/macro.infer_table_from_schema!.html
[embed-migrations]: http://docs.diesel.rs/diesel/macro.embed_migrations!.html---
- [How do these traits work?](#traits)
- [Associations, you say?](#associations)# Associations {#associations}
---
```rust
#[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, }
```---
```rust
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/](http://docs.diesel.rs/diesel/associations/index.html)
# Diesel CLI Tool {#cli}
---
Install it with
```sh
$ cargo install diesel
```---
This makes it easy to
- Setup your database
- Manage your [migrations](#migrations)
- Print your schema---
- [Tell me more about migrations](#migrations)
- [What was that about schema printing?](#infer_schema)# Migrations {#migrations}
---
`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`---
- [Oh, what's that `diesel` tool?](#cli)
# Performance {#perf}
---
- Almost all queries can be represented by unique types
- Each of these types returns a query (that uses bind params)
- Let's cache these queries as Prepared Statements!---
- Is it faster than `c`? [Yes you can use Diesel in warp drives](https://hackernoon.com/comparing-diesel-and-rust-postgres-97fd8c656fdd#.kdof0mold)
# Type System Shenanigans
---
Macros to implement traits for generic tuples of up to 52 elements
---
Enable query builder features depending on the used backend
- Basically every type and trait is generic over the backend
- E.g.: Only Postgres implements `RETURNING` clause# Testing Diesel
## Unit tests
For helper/converter functions
- `unix_epoch_decodes_correctly_with_timezone`
- `queries_with_different_types_have_different_ids`## Integration tests
Using diesel like a library
## Doc test
Examples in the API documentation are tests!
---
Secret sauce: `include!("src/doctest_setup.rs");`
## Quickcheck
Test roundtrips from Rust → DB → Rust
(With lots of macros, of course)
[Source](https://github.com/diesel-rs/diesel/blob/6a6f5835a40efd515dfc774d4b1d335cc87dd4da/diesel_tests/tests/types_roundtrip.rs)
## Compile-fail Tests
Invalid queries should not compile
So let's test that they return the expected errors!
---
The [compiletest](https://github.com/laumann/compiletest-rs) tool is also used by the Rust compiler and Clippy
# Thank you for listening!
- Try diesel tonight!
- Read the docs at [diesel.rs](http://diesel.rs/)
- Get help at [gitter.im/diesel-rs/diesel](https://gitter.im/diesel-rs/diesel)# Questions?
---
Slides are available at [git.io/diesel-adventure](https://git.io/diesel-adventure)
License: [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/)