use std::{
fmt,
hash::{Hash, Hasher},
};
use crate::error::{FraiseQLError, Result};
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd)]
pub struct EntityKey {
pub entity_type: String,
pub entity_id: String,
}
impl EntityKey {
pub fn new(entity_type: &str, entity_id: &str) -> Result<Self> {
if entity_type.is_empty() {
return Err(FraiseQLError::Validation {
message: "entity_type cannot be empty".to_string(),
path: None,
});
}
if entity_type.contains(':') {
return Err(FraiseQLError::Validation {
message: format!(
"entity_type {entity_type:?} must not contain a colon character; \
colons are used as the cache-key separator"
),
path: None,
});
}
if entity_id.is_empty() {
return Err(FraiseQLError::Validation {
message: "entity_id cannot be empty".to_string(),
path: None,
});
}
Ok(Self {
entity_type: entity_type.to_string(),
entity_id: entity_id.to_string(),
})
}
#[must_use]
pub fn to_cache_key(&self) -> String {
format!("{}:{}", self.entity_type, self.entity_id)
}
pub fn from_cache_key(cache_key: &str) -> Result<Self> {
let parts: Vec<&str> = cache_key.splitn(2, ':').collect();
if parts.len() != 2 {
return Err(FraiseQLError::Validation {
message: format!("Invalid entity key format: {}. Expected 'Type:id'", cache_key),
path: None,
});
}
Self::new(parts[0], parts[1])
}
}
impl fmt::Display for EntityKey {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.to_cache_key())
}
}
impl Hash for EntityKey {
fn hash<H: Hasher>(&self, state: &mut H) {
self.entity_type.hash(state);
self.entity_id.hash(state);
}
}