use std::collections::BTreeMap;
use selene_core::DbString;
use crate::{
SourceSpan,
analyze::{BindingId, ExprId},
};
use super::{BindingTableColumn, ExecutionPlan, PatternPlan};
#[derive(Clone, Debug)]
pub struct PlannedSubquery {
pub kind: SubqueryKind,
pub body: SubqueryBody,
pub outer_binding_refs: Vec<OuterBindingRef>,
pub span: SourceSpan,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct OuterBindingRef {
pub binding: BindingId,
pub name: DbString,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum SubqueryKind {
Exists {
negated: bool,
},
Value,
}
#[derive(Clone, Debug)]
pub enum SubqueryBody {
Pattern(Box<PatternPlan>),
Plan(Box<ExecutionPlan>),
}
#[derive(Clone, Debug)]
pub struct PlannedTableSubquery {
pub optional: bool,
pub body: Box<ExecutionPlan>,
pub outer_binding_refs: Vec<OuterBindingRef>,
pub yield_items: Vec<PlannedTableSubqueryYield>,
pub yield_schema: Vec<BindingTableColumn>,
pub span: SourceSpan,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct PlannedTableSubqueryYield {
pub source: DbString,
pub output: DbString,
pub span: SourceSpan,
}
#[derive(Clone, Debug, Default)]
pub struct SubqueryRegistry {
by_expr_id: BTreeMap<ExprId, PlannedSubquery>,
}
impl SubqueryRegistry {
pub fn insert(&mut self, expr_id: ExprId, subquery: PlannedSubquery) {
self.by_expr_id.insert(expr_id, subquery);
}
#[must_use]
pub fn get(&self, expr_id: ExprId) -> Option<&PlannedSubquery> {
self.by_expr_id.get(&expr_id)
}
pub(crate) fn iter(&self) -> impl Iterator<Item = &PlannedSubquery> {
self.by_expr_id.values()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.by_expr_id.is_empty()
}
}
#[cfg(test)]
mod tests {
use crate::{
PatternPlan, SourceSpan,
analyze::ExprId,
plan::{JoinTree, PlannedSubquery, SubqueryBody, SubqueryKind, SubqueryRegistry},
};
fn planned_subquery() -> PlannedSubquery {
PlannedSubquery {
kind: SubqueryKind::Exists { negated: false },
body: SubqueryBody::Pattern(Box::new(PatternPlan {
bindings: Vec::new(),
join_tree: JoinTree::WorstCaseOptimal {
intersection: Vec::new(),
node_id_ordering: Vec::new(),
},
filters: Vec::new(),
paths: Vec::new(),
})),
outer_binding_refs: Vec::new(),
span: SourceSpan::default(),
}
}
#[test]
fn registry_insert_get_and_is_empty() {
let mut registry = SubqueryRegistry::default();
let expr_id = ExprId::new(7);
assert!(registry.is_empty());
registry.insert(expr_id, planned_subquery());
assert!(!registry.is_empty());
assert!(matches!(
registry.get(expr_id).map(|subquery| subquery.kind),
Some(SubqueryKind::Exists { negated: false })
));
assert!(registry.get(ExprId::new(8)).is_none());
}
}