use crate::eval::graph::plan::{
BindSpec, DirectionFilter, GraphPlanConvert, NodeFilter, NodeMatch, PathMode, TripleFilter,
TripleStepFilter, TripleStepMatch, ValueFilter,
};
use crate::eval::graph::result::{PathPatternNodes, Triple};
use crate::eval::graph::string_graph::StringGraphTypes;
use crate::eval::graph::types::GraphTypes;
use crate::eval::EvalContext;
use indexmap::IndexSet;
use partiql_value::Value;
use rustc_hash::FxBuildHasher;
pub trait GraphEngine<GT: GraphTypes>:
GraphScan<GT>
+ GraphPlanConvert<StringGraphTypes, GT>
+ GraphPlanConvert<GT, StringGraphTypes>
+ GraphAccess<GT>
+ GraphFilter<GT>
{
}
pub trait GraphScan<GT: GraphTypes> {
fn scan(&self, spec: &TripleStepMatch<GT>, ctx: &dyn EvalContext) -> Vec<Triple<GT>>;
fn get(&self, spec: &NodeMatch<GT>, ctx: &dyn EvalContext) -> Vec<GT::NodeId>;
}
type FxIndexSet<T> = IndexSet<T, FxBuildHasher>;
pub trait GraphFilter<GT: GraphTypes> {
fn filter_path_nodes(
&self,
binders: &[BindSpec<GT>],
spec: &ValueFilter,
bindings: FxIndexSet<PathPatternNodes<GT>>,
ctx: &dyn EvalContext,
) -> FxIndexSet<PathPatternNodes<GT>>;
}
pub trait GraphAccess<GT: GraphTypes> {
fn node(&self, id: >::NodeId) -> &Option<Value>;
fn edge(&self, id: >::EdgeId) -> &Option<Value>;
}
pub trait TripleScan<GT: GraphTypes> {
fn scan_directed_from_to(
&self,
binders: &(BindSpec<GT>, BindSpec<GT>, BindSpec<GT>),
spec: &TripleFilter<GT>,
allow_repeated_nodes: bool,
filter: &ValueFilter,
ctx: &dyn EvalContext,
) -> impl Iterator<Item = Triple<GT>>;
fn scan_directed_to_from(
&self,
binders: &(BindSpec<GT>, BindSpec<GT>, BindSpec<GT>),
spec: &TripleFilter<GT>,
allow_repeated_nodes: bool,
filter: &ValueFilter,
ctx: &dyn EvalContext,
) -> impl Iterator<Item = Triple<GT>>;
fn scan_directed_both(
&self,
binders: &(BindSpec<GT>, BindSpec<GT>, BindSpec<GT>),
spec: &TripleFilter<GT>,
allow_repeated_nodes: bool,
filter: &ValueFilter,
ctx: &dyn EvalContext,
) -> impl Iterator<Item = Triple<GT>>;
fn scan_undirected(
&self,
binders: &(BindSpec<GT>, BindSpec<GT>, BindSpec<GT>),
spec: &TripleFilter<GT>,
allow_repeated_nodes: bool,
filter: &ValueFilter,
ctx: &dyn EvalContext,
) -> impl Iterator<Item = Triple<GT>>;
fn get(
&self,
binder: &BindSpec<GT>,
spec: &NodeFilter<GT>,
ctx: &dyn EvalContext,
) -> Vec<GT::NodeId>;
}
impl<T, GT> GraphScan<GT> for T
where
GT: GraphTypes,
T: TripleScan<GT>,
{
fn scan(&self, spec: &TripleStepMatch<GT>, ctx: &dyn EvalContext) -> Vec<Triple<GT>> {
let TripleStepMatch {
binders,
spec: TripleStepFilter { dir, triple },
filter,
path_mode,
} = spec;
let (to_from, undirected, from_to) = match dir {
DirectionFilter::L => (true, false, false),
DirectionFilter::U => (false, true, false),
DirectionFilter::R => (false, false, true),
DirectionFilter::LU => (true, true, false),
DirectionFilter::UR => (false, true, true),
DirectionFilter::LR => (true, false, true),
DirectionFilter::LUR => (true, true, true),
};
let allow_repeated_nodes = !matches!(path_mode, PathMode::Acyclic);
let mut result = vec![];
if undirected {
result.extend(self.scan_undirected(binders, triple, allow_repeated_nodes, filter, ctx));
}
match (from_to, to_from) {
(true, true) => {
result.extend(self.scan_directed_both(
binders,
triple,
allow_repeated_nodes,
filter,
ctx,
));
}
(true, false) => {
result.extend(self.scan_directed_from_to(
binders,
triple,
allow_repeated_nodes,
filter,
ctx,
));
}
(false, true) => {
result.extend(self.scan_directed_to_from(
binders,
triple,
allow_repeated_nodes,
filter,
ctx,
));
}
(false, false) => {}
}
result
}
fn get(&self, spec: &NodeMatch<GT>, ctx: &dyn EvalContext) -> Vec<GT::NodeId> {
let NodeMatch { binder, spec } = spec;
TripleScan::get(self, binder, spec, ctx)
}
}