Files
advotracker_db/src/models/traits/trait.rs
2021-05-23 14:45:01 +02:00

193 lines
6.0 KiB
Rust

// SPDX-License-Identifier: (0BSD or MIT)
/*
* advotracker - Hotline tackingtool for Advocats
*
* Copyright 2020-2021 Ralf Zerres <ralf.zerres@networkx.de>
*/
// bring models into scope
use diesel::backend::Backend;
use diesel::deserialize;
use diesel::deserialize::FromSql;
use diesel::serialize;
use diesel::serialize::{Output, ToSql};
use diesel::sql_types::Integer;
//use serde::Serializer;
use serde;
//use super::models::ConfirmState;
//use crate::db::models::ConfirmState;
// trait: meaningful enum/types for email confirmation states
// in analogy: https://noyez.gitlab.io/post/2018-08-05-a-small-custom-bool-type-in-diesel/
//#[repr(i32)]
#[derive(AsExpression, Copy, Clone, Debug, PartialEq, FromSqlRow)]
#[sql_type = "Integer"]
pub enum ConfirmState {
Unconfirmed = 0,
Confirmed = 1,
Authorized = 2,
Blocked = 3,
}
impl<DB> ToSql<Integer, DB> for ConfirmState
where
DB: Backend,
i32: ToSql<Integer, DB>,
{
fn to_sql<W: std::io::Write>(&self, out: &mut Output<W, DB>) -> serialize::Result {
let int_value;
match &self {
ConfirmState::Unconfirmed => int_value = 0,
ConfirmState::Confirmed => int_value = 1,
ConfirmState::Authorized => int_value = 2,
ConfirmState::Blocked => int_value = 3,
}
println!("Writing to sql: i32:{:?}", &int_value);
<i32 as ToSql<Integer, DB>>::to_sql(&int_value, out)
}
}
/*
impl FromSql<Integer, Sqlite>
for ConfirmState
{
fn from_sql(
bytes: Option<&<diesel::sqlite::Sqlite as diesel::backend::Backend>::RawValue>,
) -> diesel::deserialize::Result<Self> {
<i32 as diesel::deserialize::FromSql<
diesel::sql_types::Integer, diesel::sqlite::Sqlite>>::from_sql()
.map(ConfirmState::Confirmed)
}
}
*/
impl<DB> FromSql<Integer, DB> for ConfirmState
where
DB: Backend<RawValue = [u8]>,
i32: FromSql<Integer, DB>,
{
fn from_sql(bytes: Option<&DB::RawValue>) -> deserialize::Result<Self> {
match <i32 as FromSql<Integer, DB>>::from_sql(bytes)? {
0 => Ok(ConfirmState::Unconfirmed),
1 => Ok(ConfirmState::Confirmed),
2 => Ok(ConfirmState::Authorized),
3 => Ok(ConfirmState::Blocked),
x => Err(format!("Unrecognized variant {}", x).into()),
}
}
}
/*
// WIP
impl<DB> FromSql<Integer, DB> for ConfirmState
where
DB: Backend,
i32: FromSql<Bool, DB> {
//fn from_sql(bytes: Option<diesel::backend::Backend>::RawValue<DB>) -> diesel::deserialize::Result<Self> {
fn from_sql(
bytes: Option<&<DB>::RawValue>,
) -> diesel::deserialize::Result<Self> {
//println!("Reading from sql: bytes:{:?}", bytes);
match bytes {
<i32 as diesel::deserialize::FromSql<Integer, DB>>::from_sql(bytes)
.map(ConfirmState::Confirmed)
}
/*
Some(bytes) => if bytes[0] != 0 {
Ok(ConfirmState::Confirmed) }
else { Ok(ConfirmState::Unconfirmed) }
}
//<i32 as diesel::deserialize::FromSql<Integer, DB>>::from_sql(bytes).map(ConfirmState::Confirmed)
//fn from_sql(bytes: Option<Bool>) -> diesel::deserialize::Result<Self> {
// println!("Reading from sql: bytes:{:?}", bytes);
// match bytes {
// Some(bytes) => if bytes[0] != 0 {
// Ok(ConfirmState::Confirmed) }
// else { Ok(ConfirmState::Unconfirmed) },
// None => Ok(ConfirmState::Unconfirmed),
// }
*/
}
}
*/
/*
impl<DB: diesel::backend::Backend<RawValue = [u8]>>
diesel::deserialize::FromSql<diesel::sql_types::Integer, DB> for ConfirmState
{
fn from_sql(bytes: Option<&[u8]>) -> diesel::deserialize::Result<Self> {
<i32 as diesel::deserialize::FromSql<diesel::sql_types::Integer, DB>>::from_sql(
bytes,
)
.map($name)
}
}
*/
struct ConfirmStateVisitor;
use serde::de::Deserialize;
use serde::de::{self, Visitor};
impl<'de> Visitor<'de> for ConfirmStateVisitor {
type Value = ConfirmState;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("an integer or string of ",
"\"Unconfirmed (0)\",",
"\"Confirmed (1)\"",
"\"Authorized (2)\"",
"\"Blocked (3)\".");
}
//fn visit_bool<E>(self, value: bool) -> Result<ConfirmState, E>
//where
// E: de::Error,
//{
// match value {
// true => Ok(ConfirmState::Confirmed),
// false => Ok(ConfirmState::Unconfirmed),
// }
//}
fn visit_i32<E>(self, value: &'a i32) -> Result<self::Value, E>
where
E: de::Error,
{
match <i32 as FromSql<Integer, DB>>::from_sql(bytes)? {
0 => Ok(ConfirmState::Unconfirmed),
1 => Ok(ConfirmState::Confirmed),
2 => Ok(ConfirmState::Authorized),
3 => Ok(ConfirmState::Blocked),
x => Err(format!("Unrecognized variant {}", x).into()),
0 => Ok(ConfirmState::Confirmed),
false => Ok(ConfirmState::Unconfirmed),
}
}
fn visit_str<E>(self, value: &str) -> Result<self::Value, E>
where
E: de::Error,
{
match value {
//"Confirmed" | "Authorized" => Ok(ConfirmState::Confirmed),
//"Unconfirmed" | "Unauthorized" => Ok(ConfirmState::Unconfirmed),
"Unconfirmed" => Ok(ConfirmState::Unconfirmed),
"Confirmed" => Ok(ConfirmState::Confirmed),
"Authorized" => Ok(ConfirmState::Authorized),
"Bolcked" => Ok(ConfirmState::Blocked),
_s => Err(E::custom(format!("Unknown string value: {}", _s))),
}
}
}
impl<'de> Deserialize<'de> for ConfirmState {
fn deserialize<D>(deserializer: D) -> Result<self::Value, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_any(ConfirmStateVisitor)
}
}