use std::fmt::Debug;
#[cfg(any(feature = "fulltext", feature = "vector"))]
use std::sync::Arc;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum SearchProviderType {
Fulltext,
Vector,
}
impl std::fmt::Display for SearchProviderType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
SearchProviderType::Fulltext => write!(f, "FULLTEXT"),
SearchProviderType::Vector => write!(f, "VECTOR"),
}
}
}
#[derive(Debug, Clone)]
pub struct IndexInfo {
pub space_id: u64,
pub tag_name: String,
pub field_name: String,
pub index_name: Option<String>,
pub status: String,
}
pub trait SearchProvider: Send + Sync + Debug + 'static {
fn name(&self) -> &str;
fn provider_type(&self) -> SearchProviderType;
fn description(&self) -> String {
format!("{} search provider: {}", self.provider_type(), self.name())
}
fn list_indexes(&self, space_id: u64) -> Vec<IndexInfo>;
fn drop_index(&self, space_id: u64, tag_name: &str, field_name: &str) -> Result<(), String>;
}
#[cfg(feature = "fulltext")]
pub struct FulltextProvider {
manager: Arc<linkrs_fulltext::manager::FulltextIndexManager>,
}
#[cfg(feature = "fulltext")]
impl FulltextProvider {
pub fn new(manager: Arc<linkrs_fulltext::manager::FulltextIndexManager>) -> Self {
Self { manager }
}
pub fn manager(&self) -> &Arc<linkrs_fulltext::manager::FulltextIndexManager> {
&self.manager
}
}
#[cfg(feature = "fulltext")]
impl Debug for FulltextProvider {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("FulltextProvider")
.field("index_count", &self.manager.list_indexes().len())
.finish()
}
}
#[cfg(feature = "fulltext")]
impl SearchProvider for FulltextProvider {
fn name(&self) -> &str {
"fulltext"
}
fn provider_type(&self) -> SearchProviderType {
SearchProviderType::Fulltext
}
fn description(&self) -> String {
format!(
"Fulltext search provider ({} indexes)",
self.manager.list_indexes().len()
)
}
fn list_indexes(&self, space_id: u64) -> Vec<IndexInfo> {
self.manager
.list_indexes()
.into_iter()
.filter(|m| space_id == 0 || m.space_id == space_id)
.map(|m| IndexInfo {
space_id: m.space_id,
tag_name: m.tag_name,
field_name: m.field_name,
index_name: Some(m.index_name.clone()),
status: format!("{:?}", m.status),
})
.collect()
}
fn drop_index(&self, space_id: u64, tag_name: &str, field_name: &str) -> Result<(), String> {
let manager = self.manager.clone();
let tag = tag_name.to_string();
let field = field_name.to_string();
tokio::task::block_in_place(|| {
tokio::runtime::Handle::current()
.block_on(async move { manager.drop_index(space_id, &tag, &field).await })
})
.map_err(|e| e.to_string())
}
}
#[cfg(feature = "vector")]
pub struct VectorProvider {
coordinator: Arc<linkrs_sync::vector_sync::VectorSyncCoordinator>,
}
#[cfg(feature = "vector")]
impl VectorProvider {
pub fn new(coordinator: Arc<linkrs_sync::vector_sync::VectorSyncCoordinator>) -> Self {
Self { coordinator }
}
pub fn coordinator(&self) -> &Arc<linkrs_sync::vector_sync::VectorSyncCoordinator> {
&self.coordinator
}
}
#[cfg(feature = "vector")]
impl Debug for VectorProvider {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("VectorProvider")
.field("index_count", &self.coordinator.list_indexes().len())
.finish()
}
}
#[cfg(feature = "vector")]
impl SearchProvider for VectorProvider {
fn name(&self) -> &str {
"vector"
}
fn provider_type(&self) -> SearchProviderType {
SearchProviderType::Vector
}
fn description(&self) -> String {
format!(
"Vector search provider ({} indexes)",
self.coordinator.list_indexes().len()
)
}
fn list_indexes(&self, space_id: u64) -> Vec<IndexInfo> {
self.coordinator
.list_indexes()
.into_iter()
.filter(|m| space_id == 0 || m.space_id == space_id)
.map(|m| IndexInfo {
space_id: m.space_id,
tag_name: m.tag_name,
field_name: m.field_name,
index_name: m.index_name.clone(),
status: "Active".to_string(),
})
.collect()
}
fn drop_index(&self, space_id: u64, tag_name: &str, field_name: &str) -> Result<(), String> {
let coordinator = self.coordinator.clone();
let tag = tag_name.to_string();
let field = field_name.to_string();
tokio::task::block_in_place(|| {
tokio::runtime::Handle::current().block_on(async move {
coordinator.drop_vector_index(space_id, &tag, &field).await
})
})
.map_err(|e| e.to_string())
}
}