reifydb_type/value/frame/
row.rs1use std::{collections::HashMap, rc::Rc};
5
6use super::{extract::FrameError, frame::Frame};
7use crate::value::{
8 Value,
9 row_number::RowNumber,
10 try_from::{TryFromValue, TryFromValueCoerce},
11};
12
13#[derive(Debug)]
14struct ColumnIndex {
15 by_name: HashMap<String, usize>,
16}
17
18impl ColumnIndex {
19 fn new(frame: &Frame) -> Self {
20 let mut by_name = HashMap::with_capacity(frame.columns.len());
21 for (idx, col) in frame.columns.iter().enumerate() {
22 by_name.insert(col.name.clone(), idx);
23 }
24 Self {
25 by_name,
26 }
27 }
28
29 fn get(&self, name: &str) -> Option<usize> {
30 self.by_name.get(name).copied()
31 }
32}
33
34#[derive(Debug)]
35pub struct FrameRow<'a> {
36 frame: &'a Frame,
37 index: Rc<ColumnIndex>,
38 row_idx: usize,
39}
40
41impl<'a> FrameRow<'a> {
42 pub fn get<T: TryFromValue>(&self, column: &str) -> Result<Option<T>, FrameError> {
43 let col_idx = self.index.get(column).ok_or_else(|| FrameError::ColumnNotFound {
44 name: column.to_string(),
45 })?;
46
47 let col = &self.frame.columns[col_idx];
48
49 if !col.data.is_defined(self.row_idx) {
50 return Ok(None);
51 }
52
53 let value = col.data.get_value(self.row_idx);
54 T::try_from_value(&value).map(Some).map_err(|e| FrameError::ValueError {
55 column: column.to_string(),
56 row: self.row_idx,
57 error: e,
58 })
59 }
60
61 pub fn get_coerce<T: TryFromValueCoerce>(&self, column: &str) -> Result<Option<T>, FrameError> {
62 let col_idx = self.index.get(column).ok_or_else(|| FrameError::ColumnNotFound {
63 name: column.to_string(),
64 })?;
65
66 let col = &self.frame.columns[col_idx];
67
68 if !col.data.is_defined(self.row_idx) {
69 return Ok(None);
70 }
71
72 let value = col.data.get_value(self.row_idx);
73 T::try_from_value_coerce(&value).map(Some).map_err(|e| FrameError::ValueError {
74 column: column.to_string(),
75 row: self.row_idx,
76 error: e,
77 })
78 }
79
80 pub fn get_value(&self, column: &str) -> Option<Value> {
81 self.index.get(column).map(|col_idx| self.frame.columns[col_idx].data.get_value(self.row_idx))
82 }
83
84 pub fn index(&self) -> usize {
85 self.row_idx
86 }
87
88 pub fn row_number(&self) -> Option<RowNumber> {
89 self.frame.row_numbers.get(self.row_idx).copied()
90 }
91
92 pub fn is_defined(&self, column: &str) -> Option<bool> {
93 self.index.get(column).map(|col_idx| self.frame.columns[col_idx].data.is_defined(self.row_idx))
94 }
95}
96
97pub struct FrameRows<'a> {
98 frame: &'a Frame,
99 index: Rc<ColumnIndex>,
100 current: usize,
101 len: usize,
102}
103
104impl<'a> FrameRows<'a> {
105 pub(super) fn new(frame: &'a Frame) -> Self {
106 let len = frame.columns.first().map(|c| c.data.len()).unwrap_or(0);
107 Self {
108 frame,
109 index: Rc::new(ColumnIndex::new(frame)),
110 current: 0,
111 len,
112 }
113 }
114}
115
116impl<'a> Iterator for FrameRows<'a> {
117 type Item = FrameRow<'a>;
118
119 fn next(&mut self) -> Option<Self::Item> {
120 if self.current >= self.len {
121 return None;
122 }
123
124 let row = FrameRow {
125 frame: self.frame,
126 index: Rc::clone(&self.index),
127 row_idx: self.current,
128 };
129
130 self.current += 1;
131 Some(row)
132 }
133
134 fn size_hint(&self) -> (usize, Option<usize>) {
135 let remaining = self.len.saturating_sub(self.current);
136 (remaining, Some(remaining))
137 }
138}
139
140impl ExactSizeIterator for FrameRows<'_> {}
141
142impl<'a> DoubleEndedIterator for FrameRows<'a> {
143 fn next_back(&mut self) -> Option<Self::Item> {
144 if self.current >= self.len {
145 return None;
146 }
147
148 self.len -= 1;
149
150 Some(FrameRow {
151 frame: self.frame,
152 index: Rc::clone(&self.index),
153 row_idx: self.len,
154 })
155 }
156}
157
158impl Frame {
159 pub fn rows(&self) -> FrameRows<'_> {
160 FrameRows::new(self)
161 }
162}
163
164#[cfg(test)]
165pub mod tests {
166 use super::*;
167 use crate::value::{
168 container::{number::NumberContainer, utf8::Utf8Container},
169 frame::{column::FrameColumn, data::FrameColumnData},
170 };
171
172 fn make_test_frame() -> Frame {
173 Frame::with_row_numbers(
174 vec![
175 FrameColumn {
176 name: "id".to_string(),
177 data: FrameColumnData::Int8(NumberContainer::from_vec(vec![1i64, 2, 3])),
178 },
179 FrameColumn {
180 name: "name".to_string(),
181 data: FrameColumnData::Utf8(Utf8Container::new(vec![
182 "Alice".to_string(),
183 "Bob".to_string(),
184 String::new(),
185 ])),
186 },
187 ],
188 vec![100.into(), 200.into(), 300.into()],
189 )
190 }
191
192 #[test]
193 fn test_rows_iterator() {
194 let frame = make_test_frame();
195 let rows: Vec<_> = frame.rows().collect();
196
197 assert_eq!(rows.len(), 3);
198 assert_eq!(rows[0].index(), 0);
199 assert_eq!(rows[1].index(), 1);
200 assert_eq!(rows[2].index(), 2);
201 }
202
203 #[test]
204 fn test_row_get() {
205 let frame = make_test_frame();
206 let mut rows = frame.rows();
207
208 let row0 = rows.next().unwrap();
209 assert_eq!(row0.get::<i64>("id").unwrap(), Some(1i64));
210 assert_eq!(row0.get::<String>("name").unwrap(), Some("Alice".to_string()));
211
212 let row2 = rows.nth(1).unwrap(); assert_eq!(row2.get::<i64>("id").unwrap(), Some(3i64));
214 assert_eq!(row2.get::<String>("name").unwrap(), Some(String::new())); }
216
217 #[test]
218 fn test_row_get_coerce() {
219 let frame = make_test_frame();
220 let row = frame.rows().next().unwrap();
221
222 let id: Option<f64> = row.get_coerce("id").unwrap();
224 assert_eq!(id, Some(1.0f64));
225 }
226
227 #[test]
228 fn test_row_get_value() {
229 let frame = make_test_frame();
230 let row = frame.rows().next().unwrap();
231
232 let value = row.get_value("id");
233 assert!(matches!(value, Some(Value::Int8(1))));
234
235 let missing = row.get_value("nonexistent");
236 assert!(missing.is_none());
237 }
238
239 #[test]
240 fn test_row_number() {
241 let frame = make_test_frame();
242 let rows: Vec<_> = frame.rows().collect();
243
244 assert_eq!(rows[0].row_number(), Some(100.into()));
245 assert_eq!(rows[1].row_number(), Some(200.into()));
246 assert_eq!(rows[2].row_number(), Some(300.into()));
247 }
248
249 #[test]
250 fn test_is_defined() {
251 let frame = make_test_frame();
252 let rows: Vec<_> = frame.rows().collect();
253
254 assert_eq!(rows[0].is_defined("name"), Some(true));
255 assert_eq!(rows[2].is_defined("name"), Some(true)); assert_eq!(rows[0].is_defined("nonexistent"), None);
257 }
258
259 #[test]
260 fn test_exact_size_iterator() {
261 let frame = make_test_frame();
262 let rows = frame.rows();
263
264 assert_eq!(rows.len(), 3);
265 }
266
267 #[test]
268 fn test_double_ended_iterator() {
269 let frame = make_test_frame();
270 let mut rows = frame.rows();
271
272 let last = rows.next_back().unwrap();
273 assert_eq!(last.index(), 2);
274
275 let first = rows.next().unwrap();
276 assert_eq!(first.index(), 0);
277 }
278}