use ciborium::Value as CborValue;
use vantage_core::{Context, Result, VantageError, error};
use vantage_types::Record;
use super::{JoinKey, Reference};
use crate::filter::FilterOp;
use crate::vista::Vista;
#[cfg(test)]
mod tests;
impl Reference {
pub fn narrow(&self, mut target: Vista, row: &Record<CborValue>) -> Result<Vista> {
if self.kind.is_contained() || self.keys.is_empty() {
return Err(error!(
"relation has no join keys to narrow by",
relation = self.name.as_str(),
kind = self.kind.as_str()
)
.mark_incorrect_usage());
}
for key in &self.keys {
self.narrow_key(&mut target, key, row)?;
}
Ok(target)
}
fn narrow_key(&self, target: &mut Vista, key: &JoinKey, row: &Record<CborValue>) -> Result<()> {
let relation = self.name.as_str();
let value = row
.get(&key.from)
.or_else(|| crate::eval::path_get(row, &key.from))
.ok_or_else(|| {
error!(
"parent row lacks the join column",
relation = relation,
column = key.from.as_str()
)
})?;
let column = match key.target_column(target) {
Ok(column) => column.to_string(),
Err(e) => return Err(wrap(e, relation, &key.from)),
};
target
.add_condition(&column, FilterOp::Eq, value.clone())
.map_err(|e| wrap(e, relation, &column))
}
}
fn wrap(err: VantageError, relation: &str, column: &str) -> VantageError {
let (unsupported, unimplemented) = (err.is_unsupported(), err.is_unimplemented());
let wrapped = Err::<(), _>(err)
.with_context(|| {
error!(
"can't narrow the relation's target to the parent row",
relation = relation,
column = column
)
})
.unwrap_err();
if unsupported {
wrapped.mark_unsupported()
} else if unimplemented {
wrapped.mark_unimplemented()
} else {
wrapped
}
}