1use core_storage::Value;
2
3#[derive(Debug, Clone, PartialEq)]
4pub struct ResultSet {
5 columns: Vec<String>,
6 rows: Vec<Vec<Option<Value>>>,
7}
8
9impl ResultSet {
10 pub fn new(columns: Vec<String>) -> Self {
11 Self {
12 columns,
13 rows: Vec::new(),
14 }
15 }
16
17 pub fn push_row(&mut self, row: Vec<Option<Value>>) {
18 assert_eq!(
19 row.len(),
20 self.columns.len(),
21 "row arity does not match ResultSet columns"
22 );
23 self.rows.push(row);
24 }
25
26 pub fn columns(&self) -> &[String] {
27 &self.columns
28 }
29
30 pub fn len(&self) -> usize {
31 self.rows.len()
32 }
33
34 pub fn is_empty(&self) -> bool {
35 self.rows.is_empty()
36 }
37
38 pub fn row(&self, i: usize) -> &[Option<Value>] {
40 &self.rows[i]
41 }
42
43 pub fn get(&self, i: usize, col: &str) -> Option<&Value> {
44 let idx = self.columns.iter().position(|c| c == col)?;
45 self.rows.get(i)?.get(idx)?.as_ref()
46 }
47}
48
49#[cfg(test)]
50mod tests {
51 use super::ResultSet;
52 use core_storage::Value;
53
54 #[test]
55 fn resultset_basics() {
56 let mut rs = ResultSet::new(vec!["a".into(), "b".into()]);
57 rs.push_row(vec![Some(Value::Int(1)), None]);
58 assert_eq!(rs.len(), 1);
59 assert_eq!(rs.get(0, "a"), Some(&Value::Int(1)));
60 assert_eq!(rs.get(0, "b"), None);
61 assert_eq!(rs.get(0, "zz"), None);
62 assert_eq!(rs.row(0)[1], None);
63 }
64
65 #[test]
66 #[should_panic]
67 fn resultset_arity_mismatch_panics() {
68 let mut rs = ResultSet::new(vec!["a".into()]);
69 rs.push_row(vec![]);
70 }
71
72 #[test]
73 fn resultset_empty_and_columns() {
74 let rs = ResultSet::new(vec!["a".into()]);
75 assert!(rs.is_empty());
76 assert_eq!(rs.len(), 0);
77 assert_eq!(rs.columns(), &["a".to_string()]);
78 }
79}