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

vortex-data / vortex / 16574428268

28 Jul 2025 04:19PM UTC coverage: 81.787% (-0.002%) from 81.789%
16574428268

Pull #4031

github

web-flow
Merge dd94a6b4b into 904980150
Pull Request #4031: zip compute function

106 of 140 new or added lines in 1 file covered. (75.71%)

179 existing lines in 17 files now uncovered.

43402 of 53067 relevant lines covered (81.79%)

171372.57 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 std::sync::Arc;
5

6
use arrow_array::array::{
7
    Array as ArrowArray, ArrowPrimitiveType, BooleanArray as ArrowBooleanArray, GenericByteArray,
8
    NullArray as ArrowNullArray, OffsetSizeTrait, PrimitiveArray as ArrowPrimitiveArray,
9
    StructArray as ArrowStructArray,
10
};
11
use arrow_array::cast::{AsArray, as_null_array};
12
use arrow_array::types::{
13
    ByteArrayType, ByteViewType, Date32Type, Date64Type, Decimal128Type, Decimal256Type,
14
    Float16Type, Float32Type, Float64Type, Int8Type, Int16Type, Int32Type, Int64Type,
15
    Time32MillisecondType, Time32SecondType, Time64MicrosecondType, Time64NanosecondType,
16
    TimestampMicrosecondType, TimestampMillisecondType, TimestampNanosecondType,
17
    TimestampSecondType, UInt8Type, UInt16Type, UInt32Type, UInt64Type,
18
};
19
use arrow_array::{GenericByteViewArray, GenericListArray, RecordBatch, make_array};
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 {
1✔
40
        PrimitiveArray::from_byte_buffer(
1✔
41
            ByteBuffer::from_arrow_buffer(self, Alignment::of::<u8>()),
1✔
42
            PType::U8,
1✔
43
            Validity::NonNullable,
1✔
44
        )
1✔
45
        .into_array()
1✔
46
    }
1✔
47
}
48

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

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

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

78
        primitive.into_array()
58✔
79
    }
58✔
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 {
4,290✔
86
                let buffer = Buffer::from_arrow_scalar_buffer(value.values().clone());
4,290✔
87
                let validity = nulls(value.nulls(), nullable);
4,290✔
88
                PrimitiveArray::new(buffer, validity).into_array()
4,290✔
89
            }
4,290✔
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 {
28✔
108
        let decimal_type = DecimalDType::new(array.precision(), array.scale());
28✔
109
        let buffer = Buffer::from_arrow_scalar_buffer(array.values().clone());
28✔
110
        let validity = nulls(array.nulls(), nullable);
28✔
111
        DecimalArray::new(buffer, decimal_type, validity).into_array()
28✔
112
    }
28✔
113
}
114

115
impl FromArrowArray<&ArrowPrimitiveArray<Decimal256Type>> for ArrayRef {
116
    fn from_arrow(array: &ArrowPrimitiveArray<Decimal256Type>, nullable: bool) -> Self {
2✔
117
        let decimal_type = DecimalDType::new(array.precision(), array.scale());
2✔
118
        let buffer = Buffer::from_arrow_scalar_buffer(array.values().clone());
2✔
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 =
2✔
123
            unsafe { std::mem::transmute::<Buffer<arrow_buffer::i256>, Buffer<i256>>(buffer) };
2✔
124
        let validity = nulls(array.nulls(), nullable);
2✔
125
        DecimalArray::new(buffer, decimal_type, validity).into_array()
2✔
126
    }
2✔
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 {
110✔
133
                temporal_array(value, nullable)
110✔
134
            }
110✔
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
110✔
156
where
110✔
157
    T::Native: NativePType,
110✔
158
{
159
    let arr = PrimitiveArray::new(
110✔
160
        Buffer::from_arrow_scalar_buffer(value.values().clone()),
110✔
161
        nulls(value.nulls(), nullable),
110✔
162
    )
163
    .into_array();
110✔
164

165
    match T::DATA_TYPE {
110✔
166
        DataType::Timestamp(time_unit, tz) => {
84✔
167
            let tz = tz.map(|s| s.to_string());
84✔
168
            TemporalArray::new_timestamp(arr, time_unit.into(), tz).into()
84✔
169
        }
170
        DataType::Time32(time_unit) => TemporalArray::new_time(arr, time_unit.into()).into(),
4✔
171
        DataType::Time64(time_unit) => TemporalArray::new_time(arr, time_unit.into()).into(),
4✔
172
        DataType::Date32 => TemporalArray::new_date(arr, TimeUnit::D).into(),
16✔
173
        DataType::Date64 => TemporalArray::new_date(arr, TimeUnit::Ms).into(),
2✔
174
        DataType::Duration(_) => unimplemented!(),
×
UNCOV
175
        DataType::Interval(_) => unimplemented!(),
×
UNCOV
176
        _ => vortex_panic!("Invalid temporal type: {}", T::DATA_TYPE),
×
177
    }
178
}
110✔
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 {
52✔
185
        let dtype = match T::DATA_TYPE {
52✔
186
            DataType::Binary | DataType::LargeBinary => DType::Binary(nullable.into()),
4✔
187
            DataType::Utf8 | DataType::LargeUtf8 => DType::Utf8(nullable.into()),
48✔
UNCOV
188
            _ => vortex_panic!("Invalid data type for ByteArray: {}", T::DATA_TYPE),
×
189
        };
190
        VarBinArray::try_new(
52✔
191
            value.offsets().clone().into_array(),
52✔
192
            ByteBuffer::from_arrow_buffer(value.values().clone(), Alignment::of::<u8>()),
52✔
193
            dtype,
52✔
194
            nulls(value.nulls(), nullable),
52✔
195
        )
52✔
196
        .vortex_expect("Failed to convert Arrow GenericByteArray to Vortex VarBinArray")
52✔
197
        .into_array()
52✔
198
    }
52✔
199
}
200

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

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

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

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

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

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

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

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

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

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

337
fn nulls(nulls: Option<&NullBuffer>, nullable: bool) -> Validity {
14,951✔
338
    if nullable {
14,951✔
339
        nulls
9,779✔
340
            .map(|nulls| {
9,779✔
341
                if nulls.null_count() == nulls.len() {
2,462✔
342
                    Validity::AllInvalid
5✔
343
                } else {
344
                    Validity::from(nulls.inner().clone())
2,457✔
345
                }
346
            })
2,462✔
347
            .unwrap_or_else(|| Validity::AllValid)
9,779✔
348
    } else {
349
        assert!(nulls.map(|x| x.null_count() == 0).unwrap_or(true));
5,172✔
350
        Validity::NonNullable
5,172✔
351
    }
352
}
14,951✔
353

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

427
impl FromArrowArray<RecordBatch> for ArrayRef {
428
    fn from_arrow(array: RecordBatch, nullable: bool) -> Self {
134✔
429
        ArrayRef::from_arrow(&arrow_array::StructArray::from(array), nullable)
134✔
430
    }
134✔
431
}
432

433
impl FromArrowArray<&RecordBatch> for ArrayRef {
434
    fn from_arrow(array: &RecordBatch, nullable: bool) -> Self {
19✔
435
        Self::from_arrow(array.clone(), nullable)
19✔
436
    }
19✔
437
}
438

439
#[cfg(test)]
440
mod tests {
441
    use std::sync::Arc;
442

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

461
    use crate::arrays::{
462
        DecimalVTable, ListVTable, PrimitiveVTable, StructVTable, TemporalArray, VarBinVTable,
463
        VarBinViewVTable,
464
    };
465
    use crate::arrow::FromArrowArray as _;
466
    use crate::{ArrayRef, IntoArray};
467

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

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

477
        assert_eq!(vortex_array.len(), 4);
1✔
478
        assert_eq!(vortex_array_non_null.len(), 4);
1✔
479

480
        // Verify metadata - should be PrimitiveArray with I8 ptype
481
        let primitive_array = vortex_array.as_::<PrimitiveVTable>();
1✔
482
        assert_eq!(primitive_array.ptype(), PType::I8);
1✔
483

484
        let primitive_array_non_null = vortex_array_non_null.as_::<PrimitiveVTable>();
1✔
485
        assert_eq!(primitive_array_non_null.ptype(), PType::I8);
1✔
486
    }
1✔
487

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

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

496
        assert_eq!(vortex_array.len(), 4);
1✔
497
        assert_eq!(vortex_array_non_null.len(), 4);
1✔
498

499
        // Verify metadata - should be PrimitiveArray with I16 ptype
500
        let primitive_array = vortex_array.as_::<PrimitiveVTable>();
1✔
501
        assert_eq!(primitive_array.ptype(), PType::I16);
1✔
502

503
        let primitive_array_non_null = vortex_array_non_null.as_::<PrimitiveVTable>();
1✔
504
        assert_eq!(primitive_array_non_null.ptype(), PType::I16);
1✔
505
    }
1✔
506

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

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

515
        assert_eq!(vortex_array.len(), 4);
1✔
516
        assert_eq!(vortex_array_non_null.len(), 4);
1✔
517

518
        // Verify metadata - should be PrimitiveArray with I32 ptype
519
        let primitive_array = vortex_array.as_::<PrimitiveVTable>();
1✔
520
        assert_eq!(primitive_array.ptype(), PType::I32);
1✔
521

522
        let primitive_array_non_null = vortex_array_non_null.as_::<PrimitiveVTable>();
1✔
523
        assert_eq!(primitive_array_non_null.ptype(), PType::I32);
1✔
524
    }
1✔
525

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

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

534
        assert_eq!(vortex_array.len(), 4);
1✔
535
        assert_eq!(vortex_array_non_null.len(), 4);
1✔
536

537
        // Verify metadata - should be PrimitiveArray with I64 ptype
538
        let primitive_array = vortex_array.as_::<PrimitiveVTable>();
1✔
539
        assert_eq!(primitive_array.ptype(), PType::I64);
1✔
540

541
        let primitive_array_non_null = vortex_array_non_null.as_::<PrimitiveVTable>();
1✔
542
        assert_eq!(primitive_array_non_null.ptype(), PType::I64);
1✔
543
    }
1✔
544

545
    #[test]
546
    fn test_uint8_array_conversion() {
1✔
547
        let arrow_array = UInt8Array::from(vec![Some(1), None, Some(3), Some(4)]);
1✔
548
        let vortex_array = ArrayRef::from_arrow(&arrow_array, true);
1✔
549

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

553
        assert_eq!(vortex_array.len(), 4);
1✔
554
        assert_eq!(vortex_array_non_null.len(), 4);
1✔
555

556
        // Verify metadata - should be PrimitiveArray with U8 ptype
557
        let primitive_array = vortex_array.as_::<PrimitiveVTable>();
1✔
558
        assert_eq!(primitive_array.ptype(), PType::U8);
1✔
559

560
        let primitive_array_non_null = vortex_array_non_null.as_::<PrimitiveVTable>();
1✔
561
        assert_eq!(primitive_array_non_null.ptype(), PType::U8);
1✔
562
    }
1✔
563

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

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

572
        assert_eq!(vortex_array.len(), 4);
1✔
573
        assert_eq!(vortex_array_non_null.len(), 4);
1✔
574

575
        // Verify metadata - should be PrimitiveArray with U16 ptype
576
        let primitive_array = vortex_array.as_::<PrimitiveVTable>();
1✔
577
        assert_eq!(primitive_array.ptype(), PType::U16);
1✔
578

579
        let primitive_array_non_null = vortex_array_non_null.as_::<PrimitiveVTable>();
1✔
580
        assert_eq!(primitive_array_non_null.ptype(), PType::U16);
1✔
581
    }
1✔
582

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

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

591
        assert_eq!(vortex_array.len(), 4);
1✔
592
        assert_eq!(vortex_array_non_null.len(), 4);
1✔
593

594
        // Verify metadata - should be PrimitiveArray with U32 ptype
595
        let primitive_array = vortex_array.as_::<PrimitiveVTable>();
1✔
596
        assert_eq!(primitive_array.ptype(), PType::U32);
1✔
597

598
        let primitive_array_non_null = vortex_array_non_null.as_::<PrimitiveVTable>();
1✔
599
        assert_eq!(primitive_array_non_null.ptype(), PType::U32);
1✔
600
    }
1✔
601

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

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

610
        assert_eq!(vortex_array.len(), 4);
1✔
611
        assert_eq!(vortex_array_non_null.len(), 4);
1✔
612

613
        // Verify metadata - should be PrimitiveArray with U64 ptype
614
        let primitive_array = vortex_array.as_::<PrimitiveVTable>();
1✔
615
        assert_eq!(primitive_array.ptype(), PType::U64);
1✔
616

617
        let primitive_array_non_null = vortex_array_non_null.as_::<PrimitiveVTable>();
1✔
618
        assert_eq!(primitive_array_non_null.ptype(), PType::U64);
1✔
619
    }
1✔
620

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

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

639
        assert_eq!(vortex_array.len(), 3);
1✔
640
        assert_eq!(vortex_array_non_null.len(), 2);
1✔
641

642
        // Verify metadata - should be PrimitiveArray with F16 ptype
643
        let primitive_array = vortex_array.as_::<PrimitiveVTable>();
1✔
644
        assert_eq!(primitive_array.ptype(), PType::F16);
1✔
645

646
        let primitive_array_non_null = vortex_array_non_null.as_::<PrimitiveVTable>();
1✔
647
        assert_eq!(primitive_array_non_null.ptype(), PType::F16);
1✔
648
    }
1✔
649

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

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

658
        assert_eq!(vortex_array.len(), 4);
1✔
659
        assert_eq!(vortex_array_non_null.len(), 4);
1✔
660

661
        // Verify metadata - should be PrimitiveArray with F32 ptype
662
        let primitive_array = vortex_array.as_::<PrimitiveVTable>();
1✔
663
        assert_eq!(primitive_array.ptype(), PType::F32);
1✔
664

665
        let primitive_array_non_null = vortex_array_non_null.as_::<PrimitiveVTable>();
1✔
666
        assert_eq!(primitive_array_non_null.ptype(), PType::F32);
1✔
667
    }
1✔
668

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

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

677
        assert_eq!(vortex_array.len(), 4);
1✔
678
        assert_eq!(vortex_array_non_null.len(), 4);
1✔
679

680
        // Verify metadata - should be PrimitiveArray with F64 ptype
681
        let primitive_array = vortex_array.as_::<PrimitiveVTable>();
1✔
682
        assert_eq!(primitive_array.ptype(), PType::F64);
1✔
683

684
        let primitive_array_non_null = vortex_array_non_null.as_::<PrimitiveVTable>();
1✔
685
        assert_eq!(primitive_array_non_null.ptype(), PType::F64);
1✔
686
    }
1✔
687

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

698
        let vortex_array = ArrayRef::from_arrow(&decimal_array, true);
1✔
699
        assert_eq!(vortex_array.len(), 4);
1✔
700

701
        let mut builder_non_null = Decimal128Builder::with_capacity(3);
1✔
702
        builder_non_null.append_value(12345);
1✔
703
        builder_non_null.append_value(67890);
1✔
704
        builder_non_null.append_value(11111);
1✔
705
        let decimal_array_non_null = builder_non_null
1✔
706
            .finish()
1✔
707
            .with_precision_and_scale(10, 2)
1✔
708
            .unwrap();
1✔
709

710
        let vortex_array_non_null = ArrayRef::from_arrow(&decimal_array_non_null, false);
1✔
711
        assert_eq!(vortex_array_non_null.len(), 3);
1✔
712

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

718
        let decimal_vortex_array_non_null = vortex_array_non_null.as_::<DecimalVTable>();
1✔
719
        assert_eq!(
1✔
720
            decimal_vortex_array_non_null.decimal_dtype().precision(),
1✔
721
            10
722
        );
723
        assert_eq!(decimal_vortex_array_non_null.decimal_dtype().scale(), 2);
1✔
724
    }
1✔
725

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

735
        let vortex_array = ArrayRef::from_arrow(&decimal_array, true);
1✔
736
        assert_eq!(vortex_array.len(), 4);
1✔
737

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

747
        let vortex_array_non_null = ArrayRef::from_arrow(&decimal_array_non_null, false);
1✔
748
        assert_eq!(vortex_array_non_null.len(), 3);
1✔
749

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

755
        let decimal_vortex_array_non_null = vortex_array_non_null.as_::<DecimalVTable>();
1✔
756
        assert_eq!(
1✔
757
            decimal_vortex_array_non_null.decimal_dtype().precision(),
1✔
758
            38
759
        );
760
        assert_eq!(decimal_vortex_array_non_null.decimal_dtype().scale(), 10);
1✔
761
    }
1✔
762

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

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

773
        assert_eq!(vortex_array.len(), 4);
1✔
774
        assert_eq!(vortex_array_non_null.len(), 4);
1✔
775

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

780
        let temporal_array_non_null =
1✔
781
            TemporalArray::try_from(vortex_array_non_null.clone()).unwrap();
1✔
782
        assert_eq!(
1✔
783
            temporal_array_non_null.temporal_metadata().time_unit(),
1✔
784
            TimeUnit::S
785
        );
786
    }
1✔
787

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

794
        let arrow_array_non_null =
1✔
795
            TimestampMillisecondArray::from(vec![1000_i64, 2000, 3000, 4000]);
1✔
796
        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false);
1✔
797

798
        assert_eq!(vortex_array.len(), 4);
1✔
799
        assert_eq!(vortex_array_non_null.len(), 4);
1✔
800
    }
1✔
801

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

808
        let arrow_array_non_null =
1✔
809
            TimestampMicrosecondArray::from(vec![1000_i64, 2000, 3000, 4000]);
1✔
810
        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false);
1✔
811

812
        assert_eq!(vortex_array.len(), 4);
1✔
813
        assert_eq!(vortex_array_non_null.len(), 4);
1✔
814
    }
1✔
815

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

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

825
        assert_eq!(vortex_array.len(), 4);
1✔
826
        assert_eq!(vortex_array_non_null.len(), 4);
1✔
827
    }
1✔
828

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

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

837
        assert_eq!(vortex_array.len(), 4);
1✔
838
        assert_eq!(vortex_array_non_null.len(), 4);
1✔
839

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

844
        let temporal_array_non_null =
1✔
845
            TemporalArray::try_from(vortex_array_non_null.clone()).unwrap();
1✔
846
        assert_eq!(
1✔
847
            temporal_array_non_null.temporal_metadata().time_unit(),
1✔
848
            TimeUnit::S
849
        );
850
    }
1✔
851

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

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

861
        assert_eq!(vortex_array.len(), 4);
1✔
862
        assert_eq!(vortex_array_non_null.len(), 4);
1✔
863
    }
1✔
864

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

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

874
        assert_eq!(vortex_array.len(), 4);
1✔
875
        assert_eq!(vortex_array_non_null.len(), 4);
1✔
876
    }
1✔
877

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

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

887
        assert_eq!(vortex_array.len(), 4);
1✔
888
        assert_eq!(vortex_array_non_null.len(), 4);
1✔
889
    }
1✔
890

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

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

899
        assert_eq!(vortex_array.len(), 4);
1✔
900
        assert_eq!(vortex_array_non_null.len(), 4);
1✔
901
    }
1✔
902

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

913
        let arrow_array_non_null = Date64Array::from(vec![
1✔
914
            1555200000000_i64,
915
            1555213600000,
916
            1555286400000,
917
            1555372800000,
918
        ]);
919
        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false);
1✔
920

921
        assert_eq!(vortex_array.len(), 4);
1✔
922
        assert_eq!(vortex_array_non_null.len(), 4);
1✔
923
    }
1✔
924

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

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

934
        assert_eq!(vortex_array.len(), 4);
1✔
935
        assert_eq!(vortex_array_non_null.len(), 4);
1✔
936

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

941
        let varbin_array_non_null = vortex_array_non_null.as_::<VarBinVTable>();
1✔
942
        assert_eq!(varbin_array_non_null.dtype(), &DType::Utf8(false.into()));
1✔
943
    }
1✔
944

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

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

954
        assert_eq!(vortex_array.len(), 4);
1✔
955
        assert_eq!(vortex_array_non_null.len(), 4);
1✔
956
    }
1✔
957

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

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

976
        assert_eq!(vortex_array.len(), 4);
1✔
977
        assert_eq!(vortex_array_non_null.len(), 4);
1✔
978
    }
1✔
979

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

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

998
        assert_eq!(vortex_array.len(), 4);
1✔
999
        assert_eq!(vortex_array_non_null.len(), 4);
1✔
1000
    }
1✔
1001

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

1012
        let mut builder_non_null = StringViewBuilder::new();
1✔
1013
        builder_non_null.append_value("hello");
1✔
1014
        builder_non_null.append_value("world");
1✔
1015
        builder_non_null.append_value("test");
1✔
1016
        builder_non_null.append_value("vortex");
1✔
1017
        let arrow_array_non_null = builder_non_null.finish();
1✔
1018
        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false);
1✔
1019

1020
        assert_eq!(vortex_array.len(), 4);
1✔
1021
        assert_eq!(vortex_array_non_null.len(), 4);
1✔
1022

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

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

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

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

1060
        assert_eq!(vortex_array.len(), 4);
1✔
1061
        assert_eq!(vortex_array_non_null.len(), 4);
1✔
1062

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

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

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

1088
        let arrow_array_non_null = BooleanArray::from(vec![true, false, true, false]);
1✔
1089
        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false);
1✔
1090

1091
        assert_eq!(vortex_array.len(), 4);
1✔
1092
        assert_eq!(vortex_array_non_null.len(), 4);
1✔
1093
    }
1✔
1094

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

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

1107
        let arrow_array = StructArray::new(
1✔
1108
            schema.clone(),
1✔
1109
            vec![Arc::new(field1_data), Arc::new(field2_data)],
1✔
1110
            None,
1✔
1111
        );
1112

1113
        let vortex_array = ArrayRef::from_arrow(&arrow_array, false);
1✔
1114
        assert_eq!(vortex_array.len(), 3);
1✔
1115

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

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

1134
        let vortex_nullable_array = ArrayRef::from_arrow(&nullable_array, true);
1✔
1135
        assert_eq!(vortex_nullable_array.len(), 3);
1✔
1136

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

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

1153
        let vortex_array = ArrayRef::from_arrow(&arrow_array, true);
1✔
1154
        assert_eq!(vortex_array.len(), 3);
1✔
1155

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

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

1168
        let vortex_array_non_null = ArrayRef::from_arrow(&arrow_array_non_null, false);
1✔
1169
        assert_eq!(vortex_array_non_null.len(), 2);
1✔
1170

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1269
        let vortex_array = ArrayRef::from_arrow(record_batch, false);
1✔
1270
        assert_eq!(vortex_array.len(), 4);
1✔
1271

1272
        // Test with reference
1273
        let schema = Arc::new(Schema::new(vec![
1✔
1274
            Field::new("field1", DataType::Int32, false),
1✔
1275
            Field::new("field2", DataType::Utf8, false),
1✔
1276
        ]));
1277

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

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

1283
        let vortex_array = ArrayRef::from_arrow(&record_batch, false);
1✔
1284
        assert_eq!(vortex_array.len(), 4);
1✔
1285
    }
1✔
1286

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

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

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

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

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

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

1349
        ArrayRef::from_arrow(null_struct_array_with_non_nullable_field.as_ref(), true);
1✔
1350
    }
1✔
1351
}
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