use serde::{Deserialize, Deserializer, Serialize};
use serde_json::Value;
pub mod truncate;
pub use super::audit_logs::AuditLogChange;
pub use super::misc::Time;
pub trait Diff<T> {
fn changes(&self, other: &T) -> bool;
}
impl<T: PartialEq> Diff<T> for T {
fn changes(&self, other: &T) -> bool {
self != other
}
}
impl<T: PartialEq> Diff<T> for Option<T> {
fn changes(&self, other: &T) -> bool {
self.as_ref().is_some_and(|s| s.changes(other))
}
}
pub fn deserialize_default_true<'de, D>(deserializer: D) -> std::result::Result<bool, D::Error>
where
D: serde::Deserializer<'de>,
{
Option::<bool>::deserialize(deserializer).map(|b| b.unwrap_or(true))
}
pub fn deserialize_sorted<'de, D, T>(deserializer: D) -> Result<Vec<T>, D::Error>
where
D: serde::Deserializer<'de>,
T: Deserialize<'de> + Ord,
{
Vec::<T>::deserialize(deserializer).map(|mut v| {
v.sort();
v
})
}
pub fn deserialize_sorted_option<'de, D, T>(deserializer: D) -> Result<Option<Vec<T>>, D::Error>
where
D: serde::Deserializer<'de>,
T: Deserialize<'de> + Ord,
{
Option::<Vec<T>>::deserialize(deserializer).map(|opt| {
opt.map(|mut vec| {
vec.sort();
vec
})
})
}
pub fn some_option<'de, T, D>(deserializer: D) -> Result<Option<Option<T>>, D::Error>
where
T: Deserialize<'de>,
D: Deserializer<'de>,
{
Option::<T>::deserialize(deserializer).map(Some)
}
#[derive(Default)]
pub struct Changes {
changes: Vec<AuditLogChange>,
}
impl Changes {
pub fn new() -> Self {
Self {
changes: Vec::new(),
}
}
pub fn add<T: Serialize + PartialEq>(mut self, key: impl Into<String>, new: &T) -> Self {
let val = serde_json::to_value(new).unwrap_or(Value::Null);
if val != Value::Null {
self.changes.push(AuditLogChange {
key: key.into(),
old: Value::Null,
new: val,
});
}
self
}
pub fn change<T: Serialize + PartialEq>(
mut self,
key: impl Into<String>,
old: &T,
new: &T,
) -> Self {
if old != new {
self.changes.push(AuditLogChange {
key: key.into(),
old: serde_json::to_value(old).unwrap_or(Value::Null),
new: serde_json::to_value(new).unwrap_or(Value::Null),
});
}
self
}
pub fn build(self) -> Vec<AuditLogChange> {
self.changes
}
}