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