Files
foxhunt/crates/risk-data/src/lib.rs
jgrusewski 9c3d741a08 refactor: restructure repo — crates/, bin/, testing/ layout
Move 17 library crates into crates/, CLI binary into bin/fxt,
consolidate 10 test crates into testing/, split config crate
from deployment config files.

Root directory reduced from 38+ to ~17 directories.
All Cargo.toml paths and build.rs proto refs updated.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 11:56:00 +01:00

164 lines
5.0 KiB
Rust

//! Risk Data Repository
//!
//! Production-ready risk management data layer for high-frequency trading systems.
//! Provides repositories for `VaR` calculations, compliance logging, position limits,
//! and risk data models with `PostgreSQL` and Redis integration.
#![allow(missing_docs)] // Internal implementation details
// Allow pedantic lints for repository implementation
#![allow(clippy::missing_docs_in_private_items)]
#![allow(clippy::clone_on_ref_ptr)]
#![allow(clippy::str_to_string)]
#![deny(clippy::unwrap_used, clippy::expect_used)]
use std::sync::Arc;
pub mod compliance;
pub mod limits;
pub mod models;
pub mod var;
// Import the repository traits and implementations
use crate::compliance::{ComplianceRepository, ComplianceRepositoryImpl};
use crate::limits::{LimitsRepository, LimitsRepositoryImpl};
use crate::var::{VarRepository, VarRepositoryImpl};
/// Configuration for the risk data repository
#[derive(Debug, Clone)]
pub struct RiskDataConfig {
/// `PostgreSQL` database URL
pub database_url: String,
/// Redis connection URL
pub redis_url: String,
/// Maximum database connections
pub max_connections: u32,
/// Connection timeout in seconds
pub connection_timeout_secs: u64,
}
impl Default for RiskDataConfig {
fn default() -> Self {
Self {
database_url: "postgresql://localhost/foxhunt".to_owned(),
redis_url: "redis://localhost:6379".to_owned(),
max_connections: 10,
connection_timeout_secs: 30,
}
}
}
/// Main risk data repository facade providing access to all risk data operations
#[derive(Debug, Clone)]
pub struct RiskDataRepository {
var_repo: Arc<dyn VarRepository>,
compliance_repo: Arc<dyn ComplianceRepository>,
limits_repo: Arc<dyn LimitsRepository>,
}
impl RiskDataRepository {
/// Create a new risk data repository with the given configuration
///
/// # Errors
/// Returns error if the operation fails
pub async fn new(config: RiskDataConfig) -> Result<Self, RiskDataError> {
let pool = sqlx::postgres::PgPoolOptions::new()
.max_connections(config.max_connections)
.acquire_timeout(std::time::Duration::from_secs(
config.connection_timeout_secs,
))
.connect(&config.database_url)
.await?;
let redis_client = redis::Client::open(config.redis_url)?;
let redis_conn = redis::aio::ConnectionManager::new(redis_client).await?;
let var_repo = Arc::new(VarRepositoryImpl::new(pool.clone(), redis_conn.clone()));
let compliance_repo = Arc::new(ComplianceRepositoryImpl::new(
pool.clone(),
redis_conn.clone(),
));
let limits_repo = Arc::new(LimitsRepositoryImpl::new(pool.clone(), redis_conn));
Ok(Self {
var_repo,
compliance_repo,
limits_repo,
})
}
/// Get `VaR` repository
pub fn var(&self) -> Arc<dyn VarRepository> {
Arc::clone(&self.var_repo)
}
/// Get compliance repository
pub fn compliance(&self) -> Arc<dyn ComplianceRepository> {
Arc::clone(&self.compliance_repo)
}
/// Get limits repository
pub fn limits(&self) -> Arc<dyn LimitsRepository> {
Arc::clone(&self.limits_repo)
}
}
/// Common error types for risk data operations
#[derive(Debug, thiserror::Error)]
pub enum RiskDataError {
/// Database connection or query error
#[error("Database error: {0}")]
Database(#[from] sqlx::Error),
/// Redis cache operation error
#[error("Redis error: {0}")]
Redis(#[from] redis::RedisError),
/// JSON serialization/deserialization error
#[error("Serialization error: {0}")]
Serialization(#[from] serde_json::Error),
/// `VaR` calculation or modeling error
#[error("VaR calculation error: {0}")]
VarCalculation(String),
/// Compliance rule validation error
#[error("Compliance validation error: {0}")]
ComplianceValidation(String),
/// Position limits validation error
#[error("Position limits validation error: {0}")]
LimitsValidation(String),
/// Configuration setup or validation error
#[error("Configuration error: {0}")]
Configuration(String),
/// Invalid input data error
#[error("Invalid data: {0}")]
InvalidData(String),
}
/// Result type for risk data operations
pub type RiskDataResult<T> = Result<T, RiskDataError>;
#[cfg(test)]
#[allow(clippy::unwrap_used, clippy::expect_used)]
mod tests {
use super::*;
#[test]
fn test_risk_data_config_default() {
let config = RiskDataConfig::default();
assert_eq!(config.database_url, "postgresql://localhost/foxhunt");
assert_eq!(config.redis_url, "redis://localhost:6379");
assert_eq!(config.max_connections, 10);
assert_eq!(config.connection_timeout_secs, 30);
}
#[test]
fn test_risk_data_error_display() {
let error = RiskDataError::VarCalculation("Test error".to_string());
assert_eq!(error.to_string(), "VaR calculation error: Test error");
}
}