mod artifacts;
pub mod fleet;
mod key_store;
mod memory;
mod postgres;
mod sqlite;
pub use artifacts::ObjectArtifactStore;
pub use fleet::{FleetStore, InMemoryFleetStore};
pub use key_store::{InMemoryKeyStore, KeyRecord, KeyStore, SqliteKeyStore, hash_key, key_prefix};
pub use memory::InMemoryStore;
pub use postgres::PostgresStore;
pub use sqlite::SqliteStore;
use crate::error::StoreError;
use crate::models::{
AuditEvent, BaselineRecord, BaselineVersion, ListAuditEventsQuery, ListAuditEventsResponse,
ListBaselinesQuery, ListBaselinesResponse, ListVerdictsQuery, ListVerdictsResponse,
PoolMetrics, VerdictRecord,
};
use async_trait::async_trait;
use chrono::{DateTime, Utc};
#[derive(Debug, Clone)]
pub struct ArtifactMeta {
pub path: String,
pub last_modified: DateTime<Utc>,
pub size: u64,
}
#[async_trait]
pub trait ArtifactStore: std::fmt::Debug + Send + Sync {
async fn put(&self, path: &str, data: Vec<u8>) -> Result<(), StoreError>;
async fn get(&self, path: &str) -> Result<Vec<u8>, StoreError>;
async fn delete(&self, path: &str) -> Result<(), StoreError>;
async fn list(&self, prefix: Option<&str>) -> Result<Vec<ArtifactMeta>, StoreError>;
}
#[async_trait]
pub trait BaselineStore: Send + Sync {
async fn create(&self, record: &BaselineRecord) -> Result<(), StoreError>;
async fn get(
&self,
project: &str,
benchmark: &str,
version: &str,
) -> Result<Option<BaselineRecord>, StoreError>;
async fn get_latest(
&self,
project: &str,
benchmark: &str,
) -> Result<Option<BaselineRecord>, StoreError>;
async fn list(
&self,
project: &str,
query: &ListBaselinesQuery,
) -> Result<ListBaselinesResponse, StoreError>;
async fn update(&self, record: &BaselineRecord) -> Result<(), StoreError>;
async fn delete(
&self,
project: &str,
benchmark: &str,
version: &str,
) -> Result<bool, StoreError>;
async fn hard_delete(
&self,
project: &str,
benchmark: &str,
version: &str,
) -> Result<bool, StoreError>;
async fn list_versions(
&self,
project: &str,
benchmark: &str,
) -> Result<Vec<BaselineVersion>, StoreError>;
async fn health_check(&self) -> Result<StorageHealth, StoreError>;
fn backend_type(&self) -> &'static str;
fn pool_metrics(&self) -> Option<PoolMetrics> {
None
}
async fn create_verdict(&self, record: &VerdictRecord) -> Result<(), StoreError>;
async fn list_verdicts(
&self,
project: &str,
query: &ListVerdictsQuery,
) -> Result<ListVerdictsResponse, StoreError>;
}
#[async_trait]
pub trait AuditStore: Send + Sync {
async fn log_event(&self, event: &AuditEvent) -> Result<(), StoreError>;
async fn list_events(
&self,
query: &ListAuditEventsQuery,
) -> Result<ListAuditEventsResponse, StoreError>;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum StorageHealth {
Healthy,
Degraded,
Unhealthy,
}
impl StorageHealth {
pub fn as_str(&self) -> &'static str {
match self {
Self::Healthy => "healthy",
Self::Degraded => "degraded",
Self::Unhealthy => "unhealthy",
}
}
}
impl std::fmt::Display for StorageHealth {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.as_str())
}
}