|
fn roundtrip_int32() { |
|
Test { |
|
input: i32_array([ |
|
// row group 1 |
|
Some(1), |
|
None, |
|
Some(3), |
|
// row group 2 |
|
Some(0), |
|
Some(5), |
|
None, |
|
// row group 3 |
|
None, |
|
None, |
|
None, |
|
]), |
|
expected_min: i32_array([Some(1), Some(0), None]), |
|
expected_max: i32_array([Some(3), Some(5), None]), |
|
} |
|
.run() |
|
} |
|
|
|
#[test] |
|
fn roundtrip_int64() { |
|
Test { |
|
input: i64_array([ |
|
// row group 1 |
|
Some(1), |
|
None, |
|
Some(3), |
|
// row group 2 |
|
Some(0), |
|
Some(5), |
|
None, |
|
// row group 3 |
|
None, |
|
None, |
|
None, |
|
]), |
|
expected_min: i64_array([Some(1), Some(0), None]), |
|
expected_max: i64_array(vec![Some(3), Some(5), None]), |
|
} |
|
.run() |
|
} |
|
|
|
#[test] |
|
fn roundtrip_f32() { |
|
Test { |
|
input: f32_array([ |
|
// row group 1 |
|
Some(1.0), |
|
None, |
|
Some(3.0), |
|
// row group 2 |
|
Some(-1.0), |
|
Some(5.0), |
|
None, |
|
// row group 3 |
|
None, |
|
None, |
|
None, |
|
]), |
|
expected_min: f32_array([Some(1.0), Some(-1.0), None]), |
|
expected_max: f32_array([Some(3.0), Some(5.0), None]), |
|
} |
|
.run() |
|
} |
|
|
|
#[test] |
|
fn roundtrip_f64() { |
|
Test { |
|
input: f64_array([ |
|
// row group 1 |
|
Some(1.0), |
|
None, |
|
Some(3.0), |
|
// row group 2 |
|
Some(-1.0), |
|
Some(5.0), |
|
None, |
|
// row group 3 |
|
None, |
|
None, |
|
None, |
|
]), |
|
expected_min: f64_array([Some(1.0), Some(-1.0), None]), |
|
expected_max: f64_array([Some(3.0), Some(5.0), None]), |
|
} |
|
.run() |
|
} |
|
|
|
#[test] |
|
fn roundtrip_timestamp() { |
|
Test { |
|
input: timestamp_seconds_array( |
|
[ |
|
// row group 1 |
|
Some(1), |
|
None, |
|
Some(3), |
|
// row group 2 |
|
Some(9), |
|
Some(5), |
|
None, |
|
// row group 3 |
|
None, |
|
None, |
|
None, |
|
], |
|
None, |
|
), |
|
expected_min: timestamp_seconds_array([Some(1), Some(5), None], None), |
|
expected_max: timestamp_seconds_array([Some(3), Some(9), None], None), |
|
} |
|
.run(); |
|
|
|
Test { |
|
input: timestamp_milliseconds_array( |
|
[ |
|
// row group 1 |
|
Some(1), |
|
None, |
|
Some(3), |
|
// row group 2 |
|
Some(9), |
|
Some(5), |
|
None, |
|
// row group 3 |
|
None, |
|
None, |
|
None, |
|
], |
|
None, |
|
), |
|
expected_min: timestamp_milliseconds_array([Some(1), Some(5), None], None), |
|
expected_max: timestamp_milliseconds_array([Some(3), Some(9), None], None), |
|
} |
|
.run(); |
|
|
|
Test { |
|
input: timestamp_microseconds_array( |
|
[ |
|
// row group 1 |
|
Some(1), |
|
None, |
|
Some(3), |
|
// row group 2 |
|
Some(9), |
|
Some(5), |
|
None, |
|
// row group 3 |
|
None, |
|
None, |
|
None, |
|
], |
|
None, |
|
), |
|
expected_min: timestamp_microseconds_array([Some(1), Some(5), None], None), |
|
expected_max: timestamp_microseconds_array([Some(3), Some(9), None], None), |
|
} |
|
.run(); |
|
|
|
Test { |
|
input: timestamp_nanoseconds_array( |
|
[ |
|
// row group 1 |
|
Some(1), |
|
None, |
|
Some(3), |
|
// row group 2 |
|
Some(9), |
|
Some(5), |
|
None, |
|
// row group 3 |
|
None, |
|
None, |
|
None, |
|
], |
|
None, |
|
), |
|
expected_min: timestamp_nanoseconds_array([Some(1), Some(5), None], None), |
|
expected_max: timestamp_nanoseconds_array([Some(3), Some(9), None], None), |
|
} |
|
.run() |
|
} |
|
|
|
#[test] |
|
fn roundtrip_timestamp_timezoned() { |
|
Test { |
|
input: timestamp_seconds_array( |
|
[ |
|
// row group 1 |
|
Some(1), |
|
None, |
|
Some(3), |
|
// row group 2 |
|
Some(9), |
|
Some(5), |
|
None, |
|
// row group 3 |
|
None, |
|
None, |
|
None, |
|
], |
|
Some("UTC"), |
|
), |
|
expected_min: timestamp_seconds_array([Some(1), Some(5), None], Some("UTC")), |
|
expected_max: timestamp_seconds_array([Some(3), Some(9), None], Some("UTC")), |
|
} |
|
.run(); |
|
|
|
Test { |
|
input: timestamp_milliseconds_array( |
|
[ |
|
// row group 1 |
|
Some(1), |
|
None, |
|
Some(3), |
|
// row group 2 |
|
Some(9), |
|
Some(5), |
|
None, |
|
// row group 3 |
|
None, |
|
None, |
|
None, |
|
], |
|
Some("UTC"), |
|
), |
|
expected_min: timestamp_milliseconds_array([Some(1), Some(5), None], Some("UTC")), |
|
expected_max: timestamp_milliseconds_array([Some(3), Some(9), None], Some("UTC")), |
|
} |
|
.run(); |
|
|
|
Test { |
|
input: timestamp_microseconds_array( |
|
[ |
|
// row group 1 |
|
Some(1), |
|
None, |
|
Some(3), |
|
// row group 2 |
|
Some(9), |
|
Some(5), |
|
None, |
|
// row group 3 |
|
None, |
|
None, |
|
None, |
|
], |
|
Some("UTC"), |
|
), |
|
expected_min: timestamp_microseconds_array([Some(1), Some(5), None], Some("UTC")), |
|
expected_max: timestamp_microseconds_array([Some(3), Some(9), None], Some("UTC")), |
|
} |
|
.run(); |
|
|
|
Test { |
|
input: timestamp_nanoseconds_array( |
|
[ |
|
// row group 1 |
|
Some(1), |
|
None, |
|
Some(3), |
|
// row group 2 |
|
Some(9), |
|
Some(5), |
|
None, |
|
// row group 3 |
|
None, |
|
None, |
|
None, |
|
], |
|
Some("UTC"), |
|
), |
|
expected_min: timestamp_nanoseconds_array([Some(1), Some(5), None], Some("UTC")), |
|
expected_max: timestamp_nanoseconds_array([Some(3), Some(9), None], Some("UTC")), |
|
} |
|
.run() |
|
} |
|
|
|
#[test] |
|
fn roundtrip_decimal() { |
|
Test { |
|
input: Arc::new( |
|
Decimal128Array::from(vec![ |
|
// row group 1 |
|
Some(100), |
|
None, |
|
Some(22000), |
|
// row group 2 |
|
Some(500000), |
|
Some(330000), |
|
None, |
|
// row group 3 |
|
None, |
|
None, |
|
None, |
|
]) |
|
.with_precision_and_scale(9, 2) |
|
.unwrap(), |
|
), |
|
expected_min: Arc::new( |
|
Decimal128Array::from(vec![Some(100), Some(330000), None]) |
|
.with_precision_and_scale(9, 2) |
|
.unwrap(), |
|
), |
|
expected_max: Arc::new( |
|
Decimal128Array::from(vec![Some(22000), Some(500000), None]) |
|
.with_precision_and_scale(9, 2) |
|
.unwrap(), |
|
), |
|
} |
|
.run(); |
|
|
|
Test { |
|
input: Arc::new( |
|
Decimal256Array::from(vec![ |
|
// row group 1 |
|
Some(i256::from(100)), |
|
None, |
|
Some(i256::from(22000)), |
|
// row group 2 |
|
Some(i256::MAX), |
|
Some(i256::MIN), |
|
None, |
|
// row group 3 |
|
None, |
|
None, |
|
None, |
|
]) |
|
.with_precision_and_scale(76, 76) |
|
.unwrap(), |
|
), |
|
expected_min: Arc::new( |
|
Decimal256Array::from(vec![Some(i256::from(100)), Some(i256::MIN), None]) |
|
.with_precision_and_scale(76, 76) |
|
.unwrap(), |
|
), |
|
expected_max: Arc::new( |
|
Decimal256Array::from(vec![Some(i256::from(22000)), Some(i256::MAX), None]) |
|
.with_precision_and_scale(76, 76) |
|
.unwrap(), |
|
), |
|
} |
|
.run() |
|
} |
|
|
|
#[test] |
|
fn roundtrip_utf8() { |
|
Test { |
|
input: utf8_array([ |
|
// row group 1 |
|
Some("A"), |
|
None, |
|
Some("Q"), |
|
// row group 2 |
|
Some("ZZ"), |
|
Some("AA"), |
|
None, |
|
// row group 3 |
|
None, |
|
None, |
|
None, |
|
]), |
|
expected_min: utf8_array([Some("A"), Some("AA"), None]), |
|
expected_max: utf8_array([Some("Q"), Some("ZZ"), None]), |
|
} |
|
.run() |
|
} |
|
|
|
#[test] |
|
fn roundtrip_struct() { |
|
let mut test = Test { |
|
input: struct_array(vec![ |
|
// row group 1 |
|
(Some(true), Some(1)), |
|
(None, None), |
|
(Some(true), Some(3)), |
|
// row group 2 |
|
(Some(true), Some(0)), |
|
(Some(false), Some(5)), |
|
(None, None), |
|
// row group 3 |
|
(None, None), |
|
(None, None), |
|
(None, None), |
|
]), |
|
expected_min: struct_array(vec![ |
|
(Some(true), Some(1)), |
|
(Some(true), Some(0)), |
|
(None, None), |
|
]), |
|
|
|
expected_max: struct_array(vec![ |
|
(Some(true), Some(3)), |
|
(Some(true), Some(0)), |
|
(None, None), |
|
]), |
|
}; |
|
// Due to https://github.com/apache/datafusion/issues/8334, |
|
// statistics for struct arrays are not supported |
|
test.expected_min = new_null_array(test.input.data_type(), test.expected_min.len()); |
|
test.expected_max = new_null_array(test.input.data_type(), test.expected_min.len()); |
|
test.run() |
|
} |
|
|
|
#[test] |
|
fn roundtrip_binary() { |
|
Test { |
|
input: Arc::new(BinaryArray::from_opt_vec(vec![ |
|
// row group 1 |
|
Some(b"A"), |
|
None, |
|
Some(b"Q"), |
|
// row group 2 |
|
Some(b"ZZ"), |
|
Some(b"AA"), |
|
None, |
|
// row group 3 |
|
None, |
|
None, |
|
None, |
|
])), |
|
expected_min: Arc::new(BinaryArray::from_opt_vec(vec![ |
|
Some(b"A"), |
|
Some(b"AA"), |
|
None, |
|
])), |
|
expected_max: Arc::new(BinaryArray::from_opt_vec(vec![ |
|
Some(b"Q"), |
|
Some(b"ZZ"), |
|
None, |
|
])), |
|
} |
|
.run() |
|
} |
|
|
|
#[test] |
|
fn roundtrip_date32() { |
|
Test { |
|
input: date32_array(vec![ |
|
// row group 1 |
|
Some("2021-01-01"), |
|
None, |
|
Some("2021-01-03"), |
|
// row group 2 |
|
Some("2021-01-01"), |
|
Some("2021-01-05"), |
|
None, |
|
// row group 3 |
|
None, |
|
None, |
|
None, |
|
]), |
|
expected_min: date32_array(vec![Some("2021-01-01"), Some("2021-01-01"), None]), |
|
expected_max: date32_array(vec![Some("2021-01-03"), Some("2021-01-05"), None]), |
|
} |
|
.run() |
|
} |
|
|
|
#[test] |
|
fn roundtrip_date64() { |
|
Test { |
|
input: date64_array(vec![ |
|
// row group 1 |
|
Some("2021-01-01"), |
|
None, |
|
Some("2021-01-03"), |
|
// row group 2 |
|
Some("2021-01-01"), |
|
Some("2021-01-05"), |
|
None, |
|
// row group 3 |
|
None, |
|
None, |
|
None, |
|
]), |
|
expected_min: date64_array(vec![Some("2021-01-01"), Some("2021-01-01"), None]), |
|
expected_max: date64_array(vec![Some("2021-01-03"), Some("2021-01-05"), None]), |
|
} |
|
.run() |
|
} |
|
|
|
#[test] |
|
fn roundtrip_large_binary_array() { |
|
let input: Vec<Option<&[u8]>> = vec![ |
|
// row group 1 |
|
Some(b"A"), |
|
None, |
|
Some(b"Q"), |
|
// row group 2 |
|
Some(b"ZZ"), |
|
Some(b"AA"), |
|
None, |
|
// row group 3 |
|
None, |
|
None, |
|
None, |
|
]; |
|
|
|
let expected_min: Vec<Option<&[u8]>> = vec![Some(b"A"), Some(b"AA"), None]; |
|
let expected_max: Vec<Option<&[u8]>> = vec![Some(b"Q"), Some(b"ZZ"), None]; |
|
|
|
Test { |
|
input: large_binary_array(input), |
|
expected_min: large_binary_array(expected_min), |
|
expected_max: large_binary_array(expected_max), |
|
} |
|
.run(); |
|
} |
|
|
|
#[test] |
|
fn struct_and_non_struct() { |
|
// Ensures that statistics for an array that appears *after* a struct |
|
// array are not wrong |
|
let struct_col = struct_array(vec![ |
|
// row group 1 |
|
(Some(true), Some(1)), |
|
(None, None), |
|
(Some(true), Some(3)), |
|
]); |
|
let int_col = i32_array([Some(100), Some(200), Some(300)]); |
|
let expected_min = i32_array([Some(100)]); |
|
let expected_max = i32_array(vec![Some(300)]); |
|
|
|
// use a name that shadows a name in the struct column |
|
match struct_col.data_type() { |
|
DataType::Struct(fields) => { |
|
assert_eq!(fields.get(1).unwrap().name(), "int_col") |
|
} |
|
_ => panic!("unexpected data type for struct column"), |
|
}; |
|
|
|
let input_batch = |
|
RecordBatch::try_from_iter([("struct_col", struct_col), ("int_col", int_col)]).unwrap(); |
|
|
|
let schema = input_batch.schema(); |
|
|
|
let metadata = parquet_metadata(schema.clone(), input_batch); |
|
let parquet_schema = metadata.file_metadata().schema_descr(); |
|
|
|
// read the int_col statistics |
|
let (idx, _) = parquet_column(parquet_schema, &schema, "int_col").unwrap(); |
|
assert_eq!(idx, 2); |
|
|
|
let row_groups = metadata.row_groups(); |
|
let converter = StatisticsConverter::try_new("int_col", &schema, parquet_schema).unwrap(); |
|
|
|
let min = converter.row_group_mins(row_groups.iter()).unwrap(); |
|
assert_eq!( |
|
&min, |
|
&expected_min, |
|
"Min. Statistics\n\n{}\n\n", |
|
DisplayStats(row_groups) |
|
); |
|
|
|
let max = converter.row_group_maxes(row_groups.iter()).unwrap(); |
|
assert_eq!( |
|
&max, |
|
&expected_max, |
|
"Max. Statistics\n\n{}\n\n", |
|
DisplayStats(row_groups) |
|
); |
|
} |
|
|
Is your feature request related to a problem or challenge? Please describe what you are trying to do.
When adding additional support to the statistics converter as @Kev1n8 did in #6181 the presence of two sets of tests is quite confusing about where to add tests for the new test
There are tests in both
Describe the solution you'd like
I would like to remove the rundant tests
Describe alternatives you've considered
I think the clearest alternateive is to move all the tests from https://github.com/apache/arrow-rs/blob/master/parquet/src/arrow/arrow_reader/statistics.rs to https://github.com/apache/arrow-rs/blob/master/parquet/tests/arrow_reader/statistics.rs
We should only move the non duplicated tests.
So that means something like:
arrow-rs/parquet/src/arrow/arrow_reader/statistics.rs
Lines 1513 to 1522 in f2de2cd
arrow-rs/parquet/src/arrow/arrow_reader/statistics.rs
Lines 1548 to 2113 in f2de2cd
arrow-rs/parquet/src/arrow/arrow_reader/statistics.rs
Lines 2115 to 2235 in f2de2cd
arrow-rs/parquet/src/arrow/arrow_reader/statistics.rs
Lines 2237 to 2258 in f2de2cd
Additional context
This duplication is a historical artifact of how this code was developed in DataFusion and then it got brought over when @efredine ported the work in #6046