Expand description
§Diesel-enums
diesel-enums can be used to create mappings between Rust enums and database tables with fixed values, as well as custom postgres enums.
It creates a seamless interface with the diesel API, and generates the logic to enforce the correctness of the mapping.
Refer to the documentation for DbEnum and PgEnum to learn more about usage.
§Full Example With Sqlite
use diesel_enums::db_enum;
use std::{error::Error, time::Duration};
use deadpool_diesel::{
Runtime,
sqlite::{Manager, Object, Pool},
};
use diesel::{SqliteConnection, connection::SimpleConnection, prelude::*};
use diesel_enums::AsyncTestRunner;
use tokio::sync::OnceCell;
// Normally these would be in the `schema.rs` file...
diesel::table! {
statuses (id) {
id -> Integer,
name -> Text
}
}
diesel::table! {
users (id) {
id -> Integer,
name -> Text,
status_id -> Integer,
}
}
diesel::joinable!(users -> statuses (status_id));
diesel::allow_tables_to_appear_in_same_query!(statuses, users,);
// We set up a custom runner to use in the generated tests
pub struct SqliteRunner;
impl AsyncTestRunner<SqliteConnection> for SqliteRunner {
async fn run_check<F>(f: F) -> diesel_enums::DbEnumCheck
where
F: FnOnce(&mut SqliteConnection) -> diesel_enums::DbEnumCheck + Send + 'static,
{
get_or_init_pool()
.await
.interact(f)
.await
.expect("Failed to interact with the database")
}
}
#[db_enum]
// Using our custom test runner
#[db(async_runner = SqliteRunner, table = statuses)]
pub enum Status {
Offline,
Active,
Busy,
}
#[derive(
Clone, Debug, PartialEq, Eq, Queryable, Selectable, Insertable, Associations, Identifiable,
)]
#[diesel(belongs_to(Status))]
pub struct User {
#[diesel(skip_insertion)]
pub id: i32,
pub name: String,
pub status_id: Status,
}
static SQLITE_POOL: OnceCell<Pool> = OnceCell::const_new();
pub async fn get_or_init_pool() -> Object {
SQLITE_POOL
.get_or_init(create_sqlite_pool)
.await
.get()
.await
.expect("Could not get a connection")
}
pub async fn create_sqlite_pool() -> deadpool_diesel::sqlite::Pool {
let db_url = "file:example_db?mode=memory&cache=shared";
let manager = Manager::new(db_url, Runtime::Tokio1);
let pool = Pool::builder(manager)
.max_size(1)
.runtime(Runtime::Tokio1)
.wait_timeout(Some(Duration::from_secs(5)))
.create_timeout(Some(Duration::from_secs(5)))
.build()
.expect("could not build the connection pool");
pool.get()
.await
.expect("Failed to get connection")
.interact(|conn| {
conn.batch_execute(
r"
PRAGMA foreign_keys = ON;
CREATE TABLE statuses (
id INTEGER NOT NULL PRIMARY KEY autoincrement,
name TEXT NOT NULL
);
INSERT INTO statuses (name) VALUES
('offline'), ('active'), ('busy');
CREATE TABLE users (
id INTEGER NOT NULL PRIMARY KEY autoincrement,
name TEXT NOT NULL,
status_id INTEGER NOT NULL,
FOREIGN KEY (status_id) REFERENCES statuses (id)
);
",
)
})
.await
.expect("Failed interaction")
.expect("Failed initial query");
pool
}
pub async fn run_sqlite_query<T: Send + 'static>(
callback: impl FnOnce(&mut SqliteConnection) -> QueryResult<T> + Send + 'static,
) -> Result<T, Box<dyn Error>> {
Ok(get_or_init_pool()
.await
.interact(callback)
.await??)
}
#[tokio::test]
async fn example() {
let tom = User {
id: 1,
name: "Tom Bombadil".to_string(),
status_id: Status::Active,
};
let clone = tom.clone();
let inserted = run_sqlite_query(move |conn| {
diesel::insert_into(users::table)
.values(&clone)
.returning(User::as_select())
.get_result(conn)
})
.await
.expect("Failed insertion");
assert_eq!(inserted, tom);
let filtered_query = run_sqlite_query(|conn| {
users::table
.select(User::as_select())
// We can filter with the enum directly!
.filter(users::status_id.eq(Status::Active))
.first(conn)
})
.await
.expect("Failed filtered query");
assert_eq!(filtered_query, tom);
let all_active = run_sqlite_query(|conn| {
// Join queries become very concise
User::belonging_to(&Status::Active)
.select(User::as_select())
.get_results(conn)
})
.await
.expect("Failed query");
assert_eq!(all_active.first().unwrap(), &tom);
}
#[db_enum]
// Wrong mapping! The generated test would catch this
#[db(skip_test, table = statuses)]
pub enum WrongStatus {
Offline,
Active,
}
#[tokio::test]
async fn wrong_status() {
assert!(
SqliteRunner::check_enum::<WrongStatus>()
.await
.is_err()
)
}§Features
postgres— Enables support for custom postgres enumssqlite-async-runner— Exports the test runner for sqlitedefault-sqlite-runner— Indicates that the sqlite runner should be used by defaultpg-async-runner— Exports the test runner for postgresdefault-pg-runner— Indicates that the postgres runner should be used by defaultcrate-runner— Indicates that the default runner is located atcrate::db_test_runner::DbTestRunner.async-crate-runner— Indicates that the default runner is located atcrate::db_test_runner::DbTestRunner, and that it is an async runner.
Structs§
- Async
PgRunner pg-async-runner - The default (async) test runner for Postgres. It uses
deadpool-dieselto create a connection pool that can be shared among tests, so that they can be executed faster. - Async
Sqlite Runner sqlite-async-runner - The default (async) test runner for SQLite. It uses
deadpool-dieselto create a connection pool, and sets the journal mode to WAL to allow for concurrent reads and faster tests. - DbEnum
Error - An error that is produced when a rust enum does not match a database enum or table.
- IdMismatch
- Represents a mismatch between a Rust variant and a database variant.
- Unknown
IdError - An error that can occur when trying to create an instance of a
DbEnumfrom a number. - Unknown
Variant Error - An error that can occur when trying to create an instance of a
DbEnumorPgEnumfrom a string.
Traits§
- Async
Test Runner - Trait for running database checks for mapped enums, asynchronously.
- DbEnum
- Maps a Rust enum to a database table with fixed values.
- PgEnum
postgres - Maps a Rust enum to a custom enum in postgres.
- Sync
Test Runner - Trait for running database checks for mapped enums, synchronously.
Type Aliases§
- DbEnum
Check - The outcome of an operation that checks if a Rust enum and a database source are mapped correctly.
Attribute Macros§
- db_enum
- Shortcut for deriving
DbEnumon the target enum, along with the other required derives for it. - pg_enum
- Shortcut for deriving
PgEnumon the target enum, along with the other required derives for it.