use crate::error::{MemoryError, Result};
use futures::future::BoxFuture;
use serde::{Deserialize, Serialize};
use serde_json::Value;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct StoreItem {
pub namespace: Vec<String>,
pub key: String,
pub value: Value,
pub created_at: u64,
pub updated_at: u64,
pub score: Option<f32>,
}
impl StoreItem {
pub fn new(namespace: Vec<String>, key: String, value: Value) -> Self {
let now = crate::utils::time::now_secs();
Self {
namespace,
key,
value,
created_at: now,
updated_at: now,
score: None,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum SearchMode {
Keyword,
Semantic,
Hybrid,
}
#[derive(Debug, Clone, Copy)]
pub struct SearchQuery<'a> {
pub text: &'a str,
pub limit: usize,
pub mode: SearchMode,
}
impl<'a> SearchQuery<'a> {
pub fn keyword(text: &'a str, limit: usize) -> Self {
Self {
text,
limit,
mode: SearchMode::Keyword,
}
}
pub fn semantic(text: &'a str, limit: usize) -> Self {
Self {
text,
limit,
mode: SearchMode::Semantic,
}
}
pub fn hybrid(text: &'a str, limit: usize) -> Self {
Self {
text,
limit,
mode: SearchMode::Hybrid,
}
}
}
pub trait Store: Send + Sync {
fn put<'a>(
&'a self,
namespace: &'a [&'a str],
key: &'a str,
value: Value,
) -> BoxFuture<'a, Result<()>>;
fn get<'a>(
&'a self,
namespace: &'a [&'a str],
key: &'a str,
) -> BoxFuture<'a, Result<Option<StoreItem>>>;
fn search<'a>(
&'a self,
namespace: &'a [&'a str],
query: &'a str,
limit: usize,
) -> BoxFuture<'a, Result<Vec<StoreItem>>>;
fn search_with<'a>(
&'a self,
namespace: &'a [&'a str],
query: SearchQuery<'a>,
) -> BoxFuture<'a, Result<Vec<StoreItem>>> {
Box::pin(async move {
match query.mode {
SearchMode::Keyword => self.search(namespace, query.text, query.limit).await,
SearchMode::Semantic => Err(MemoryError::Unsupported(
"semantic search is not supported by this Store".to_string(),
)
.into()),
SearchMode::Hybrid => Err(MemoryError::Unsupported(
"hybrid search is not supported by this Store".to_string(),
)
.into()),
}
})
}
fn delete<'a>(&'a self, namespace: &'a [&'a str], key: &'a str) -> BoxFuture<'a, Result<bool>>;
fn list_namespaces<'a>(
&'a self,
prefix: Option<&'a [&'a str]>,
) -> BoxFuture<'a, Result<Vec<Vec<String>>>>;
fn list<'a>(&'a self, namespace: &'a [&'a str]) -> BoxFuture<'a, Result<Vec<StoreItem>>>;
}