shape_runtime/data/load_query.rs
1//! Generic load query for industry-agnostic data loading.
2//!
3//! Phase 1.B (ADR-006 §2.7.4 audit-accuracy ruling): the
4//! `to_data_query` body decoded `&ValueWord` parameters via tag-bit
5//! dispatch (`as_str()`, `as_time()`, `as_timeframe()`, `as_duration()`,
6//! `as_f64()`) that no longer exists. The kind-threaded rebuild
7//! lands in Phase 2c when the per-position `NativeKind` is threaded
8//! from the schema; until then the body returns a deferred error and
9//! the type signature is preserved at the [`KindedSlot`] shape per
10//! ADR-006 §2.7.5.
11
12use super::DataQuery;
13use shape_ast::error::{Result, ShapeError};
14use shape_value::KindedSlot;
15use std::collections::HashMap;
16
17/// Generic data load request (industry-agnostic).
18#[derive(Debug, Clone, Default)]
19pub struct LoadQuery {
20 /// Provider name (e.g., "data", "api", "warehouse"). If `None`,
21 /// uses the default provider.
22 pub provider: Option<String>,
23
24 /// Generic parameters (arbitrary key-value). `KindedSlot`'s explicit
25 /// `Drop`/`Clone` impls dispatch on `NativeKind` so each parameter's
26 /// heap refcount is released on teardown.
27 pub params: HashMap<String, KindedSlot>,
28
29 /// Target type name for validation (e.g., "Candle", "TickData").
30 pub target_type: Option<String>,
31
32 /// Optional column mapping override.
33 pub column_mapping: Option<HashMap<String, String>>,
34}
35
36impl LoadQuery {
37 /// Create a new empty load query.
38 pub fn new() -> Self {
39 Self::default()
40 }
41
42 /// Set the provider name.
43 pub fn with_provider(mut self, name: &str) -> Self {
44 self.provider = Some(name.to_string());
45 self
46 }
47
48 /// Add a parameter.
49 pub fn with_param(mut self, key: &str, value: KindedSlot) -> Self {
50 self.params.insert(key.to_string(), value);
51 self
52 }
53
54 /// Set the target type for validation.
55 pub fn with_type(mut self, type_name: &str) -> Self {
56 self.target_type = Some(type_name.to_string());
57 self
58 }
59
60 /// Set the column mapping.
61 pub fn with_column_mapping(mut self, mapping: HashMap<String, String>) -> Self {
62 self.column_mapping = Some(mapping);
63 self
64 }
65
66 /// Convert to a provider-specific [`DataQuery`].
67 ///
68 /// Phase 1.B: the param-decode helpers (`value_to_timestamp`,
69 /// `as_timeframe`/`as_duration` decoders) are deferred to Phase 2c.
70 /// Until then, this method returns a deferred error rather than
71 /// silently produce a malformed `DataQuery`.
72 pub fn to_data_query(&self) -> Result<DataQuery> {
73 Err(ShapeError::RuntimeError {
74 message: "LoadQuery::to_data_query: pending Phase 2c kind-threaded param decode — see ADR-006 §2.7.4".to_string(),
75 location: None,
76 })
77 }
78}
79
80#[cfg(test)]
81mod tests {
82 // Pre-bulldozer behavioural tests covered the `to_data_query`
83 // happy-path / error-path / range / limit shapes. They return
84 // alongside the kind-threaded rebuild in Phase 2c.
85
86 use super::*;
87
88 #[test]
89 fn test_basic_query_metadata() {
90 // Metadata-only test that doesn't invoke the deferred body.
91 let query = LoadQuery::new()
92 .with_provider("data")
93 .with_type("Candle");
94
95 assert_eq!(query.provider, Some("data".to_string()));
96 assert_eq!(query.target_type, Some("Candle".to_string()));
97 }
98}