• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

vortex-data / vortex / 16509961961

24 Jul 2025 11:24PM UTC coverage: 81.792% (+0.7%) from 81.091%
16509961961

Pull #4002

github

web-flow
Merge fe709c0ab into f14d4e4bc
Pull Request #4002: fix: Implement compact for ListArray

115 of 128 new or added lines in 6 files covered. (89.84%)

234 existing lines in 12 files now uncovered.

43260 of 52890 relevant lines covered (81.79%)

170683.44 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

95.3
/vortex-array/src/arrow/convert.rs
1
// SPDX-License-Identifier: Apache-2.0
2
// SPDX-FileCopyrightText: Copyright the Vortex contributors
3

4
use arrow_array::array::{
5
    Array as ArrowArray, ArrowPrimitiveType, BooleanArray as ArrowBooleanArray, GenericByteArray,
6
    NullArray as ArrowNullArray, OffsetSizeTrait, PrimitiveArray as ArrowPrimitiveArray,
7
    StructArray as ArrowStructArray,
8
};
9
use arrow_array::cast::{AsArray, as_null_array};
10
use arrow_array::types::{
11
    ByteArrayType, ByteViewType, Date32Type, Date64Type, Decimal128Type, Decimal256Type,
12
    Float16Type, Float32Type, Float64Type, Int8Type, Int16Type, Int32Type, Int64Type,
13
    Time32MillisecondType, Time32SecondType, Time64MicrosecondType, Time64NanosecondType,
14
    TimestampMicrosecondType, TimestampMillisecondType, TimestampNanosecondType,
15
    TimestampSecondType, UInt8Type, UInt16Type, UInt32Type, UInt64Type,
16
};
17
use arrow_array::{GenericByteViewArray, GenericListArray, RecordBatch, make_array};
18
use arrow_buffer::buffer::{NullBuffer, OffsetBuffer};
19
use arrow_buffer::{ArrowNativeType, BooleanBuffer, Buffer as ArrowBuffer, ScalarBuffer};
20
use arrow_schema::{DataType, TimeUnit as ArrowTimeUnit};
21
use itertools::Itertools;
22
use vortex_buffer::{Alignment, Buffer, ByteBuffer};
23
use vortex_dtype::datetime::TimeUnit;
24
use vortex_dtype::{DType, DecimalDType, NativePType, PType};
25
use vortex_error::{VortexExpect as _, vortex_panic};
26
use vortex_scalar::i256;
27

28
use crate::arrays::{
29
    BoolArray, DecimalArray, ListArray, NullArray, PrimitiveArray, StructArray, TemporalArray,
30
    VarBinArray, VarBinViewArray,
31
};
32
use crate::arrow::FromArrowArray;
33
use crate::validity::Validity;
34
use crate::{ArrayRef, IntoArray};
35

36
impl IntoArray for ArrowBuffer {
37
    fn into_array(self) -> ArrayRef {
1✔
38
        PrimitiveArray::from_byte_buffer(
1✔
39
            ByteBuffer::from_arrow_buffer(self, Alignment::of::<u8>()),
1✔
40
            PType::U8,
1✔
41
            Validity::NonNullable,
1✔
42
        )
1✔
43
        .into_array()
1✔
44
    }
1✔
45
}
46

47
impl IntoArray for BooleanBuffer {
48
    fn into_array(self) -> ArrayRef {
1✔
49
        BoolArray::new(self, Validity::NonNullable).into_array()
1✔
50
    }
1✔
51
}
52

53
impl<T> IntoArray for ScalarBuffer<T>
54
where
55
    T: ArrowNativeType + NativePType,
56
{
57
    fn into_array(self) -> ArrayRef {
1✔
58
        PrimitiveArray::new(
1✔
59
            Buffer::<T>::from_arrow_scalar_buffer(self),
1✔
60
            Validity::NonNullable,
1✔
61
        )
1✔
62
        .into_array()
1✔
63
    }
1✔
64
}
65

66
impl<O> IntoArray for OffsetBuffer<O>
67
where
68
    O: NativePType + OffsetSizeTrait,
69
{
70
    fn into_array(self) -> ArrayRef {
57✔
71
        let primitive = PrimitiveArray::new(
57✔
72
            Buffer::from_arrow_scalar_buffer(self.into_inner()),
57✔
73
            Validity::NonNullable,
57✔
74
        );
75

76
        primitive.into_array()
57✔
77
    }
57✔
78
}
79

80
macro_rules! impl_from_arrow_primitive {
81
    ($ty:path) => {
82
        impl FromArrowArray<&ArrowPrimitiveArray<$ty>> for ArrayRef {
83
            fn from_arrow(value: &ArrowPrimitiveArray<$ty>, nullable: bool) -> Self {
4,182✔
84
                let buffer = Buffer::from_arrow_scalar_buffer(value.values().clone());
4,182✔
85
                let validity = nulls(value.nulls(), nullable);
4,182✔
86
                PrimitiveArray::new(buffer, validity).into_array()
4,182✔
87
            }
4,182✔
88
        }
89
    };
90
}
91

92
impl_from_arrow_primitive!(Int8Type);
93
impl_from_arrow_primitive!(Int16Type);
94
impl_from_arrow_primitive!(Int32Type);
95
impl_from_arrow_primitive!(Int64Type);
96
impl_from_arrow_primitive!(UInt8Type);
97
impl_from_arrow_primitive!(UInt16Type);
98
impl_from_arrow_primitive!(UInt32Type);
99
impl_from_arrow_primitive!(UInt64Type);
100
impl_from_arrow_primitive!(Float16Type);
101
impl_from_arrow_primitive!(Float32Type);
102
impl_from_arrow_primitive!(Float64Type);
103

104
impl FromArrowArray<&ArrowPrimitiveArray<Decimal128Type>> for ArrayRef {
105
    fn from_arrow(array: &ArrowPrimitiveArray<Decimal128Type>, nullable: bool) -> Self {
28✔
106
        let decimal_type = DecimalDType::new(array.precision(), array.scale());
28✔
107
        let buffer = Buffer::from_arrow_scalar_buffer(array.values().clone());
28✔
108
        let validity = nulls(array.nulls(), nullable);
28✔
109
        DecimalArray::new(buffer, decimal_type, validity).into_array()
28✔
110
    }
28✔
111
}
112

113
impl FromArrowArray<&ArrowPrimitiveArray<Decimal256Type>> for ArrayRef {
114
    fn from_arrow(array: &ArrowPrimitiveArray<Decimal256Type>, nullable: bool) -> Self {
2✔
115
        let decimal_type = DecimalDType::new(array.precision(), array.scale());
2✔
116
        let buffer = Buffer::from_arrow_scalar_buffer(array.values().clone());
2✔
117
        // SAFETY: Our i256 implementation has the same bit-pattern representation of the
118
        //  arrow_buffer::i256 type. It is safe to treat values held inside the buffer as values
119
        //  of either type.
120
        let buffer =
2✔
121
            unsafe { std::mem::transmute::<Buffer<arrow_buffer::i256>, Buffer<i256>>(buffer) };
2✔
122
        let validity = nulls(array.nulls(), nullable);
2✔
123
        DecimalArray::new(buffer, decimal_type, validity).into_array()
2✔
124
    }
2✔
125
}
126

127
macro_rules! impl_from_arrow_temporal {
128
    ($ty:path) => {
129
        impl FromArrowArray<&ArrowPrimitiveArray<$ty>> for ArrayRef {
130
            fn from_arrow(value: &ArrowPrimitiveArray<$ty>, nullable: bool) -> Self {
108✔
131
                temporal_array(value, nullable)
108✔
132
            }
108✔
133
        }
134
    };
135
}
136

137
// timestamp
138
impl_from_arrow_temporal!(TimestampSecondType);
139
impl_from_arrow_temporal!(TimestampMillisecondType);
140
impl_from_arrow_temporal!(TimestampMicrosecondType);
141
impl_from_arrow_temporal!(TimestampNanosecondType);
142

143
// time
144
impl_from_arrow_temporal!(Time32SecondType);
145
impl_from_arrow_temporal!(Time32MillisecondType);
146
impl_from_arrow_temporal!(Time64MicrosecondType);
147
impl_from_arrow_temporal!(Time64NanosecondType);
148

149
// date
150
impl_from_arrow_temporal!(Date32Type);
151
impl_from_arrow_temporal!(Date64Type);
152

153
fn temporal_array<T: ArrowPrimitiveType>(value: &ArrowPrimitiveArray<T>, nullable: bool) -> ArrayRef
108✔
154
where
108✔
155
    T::Native: NativePType,
108✔
156
{
157
    let arr = PrimitiveArray::new(
108✔
158
        Buffer::from_arrow_scalar_buffer(value.values().clone()),
108✔
159
        nulls(value.nulls(), nullable),
108✔
160
    )
161
    .into_array();
108✔
162

163
    match T::DATA_TYPE {
108✔
164
        DataType::Timestamp(time_unit, tz) => {
82✔
165
            let tz = tz.map(|s| s.to_string());
82✔
166
            TemporalArray::new_timestamp(arr, time_unit.into(), tz).into()
82✔
167
        }
168
        DataType::Time32(time_unit) => TemporalArray::new_time(arr, time_unit.into()).into(),
4✔
169
        DataType::Time64(time_unit) => TemporalArray::new_time(arr, time_unit.into()).into(),
4✔
170
        DataType::Date32 => TemporalArray::new_date(arr, TimeUnit::D).into(),
16✔
171
        DataType::Date64 => TemporalArray::new_date(arr, TimeUnit::Ms).into(),
2✔
172
        DataType::Duration(_) => unimplemented!(),
×
UNCOV
173
        DataType::Interval(_) => unimplemented!(),
×
174
        _ => vortex_panic!("Invalid temporal type: {}", T::DATA_TYPE),
×
175
    }
176
}
108✔
177

178
impl<T: ByteArrayType> FromArrowArray<&GenericByteArray<T>> for ArrayRef
179
where
180
    <T as ByteArrayType>::Offset: NativePType,
181
{
182
    fn from_arrow(value: &GenericByteArray<T>, nullable: bool) -> Self {
51✔
183
        let dtype = match T::DATA_TYPE {
51✔
184
            DataType::Binary | DataType::LargeBinary => DType::Binary(nullable.into()),
4✔
185
            DataType::Utf8 | DataType::LargeUtf8 => DType::Utf8(nullable.into()),
47✔
UNCOV
186
            _ => vortex_panic!("Invalid data type for ByteArray: {}", T::DATA_TYPE),
×
187
        };
188
        VarBinArray::try_new(
51✔
189
            value.offsets().clone().into_array(),
51✔
190
            ByteBuffer::from_arrow_buffer(value.values().clone(), Alignment::of::<u8>()),
51✔
191
            dtype,
51✔
192
            nulls(value.nulls(), nullable),
51✔
193
        )
51✔
194
        .vortex_expect("Failed to convert Arrow GenericByteArray to Vortex VarBinArray")
51✔
195
        .into_array()
51✔
196
    }
51✔
197
}
198

199
impl<T: ByteViewType> FromArrowArray<&GenericByteViewArray<T>> for ArrayRef {
200
    fn from_arrow(value: &GenericByteViewArray<T>, nullable: bool) -> Self {
1,979✔
201
        let dtype = match T::DATA_TYPE {
1,979✔
202
            DataType::BinaryView => DType::Binary(nullable.into()),
43✔
203
            DataType::Utf8View => DType::Utf8(nullable.into()),
1,936✔
UNCOV
204
            _ => vortex_panic!("Invalid data type for ByteViewArray: {}", T::DATA_TYPE),
×
205
        };
206

207
        let views_buffer = Buffer::from_byte_buffer(
1,979✔
208
            Buffer::from_arrow_scalar_buffer(value.views().clone()).into_byte_buffer(),
1,979✔
209
        );
210

211
        VarBinViewArray::try_new(
1,979✔
212
            views_buffer,
1,979✔
213
            value
1,979✔
214
                .data_buffers()
1,979✔
215
                .iter()
1,979✔
216
                .map(|b| ByteBuffer::from_arrow_buffer(b.clone(), Alignment::of::<u8>()))
2,153✔
217
                .collect::<Vec<_>>(),
1,979✔
218
            dtype,
1,979✔
219
            nulls(value.nulls(), nullable),
1,979✔
220
        )
221
        .vortex_expect("Failed to convert Arrow GenericByteViewArray to Vortex VarBinViewArray")
1,979✔
222
        .into_array()
1,979✔
223
    }
1,979✔
224
}
225

226
impl FromArrowArray<&ArrowBooleanArray> for ArrayRef {
227
    fn from_arrow(value: &ArrowBooleanArray, nullable: bool) -> Self {
8,211✔
228
        BoolArray::new(value.values().clone(), nulls(value.nulls(), nullable)).into_array()
8,211✔
229
    }
8,211✔
230
}
231

232
/// Strip out the nulls from this array and return a new array without nulls.
233
fn remove_nulls(data: arrow_data::ArrayData) -> arrow_data::ArrayData {
4✔
234
    if data.null_count() == 0 {
4✔
235
        // No nulls to remove, return the array as is
UNCOV
236
        return data;
×
237
    }
4✔
238

239
    let children = match data.data_type() {
4✔
240
        DataType::Struct(fields) => Some(
1✔
241
            fields
1✔
242
                .iter()
1✔
243
                .zip(data.child_data().iter())
1✔
244
                .map(|(field, child_data)| {
1✔
245
                    if field.is_nullable() {
1✔
UNCOV
246
                        child_data.clone()
×
247
                    } else {
248
                        remove_nulls(child_data.clone())
1✔
249
                    }
250
                })
1✔
251
                .collect_vec(),
1✔
252
        ),
UNCOV
253
        DataType::List(f)
×
UNCOV
254
        | DataType::LargeList(f)
×
UNCOV
255
        | DataType::ListView(f)
×
256
        | DataType::LargeListView(f)
×
257
        | DataType::FixedSizeList(f, _)
×
258
            if !f.is_nullable() =>
×
259
        {
260
            // All list types only have one child
261
            assert_eq!(
×
UNCOV
262
                data.child_data().len(),
×
263
                1,
264
                "List types should have one child"
×
265
            );
UNCOV
266
            Some(vec![remove_nulls(data.child_data()[0].clone())])
×
267
        }
268
        _ => None,
3✔
269
    };
270

271
    let mut builder = data.into_builder().nulls(None);
4✔
272
    if let Some(children) = children {
4✔
273
        builder = builder.child_data(children);
1✔
274
    }
3✔
275
    builder
4✔
276
        .build()
4✔
277
        .vortex_expect("reconstructing array without nulls")
4✔
278
}
4✔
279

280
impl FromArrowArray<&ArrowStructArray> for ArrayRef {
281
    fn from_arrow(value: &ArrowStructArray, nullable: bool) -> Self {
138✔
282
        StructArray::try_new(
138✔
283
            value.column_names().iter().copied().collect(),
138✔
284
            value
138✔
285
                .columns()
138✔
286
                .iter()
138✔
287
                .zip(value.fields())
138✔
288
                .map(|(c, field)| {
1,019✔
289
                    // Arrow pushes down nulls, even into non-nullable fields. So we strip them
290
                    // out here because Vortex is a little more strict.
291
                    if c.null_count() > 0 && !field.is_nullable() {
1,019✔
292
                        let stripped = make_array(remove_nulls(c.into_data()));
3✔
293
                        Self::from_arrow(stripped.as_ref(), false)
3✔
294
                    } else {
295
                        Self::from_arrow(c.as_ref(), field.is_nullable())
1,016✔
296
                    }
297
                })
1,019✔
298
                .collect(),
138✔
299
            value.len(),
138✔
300
            nulls(value.nulls(), nullable),
138✔
301
        )
302
        .vortex_expect("Failed to convert Arrow StructArray to Vortex StructArray")
138✔
303
        .into_array()
138✔
304
    }
138✔
305
}
306

307
impl<O: OffsetSizeTrait + NativePType> FromArrowArray<&GenericListArray<O>> for ArrayRef {
308
    fn from_arrow(value: &GenericListArray<O>, nullable: bool) -> Self {
5✔
309
        // Extract the validity of the underlying element array
310
        let elem_nullable = match value.data_type() {
5✔
311
            DataType::List(field) => field.is_nullable(),
3✔
312
            DataType::LargeList(field) => field.is_nullable(),
2✔
UNCOV
313
            dt => vortex_panic!("Invalid data type for ListArray: {dt}"),
×
314
        };
315
        ListArray::try_new(
5✔
316
            Self::from_arrow(value.values().as_ref(), elem_nullable),
5✔
317
            // offsets are always non-nullable
5✔
318
            value.offsets().clone().into_array(),
5✔
319
            nulls(value.nulls(), nullable),
5✔
320
        )
5✔
321
        .vortex_expect("Failed to convert Arrow StructArray to Vortex StructArray")
5✔
322
        .into_array()
5✔
323
    }
5✔
324
}
325

326
impl FromArrowArray<&ArrowNullArray> for ArrayRef {
327
    fn from_arrow(value: &ArrowNullArray, nullable: bool) -> Self {
1✔
328
        assert!(nullable);
1✔
329
        NullArray::new(value.len()).into_array()
1✔
330
    }
1✔
331
}
332

333
fn nulls(nulls: Option<&NullBuffer>, nullable: bool) -> Validity {
14,703✔
334
    if nullable {
14,703✔
335
        nulls
9,650✔
336
            .map(|nulls| {
9,650✔
337
                if nulls.null_count() == nulls.len() {
2,399✔
338
                    Validity::AllInvalid
5✔
339
                } else {
340
                    Validity::from(nulls.inner().clone())
2,394✔
341
                }
342
            })
2,399✔
343
            .unwrap_or_else(|| Validity::AllValid)
9,650✔
344
    } else {
345
        assert!(nulls.map(|x| x.null_count() == 0).unwrap_or(true));
5,053✔
346
        Validity::NonNullable
5,053✔
347
    }
348
}
14,703✔
349

350
impl FromArrowArray<&dyn ArrowArray> for ArrayRef {
351
    fn from_arrow(array: &dyn ArrowArray, nullable: bool) -> Self {
6,297✔
352
        match array.data_type() {
6,297✔
353
            DataType::Boolean => Self::from_arrow(array.as_boolean(), nullable),
1✔
354
            DataType::UInt8 => Self::from_arrow(array.as_primitive::<UInt8Type>(), nullable),
43✔
355
            DataType::UInt16 => Self::from_arrow(array.as_primitive::<UInt16Type>(), nullable),
528✔
356
            DataType::UInt32 => Self::from_arrow(array.as_primitive::<UInt32Type>(), nullable),
10✔
357
            DataType::UInt64 => Self::from_arrow(array.as_primitive::<UInt64Type>(), nullable),
639✔
358
            DataType::Int8 => Self::from_arrow(array.as_primitive::<Int8Type>(), nullable),
6✔
359
            DataType::Int16 => Self::from_arrow(array.as_primitive::<Int16Type>(), nullable),
6✔
360
            DataType::Int32 => Self::from_arrow(array.as_primitive::<Int32Type>(), nullable),
2,287✔
361
            DataType::Int64 => Self::from_arrow(array.as_primitive::<Int64Type>(), nullable),
264✔
362
            DataType::Float16 => Self::from_arrow(array.as_primitive::<Float16Type>(), nullable),
2✔
363
            DataType::Float32 => Self::from_arrow(array.as_primitive::<Float32Type>(), nullable),
4✔
364
            DataType::Float64 => Self::from_arrow(array.as_primitive::<Float64Type>(), nullable),
371✔
365
            DataType::Utf8 => Self::from_arrow(array.as_string::<i32>(), nullable),
6✔
366
            DataType::LargeUtf8 => Self::from_arrow(array.as_string::<i64>(), nullable),
37✔
UNCOV
367
            DataType::Binary => Self::from_arrow(array.as_binary::<i32>(), nullable),
×
UNCOV
368
            DataType::LargeBinary => Self::from_arrow(array.as_binary::<i64>(), nullable),
×
369
            DataType::BinaryView => Self::from_arrow(array.as_binary_view(), nullable),
41✔
370
            DataType::Utf8View => Self::from_arrow(array.as_string_view(), nullable),
1,934✔
371
            DataType::Struct(_) => Self::from_arrow(array.as_struct(), nullable),
4✔
UNCOV
372
            DataType::List(_) => Self::from_arrow(array.as_list::<i32>(), nullable),
×
UNCOV
373
            DataType::LargeList(_) => Self::from_arrow(array.as_list::<i64>(), nullable),
×
UNCOV
374
            DataType::Null => Self::from_arrow(as_null_array(array), nullable),
×
375
            DataType::Timestamp(u, _) => match u {
74✔
376
                ArrowTimeUnit::Second => {
UNCOV
377
                    Self::from_arrow(array.as_primitive::<TimestampSecondType>(), nullable)
×
378
                }
379
                ArrowTimeUnit::Millisecond => {
UNCOV
380
                    Self::from_arrow(array.as_primitive::<TimestampMillisecondType>(), nullable)
×
381
                }
382
                ArrowTimeUnit::Microsecond => {
383
                    Self::from_arrow(array.as_primitive::<TimestampMicrosecondType>(), nullable)
74✔
384
                }
385
                ArrowTimeUnit::Nanosecond => {
UNCOV
386
                    Self::from_arrow(array.as_primitive::<TimestampNanosecondType>(), nullable)
×
387
                }
388
            },
389
            DataType::Date32 => Self::from_arrow(array.as_primitive::<Date32Type>(), nullable),
14✔
UNCOV
390
            DataType::Date64 => Self::from_arrow(array.as_primitive::<Date64Type>(), nullable),
×
UNCOV
391
            DataType::Time32(u) => match u {
×
392
                ArrowTimeUnit::Second => {
UNCOV
393
                    Self::from_arrow(array.as_primitive::<Time32SecondType>(), nullable)
×
394
                }
395
                ArrowTimeUnit::Millisecond => {
UNCOV
396
                    Self::from_arrow(array.as_primitive::<Time32MillisecondType>(), nullable)
×
397
                }
UNCOV
398
                _ => unreachable!(),
×
399
            },
UNCOV
400
            DataType::Time64(u) => match u {
×
401
                ArrowTimeUnit::Microsecond => {
UNCOV
402
                    Self::from_arrow(array.as_primitive::<Time64MicrosecondType>(), nullable)
×
403
                }
404
                ArrowTimeUnit::Nanosecond => {
405
                    Self::from_arrow(array.as_primitive::<Time64NanosecondType>(), nullable)
×
406
                }
UNCOV
407
                _ => unreachable!(),
×
408
            },
409
            DataType::Decimal128(..) => {
410
                Self::from_arrow(array.as_primitive::<Decimal128Type>(), nullable)
26✔
411
            }
412
            DataType::Decimal256(..) => {
413
                Self::from_arrow(array.as_primitive::<Decimal256Type>(), nullable)
×
414
            }
415
            _ => vortex_panic!(
×
UNCOV
416
                "Array encoding not implemented for Arrow data type {}",
×
417
                array.data_type().clone()
×
418
            ),
419
        }
420
    }
6,297✔
421
}
422

423
impl FromArrowArray<RecordBatch> for ArrayRef {
424
    fn from_arrow(array: RecordBatch, nullable: bool) -> Self {
131✔
425
        ArrayRef::from_arrow(&arrow_array::StructArray::from(array), nullable)
131✔
426
    }
131✔
427
}
428

429
impl FromArrowArray<&RecordBatch> for ArrayRef {
430
    fn from_arrow(array: &RecordBatch, nullable: bool) -> Self {
19✔
431
        Self::from_arrow(array.clone(), nullable)
19✔
432
    }
19✔
433
}
434

435
#[cfg(test)]
436
mod tests {
437
    use std::sync::Arc;
438

439
    use arrow_array::builder::{
440
        BinaryViewBuilder, Decimal128Builder, Decimal256Builder, Int32Builder, LargeListBuilder,
441
        ListBuilder, StringViewBuilder,
442
    };
443
    use arrow_array::types::{ArrowPrimitiveType, Float16Type};
444
    use arrow_array::{
445
        Array as ArrowArray, BinaryArray, BooleanArray, Date32Array, Date64Array, Float32Array,
446
        Float64Array, Int8Array, Int16Array, Int32Array, Int64Array, LargeBinaryArray,
447
        LargeStringArray, NullArray, RecordBatch, StringArray, StructArray, Time32MillisecondArray,
448
        Time32SecondArray, Time64MicrosecondArray, Time64NanosecondArray,
449
        TimestampMicrosecondArray, TimestampMillisecondArray, TimestampNanosecondArray,
450
        TimestampSecondArray, UInt8Array, UInt16Array, UInt32Array, UInt64Array, new_null_array,
451
    };
452
    use arrow_buffer::{BooleanBuffer, Buffer as ArrowBuffer, OffsetBuffer, ScalarBuffer};
453
    use arrow_schema::{DataType, Field, Fields, Schema};
454
    use vortex_dtype::datetime::TimeUnit;
455
    use vortex_dtype::{DType, PType};
456

457
    use crate::arrays::{
458
        DecimalVTable, ListVTable, PrimitiveVTable, StructVTable, TemporalArray, VarBinVTable,
459
        VarBinViewVTable,
460
    };
461
    use crate::arrow::FromArrowArray as _;
462
    use crate::{ArrayRef, IntoArray};
463

464
    // Test primitive array conversions
465
    #[test]
466
    fn test_int8_array_conversion() {
1✔
467
        let arrow_array = Int8Array::from(vec![Some(1), None, Some(3), Some(4)]);
1✔
468
        let vortex_array = ArrayRef::from_arrow(&arrow_array, true);
1✔
469

470
        let arrow_array_non_null = Int8Array::from(vec![1, 2, 3, 4]);
1✔
471
        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false);
1✔
472

473
        assert_eq!(vortex_array.len(), 4);
1✔
474
        assert_eq!(vortex_array_non_null.len(), 4);
1✔
475

476
        // Verify metadata - should be PrimitiveArray with I8 ptype
477
        let primitive_array = vortex_array.as_::<PrimitiveVTable>();
1✔
478
        assert_eq!(primitive_array.ptype(), PType::I8);
1✔
479

480
        let primitive_array_non_null = vortex_array_non_null.as_::<PrimitiveVTable>();
1✔
481
        assert_eq!(primitive_array_non_null.ptype(), PType::I8);
1✔
482
    }
1✔
483

484
    #[test]
485
    fn test_int16_array_conversion() {
1✔
486
        let arrow_array = Int16Array::from(vec![Some(100), None, Some(300), Some(400)]);
1✔
487
        let vortex_array = ArrayRef::from_arrow(&arrow_array, true);
1✔
488

489
        let arrow_array_non_null = Int16Array::from(vec![100, 200, 300, 400]);
1✔
490
        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false);
1✔
491

492
        assert_eq!(vortex_array.len(), 4);
1✔
493
        assert_eq!(vortex_array_non_null.len(), 4);
1✔
494

495
        // Verify metadata - should be PrimitiveArray with I16 ptype
496
        let primitive_array = vortex_array.as_::<PrimitiveVTable>();
1✔
497
        assert_eq!(primitive_array.ptype(), PType::I16);
1✔
498

499
        let primitive_array_non_null = vortex_array_non_null.as_::<PrimitiveVTable>();
1✔
500
        assert_eq!(primitive_array_non_null.ptype(), PType::I16);
1✔
501
    }
1✔
502

503
    #[test]
504
    fn test_int32_array_conversion() {
1✔
505
        let arrow_array = Int32Array::from(vec![Some(1000), None, Some(3000), Some(4000)]);
1✔
506
        let vortex_array = ArrayRef::from_arrow(&arrow_array, true);
1✔
507

508
        let arrow_array_non_null = Int32Array::from(vec![1000, 2000, 3000, 4000]);
1✔
509
        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false);
1✔
510

511
        assert_eq!(vortex_array.len(), 4);
1✔
512
        assert_eq!(vortex_array_non_null.len(), 4);
1✔
513

514
        // Verify metadata - should be PrimitiveArray with I32 ptype
515
        let primitive_array = vortex_array.as_::<PrimitiveVTable>();
1✔
516
        assert_eq!(primitive_array.ptype(), PType::I32);
1✔
517

518
        let primitive_array_non_null = vortex_array_non_null.as_::<PrimitiveVTable>();
1✔
519
        assert_eq!(primitive_array_non_null.ptype(), PType::I32);
1✔
520
    }
1✔
521

522
    #[test]
523
    fn test_int64_array_conversion() {
1✔
524
        let arrow_array = Int64Array::from(vec![Some(10000), None, Some(30000), Some(40000)]);
1✔
525
        let vortex_array = ArrayRef::from_arrow(&arrow_array, true);
1✔
526

527
        let arrow_array_non_null = Int64Array::from(vec![10000_i64, 20000, 30000, 40000]);
1✔
528
        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false);
1✔
529

530
        assert_eq!(vortex_array.len(), 4);
1✔
531
        assert_eq!(vortex_array_non_null.len(), 4);
1✔
532

533
        // Verify metadata - should be PrimitiveArray with I64 ptype
534
        let primitive_array = vortex_array.as_::<PrimitiveVTable>();
1✔
535
        assert_eq!(primitive_array.ptype(), PType::I64);
1✔
536

537
        let primitive_array_non_null = vortex_array_non_null.as_::<PrimitiveVTable>();
1✔
538
        assert_eq!(primitive_array_non_null.ptype(), PType::I64);
1✔
539
    }
1✔
540

541
    #[test]
542
    fn test_uint8_array_conversion() {
1✔
543
        let arrow_array = UInt8Array::from(vec![Some(1), None, Some(3), Some(4)]);
1✔
544
        let vortex_array = ArrayRef::from_arrow(&arrow_array, true);
1✔
545

546
        let arrow_array_non_null = UInt8Array::from(vec![1_u8, 2, 3, 4]);
1✔
547
        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false);
1✔
548

549
        assert_eq!(vortex_array.len(), 4);
1✔
550
        assert_eq!(vortex_array_non_null.len(), 4);
1✔
551

552
        // Verify metadata - should be PrimitiveArray with U8 ptype
553
        let primitive_array = vortex_array.as_::<PrimitiveVTable>();
1✔
554
        assert_eq!(primitive_array.ptype(), PType::U8);
1✔
555

556
        let primitive_array_non_null = vortex_array_non_null.as_::<PrimitiveVTable>();
1✔
557
        assert_eq!(primitive_array_non_null.ptype(), PType::U8);
1✔
558
    }
1✔
559

560
    #[test]
561
    fn test_uint16_array_conversion() {
1✔
562
        let arrow_array = UInt16Array::from(vec![Some(100), None, Some(300), Some(400)]);
1✔
563
        let vortex_array = ArrayRef::from_arrow(&arrow_array, true);
1✔
564

565
        let arrow_array_non_null = UInt16Array::from(vec![100_u16, 200, 300, 400]);
1✔
566
        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false);
1✔
567

568
        assert_eq!(vortex_array.len(), 4);
1✔
569
        assert_eq!(vortex_array_non_null.len(), 4);
1✔
570

571
        // Verify metadata - should be PrimitiveArray with U16 ptype
572
        let primitive_array = vortex_array.as_::<PrimitiveVTable>();
1✔
573
        assert_eq!(primitive_array.ptype(), PType::U16);
1✔
574

575
        let primitive_array_non_null = vortex_array_non_null.as_::<PrimitiveVTable>();
1✔
576
        assert_eq!(primitive_array_non_null.ptype(), PType::U16);
1✔
577
    }
1✔
578

579
    #[test]
580
    fn test_uint32_array_conversion() {
1✔
581
        let arrow_array = UInt32Array::from(vec![Some(1000), None, Some(3000), Some(4000)]);
1✔
582
        let vortex_array = ArrayRef::from_arrow(&arrow_array, true);
1✔
583

584
        let arrow_array_non_null = UInt32Array::from(vec![1000_u32, 2000, 3000, 4000]);
1✔
585
        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false);
1✔
586

587
        assert_eq!(vortex_array.len(), 4);
1✔
588
        assert_eq!(vortex_array_non_null.len(), 4);
1✔
589

590
        // Verify metadata - should be PrimitiveArray with U32 ptype
591
        let primitive_array = vortex_array.as_::<PrimitiveVTable>();
1✔
592
        assert_eq!(primitive_array.ptype(), PType::U32);
1✔
593

594
        let primitive_array_non_null = vortex_array_non_null.as_::<PrimitiveVTable>();
1✔
595
        assert_eq!(primitive_array_non_null.ptype(), PType::U32);
1✔
596
    }
1✔
597

598
    #[test]
599
    fn test_uint64_array_conversion() {
1✔
600
        let arrow_array = UInt64Array::from(vec![Some(10000), None, Some(30000), Some(40000)]);
1✔
601
        let vortex_array = ArrayRef::from_arrow(&arrow_array, true);
1✔
602

603
        let arrow_array_non_null = UInt64Array::from(vec![10000_u64, 20000, 30000, 40000]);
1✔
604
        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false);
1✔
605

606
        assert_eq!(vortex_array.len(), 4);
1✔
607
        assert_eq!(vortex_array_non_null.len(), 4);
1✔
608

609
        // Verify metadata - should be PrimitiveArray with U64 ptype
610
        let primitive_array = vortex_array.as_::<PrimitiveVTable>();
1✔
611
        assert_eq!(primitive_array.ptype(), PType::U64);
1✔
612

613
        let primitive_array_non_null = vortex_array_non_null.as_::<PrimitiveVTable>();
1✔
614
        assert_eq!(primitive_array_non_null.ptype(), PType::U64);
1✔
615
    }
1✔
616

617
    #[test]
618
    fn test_float16_array_conversion() {
1✔
619
        let values = vec![
1✔
620
            Some(<Float16Type as ArrowPrimitiveType>::Native::from_f32(1.5)),
1✔
621
            None,
1✔
622
            Some(<Float16Type as ArrowPrimitiveType>::Native::from_f32(3.5)),
1✔
623
        ];
624
        let arrow_array = arrow_array::PrimitiveArray::<Float16Type>::from(values);
1✔
625
        let vortex_array = ArrayRef::from_arrow(&arrow_array, true);
1✔
626

627
        let non_null_values = vec![
1✔
628
            <Float16Type as ArrowPrimitiveType>::Native::from_f32(1.5),
1✔
629
            <Float16Type as ArrowPrimitiveType>::Native::from_f32(2.5),
1✔
630
        ];
631
        let arrow_array_non_null =
1✔
632
            arrow_array::PrimitiveArray::<Float16Type>::from(non_null_values);
1✔
633
        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false);
1✔
634

635
        assert_eq!(vortex_array.len(), 3);
1✔
636
        assert_eq!(vortex_array_non_null.len(), 2);
1✔
637

638
        // Verify metadata - should be PrimitiveArray with F16 ptype
639
        let primitive_array = vortex_array.as_::<PrimitiveVTable>();
1✔
640
        assert_eq!(primitive_array.ptype(), PType::F16);
1✔
641

642
        let primitive_array_non_null = vortex_array_non_null.as_::<PrimitiveVTable>();
1✔
643
        assert_eq!(primitive_array_non_null.ptype(), PType::F16);
1✔
644
    }
1✔
645

646
    #[test]
647
    fn test_float32_array_conversion() {
1✔
648
        let arrow_array = Float32Array::from(vec![Some(1.5), None, Some(3.5), Some(4.5)]);
1✔
649
        let vortex_array = ArrayRef::from_arrow(&arrow_array, true);
1✔
650

651
        let arrow_array_non_null = Float32Array::from(vec![1.5_f32, 2.5, 3.5, 4.5]);
1✔
652
        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false);
1✔
653

654
        assert_eq!(vortex_array.len(), 4);
1✔
655
        assert_eq!(vortex_array_non_null.len(), 4);
1✔
656

657
        // Verify metadata - should be PrimitiveArray with F32 ptype
658
        let primitive_array = vortex_array.as_::<PrimitiveVTable>();
1✔
659
        assert_eq!(primitive_array.ptype(), PType::F32);
1✔
660

661
        let primitive_array_non_null = vortex_array_non_null.as_::<PrimitiveVTable>();
1✔
662
        assert_eq!(primitive_array_non_null.ptype(), PType::F32);
1✔
663
    }
1✔
664

665
    #[test]
666
    fn test_float64_array_conversion() {
1✔
667
        let arrow_array = Float64Array::from(vec![Some(1.5), None, Some(3.5), Some(4.5)]);
1✔
668
        let vortex_array = ArrayRef::from_arrow(&arrow_array, true);
1✔
669

670
        let arrow_array_non_null = Float64Array::from(vec![1.5_f64, 2.5, 3.5, 4.5]);
1✔
671
        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false);
1✔
672

673
        assert_eq!(vortex_array.len(), 4);
1✔
674
        assert_eq!(vortex_array_non_null.len(), 4);
1✔
675

676
        // Verify metadata - should be PrimitiveArray with F64 ptype
677
        let primitive_array = vortex_array.as_::<PrimitiveVTable>();
1✔
678
        assert_eq!(primitive_array.ptype(), PType::F64);
1✔
679

680
        let primitive_array_non_null = vortex_array_non_null.as_::<PrimitiveVTable>();
1✔
681
        assert_eq!(primitive_array_non_null.ptype(), PType::F64);
1✔
682
    }
1✔
683

684
    // Test decimal array conversions
685
    #[test]
686
    fn test_decimal128_array_conversion() {
1✔
687
        let mut builder = Decimal128Builder::with_capacity(4);
1✔
688
        builder.append_value(12345);
1✔
689
        builder.append_null();
1✔
690
        builder.append_value(67890);
1✔
691
        builder.append_value(11111);
1✔
692
        let decimal_array = builder.finish().with_precision_and_scale(10, 2).unwrap();
1✔
693

694
        let vortex_array = ArrayRef::from_arrow(&decimal_array, true);
1✔
695
        assert_eq!(vortex_array.len(), 4);
1✔
696

697
        let mut builder_non_null = Decimal128Builder::with_capacity(3);
1✔
698
        builder_non_null.append_value(12345);
1✔
699
        builder_non_null.append_value(67890);
1✔
700
        builder_non_null.append_value(11111);
1✔
701
        let decimal_array_non_null = builder_non_null
1✔
702
            .finish()
1✔
703
            .with_precision_and_scale(10, 2)
1✔
704
            .unwrap();
1✔
705

706
        let vortex_array_non_null = ArrayRef::from_arrow(&decimal_array_non_null, false);
1✔
707
        assert_eq!(vortex_array_non_null.len(), 3);
1✔
708

709
        // Verify metadata - should be DecimalArray with correct precision and scale
710
        let decimal_vortex_array = vortex_array.as_::<DecimalVTable>();
1✔
711
        assert_eq!(decimal_vortex_array.decimal_dtype().precision(), 10);
1✔
712
        assert_eq!(decimal_vortex_array.decimal_dtype().scale(), 2);
1✔
713

714
        let decimal_vortex_array_non_null = vortex_array_non_null.as_::<DecimalVTable>();
1✔
715
        assert_eq!(
1✔
716
            decimal_vortex_array_non_null.decimal_dtype().precision(),
1✔
717
            10
718
        );
719
        assert_eq!(decimal_vortex_array_non_null.decimal_dtype().scale(), 2);
1✔
720
    }
1✔
721

722
    #[test]
723
    fn test_decimal256_array_conversion() {
1✔
724
        let mut builder = Decimal256Builder::with_capacity(4);
1✔
725
        builder.append_value(arrow_buffer::i256::from_i128(12345));
1✔
726
        builder.append_null();
1✔
727
        builder.append_value(arrow_buffer::i256::from_i128(67890));
1✔
728
        builder.append_value(arrow_buffer::i256::from_i128(11111));
1✔
729
        let decimal_array = builder.finish().with_precision_and_scale(38, 10).unwrap();
1✔
730

731
        let vortex_array = ArrayRef::from_arrow(&decimal_array, true);
1✔
732
        assert_eq!(vortex_array.len(), 4);
1✔
733

734
        let mut builder_non_null = Decimal256Builder::with_capacity(3);
1✔
735
        builder_non_null.append_value(arrow_buffer::i256::from_i128(12345));
1✔
736
        builder_non_null.append_value(arrow_buffer::i256::from_i128(67890));
1✔
737
        builder_non_null.append_value(arrow_buffer::i256::from_i128(11111));
1✔
738
        let decimal_array_non_null = builder_non_null
1✔
739
            .finish()
1✔
740
            .with_precision_and_scale(38, 10)
1✔
741
            .unwrap();
1✔
742

743
        let vortex_array_non_null = ArrayRef::from_arrow(&decimal_array_non_null, false);
1✔
744
        assert_eq!(vortex_array_non_null.len(), 3);
1✔
745

746
        // Verify metadata - should be DecimalArray with correct precision and scale
747
        let decimal_vortex_array = vortex_array.as_::<DecimalVTable>();
1✔
748
        assert_eq!(decimal_vortex_array.decimal_dtype().precision(), 38);
1✔
749
        assert_eq!(decimal_vortex_array.decimal_dtype().scale(), 10);
1✔
750

751
        let decimal_vortex_array_non_null = vortex_array_non_null.as_::<DecimalVTable>();
1✔
752
        assert_eq!(
1✔
753
            decimal_vortex_array_non_null.decimal_dtype().precision(),
1✔
754
            38
755
        );
756
        assert_eq!(decimal_vortex_array_non_null.decimal_dtype().scale(), 10);
1✔
757
    }
1✔
758

759
    // Test temporal array conversions
760
    #[test]
761
    fn test_timestamp_second_array_conversion() {
1✔
762
        let arrow_array =
1✔
763
            TimestampSecondArray::from(vec![Some(1000), None, Some(3000), Some(4000)]);
1✔
764
        let vortex_array = ArrayRef::from_arrow(&arrow_array, true);
1✔
765

766
        let arrow_array_non_null = TimestampSecondArray::from(vec![1000_i64, 2000, 3000, 4000]);
1✔
767
        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false);
1✔
768

769
        assert_eq!(vortex_array.len(), 4);
1✔
770
        assert_eq!(vortex_array_non_null.len(), 4);
1✔
771

772
        // Verify metadata - should be TemporalArray with Second time unit
773
        let temporal_array = TemporalArray::try_from(vortex_array.clone()).unwrap();
1✔
774
        assert_eq!(temporal_array.temporal_metadata().time_unit(), TimeUnit::S);
1✔
775

776
        let temporal_array_non_null =
1✔
777
            TemporalArray::try_from(vortex_array_non_null.clone()).unwrap();
1✔
778
        assert_eq!(
1✔
779
            temporal_array_non_null.temporal_metadata().time_unit(),
1✔
780
            TimeUnit::S
781
        );
782
    }
1✔
783

784
    #[test]
785
    fn test_timestamp_millisecond_array_conversion() {
1✔
786
        let arrow_array =
1✔
787
            TimestampMillisecondArray::from(vec![Some(1000), None, Some(3000), Some(4000)]);
1✔
788
        let vortex_array = ArrayRef::from_arrow(&arrow_array, true);
1✔
789

790
        let arrow_array_non_null =
1✔
791
            TimestampMillisecondArray::from(vec![1000_i64, 2000, 3000, 4000]);
1✔
792
        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false);
1✔
793

794
        assert_eq!(vortex_array.len(), 4);
1✔
795
        assert_eq!(vortex_array_non_null.len(), 4);
1✔
796
    }
1✔
797

798
    #[test]
799
    fn test_timestamp_microsecond_array_conversion() {
1✔
800
        let arrow_array =
1✔
801
            TimestampMicrosecondArray::from(vec![Some(1000), None, Some(3000), Some(4000)]);
1✔
802
        let vortex_array = ArrayRef::from_arrow(&arrow_array, true);
1✔
803

804
        let arrow_array_non_null =
1✔
805
            TimestampMicrosecondArray::from(vec![1000_i64, 2000, 3000, 4000]);
1✔
806
        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false);
1✔
807

808
        assert_eq!(vortex_array.len(), 4);
1✔
809
        assert_eq!(vortex_array_non_null.len(), 4);
1✔
810
    }
1✔
811

812
    #[test]
813
    fn test_timestamp_nanosecond_array_conversion() {
1✔
814
        let arrow_array =
1✔
815
            TimestampNanosecondArray::from(vec![Some(1000), None, Some(3000), Some(4000)]);
1✔
816
        let vortex_array = ArrayRef::from_arrow(&arrow_array, true);
1✔
817

818
        let arrow_array_non_null = TimestampNanosecondArray::from(vec![1000_i64, 2000, 3000, 4000]);
1✔
819
        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false);
1✔
820

821
        assert_eq!(vortex_array.len(), 4);
1✔
822
        assert_eq!(vortex_array_non_null.len(), 4);
1✔
823
    }
1✔
824

825
    #[test]
826
    fn test_time32_second_array_conversion() {
1✔
827
        let arrow_array = Time32SecondArray::from(vec![Some(1000), None, Some(3000), Some(4000)]);
1✔
828
        let vortex_array = ArrayRef::from_arrow(&arrow_array, true);
1✔
829

830
        let arrow_array_non_null = Time32SecondArray::from(vec![1000_i32, 2000, 3000, 4000]);
1✔
831
        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false);
1✔
832

833
        assert_eq!(vortex_array.len(), 4);
1✔
834
        assert_eq!(vortex_array_non_null.len(), 4);
1✔
835

836
        // Verify metadata - should be TemporalArray with Second time unit
837
        let temporal_array = TemporalArray::try_from(vortex_array.clone()).unwrap();
1✔
838
        assert_eq!(temporal_array.temporal_metadata().time_unit(), TimeUnit::S);
1✔
839

840
        let temporal_array_non_null =
1✔
841
            TemporalArray::try_from(vortex_array_non_null.clone()).unwrap();
1✔
842
        assert_eq!(
1✔
843
            temporal_array_non_null.temporal_metadata().time_unit(),
1✔
844
            TimeUnit::S
845
        );
846
    }
1✔
847

848
    #[test]
849
    fn test_time32_millisecond_array_conversion() {
1✔
850
        let arrow_array =
1✔
851
            Time32MillisecondArray::from(vec![Some(1000), None, Some(3000), Some(4000)]);
1✔
852
        let vortex_array = ArrayRef::from_arrow(&arrow_array, true);
1✔
853

854
        let arrow_array_non_null = Time32MillisecondArray::from(vec![1000_i32, 2000, 3000, 4000]);
1✔
855
        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false);
1✔
856

857
        assert_eq!(vortex_array.len(), 4);
1✔
858
        assert_eq!(vortex_array_non_null.len(), 4);
1✔
859
    }
1✔
860

861
    #[test]
862
    fn test_time64_microsecond_array_conversion() {
1✔
863
        let arrow_array =
1✔
864
            Time64MicrosecondArray::from(vec![Some(1000), None, Some(3000), Some(4000)]);
1✔
865
        let vortex_array = ArrayRef::from_arrow(&arrow_array, true);
1✔
866

867
        let arrow_array_non_null = Time64MicrosecondArray::from(vec![1000_i64, 2000, 3000, 4000]);
1✔
868
        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false);
1✔
869

870
        assert_eq!(vortex_array.len(), 4);
1✔
871
        assert_eq!(vortex_array_non_null.len(), 4);
1✔
872
    }
1✔
873

874
    #[test]
875
    fn test_time64_nanosecond_array_conversion() {
1✔
876
        let arrow_array =
1✔
877
            Time64NanosecondArray::from(vec![Some(1000), None, Some(3000), Some(4000)]);
1✔
878
        let vortex_array = ArrayRef::from_arrow(&arrow_array, true);
1✔
879

880
        let arrow_array_non_null = Time64NanosecondArray::from(vec![1000_i64, 2000, 3000, 4000]);
1✔
881
        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false);
1✔
882

883
        assert_eq!(vortex_array.len(), 4);
1✔
884
        assert_eq!(vortex_array_non_null.len(), 4);
1✔
885
    }
1✔
886

887
    #[test]
888
    fn test_date32_array_conversion() {
1✔
889
        let arrow_array = Date32Array::from(vec![Some(18000), None, Some(18002), Some(18003)]);
1✔
890
        let vortex_array = ArrayRef::from_arrow(&arrow_array, true);
1✔
891

892
        let arrow_array_non_null = Date32Array::from(vec![18000_i32, 18001, 18002, 18003]);
1✔
893
        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false);
1✔
894

895
        assert_eq!(vortex_array.len(), 4);
1✔
896
        assert_eq!(vortex_array_non_null.len(), 4);
1✔
897
    }
1✔
898

899
    #[test]
900
    fn test_date64_array_conversion() {
1✔
901
        let arrow_array = Date64Array::from(vec![
1✔
902
            Some(1555200000000),
1✔
903
            None,
1✔
904
            Some(1555286400000),
1✔
905
            Some(1555372800000),
1✔
906
        ]);
907
        let vortex_array = ArrayRef::from_arrow(&arrow_array, true);
1✔
908

909
        let arrow_array_non_null = Date64Array::from(vec![
1✔
910
            1555200000000_i64,
911
            1555213600000,
912
            1555286400000,
913
            1555372800000,
914
        ]);
915
        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false);
1✔
916

917
        assert_eq!(vortex_array.len(), 4);
1✔
918
        assert_eq!(vortex_array_non_null.len(), 4);
1✔
919
    }
1✔
920

921
    // Test string/binary array conversions
922
    #[test]
923
    fn test_utf8_array_conversion() {
1✔
924
        let arrow_array = StringArray::from(vec![Some("hello"), None, Some("world"), Some("test")]);
1✔
925
        let vortex_array = ArrayRef::from_arrow(&arrow_array, true);
1✔
926

927
        let arrow_array_non_null = StringArray::from(vec!["hello", "world", "test", "vortex"]);
1✔
928
        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false);
1✔
929

930
        assert_eq!(vortex_array.len(), 4);
1✔
931
        assert_eq!(vortex_array_non_null.len(), 4);
1✔
932

933
        // Verify metadata - should be VarBinArray with Utf8 dtype
934
        let varbin_array = vortex_array.as_::<VarBinVTable>();
1✔
935
        assert_eq!(varbin_array.dtype(), &DType::Utf8(true.into()));
1✔
936

937
        let varbin_array_non_null = vortex_array_non_null.as_::<VarBinVTable>();
1✔
938
        assert_eq!(varbin_array_non_null.dtype(), &DType::Utf8(false.into()));
1✔
939
    }
1✔
940

941
    #[test]
942
    fn test_large_utf8_array_conversion() {
1✔
943
        let arrow_array =
1✔
944
            LargeStringArray::from(vec![Some("hello"), None, Some("world"), Some("test")]);
1✔
945
        let vortex_array = ArrayRef::from_arrow(&arrow_array, true);
1✔
946

947
        let arrow_array_non_null = LargeStringArray::from(vec!["hello", "world", "test", "vortex"]);
1✔
948
        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false);
1✔
949

950
        assert_eq!(vortex_array.len(), 4);
1✔
951
        assert_eq!(vortex_array_non_null.len(), 4);
1✔
952
    }
1✔
953

954
    #[test]
955
    fn test_binary_array_conversion() {
1✔
956
        let arrow_array = BinaryArray::from(vec![
1✔
957
            Some("hello".as_bytes()),
1✔
958
            None,
1✔
959
            Some("world".as_bytes()),
1✔
960
            Some("test".as_bytes()),
1✔
961
        ]);
962
        let vortex_array = ArrayRef::from_arrow(&arrow_array, true);
1✔
963

964
        let arrow_array_non_null = BinaryArray::from(vec![
1✔
965
            "hello".as_bytes(),
1✔
966
            "world".as_bytes(),
1✔
967
            "test".as_bytes(),
1✔
968
            "vortex".as_bytes(),
1✔
969
        ]);
970
        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false);
1✔
971

972
        assert_eq!(vortex_array.len(), 4);
1✔
973
        assert_eq!(vortex_array_non_null.len(), 4);
1✔
974
    }
1✔
975

976
    #[test]
977
    fn test_large_binary_array_conversion() {
1✔
978
        let arrow_array = LargeBinaryArray::from(vec![
1✔
979
            Some("hello".as_bytes()),
1✔
980
            None,
1✔
981
            Some("world".as_bytes()),
1✔
982
            Some("test".as_bytes()),
1✔
983
        ]);
984
        let vortex_array = ArrayRef::from_arrow(&arrow_array, true);
1✔
985

986
        let arrow_array_non_null = LargeBinaryArray::from(vec![
1✔
987
            "hello".as_bytes(),
1✔
988
            "world".as_bytes(),
1✔
989
            "test".as_bytes(),
1✔
990
            "vortex".as_bytes(),
1✔
991
        ]);
992
        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false);
1✔
993

994
        assert_eq!(vortex_array.len(), 4);
1✔
995
        assert_eq!(vortex_array_non_null.len(), 4);
1✔
996
    }
1✔
997

998
    #[test]
999
    fn test_utf8_view_array_conversion() {
1✔
1000
        let mut builder = StringViewBuilder::new();
1✔
1001
        builder.append_value("hello");
1✔
1002
        builder.append_null();
1✔
1003
        builder.append_value("world");
1✔
1004
        builder.append_value("test");
1✔
1005
        let arrow_array = builder.finish();
1✔
1006
        let vortex_array = ArrayRef::from_arrow(&arrow_array, true);
1✔
1007

1008
        let mut builder_non_null = StringViewBuilder::new();
1✔
1009
        builder_non_null.append_value("hello");
1✔
1010
        builder_non_null.append_value("world");
1✔
1011
        builder_non_null.append_value("test");
1✔
1012
        builder_non_null.append_value("vortex");
1✔
1013
        let arrow_array_non_null = builder_non_null.finish();
1✔
1014
        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false);
1✔
1015

1016
        assert_eq!(vortex_array.len(), 4);
1✔
1017
        assert_eq!(vortex_array_non_null.len(), 4);
1✔
1018

1019
        // Verify metadata - should be VarBinViewArray with correct buffer count and dtype
1020
        let varbin_view_array = vortex_array.as_::<VarBinViewVTable>();
1✔
1021
        assert_eq!(
1✔
1022
            varbin_view_array.buffers().len(),
1✔
1023
            arrow_array.data_buffers().len()
1✔
1024
        );
1025
        assert_eq!(varbin_view_array.dtype(), &DType::Utf8(true.into()));
1✔
1026

1027
        let varbin_view_array_non_null = vortex_array_non_null.as_::<VarBinViewVTable>();
1✔
1028
        assert_eq!(
1✔
1029
            varbin_view_array_non_null.buffers().len(),
1✔
1030
            arrow_array_non_null.data_buffers().len()
1✔
1031
        );
1032
        assert_eq!(
1✔
1033
            varbin_view_array_non_null.dtype(),
1✔
1034
            &DType::Utf8(false.into())
1✔
1035
        );
1036
    }
1✔
1037

1038
    #[test]
1039
    fn test_binary_view_array_conversion() {
1✔
1040
        let mut builder = BinaryViewBuilder::new();
1✔
1041
        builder.append_value(b"hello");
1✔
1042
        builder.append_null();
1✔
1043
        builder.append_value(b"world");
1✔
1044
        builder.append_value(b"test");
1✔
1045
        let arrow_array = builder.finish();
1✔
1046
        let vortex_array = ArrayRef::from_arrow(&arrow_array, true);
1✔
1047

1048
        let mut builder_non_null = BinaryViewBuilder::new();
1✔
1049
        builder_non_null.append_value(b"hello");
1✔
1050
        builder_non_null.append_value(b"world");
1✔
1051
        builder_non_null.append_value(b"test");
1✔
1052
        builder_non_null.append_value(b"vortex");
1✔
1053
        let arrow_array_non_null = builder_non_null.finish();
1✔
1054
        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false);
1✔
1055

1056
        assert_eq!(vortex_array.len(), 4);
1✔
1057
        assert_eq!(vortex_array_non_null.len(), 4);
1✔
1058

1059
        // Verify metadata - should be VarBinViewArray with correct buffer count and dtype
1060
        let varbin_view_array = vortex_array.as_::<VarBinViewVTable>();
1✔
1061
        assert_eq!(
1✔
1062
            varbin_view_array.buffers().len(),
1✔
1063
            arrow_array.data_buffers().len()
1✔
1064
        );
1065
        assert_eq!(varbin_view_array.dtype(), &DType::Binary(true.into()));
1✔
1066

1067
        let varbin_view_array_non_null = vortex_array_non_null.as_::<VarBinViewVTable>();
1✔
1068
        assert_eq!(
1✔
1069
            varbin_view_array_non_null.buffers().len(),
1✔
1070
            arrow_array_non_null.data_buffers().len()
1✔
1071
        );
1072
        assert_eq!(
1✔
1073
            varbin_view_array_non_null.dtype(),
1✔
1074
            &DType::Binary(false.into())
1✔
1075
        );
1076
    }
1✔
1077

1078
    // Test boolean array conversions
1079
    #[test]
1080
    fn test_boolean_array_conversion() {
1✔
1081
        let arrow_array = BooleanArray::from(vec![Some(true), None, Some(false), Some(true)]);
1✔
1082
        let vortex_array = ArrayRef::from_arrow(&arrow_array, true);
1✔
1083

1084
        let arrow_array_non_null = BooleanArray::from(vec![true, false, true, false]);
1✔
1085
        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false);
1✔
1086

1087
        assert_eq!(vortex_array.len(), 4);
1✔
1088
        assert_eq!(vortex_array_non_null.len(), 4);
1✔
1089
    }
1✔
1090

1091
    // Test struct array conversions
1092
    #[test]
1093
    fn test_struct_array_conversion() {
1✔
1094
        let fields = vec![
1✔
1095
            Field::new("field1", DataType::Int32, true),
1✔
1096
            Field::new("field2", DataType::Utf8, false),
1✔
1097
        ];
1098
        let schema = Fields::from(fields);
1✔
1099

1100
        let field1_data = Int32Array::from(vec![Some(1), None, Some(3)]);
1✔
1101
        let field2_data = StringArray::from(vec!["a", "b", "c"]);
1✔
1102

1103
        let arrow_array = StructArray::new(
1✔
1104
            schema.clone(),
1✔
1105
            vec![Arc::new(field1_data), Arc::new(field2_data)],
1✔
1106
            None,
1✔
1107
        );
1108

1109
        let vortex_array = ArrayRef::from_arrow(&arrow_array, false);
1✔
1110
        assert_eq!(vortex_array.len(), 3);
1✔
1111

1112
        // Verify metadata - should be StructArray with correct field names
1113
        let struct_vortex_array = vortex_array.as_::<StructVTable>();
1✔
1114
        assert_eq!(struct_vortex_array.names().len(), 2);
1✔
1115
        assert_eq!(struct_vortex_array.names()[0], "field1".into());
1✔
1116
        assert_eq!(struct_vortex_array.names()[1], "field2".into());
1✔
1117

1118
        // Test nullable struct
1119
        let nullable_array = StructArray::new(
1✔
1120
            schema,
1✔
1121
            vec![
1✔
1122
                Arc::new(Int32Array::from(vec![Some(1), None, Some(3)])),
1✔
1123
                Arc::new(StringArray::from(vec!["a", "b", "c"])),
1✔
1124
            ],
1125
            Some(arrow_buffer::NullBuffer::new(BooleanBuffer::from(vec![
1✔
1126
                true, false, true,
1✔
1127
            ]))),
1✔
1128
        );
1129

1130
        let vortex_nullable_array = ArrayRef::from_arrow(&nullable_array, true);
1✔
1131
        assert_eq!(vortex_nullable_array.len(), 3);
1✔
1132

1133
        // Verify metadata for nullable struct
1134
        let struct_vortex_nullable_array = vortex_nullable_array.as_::<StructVTable>();
1✔
1135
        assert_eq!(struct_vortex_nullable_array.names().len(), 2);
1✔
1136
        assert_eq!(struct_vortex_nullable_array.names()[0], "field1".into());
1✔
1137
        assert_eq!(struct_vortex_nullable_array.names()[1], "field2".into());
1✔
1138
    }
1✔
1139

1140
    // Test list array conversions
1141
    #[test]
1142
    fn test_list_array_conversion() {
1✔
1143
        let mut builder = ListBuilder::new(Int32Builder::new());
1✔
1144
        builder.append_value([Some(1), None, Some(3)]);
1✔
1145
        builder.append_null();
1✔
1146
        builder.append_value([Some(4), Some(5)]);
1✔
1147
        let arrow_array = builder.finish();
1✔
1148

1149
        let vortex_array = ArrayRef::from_arrow(&arrow_array, true);
1✔
1150
        assert_eq!(vortex_array.len(), 3);
1✔
1151

1152
        // Verify metadata - should be ListArray with correct offsets
1153
        let list_vortex_array = vortex_array.as_::<ListVTable>();
1✔
1154
        let offsets_array = list_vortex_array.offsets().as_::<PrimitiveVTable>();
1✔
1155
        assert_eq!(offsets_array.len(), 4); // n+1 offsets for n lists
1✔
1156
        assert_eq!(offsets_array.ptype(), PType::I32);
1✔
1157

1158
        // Test non-nullable list
1159
        let mut builder_non_null = ListBuilder::new(Int32Builder::new());
1✔
1160
        builder_non_null.append_value([Some(1), None, Some(3)]);
1✔
1161
        builder_non_null.append_value([Some(4), Some(5)]);
1✔
1162
        let arrow_array_non_null = builder_non_null.finish();
1✔
1163

1164
        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false);
1✔
1165
        assert_eq!(vortex_array_non_null.len(), 2);
1✔
1166

1167
        // Verify metadata for non-nullable list
1168
        let list_vortex_array_non_null = vortex_array_non_null.as_::<ListVTable>();
1✔
1169
        let offsets_array_non_null = list_vortex_array_non_null
1✔
1170
            .offsets()
1✔
1171
            .as_::<PrimitiveVTable>();
1✔
1172
        assert_eq!(offsets_array_non_null.len(), 3); // n+1 offsets for n lists
1✔
1173
        assert_eq!(offsets_array_non_null.ptype(), PType::I32);
1✔
1174
    }
1✔
1175

1176
    #[test]
1177
    fn test_large_list_array_conversion() {
1✔
1178
        let mut builder = LargeListBuilder::new(Int32Builder::new());
1✔
1179
        builder.append_value([Some(1), None, Some(3)]);
1✔
1180
        builder.append_null();
1✔
1181
        builder.append_value([Some(4), Some(5)]);
1✔
1182
        let arrow_array = builder.finish();
1✔
1183

1184
        let vortex_array = ArrayRef::from_arrow(&arrow_array, true);
1✔
1185
        assert_eq!(vortex_array.len(), 3);
1✔
1186

1187
        // Verify metadata - should be ListArray with correct offsets (I64 for large lists)
1188
        let list_vortex_array = vortex_array.as_::<ListVTable>();
1✔
1189
        let offsets_array = list_vortex_array.offsets().as_::<PrimitiveVTable>();
1✔
1190
        assert_eq!(offsets_array.len(), 4); // n+1 offsets for n lists
1✔
1191
        assert_eq!(offsets_array.ptype(), PType::I64); // Large lists use I64 offsets
1✔
1192

1193
        // Test non-nullable large list
1194
        let mut builder_non_null = LargeListBuilder::new(Int32Builder::new());
1✔
1195
        builder_non_null.append_value([Some(1), None, Some(3)]);
1✔
1196
        builder_non_null.append_value([Some(4), Some(5)]);
1✔
1197
        let arrow_array_non_null = builder_non_null.finish();
1✔
1198

1199
        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false);
1✔
1200
        assert_eq!(vortex_array_non_null.len(), 2);
1✔
1201

1202
        // Verify metadata for non-nullable large list
1203
        let list_vortex_array_non_null = vortex_array_non_null.as_::<ListVTable>();
1✔
1204
        let offsets_array_non_null = list_vortex_array_non_null
1✔
1205
            .offsets()
1✔
1206
            .as_::<PrimitiveVTable>();
1✔
1207
        assert_eq!(offsets_array_non_null.len(), 3); // n+1 offsets for n lists
1✔
1208
        assert_eq!(offsets_array_non_null.ptype(), PType::I64); // Large lists use I64 offsets
1✔
1209
    }
1✔
1210

1211
    // Test null array conversions
1212
    #[test]
1213
    fn test_null_array_conversion() {
1✔
1214
        let arrow_array = NullArray::new(5);
1✔
1215
        let vortex_array = ArrayRef::from_arrow(&arrow_array, true);
1✔
1216
        assert_eq!(vortex_array.len(), 5);
1✔
1217
    }
1✔
1218

1219
    // Test buffer conversions
1220
    #[test]
1221
    fn test_arrow_buffer_conversion() {
1✔
1222
        let data = vec![1u8, 2, 3, 4, 5];
1✔
1223
        let arrow_buffer = ArrowBuffer::from_vec(data);
1✔
1224
        let vortex_array = arrow_buffer.into_array();
1✔
1225
        assert_eq!(vortex_array.len(), 5);
1✔
1226
    }
1✔
1227

1228
    #[test]
1229
    fn test_boolean_buffer_conversion() {
1✔
1230
        let data = vec![true, false, true, false, true];
1✔
1231
        let boolean_buffer = BooleanBuffer::from(data);
1✔
1232
        let vortex_array = boolean_buffer.into_array();
1✔
1233
        assert_eq!(vortex_array.len(), 5);
1✔
1234
    }
1✔
1235

1236
    #[test]
1237
    fn test_scalar_buffer_conversion() {
1✔
1238
        let data = vec![1i32, 2, 3, 4, 5];
1✔
1239
        let scalar_buffer = ScalarBuffer::from(data);
1✔
1240
        let vortex_array = scalar_buffer.into_array();
1✔
1241
        assert_eq!(vortex_array.len(), 5);
1✔
1242
    }
1✔
1243

1244
    #[test]
1245
    fn test_offset_buffer_conversion() {
1✔
1246
        let data = vec![0i32, 2, 5, 8, 10];
1✔
1247
        let offset_buffer = OffsetBuffer::new(ScalarBuffer::from(data));
1✔
1248
        let vortex_array = offset_buffer.into_array();
1✔
1249
        assert_eq!(vortex_array.len(), 5);
1✔
1250
    }
1✔
1251

1252
    // Test RecordBatch conversions
1253
    #[test]
1254
    fn test_record_batch_conversion() {
1✔
1255
        let schema = Arc::new(Schema::new(vec![
1✔
1256
            Field::new("field1", DataType::Int32, false),
1✔
1257
            Field::new("field2", DataType::Utf8, false),
1✔
1258
        ]));
1259

1260
        let field1_data = Arc::new(Int32Array::from(vec![1, 2, 3, 4]));
1✔
1261
        let field2_data = Arc::new(StringArray::from(vec!["a", "b", "c", "d"]));
1✔
1262

1263
        let record_batch = RecordBatch::try_new(schema, vec![field1_data, field2_data]).unwrap();
1✔
1264

1265
        let vortex_array = ArrayRef::from_arrow(record_batch, false);
1✔
1266
        assert_eq!(vortex_array.len(), 4);
1✔
1267

1268
        // Test with reference
1269
        let schema = Arc::new(Schema::new(vec![
1✔
1270
            Field::new("field1", DataType::Int32, false),
1✔
1271
            Field::new("field2", DataType::Utf8, false),
1✔
1272
        ]));
1273

1274
        let field1_data = Arc::new(Int32Array::from(vec![1, 2, 3, 4]));
1✔
1275
        let field2_data = Arc::new(StringArray::from(vec!["a", "b", "c", "d"]));
1✔
1276

1277
        let record_batch = RecordBatch::try_new(schema, vec![field1_data, field2_data]).unwrap();
1✔
1278

1279
        let vortex_array = ArrayRef::from_arrow(&record_batch, false);
1✔
1280
        assert_eq!(vortex_array.len(), 4);
1✔
1281
    }
1✔
1282

1283
    // Test dynamic dispatch conversion
1284
    #[test]
1285
    fn test_dyn_array_conversion() {
1✔
1286
        let int_array = Int32Array::from(vec![1, 2, 3, 4]);
1✔
1287
        let dyn_array: &dyn ArrowArray = &int_array;
1✔
1288
        let vortex_array = ArrayRef::from_arrow(dyn_array, false);
1✔
1289
        assert_eq!(vortex_array.len(), 4);
1✔
1290

1291
        let string_array = StringArray::from(vec!["a", "b", "c"]);
1✔
1292
        let dyn_array: &dyn ArrowArray = &string_array;
1✔
1293
        let vortex_array = ArrayRef::from_arrow(dyn_array, false);
1✔
1294
        assert_eq!(vortex_array.len(), 3);
1✔
1295

1296
        let bool_array = BooleanArray::from(vec![true, false, true]);
1✔
1297
        let dyn_array: &dyn ArrowArray = &bool_array;
1✔
1298
        let vortex_array = ArrayRef::from_arrow(dyn_array, false);
1✔
1299
        assert_eq!(vortex_array.len(), 3);
1✔
1300
    }
1✔
1301

1302
    // Existing tests
1303
    #[test]
1304
    pub fn nullable_may_contain_non_nullable() {
1✔
1305
        let null_struct_array_with_non_nullable_field = new_null_array(
1✔
1306
            &DataType::Struct(Fields::from(vec![Field::new(
1✔
1307
                "non_nullable_inner",
1✔
1308
                DataType::Int32,
1✔
1309
                false,
1✔
1310
            )])),
1✔
1311
            1,
1312
        );
1313
        ArrayRef::from_arrow(null_struct_array_with_non_nullable_field.as_ref(), true);
1✔
1314
    }
1✔
1315

1316
    #[test]
1317
    pub fn nullable_may_contain_deeply_nested_non_nullable() {
1✔
1318
        let null_struct_array_with_non_nullable_field = new_null_array(
1✔
1319
            &DataType::Struct(Fields::from(vec![Field::new(
1✔
1320
                "non_nullable_inner",
1✔
1321
                DataType::Struct(Fields::from(vec![Field::new(
1✔
1322
                    "non_nullable_deeper_inner",
1✔
1323
                    DataType::Int32,
1✔
1324
                    false,
1✔
1325
                )])),
1✔
1326
                false,
1✔
1327
            )])),
1✔
1328
            1,
1329
        );
1330
        ArrayRef::from_arrow(null_struct_array_with_non_nullable_field.as_ref(), true);
1✔
1331
    }
1✔
1332

1333
    #[test]
1334
    #[should_panic]
1335
    pub fn cannot_handle_nullable_struct_containing_non_nullable_dictionary() {
1✔
1336
        let null_struct_array_with_non_nullable_field = new_null_array(
1✔
1337
            &DataType::Struct(Fields::from(vec![Field::new(
1✔
1338
                "non_nullable_deeper_inner",
1✔
1339
                DataType::Dictionary(Box::new(DataType::Int32), Box::new(DataType::Utf8)),
1✔
1340
                false,
1✔
1341
            )])),
1✔
1342
            1,
1343
        );
1344

1345
        ArrayRef::from_arrow(null_struct_array_with_non_nullable_field.as_ref(), true);
1✔
1346
    }
1✔
1347
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc