use std::collections::HashMap;
use std::hash::Hash;
use super::dix_data::DixData;
use super::dix_value::DixValue;
impl DixValue {
pub fn field(&self, name: &str) -> Option<&DixValue> {
self.as_object().and_then(|o| o.get(name))
}
pub fn field_path(&self, path: &str) -> Option<&DixValue> {
path.split('.').try_fold(self, |cur, segment| cur.field(segment))
}
pub fn query(&self) -> Option<DixQuery> {
self.as_array().map(DixQuery::from_slice)
}
}
#[derive(Debug, Clone, Default)]
pub struct DixQuery {
items: Vec<DixValue>,
}
impl DixQuery {
pub fn new(items: Vec<DixValue>) -> Self {
DixQuery { items }
}
pub fn from_slice(items: &[DixValue]) -> Self {
DixQuery { items: items.to_vec() }
}
pub fn where_(mut self, predicate: impl Fn(&DixValue) -> bool) -> Self {
self.items.retain(|v| predicate(v));
self
}
pub fn where_field_eq(self, field: &str, value: &DixValue) -> Self {
self.where_(move |v| v.field(field) == Some(value))
}
pub fn skip(mut self, n: usize) -> Self {
if n >= self.items.len() {
self.items.clear();
} else {
self.items.drain(0..n);
}
self
}
pub fn take(mut self, n: usize) -> Self {
self.items.truncate(n);
self
}
pub fn distinct(mut self) -> Self {
let mut out: Vec<DixValue> = Vec::with_capacity(self.items.len());
for v in self.items.drain(..) {
if !out.contains(&v) {
out.push(v);
}
}
self.items = out;
self
}
pub fn select<'q, T>(&'q self, map: impl Fn(&'q DixValue) -> T) -> Vec<T> {
self.items.iter().map(map).collect()
}
pub fn select_field(&self, name: &str) -> Vec<Option<DixValue>> {
self.items.iter().map(|v| v.field(name).cloned()).collect()
}
pub fn order_by<K: Ord>(mut self, key: impl Fn(&DixValue) -> K) -> Self {
self.items.sort_by_key(key);
self
}
pub fn order_by_desc<K: Ord>(mut self, key: impl Fn(&DixValue) -> K) -> Self {
self.items.sort_by(|a, b| key(b).cmp(&key(a)));
self
}
pub fn group_by<K: Eq + Hash + Clone>(
self,
key: impl Fn(&DixValue) -> K,
) -> Vec<(K, Vec<DixValue>)> {
let mut order: Vec<K> = Vec::new();
let mut groups: HashMap<K, Vec<DixValue>> = HashMap::new();
for v in self.items {
let k = key(&v);
if !groups.contains_key(&k) {
order.push(k.clone());
}
groups.entry(k).or_default().push(v);
}
order
.into_iter()
.map(|k| {
let vs = groups.remove(&k).unwrap_or_default();
(k, vs)
})
.collect()
}
pub fn any(&self, predicate: impl Fn(&DixValue) -> bool) -> bool {
self.items.iter().any(|v| predicate(v))
}
pub fn all(&self, predicate: impl Fn(&DixValue) -> bool) -> bool {
self.items.iter().all(|v| predicate(v))
}
pub fn count(&self) -> usize {
self.items.len()
}
pub fn is_empty(&self) -> bool {
self.items.is_empty()
}
pub fn first(&self) -> Option<&DixValue> {
self.items.first()
}
pub fn first_or<'d>(&'d self, default: &'d DixValue) -> &'d DixValue {
self.first().unwrap_or(default)
}
pub fn last(&self) -> Option<&DixValue> {
self.items.last()
}
pub fn nth(&self, index: usize) -> Option<&DixValue> {
self.items.get(index)
}
pub fn sum_int(&self) -> i64 {
self.items.iter().filter_map(DixValue::as_long).sum()
}
pub fn sum_float(&self) -> f64 {
self.items.iter().filter_map(DixValue::as_float).sum()
}
pub fn avg_float(&self) -> Option<f64> {
let (sum, n) = self.items.iter().filter_map(DixValue::as_float)
.fold((0.0_f64, 0usize), |(s, n), v| (s + v, n + 1));
if n == 0 { None } else { Some(sum / n as f64) }
}
pub fn min_by_key<K: Ord>(&self, key: impl Fn(&DixValue) -> K) -> Option<&DixValue> {
self.items.iter().min_by_key(|v| key(v))
}
pub fn max_by_key<K: Ord>(&self, key: impl Fn(&DixValue) -> K) -> Option<&DixValue> {
self.items.iter().max_by_key(|v| key(v))
}
pub fn to_vec(self) -> Vec<DixValue> {
self.items
}
pub fn as_slice(&self) -> &[DixValue] {
&self.items
}
pub fn iter(&self) -> std::slice::Iter<'_, DixValue> {
self.items.iter()
}
}
impl IntoIterator for DixQuery {
type Item = DixValue;
type IntoIter = std::vec::IntoIter<DixValue>;
fn into_iter(self) -> Self::IntoIter {
self.items.into_iter()
}
}
impl<'a> IntoIterator for &'a DixQuery {
type Item = &'a DixValue;
type IntoIter = std::slice::Iter<'a, DixValue>;
fn into_iter(self) -> Self::IntoIter {
self.items.iter()
}
}
impl FromIterator<DixValue> for DixQuery {
fn from_iter<I: IntoIterator<Item = DixValue>>(iter: I) -> Self {
DixQuery { items: iter.into_iter().collect() }
}
}
impl DixData {
pub fn query(&self, path: &str) -> Option<DixQuery> {
self.get_value(path).and_then(DixValue::query)
}
pub fn query_many(&self, pattern: &str) -> DixQuery {
DixQuery::new(self.select_many::<DixValue>(pattern))
}
}