use key_paths_core::KeyPaths;
use std::collections::HashMap;
pub struct LazyJoinQuery<'a, L: 'static, R: 'static> {
left: &'a [L],
right: &'a [R],
}
impl<'a, L: 'static, R: 'static> LazyJoinQuery<'a, L, R> {
pub fn new(left: &'a [L], right: &'a [R]) -> Self {
Self { left, right }
}
pub fn inner_join_lazy<K, O, F>(
&self,
left_key: KeyPaths<L, K>,
right_key: KeyPaths<R, K>,
mapper: F,
) -> impl Iterator<Item = O> + 'a
where
K: Eq + std::hash::Hash + Clone + 'static,
F: Fn(&'a L, &'a R) -> O + 'a,
O: 'a,
{
let mut right_index: HashMap<K, Vec<&'a R>> = HashMap::new();
for item in self.right.iter() {
if let Some(key) = right_key.get(item).cloned() {
right_index.entry(key).or_insert_with(Vec::new).push(item);
}
}
self.left.iter().flat_map(move |left_item| {
let key_opt = left_key.get(left_item).cloned();
if let Some(key) = key_opt {
if let Some(right_items) = right_index.get(&key) {
let matches: Vec<O> = right_items.iter()
.map(|right_item| mapper(left_item, right_item))
.collect();
matches.into_iter()
} else {
Vec::<O>::new().into_iter()
}
} else {
Vec::<O>::new().into_iter()
}
})
}
pub fn left_join_lazy<K, O, F>(
&self,
left_key: KeyPaths<L, K>,
right_key: KeyPaths<R, K>,
mapper: F,
) -> impl Iterator<Item = O> + 'a
where
K: Eq + std::hash::Hash + Clone + 'static,
F: Fn(&'a L, Option<&'a R>) -> O + 'a,
O: 'a,
{
let mut right_index: HashMap<K, Vec<&'a R>> = HashMap::new();
for item in self.right.iter() {
if let Some(key) = right_key.get(item).cloned() {
right_index.entry(key).or_insert_with(Vec::new).push(item);
}
}
self.left.iter().flat_map(move |left_item| {
let key_opt = left_key.get(left_item).cloned();
if let Some(key) = key_opt {
if let Some(right_items) = right_index.get(&key) {
let matches: Vec<O> = right_items.iter()
.map(|right_item| mapper(left_item, Some(right_item)))
.collect();
matches.into_iter()
} else {
vec![mapper(left_item, None)].into_iter()
}
} else {
vec![mapper(left_item, None)].into_iter()
}
})
}
pub fn inner_join_where_lazy<K, O, F, P>(
&self,
left_key: KeyPaths<L, K>,
right_key: KeyPaths<R, K>,
predicate: P,
mapper: F,
) -> impl Iterator<Item = O> + 'a
where
K: Eq + std::hash::Hash + Clone + 'static,
F: Fn(&'a L, &'a R) -> O + 'a,
P: Fn(&'a L, &'a R) -> bool + 'a,
O: 'a,
{
let mut right_index: HashMap<K, Vec<&'a R>> = HashMap::new();
for item in self.right.iter() {
if let Some(key) = right_key.get(item).cloned() {
right_index.entry(key).or_insert_with(Vec::new).push(item);
}
}
self.left.iter().flat_map(move |left_item| {
let key_opt = left_key.get(left_item).cloned();
if let Some(key) = key_opt {
if let Some(right_items) = right_index.get(&key) {
let matches: Vec<O> = right_items.iter()
.filter(|right_item| predicate(left_item, right_item))
.map(|right_item| mapper(left_item, right_item))
.collect();
matches.into_iter()
} else {
Vec::<O>::new().into_iter()
}
} else {
Vec::<O>::new().into_iter()
}
})
}
}