use super::cache_key::{CacheHashKey, CacheKey, ValueType};
use std::time::Duration;
pub trait CacheKeyBuilder {
fn get_prefix(&self) -> Option<&str> {
None
}
fn get_tenant(&self) -> Option<&str> {
None
}
fn set_tenant_id(&mut self, _tenant_id: u64) {}
fn get_modular(&self) -> Option<&str> {
None
}
fn get_table(&self) -> &str;
fn get_field(&self) -> Option<&str> {
None
}
fn get_value_type(&self) -> ValueType {
ValueType::Obj
}
fn get_expire(&self) -> Option<Duration> {
None
}
fn get_pattern(&self) -> String {
format!("*:{}:*", self.get_table())
}
fn key(&self, uniques: &[&dyn ToString]) -> CacheKey {
let key = self.build_key(uniques);
assert!(!key.is_empty(), "key 不能为空");
CacheKey::new(key, self.get_expire())
}
fn hash_field_key(&self, field: &dyn ToString, uniques: &[&dyn ToString]) -> CacheHashKey {
let key = self.build_key(uniques);
assert!(!key.is_empty(), "key 不能为空");
CacheHashKey::new(key, Some(field.to_string()), self.get_expire())
}
fn hash_key(&self, uniques: &[&dyn ToString]) -> CacheHashKey {
let key = self.build_key(uniques);
assert!(!key.is_empty(), "key 不能为空");
CacheHashKey::new(key, None, self.get_expire())
}
fn build_key(&self, uniques: &[&dyn ToString]) -> String {
let mut parts = Vec::new();
if let Some(prefix) = self.get_prefix() {
if !prefix.is_empty() {
parts.push(prefix.to_string());
}
}
if let Some(tenant) = self.get_tenant() {
if !tenant.is_empty() {
parts.push(tenant.to_string());
}
}
if let Some(modular) = self.get_modular() {
if !modular.is_empty() {
parts.push(modular.to_string());
}
}
let table = self.get_table();
assert!(!table.is_empty(), "缓存业务类型不能为空");
parts.push(table.to_string());
if let Some(field) = self.get_field() {
if !field.is_empty() {
parts.push(field.to_string());
}
}
parts.push(self.get_value_type().as_str().to_string());
for unique in uniques {
let value = unique.to_string();
if !value.is_empty() {
parts.push(value);
}
}
parts.join(":")
}
}
#[derive(Debug, Clone)]
pub struct SimpleCacheKeyBuilder {
pub prefix: Option<String>,
pub tenant: Option<String>,
pub modular: Option<String>,
pub table: String,
pub field: Option<String>,
pub value_type: ValueType,
pub expire: Option<Duration>,
}
impl SimpleCacheKeyBuilder {
pub fn new(table: impl Into<String>) -> Self {
Self {
prefix: None,
tenant: None,
modular: None,
table: table.into(),
field: None,
value_type: ValueType::Obj,
expire: None,
}
}
pub fn with_prefix(mut self, prefix: impl Into<String>) -> Self {
self.prefix = Some(prefix.into());
self
}
pub fn with_tenant(mut self, tenant: impl Into<String>) -> Self {
self.tenant = Some(tenant.into());
self
}
pub fn with_modular(mut self, modular: impl Into<String>) -> Self {
self.modular = Some(modular.into());
self
}
pub fn with_field(mut self, field: impl Into<String>) -> Self {
self.field = Some(field.into());
self
}
pub fn with_value_type(mut self, value_type: ValueType) -> Self {
self.value_type = value_type;
self
}
pub fn with_expire(mut self, expire: Duration) -> Self {
self.expire = Some(expire);
self
}
}
impl CacheKeyBuilder for SimpleCacheKeyBuilder {
fn get_prefix(&self) -> Option<&str> {
self.prefix.as_deref()
}
fn get_tenant(&self) -> Option<&str> {
self.tenant.as_deref()
}
fn get_modular(&self) -> Option<&str> {
self.modular.as_deref()
}
fn get_table(&self) -> &str {
&self.table
}
fn get_field(&self) -> Option<&str> {
self.field.as_deref()
}
fn get_value_type(&self) -> ValueType {
self.value_type
}
fn get_expire(&self) -> Option<Duration> {
self.expire
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_simple_cache_key_builder() {
let builder = SimpleCacheKeyBuilder::new("user")
.with_prefix("dev")
.with_tenant("0000")
.with_modular("authority")
.with_field("id")
.with_value_type(ValueType::Obj);
let key = builder.key(&[&1u64]);
assert_eq!(key.key, "dev:0000:authority:user:id:obj:1");
}
#[test]
fn test_cache_key_without_optional_fields() {
let builder = SimpleCacheKeyBuilder::new("tenant");
let key = builder.key(&[&1u64]);
assert_eq!(key.key, "tenant:obj:1");
}
#[test]
fn test_hash_key() {
let builder = SimpleCacheKeyBuilder::new("user")
.with_tenant("0000")
.with_modular("authority");
let hash_key = builder.hash_field_key(&"name", &[&1u64]);
assert_eq!(hash_key.key, "0000:authority:user:obj:1");
assert_eq!(hash_key.field, Some("name".to_string()));
}
#[test]
fn test_multiple_uniques() {
let builder = SimpleCacheKeyBuilder::new("user.activity")
.with_tenant("0000")
.with_modular("authority")
.with_field("id.id")
.with_value_type(ValueType::Number);
let key = builder.key(&[&1u64, &3u64]);
assert_eq!(key.key, "0000:authority:user.activity:id.id:number:1:3");
}
}