pub(crate) mod legacy_bincode;
pub mod redb;
pub mod schema;
pub use self::redb::RedbStorage;
pub use schema::{DatabaseMetadata, SCHEMA_VERSION};
#[cfg(feature = "sync")]
use std::collections::BTreeMap;
use std::path::Path;
use crate::activity::Activity;
use crate::collective::Collective;
use crate::config::{Config, DecayConfig};
use crate::error::Result;
use crate::experience::{Experience, ExperienceUpdate};
use crate::insight::DerivedInsight;
use crate::relation::{ExperienceRelation, RelationType};
#[cfg(feature = "sync")]
use crate::types::InstanceId;
use crate::types::{CollectiveId, ExperienceId, InsightId, RelationId, Timestamp};
pub trait StorageEngine: Send + Sync {
fn metadata(&self) -> &DatabaseMetadata;
fn close(self: Box<Self>) -> Result<()>;
fn path(&self) -> Option<&Path>;
fn save_collective(&self, collective: &Collective) -> Result<()>;
fn get_collective(&self, id: CollectiveId) -> Result<Option<Collective>>;
fn list_collectives(&self) -> Result<Vec<Collective>>;
fn delete_collective(&self, id: CollectiveId) -> Result<bool>;
fn get_decay_config(&self, collective_id: CollectiveId) -> Result<Option<DecayConfig>>;
fn set_decay_config(&self, collective_id: CollectiveId, config: DecayConfig) -> Result<()>;
fn count_experiences_in_collective(&self, id: CollectiveId) -> Result<u64>;
fn delete_experiences_by_collective(&self, id: CollectiveId) -> Result<u64>;
fn list_experience_ids_in_collective(&self, id: CollectiveId) -> Result<Vec<ExperienceId>>;
fn get_recent_experience_ids(
&self,
collective_id: CollectiveId,
limit: usize,
) -> Result<Vec<(ExperienceId, Timestamp)>>;
fn save_experience(&self, experience: &Experience) -> Result<()>;
fn get_experience(&self, id: ExperienceId) -> Result<Option<Experience>>;
fn update_experience(&self, id: ExperienceId, update: &ExperienceUpdate) -> Result<bool>;
#[cfg(feature = "sync")]
fn merge_experience_applications(
&self,
id: ExperienceId,
applications: &BTreeMap<InstanceId, u32>,
last_reinforced: Option<Timestamp>,
) -> Result<bool>;
fn delete_experience(&self, id: ExperienceId) -> Result<bool>;
fn reinforce_experience(&self, id: ExperienceId) -> Result<Option<u32>>;
fn save_embedding(&self, id: ExperienceId, embedding: &[f32]) -> Result<()>;
fn get_embedding(&self, id: ExperienceId) -> Result<Option<Vec<f32>>>;
fn save_relation(&self, relation: &ExperienceRelation) -> Result<()>;
fn get_relation(&self, id: RelationId) -> Result<Option<ExperienceRelation>>;
fn delete_relation(&self, id: RelationId) -> Result<bool>;
fn get_relation_ids_by_source(&self, experience_id: ExperienceId) -> Result<Vec<RelationId>>;
fn get_relation_ids_by_target(&self, experience_id: ExperienceId) -> Result<Vec<RelationId>>;
fn delete_relations_for_experience(&self, experience_id: ExperienceId) -> Result<u64>;
fn relation_exists(
&self,
source_id: ExperienceId,
target_id: ExperienceId,
relation_type: RelationType,
) -> Result<bool>;
fn save_insight(&self, insight: &DerivedInsight) -> Result<()>;
fn get_insight(&self, id: InsightId) -> Result<Option<DerivedInsight>>;
fn delete_insight(&self, id: InsightId) -> Result<bool>;
fn list_insight_ids_in_collective(&self, id: CollectiveId) -> Result<Vec<InsightId>>;
fn delete_insights_by_collective(&self, id: CollectiveId) -> Result<u64>;
fn save_activity(&self, activity: &Activity) -> Result<()>;
fn get_activity(&self, agent_id: &str, collective_id: CollectiveId)
-> Result<Option<Activity>>;
fn delete_activity(&self, agent_id: &str, collective_id: CollectiveId) -> Result<bool>;
fn list_activities_in_collective(&self, collective_id: CollectiveId) -> Result<Vec<Activity>>;
fn delete_activities_by_collective(&self, collective_id: CollectiveId) -> Result<u64>;
fn list_experience_ids_paginated(
&self,
collective_id: CollectiveId,
limit: usize,
offset: usize,
) -> Result<Vec<ExperienceId>>;
fn list_relations_in_collective(
&self,
collective_id: CollectiveId,
limit: usize,
offset: usize,
) -> Result<Vec<crate::relation::ExperienceRelation>>;
fn list_insight_ids_paginated(
&self,
collective_id: CollectiveId,
limit: usize,
offset: usize,
) -> Result<Vec<InsightId>>;
fn get_wal_sequence(&self) -> Result<u64>;
fn poll_watch_events(
&self,
since_seq: u64,
limit: usize,
) -> Result<(Vec<schema::WatchEventRecord>, u64)>;
#[cfg(feature = "sync")]
fn poll_sync_events(
&self,
since_seq: u64,
limit: usize,
) -> Result<Vec<(u64, schema::WatchEventRecord)>>;
#[cfg(feature = "sync")]
fn instance_id(&self) -> crate::sync::InstanceId;
#[cfg(feature = "sync")]
fn save_sync_cursor(&self, cursor: &crate::sync::SyncCursor) -> Result<()>;
#[cfg(feature = "sync")]
fn load_sync_cursor(
&self,
instance_id: &crate::sync::InstanceId,
) -> Result<Option<crate::sync::SyncCursor>>;
#[cfg(feature = "sync")]
fn list_sync_cursors(&self) -> Result<Vec<crate::sync::SyncCursor>>;
#[cfg(feature = "sync")]
fn compact_wal_events(&self, up_to_seq: u64) -> Result<u64>;
}
pub fn open_storage(path: impl AsRef<Path>, config: &Config) -> Result<Box<dyn StorageEngine>> {
let storage = RedbStorage::open(path, config)?;
Ok(Box::new(storage))
}
#[cfg(test)]
mod tests {
use super::*;
use crate::config::EmbeddingDimension;
use tempfile::tempdir;
#[test]
fn test_open_storage() {
let dir = tempdir().unwrap();
let path = dir.path().join("test.db");
let config = Config::default();
let storage = open_storage(&path, &config).unwrap();
assert_eq!(
storage.metadata().embedding_dimension,
EmbeddingDimension::D384
);
assert!(storage.path().is_some());
storage.close().unwrap();
}
#[test]
fn test_storage_engine_is_send_sync() {
fn assert_send_sync<T: Send + Sync>() {}
assert_send_sync::<RedbStorage>();
}
}