use crate::pipeline::*;
pub(crate) fn is_bare(query: &Query) -> bool {
query.correlations.is_empty()
&& !query.branches.is_empty()
&& query.branches.iter().all(|b| {
matches!(b.anchor, Anchor::Root) && b.steps.is_empty() && b.projection.is_none()
})
}
pub(crate) fn eval_bare<H: Host>(
query: &Query,
host: &H,
outer: Option<&Scope<'_, H::Ext>>,
) -> (Vec<Thread<H::Ext>>, bool) {
let trace = H::Trace::default();
let mut caps: Vec<Thread<H::Ext>> = Vec::new();
for _ in &query.branches {
let t = Thread {
register: outer.map(|s| s.register.to_vec()).unwrap_or_default(),
topic: None,
prov: Prov::default(),
members: Vec::new(),
captures: outer.map(|s| s.captures.to_vec()).unwrap_or_default(),
named: outer.map(|s| s.named.to_vec()).unwrap_or_default(),
ext: host.root_ext(),
};
if !caps
.iter()
.any(|c| reg_key(&c.register) == reg_key(&t.register))
{
caps.push(t);
}
}
if outer.is_none()
&& let Some(seed) = run_option(|o| o.topic.clone())
{
for c in caps.iter_mut().filter(|c| c.topic.is_none()) {
c.topic = Some(seed.clone());
}
}
let at = query.join_at.min(query.pipeline.len());
let top = outer.is_none();
let start = if query.branches.iter().any(|b| b.projection.is_some()) {
crate::syntax::parser::PipeMode::Scalar
} else {
crate::syntax::parser::PipeMode::Nav
};
let mid = query.pipeline[..at]
.iter()
.fold(start, |m, c| crate::syntax::parser::command_mode_out(c, m));
caps = apply_commands(
&query.pipeline[..at],
start,
0,
top,
caps,
host,
&trace,
outer,
);
caps = apply_commands(
&query.pipeline[at..],
mid,
at,
top,
caps,
host,
&trace,
outer,
);
(caps, pipeline_projected(query))
}
pub(crate) fn pipeline_projected(query: &Query) -> bool {
let mut projected = query.branches.iter().any(|b| b.projection.is_some());
let mut before_group: Vec<bool> = Vec::new();
for command in &query.pipeline {
match command {
Command::Agg(call) if matches!(call.name.as_str(), "group" | "window") => {
before_group.push(projected);
projected = true;
}
Command::Agg(call) if call.name == "ungroup" => {
projected = before_group.pop().unwrap_or(false);
}
Command::Agg(call) if call.name == "collapse" => {}
Command::Nav(b) => projected = b.projection.is_some(),
s => projected = projected || command_projects(s),
}
}
projected
}
pub(crate) fn command_projects(command: &Command) -> bool {
match command {
Command::Select(_) | Command::Filter(_) => false,
Command::Push(_)
| Command::Subcontext { .. }
| Command::ExprPush { .. }
| Command::RecordPush { .. }
| Command::FieldsPush
| Command::AggPush { .. } => false,
Command::Repeat { command, .. } | Command::Attach { command, .. } => {
command_projects(command)
}
Command::Splice(_) | Command::Param { .. } => false,
Command::SessionPush(_) => false,
Command::Nav(b) => b.projection.is_some(),
Command::Agg(call) => {
!(stdlib::known_keyed(&call.name)
|| matches!(
call.name.as_str(),
"sort" | "unique" | "reverse" | "first" | "last"
))
|| call.name == "group"
}
_ => true,
}
}