Skip to content

Instantly share code, notes, and snippets.

@rjloura
Last active October 3, 2019 19:23
Show Gist options
  • Save rjloura/704f71a519b0a849275b24ecc2a65838 to your computer and use it in GitHub Desktop.
Save rjloura/704f71a519b0a849275b24ecc2a65838 to your computer and use it in GitHub Desktop.
How to implement diesel's ToSql and FromSql for enums that have variants with fields
use diesel::deserialize::{self, FromSql};
use diesel::serialize::{self, IsNull, Output, ToSql};
use diesel::backend;
use std::io::Write;
use diesel::sql_types;
#[derive(Debug, Clone, Copy, PartialEq, FromSqlRow, AsExpression)]
#[sql_type="sql_types::Text"]
pub enum EvacuateObjectStatus {
Unprocessed,
Assigned,
Skipped(SkippedReason),
PostProcessing,
Complete,
}
#[derive(Debug, Clone, Copy, PartialEq, FromSqlRow, AsExpression)]
#[sql_type="sql_types::Text"]
pub enum PersistentReasons {
Foo,
}
#[derive(Debug, Clone, Copy, PartialEq, FromSqlRow, AsExpression)]
#[sql_type="sql_types::Text"]
pub enum RetryReasons {
Bar,
}
#[derive(Debug, Clone, Copy, PartialEq, FromSqlRow, AsExpression)]
#[sql_type="sql_types::Text"]
pub enum SkippedReason {
Retry(RetryReasons),
Persistent(PersistentReasons),
}
impl ToSql<sql_types::Text, Sqlite> for EvacuateObjectStatus {
fn to_sql<W: Write>(&self, out: &mut Output<W, Sqlite>
) -> serialize::Result
{
// TODO: append to buffer and call out.write_all() once
// let out = String::new();
match *self {
EvacuateObjectStatus::Unprocessed => out.write_all(b"unprocessed")?,
EvacuateObjectStatus::Assigned => out.write_all(b"assigned")?,
EvacuateObjectStatus::PostProcessing => {
out.write_all(b"post_processing")?
},
EvacuateObjectStatus::Complete => out.write_all(b"complete")?,
EvacuateObjectStatus::Skipped(s) => {
match s {
SkippedReason::Retry(r) => {
match r {
RetryReasons::Bar => {
out.write_all(b"skipped:retry:bar")?
}
}
},
SkippedReason::Persistent(p) => {
match p {
PersistentReasons::Foo => {
out.write_all(b"skipped:persistent:foo")?
},
}
}
}
}
}
Ok(IsNull::No)
}
}
impl FromSql<sql_types::Text, Sqlite> for EvacuateObjectStatus {
fn from_sql(
bytes: Option<backend::RawValue<Sqlite>>
) -> deserialize::Result<Self> {
let t = not_none!(bytes).read_text();
let st: String = t.to_string();
let splits: Vec<&str> = st.split(':').collect();
match splits[0] {
"unprocessed" => Ok(EvacuateObjectStatus::Unprocessed),
"assigned" => Ok(EvacuateObjectStatus::Assigned),
"post_processing" => Ok(EvacuateObjectStatus::PostProcessing),
"complete" => Ok(EvacuateObjectStatus::Complete),
"skipped" => {
match splits[1] {
"retry" => match splits[2] {
"bar" => {
Ok(EvacuateObjectStatus::Skipped(SkippedReason::Retry(RetryReasons::Bar)))
}
_ => Err("Unrecognized enum variant".into()),
},
"persistent" => match splits [2] {
"foo" => {
Ok(EvacuateObjectStatus::Skipped(SkippedReason::Persistent(PersistentReasons::Foo)))
}
_ => Err("Unrecognized enum variant".into()),
}
_ => Err("Unrecognized enum variant".into()),
}
}
_ => Err("Unrecognized enum variant".into()),
}
}
}
pub type ObjectId = String;
pub type AssignmentId = String;
#[derive(Insertable, Queryable, Identifiable, Debug, PartialEq)]
#[table_name = "evacuateobjects"]
pub struct EvacuateObjectDB {
pub id: String,
pub object: String,
pub assignment: AssignmentId,
pub status: EvacuateObjectStatus,
}
table! {
use diesel::sql_types::{Text};
evacuateobjects (id) {
id -> Text,
object -> Text,
assignment -> Text,
status -> Text,
}
}
@rjloura
Copy link
Author

rjloura commented Oct 3, 2019

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment