/Users/andrewlamb/Software/arrow-rs/arrow-array/src/builder/generic_list_view_builder.rs
Line | Count | Source |
1 | | // Licensed to the Apache Software Foundation (ASF) under one |
2 | | // or more contributor license agreements. See the NOTICE file |
3 | | // distributed with this work for additional information |
4 | | // regarding copyright ownership. The ASF licenses this file |
5 | | // to you under the Apache License, Version 2.0 (the |
6 | | // "License"); you may not use this file except in compliance |
7 | | // with the License. You may obtain a copy of the License at |
8 | | // |
9 | | // http://www.apache.org/licenses/LICENSE-2.0 |
10 | | // |
11 | | // Unless required by applicable law or agreed to in writing, |
12 | | // software distributed under the License is distributed on an |
13 | | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
14 | | // KIND, either express or implied. See the License for the |
15 | | // specific language governing permissions and limitations |
16 | | // under the License. |
17 | | |
18 | | use crate::builder::ArrayBuilder; |
19 | | use crate::{ArrayRef, GenericListViewArray, OffsetSizeTrait}; |
20 | | use arrow_buffer::{Buffer, NullBufferBuilder, ScalarBuffer}; |
21 | | use arrow_schema::{Field, FieldRef}; |
22 | | use std::any::Any; |
23 | | use std::sync::Arc; |
24 | | |
25 | | /// Builder for [`GenericListViewArray`] |
26 | | #[derive(Debug)] |
27 | | pub struct GenericListViewBuilder<OffsetSize: OffsetSizeTrait, T: ArrayBuilder> { |
28 | | offsets_builder: Vec<OffsetSize>, |
29 | | sizes_builder: Vec<OffsetSize>, |
30 | | null_buffer_builder: NullBufferBuilder, |
31 | | values_builder: T, |
32 | | field: Option<FieldRef>, |
33 | | current_offset: OffsetSize, |
34 | | } |
35 | | |
36 | | impl<O: OffsetSizeTrait, T: ArrayBuilder + Default> Default for GenericListViewBuilder<O, T> { |
37 | | fn default() -> Self { |
38 | | Self::new(T::default()) |
39 | | } |
40 | | } |
41 | | |
42 | | impl<OffsetSize: OffsetSizeTrait, T: ArrayBuilder> ArrayBuilder |
43 | | for GenericListViewBuilder<OffsetSize, T> |
44 | | { |
45 | | /// Returns the builder as a non-mutable `Any` reference. |
46 | 0 | fn as_any(&self) -> &dyn Any { |
47 | 0 | self |
48 | 0 | } |
49 | | |
50 | | /// Returns the builder as a mutable `Any` reference. |
51 | 0 | fn as_any_mut(&mut self) -> &mut dyn Any { |
52 | 0 | self |
53 | 0 | } |
54 | | |
55 | | /// Returns the boxed builder as a box of `Any`. |
56 | 0 | fn into_box_any(self: Box<Self>) -> Box<dyn Any> { |
57 | 0 | self |
58 | 0 | } |
59 | | |
60 | | /// Returns the number of array slots in the builder |
61 | 0 | fn len(&self) -> usize { |
62 | 0 | self.null_buffer_builder.len() |
63 | 0 | } |
64 | | |
65 | | /// Builds the array and reset this builder. |
66 | 0 | fn finish(&mut self) -> ArrayRef { |
67 | 0 | Arc::new(self.finish()) |
68 | 0 | } |
69 | | |
70 | | /// Builds the array without resetting the builder. |
71 | 0 | fn finish_cloned(&self) -> ArrayRef { |
72 | 0 | Arc::new(self.finish_cloned()) |
73 | 0 | } |
74 | | } |
75 | | |
76 | | impl<OffsetSize: OffsetSizeTrait, T: ArrayBuilder> GenericListViewBuilder<OffsetSize, T> { |
77 | | /// Creates a new [`GenericListViewBuilder`] from a given values array builder |
78 | | pub fn new(values_builder: T) -> Self { |
79 | | let capacity = values_builder.len(); |
80 | | Self::with_capacity(values_builder, capacity) |
81 | | } |
82 | | |
83 | | /// Creates a new [`GenericListViewBuilder`] from a given values array builder |
84 | | /// `capacity` is the number of items to pre-allocate space for in this builder |
85 | 0 | pub fn with_capacity(values_builder: T, capacity: usize) -> Self { |
86 | 0 | let offsets_builder = Vec::with_capacity(capacity); |
87 | 0 | let sizes_builder = Vec::with_capacity(capacity); |
88 | 0 | Self { |
89 | 0 | offsets_builder, |
90 | 0 | null_buffer_builder: NullBufferBuilder::new(capacity), |
91 | 0 | values_builder, |
92 | 0 | sizes_builder, |
93 | 0 | field: None, |
94 | 0 | current_offset: OffsetSize::zero(), |
95 | 0 | } |
96 | 0 | } |
97 | | |
98 | | /// |
99 | | /// By default a nullable field is created with the name `item` |
100 | | /// |
101 | | /// Note: [`Self::finish`] and [`Self::finish_cloned`] will panic if the |
102 | | /// field's data type does not match that of `T` |
103 | 0 | pub fn with_field(self, field: impl Into<FieldRef>) -> Self { |
104 | 0 | Self { |
105 | 0 | field: Some(field.into()), |
106 | 0 | ..self |
107 | 0 | } |
108 | 0 | } |
109 | | } |
110 | | |
111 | | impl<OffsetSize: OffsetSizeTrait, T: ArrayBuilder> GenericListViewBuilder<OffsetSize, T> |
112 | | where |
113 | | T: 'static, |
114 | | { |
115 | | /// Returns the child array builder as a mutable reference. |
116 | | /// |
117 | | /// This mutable reference can be used to append values into the child array builder, |
118 | | /// but you must call [`append`](#method.append) to delimit each distinct list value. |
119 | | pub fn values(&mut self) -> &mut T { |
120 | | &mut self.values_builder |
121 | | } |
122 | | |
123 | | /// Returns the child array builder as an immutable reference |
124 | | pub fn values_ref(&self) -> &T { |
125 | | &self.values_builder |
126 | | } |
127 | | |
128 | | /// Finish the current variable-length list array slot |
129 | | /// |
130 | | /// # Panics |
131 | | /// |
132 | | /// Panics if the length of [`Self::values`] exceeds `OffsetSize::MAX` |
133 | | #[inline] |
134 | | pub fn append(&mut self, is_valid: bool) { |
135 | | self.offsets_builder.push(self.current_offset); |
136 | | self.sizes_builder.push( |
137 | | OffsetSize::from_usize( |
138 | | self.values_builder.len() - self.current_offset.to_usize().unwrap(), |
139 | | ) |
140 | | .unwrap(), |
141 | | ); |
142 | | self.null_buffer_builder.append(is_valid); |
143 | | self.current_offset = OffsetSize::from_usize(self.values_builder.len()).unwrap(); |
144 | | } |
145 | | |
146 | | /// Append value into this [`GenericListViewBuilder`] |
147 | | #[inline] |
148 | | pub fn append_value<I, V>(&mut self, i: I) |
149 | | where |
150 | | T: Extend<Option<V>>, |
151 | | I: IntoIterator<Item = Option<V>>, |
152 | | { |
153 | | self.extend(std::iter::once(Some(i))) |
154 | | } |
155 | | |
156 | | /// Append a null to this [`GenericListViewBuilder`] |
157 | | /// |
158 | | /// See [`Self::append_value`] for an example use. |
159 | | #[inline] |
160 | | pub fn append_null(&mut self) { |
161 | | self.offsets_builder.push(self.current_offset); |
162 | | self.sizes_builder.push(OffsetSize::from_usize(0).unwrap()); |
163 | | self.null_buffer_builder.append_null(); |
164 | | } |
165 | | |
166 | | /// Appends an optional value into this [`GenericListViewBuilder`] |
167 | | /// |
168 | | /// If `Some` calls [`Self::append_value`] otherwise calls [`Self::append_null`] |
169 | | #[inline] |
170 | | pub fn append_option<I, V>(&mut self, i: Option<I>) |
171 | | where |
172 | | T: Extend<Option<V>>, |
173 | | I: IntoIterator<Item = Option<V>>, |
174 | | { |
175 | | match i { |
176 | | Some(i) => self.append_value(i), |
177 | | None => self.append_null(), |
178 | | } |
179 | | } |
180 | | |
181 | | /// Builds the [`GenericListViewArray`] and reset this builder. |
182 | 0 | pub fn finish(&mut self) -> GenericListViewArray<OffsetSize> { |
183 | 0 | let values = self.values_builder.finish(); |
184 | 0 | let nulls = self.null_buffer_builder.finish(); |
185 | 0 | let offsets = Buffer::from_vec(std::mem::take(&mut self.offsets_builder)); |
186 | 0 | self.current_offset = OffsetSize::zero(); |
187 | | |
188 | | // Safety: Safe by construction |
189 | 0 | let offsets = ScalarBuffer::from(offsets); |
190 | 0 | let sizes = Buffer::from_vec(std::mem::take(&mut self.sizes_builder)); |
191 | 0 | let sizes = ScalarBuffer::from(sizes); |
192 | 0 | let field = match &self.field { |
193 | 0 | Some(f) => f.clone(), |
194 | 0 | None => Arc::new(Field::new("item", values.data_type().clone(), true)), |
195 | | }; |
196 | 0 | GenericListViewArray::new(field, offsets, sizes, values, nulls) |
197 | 0 | } |
198 | | |
199 | | /// Builds the [`GenericListViewArray`] without resetting the builder. |
200 | 0 | pub fn finish_cloned(&self) -> GenericListViewArray<OffsetSize> { |
201 | 0 | let values = self.values_builder.finish_cloned(); |
202 | 0 | let nulls = self.null_buffer_builder.finish_cloned(); |
203 | | |
204 | 0 | let offsets = Buffer::from_slice_ref(self.offsets_builder.as_slice()); |
205 | | // Safety: safe by construction |
206 | 0 | let offsets = ScalarBuffer::from(offsets); |
207 | | |
208 | 0 | let sizes = Buffer::from_slice_ref(self.sizes_builder.as_slice()); |
209 | 0 | let sizes = ScalarBuffer::from(sizes); |
210 | | |
211 | 0 | let field = match &self.field { |
212 | 0 | Some(f) => f.clone(), |
213 | 0 | None => Arc::new(Field::new("item", values.data_type().clone(), true)), |
214 | | }; |
215 | | |
216 | 0 | GenericListViewArray::new(field, offsets, sizes, values, nulls) |
217 | 0 | } |
218 | | |
219 | | /// Returns the current offsets buffer as a slice |
220 | | pub fn offsets_slice(&self) -> &[OffsetSize] { |
221 | | self.offsets_builder.as_slice() |
222 | | } |
223 | | } |
224 | | |
225 | | impl<O, B, V, E> Extend<Option<V>> for GenericListViewBuilder<O, B> |
226 | | where |
227 | | O: OffsetSizeTrait, |
228 | | B: ArrayBuilder + Extend<E>, |
229 | | V: IntoIterator<Item = E>, |
230 | | { |
231 | | #[inline] |
232 | | fn extend<T: IntoIterator<Item = Option<V>>>(&mut self, iter: T) { |
233 | | for v in iter { |
234 | | match v { |
235 | | Some(elements) => { |
236 | | self.values_builder.extend(elements); |
237 | | self.append(true); |
238 | | } |
239 | | None => self.append(false), |
240 | | } |
241 | | } |
242 | | } |
243 | | } |
244 | | |
245 | | #[cfg(test)] |
246 | | mod tests { |
247 | | use super::*; |
248 | | use crate::builder::{make_builder, Int32Builder, ListViewBuilder}; |
249 | | use crate::cast::AsArray; |
250 | | use crate::types::Int32Type; |
251 | | use crate::{Array, Int32Array}; |
252 | | use arrow_schema::DataType; |
253 | | |
254 | | fn test_generic_list_view_array_builder_impl<O: OffsetSizeTrait>() { |
255 | | let values_builder = Int32Builder::with_capacity(10); |
256 | | let mut builder = GenericListViewBuilder::<O, _>::new(values_builder); |
257 | | |
258 | | // [[0, 1, 2], [3, 4, 5], [6, 7]] |
259 | | builder.values().append_value(0); |
260 | | builder.values().append_value(1); |
261 | | builder.values().append_value(2); |
262 | | builder.append(true); |
263 | | builder.values().append_value(3); |
264 | | builder.values().append_value(4); |
265 | | builder.values().append_value(5); |
266 | | builder.append(true); |
267 | | builder.values().append_value(6); |
268 | | builder.values().append_value(7); |
269 | | builder.append(true); |
270 | | let list_array = builder.finish(); |
271 | | |
272 | | let list_values = list_array.values().as_primitive::<Int32Type>(); |
273 | | assert_eq!(list_values.values(), &[0, 1, 2, 3, 4, 5, 6, 7]); |
274 | | assert_eq!(list_array.value_offsets(), [0, 3, 6].map(O::usize_as)); |
275 | | assert_eq!(list_array.value_sizes(), [3, 3, 2].map(O::usize_as)); |
276 | | assert_eq!(DataType::Int32, list_array.value_type()); |
277 | | assert_eq!(3, list_array.len()); |
278 | | assert_eq!(0, list_array.null_count()); |
279 | | assert_eq!(O::from_usize(6).unwrap(), list_array.value_offsets()[2]); |
280 | | assert_eq!(O::from_usize(2).unwrap(), list_array.value_sizes()[2]); |
281 | | for i in 0..2 { |
282 | | assert!(list_array.is_valid(i)); |
283 | | assert!(!list_array.is_null(i)); |
284 | | } |
285 | | } |
286 | | |
287 | | #[test] |
288 | | fn test_list_view_array_builder() { |
289 | | test_generic_list_view_array_builder_impl::<i32>() |
290 | | } |
291 | | |
292 | | #[test] |
293 | | fn test_large_list_view_array_builder() { |
294 | | test_generic_list_view_array_builder_impl::<i64>() |
295 | | } |
296 | | |
297 | | fn test_generic_list_view_array_builder_nulls_impl<O: OffsetSizeTrait>() { |
298 | | let values_builder = Int32Builder::with_capacity(10); |
299 | | let mut builder = GenericListViewBuilder::<O, _>::new(values_builder); |
300 | | |
301 | | // [[0, 1, 2], null, [3, null, 5], [6, 7]] |
302 | | builder.values().append_value(0); |
303 | | builder.values().append_value(1); |
304 | | builder.values().append_value(2); |
305 | | builder.append(true); |
306 | | builder.append(false); |
307 | | builder.values().append_value(3); |
308 | | builder.values().append_null(); |
309 | | builder.values().append_value(5); |
310 | | builder.append(true); |
311 | | builder.values().append_value(6); |
312 | | builder.values().append_value(7); |
313 | | builder.append(true); |
314 | | |
315 | | let list_array = builder.finish(); |
316 | | |
317 | | assert_eq!(DataType::Int32, list_array.value_type()); |
318 | | assert_eq!(4, list_array.len()); |
319 | | assert_eq!(1, list_array.null_count()); |
320 | | assert_eq!(O::from_usize(3).unwrap(), list_array.value_offsets()[2]); |
321 | | assert_eq!(O::from_usize(3).unwrap(), list_array.value_sizes()[2]); |
322 | | } |
323 | | |
324 | | #[test] |
325 | | fn test_list_view_array_builder_nulls() { |
326 | | test_generic_list_view_array_builder_nulls_impl::<i32>() |
327 | | } |
328 | | |
329 | | #[test] |
330 | | fn test_large_list_view_array_builder_nulls() { |
331 | | test_generic_list_view_array_builder_nulls_impl::<i64>() |
332 | | } |
333 | | |
334 | | #[test] |
335 | | fn test_list_view_array_builder_finish() { |
336 | | let values_builder = Int32Array::builder(5); |
337 | | let mut builder = ListViewBuilder::new(values_builder); |
338 | | |
339 | | builder.values().append_slice(&[1, 2, 3]); |
340 | | builder.append(true); |
341 | | builder.values().append_slice(&[4, 5, 6]); |
342 | | builder.append(true); |
343 | | |
344 | | let mut arr = builder.finish(); |
345 | | assert_eq!(2, arr.len()); |
346 | | assert!(builder.is_empty()); |
347 | | |
348 | | builder.values().append_slice(&[7, 8, 9]); |
349 | | builder.append(true); |
350 | | arr = builder.finish(); |
351 | | assert_eq!(1, arr.len()); |
352 | | assert!(builder.is_empty()); |
353 | | } |
354 | | |
355 | | #[test] |
356 | | fn test_list_view_array_builder_finish_cloned() { |
357 | | let values_builder = Int32Array::builder(5); |
358 | | let mut builder = ListViewBuilder::new(values_builder); |
359 | | |
360 | | builder.values().append_slice(&[1, 2, 3]); |
361 | | builder.append(true); |
362 | | builder.values().append_slice(&[4, 5, 6]); |
363 | | builder.append(true); |
364 | | |
365 | | let mut arr = builder.finish_cloned(); |
366 | | assert_eq!(2, arr.len()); |
367 | | assert!(!builder.is_empty()); |
368 | | |
369 | | builder.values().append_slice(&[7, 8, 9]); |
370 | | builder.append(true); |
371 | | arr = builder.finish(); |
372 | | assert_eq!(3, arr.len()); |
373 | | assert!(builder.is_empty()); |
374 | | } |
375 | | |
376 | | #[test] |
377 | | fn test_list_view_list_view_array_builder() { |
378 | | let primitive_builder = Int32Builder::with_capacity(10); |
379 | | let values_builder = ListViewBuilder::new(primitive_builder); |
380 | | let mut builder = ListViewBuilder::new(values_builder); |
381 | | |
382 | | // [[[1, 2], [3, 4]], [[5, 6, 7], null, [8]], null, [[9, 10]]] |
383 | | builder.values().values().append_value(1); |
384 | | builder.values().values().append_value(2); |
385 | | builder.values().append(true); |
386 | | builder.values().values().append_value(3); |
387 | | builder.values().values().append_value(4); |
388 | | builder.values().append(true); |
389 | | builder.append(true); |
390 | | |
391 | | builder.values().values().append_value(5); |
392 | | builder.values().values().append_value(6); |
393 | | builder.values().values().append_value(7); |
394 | | builder.values().append(true); |
395 | | builder.values().append(false); |
396 | | builder.values().values().append_value(8); |
397 | | builder.values().append(true); |
398 | | builder.append(true); |
399 | | |
400 | | builder.append(false); |
401 | | |
402 | | builder.values().values().append_value(9); |
403 | | builder.values().values().append_value(10); |
404 | | builder.values().append(true); |
405 | | builder.append(true); |
406 | | |
407 | | let l1 = builder.finish(); |
408 | | |
409 | | assert_eq!(4, l1.len()); |
410 | | assert_eq!(1, l1.null_count()); |
411 | | |
412 | | assert_eq!(l1.value_offsets(), &[0, 2, 5, 5]); |
413 | | assert_eq!(l1.value_sizes(), &[2, 3, 0, 1]); |
414 | | |
415 | | let l2 = l1.values().as_list_view::<i32>(); |
416 | | |
417 | | assert_eq!(6, l2.len()); |
418 | | assert_eq!(1, l2.null_count()); |
419 | | assert_eq!(l2.value_offsets(), &[0, 2, 4, 7, 7, 8]); |
420 | | assert_eq!(l2.value_sizes(), &[2, 2, 3, 0, 1, 2]); |
421 | | |
422 | | let i1 = l2.values().as_primitive::<Int32Type>(); |
423 | | assert_eq!(10, i1.len()); |
424 | | assert_eq!(0, i1.null_count()); |
425 | | assert_eq!(i1.values(), &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); |
426 | | } |
427 | | |
428 | | #[test] |
429 | | fn test_extend() { |
430 | | let mut builder = ListViewBuilder::new(Int32Builder::new()); |
431 | | builder.extend([ |
432 | | Some(vec![Some(1), Some(2), Some(7), None]), |
433 | | Some(vec![]), |
434 | | Some(vec![Some(4), Some(5)]), |
435 | | None, |
436 | | ]); |
437 | | |
438 | | let array = builder.finish(); |
439 | | assert_eq!(array.value_offsets(), [0, 4, 4, 6]); |
440 | | assert_eq!(array.value_sizes(), [4, 0, 2, 0]); |
441 | | assert_eq!(array.null_count(), 1); |
442 | | assert!(array.is_null(3)); |
443 | | let elements = array.values().as_primitive::<Int32Type>(); |
444 | | assert_eq!(elements.values(), &[1, 2, 7, 0, 4, 5]); |
445 | | assert_eq!(elements.null_count(), 1); |
446 | | assert!(elements.is_null(3)); |
447 | | } |
448 | | |
449 | | #[test] |
450 | | fn test_boxed_primitive_array_builder() { |
451 | | let values_builder = make_builder(&DataType::Int32, 5); |
452 | | let mut builder = ListViewBuilder::new(values_builder); |
453 | | |
454 | | builder |
455 | | .values() |
456 | | .as_any_mut() |
457 | | .downcast_mut::<Int32Builder>() |
458 | | .expect("should be an Int32Builder") |
459 | | .append_slice(&[1, 2, 3]); |
460 | | builder.append(true); |
461 | | |
462 | | builder |
463 | | .values() |
464 | | .as_any_mut() |
465 | | .downcast_mut::<Int32Builder>() |
466 | | .expect("should be an Int32Builder") |
467 | | .append_slice(&[4, 5, 6]); |
468 | | builder.append(true); |
469 | | |
470 | | let arr = builder.finish(); |
471 | | assert_eq!(2, arr.len()); |
472 | | |
473 | | let elements = arr.values().as_primitive::<Int32Type>(); |
474 | | assert_eq!(elements.values(), &[1, 2, 3, 4, 5, 6]); |
475 | | } |
476 | | |
477 | | #[test] |
478 | | fn test_boxed_list_view_list_view_array_builder() { |
479 | | // This test is same as `test_list_list_array_builder` but uses boxed builders. |
480 | | let values_builder = make_builder( |
481 | | &DataType::ListView(Arc::new(Field::new("item", DataType::Int32, true))), |
482 | | 10, |
483 | | ); |
484 | | test_boxed_generic_list_view_generic_list_view_array_builder::<i32>(values_builder); |
485 | | } |
486 | | |
487 | | #[test] |
488 | | fn test_boxed_large_list_view_large_list_view_array_builder() { |
489 | | // This test is same as `test_list_list_array_builder` but uses boxed builders. |
490 | | let values_builder = make_builder( |
491 | | &DataType::LargeListView(Arc::new(Field::new("item", DataType::Int32, true))), |
492 | | 10, |
493 | | ); |
494 | | test_boxed_generic_list_view_generic_list_view_array_builder::<i64>(values_builder); |
495 | | } |
496 | | |
497 | | fn test_boxed_generic_list_view_generic_list_view_array_builder<O>( |
498 | | values_builder: Box<dyn ArrayBuilder>, |
499 | | ) where |
500 | | O: OffsetSizeTrait + PartialEq, |
501 | | { |
502 | | let mut builder: GenericListViewBuilder<O, Box<dyn ArrayBuilder>> = |
503 | | GenericListViewBuilder::<O, Box<dyn ArrayBuilder>>::new(values_builder); |
504 | | |
505 | | // [[[1, 2], [3, 4]], [[5, 6, 7], null, [8]], null, [[9, 10]]] |
506 | | builder |
507 | | .values() |
508 | | .as_any_mut() |
509 | | .downcast_mut::<GenericListViewBuilder<O, Box<dyn ArrayBuilder>>>() |
510 | | .expect("should be an (Large)ListViewBuilder") |
511 | | .values() |
512 | | .as_any_mut() |
513 | | .downcast_mut::<Int32Builder>() |
514 | | .expect("should be an Int32Builder") |
515 | | .append_value(1); |
516 | | builder |
517 | | .values() |
518 | | .as_any_mut() |
519 | | .downcast_mut::<GenericListViewBuilder<O, Box<dyn ArrayBuilder>>>() |
520 | | .expect("should be an (Large)ListViewBuilder") |
521 | | .values() |
522 | | .as_any_mut() |
523 | | .downcast_mut::<Int32Builder>() |
524 | | .expect("should be an Int32Builder") |
525 | | .append_value(2); |
526 | | builder |
527 | | .values() |
528 | | .as_any_mut() |
529 | | .downcast_mut::<GenericListViewBuilder<O, Box<dyn ArrayBuilder>>>() |
530 | | .expect("should be an (Large)ListViewBuilder") |
531 | | .append(true); |
532 | | builder |
533 | | .values() |
534 | | .as_any_mut() |
535 | | .downcast_mut::<GenericListViewBuilder<O, Box<dyn ArrayBuilder>>>() |
536 | | .expect("should be an (Large)ListViewBuilder") |
537 | | .values() |
538 | | .as_any_mut() |
539 | | .downcast_mut::<Int32Builder>() |
540 | | .expect("should be an Int32Builder") |
541 | | .append_value(3); |
542 | | builder |
543 | | .values() |
544 | | .as_any_mut() |
545 | | .downcast_mut::<GenericListViewBuilder<O, Box<dyn ArrayBuilder>>>() |
546 | | .expect("should be an (Large)ListViewBuilder") |
547 | | .values() |
548 | | .as_any_mut() |
549 | | .downcast_mut::<Int32Builder>() |
550 | | .expect("should be an Int32Builder") |
551 | | .append_value(4); |
552 | | builder |
553 | | .values() |
554 | | .as_any_mut() |
555 | | .downcast_mut::<GenericListViewBuilder<O, Box<dyn ArrayBuilder>>>() |
556 | | .expect("should be an (Large)ListViewBuilder") |
557 | | .append(true); |
558 | | builder.append(true); |
559 | | |
560 | | builder |
561 | | .values() |
562 | | .as_any_mut() |
563 | | .downcast_mut::<GenericListViewBuilder<O, Box<dyn ArrayBuilder>>>() |
564 | | .expect("should be an (Large)ListViewBuilder") |
565 | | .values() |
566 | | .as_any_mut() |
567 | | .downcast_mut::<Int32Builder>() |
568 | | .expect("should be an Int32Builder") |
569 | | .append_value(5); |
570 | | builder |
571 | | .values() |
572 | | .as_any_mut() |
573 | | .downcast_mut::<GenericListViewBuilder<O, Box<dyn ArrayBuilder>>>() |
574 | | .expect("should be an (Large)ListViewBuilder") |
575 | | .values() |
576 | | .as_any_mut() |
577 | | .downcast_mut::<Int32Builder>() |
578 | | .expect("should be an Int32Builder") |
579 | | .append_value(6); |
580 | | builder |
581 | | .values() |
582 | | .as_any_mut() |
583 | | .downcast_mut::<GenericListViewBuilder<O, Box<dyn ArrayBuilder>>>() |
584 | | .expect("should be an (Large)ListViewBuilder") |
585 | | .values() |
586 | | .as_any_mut() |
587 | | .downcast_mut::<Int32Builder>() |
588 | | .expect("should be an (Large)ListViewBuilder") |
589 | | .append_value(7); |
590 | | builder |
591 | | .values() |
592 | | .as_any_mut() |
593 | | .downcast_mut::<GenericListViewBuilder<O, Box<dyn ArrayBuilder>>>() |
594 | | .expect("should be an (Large)ListViewBuilder") |
595 | | .append(true); |
596 | | builder |
597 | | .values() |
598 | | .as_any_mut() |
599 | | .downcast_mut::<GenericListViewBuilder<O, Box<dyn ArrayBuilder>>>() |
600 | | .expect("should be an (Large)ListViewBuilder") |
601 | | .append(false); |
602 | | builder |
603 | | .values() |
604 | | .as_any_mut() |
605 | | .downcast_mut::<GenericListViewBuilder<O, Box<dyn ArrayBuilder>>>() |
606 | | .expect("should be an (Large)ListViewBuilder") |
607 | | .values() |
608 | | .as_any_mut() |
609 | | .downcast_mut::<Int32Builder>() |
610 | | .expect("should be an Int32Builder") |
611 | | .append_value(8); |
612 | | builder |
613 | | .values() |
614 | | .as_any_mut() |
615 | | .downcast_mut::<GenericListViewBuilder<O, Box<dyn ArrayBuilder>>>() |
616 | | .expect("should be an (Large)ListViewBuilder") |
617 | | .append(true); |
618 | | builder.append(true); |
619 | | |
620 | | builder.append(false); |
621 | | |
622 | | builder |
623 | | .values() |
624 | | .as_any_mut() |
625 | | .downcast_mut::<GenericListViewBuilder<O, Box<dyn ArrayBuilder>>>() |
626 | | .expect("should be an (Large)ListViewBuilder") |
627 | | .values() |
628 | | .as_any_mut() |
629 | | .downcast_mut::<Int32Builder>() |
630 | | .expect("should be an Int32Builder") |
631 | | .append_value(9); |
632 | | builder |
633 | | .values() |
634 | | .as_any_mut() |
635 | | .downcast_mut::<GenericListViewBuilder<O, Box<dyn ArrayBuilder>>>() |
636 | | .expect("should be an (Large)ListViewBuilder") |
637 | | .values() |
638 | | .as_any_mut() |
639 | | .downcast_mut::<Int32Builder>() |
640 | | .expect("should be an Int32Builder") |
641 | | .append_value(10); |
642 | | builder |
643 | | .values() |
644 | | .as_any_mut() |
645 | | .downcast_mut::<GenericListViewBuilder<O, Box<dyn ArrayBuilder>>>() |
646 | | .expect("should be an (Large)ListViewBuilder") |
647 | | .append(true); |
648 | | builder.append(true); |
649 | | |
650 | | let l1 = builder.finish(); |
651 | | assert_eq!(4, l1.len()); |
652 | | assert_eq!(1, l1.null_count()); |
653 | | assert_eq!(l1.value_offsets(), &[0, 2, 5, 5].map(O::usize_as)); |
654 | | assert_eq!(l1.value_sizes(), &[2, 3, 0, 1].map(O::usize_as)); |
655 | | |
656 | | let l2 = l1.values().as_list_view::<O>(); |
657 | | assert_eq!(6, l2.len()); |
658 | | assert_eq!(1, l2.null_count()); |
659 | | assert_eq!(l2.value_offsets(), &[0, 2, 4, 7, 7, 8].map(O::usize_as)); |
660 | | assert_eq!(l2.value_sizes(), &[2, 2, 3, 0, 1, 2].map(O::usize_as)); |
661 | | |
662 | | let i1 = l2.values().as_primitive::<Int32Type>(); |
663 | | assert_eq!(10, i1.len()); |
664 | | assert_eq!(0, i1.null_count()); |
665 | | assert_eq!(i1.values(), &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); |
666 | | } |
667 | | |
668 | | #[test] |
669 | | fn test_with_field() { |
670 | | let field = Arc::new(Field::new("bar", DataType::Int32, false)); |
671 | | let mut builder = ListViewBuilder::new(Int32Builder::new()).with_field(field.clone()); |
672 | | builder.append_value([Some(1), Some(2), Some(3)]); |
673 | | builder.append_null(); // This is fine as nullability refers to nullability of values |
674 | | builder.append_value([Some(4)]); |
675 | | let array = builder.finish(); |
676 | | assert_eq!(array.len(), 3); |
677 | | assert_eq!(array.data_type(), &DataType::ListView(field.clone())); |
678 | | |
679 | | builder.append_value([Some(4), Some(5)]); |
680 | | let array = builder.finish(); |
681 | | assert_eq!(array.data_type(), &DataType::ListView(field)); |
682 | | assert_eq!(array.len(), 1); |
683 | | } |
684 | | |
685 | | #[test] |
686 | | #[should_panic( |
687 | | expected = r#"Non-nullable field of ListViewArray \"item\" cannot contain nulls"# |
688 | | )] |
689 | | // If a non-nullable type is declared but a null value is used, it will be intercepted by the null check. |
690 | | fn test_checks_nullability() { |
691 | | let field = Arc::new(Field::new("item", DataType::Int32, false)); |
692 | | let mut builder = ListViewBuilder::new(Int32Builder::new()).with_field(field.clone()); |
693 | | builder.append_value([Some(1), None]); |
694 | | builder.finish(); |
695 | | } |
696 | | |
697 | | #[test] |
698 | | #[should_panic(expected = "ListViewArray expected data type Int64 got Int32")] |
699 | | // If the declared type does not match the actual appended type, it will be intercepted by type checking in the finish function. |
700 | | fn test_checks_data_type() { |
701 | | let field = Arc::new(Field::new("item", DataType::Int64, false)); |
702 | | let mut builder = ListViewBuilder::new(Int32Builder::new()).with_field(field.clone()); |
703 | | builder.append_value([Some(1)]); |
704 | | builder.finish(); |
705 | | } |
706 | | } |