1use serde_json::Value;
2use std::collections::HashMap;
3use std::path::Path;
4
5use super::DataSource;
6use super::error::DataError;
7use crate::layout::value::{DataValue, ValueSource};
8
9pub struct JsonDataSource {
12 version_columns: Vec<HashMap<String, Value>>,
13}
14
15impl JsonDataSource {
16 fn new(version_columns: Vec<HashMap<String, Value>>) -> Self {
17 JsonDataSource { version_columns }
18 }
19
20 pub fn from_value(data: Value, versions: &[String]) -> Result<Self, DataError> {
23 let data: HashMap<String, HashMap<String, Value>> = serde_json::from_value(data)
24 .map_err(|e| DataError::FileError(format!("failed to parse JSON: {}", e)))?;
25
26 Self::from_version_map(data, versions)
27 }
28
29 pub fn from_str(json_content: &str, versions: &[String]) -> Result<Self, DataError> {
31 let data: HashMap<String, HashMap<String, Value>> = serde_json::from_str(json_content)
32 .map_err(|e| DataError::FileError(format!("failed to parse JSON: {}", e)))?;
33
34 Self::from_version_map(data, versions)
35 }
36
37 pub fn from_path(path: impl AsRef<Path>, versions: &[String]) -> Result<Self, DataError> {
39 let path = path.as_ref();
40 let json_content = std::fs::read_to_string(path).map_err(|_| {
41 DataError::FileError(format!("failed to open file: {}", path.display()))
42 })?;
43
44 Self::from_str(&json_content, versions)
45 }
46
47 fn from_version_map(
48 data: HashMap<String, HashMap<String, Value>>,
49 versions: &[String],
50 ) -> Result<Self, DataError> {
51 let mut version_columns = Vec::with_capacity(versions.len());
52
53 for version in versions {
54 let map = data
55 .get(version)
56 .ok_or_else(|| {
57 DataError::RetrievalError(format!(
58 "version '{}' not found in JSON data",
59 version
60 ))
61 })?
62 .clone();
63 version_columns.push(map);
64 }
65
66 Ok(Self::new(version_columns))
67 }
68
69 fn lookup(&self, name: &str) -> Option<&Value> {
70 self.version_columns
71 .iter()
72 .find_map(|map| map.get(name).filter(|v| !v.is_null()))
73 }
74
75 fn value_to_data_value(value: &Value) -> Result<DataValue, DataError> {
76 match value {
77 Value::Bool(b) => Ok(DataValue::Bool(*b)),
78 Value::Number(n) => {
79 if let Some(u) = n.as_u64() {
80 Ok(DataValue::U64(u))
81 } else if let Some(i) = n.as_i64() {
82 Ok(DataValue::I64(i))
83 } else if let Some(f) = n.as_f64() {
84 Ok(DataValue::F64(f))
85 } else {
86 Err(DataError::RetrievalError(
87 "unsupported numeric type".to_owned(),
88 ))
89 }
90 }
91 Value::String(s) => Ok(DataValue::Str(s.clone())),
92 _ => Err(DataError::RetrievalError(
93 "expected scalar value".to_owned(),
94 )),
95 }
96 }
97}
98
99impl DataSource for JsonDataSource {
100 fn retrieve_single_value(&self, name: &str) -> Result<DataValue, DataError> {
101 let result = (|| {
102 let value = self
103 .lookup(name)
104 .ok_or_else(|| DataError::RetrievalError("key not found in any version".into()))?;
105
106 let dv = Self::value_to_data_value(value)?;
107 match dv {
108 DataValue::Str(_) => Err(DataError::RetrievalError(
109 "Found non-numeric single value".to_owned(),
110 )),
111 _ => Ok(dv),
112 }
113 })();
114
115 result.map_err(|e| DataError::WhileRetrieving {
116 name: name.to_owned(),
117 source: Box::new(e),
118 })
119 }
120
121 fn retrieve_1d_array_or_string(&self, name: &str) -> Result<ValueSource, DataError> {
122 let result = (|| {
123 let value = self
124 .lookup(name)
125 .ok_or_else(|| DataError::RetrievalError("key not found in any version".into()))?;
126
127 match value {
128 Value::Array(arr) => {
129 let items: Result<Vec<_>, _> =
130 arr.iter().map(Self::value_to_data_value).collect();
131 Ok(ValueSource::Array(items?))
132 }
133 Value::String(s) => Ok(ValueSource::Single(DataValue::Str(s.clone()))),
134 _ => Err(DataError::RetrievalError(
135 "expected array or string for 1D array".to_owned(),
136 )),
137 }
138 })();
139
140 result.map_err(|e| DataError::WhileRetrieving {
141 name: name.to_owned(),
142 source: Box::new(e),
143 })
144 }
145
146 fn retrieve_2d_array(&self, name: &str) -> Result<Vec<Vec<DataValue>>, DataError> {
147 let result = (|| {
148 let value = self
149 .lookup(name)
150 .ok_or_else(|| DataError::RetrievalError("key not found in any version".into()))?;
151
152 let Value::Array(outer) = value else {
153 return Err(DataError::RetrievalError(
154 "expected 2D array (array of arrays)".to_owned(),
155 ));
156 };
157
158 outer
159 .iter()
160 .map(|row_val| {
161 let Value::Array(inner) = row_val else {
162 return Err(DataError::RetrievalError(
163 "expected array for 2D array row".to_owned(),
164 ));
165 };
166 inner.iter().map(Self::value_to_data_value).collect()
167 })
168 .collect()
169 })();
170
171 result.map_err(|e| DataError::WhileRetrieving {
172 name: name.to_owned(),
173 source: Box::new(e),
174 })
175 }
176}