Skip to main content

shape_runtime/data/
provider.rs

1//! DataProvider trait and error types
2//!
3//! Defines the interface for data sources. Implementations live outside
4//! shape-core (e.g., in shape-cli for data integration).
5
6use super::{DataFrame, DataQuery, Timeframe};
7use std::sync::Arc;
8use thiserror::Error;
9
10/// Error type for data provider operations
11#[derive(Debug, Error)]
12pub enum DataError {
13    #[error("Symbol not found: {0}")]
14    SymbolNotFound(String),
15
16    #[error("No data available for timeframe: {0}")]
17    TimeframeNotAvailable(String),
18
19    #[error("No data in requested range")]
20    NoDataInRange,
21
22    #[error("IO error: {0}")]
23    Io(#[from] std::io::Error),
24
25    #[error("Provider error: {0}")]
26    Provider(String),
27
28    #[error("Configuration error: {0}")]
29    Config(String),
30}
31
32/// Trait for data providers
33///
34/// Implementations of this trait provide access to time series data.
35/// The trait is designed to be simple and synchronous - async operations
36/// should be handled by the implementation internally.
37pub trait DataProvider: Send + Sync {
38    /// Load data matching the query
39    ///
40    /// Returns a DataFrame with the requested data, or an error if the
41    /// data is not available.
42    fn load(&self, query: &DataQuery) -> Result<DataFrame, DataError>;
43
44    /// Check if data is available for a symbol/timeframe combination
45    fn has_data(&self, symbol: &str, timeframe: &Timeframe) -> bool;
46
47    /// List available symbols
48    fn symbols(&self) -> Vec<String>;
49
50    /// List available timeframes for a symbol
51    fn timeframes(&self, symbol: &str) -> Vec<Timeframe> {
52        // Default implementation returns empty - providers can override
53        let _ = symbol;
54        Vec::new()
55    }
56}
57
58/// A no-op provider that returns no data
59///
60/// Useful as a default when no provider is configured.
61#[derive(Debug, Clone, Default)]
62pub struct NullProvider;
63
64impl DataProvider for NullProvider {
65    fn load(&self, query: &DataQuery) -> Result<DataFrame, DataError> {
66        Err(DataError::SymbolNotFound(query.id.clone()))
67    }
68
69    fn has_data(&self, _symbol: &str, _timeframe: &Timeframe) -> bool {
70        false
71    }
72
73    fn symbols(&self) -> Vec<String> {
74        Vec::new()
75    }
76}
77
78/// Type alias for a shared DataProvider
79pub type SharedDataProvider = Arc<dyn DataProvider>;
80
81#[cfg(test)]
82mod tests {
83    use super::*;
84
85    #[test]
86    fn test_null_provider() {
87        let provider = NullProvider;
88        let query = DataQuery::new("TEST", Timeframe::d1());
89
90        assert!(!provider.has_data("TEST", &Timeframe::d1()));
91        assert!(provider.symbols().is_empty());
92        assert!(provider.load(&query).is_err());
93    }
94}