4 releases
0.1.3 | Jul 1, 2019 |
---|---|
0.1.2 | Jul 1, 2019 |
0.1.1 | Jul 1, 2019 |
0.1.0 | Jul 1, 2019 |
#17 in #table-column
15KB
270 lines
diesel-sort-struct-fields
Macro to sort struct fields and table!
columns to avoid subtle bugs with Diesel.
See the crate documentation for a usage examples and more info.
License: MIT
lib.rs
:
Macro to sort struct fields and table!
columns to avoid subtle bugs.
The way Diesel maps a response from a query into a struct is by treating a row as a tuple and assigning the fields in the order of the fields in code. Something like (not real code):
struct User {
id: i32,
name: String,
}
fn user_from_row(row: (i32, String)) -> User {
User {
id: row.0,
name: row.1,
}
}
This works well, but it will break in subtle ways if the order of id
and name
aren't the
same in table!
and struct User { ... }
. So this code doesn't compile:
#[macro_use]
extern crate diesel;
use diesel::prelude::*;
table! {
users {
// order here doesn't match order in the struct
name -> VarChar,
id -> Integer,
}
}
#[derive(Queryable)]
struct User {
id: i32,
name: String,
}
fn main() {
let db = connect_to_db();
users::table
.select(users::all_columns)
.load::<User>(&db)
.unwrap();
}
fn connect_to_db() -> PgConnection {
PgConnection::establish("postgres://localhost/diesel-sort-struct-fields").unwrap()
}
Luckily you get a type error, so Diesel is clearly telling you that something is wrong. However
if the types of id
and name
were the same you wouldn't get a type error. You would just
have subtle bugs that could take hours to track down (it did for me).
This crate prevents that with a simple procedural macro that sorts the fields of your model
struct and table!
such that you can define them in any order, but once the code gets to the
compiler the order will always be the same.
Example:
#[macro_use]
extern crate diesel;
use diesel_sort_struct_fields::{sort_columns, sort_fields};
use diesel::prelude::*;
#[sort_columns]
table! {
users {
name -> VarChar,
id -> Integer,
}
}
#[sort_fields]
#[derive(Queryable)]
struct User {
id: i32,
name: String,
}
fn main() {
let db = connect_to_db();
let users = users::table
.select(users::all_columns)
.load::<User>(&db)
.unwrap();
assert_eq!(0, users.len());
}
fn connect_to_db() -> PgConnection {
PgConnection::establish("postgres://localhost/diesel-sort-struct-fields").unwrap()
}
Dependencies
~2MB
~46K SLoC