use std::collections::BTreeMap;
use crate::qbe::SortOrder;
use crate::query_criteria::{compare, parse_predicate};
use crate::query_engine::EngineError;
use crate::schema::{FieldValue, TableDef};
pub fn view_order(
table: &TableDef,
rows: &[Vec<FieldValue>],
sort: Option<(&str, SortOrder)>,
filters: &BTreeMap<String, String>,
) -> Result<Vec<usize>, EngineError> {
let column_of = |name: &str| -> Result<usize, EngineError> {
table
.fields
.iter()
.position(|field| field.name.eq_ignore_ascii_case(name))
.ok_or(EngineError::UnknownField {
field: name.to_owned(),
table: table.name.clone(),
})
};
let mut predicates = Vec::new();
for (field, criteria) in filters {
let index = column_of(field)?;
let column = &table.fields[index];
predicates.push((index, parse_predicate(criteria, field, column)?));
}
let mut order: Vec<usize> = (0..rows.len()).collect();
order.retain(|&row| {
predicates
.iter()
.all(|(index, predicate)| predicate.matches(&rows[row][*index]))
});
if let Some((field, direction)) = sort {
let index = column_of(field)?;
let descending = direction == SortOrder::Descending;
order.sort_by(|&a, &b| {
let ordering =
compare(&rows[a][index], &rows[b][index]).unwrap_or(std::cmp::Ordering::Equal);
if descending {
ordering.reverse()
} else {
ordering
}
});
}
Ok(order)
}