1use std::{marker::PhantomData, sync::Arc};
2
3use arrow_array::{
4 Array, ArrayRef, FixedSizeListArray, LargeListArray, ListArray, MapArray, StructArray,
5 UnionArray,
6};
7use arrow_schema::{FieldRef, Fields, UnionFields, UnionMode};
8
9use super::{
10 cell::{DynCellRef, view_cell_with_projector},
11 path::Path,
12 projection::{FieldProjector, StructProjection},
13};
14use crate::DynViewError;
15
16pub struct DynStructView<'a> {
18 pub(super) array: &'a StructArray,
19 pub(super) fields: Fields,
20 pub(super) row: usize,
21 pub(super) base_path: Path,
22 pub(super) projection: Option<Arc<StructProjection>>,
23}
24
25impl<'a> DynStructView<'a> {
26 pub fn len(&self) -> usize {
28 self.fields.len()
29 }
30
31 pub fn is_empty(&self) -> bool {
33 self.fields.is_empty()
34 }
35
36 pub fn get(&'a self, index: usize) -> Result<Option<DynCellRef<'a>>, DynViewError> {
38 let field = self
39 .fields
40 .get(index)
41 .ok_or_else(|| DynViewError::ColumnOutOfBounds {
42 column: index,
43 width: self.fields.len(),
44 })?;
45 let (source_index, projector) = if let Some(projection) = &self.projection {
46 let child = projection
47 .children
48 .get(index)
49 .ok_or(DynViewError::ColumnOutOfBounds {
50 column: index,
51 width: projection.children.len(),
52 })?;
53 (child.source_index, Some(&child.projector))
54 } else {
55 (index, None)
56 };
57 let child = self.array.column(source_index);
58 let path = self.base_path.push_field(field.name());
59 view_cell_with_projector(&path, field.as_ref(), projector, child.as_ref(), self.row)
60 }
61
62 pub fn get_by_name(
64 &'a self,
65 name: &str,
66 ) -> Option<Result<Option<DynCellRef<'a>>, DynViewError>> {
67 self.fields
68 .iter()
69 .position(|f| f.name() == name)
70 .map(move |idx| self.get(idx))
71 }
72}
73
74#[derive(Debug, Clone)]
76pub struct DynListView<'a> {
77 pub(super) values: ArrayRef,
78 pub(super) item_field: FieldRef,
79 pub(super) start: usize,
80 pub(super) end: usize,
81 pub(super) base_path: Path,
82 pub(super) item_projector: Option<FieldProjector>,
83 pub(super) _marker: PhantomData<&'a ()>,
84}
85
86impl<'a> DynListView<'a> {
87 pub(super) fn new_list(
88 array: &'a ListArray,
89 item_field: FieldRef,
90 base_path: Path,
91 row: usize,
92 item_projector: Option<FieldProjector>,
93 ) -> Result<Self, DynViewError> {
94 let offsets = array.value_offsets();
95 let start = offsets[row] as usize;
96 let end = offsets[row + 1] as usize;
97 Ok(Self {
98 values: array.values().clone(),
99 item_field,
100 start,
101 end,
102 base_path,
103 item_projector,
104 _marker: PhantomData,
105 })
106 }
107
108 pub(super) fn new_large_list(
109 array: &'a LargeListArray,
110 item_field: FieldRef,
111 base_path: Path,
112 row: usize,
113 item_projector: Option<FieldProjector>,
114 ) -> Result<Self, DynViewError> {
115 let offsets = array.value_offsets();
116 let start = offsets[row] as usize;
117 let end = offsets[row + 1] as usize;
118 Ok(Self {
119 values: array.values().clone(),
120 item_field,
121 start,
122 end,
123 base_path,
124 item_projector,
125 _marker: PhantomData,
126 })
127 }
128
129 pub fn len(&self) -> usize {
131 self.end - self.start
132 }
133
134 pub fn is_empty(&self) -> bool {
136 self.len() == 0
137 }
138
139 pub fn get(&'a self, index: usize) -> Result<Option<DynCellRef<'a>>, DynViewError> {
141 if index >= self.len() {
142 return Err(DynViewError::RowOutOfBounds {
143 row: index,
144 len: self.len(),
145 });
146 }
147 let absolute = self.start + index;
148 let path = self.base_path.push_index(index);
149 let projector = self.item_projector.as_ref();
150 view_cell_with_projector(
151 &path,
152 self.item_field.as_ref(),
153 projector,
154 self.values.as_ref(),
155 absolute,
156 )
157 }
158}
159
160#[derive(Debug, Clone)]
162pub struct DynFixedSizeListView<'a> {
163 pub(super) values: ArrayRef,
164 pub(super) item_field: FieldRef,
165 pub(super) start: usize,
166 pub(super) len: usize,
167 pub(super) base_path: Path,
168 pub(super) item_projector: Option<FieldProjector>,
169 pub(super) _marker: PhantomData<&'a ()>,
170}
171
172impl<'a> DynFixedSizeListView<'a> {
173 pub(super) fn new(
174 array: &'a FixedSizeListArray,
175 item_field: FieldRef,
176 len: usize,
177 base_path: Path,
178 row: usize,
179 item_projector: Option<FieldProjector>,
180 ) -> Result<Self, DynViewError> {
181 let start = row * len;
182 Ok(Self {
183 values: array.values().clone(),
184 item_field,
185 start,
186 len,
187 base_path,
188 item_projector,
189 _marker: PhantomData,
190 })
191 }
192
193 pub fn len(&self) -> usize {
195 self.len
196 }
197
198 pub fn is_empty(&self) -> bool {
200 self.len == 0
201 }
202
203 pub fn get(&'a self, index: usize) -> Result<Option<DynCellRef<'a>>, DynViewError> {
205 if index >= self.len {
206 return Err(DynViewError::RowOutOfBounds {
207 row: index,
208 len: self.len,
209 });
210 }
211 let absolute = self.start + index;
212 let path = self.base_path.push_index(index);
213 let projector = self.item_projector.as_ref();
214 view_cell_with_projector(
215 &path,
216 self.item_field.as_ref(),
217 projector,
218 self.values.as_ref(),
219 absolute,
220 )
221 }
222}
223
224#[derive(Debug, Clone)]
226pub struct DynMapView<'a> {
227 pub(super) array: &'a MapArray,
228 pub(super) start: usize,
229 pub(super) end: usize,
230 pub(super) base_path: Path,
231 pub(super) fields: Fields,
232 pub(super) projection: Option<Arc<StructProjection>>,
233}
234
235impl<'a> DynMapView<'a> {
236 pub(super) fn new(
237 array: &'a MapArray,
238 base_path: Path,
239 row: usize,
240 ) -> Result<Self, DynViewError> {
241 let entry_fields = array
242 .entries()
243 .as_any()
244 .downcast_ref::<StructArray>()
245 .map(|struct_arr| struct_arr.fields().clone())
246 .ok_or_else(|| DynViewError::Invalid {
247 column: 0,
248 path: base_path.path.clone(),
249 message: "map entries must be struct".to_string(),
250 })?;
251 Self::with_projection(array, entry_fields, base_path, row, None)
252 }
253
254 pub(super) fn with_projection(
255 array: &'a MapArray,
256 entry_fields: Fields,
257 base_path: Path,
258 row: usize,
259 projection: Option<Arc<StructProjection>>,
260 ) -> Result<Self, DynViewError> {
261 let offsets = array.value_offsets();
262 let start = offsets[row] as usize;
263 let end = offsets[row + 1] as usize;
264 Ok(Self {
265 array,
266 start,
267 end,
268 base_path,
269 fields: entry_fields,
270 projection,
271 })
272 }
273
274 pub fn len(&self) -> usize {
276 self.end - self.start
277 }
278
279 pub fn is_empty(&self) -> bool {
281 self.len() == 0
282 }
283
284 pub fn get(
286 &'a self,
287 index: usize,
288 ) -> Result<(DynCellRef<'a>, Option<DynCellRef<'a>>), DynViewError> {
289 if index >= self.len() {
290 return Err(DynViewError::RowOutOfBounds {
291 row: index,
292 len: self.len(),
293 });
294 }
295 let entries = self.array.entries();
296 let struct_entry = entries
297 .as_any()
298 .downcast_ref::<StructArray>()
299 .ok_or_else(|| DynViewError::Invalid {
300 column: self.base_path.column,
301 path: self.base_path.path.clone(),
302 message: "map entries must be struct arrays".to_string(),
303 })?;
304
305 let (key_source, key_projector) = if let Some(proj) = &self.projection {
306 let child = proj.children.first().ok_or_else(|| DynViewError::Invalid {
307 column: self.base_path.column,
308 path: self.base_path.path.clone(),
309 message: "map projection missing key child".to_string(),
310 })?;
311 (child.source_index, Some(&child.projector))
312 } else {
313 (0, None)
314 };
315 let (value_source, value_projector) = if let Some(proj) = &self.projection {
316 let child = proj.children.get(1).ok_or_else(|| DynViewError::Invalid {
317 column: self.base_path.column,
318 path: self.base_path.path.clone(),
319 message: "map projection missing value child".to_string(),
320 })?;
321 (child.source_index, Some(&child.projector))
322 } else {
323 (1, None)
324 };
325 let keys = struct_entry.column(key_source);
326 let values = struct_entry.column(value_source);
327 let key_field = Arc::clone(self.fields.first().ok_or_else(|| DynViewError::Invalid {
328 column: self.base_path.column,
329 path: self.base_path.path.clone(),
330 message: "map schema missing key field".to_string(),
331 })?);
332 let value_field = Arc::clone(self.fields.get(1).ok_or_else(|| DynViewError::Invalid {
333 column: self.base_path.column,
334 path: self.base_path.path.clone(),
335 message: "map schema missing value field".to_string(),
336 })?);
337
338 let absolute = self.start + index;
339 let key_path = self.base_path.push_index(index).push_key();
340 let key = view_cell_with_projector(
341 &key_path,
342 key_field.as_ref(),
343 key_projector,
344 keys.as_ref(),
345 absolute,
346 )?
347 .ok_or_else(|| DynViewError::Invalid {
348 column: key_path.column,
349 path: key_path.path.clone(),
350 message: "map keys may not be null".to_string(),
351 })?;
352
353 let value_path = self.base_path.push_index(index).push_value();
354 let value = view_cell_with_projector(
355 &value_path,
356 value_field.as_ref(),
357 value_projector,
358 values.as_ref(),
359 absolute,
360 )?;
361
362 Ok((key, value))
363 }
364}
365
366#[derive(Debug, Clone)]
368pub struct DynUnionView<'a> {
369 pub(super) array: &'a UnionArray,
370 pub(super) fields: UnionFields,
371 pub(super) mode: UnionMode,
372 pub(super) row: usize,
373 pub(super) base_path: Path,
374}
375
376impl<'a> DynUnionView<'a> {
377 pub(super) fn new(
378 array: &'a UnionArray,
379 fields: UnionFields,
380 mode: UnionMode,
381 base_path: Path,
382 row: usize,
383 ) -> Result<Self, DynViewError> {
384 if row >= array.len() {
385 return Err(DynViewError::RowOutOfBounds {
386 row,
387 len: array.len(),
388 });
389 }
390 Ok(Self {
391 array,
392 fields,
393 mode,
394 row,
395 base_path,
396 })
397 }
398
399 pub fn type_id(&self) -> i8 {
401 self.array.type_id(self.row)
402 }
403
404 fn variant_field(&self) -> Result<(i8, FieldRef), DynViewError> {
406 let tag = self.type_id();
407 self.fields
408 .iter()
409 .find_map(|(t, field)| {
410 if t == tag {
411 Some((t, Arc::clone(field)))
412 } else {
413 None
414 }
415 })
416 .ok_or_else(|| DynViewError::Invalid {
417 column: self.base_path.column,
418 path: self.base_path.path.clone(),
419 message: format!("unknown union type id {tag}"),
420 })
421 }
422
423 pub fn variant_name(&self) -> Option<&str> {
425 let tag = self.type_id();
426 self.fields
427 .iter()
428 .find(|(t, _)| *t == tag)
429 .map(|(_, field)| field.name().as_str())
430 }
431
432 pub fn value(&'a self) -> Result<Option<DynCellRef<'a>>, DynViewError> {
434 let (tag, field) = self.variant_field()?;
435 let child = self.array.child(tag);
436 let child_index = match self.mode {
437 UnionMode::Dense => self.array.value_offset(self.row),
438 UnionMode::Sparse => self.row,
439 };
440 let path = self.base_path.push_variant(field.name().as_str(), tag);
441 view_cell_with_projector(&path, field.as_ref(), None, child.as_ref(), child_index)
442 }
443}