Skip to main content

shape_runtime/
query_result.rs

1//! Enhanced query result types that support both analysis and simulations
2
3use chrono::{DateTime, Utc};
4use serde::{Deserialize, Serialize};
5use std::collections::HashMap;
6
7/// Comprehensive query result that can contain multiple types of output
8#[derive(Debug, Clone)]
9pub struct QueryResult {
10    /// Type of query that was executed
11    pub query_type: QueryType,
12
13    /// Pattern matches if this was a find/scan query
14    pub matches: Option<Vec<PatternMatch>>,
15
16    /// Statistical analysis results
17    pub statistics: Option<StatisticalAnalysis>,
18
19    /// Alert results
20    pub alert: Option<AlertResult>,
21
22    /// Combined summary metrics
23    pub summary: Option<SummaryMetrics>,
24
25    /// Raw data for custom visualization
26    pub data: Option<QueryData>,
27
28    /// Execution metadata
29    pub metadata: QueryMetadata,
30}
31
32#[derive(Debug, Clone, Serialize, Deserialize)]
33pub enum QueryType {
34    Find,
35    Scan,
36    Analyze,
37    Simulate,
38    Alert,
39    Value,
40    With,
41    Backtest,
42}
43
44/// Statistical analysis of patterns or conditions
45#[derive(Debug, Clone, Serialize, Deserialize)]
46pub struct StatisticalAnalysis {
47    /// Total occurrences of the pattern/condition
48    pub total_occurrences: usize,
49
50    /// Success rate (however defined by the query)
51    pub success_rate: f64,
52
53    /// Distribution of outcomes
54    pub outcome_distribution: HashMap<String, f64>,
55
56    /// Time-based statistics
57    pub time_stats: TimeStatistics,
58
59    /// Magnitude statistics (generic value analysis)
60    pub magnitude_stats: MagnitudeStatistics,
61
62    /// Custom metrics defined by the query
63    pub custom_metrics: HashMap<String, f64>,
64}
65
66#[derive(Debug, Clone, Serialize, Deserialize)]
67pub struct TimeStatistics {
68    /// Average time to outcome
69    pub avg_time_to_outcome: f64,
70
71    /// Distribution by hour of day
72    pub hourly_distribution: Vec<HourlyStats>,
73
74    /// Distribution by day of week
75    pub daily_distribution: Vec<DailyStats>,
76
77    /// Seasonality metrics
78    pub seasonality: Option<SeasonalityMetrics>,
79}
80
81#[derive(Debug, Clone, Serialize, Deserialize)]
82pub struct HourlyStats {
83    pub hour: u8,
84    pub occurrences: usize,
85    pub success_rate: f64,
86    pub avg_magnitude: f64,
87}
88
89#[derive(Debug, Clone, Serialize, Deserialize)]
90pub struct DailyStats {
91    pub day: String,
92    pub occurrences: usize,
93    pub success_rate: f64,
94    pub avg_magnitude: f64,
95}
96
97#[derive(Debug, Clone, Serialize, Deserialize)]
98pub struct SeasonalityMetrics {
99    pub monthly_pattern: Vec<f64>,
100    pub quarterly_pattern: Vec<f64>,
101    pub yearly_trend: Vec<f64>,
102}
103
104#[derive(Debug, Clone, Serialize, Deserialize)]
105pub struct MagnitudeStatistics {
106    pub average: f64,
107    pub median: f64,
108    pub std_dev: f64,
109    pub min: f64,
110    pub max: f64,
111    pub percentiles: HashMap<String, f64>, // "p25", "p75", "p95", etc.
112}
113
114/// Alert result
115#[derive(Debug, Clone, Serialize, Deserialize)]
116pub struct AlertResult {
117    pub id: String,
118    pub active: bool,
119    pub message: String,
120    pub level: String,
121    pub timestamp: DateTime<Utc>,
122}
123
124/// Combined summary metrics for quick overview
125#[derive(Debug, Clone, Serialize, Deserialize)]
126pub struct SummaryMetrics {
127    /// Key statistical findings
128    pub pattern_frequency: f64, // frequency relative to data points
129    pub pattern_reliability: f64, // success rate
130
131    /// Combined score
132    pub confidence_score: f64, // 0-100
133
134    /// Generic value analysis
135    pub average_outcome: f64,
136    pub expectancy: f64,
137}
138
139/// Raw data for custom analysis/visualization
140#[derive(Debug, Clone, Serialize, Deserialize)]
141pub struct QueryData {
142    /// Time series data
143    pub time_series: Vec<TimeSeriesPoint>,
144
145    /// Distribution data
146    pub distributions: HashMap<String, Vec<f64>>,
147
148    /// Correlation matrices
149    pub correlations: HashMap<String, Vec<Vec<f64>>>,
150
151    /// Custom data tables
152    pub tables: HashMap<String, DataTable>,
153}
154
155#[derive(Debug, Clone, Serialize, Deserialize)]
156pub struct TimeSeriesPoint {
157    pub timestamp: DateTime<Utc>,
158    pub values: HashMap<String, f64>,
159}
160
161#[derive(Debug, Clone, Serialize, Deserialize)]
162pub struct DataTable {
163    pub columns: Vec<String>,
164    pub rows: Vec<Vec<serde_json::Value>>,
165}
166
167/// Query execution metadata
168#[derive(Debug, Clone, Serialize, Deserialize)]
169pub struct QueryMetadata {
170    pub execution_time_ms: u64,
171    pub data_points_analyzed: usize,
172    pub timeframe: String,
173    pub id: String,
174    pub date_range: (DateTime<Utc>, DateTime<Utc>),
175    pub query_hash: String, // for caching
176    pub warnings: Vec<String>,
177}
178
179/// Pattern match with enhanced information
180#[derive(Debug, Clone, Serialize, Deserialize)]
181pub struct PatternMatch {
182    pub pattern_name: String,
183    pub index: usize,
184    pub timestamp: DateTime<Utc>,
185    pub confidence: f64,
186    pub id: String,
187    pub metadata: serde_json::Value,
188}
189
190impl QueryResult {
191    /// Create a new empty result
192    pub fn new(query_type: QueryType, id: String, timeframe: String) -> Self {
193        Self {
194            query_type,
195            matches: None,
196            statistics: None,
197            alert: None,
198            summary: None,
199            data: None,
200            metadata: QueryMetadata {
201                execution_time_ms: 0,
202                data_points_analyzed: 0,
203                timeframe,
204                id,
205                date_range: (Utc::now(), Utc::now()),
206                query_hash: String::new(),
207                warnings: Vec::new(),
208            },
209        }
210    }
211
212    /// Add statistical analysis results
213    pub fn with_statistics(mut self, stats: StatisticalAnalysis) -> Self {
214        self.statistics = Some(stats);
215        self
216    }
217
218    /// Add alert results
219    pub fn with_alert(mut self, alert: AlertResult) -> Self {
220        self.alert = Some(alert);
221        self
222    }
223
224    /// Calculate and add summary metrics
225    pub fn calculate_summary(&mut self) {
226        let mut summary = SummaryMetrics {
227            pattern_frequency: 0.0,
228            pattern_reliability: 0.0,
229            confidence_score: 0.0,
230            average_outcome: 0.0,
231            expectancy: 0.0,
232        };
233
234        // Calculate from statistics
235        if let Some(ref stats) = self.statistics {
236            summary.pattern_frequency = if self.metadata.data_points_analyzed > 0 {
237                stats.total_occurrences as f64 / self.metadata.data_points_analyzed as f64
238            } else {
239                0.0
240            };
241            summary.pattern_reliability = stats.success_rate;
242            summary.average_outcome = stats.magnitude_stats.average;
243            summary.expectancy = stats.success_rate * stats.magnitude_stats.average;
244        }
245
246        // Overall confidence score (0-100)
247        summary.confidence_score = calculate_confidence_score(&summary, &self.statistics);
248
249        self.summary = Some(summary);
250    }
251
252    /// Format summary as a human-readable string
253    pub fn format_summary(&self) -> String {
254        if let Some(ref summary) = self.summary {
255            format!(
256                "Frequency: {:.4}, Reliability: {:.2}%, Confidence: {:.1}/100",
257                summary.pattern_frequency,
258                summary.pattern_reliability * 100.0,
259                summary.confidence_score
260            )
261        } else {
262            "No summary available".to_string()
263        }
264    }
265}
266
267/// Calculate a confidence score based on various metrics
268fn calculate_confidence_score(
269    _summary: &SummaryMetrics,
270    stats: &Option<StatisticalAnalysis>,
271) -> f64 {
272    let mut score: f64 = 50.0; // Start neutral
273
274    // Statistical confidence
275    if let Some(stats) = stats {
276        if stats.total_occurrences > 100 {
277            score += 10.0; // Good sample size
278        }
279        if stats.success_rate > 0.6 {
280            score += 10.0;
281        }
282    }
283
284    score.clamp(0.0, 100.0)
285}