use super::*;
use crate::table::columnar::bytes_column_row;
fn u32_field(id: u16, absent: Absent) -> ProjectedField {
ProjectedField::new(id, TypeTag::Fixed(4), absent).unwrap()
}
fn fixed_column(id: u16, cells: &[[u8; 4]], validity: Option<Vec<u8>>) -> Column {
Column {
column_id: id,
type_tag: TypeTag::Fixed(4),
validity,
data: Slice::from(cells.concat()),
}
}
fn bytes_column(id: u16, cells: &[&[u8]], validity: Option<Vec<u8>>) -> Column {
Column {
column_id: id,
type_tag: TypeTag::Bytes,
validity,
data: frame_bytes_column(cells.len(), || cells.iter().copied()).unwrap(),
}
}
#[test]
fn a_default_of_the_wrong_width_is_refused_at_declaration() {
let field = ProjectedField::new(
5,
TypeTag::Fixed(4),
Absent::Default(Slice::from(&[1u8][..])),
);
assert!(matches!(field, Err(Error::Projection(_))));
}
#[test]
fn an_intrinsic_column_cannot_be_declared() {
let field = ProjectedField::new(COL_USER_KEY, TypeTag::Bytes, Absent::Null);
assert!(matches!(field, Err(Error::Projection(_))));
assert_eq!(
Some(TypeTag::Bytes),
ProjectedField::by_id(COL_USER_KEY).type_tag()
);
assert_eq!(None, ProjectedField::by_id(7).type_tag());
}
#[test]
fn a_missing_column_reads_as_declared() {
let batch = || ColumnBatch {
row_count: 3,
columns: vec![fixed_column(4, &[[1; 4], [2; 4], [3; 4]], None)],
};
let null = conform(batch(), &[u32_field(5, Absent::Null)]).unwrap();
let column = null.columns.first().unwrap();
assert_eq!(5, column.column_id);
assert_eq!(Some(vec![0u8]), column.validity);
assert_eq!(12, column.data.len());
let default = conform(
batch(),
&[u32_field(5, Absent::Default(Slice::from(&[9u8; 4][..])))],
)
.unwrap();
let column = default.columns.first().unwrap();
assert_eq!(None, column.validity);
assert_eq!(&[9u8; 12][..], &*column.data);
assert!(matches!(
conform(batch(), &[u32_field(5, Absent::Error)]),
Err(Error::Projection(_))
));
assert!(matches!(
conform(batch(), &[ProjectedField::by_id(5)]),
Err(Error::Projection(_))
));
}
#[test]
fn a_null_cell_reads_as_declared() {
let batch = || ColumnBatch {
row_count: 3,
columns: vec![
fixed_column(5, &[[1; 4], [0; 4], [3; 4]], Some(vec![0b101])),
bytes_column(6, &[b"a", b"", b"c"], Some(vec![0b101])),
],
};
let kept = conform(
batch(),
&[
u32_field(5, Absent::Null),
ProjectedField::new(6, TypeTag::Bytes, Absent::Null).unwrap(),
],
)
.unwrap();
assert_eq!(batch().columns, kept.columns);
let filled = conform(
batch(),
&[
u32_field(5, Absent::Default(Slice::from(&[9u8; 4][..]))),
ProjectedField::new(6, TypeTag::Bytes, Absent::Default(Slice::from(&b"zz"[..])))
.unwrap(),
],
)
.unwrap();
let [fixed, bytes] = filled.columns.as_slice() else {
panic!("two columns");
};
assert_eq!(None, fixed.validity);
assert_eq!([[1u8; 4], [9; 4], [3; 4]].concat(), &*fixed.data);
assert_eq!(None, bytes.validity);
let cells: Vec<&[u8]> = (0..3)
.map(|row| bytes_column_row(&bytes.data, 3, row).unwrap())
.collect();
assert_eq!(vec![&b"a"[..], b"zz", b"c"], cells);
assert!(matches!(
conform(batch(), &[u32_field(5, Absent::Error)]),
Err(Error::Projection(_))
));
}
#[test]
fn a_validity_bitmap_without_nulls_is_kept_and_satisfies_a_required_field() {
let column = fixed_column(5, &[[1; 4], [2; 4]], Some(vec![0b11]));
let batch = ColumnBatch {
row_count: 2,
columns: vec![column.clone()],
};
let out = conform(batch, &[u32_field(5, Absent::Error)]).unwrap();
assert_eq!(vec![column], out.columns);
}
#[test]
fn a_column_of_another_type_is_refused() {
let batch = ColumnBatch {
row_count: 1,
columns: vec![bytes_column(5, &[b"a"], None)],
};
assert!(matches!(
conform(batch, &[u32_field(5, Absent::Null)]),
Err(Error::Projection(_))
));
}
#[test]
fn columns_come_back_in_projection_order() {
let batch = ColumnBatch {
row_count: 1,
columns: vec![
fixed_column(4, &[[4; 4]], None),
fixed_column(5, &[[5; 4]], None),
fixed_column(6, &[[6; 4]], None),
],
};
let out = conform(batch, &[ProjectedField::by_id(6), ProjectedField::by_id(4)]).unwrap();
let ids: Vec<u16> = out.columns.iter().map(|c| c.column_id).collect();
assert_eq!(vec![6, 4, 5], ids);
}
#[test]
fn a_projected_row_checks_what_the_projector_writes() {
let fields = [u32_field(5, Absent::Null), ProjectedField::by_id(6)];
let mut cells = vec![None, None];
let mut row = ProjectedRow::new(&fields, &mut cells);
row.set(0, &[1, 2, 3, 4]).unwrap();
assert!(matches!(row.set(0, &[1, 2]), Err(Error::Projection(_))));
assert!(matches!(row.set(1, b"x"), Err(Error::Projection(_))));
assert!(matches!(row.set(2, b"x"), Err(Error::Projection(_))));
assert_eq!(vec![Some(vec![1, 2, 3, 4]), None], cells);
}