use crate::stream::joiner::{pair_row, Joiner};
use crate::stream::relational::{Concat, Leaf};
use super::fixtures::{RelAssignment, RelEmployee, RelShift};
fn sample_row<'e>(
assignment: &'e RelAssignment,
shift: &'e RelShift,
) -> Concat<'e, Leaf<'e, RelAssignment>, RelShift> {
pair_row(assignment, 0, shift, 0)
}
#[test]
fn row_aware_comparison_matches_with_strict_boundaries() {
use crate::stream::joiner::less_than_on;
let assignment = RelAssignment {
shift_id: 10,
employee_code: "e0".to_string(),
};
let shift = RelShift {
id: 10,
night: true,
};
let row = sample_row(&assignment, &shift);
let early = RelEmployee {
code: "e0".to_string(),
};
let _ = (row, early);
let condition = less_than_on(
|row: &Concat<Leaf<'_, RelAssignment>, RelShift>| row.left.entity.shift_id,
|employee: &RelEmployee| employee.code.len() as u32,
);
let row2 = sample_row(&assignment, &shift);
assert!(condition.matches(
&row2,
&RelEmployee {
code: "e0-extra-long-code".to_string(),
}
));
assert!(!condition.matches(
&row2,
&RelEmployee {
code: "".to_string(),
}
));
}
#[test]
fn row_aware_overlap_keeps_half_open_endpoint_semantics() {
use crate::stream::joiner::overlap_on;
let assignment = RelAssignment {
shift_id: 10,
employee_code: "e0".to_string(),
};
let shift = RelShift {
id: 10,
night: true,
};
let row = sample_row(&assignment, &shift);
let condition = overlap_on(
|row: &Concat<Leaf<'_, RelAssignment>, RelShift>| row.right.entity.id as i64,
|row: &Concat<Leaf<'_, RelAssignment>, RelShift>| row.right.entity.id as i64 + 10,
|employee: &RelEmployee| employee.code.len() as i64,
|employee: &RelEmployee| employee.code.len() as i64 + 5,
);
assert!(condition.matches(
&row,
&RelEmployee {
code: "e012345678".to_string(),
}
));
assert!(!condition.matches(
&row,
&RelEmployee {
code: "".to_string(),
}
));
}
#[test]
fn planned_strategies_route_indexable_conditions_to_indexes() {
use crate::stream::joiner::Strategy;
use crate::stream::joiner::{equal_bi, filtering_on, less_than, overlap_on, plan_strategy};
let eq = equal_bi(
|assignment: &RelAssignment| assignment.shift_id,
|shift: &RelShift| shift.id,
);
assert_eq!(plan_strategy(&eq), Strategy::EquiHash);
let cmp = less_than(
|assignment: &RelAssignment| assignment.shift_id,
|shift: &RelShift| shift.id,
);
assert_eq!(plan_strategy(&cmp), Strategy::OrderedScan);
let ov = overlap_on(
|row: &Concat<Leaf<'_, RelAssignment>, RelShift>| row.right.entity.id as i64,
|row: &Concat<Leaf<'_, RelAssignment>, RelShift>| row.right.entity.id as i64 + 10,
|employee: &RelEmployee| employee.code.len() as i64,
|employee: &RelEmployee| employee.code.len() as i64 + 5,
);
assert_eq!(plan_strategy(&ov), Strategy::IntervalNarrow);
let pred = filtering_on(
|row: &Concat<Leaf<'_, RelAssignment>, RelShift>, employee: &RelEmployee| {
row.left.entity.employee_code == employee.code
},
);
assert_eq!(plan_strategy(&pred), Strategy::Scan);
}
#[test]
fn and_normalizes_heterogeneous_conditions_with_combined_residual() {
use crate::stream::joiner::{equal_on, less_than_on, plan_strategy, Joiner, Strategy};
use crate::stream::relational::{operator::Pair, Leaf};
fn eq_key(row: &Pair<Leaf<'_, RelAssignment>, Leaf<'_, RelShift>>) -> u32 {
row.left.entity.shift_id
}
fn eq_right(shift: &Leaf<'_, RelShift>) -> u32 {
shift.entity.id
}
fn cmp_key(row: &Pair<Leaf<'_, RelAssignment>, Leaf<'_, RelShift>>) -> i64 {
row.left.entity.shift_id as i64
}
fn cmp_right(shift: &Leaf<'_, RelShift>) -> i64 {
shift.entity.id as i64 + 50
}
assert_eq!(
plan_strategy(&equal_on(eq_key, eq_right).and(less_than_on(cmp_key, cmp_right))),
Strategy::EquiHash
);
assert_eq!(
plan_strategy(&less_than_on(cmp_key, cmp_right).and(equal_on(eq_key, eq_right))),
Strategy::EquiHash
);
let assignment = RelAssignment {
shift_id: 10,
employee_code: "e0".to_string(),
};
let shift = RelShift {
id: 10,
night: true,
};
let row = Pair {
left: Leaf::new(&assignment, 0),
right: Leaf::new(&shift, 0),
};
assert!(equal_on(eq_key, eq_right)
.and(less_than_on(cmp_key, cmp_right))
.matches(&row, &row.right));
let low = RelShift { id: 0, night: true };
let low_leaf = Leaf::new(&low, 1);
assert!(!equal_on(eq_key, eq_right)
.and(less_than_on(cmp_key, cmp_right))
.matches(&row, &low_leaf));
}
#[test]
fn row_aware_predicate_matches_arbitrary_typed_conditions() {
use crate::stream::joiner::filtering_on;
let assignment = RelAssignment {
shift_id: 10,
employee_code: "e0".to_string(),
};
let shift = RelShift {
id: 10,
night: true,
};
let row = sample_row(&assignment, &shift);
let condition = filtering_on(
|row: &Concat<Leaf<'_, RelAssignment>, RelShift>, employee: &RelEmployee| {
row.left.entity.employee_code == employee.code && row.right.entity.night
},
);
assert!(condition.matches(
&row,
&RelEmployee {
code: "e0".to_string(),
}
));
assert!(!condition.matches(
&row,
&RelEmployee {
code: "e1".to_string(),
}
));
}