use std::hash::{Hash, Hasher};
#[derive(Debug, Clone, Eq, serde::Serialize, serde::Deserialize)]
pub struct RefreshKey {
pub entity: String,
pub pk: i64,
#[serde(default)]
pub dedup_key: Option<String>,
}
impl RefreshKey {
pub fn pk(entity: impl Into<String>, pk: i64) -> Self {
Self {
entity: entity.into(),
pk,
dedup_key: None,
}
}
pub fn dedup(entity: impl Into<String>, key: impl Into<String>) -> Self {
Self {
entity: entity.into(),
pk: 0,
dedup_key: Some(key.into()),
}
}
pub fn is_dedup(&self) -> bool {
self.dedup_key.is_some()
}
}
impl PartialEq for RefreshKey {
fn eq(&self, other: &Self) -> bool {
self.entity == other.entity && self.pk == other.pk && self.dedup_key == other.dedup_key
}
}
impl Hash for RefreshKey {
fn hash<H: Hasher>(&self, state: &mut H) {
self.entity.hash(state);
self.pk.hash(state);
self.dedup_key.hash(state);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_refresh_key_equality() {
let key1 = RefreshKey::pk("user", 42);
let key2 = RefreshKey::pk("user", 42);
let key3 = RefreshKey::pk("user", 43);
assert_eq!(key1, key2);
assert_ne!(key1, key3);
}
#[test]
fn test_refresh_key_hashset_dedup() {
let mut set = std::collections::HashSet::new();
set.insert(RefreshKey::pk("user", 42));
set.insert(RefreshKey::pk("user", 42)); set.insert(RefreshKey::pk("post", 42));
assert_eq!(set.len(), 2);
}
#[test]
fn test_dedup_key_distinct_from_pk_key() {
let pk_key = RefreshKey::pk("contract", 42);
let dedup_key = RefreshKey::dedup("contract", "some-uuid");
assert_ne!(pk_key, dedup_key);
}
#[test]
fn test_dedup_key_hashset() {
let mut set = std::collections::HashSet::new();
set.insert(RefreshKey::dedup("contract", "uuid-1"));
set.insert(RefreshKey::dedup("contract", "uuid-1")); set.insert(RefreshKey::dedup("contract", "uuid-2"));
assert_eq!(set.len(), 2);
}
#[test]
fn test_is_dedup() {
assert!(!RefreshKey::pk("user", 1).is_dedup());
assert!(RefreshKey::dedup("contract", "uuid").is_dedup());
}
#[test]
fn test_serde_roundtrip_pk() {
let key = RefreshKey::pk("user", 99);
let json = serde_json::to_string(&key).unwrap();
let back: RefreshKey = serde_json::from_str(&json).unwrap();
assert_eq!(key, back);
}
#[test]
fn test_serde_roundtrip_dedup() {
let key = RefreshKey::dedup("contract", "some-uuid-val");
let json = serde_json::to_string(&key).unwrap();
let back: RefreshKey = serde_json::from_str(&json).unwrap();
assert_eq!(key, back);
}
#[test]
fn test_serde_backward_compat_no_dedup_key_field() {
let json = r#"{"entity":"user","pk":42}"#;
let key: RefreshKey = serde_json::from_str(json).unwrap();
assert_eq!(key.entity, "user");
assert_eq!(key.pk, 42);
assert!(key.dedup_key.is_none());
}
}