use crate::spec::DataField;
use std::collections::HashMap;
pub const NULL_FIELD_INDEX: i32 = -1;
pub fn create_index_mapping(
table_fields: &[DataField],
data_fields: &[DataField],
) -> Option<Vec<i32>> {
let mut field_id_to_index: HashMap<i32, i32> = HashMap::with_capacity(data_fields.len());
for (i, field) in data_fields.iter().enumerate() {
field_id_to_index.insert(field.id(), i as i32);
}
let mut index_mapping = Vec::with_capacity(table_fields.len());
for field in table_fields {
let data_index = field_id_to_index
.get(&field.id())
.copied()
.unwrap_or(NULL_FIELD_INDEX);
index_mapping.push(data_index);
}
let is_identity = index_mapping.len() == data_fields.len()
&& index_mapping
.iter()
.enumerate()
.all(|(i, &idx)| idx == i as i32);
if is_identity {
None
} else {
Some(index_mapping)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::spec::{DataType, IntType, VarCharType};
fn field(id: i32, name: &str) -> DataField {
DataField::new(id, name.to_string(), DataType::Int(IntType::new()))
}
#[test]
fn test_identity_mapping() {
let table_fields = vec![field(0, "a"), field(1, "b"), field(2, "c")];
let data_fields = vec![field(0, "a"), field(1, "b"), field(2, "c")];
assert_eq!(create_index_mapping(&table_fields, &data_fields), None);
}
#[test]
fn test_added_column() {
let table_fields = vec![field(0, "a"), field(1, "b"), field(2, "c")];
let data_fields = vec![field(0, "a"), field(1, "b")];
assert_eq!(
create_index_mapping(&table_fields, &data_fields),
Some(vec![0, 1, -1])
);
}
#[test]
fn test_reordered_fields() {
let table_fields = vec![field(1, "c"), field(6, "b"), field(3, "a")];
let data_fields = vec![field(1, "a"), field(3, "c")];
assert_eq!(
create_index_mapping(&table_fields, &data_fields),
Some(vec![0, -1, 1])
);
}
#[test]
fn test_renamed_column() {
let table_fields = vec![field(0, "id"), field(1, "new_name")];
let data_fields = vec![field(0, "id"), field(1, "old_name")];
assert_eq!(create_index_mapping(&table_fields, &data_fields), None);
}
#[test]
fn test_empty_data_fields() {
let table_fields = vec![field(0, "a"), field(1, "b")];
let data_fields: Vec<DataField> = vec![];
assert_eq!(
create_index_mapping(&table_fields, &data_fields),
Some(vec![-1, -1])
);
}
#[test]
fn test_type_promotion_same_mapping() {
let table_fields = vec![
DataField::new(0, "id".to_string(), DataType::Int(IntType::new())),
DataField::new(
1,
"name".to_string(),
DataType::VarChar(VarCharType::string_type()),
),
];
let data_fields = vec![
DataField::new(0, "id".to_string(), DataType::Int(IntType::new())),
DataField::new(
1,
"name".to_string(),
DataType::VarChar(VarCharType::string_type()),
),
];
assert_eq!(create_index_mapping(&table_fields, &data_fields), None);
}
}