xdl_database/
recordset.rs1use serde_json::Value as JsonValue;
4use std::collections::HashMap;
5use xdl_core::{XdlError, XdlResult, XdlValue};
6
7#[derive(Debug, Clone)]
9pub struct ColumnInfo {
10 pub name: String,
11 pub data_type: String,
12 pub ordinal: usize,
13}
14
15#[derive(Debug, Clone)]
17pub struct Recordset {
18 columns: Vec<ColumnInfo>,
19 rows: Vec<Vec<JsonValue>>,
20 current_row: usize,
21}
22
23impl Recordset {
24 pub fn new(columns: Vec<ColumnInfo>, rows: Vec<Vec<JsonValue>>) -> Self {
26 Self {
27 columns,
28 rows,
29 current_row: 0,
30 }
31 }
32
33 pub fn empty() -> Self {
35 Self {
36 columns: Vec::new(),
37 rows: Vec::new(),
38 current_row: 0,
39 }
40 }
41
42 pub fn row_count(&self) -> usize {
44 self.rows.len()
45 }
46
47 pub fn column_count(&self) -> usize {
49 self.columns.len()
50 }
51
52 pub fn column_names(&self) -> Vec<String> {
54 self.columns.iter().map(|c| c.name.clone()).collect()
55 }
56
57 pub fn columns(&self) -> &[ColumnInfo] {
59 &self.columns
60 }
61
62 #[allow(clippy::should_implement_trait)]
64 pub fn next(&mut self) -> bool {
65 if self.current_row < self.rows.len() {
66 self.current_row += 1;
67 true
68 } else {
69 false
70 }
71 }
72
73 pub fn reset(&mut self) {
75 self.current_row = 0;
76 }
77
78 pub fn current_row(&self) -> Option<HashMap<String, JsonValue>> {
80 if self.current_row < self.rows.len() {
81 let row = &self.rows[self.current_row];
82 let mut map = HashMap::new();
83
84 for (i, value) in row.iter().enumerate() {
85 if let Some(col) = self.columns.get(i) {
86 map.insert(col.name.clone(), value.clone());
87 }
88 }
89
90 Some(map)
91 } else {
92 None
93 }
94 }
95
96 pub fn get_data(&self) -> XdlResult<XdlValue> {
98 if self.rows.is_empty() {
102 return Ok(XdlValue::Undefined);
103 }
104
105 let mut row_arrays = Vec::new();
107
108 for row in &self.rows {
109 let mut row_values = Vec::new();
110
111 for cell in row {
112 let xdl_val = json_to_xdl(cell)?;
113 row_values.push(xdl_val);
114 }
115
116 row_arrays.push(XdlValue::NestedArray(row_values));
117 }
118
119 Ok(XdlValue::NestedArray(row_arrays))
120 }
121
122 pub fn get_data_structured(&self) -> XdlResult<HashMap<String, Vec<XdlValue>>> {
124 let mut result = HashMap::new();
125
126 for col in &self.columns {
128 result.insert(col.name.clone(), Vec::new());
129 }
130
131 for row in &self.rows {
133 for (i, cell) in row.iter().enumerate() {
134 if let Some(col) = self.columns.get(i) {
135 let xdl_val = json_to_xdl(cell)?;
136 if let Some(col_vec) = result.get_mut(&col.name) {
137 col_vec.push(xdl_val);
138 }
139 }
140 }
141 }
142
143 Ok(result)
144 }
145
146 pub fn get_column(&self, column_name: &str) -> XdlResult<Vec<XdlValue>> {
148 let col_index = self
149 .columns
150 .iter()
151 .position(|c| c.name == column_name)
152 .ok_or_else(|| XdlError::RuntimeError(format!("Column not found: {}", column_name)))?;
153
154 let mut values = Vec::new();
155 for row in &self.rows {
156 if let Some(cell) = row.get(col_index) {
157 values.push(json_to_xdl(cell)?);
158 }
159 }
160
161 Ok(values)
162 }
163
164 pub fn get_row(&self, index: usize) -> Option<&Vec<JsonValue>> {
166 self.rows.get(index)
167 }
168
169 pub fn is_empty(&self) -> bool {
171 self.rows.is_empty()
172 }
173}
174
175fn json_to_xdl(value: &JsonValue) -> XdlResult<XdlValue> {
177 match value {
178 JsonValue::Null => Ok(XdlValue::Undefined),
179 JsonValue::Bool(b) => Ok(XdlValue::Long(if *b { 1 } else { 0 })),
180 JsonValue::Number(n) => {
181 if let Some(i) = n.as_i64() {
182 if i >= i32::MIN as i64 && i <= i32::MAX as i64 {
183 Ok(XdlValue::Long(i as i32))
184 } else {
185 Ok(XdlValue::Long64(i))
186 }
187 } else if let Some(f) = n.as_f64() {
188 Ok(XdlValue::Double(f))
189 } else {
190 Ok(XdlValue::Undefined)
191 }
192 }
193 JsonValue::String(s) => Ok(XdlValue::String(s.clone())),
194 JsonValue::Array(arr) => {
195 let values: Result<Vec<_>, _> = arr.iter().map(json_to_xdl).collect();
196 Ok(XdlValue::NestedArray(values?))
197 }
198 JsonValue::Object(_) => {
199 Ok(XdlValue::String(value.to_string()))
201 }
202 }
203}
204
205#[cfg(test)]
206mod tests {
207 use super::*;
208
209 #[test]
210 fn test_empty_recordset() {
211 let rs = Recordset::empty();
212 assert_eq!(rs.row_count(), 0);
213 assert_eq!(rs.column_count(), 0);
214 assert!(rs.is_empty());
215 }
216
217 #[test]
218 fn test_recordset_with_data() {
219 let columns = vec![
220 ColumnInfo {
221 name: "id".to_string(),
222 data_type: "integer".to_string(),
223 ordinal: 0,
224 },
225 ColumnInfo {
226 name: "name".to_string(),
227 data_type: "text".to_string(),
228 ordinal: 1,
229 },
230 ];
231
232 let rows = vec![
233 vec![JsonValue::from(1), JsonValue::from("Alice")],
234 vec![JsonValue::from(2), JsonValue::from("Bob")],
235 ];
236
237 let rs = Recordset::new(columns, rows);
238
239 assert_eq!(rs.row_count(), 2);
240 assert_eq!(rs.column_count(), 2);
241 assert!(!rs.is_empty());
242 assert_eq!(rs.column_names(), vec!["id", "name"]);
243 }
244}