use std::fmt;
const DEFAULT_NAMESPACE: &str = "rig";
const DEFAULT_INDEX: &str = "rig:index";
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct RedisConfig {
url: String,
namespace: String,
index: String,
}
impl RedisConfig {
pub fn new(url: impl Into<String>) -> Self {
Self {
url: url.into(),
namespace: DEFAULT_NAMESPACE.to_string(),
index: DEFAULT_INDEX.to_string(),
}
}
pub fn url(&self) -> &str {
&self.url
}
pub fn namespace(&self) -> &str {
&self.namespace
}
pub fn index(&self) -> &str {
&self.index
}
pub fn with_namespace(mut self, namespace: impl Into<String>) -> Self {
self.namespace = namespace.into();
self
}
pub fn with_index(mut self, index: impl Into<String>) -> Self {
self.index = index.into();
self
}
}
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct RedisKey(String);
impl RedisKey {
pub fn new(namespace: impl AsRef<str>, key: impl AsRef<str>) -> Self {
let namespace = namespace.as_ref().trim_matches(':');
let key = key.as_ref().trim_matches(':');
if namespace.is_empty() {
Self(key.to_string())
} else if key.is_empty() {
Self(namespace.to_string())
} else {
Self(format!("{namespace}:{key}"))
}
}
pub fn as_str(&self) -> &str {
&self.0
}
pub fn into_string(self) -> String {
self.0
}
}
impl fmt::Display for RedisKey {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(formatter)
}
}
impl AsRef<str> for RedisKey {
fn as_ref(&self) -> &str {
self.as_str()
}
}
impl From<RedisKey> for String {
fn from(key: RedisKey) -> Self {
key.into_string()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn config_uses_defaults() {
let config = RedisConfig::new("redis://localhost:6379");
assert_eq!(config.url(), "redis://localhost:6379");
assert_eq!(config.namespace(), "rig");
assert_eq!(config.index(), "rig:index");
}
#[test]
fn config_can_be_customized() {
let config = RedisConfig::new("redis://localhost:6379")
.with_namespace("agents")
.with_index("agent-memory");
assert_eq!(config.namespace(), "agents");
assert_eq!(config.index(), "agent-memory");
}
#[test]
fn key_joins_namespace_and_key() {
let key = RedisKey::new("rig", "documents:1");
assert_eq!(key.as_str(), "rig:documents:1");
assert_eq!(key.to_string(), "rig:documents:1");
}
#[test]
fn key_trims_extra_separators() {
let key = RedisKey::new("rig:", ":documents:1:");
assert_eq!(key.as_str(), "rig:documents:1");
}
#[test]
fn key_allows_empty_namespace() {
let key = RedisKey::new("", "documents:1");
assert_eq!(key.as_str(), "documents:1");
}
}