1use std::{
5 collections::{BinaryHeap, VecDeque},
6 ops::Range,
7 sync::Arc,
8};
9
10use super::{
11 fixed_size_list::StructuralFixedSizeListDecoder, list::StructuralListDecoder,
12 map::StructuralMapDecoder, primitive::StructuralPrimitiveFieldDecoder,
13};
14use crate::{
15 decoder::{
16 DecodedArray, FilterExpression, LoadedPageShard, NextDecodeTask, PageEncoding,
17 ScheduledScanLine, SchedulerContext, StructuralDecodeArrayTask, StructuralFieldDecoder,
18 StructuralFieldScheduler, StructuralSchedulingJob,
19 },
20 encoder::{EncodeTask, EncodedColumn, EncodedPage, FieldEncoder, OutOfLineBuffers},
21 format::pb,
22 repdef::{CompositeRepDefUnraveler, RepDefBuilder},
23};
24use arrow_array::{Array, ArrayRef, StructArray, cast::AsArray};
25use arrow_schema::{DataType, Fields};
26use futures::{
27 FutureExt, StreamExt, TryStreamExt,
28 future::BoxFuture,
29 stream::{FuturesOrdered, FuturesUnordered},
30};
31use itertools::Itertools;
32use lance_arrow::FieldExt;
33use lance_arrow::{deepcopy::deep_copy_nulls, r#struct::StructArrayExt};
34use lance_core::{Error, Result};
35use log::trace;
36
37#[derive(Debug)]
38struct StructuralSchedulingJobWithStatus<'a> {
39 col_idx: u32,
40 col_name: &'a str,
41 job: Box<dyn StructuralSchedulingJob + 'a>,
42 rows_scheduled: u64,
43 rows_remaining: u64,
44 ready_scan_lines: VecDeque<ScheduledScanLine>,
45}
46
47impl PartialEq for StructuralSchedulingJobWithStatus<'_> {
48 fn eq(&self, other: &Self) -> bool {
49 self.col_idx == other.col_idx
50 }
51}
52
53impl Eq for StructuralSchedulingJobWithStatus<'_> {}
54
55impl PartialOrd for StructuralSchedulingJobWithStatus<'_> {
56 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
57 Some(self.cmp(other))
58 }
59}
60
61impl Ord for StructuralSchedulingJobWithStatus<'_> {
62 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
63 other.rows_scheduled.cmp(&self.rows_scheduled)
65 }
66}
67
68#[derive(Debug)]
75struct RepDefStructSchedulingJob<'a> {
76 children: BinaryHeap<StructuralSchedulingJobWithStatus<'a>>,
78 rows_scheduled: u64,
79 num_rows: u64,
80}
81
82impl<'a> RepDefStructSchedulingJob<'a> {
83 fn new(
84 scheduler: &'a StructuralStructScheduler,
85 children: Vec<Box<dyn StructuralSchedulingJob + 'a>>,
86 num_rows: u64,
87 ) -> Self {
88 let children = children
89 .into_iter()
90 .enumerate()
91 .map(|(idx, job)| StructuralSchedulingJobWithStatus {
92 col_idx: idx as u32,
93 col_name: scheduler.child_fields[idx].name(),
94 job,
95 rows_scheduled: 0,
96 rows_remaining: num_rows,
97 ready_scan_lines: VecDeque::new(),
98 })
99 .collect::<BinaryHeap<_>>();
100 Self {
101 children,
102 rows_scheduled: 0,
103 num_rows,
104 }
105 }
106}
107
108impl StructuralSchedulingJob for RepDefStructSchedulingJob<'_> {
109 fn schedule_next(
110 &mut self,
111 mut context: &mut SchedulerContext,
112 ) -> Result<Vec<ScheduledScanLine>> {
113 if self.children.is_empty() {
114 if self.rows_scheduled == self.num_rows {
116 return Ok(Vec::new());
117 }
118 self.rows_scheduled = self.num_rows;
119 return Ok(vec![ScheduledScanLine {
120 decoders: Vec::new(),
121 rows_scheduled: self.num_rows,
122 }]);
123 }
124
125 let mut decoders = Vec::new();
126 let old_rows_scheduled = self.rows_scheduled;
127 while old_rows_scheduled == self.rows_scheduled {
130 if self.children.is_empty() {
131 return Ok(Vec::new());
133 }
134 let mut next_child = self.children.pop().unwrap();
135 if next_child.ready_scan_lines.is_empty() {
136 let scoped = context.push(next_child.col_name, next_child.col_idx);
137 let child_scans = next_child.job.schedule_next(scoped.context)?;
138 context = scoped.pop();
139 if child_scans.is_empty() {
140 continue;
142 }
143 next_child.ready_scan_lines.extend(child_scans);
144 }
145 let child_scan = next_child.ready_scan_lines.pop_front().unwrap();
146 trace!(
147 "Scheduled {} rows for child {}",
148 child_scan.rows_scheduled, next_child.col_idx
149 );
150 next_child.rows_scheduled += child_scan.rows_scheduled;
151 next_child.rows_remaining -= child_scan.rows_scheduled;
152 decoders.extend(child_scan.decoders);
153 self.children.push(next_child);
154 self.rows_scheduled = self.children.peek().unwrap().rows_scheduled;
155 }
156 let struct_rows_scheduled = self.rows_scheduled - old_rows_scheduled;
157 Ok(vec![ScheduledScanLine {
158 decoders,
159 rows_scheduled: struct_rows_scheduled,
160 }])
161 }
162}
163
164#[derive(Debug)]
175pub struct StructuralStructScheduler {
176 children: Vec<Box<dyn StructuralFieldScheduler>>,
177 child_fields: Fields,
178}
179
180impl StructuralStructScheduler {
181 pub fn new(children: Vec<Box<dyn StructuralFieldScheduler>>, child_fields: Fields) -> Self {
182 Self {
183 children,
184 child_fields,
185 }
186 }
187}
188
189impl StructuralFieldScheduler for StructuralStructScheduler {
190 fn schedule_ranges<'a>(
191 &'a self,
192 ranges: &[Range<u64>],
193 filter: &FilterExpression,
194 ) -> Result<Box<dyn StructuralSchedulingJob + 'a>> {
195 let num_rows = ranges.iter().map(|r| r.end - r.start).sum();
196
197 let child_schedulers = self
198 .children
199 .iter()
200 .map(|child| child.schedule_ranges(ranges, filter))
201 .collect::<Result<Vec<_>>>()?;
202
203 Ok(Box::new(RepDefStructSchedulingJob::new(
204 self,
205 child_schedulers,
206 num_rows,
207 )))
208 }
209
210 fn initialize<'a>(
211 &'a mut self,
212 filter: &'a FilterExpression,
213 context: &'a SchedulerContext,
214 ) -> BoxFuture<'a, Result<()>> {
215 let children_initialization = self
216 .children
217 .iter_mut()
218 .map(|child| child.initialize(filter, context))
219 .collect::<FuturesUnordered<_>>();
220 async move {
221 children_initialization
222 .map(|res| res.map(|_| ()))
223 .try_collect::<Vec<_>>()
224 .await?;
225 Ok(())
226 }
227 .boxed()
228 }
229}
230
231#[derive(Debug)]
232pub struct StructuralStructDecoder {
233 children: Vec<Box<dyn StructuralFieldDecoder>>,
234 data_type: DataType,
235 child_fields: Fields,
236 is_root: bool,
238}
239
240impl StructuralStructDecoder {
241 pub fn new(fields: Fields, should_validate: bool, is_root: bool) -> Result<Self> {
242 let children = fields
243 .iter()
244 .map(|field| Self::field_to_decoder(field, should_validate))
245 .collect::<Result<Vec<_>>>()?;
246 let data_type = DataType::Struct(fields.clone());
247 Ok(Self {
248 data_type,
249 children,
250 child_fields: fields,
251 is_root,
252 })
253 }
254
255 fn field_to_decoder(
256 field: &Arc<arrow_schema::Field>,
257 should_validate: bool,
258 ) -> Result<Box<dyn StructuralFieldDecoder>> {
259 match field.data_type() {
260 DataType::Struct(fields) => {
261 if field.is_packed_struct() || field.is_blob() {
262 let decoder =
263 StructuralPrimitiveFieldDecoder::new(&field.clone(), should_validate);
264 Ok(Box::new(decoder))
265 } else {
266 Ok(Box::new(Self::new(fields.clone(), should_validate, false)?))
267 }
268 }
269 DataType::List(child_field) | DataType::LargeList(child_field) => {
270 let child_decoder = Self::field_to_decoder(child_field, should_validate)?;
271 Ok(Box::new(StructuralListDecoder::new(
272 child_decoder,
273 field.data_type().clone(),
274 )))
275 }
276 DataType::FixedSizeList(child_field, _)
277 if matches!(child_field.data_type(), DataType::Struct(_)) =>
278 {
279 let child_decoder = Self::field_to_decoder(child_field, should_validate)?;
281 Ok(Box::new(StructuralFixedSizeListDecoder::new(
282 child_decoder,
283 field.data_type().clone(),
284 )))
285 }
286 DataType::Map(entries_field, keys_sorted) => {
287 if *keys_sorted {
288 return Err(Error::not_supported_source(
289 "Map data type with keys_sorted=true is not supported yet"
290 .to_string()
291 .into(),
292 ));
293 }
294 let child_decoder = Self::field_to_decoder(entries_field, should_validate)?;
295 Ok(Box::new(StructuralMapDecoder::new(
296 child_decoder,
297 field.data_type().clone(),
298 )))
299 }
300 DataType::RunEndEncoded(_, _) => todo!(),
301 DataType::ListView(_) | DataType::LargeListView(_) => todo!(),
302 DataType::Union(_, _) => todo!(),
303 _ => Ok(Box::new(StructuralPrimitiveFieldDecoder::new(
304 field,
305 should_validate,
306 ))),
307 }
308 }
309
310 pub fn drain_batch_task(&mut self, num_rows: u64) -> Result<NextDecodeTask> {
311 let array_drain = self.drain(num_rows)?;
312 Ok(NextDecodeTask {
313 num_rows,
314 task: Box::new(array_drain),
315 })
316 }
317}
318
319impl StructuralFieldDecoder for StructuralStructDecoder {
320 fn accept_page(&mut self, mut child: LoadedPageShard) -> Result<()> {
321 let child_idx = child.path.pop_front().unwrap();
323 self.children[child_idx as usize].accept_page(child)?;
325 Ok(())
326 }
327
328 fn drain(&mut self, num_rows: u64) -> Result<Box<dyn StructuralDecodeArrayTask>> {
329 let child_tasks = self
330 .children
331 .iter_mut()
332 .map(|child| child.drain(num_rows))
333 .collect::<Result<Vec<_>>>()?;
334 Ok(Box::new(RepDefStructDecodeTask {
335 children: child_tasks,
336 child_fields: self.child_fields.clone(),
337 is_root: self.is_root,
338 num_rows,
339 }))
340 }
341
342 fn data_type(&self) -> &DataType {
343 &self.data_type
344 }
345}
346
347#[derive(Debug)]
348struct RepDefStructDecodeTask {
349 children: Vec<Box<dyn StructuralDecodeArrayTask>>,
350 child_fields: Fields,
351 is_root: bool,
352 num_rows: u64,
353}
354
355impl StructuralDecodeArrayTask for RepDefStructDecodeTask {
356 fn decode(self: Box<Self>) -> Result<DecodedArray> {
357 if self.children.is_empty() {
358 return Ok(DecodedArray {
359 array: Arc::new(StructArray::new_empty_fields(self.num_rows as usize, None)),
360 repdef: CompositeRepDefUnraveler::new(vec![]),
361 data_size: 0,
362 });
363 }
364
365 let arrays = self
366 .children
367 .into_iter()
368 .map(|task| task.decode())
369 .collect::<Result<Vec<_>>>()?;
370 let mut children = Vec::with_capacity(arrays.len());
371 let mut repdefs = Vec::with_capacity(arrays.len());
372 let mut data_size = 0u64;
373 let mut arrays_iter = arrays.into_iter();
374 let first_array = arrays_iter.next().ok_or_else(|| {
375 Error::internal("Struct decoder unexpectedly has no child arrays".to_string())
376 })?;
377 let length = first_array.array.len();
378
379 repdefs.push(first_array.repdef);
381 data_size += first_array.data_size;
382 children.push(first_array.array);
383
384 for array in arrays_iter {
385 if length != array.array.len() {
386 return Err(Error::invalid_input_source(
387 format!(
388 "Struct child array length {} does not match sibling length {}",
389 array.array.len(),
390 length
391 )
392 .into(),
393 ));
394 }
395 data_size += array.data_size;
396 children.push(array.array);
397 repdefs.push(array.repdef);
398 }
399
400 let primary_repdef = repdefs
405 .iter()
406 .position(CompositeRepDefUnraveler::has_sparse)
407 .unwrap_or(0);
408 let mut repdef = repdefs.swap_remove(primary_repdef);
409 if repdef.has_sparse() {
410 for sibling in repdefs {
411 if sibling.has_sparse() {
412 repdef.add_compatibility_check(sibling);
413 }
414 }
415 }
416
417 let validity = if self.is_root {
418 repdef.ensure_exhausted()?;
419 None
420 } else {
421 repdef.unravel_validity(length)?
422 };
423
424 let array = StructArray::try_new(self.child_fields, children, validity)
425 .map_err(|e| Error::invalid_input_source(e.to_string().into()))?;
426 Ok(DecodedArray {
427 array: Arc::new(array),
428 repdef,
429 data_size,
430 })
431 }
432}
433
434pub struct StructStructuralEncoder {
439 keep_original_array: bool,
440 children: Vec<Box<dyn FieldEncoder>>,
441}
442
443impl StructStructuralEncoder {
444 pub fn new(keep_original_array: bool, children: Vec<Box<dyn FieldEncoder>>) -> Self {
445 Self {
446 keep_original_array,
447 children,
448 }
449 }
450}
451
452impl FieldEncoder for StructStructuralEncoder {
453 fn maybe_encode(
454 &mut self,
455 array: ArrayRef,
456 external_buffers: &mut OutOfLineBuffers,
457 mut repdef: RepDefBuilder,
458 row_number: u64,
459 num_rows: u64,
460 ) -> Result<Vec<EncodeTask>> {
461 let struct_array = array.as_struct();
462 let mut struct_array = struct_array.normalize_slicing()?;
463 if let Some(validity) = struct_array.nulls() {
464 if self.keep_original_array {
465 repdef.add_validity_bitmap(validity.clone())
466 } else {
467 repdef.add_validity_bitmap(deep_copy_nulls(Some(validity)).unwrap())
468 }
469 struct_array = struct_array.pushdown_nulls()?;
470 } else {
471 repdef.add_no_null(struct_array.len());
472 }
473 let child_tasks = self
474 .children
475 .iter_mut()
476 .zip(struct_array.columns().iter())
477 .map(|(encoder, arr)| {
478 encoder.maybe_encode(
479 arr.clone(),
480 external_buffers,
481 repdef.clone(),
482 row_number,
483 num_rows,
484 )
485 })
486 .collect::<Result<Vec<_>>>()?;
487 Ok(child_tasks.into_iter().flatten().collect::<Vec<_>>())
488 }
489
490 fn flush(&mut self, external_buffers: &mut OutOfLineBuffers) -> Result<Vec<EncodeTask>> {
491 self.children
492 .iter_mut()
493 .map(|encoder| encoder.flush(external_buffers))
494 .flatten_ok()
495 .collect::<Result<Vec<_>>>()
496 }
497
498 fn num_columns(&self) -> u32 {
499 self.children
500 .iter()
501 .map(|child| child.num_columns())
502 .sum::<u32>()
503 }
504
505 fn finish(
506 &mut self,
507 external_buffers: &mut OutOfLineBuffers,
508 ) -> BoxFuture<'_, Result<Vec<crate::encoder::EncodedColumn>>> {
509 let mut child_columns = self
510 .children
511 .iter_mut()
512 .map(|child| child.finish(external_buffers))
513 .collect::<FuturesOrdered<_>>();
514 async move {
515 let mut encoded_columns = Vec::with_capacity(child_columns.len());
516 while let Some(child_cols) = child_columns.next().await {
517 encoded_columns.extend(child_cols?);
518 }
519 Ok(encoded_columns)
520 }
521 .boxed()
522 }
523}
524
525pub struct StructFieldEncoder {
526 children: Vec<Box<dyn FieldEncoder>>,
527 column_index: u32,
528 num_rows_seen: u64,
529}
530
531impl StructFieldEncoder {
532 pub fn new(children: Vec<Box<dyn FieldEncoder>>, column_index: u32) -> Self {
533 Self {
534 children,
535 column_index,
536 num_rows_seen: 0,
537 }
538 }
539}
540
541impl FieldEncoder for StructFieldEncoder {
542 fn maybe_encode(
543 &mut self,
544 array: ArrayRef,
545 external_buffers: &mut OutOfLineBuffers,
546 repdef: RepDefBuilder,
547 row_number: u64,
548 num_rows: u64,
549 ) -> Result<Vec<EncodeTask>> {
550 self.num_rows_seen += array.len() as u64;
551 let struct_array = array.as_struct();
552 let child_tasks = self
553 .children
554 .iter_mut()
555 .zip(struct_array.columns().iter())
556 .map(|(encoder, arr)| {
557 encoder.maybe_encode(
558 arr.clone(),
559 external_buffers,
560 repdef.clone(),
561 row_number,
562 num_rows,
563 )
564 })
565 .collect::<Result<Vec<_>>>()?;
566 Ok(child_tasks.into_iter().flatten().collect::<Vec<_>>())
567 }
568
569 fn flush(&mut self, external_buffers: &mut OutOfLineBuffers) -> Result<Vec<EncodeTask>> {
570 let child_tasks = self
571 .children
572 .iter_mut()
573 .map(|encoder| encoder.flush(external_buffers))
574 .collect::<Result<Vec<_>>>()?;
575 Ok(child_tasks.into_iter().flatten().collect::<Vec<_>>())
576 }
577
578 fn num_columns(&self) -> u32 {
579 self.children
580 .iter()
581 .map(|child| child.num_columns())
582 .sum::<u32>()
583 + 1
584 }
585
586 fn finish(
587 &mut self,
588 external_buffers: &mut OutOfLineBuffers,
589 ) -> BoxFuture<'_, Result<Vec<crate::encoder::EncodedColumn>>> {
590 let mut child_columns = self
591 .children
592 .iter_mut()
593 .map(|child| child.finish(external_buffers))
594 .collect::<FuturesOrdered<_>>();
595 let num_rows_seen = self.num_rows_seen;
596 let column_index = self.column_index;
597 async move {
598 let mut columns = Vec::new();
599 let mut header = EncodedColumn::default();
601 header.final_pages.push(EncodedPage {
602 data: Vec::new(),
603 description: PageEncoding::Legacy(pb::ArrayEncoding {
604 array_encoding: Some(pb::array_encoding::ArrayEncoding::Struct(
605 pb::SimpleStruct {},
606 )),
607 }),
608 num_rows: num_rows_seen,
609 column_idx: column_index,
610 row_number: 0, });
612 columns.push(header);
613 while let Some(child_cols) = child_columns.next().await {
615 columns.extend(child_cols?);
616 }
617 Ok(columns)
618 }
619 .boxed()
620 }
621}
622
623#[cfg(test)]
624mod tests {
625
626 use std::{collections::HashMap, sync::Arc};
627
628 use arrow_array::{
629 Array, ArrayRef, Float64Array, Int32Array, Int64Array, ListArray, StructArray,
630 builder::{Int32Builder, ListBuilder},
631 };
632 use arrow_buffer::{BooleanBuffer, NullBuffer, OffsetBuffer, ScalarBuffer};
633 use arrow_schema::{DataType, Field, Fields};
634
635 use crate::testing::{TestCases, check_basic_random, check_round_trip_encoding_of_data};
636
637 #[test_log::test(tokio::test)]
638 async fn test_simple_struct() {
639 let data_type = DataType::Struct(Fields::from(vec![
640 Field::new("a", DataType::Int32, false),
641 Field::new("b", DataType::Int32, false),
642 ]));
643 let field = Field::new("", data_type, false);
644 check_basic_random(field).await;
645 }
646
647 #[test_log::test(tokio::test)]
648 async fn test_nullable_struct() {
649 let inner_fields = Fields::from(vec![
667 Field::new("x", DataType::Int32, false),
668 Field::new("y", DataType::Int32, true),
669 ]);
670 let inner_struct = DataType::Struct(inner_fields.clone());
671 let outer_fields = Fields::from(vec![
672 Field::new("score", DataType::Int32, true),
673 Field::new("location", inner_struct, true),
674 ]);
675
676 let x_vals = Int32Array::from(vec![Some(1), Some(2), Some(3), Some(4), Some(5)]);
677 let y_vals = Int32Array::from(vec![Some(6), None, Some(8), Some(9), Some(10)]);
678 let scores = Int32Array::from(vec![None, Some(12), Some(13), Some(14), Some(15)]);
679
680 let location_validity = NullBuffer::from(vec![true, true, true, false, true]);
681 let locations = StructArray::new(
682 inner_fields,
683 vec![Arc::new(x_vals), Arc::new(y_vals)],
684 Some(location_validity),
685 );
686
687 let rows_validity = NullBuffer::from(vec![true, true, true, true, false]);
688 let rows = StructArray::new(
689 outer_fields,
690 vec![Arc::new(scores), Arc::new(locations)],
691 Some(rows_validity),
692 );
693
694 let test_cases = TestCases::default().with_structural_encodings();
695
696 check_round_trip_encoding_of_data(vec![Arc::new(rows)], &test_cases, HashMap::new()).await;
697 }
698
699 #[test_log::test(tokio::test)]
700 async fn test_simple_masked_nonempty_list() {
701 let items = Int32Array::from(vec![Some(1), Some(2), None, Some(4), Some(5), Some(6)]);
704 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![0, 2, 3, 4, 4, 4, 5]));
705 let list_validity = BooleanBuffer::from(vec![true, true, true, true, false, true]);
706 let list_array = ListArray::new(
707 Arc::new(Field::new("item", DataType::Int32, true)),
708 offsets,
709 Arc::new(items),
710 Some(NullBuffer::new(list_validity)),
711 );
712 let struct_validity = BooleanBuffer::from(vec![true, true, true, true, true, false]);
713 let struct_array = StructArray::new(
714 Fields::from(vec![Field::new(
715 "inner_list",
716 list_array.data_type().clone(),
717 true,
718 )]),
719 vec![Arc::new(list_array)],
720 Some(NullBuffer::new(struct_validity)),
721 );
722 check_round_trip_encoding_of_data(
723 vec![Arc::new(struct_array)],
724 &TestCases::default().with_structural_encodings(),
725 HashMap::new(),
726 )
727 .await;
728 }
729
730 #[test_log::test(tokio::test)]
731 async fn test_simple_struct_list() {
732 let items = Int32Array::from(vec![Some(1), Some(2), None, Some(4)]);
735 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![0, 2, 3, 4, 4, 4, 4]));
736 let list_validity = BooleanBuffer::from(vec![true, true, true, true, false, true]);
737 let list_array = ListArray::new(
738 Arc::new(Field::new("item", DataType::Int32, true)),
739 offsets,
740 Arc::new(items),
741 Some(NullBuffer::new(list_validity)),
742 );
743 let struct_validity = BooleanBuffer::from(vec![true, true, true, true, true, false]);
744 let struct_array = StructArray::new(
745 Fields::from(vec![Field::new(
746 "inner_list",
747 list_array.data_type().clone(),
748 true,
749 )]),
750 vec![Arc::new(list_array)],
751 Some(NullBuffer::new(struct_validity)),
752 );
753 check_round_trip_encoding_of_data(
754 vec![Arc::new(struct_array)],
755 &TestCases::default().with_structural_encodings(),
756 HashMap::new(),
757 )
758 .await;
759 }
760
761 #[test_log::test(tokio::test)]
762 async fn test_struct_list() {
763 let data_type = DataType::Struct(Fields::from(vec![
764 Field::new(
765 "inner_list",
766 DataType::List(Arc::new(Field::new("item", DataType::Int32, true))),
767 true,
768 ),
769 Field::new("outer_int", DataType::Int32, true),
770 ]));
771 let field = Field::new("row", data_type, false);
772 check_basic_random(field).await;
773 }
774
775 #[test_log::test(tokio::test)]
776 async fn test_empty_struct() {
777 let data_type = DataType::Struct(Fields::from(Vec::<Field>::default()));
780 let field = Field::new("row", data_type, false);
781 check_basic_random(field).await;
782 }
783
784 #[test_log::test(tokio::test)]
785 async fn test_complicated_struct() {
786 let data_type = DataType::Struct(Fields::from(vec![
787 Field::new("int", DataType::Int32, true),
788 Field::new(
789 "inner",
790 DataType::Struct(Fields::from(vec![
791 Field::new("inner_int", DataType::Int32, true),
792 Field::new(
793 "inner_list",
794 DataType::List(Arc::new(Field::new("item", DataType::Int32, true))),
795 true,
796 ),
797 ])),
798 true,
799 ),
800 Field::new("outer_binary", DataType::Binary, true),
801 ]));
802 let field = Field::new("row", data_type, false);
803 check_basic_random(field).await;
804 }
805
806 #[test_log::test(tokio::test)]
807 async fn test_list_of_struct_with_null_struct_element() {
808 use arrow_array::StringArray;
811
812 let tag_array = StringArray::from(vec![
813 Some("valid"),
814 Some("null_struct"),
815 Some("valid"),
816 Some("valid"),
817 ]);
818 let struct_fields = Fields::from(vec![Field::new("tag", DataType::Utf8, true)]);
819 let struct_validity = NullBuffer::from(vec![false, true, false, false]);
821 let struct_array = StructArray::new(
822 struct_fields.clone(),
823 vec![Arc::new(tag_array)],
824 Some(struct_validity),
825 );
826
827 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![0, 4]));
828 let list_field = Field::new("item", DataType::Struct(struct_fields), true);
829 let list_array =
830 ListArray::new(Arc::new(list_field), offsets, Arc::new(struct_array), None);
831
832 check_round_trip_encoding_of_data(
833 vec![Arc::new(list_array)],
834 &TestCases::default().with_u32_structural_encodings(),
835 HashMap::new(),
836 )
837 .await;
838 }
839
840 #[test_log::test(tokio::test)]
841 async fn test_list_of_struct_with_all_null_child() {
842 use arrow_array::StringArray;
843
844 let a_array = StringArray::from(vec![Some("w"), Some("x"), Some("y"), Some("z")]);
845 let b_array = StringArray::from(vec![None::<&str>, None, None, None]);
846 let struct_fields = Fields::from(vec![
847 Field::new("a", DataType::Utf8, true),
848 Field::new("b", DataType::Utf8, true),
849 ]);
850 let struct_array = StructArray::new(
851 struct_fields.clone(),
852 vec![Arc::new(a_array), Arc::new(b_array)],
853 None,
854 );
855
856 let offsets = OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![0, 2, 4]));
857 let list_field = Field::new("item", DataType::Struct(struct_fields), true);
858 let list_array =
859 ListArray::new(Arc::new(list_field), offsets, Arc::new(struct_array), None);
860
861 check_round_trip_encoding_of_data(
862 vec![Arc::new(list_array)],
863 &TestCases::default()
864 .with_range(0..1)
865 .with_range(1..2)
866 .with_indices(vec![0])
867 .with_indices(vec![1])
868 .with_structural_encodings(),
869 HashMap::new(),
870 )
871 .await;
872 }
873
874 #[test_log::test(tokio::test)]
875 async fn test_list_of_struct_with_constant_child_and_empty_lists() {
876 let item_fields = Fields::from(vec![
877 Field::new("maneuver", DataType::Int64, true),
878 Field::new("remaining_dist", DataType::Float64, true),
879 ]);
880 let item_array = StructArray::new(
881 item_fields.clone(),
882 vec![
883 Arc::new(Int64Array::from(vec![Some(3), Some(3), Some(3)])),
884 Arc::new(Float64Array::from(vec![Some(1.0), Some(2.0), Some(3.0)])),
885 ],
886 None,
887 );
888
889 let list_field = Field::new("item", DataType::Struct(item_fields), true);
890 let list_array = ListArray::new(
891 Arc::new(list_field),
892 OffsetBuffer::new(ScalarBuffer::<i32>::from(vec![0, 1, 2, 3, 3, 3, 3])),
893 Arc::new(item_array),
894 None,
895 );
896
897 let data_fields = Fields::from(vec![Field::new(
898 "maneuvers",
899 list_array.data_type().clone(),
900 true,
901 )]);
902 let data_array = StructArray::new(data_fields.clone(), vec![Arc::new(list_array)], None);
903 let row_validity = NullBuffer::from(vec![true, true, true, true, true, false]);
904 let row_array = StructArray::new(
905 Fields::from(vec![Field::new(
906 "data",
907 DataType::Struct(data_fields),
908 true,
909 )]),
910 vec![Arc::new(data_array)],
911 Some(row_validity),
912 );
913
914 check_round_trip_encoding_of_data(
915 vec![Arc::new(row_array)],
916 &TestCases::default().with_structural_encodings(),
917 HashMap::new(),
918 )
919 .await;
920 }
921
922 #[test_log::test(tokio::test)]
923 async fn test_ragged_scheduling() {
924 let items_builder = Int32Builder::new();
928 let mut list_builder = ListBuilder::new(items_builder);
929 for _ in 0..10000 {
930 list_builder.append_null();
931 }
932 let list_array = Arc::new(list_builder.finish());
933 let int_array = Arc::new(Int32Array::from_iter_values(0..10000));
934 let fields = vec![
935 Field::new("", list_array.data_type().clone(), true),
936 Field::new("", int_array.data_type().clone(), true),
937 ];
938 let struct_array = Arc::new(StructArray::new(
939 Fields::from(fields),
940 vec![list_array, int_array],
941 None,
942 )) as ArrayRef;
943 let struct_arrays = (0..10000)
944 .step_by(437)
946 .map(|offset| struct_array.slice(offset, 437.min(10000 - offset)))
947 .collect::<Vec<_>>();
948 check_round_trip_encoding_of_data(struct_arrays, &TestCases::default(), HashMap::new())
949 .await;
950 }
951}