You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

84 lines
1.6 KiB

//! Universally unique identifier
//!
//! Wrapper around `Uuid` to store it as text in sql table.
use std::cmp::{Eq, PartialEq};
use std::fmt;
use std::hash::{Hash, Hasher};
use rusqlite::types::{FromSql, FromSqlError, FromSqlResult, ToSql, ToSqlOutput, ValueRef};
use serde::{Deserialize, Serialize};
use uuid::Uuid;
/// Universally unique identifier
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
pub struct Id(Uuid);
impl Id {
/// Return a newly generated `Id`
pub fn new() -> Self {
Self(Uuid::new_v4())
}
}
impl fmt::Display for Id {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl Hash for Id {
fn hash<H: Hasher>(&self, state: &mut H) {
self.0.hash(state);
}
}
impl Into<Uuid> for Id {
fn into(self) -> Uuid {
self.0
}
}
impl From<Uuid> for Id {
fn from(u: Uuid) -> Self {
Self(u)
}
}
impl Eq for Id {}
impl PartialEq for Id {
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}
impl FromSql for Id {
fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
let s = match value.as_str() {
Ok(s) => s,
Err(e) => {
log::error!("{}({}) :: {} :: {}", file!(), line!(), "value.as_str()", e);
return Err(e);
}
};
match Uuid::parse_str(s) {
Ok(id) => return Ok(Self(id)),
Err(e) => {
log::error!("{}({}) :: Uuid::parse_str(\"{}\") :: {}", file!(), line!(), s, e);
Err(FromSqlError::Other(Box::from(e)))
}
}
}
}
impl ToSql for Id {
fn to_sql(&self) -> rusqlite::Result<ToSqlOutput<'_>> {
let h = self.0.to_hyphenated();
let mut buf = Uuid::encode_buffer();
let s = h.encode_lower(&mut buf);
Ok(ToSqlOutput::from(s.to_string()))
}
}