diff --git a/src/models/users/trait.rs b/src/models/users/trait.rs new file mode 100644 index 0000000..6e16c32 --- /dev/null +++ b/src/models/users/trait.rs @@ -0,0 +1,192 @@ +/* + * advotracker - Hotline tackingtool for Advocats + * + * Copyright 2020 Ralf Zerres + * SPDX-License-Identifier: (0BSD or MIT) + */ + +// 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 ToSql for ConfirmState +where + DB: Backend, + i32: ToSql, +{ + fn to_sql(&self, out: &mut Output) -> 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); + >::to_sql(&int_value, out) + } +} + +/* +impl FromSql + for ConfirmState +{ + fn from_sql( + bytes: Option<&::RawValue>, + ) -> diesel::deserialize::Result { + >::from_sql() + .map(ConfirmState::Confirmed) + } +} + */ + +impl FromSql for ConfirmState +where + DB: Backend, + i32: FromSql, +{ + fn from_sql(bytes: Option<&DB::RawValue>) -> deserialize::Result { + match >::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 FromSql for ConfirmState +where + DB: Backend, + i32: FromSql { + //fn from_sql(bytes: Option::RawValue) -> diesel::deserialize::Result { + fn from_sql( + bytes: Option<&::RawValue>, + ) -> diesel::deserialize::Result { + //println!("Reading from sql: bytes:{:?}", bytes); + match bytes { + >::from_sql(bytes) + .map(ConfirmState::Confirmed) + } + /* + Some(bytes) => if bytes[0] != 0 { + Ok(ConfirmState::Confirmed) } + else { Ok(ConfirmState::Unconfirmed) } + } + //>::from_sql(bytes).map(ConfirmState::Confirmed) + //fn from_sql(bytes: Option) -> diesel::deserialize::Result { + // 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> + diesel::deserialize::FromSql for ConfirmState +{ + fn from_sql(bytes: Option<&[u8]>) -> diesel::deserialize::Result { + >::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(self, value: bool) -> Result + //where + // E: de::Error, + //{ + // match value { + // true => Ok(ConfirmState::Confirmed), + // false => Ok(ConfirmState::Unconfirmed), + // } + //} + + fn visit_i32(self, value: &'a i32) -> Result + where + E: de::Error, + { + match >::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(self, value: &str) -> Result + 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(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + deserializer.deserialize_any(ConfirmStateVisitor) + } +}