use nodedb_physical::physical_plan::{ExchangeMode, ExchangeOp, PhysicalPlan, QueryOp};
pub(crate) fn streamable_gather_child(plan: &PhysicalPlan) -> Option<(PhysicalPlan, usize)> {
let PhysicalPlan::Query(QueryOp::Exchange(ExchangeOp {
child,
mode: ExchangeMode::Gather {
as_aggregate: false,
},
})) = plan
else {
return None;
};
if !child.is_streamable_unordered_scan() {
return None;
}
let limit = child.streamable_scan_limit();
Some(((**child).clone(), limit))
}
#[cfg(test)]
mod tests {
use super::*;
use nodedb_physical::physical_plan::{DocumentOp, ExchangeMode, ExchangeOp, QueryOp};
fn unordered_scan() -> PhysicalPlan {
PhysicalPlan::Document(DocumentOp::Scan {
collection: "docs".into(),
filters: Vec::new(),
limit: 1234,
offset: 0,
sort_keys: Vec::new(),
distinct: false,
projection: Vec::new(),
computed_columns: Vec::new(),
window_functions: Vec::new(),
system_time: nodedb_types::SystemTimeScope::Current,
valid_at_ms: None,
prefilter: None,
})
}
fn gather(child: PhysicalPlan, as_aggregate: bool) -> PhysicalPlan {
PhysicalPlan::Query(QueryOp::Exchange(ExchangeOp {
child: Box::new(child),
mode: ExchangeMode::Gather { as_aggregate },
}))
}
#[test]
fn streamable_gather_over_scan_yields_child_and_limit() {
let plan = gather(unordered_scan(), false);
let (child, limit) = streamable_gather_child(&plan).expect("eligible");
assert!(child.is_streamable_unordered_scan());
assert_eq!(limit, 1234);
}
#[test]
fn aggregate_gather_is_not_streamable() {
let plan = gather(unordered_scan(), true);
assert!(streamable_gather_child(&plan).is_none());
}
#[test]
fn bare_scan_without_exchange_is_not_streamable() {
assert!(streamable_gather_child(&unordered_scan()).is_none());
}
}