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

vortex-data / vortex / 16980200873

15 Aug 2025 12:53AM UTC coverage: 49.805%. First build
16980200873

Pull #2456

github

web-flow
Merge aff477380 into aaf3e36ad
Pull Request #2456: feat: basic BoolBuffer / BoolBufferMut

574 of 1074 new or added lines in 84 files covered. (53.45%)

20158 of 40474 relevant lines covered (49.8%)

238516.31 hits per line

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

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

4
use std::sync::Arc;
5

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

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

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

49
impl IntoArray for BooleanBuffer {
50
    fn into_array(self) -> ArrayRef {
×
NEW
51
        BoolArray::new(self.into(), Validity::NonNullable).into_array()
×
52
    }
×
53
}
54

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

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

78
        primitive.into_array()
×
79
    }
×
80
}
81

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

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

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

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

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

139
// timestamp
140
impl_from_arrow_temporal!(TimestampSecondType);
141
impl_from_arrow_temporal!(TimestampMillisecondType);
142
impl_from_arrow_temporal!(TimestampMicrosecondType);
143
impl_from_arrow_temporal!(TimestampNanosecondType);
144

145
// time
146
impl_from_arrow_temporal!(Time32SecondType);
147
impl_from_arrow_temporal!(Time32MillisecondType);
148
impl_from_arrow_temporal!(Time64MicrosecondType);
149
impl_from_arrow_temporal!(Time64NanosecondType);
150

151
// date
152
impl_from_arrow_temporal!(Date32Type);
153
impl_from_arrow_temporal!(Date64Type);
154

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

165
    match value.data_type() {
21✔
166
        DataType::Timestamp(time_unit, tz) => {
×
167
            let tz = tz.as_ref().map(|s| s.to_string());
×
168
            TemporalArray::new_timestamp(arr, time_unit.into(), tz).into()
×
169
        }
170
        DataType::Time32(time_unit) => TemporalArray::new_time(arr, time_unit.into()).into(),
×
171
        DataType::Time64(time_unit) => TemporalArray::new_time(arr, time_unit.into()).into(),
×
172
        DataType::Date32 => TemporalArray::new_date(arr, TimeUnit::D).into(),
21✔
173
        DataType::Date64 => TemporalArray::new_date(arr, TimeUnit::Ms).into(),
×
174
        DataType::Duration(_) => unimplemented!(),
×
175
        DataType::Interval(_) => unimplemented!(),
×
176
        _ => vortex_panic!("Invalid temporal type: {}", value.data_type()),
×
177
    }
178
}
21✔
179

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

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

209
        let views_buffer = Buffer::from_byte_buffer(
120✔
210
            Buffer::from_arrow_scalar_buffer(value.views().clone()).into_byte_buffer(),
120✔
211
        );
212

213
        VarBinViewArray::try_new(
120✔
214
            views_buffer,
120✔
215
            Arc::from(
120✔
216
                value
120✔
217
                    .data_buffers()
120✔
218
                    .iter()
120✔
219
                    .map(|b| ByteBuffer::from_arrow_buffer(b.clone(), Alignment::of::<u8>()))
381✔
220
                    .collect::<Vec<_>>(),
120✔
221
            ),
222
            dtype,
120✔
223
            nulls(value.nulls(), nullable),
120✔
224
        )
225
        .vortex_expect("Failed to convert Arrow GenericByteViewArray to Vortex VarBinViewArray")
120✔
226
        .into_array()
120✔
227
    }
120✔
228
}
229

230
impl FromArrowArray<&ArrowBooleanArray> for ArrayRef {
231
    fn from_arrow(value: &ArrowBooleanArray, nullable: bool) -> Self {
8,628✔
232
        BoolArray::new(
8,628✔
233
            value.values().clone().into(),
8,628✔
234
            nulls(value.nulls(), nullable),
8,628✔
235
        )
8,628✔
236
        .into_array()
8,628✔
237
    }
8,628✔
238
}
239

240
/// Strip out the nulls from this array and return a new array without nulls.
241
fn remove_nulls(data: arrow_data::ArrayData) -> arrow_data::ArrayData {
×
242
    if data.null_count() == 0 {
×
243
        // No nulls to remove, return the array as is
244
        return data;
×
245
    }
×
246

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

279
    let mut builder = data.into_builder().nulls(None);
×
280
    if let Some(children) = children {
×
281
        builder = builder.child_data(children);
×
282
    }
×
283
    builder
×
284
        .build()
×
285
        .vortex_expect("reconstructing array without nulls")
×
286
}
×
287

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

315
impl<O: OffsetSizeTrait + NativePType> FromArrowArray<&GenericListArray<O>> for ArrayRef {
316
    fn from_arrow(value: &GenericListArray<O>, nullable: bool) -> Self {
×
317
        // Extract the validity of the underlying element array
318
        let elem_nullable = match value.data_type() {
×
319
            DataType::List(field) => field.is_nullable(),
×
320
            DataType::LargeList(field) => field.is_nullable(),
×
321
            dt => vortex_panic!("Invalid data type for ListArray: {dt}"),
×
322
        };
323
        ListArray::try_new(
×
324
            Self::from_arrow(value.values().as_ref(), elem_nullable),
×
325
            // offsets are always non-nullable
×
326
            value.offsets().clone().into_array(),
×
327
            nulls(value.nulls(), nullable),
×
328
        )
×
329
        .vortex_expect("Failed to convert Arrow StructArray to Vortex StructArray")
×
330
        .into_array()
×
331
    }
×
332
}
333

334
impl FromArrowArray<&ArrowNullArray> for ArrayRef {
335
    fn from_arrow(value: &ArrowNullArray, nullable: bool) -> Self {
×
336
        assert!(nullable);
×
337
        NullArray::new(value.len()).into_array()
×
338
    }
×
339
}
340

341
fn nulls(nulls: Option<&NullBuffer>, nullable: bool) -> Validity {
8,904✔
342
    if nullable {
8,904✔
343
        nulls
8,190✔
344
            .map(|nulls| {
8,190✔
345
                if nulls.null_count() == nulls.len() {
×
346
                    Validity::AllInvalid
×
347
                } else {
NEW
348
                    Validity::from(nulls.clone())
×
349
                }
350
            })
×
351
            .unwrap_or_else(|| Validity::AllValid)
8,190✔
352
    } else {
353
        assert!(nulls.map(|x| x.null_count() == 0).unwrap_or(true));
714✔
354
        Validity::NonNullable
714✔
355
    }
356
}
8,904✔
357

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

431
impl FromArrowArray<RecordBatch> for ArrayRef {
432
    fn from_arrow(array: RecordBatch, nullable: bool) -> Self {
27✔
433
        ArrayRef::from_arrow(&arrow_array::StructArray::from(array), nullable)
27✔
434
    }
27✔
435
}
436

437
impl FromArrowArray<&RecordBatch> for ArrayRef {
438
    fn from_arrow(array: &RecordBatch, nullable: bool) -> Self {
27✔
439
        Self::from_arrow(array.clone(), nullable)
27✔
440
    }
27✔
441
}
442

443
#[cfg(test)]
444
mod tests {
445
    use std::sync::Arc;
446

447
    use arrow_array::builder::{
448
        BinaryViewBuilder, Decimal128Builder, Decimal256Builder, Int32Builder, LargeListBuilder,
449
        ListBuilder, StringViewBuilder,
450
    };
451
    use arrow_array::types::{ArrowPrimitiveType, Float16Type};
452
    use arrow_array::{
453
        Array as ArrowArray, BinaryArray, BooleanArray, Date32Array, Date64Array, Float32Array,
454
        Float64Array, Int8Array, Int16Array, Int32Array, Int64Array, LargeBinaryArray,
455
        LargeStringArray, NullArray, RecordBatch, StringArray, StructArray, Time32MillisecondArray,
456
        Time32SecondArray, Time64MicrosecondArray, Time64NanosecondArray,
457
        TimestampMicrosecondArray, TimestampMillisecondArray, TimestampNanosecondArray,
458
        TimestampSecondArray, UInt8Array, UInt16Array, UInt32Array, UInt64Array, new_null_array,
459
    };
460
    use arrow_buffer::{BooleanBuffer, Buffer as ArrowBuffer, OffsetBuffer, ScalarBuffer};
461
    use arrow_schema::{DataType, Field, Fields, Schema};
462
    use vortex_dtype::datetime::{TIMESTAMP_ID, TemporalMetadata, TimeUnit};
463
    use vortex_dtype::{DType, ExtDType, Nullability, PType};
464

465
    use crate::arrays::{
466
        DecimalVTable, ListVTable, PrimitiveVTable, StructVTable, TemporalArray, VarBinVTable,
467
        VarBinViewVTable,
468
    };
469
    use crate::arrow::FromArrowArray as _;
470
    use crate::{ArrayRef, IntoArray};
471

472
    // Test primitive array conversions
473
    #[test]
474
    fn test_int8_array_conversion() {
475
        let arrow_array = Int8Array::from(vec![Some(1), None, Some(3), Some(4)]);
476
        let vortex_array = ArrayRef::from_arrow(&arrow_array, true);
477

478
        let arrow_array_non_null = Int8Array::from(vec![1, 2, 3, 4]);
479
        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false);
480

481
        assert_eq!(vortex_array.len(), 4);
482
        assert_eq!(vortex_array_non_null.len(), 4);
483

484
        // Verify metadata - should be PrimitiveArray with I8 ptype
485
        let primitive_array = vortex_array.as_::<PrimitiveVTable>();
486
        assert_eq!(primitive_array.ptype(), PType::I8);
487

488
        let primitive_array_non_null = vortex_array_non_null.as_::<PrimitiveVTable>();
489
        assert_eq!(primitive_array_non_null.ptype(), PType::I8);
490
    }
491

492
    #[test]
493
    fn test_int16_array_conversion() {
494
        let arrow_array = Int16Array::from(vec![Some(100), None, Some(300), Some(400)]);
495
        let vortex_array = ArrayRef::from_arrow(&arrow_array, true);
496

497
        let arrow_array_non_null = Int16Array::from(vec![100, 200, 300, 400]);
498
        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false);
499

500
        assert_eq!(vortex_array.len(), 4);
501
        assert_eq!(vortex_array_non_null.len(), 4);
502

503
        // Verify metadata - should be PrimitiveArray with I16 ptype
504
        let primitive_array = vortex_array.as_::<PrimitiveVTable>();
505
        assert_eq!(primitive_array.ptype(), PType::I16);
506

507
        let primitive_array_non_null = vortex_array_non_null.as_::<PrimitiveVTable>();
508
        assert_eq!(primitive_array_non_null.ptype(), PType::I16);
509
    }
510

511
    #[test]
512
    fn test_int32_array_conversion() {
513
        let arrow_array = Int32Array::from(vec![Some(1000), None, Some(3000), Some(4000)]);
514
        let vortex_array = ArrayRef::from_arrow(&arrow_array, true);
515

516
        let arrow_array_non_null = Int32Array::from(vec![1000, 2000, 3000, 4000]);
517
        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false);
518

519
        assert_eq!(vortex_array.len(), 4);
520
        assert_eq!(vortex_array_non_null.len(), 4);
521

522
        // Verify metadata - should be PrimitiveArray with I32 ptype
523
        let primitive_array = vortex_array.as_::<PrimitiveVTable>();
524
        assert_eq!(primitive_array.ptype(), PType::I32);
525

526
        let primitive_array_non_null = vortex_array_non_null.as_::<PrimitiveVTable>();
527
        assert_eq!(primitive_array_non_null.ptype(), PType::I32);
528
    }
529

530
    #[test]
531
    fn test_int64_array_conversion() {
532
        let arrow_array = Int64Array::from(vec![Some(10000), None, Some(30000), Some(40000)]);
533
        let vortex_array = ArrayRef::from_arrow(&arrow_array, true);
534

535
        let arrow_array_non_null = Int64Array::from(vec![10000_i64, 20000, 30000, 40000]);
536
        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false);
537

538
        assert_eq!(vortex_array.len(), 4);
539
        assert_eq!(vortex_array_non_null.len(), 4);
540

541
        // Verify metadata - should be PrimitiveArray with I64 ptype
542
        let primitive_array = vortex_array.as_::<PrimitiveVTable>();
543
        assert_eq!(primitive_array.ptype(), PType::I64);
544

545
        let primitive_array_non_null = vortex_array_non_null.as_::<PrimitiveVTable>();
546
        assert_eq!(primitive_array_non_null.ptype(), PType::I64);
547
    }
548

549
    #[test]
550
    fn test_uint8_array_conversion() {
551
        let arrow_array = UInt8Array::from(vec![Some(1), None, Some(3), Some(4)]);
552
        let vortex_array = ArrayRef::from_arrow(&arrow_array, true);
553

554
        let arrow_array_non_null = UInt8Array::from(vec![1_u8, 2, 3, 4]);
555
        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false);
556

557
        assert_eq!(vortex_array.len(), 4);
558
        assert_eq!(vortex_array_non_null.len(), 4);
559

560
        // Verify metadata - should be PrimitiveArray with U8 ptype
561
        let primitive_array = vortex_array.as_::<PrimitiveVTable>();
562
        assert_eq!(primitive_array.ptype(), PType::U8);
563

564
        let primitive_array_non_null = vortex_array_non_null.as_::<PrimitiveVTable>();
565
        assert_eq!(primitive_array_non_null.ptype(), PType::U8);
566
    }
567

568
    #[test]
569
    fn test_uint16_array_conversion() {
570
        let arrow_array = UInt16Array::from(vec![Some(100), None, Some(300), Some(400)]);
571
        let vortex_array = ArrayRef::from_arrow(&arrow_array, true);
572

573
        let arrow_array_non_null = UInt16Array::from(vec![100_u16, 200, 300, 400]);
574
        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false);
575

576
        assert_eq!(vortex_array.len(), 4);
577
        assert_eq!(vortex_array_non_null.len(), 4);
578

579
        // Verify metadata - should be PrimitiveArray with U16 ptype
580
        let primitive_array = vortex_array.as_::<PrimitiveVTable>();
581
        assert_eq!(primitive_array.ptype(), PType::U16);
582

583
        let primitive_array_non_null = vortex_array_non_null.as_::<PrimitiveVTable>();
584
        assert_eq!(primitive_array_non_null.ptype(), PType::U16);
585
    }
586

587
    #[test]
588
    fn test_uint32_array_conversion() {
589
        let arrow_array = UInt32Array::from(vec![Some(1000), None, Some(3000), Some(4000)]);
590
        let vortex_array = ArrayRef::from_arrow(&arrow_array, true);
591

592
        let arrow_array_non_null = UInt32Array::from(vec![1000_u32, 2000, 3000, 4000]);
593
        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false);
594

595
        assert_eq!(vortex_array.len(), 4);
596
        assert_eq!(vortex_array_non_null.len(), 4);
597

598
        // Verify metadata - should be PrimitiveArray with U32 ptype
599
        let primitive_array = vortex_array.as_::<PrimitiveVTable>();
600
        assert_eq!(primitive_array.ptype(), PType::U32);
601

602
        let primitive_array_non_null = vortex_array_non_null.as_::<PrimitiveVTable>();
603
        assert_eq!(primitive_array_non_null.ptype(), PType::U32);
604
    }
605

606
    #[test]
607
    fn test_uint64_array_conversion() {
608
        let arrow_array = UInt64Array::from(vec![Some(10000), None, Some(30000), Some(40000)]);
609
        let vortex_array = ArrayRef::from_arrow(&arrow_array, true);
610

611
        let arrow_array_non_null = UInt64Array::from(vec![10000_u64, 20000, 30000, 40000]);
612
        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false);
613

614
        assert_eq!(vortex_array.len(), 4);
615
        assert_eq!(vortex_array_non_null.len(), 4);
616

617
        // Verify metadata - should be PrimitiveArray with U64 ptype
618
        let primitive_array = vortex_array.as_::<PrimitiveVTable>();
619
        assert_eq!(primitive_array.ptype(), PType::U64);
620

621
        let primitive_array_non_null = vortex_array_non_null.as_::<PrimitiveVTable>();
622
        assert_eq!(primitive_array_non_null.ptype(), PType::U64);
623
    }
624

625
    #[test]
626
    fn test_float16_array_conversion() {
627
        let values = vec![
628
            Some(<Float16Type as ArrowPrimitiveType>::Native::from_f32(1.5)),
629
            None,
630
            Some(<Float16Type as ArrowPrimitiveType>::Native::from_f32(3.5)),
631
        ];
632
        let arrow_array = arrow_array::PrimitiveArray::<Float16Type>::from(values);
633
        let vortex_array = ArrayRef::from_arrow(&arrow_array, true);
634

635
        let non_null_values = vec![
636
            <Float16Type as ArrowPrimitiveType>::Native::from_f32(1.5),
637
            <Float16Type as ArrowPrimitiveType>::Native::from_f32(2.5),
638
        ];
639
        let arrow_array_non_null =
640
            arrow_array::PrimitiveArray::<Float16Type>::from(non_null_values);
641
        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false);
642

643
        assert_eq!(vortex_array.len(), 3);
644
        assert_eq!(vortex_array_non_null.len(), 2);
645

646
        // Verify metadata - should be PrimitiveArray with F16 ptype
647
        let primitive_array = vortex_array.as_::<PrimitiveVTable>();
648
        assert_eq!(primitive_array.ptype(), PType::F16);
649

650
        let primitive_array_non_null = vortex_array_non_null.as_::<PrimitiveVTable>();
651
        assert_eq!(primitive_array_non_null.ptype(), PType::F16);
652
    }
653

654
    #[test]
655
    fn test_float32_array_conversion() {
656
        let arrow_array = Float32Array::from(vec![Some(1.5), None, Some(3.5), Some(4.5)]);
657
        let vortex_array = ArrayRef::from_arrow(&arrow_array, true);
658

659
        let arrow_array_non_null = Float32Array::from(vec![1.5_f32, 2.5, 3.5, 4.5]);
660
        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false);
661

662
        assert_eq!(vortex_array.len(), 4);
663
        assert_eq!(vortex_array_non_null.len(), 4);
664

665
        // Verify metadata - should be PrimitiveArray with F32 ptype
666
        let primitive_array = vortex_array.as_::<PrimitiveVTable>();
667
        assert_eq!(primitive_array.ptype(), PType::F32);
668

669
        let primitive_array_non_null = vortex_array_non_null.as_::<PrimitiveVTable>();
670
        assert_eq!(primitive_array_non_null.ptype(), PType::F32);
671
    }
672

673
    #[test]
674
    fn test_float64_array_conversion() {
675
        let arrow_array = Float64Array::from(vec![Some(1.5), None, Some(3.5), Some(4.5)]);
676
        let vortex_array = ArrayRef::from_arrow(&arrow_array, true);
677

678
        let arrow_array_non_null = Float64Array::from(vec![1.5_f64, 2.5, 3.5, 4.5]);
679
        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false);
680

681
        assert_eq!(vortex_array.len(), 4);
682
        assert_eq!(vortex_array_non_null.len(), 4);
683

684
        // Verify metadata - should be PrimitiveArray with F64 ptype
685
        let primitive_array = vortex_array.as_::<PrimitiveVTable>();
686
        assert_eq!(primitive_array.ptype(), PType::F64);
687

688
        let primitive_array_non_null = vortex_array_non_null.as_::<PrimitiveVTable>();
689
        assert_eq!(primitive_array_non_null.ptype(), PType::F64);
690
    }
691

692
    // Test decimal array conversions
693
    #[test]
694
    fn test_decimal128_array_conversion() {
695
        let mut builder = Decimal128Builder::with_capacity(4);
696
        builder.append_value(12345);
697
        builder.append_null();
698
        builder.append_value(67890);
699
        builder.append_value(11111);
700
        let decimal_array = builder.finish().with_precision_and_scale(10, 2).unwrap();
701

702
        let vortex_array = ArrayRef::from_arrow(&decimal_array, true);
703
        assert_eq!(vortex_array.len(), 4);
704

705
        let mut builder_non_null = Decimal128Builder::with_capacity(3);
706
        builder_non_null.append_value(12345);
707
        builder_non_null.append_value(67890);
708
        builder_non_null.append_value(11111);
709
        let decimal_array_non_null = builder_non_null
710
            .finish()
711
            .with_precision_and_scale(10, 2)
712
            .unwrap();
713

714
        let vortex_array_non_null = ArrayRef::from_arrow(&decimal_array_non_null, false);
715
        assert_eq!(vortex_array_non_null.len(), 3);
716

717
        // Verify metadata - should be DecimalArray with correct precision and scale
718
        let decimal_vortex_array = vortex_array.as_::<DecimalVTable>();
719
        assert_eq!(decimal_vortex_array.decimal_dtype().precision(), 10);
720
        assert_eq!(decimal_vortex_array.decimal_dtype().scale(), 2);
721

722
        let decimal_vortex_array_non_null = vortex_array_non_null.as_::<DecimalVTable>();
723
        assert_eq!(
724
            decimal_vortex_array_non_null.decimal_dtype().precision(),
725
            10
726
        );
727
        assert_eq!(decimal_vortex_array_non_null.decimal_dtype().scale(), 2);
728
    }
729

730
    #[test]
731
    fn test_decimal256_array_conversion() {
732
        let mut builder = Decimal256Builder::with_capacity(4);
733
        builder.append_value(arrow_buffer::i256::from_i128(12345));
734
        builder.append_null();
735
        builder.append_value(arrow_buffer::i256::from_i128(67890));
736
        builder.append_value(arrow_buffer::i256::from_i128(11111));
737
        let decimal_array = builder.finish().with_precision_and_scale(38, 10).unwrap();
738

739
        let vortex_array = ArrayRef::from_arrow(&decimal_array, true);
740
        assert_eq!(vortex_array.len(), 4);
741

742
        let mut builder_non_null = Decimal256Builder::with_capacity(3);
743
        builder_non_null.append_value(arrow_buffer::i256::from_i128(12345));
744
        builder_non_null.append_value(arrow_buffer::i256::from_i128(67890));
745
        builder_non_null.append_value(arrow_buffer::i256::from_i128(11111));
746
        let decimal_array_non_null = builder_non_null
747
            .finish()
748
            .with_precision_and_scale(38, 10)
749
            .unwrap();
750

751
        let vortex_array_non_null = ArrayRef::from_arrow(&decimal_array_non_null, false);
752
        assert_eq!(vortex_array_non_null.len(), 3);
753

754
        // Verify metadata - should be DecimalArray with correct precision and scale
755
        let decimal_vortex_array = vortex_array.as_::<DecimalVTable>();
756
        assert_eq!(decimal_vortex_array.decimal_dtype().precision(), 38);
757
        assert_eq!(decimal_vortex_array.decimal_dtype().scale(), 10);
758

759
        let decimal_vortex_array_non_null = vortex_array_non_null.as_::<DecimalVTable>();
760
        assert_eq!(
761
            decimal_vortex_array_non_null.decimal_dtype().precision(),
762
            38
763
        );
764
        assert_eq!(decimal_vortex_array_non_null.decimal_dtype().scale(), 10);
765
    }
766

767
    // Test temporal array conversions
768
    #[test]
769
    fn test_timestamp_second_array_conversion() {
770
        let arrow_array =
771
            TimestampSecondArray::from(vec![Some(1000), None, Some(3000), Some(4000)]);
772
        let vortex_array = ArrayRef::from_arrow(&arrow_array, true);
773

774
        let arrow_array_non_null = TimestampSecondArray::from(vec![1000_i64, 2000, 3000, 4000]);
775
        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false);
776

777
        assert_eq!(vortex_array.len(), 4);
778
        assert_eq!(vortex_array_non_null.len(), 4);
779

780
        // Verify metadata - should be TemporalArray with Second time unit
781
        let temporal_array = TemporalArray::try_from(vortex_array.clone()).unwrap();
782
        assert_eq!(temporal_array.temporal_metadata().time_unit(), TimeUnit::S);
783

784
        let temporal_array_non_null =
785
            TemporalArray::try_from(vortex_array_non_null.clone()).unwrap();
786
        assert_eq!(
787
            temporal_array_non_null.temporal_metadata().time_unit(),
788
            TimeUnit::S
789
        );
790
    }
791

792
    #[test]
793
    fn test_timestamp_millisecond_array_conversion() {
794
        let arrow_array =
795
            TimestampMillisecondArray::from(vec![Some(1000), None, Some(3000), Some(4000)]);
796
        let vortex_array = ArrayRef::from_arrow(&arrow_array, true);
797

798
        let arrow_array_non_null =
799
            TimestampMillisecondArray::from(vec![1000_i64, 2000, 3000, 4000]);
800
        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false);
801

802
        assert_eq!(vortex_array.len(), 4);
803
        assert_eq!(vortex_array_non_null.len(), 4);
804
    }
805

806
    #[test]
807
    fn test_timestamp_microsecond_array_conversion() {
808
        let arrow_array =
809
            TimestampMicrosecondArray::from(vec![Some(1000), None, Some(3000), Some(4000)]);
810
        let vortex_array = ArrayRef::from_arrow(&arrow_array, true);
811

812
        let arrow_array_non_null =
813
            TimestampMicrosecondArray::from(vec![1000_i64, 2000, 3000, 4000]);
814
        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false);
815

816
        assert_eq!(vortex_array.len(), 4);
817
        assert_eq!(vortex_array_non_null.len(), 4);
818
    }
819

820
    #[test]
821
    fn test_timestamp_timezone_microsecond_array_conversion() {
822
        let arrow_array =
823
            TimestampMicrosecondArray::from(vec![Some(1000), None, Some(3000), Some(4000)])
824
                .with_timezone("UTC");
825
        let vortex_array = ArrayRef::from_arrow(&arrow_array, true);
826

827
        let arrow_array_non_null =
828
            TimestampMicrosecondArray::from(vec![1000_i64, 2000, 3000, 4000]).with_timezone("UTC");
829
        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false);
830

831
        assert_eq!(vortex_array.len(), 4);
832
        assert_eq!(
833
            vortex_array.dtype(),
834
            &DType::Extension(Arc::new(ExtDType::new(
835
                TIMESTAMP_ID.clone(),
836
                Arc::new(DType::Primitive(PType::I64, Nullability::Nullable)),
837
                Some(TemporalMetadata::Timestamp(TimeUnit::Us, Some("UTC".to_string())).into())
838
            )))
839
        );
840
        assert_eq!(vortex_array_non_null.len(), 4);
841
        assert_eq!(
842
            vortex_array_non_null.dtype(),
843
            &DType::Extension(Arc::new(ExtDType::new(
844
                TIMESTAMP_ID.clone(),
845
                Arc::new(DType::Primitive(PType::I64, Nullability::NonNullable)),
846
                Some(TemporalMetadata::Timestamp(TimeUnit::Us, Some("UTC".to_string())).into())
847
            )))
848
        );
849
    }
850

851
    #[test]
852
    fn test_timestamp_nanosecond_array_conversion() {
853
        let arrow_array =
854
            TimestampNanosecondArray::from(vec![Some(1000), None, Some(3000), Some(4000)]);
855
        let vortex_array = ArrayRef::from_arrow(&arrow_array, true);
856

857
        let arrow_array_non_null = TimestampNanosecondArray::from(vec![1000_i64, 2000, 3000, 4000]);
858
        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false);
859

860
        assert_eq!(vortex_array.len(), 4);
861
        assert_eq!(vortex_array_non_null.len(), 4);
862
    }
863

864
    #[test]
865
    fn test_time32_second_array_conversion() {
866
        let arrow_array = Time32SecondArray::from(vec![Some(1000), None, Some(3000), Some(4000)]);
867
        let vortex_array = ArrayRef::from_arrow(&arrow_array, true);
868

869
        let arrow_array_non_null = Time32SecondArray::from(vec![1000_i32, 2000, 3000, 4000]);
870
        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false);
871

872
        assert_eq!(vortex_array.len(), 4);
873
        assert_eq!(vortex_array_non_null.len(), 4);
874

875
        // Verify metadata - should be TemporalArray with Second time unit
876
        let temporal_array = TemporalArray::try_from(vortex_array.clone()).unwrap();
877
        assert_eq!(temporal_array.temporal_metadata().time_unit(), TimeUnit::S);
878

879
        let temporal_array_non_null =
880
            TemporalArray::try_from(vortex_array_non_null.clone()).unwrap();
881
        assert_eq!(
882
            temporal_array_non_null.temporal_metadata().time_unit(),
883
            TimeUnit::S
884
        );
885
    }
886

887
    #[test]
888
    fn test_time32_millisecond_array_conversion() {
889
        let arrow_array =
890
            Time32MillisecondArray::from(vec![Some(1000), None, Some(3000), Some(4000)]);
891
        let vortex_array = ArrayRef::from_arrow(&arrow_array, true);
892

893
        let arrow_array_non_null = Time32MillisecondArray::from(vec![1000_i32, 2000, 3000, 4000]);
894
        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false);
895

896
        assert_eq!(vortex_array.len(), 4);
897
        assert_eq!(vortex_array_non_null.len(), 4);
898
    }
899

900
    #[test]
901
    fn test_time64_microsecond_array_conversion() {
902
        let arrow_array =
903
            Time64MicrosecondArray::from(vec![Some(1000), None, Some(3000), Some(4000)]);
904
        let vortex_array = ArrayRef::from_arrow(&arrow_array, true);
905

906
        let arrow_array_non_null = Time64MicrosecondArray::from(vec![1000_i64, 2000, 3000, 4000]);
907
        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false);
908

909
        assert_eq!(vortex_array.len(), 4);
910
        assert_eq!(vortex_array_non_null.len(), 4);
911
    }
912

913
    #[test]
914
    fn test_time64_nanosecond_array_conversion() {
915
        let arrow_array =
916
            Time64NanosecondArray::from(vec![Some(1000), None, Some(3000), Some(4000)]);
917
        let vortex_array = ArrayRef::from_arrow(&arrow_array, true);
918

919
        let arrow_array_non_null = Time64NanosecondArray::from(vec![1000_i64, 2000, 3000, 4000]);
920
        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false);
921

922
        assert_eq!(vortex_array.len(), 4);
923
        assert_eq!(vortex_array_non_null.len(), 4);
924
    }
925

926
    #[test]
927
    fn test_date32_array_conversion() {
928
        let arrow_array = Date32Array::from(vec![Some(18000), None, Some(18002), Some(18003)]);
929
        let vortex_array = ArrayRef::from_arrow(&arrow_array, true);
930

931
        let arrow_array_non_null = Date32Array::from(vec![18000_i32, 18001, 18002, 18003]);
932
        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false);
933

934
        assert_eq!(vortex_array.len(), 4);
935
        assert_eq!(vortex_array_non_null.len(), 4);
936
    }
937

938
    #[test]
939
    fn test_date64_array_conversion() {
940
        let arrow_array = Date64Array::from(vec![
941
            Some(1555200000000),
942
            None,
943
            Some(1555286400000),
944
            Some(1555372800000),
945
        ]);
946
        let vortex_array = ArrayRef::from_arrow(&arrow_array, true);
947

948
        let arrow_array_non_null = Date64Array::from(vec![
949
            1555200000000_i64,
950
            1555213600000,
951
            1555286400000,
952
            1555372800000,
953
        ]);
954
        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false);
955

956
        assert_eq!(vortex_array.len(), 4);
957
        assert_eq!(vortex_array_non_null.len(), 4);
958
    }
959

960
    // Test string/binary array conversions
961
    #[test]
962
    fn test_utf8_array_conversion() {
963
        let arrow_array = StringArray::from(vec![Some("hello"), None, Some("world"), Some("test")]);
964
        let vortex_array = ArrayRef::from_arrow(&arrow_array, true);
965

966
        let arrow_array_non_null = StringArray::from(vec!["hello", "world", "test", "vortex"]);
967
        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false);
968

969
        assert_eq!(vortex_array.len(), 4);
970
        assert_eq!(vortex_array_non_null.len(), 4);
971

972
        // Verify metadata - should be VarBinArray with Utf8 dtype
973
        let varbin_array = vortex_array.as_::<VarBinVTable>();
974
        assert_eq!(varbin_array.dtype(), &DType::Utf8(true.into()));
975

976
        let varbin_array_non_null = vortex_array_non_null.as_::<VarBinVTable>();
977
        assert_eq!(varbin_array_non_null.dtype(), &DType::Utf8(false.into()));
978
    }
979

980
    #[test]
981
    fn test_large_utf8_array_conversion() {
982
        let arrow_array =
983
            LargeStringArray::from(vec![Some("hello"), None, Some("world"), Some("test")]);
984
        let vortex_array = ArrayRef::from_arrow(&arrow_array, true);
985

986
        let arrow_array_non_null = LargeStringArray::from(vec!["hello", "world", "test", "vortex"]);
987
        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false);
988

989
        assert_eq!(vortex_array.len(), 4);
990
        assert_eq!(vortex_array_non_null.len(), 4);
991
    }
992

993
    #[test]
994
    fn test_binary_array_conversion() {
995
        let arrow_array = BinaryArray::from(vec![
996
            Some("hello".as_bytes()),
997
            None,
998
            Some("world".as_bytes()),
999
            Some("test".as_bytes()),
1000
        ]);
1001
        let vortex_array = ArrayRef::from_arrow(&arrow_array, true);
1002

1003
        let arrow_array_non_null = BinaryArray::from(vec![
1004
            "hello".as_bytes(),
1005
            "world".as_bytes(),
1006
            "test".as_bytes(),
1007
            "vortex".as_bytes(),
1008
        ]);
1009
        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false);
1010

1011
        assert_eq!(vortex_array.len(), 4);
1012
        assert_eq!(vortex_array_non_null.len(), 4);
1013
    }
1014

1015
    #[test]
1016
    fn test_large_binary_array_conversion() {
1017
        let arrow_array = LargeBinaryArray::from(vec![
1018
            Some("hello".as_bytes()),
1019
            None,
1020
            Some("world".as_bytes()),
1021
            Some("test".as_bytes()),
1022
        ]);
1023
        let vortex_array = ArrayRef::from_arrow(&arrow_array, true);
1024

1025
        let arrow_array_non_null = LargeBinaryArray::from(vec![
1026
            "hello".as_bytes(),
1027
            "world".as_bytes(),
1028
            "test".as_bytes(),
1029
            "vortex".as_bytes(),
1030
        ]);
1031
        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false);
1032

1033
        assert_eq!(vortex_array.len(), 4);
1034
        assert_eq!(vortex_array_non_null.len(), 4);
1035
    }
1036

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

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

1055
        assert_eq!(vortex_array.len(), 4);
1056
        assert_eq!(vortex_array_non_null.len(), 4);
1057

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

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

1077
    #[test]
1078
    fn test_binary_view_array_conversion() {
1079
        let mut builder = BinaryViewBuilder::new();
1080
        builder.append_value(b"hello");
1081
        builder.append_null();
1082
        builder.append_value(b"world");
1083
        builder.append_value(b"test");
1084
        let arrow_array = builder.finish();
1085
        let vortex_array = ArrayRef::from_arrow(&arrow_array, true);
1086

1087
        let mut builder_non_null = BinaryViewBuilder::new();
1088
        builder_non_null.append_value(b"hello");
1089
        builder_non_null.append_value(b"world");
1090
        builder_non_null.append_value(b"test");
1091
        builder_non_null.append_value(b"vortex");
1092
        let arrow_array_non_null = builder_non_null.finish();
1093
        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false);
1094

1095
        assert_eq!(vortex_array.len(), 4);
1096
        assert_eq!(vortex_array_non_null.len(), 4);
1097

1098
        // Verify metadata - should be VarBinViewArray with correct buffer count and dtype
1099
        let varbin_view_array = vortex_array.as_::<VarBinViewVTable>();
1100
        assert_eq!(
1101
            varbin_view_array.buffers().len(),
1102
            arrow_array.data_buffers().len()
1103
        );
1104
        assert_eq!(varbin_view_array.dtype(), &DType::Binary(true.into()));
1105

1106
        let varbin_view_array_non_null = vortex_array_non_null.as_::<VarBinViewVTable>();
1107
        assert_eq!(
1108
            varbin_view_array_non_null.buffers().len(),
1109
            arrow_array_non_null.data_buffers().len()
1110
        );
1111
        assert_eq!(
1112
            varbin_view_array_non_null.dtype(),
1113
            &DType::Binary(false.into())
1114
        );
1115
    }
1116

1117
    // Test boolean array conversions
1118
    #[test]
1119
    fn test_boolean_array_conversion() {
1120
        let arrow_array = BooleanArray::from(vec![Some(true), None, Some(false), Some(true)]);
1121
        let vortex_array = ArrayRef::from_arrow(&arrow_array, true);
1122

1123
        let arrow_array_non_null = BooleanArray::from(vec![true, false, true, false]);
1124
        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false);
1125

1126
        assert_eq!(vortex_array.len(), 4);
1127
        assert_eq!(vortex_array_non_null.len(), 4);
1128
    }
1129

1130
    // Test struct array conversions
1131
    #[test]
1132
    fn test_struct_array_conversion() {
1133
        let fields = vec![
1134
            Field::new("field1", DataType::Int32, true),
1135
            Field::new("field2", DataType::Utf8, false),
1136
        ];
1137
        let schema = Fields::from(fields);
1138

1139
        let field1_data = Int32Array::from(vec![Some(1), None, Some(3)]);
1140
        let field2_data = StringArray::from(vec!["a", "b", "c"]);
1141

1142
        let arrow_array = StructArray::new(
1143
            schema.clone(),
1144
            vec![Arc::new(field1_data), Arc::new(field2_data)],
1145
            None,
1146
        );
1147

1148
        let vortex_array = ArrayRef::from_arrow(&arrow_array, false);
1149
        assert_eq!(vortex_array.len(), 3);
1150

1151
        // Verify metadata - should be StructArray with correct field names
1152
        let struct_vortex_array = vortex_array.as_::<StructVTable>();
1153
        assert_eq!(struct_vortex_array.names().len(), 2);
1154
        assert_eq!(struct_vortex_array.names()[0], "field1".into());
1155
        assert_eq!(struct_vortex_array.names()[1], "field2".into());
1156

1157
        // Test nullable struct
1158
        let nullable_array = StructArray::new(
1159
            schema,
1160
            vec![
1161
                Arc::new(Int32Array::from(vec![Some(1), None, Some(3)])),
1162
                Arc::new(StringArray::from(vec!["a", "b", "c"])),
1163
            ],
1164
            Some(arrow_buffer::NullBuffer::new(BooleanBuffer::from(vec![
1165
                true, false, true,
1166
            ]))),
1167
        );
1168

1169
        let vortex_nullable_array = ArrayRef::from_arrow(&nullable_array, true);
1170
        assert_eq!(vortex_nullable_array.len(), 3);
1171

1172
        // Verify metadata for nullable struct
1173
        let struct_vortex_nullable_array = vortex_nullable_array.as_::<StructVTable>();
1174
        assert_eq!(struct_vortex_nullable_array.names().len(), 2);
1175
        assert_eq!(struct_vortex_nullable_array.names()[0], "field1".into());
1176
        assert_eq!(struct_vortex_nullable_array.names()[1], "field2".into());
1177
    }
1178

1179
    // Test list array conversions
1180
    #[test]
1181
    fn test_list_array_conversion() {
1182
        let mut builder = ListBuilder::new(Int32Builder::new());
1183
        builder.append_value([Some(1), None, Some(3)]);
1184
        builder.append_null();
1185
        builder.append_value([Some(4), Some(5)]);
1186
        let arrow_array = builder.finish();
1187

1188
        let vortex_array = ArrayRef::from_arrow(&arrow_array, true);
1189
        assert_eq!(vortex_array.len(), 3);
1190

1191
        // Verify metadata - should be ListArray with correct offsets
1192
        let list_vortex_array = vortex_array.as_::<ListVTable>();
1193
        let offsets_array = list_vortex_array.offsets().as_::<PrimitiveVTable>();
1194
        assert_eq!(offsets_array.len(), 4); // n+1 offsets for n lists
1195
        assert_eq!(offsets_array.ptype(), PType::I32);
1196

1197
        // Test non-nullable list
1198
        let mut builder_non_null = ListBuilder::new(Int32Builder::new());
1199
        builder_non_null.append_value([Some(1), None, Some(3)]);
1200
        builder_non_null.append_value([Some(4), Some(5)]);
1201
        let arrow_array_non_null = builder_non_null.finish();
1202

1203
        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false);
1204
        assert_eq!(vortex_array_non_null.len(), 2);
1205

1206
        // Verify metadata for non-nullable list
1207
        let list_vortex_array_non_null = vortex_array_non_null.as_::<ListVTable>();
1208
        let offsets_array_non_null = list_vortex_array_non_null
1209
            .offsets()
1210
            .as_::<PrimitiveVTable>();
1211
        assert_eq!(offsets_array_non_null.len(), 3); // n+1 offsets for n lists
1212
        assert_eq!(offsets_array_non_null.ptype(), PType::I32);
1213
    }
1214

1215
    #[test]
1216
    fn test_large_list_array_conversion() {
1217
        let mut builder = LargeListBuilder::new(Int32Builder::new());
1218
        builder.append_value([Some(1), None, Some(3)]);
1219
        builder.append_null();
1220
        builder.append_value([Some(4), Some(5)]);
1221
        let arrow_array = builder.finish();
1222

1223
        let vortex_array = ArrayRef::from_arrow(&arrow_array, true);
1224
        assert_eq!(vortex_array.len(), 3);
1225

1226
        // Verify metadata - should be ListArray with correct offsets (I64 for large lists)
1227
        let list_vortex_array = vortex_array.as_::<ListVTable>();
1228
        let offsets_array = list_vortex_array.offsets().as_::<PrimitiveVTable>();
1229
        assert_eq!(offsets_array.len(), 4); // n+1 offsets for n lists
1230
        assert_eq!(offsets_array.ptype(), PType::I64); // Large lists use I64 offsets
1231

1232
        // Test non-nullable large list
1233
        let mut builder_non_null = LargeListBuilder::new(Int32Builder::new());
1234
        builder_non_null.append_value([Some(1), None, Some(3)]);
1235
        builder_non_null.append_value([Some(4), Some(5)]);
1236
        let arrow_array_non_null = builder_non_null.finish();
1237

1238
        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false);
1239
        assert_eq!(vortex_array_non_null.len(), 2);
1240

1241
        // Verify metadata for non-nullable large list
1242
        let list_vortex_array_non_null = vortex_array_non_null.as_::<ListVTable>();
1243
        let offsets_array_non_null = list_vortex_array_non_null
1244
            .offsets()
1245
            .as_::<PrimitiveVTable>();
1246
        assert_eq!(offsets_array_non_null.len(), 3); // n+1 offsets for n lists
1247
        assert_eq!(offsets_array_non_null.ptype(), PType::I64); // Large lists use I64 offsets
1248
    }
1249

1250
    // Test null array conversions
1251
    #[test]
1252
    fn test_null_array_conversion() {
1253
        let arrow_array = NullArray::new(5);
1254
        let vortex_array = ArrayRef::from_arrow(&arrow_array, true);
1255
        assert_eq!(vortex_array.len(), 5);
1256
    }
1257

1258
    // Test buffer conversions
1259
    #[test]
1260
    fn test_arrow_buffer_conversion() {
1261
        let data = vec![1u8, 2, 3, 4, 5];
1262
        let arrow_buffer = ArrowBuffer::from_vec(data);
1263
        let vortex_array = arrow_buffer.into_array();
1264
        assert_eq!(vortex_array.len(), 5);
1265
    }
1266

1267
    #[test]
1268
    fn test_boolean_buffer_conversion() {
1269
        let data = vec![true, false, true, false, true];
1270
        let boolean_buffer = BooleanBuffer::from(data);
1271
        let vortex_array = boolean_buffer.into_array();
1272
        assert_eq!(vortex_array.len(), 5);
1273
    }
1274

1275
    #[test]
1276
    fn test_scalar_buffer_conversion() {
1277
        let data = vec![1i32, 2, 3, 4, 5];
1278
        let scalar_buffer = ScalarBuffer::from(data);
1279
        let vortex_array = scalar_buffer.into_array();
1280
        assert_eq!(vortex_array.len(), 5);
1281
    }
1282

1283
    #[test]
1284
    fn test_offset_buffer_conversion() {
1285
        let data = vec![0i32, 2, 5, 8, 10];
1286
        let offset_buffer = OffsetBuffer::new(ScalarBuffer::from(data));
1287
        let vortex_array = offset_buffer.into_array();
1288
        assert_eq!(vortex_array.len(), 5);
1289
    }
1290

1291
    // Test RecordBatch conversions
1292
    #[test]
1293
    fn test_record_batch_conversion() {
1294
        let schema = Arc::new(Schema::new(vec![
1295
            Field::new("field1", DataType::Int32, false),
1296
            Field::new("field2", DataType::Utf8, false),
1297
        ]));
1298

1299
        let field1_data = Arc::new(Int32Array::from(vec![1, 2, 3, 4]));
1300
        let field2_data = Arc::new(StringArray::from(vec!["a", "b", "c", "d"]));
1301

1302
        let record_batch = RecordBatch::try_new(schema, vec![field1_data, field2_data]).unwrap();
1303

1304
        let vortex_array = ArrayRef::from_arrow(record_batch, false);
1305
        assert_eq!(vortex_array.len(), 4);
1306

1307
        // Test with reference
1308
        let schema = Arc::new(Schema::new(vec![
1309
            Field::new("field1", DataType::Int32, false),
1310
            Field::new("field2", DataType::Utf8, false),
1311
        ]));
1312

1313
        let field1_data = Arc::new(Int32Array::from(vec![1, 2, 3, 4]));
1314
        let field2_data = Arc::new(StringArray::from(vec!["a", "b", "c", "d"]));
1315

1316
        let record_batch = RecordBatch::try_new(schema, vec![field1_data, field2_data]).unwrap();
1317

1318
        let vortex_array = ArrayRef::from_arrow(&record_batch, false);
1319
        assert_eq!(vortex_array.len(), 4);
1320
    }
1321

1322
    // Test dynamic dispatch conversion
1323
    #[test]
1324
    fn test_dyn_array_conversion() {
1325
        let int_array = Int32Array::from(vec![1, 2, 3, 4]);
1326
        let dyn_array: &dyn ArrowArray = &int_array;
1327
        let vortex_array = ArrayRef::from_arrow(dyn_array, false);
1328
        assert_eq!(vortex_array.len(), 4);
1329

1330
        let string_array = StringArray::from(vec!["a", "b", "c"]);
1331
        let dyn_array: &dyn ArrowArray = &string_array;
1332
        let vortex_array = ArrayRef::from_arrow(dyn_array, false);
1333
        assert_eq!(vortex_array.len(), 3);
1334

1335
        let bool_array = BooleanArray::from(vec![true, false, true]);
1336
        let dyn_array: &dyn ArrowArray = &bool_array;
1337
        let vortex_array = ArrayRef::from_arrow(dyn_array, false);
1338
        assert_eq!(vortex_array.len(), 3);
1339
    }
1340

1341
    // Existing tests
1342
    #[test]
1343
    pub fn nullable_may_contain_non_nullable() {
1344
        let null_struct_array_with_non_nullable_field = new_null_array(
1345
            &DataType::Struct(Fields::from(vec![Field::new(
1346
                "non_nullable_inner",
1347
                DataType::Int32,
1348
                false,
1349
            )])),
1350
            1,
1351
        );
1352
        ArrayRef::from_arrow(null_struct_array_with_non_nullable_field.as_ref(), true);
1353
    }
1354

1355
    #[test]
1356
    pub fn nullable_may_contain_deeply_nested_non_nullable() {
1357
        let null_struct_array_with_non_nullable_field = new_null_array(
1358
            &DataType::Struct(Fields::from(vec![Field::new(
1359
                "non_nullable_inner",
1360
                DataType::Struct(Fields::from(vec![Field::new(
1361
                    "non_nullable_deeper_inner",
1362
                    DataType::Int32,
1363
                    false,
1364
                )])),
1365
                false,
1366
            )])),
1367
            1,
1368
        );
1369
        ArrayRef::from_arrow(null_struct_array_with_non_nullable_field.as_ref(), true);
1370
    }
1371

1372
    #[test]
1373
    #[should_panic]
1374
    pub fn cannot_handle_nullable_struct_containing_non_nullable_dictionary() {
1375
        let null_struct_array_with_non_nullable_field = new_null_array(
1376
            &DataType::Struct(Fields::from(vec![Field::new(
1377
                "non_nullable_deeper_inner",
1378
                DataType::Dictionary(Box::new(DataType::Int32), Box::new(DataType::Utf8)),
1379
                false,
1380
            )])),
1381
            1,
1382
        );
1383

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

© 2026 Coveralls, Inc