use crate::filter::Filter;
use crate::CanonicalValue;
#[derive(Debug, Clone, Default)]
pub struct Transforms {
pub filter: Option<Filter>,
pub select: Option<Vec<String>>,
pub rename: Vec<(String, String)>,
pub limit: Option<usize>,
}
impl Transforms {
pub fn is_empty(&self) -> bool {
self.filter.is_none()
&& self.select.is_none()
&& self.rename.is_empty()
&& self.limit.is_none()
}
pub fn apply_to_row(
&self,
mut row: Vec<(String, CanonicalValue)>,
) -> Option<Vec<(String, CanonicalValue)>> {
if let Some(f) = &self.filter {
let wrapped = CanonicalValue::Object(row.clone());
if !f.matches(&wrapped) {
return None;
}
}
for (from, to) in &self.rename {
for (k, _) in row.iter_mut() {
if k == from {
*k = to.clone();
break;
}
}
}
if let Some(sel) = &self.select {
let mut new_row = Vec::with_capacity(sel.len());
for name in sel {
match row.iter().find(|(k, _)| k == name) {
Some((k, v)) => new_row.push((k.clone(), v.clone())),
None => new_row.push((name.clone(), CanonicalValue::Null)),
}
}
row = new_row;
}
Some(row)
}
pub fn apply_to_array(&self, value: &CanonicalValue) -> CanonicalValue {
let rows = match value {
CanonicalValue::Array(a) => a,
_ => return value.clone(),
};
let limit = self.limit.unwrap_or(usize::MAX);
let mut out = Vec::new();
for row in rows {
if out.len() >= limit {
break;
}
match row {
CanonicalValue::Object(o) => {
if let Some(new_row) = self.apply_to_row(o.clone()) {
out.push(CanonicalValue::Object(new_row));
}
}
other => out.push(other.clone()),
}
}
CanonicalValue::Array(out)
}
}