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