#![allow(clippy::pedantic)]
#![allow(clippy::nursery)]
#![allow(clippy::needless_pass_by_value)]
#![allow(clippy::missing_errors_doc)]
#![allow(clippy::missing_panics_doc)]
#![allow(clippy::must_use_candidate)]
#![allow(clippy::uninlined_format_args)]
#![allow(clippy::similar_names)]
#![allow(clippy::module_name_repetitions)]
#![allow(clippy::doc_markdown)]
#![allow(clippy::wildcard_imports)]
#![allow(clippy::redundant_closure_for_method_calls)]
uniffi::setup_scaffolding!();
mod agent;
mod collection;
mod collection_sparse;
mod graph;
mod types;
pub use agent::{SemanticResult, VelesSemanticMemory};
pub use collection::VelesCollection;
pub use graph::{MobileGraphEdge, MobileGraphNode, MobileGraphStore, TraversalResult};
pub use types::{
DistanceMetric, FusionStrategy, IndividualSearchRequest, MobileCollectionStats,
MobileIndexInfo, PqTrainConfig, SearchResult, StorageMode, VelesError, VelesPoint,
VelesSparseVector,
};
use std::sync::Arc;
use velesdb_core::Database as CoreDatabase;
#[cfg(test)]
use velesdb_core::DistanceMetric as CoreDistanceMetric;
#[cfg(test)]
use velesdb_core::FusionStrategy as CoreFusionStrategy;
#[derive(uniffi::Object)]
pub struct VelesDatabase {
inner: CoreDatabase,
}
#[uniffi::export]
impl VelesDatabase {
#[uniffi::constructor]
pub fn open(path: String) -> Result<Arc<Self>, VelesError> {
let db = CoreDatabase::open(&path)?;
Ok(Arc::new(Self { inner: db }))
}
pub fn create_collection(
&self,
name: String,
dimension: u32,
metric: DistanceMetric,
) -> Result<(), VelesError> {
self.inner.create_collection(
&name,
usize::try_from(dimension).unwrap_or(usize::MAX),
metric.into(),
)?;
Ok(())
}
pub fn create_collection_with_storage(
&self,
name: String,
dimension: u32,
metric: DistanceMetric,
storage_mode: StorageMode,
) -> Result<(), VelesError> {
self.inner.create_vector_collection_with_options(
&name,
usize::try_from(dimension).unwrap_or(usize::MAX),
metric.into(),
storage_mode.into(),
)?;
Ok(())
}
pub fn create_metadata_collection(&self, name: String) -> Result<(), VelesError> {
self.inner.create_metadata_collection(&name)?;
Ok(())
}
pub fn get_collection(&self, name: String) -> Result<Option<Arc<VelesCollection>>, VelesError> {
if let Some(coll) = self.inner.get_vector_collection(&name) {
return Ok(Some(Arc::new(VelesCollection { inner: coll })));
}
let path = self.inner.data_dir().join(&name);
if path.join("config.json").exists() {
match velesdb_core::VectorCollection::open(path) {
Ok(coll) => return Ok(Some(Arc::new(VelesCollection { inner: coll }))),
Err(e) => {
tracing::warn!(
collection = %name,
error = %e,
"VectorCollection::open failed for existing config; collection skipped"
);
}
}
}
Ok(None)
}
pub fn list_collections(&self) -> Vec<String> {
self.inner.list_collections()
}
pub fn delete_collection(&self, name: String) -> Result<(), VelesError> {
self.inner.delete_collection(&name)?;
Ok(())
}
pub fn train_pq(
&self,
collection_name: String,
config: PqTrainConfig,
) -> Result<String, VelesError> {
use std::collections::HashMap;
use velesdb_core::velesql::{Query, TrainStatement, WithValue};
let mut params = HashMap::new();
params.insert("m".to_string(), WithValue::Integer(i64::from(config.m)));
params.insert("k".to_string(), WithValue::Integer(i64::from(config.k)));
if config.opq {
params.insert("type".to_string(), WithValue::Identifier("opq".to_string()));
}
let query = Query::new_train(TrainStatement {
collection: collection_name,
params,
});
let empty_params = HashMap::new();
self.inner
.execute_query(&query, &empty_params)
.map_err(|e| VelesError::Database {
message: format!("PQ training failed: {e}"),
})?;
Ok("PQ training complete".to_string())
}
}
#[cfg(test)]
#[path = "lib_tests.rs"]
mod tests;