use crate::types::{
gvalue::{Primitive, PrimitivePredicate},
keys::{DegreeDirection, Rank, VertexKey},
prop_key::PropKey,
StoreError, ORDER_KEY_INLINE, SMALL_VECTOR_LENGTH, STEP_LABEL_INLINE, VERTEX_PROPS_LENGTH,
};
use smallvec::SmallVec;
use smol_str::SmolStr;
pub type OptimizerRule = fn(&mut LogicalPlan) -> Result<bool, StoreError>;
pub trait Optimizer {
fn optimize(&mut self, _: &OptimizerRule) -> Result<bool, StoreError> {
Ok(false)
}
}
#[derive(Clone)]
pub struct LogicalPlan {
pub steps: Vec<LogicalStep>,
}
impl Optimizer for LogicalPlan {
fn optimize(&mut self, rule: &OptimizerRule) -> Result<bool, StoreError> {
let mut changed = false;
for step in self.steps.iter_mut() {
changed |= step.optimize(rule)?;
}
changed |= rule(self)?;
Ok(changed)
}
}
impl LogicalPlan {
pub fn has_path_consumer(&self) -> bool {
fn scan(steps: &[LogicalStep]) -> bool {
use LogicalStep::*;
for s in steps {
match s {
As(_) | Select(_) | Path(_) | SimplePath(_) | CyclicPath(_) => return true,
Not(NotStep { plan }) if scan(&plan.steps) => {
return true;
}
And(AndStep { plans }) | Or(OrStep { plans }) => {
for p in plans {
if scan(&p.steps) {
return true;
}
}
}
Union(UnionStep { plans }) => {
for p in plans {
if scan(&p.steps) {
return true;
}
}
}
Coalesce(CoalesceStep { plans }) => {
for p in plans {
if scan(&p.steps) {
return true;
}
}
}
Where(WhereStep { plan }) if scan(&plan.steps) => {
return true;
}
Repeat(RepeatStep { body, until, emit, .. }) => {
if scan(&body.steps) {
return true;
}
if let Some(p) = until {
if scan(&p.steps) {
return true;
}
}
if let EmitSpec::If(p) = emit {
if scan(&p.steps) {
return true;
}
}
}
Choose(ChooseStep { predicate, true_choice, false_choice, .. }) => {
if scan(&predicate.steps) {
return true;
}
if scan(&true_choice.steps) {
return true;
}
if let Some(fc) = false_choice {
if scan(&fc.steps) {
return true;
}
}
}
Local(LocalStep { plan }) if scan(&plan.steps) => {
return true;
}
_ => {}
}
}
false
}
scan(&self.steps)
}
}
#[derive(Clone)]
pub enum LogicalStep {
Both(BothStep),
BothE(BothEStep),
Count(CountStep),
Degree(DegreeStep),
HasLabel(HasLabelStep),
HasProperty(HasPropertyStep),
In(InStep),
InE(InEStep),
Out(OutStep),
OutE(OutEStep),
InV(InVStep),
OtherV(OtherVStep),
OutV(OutVStep),
ScalarFilter(ScalarFilterStep),
Values(ValuesStep),
Properties(PropertiesStep),
Where(WhereStep),
Union(UnionStep),
AddV(AddVStep),
AddE(AddEStep),
From(FromStep),
To(ToStep),
Property(PropertyStep),
V(VStep),
E(EStep),
Limit(LimitStep),
HasId(HasIdStep),
Coalesce(CoalesceStep),
EndVertexFilter(EndVertexFilter),
Drop(DropStep),
Path(PathStep),
Dedup(DedupStep),
Fold(FoldStep),
Repeat(RepeatStep),
Not(NotStep),
And(AndStep),
Or(OrStep),
Sum(SumStep),
Mean(MeanStep),
Max(MaxStep),
Min(MinStep),
Unfold(UnfoldStep),
As(AsStep),
Select(SelectStep),
Range(RangeStep),
Skip(SkipStep),
Tail(TailStep),
Order(OrderStep),
SimplePath(SimplePathStep),
CyclicPath(CyclicPathStep),
Choose(ChooseStep),
Group(GroupStep),
GroupCount(GroupCountStep),
Id(IdStep),
Label(LabelStep),
Rank(RankStep),
HasRank(HasRankStep),
Constant(ConstantStep),
Identity(IdentityStep),
Local(LocalStep),
}
#[derive(Clone)]
pub enum EmitSpec {
Never,
Always,
If(LogicalPlan),
}
#[derive(Clone)]
pub struct RepeatStep {
pub body: LogicalPlan,
pub until: Option<LogicalPlan>,
pub times: Option<i64>,
pub emit: EmitSpec,
}
impl Optimizer for RepeatStep {
fn optimize(&mut self, optimizer_rule: &OptimizerRule) -> Result<bool, StoreError> {
let mut changed = false;
changed |= optimizer_rule(&mut self.body)?;
if let Some(ref mut until) = self.until {
changed |= optimizer_rule(until)?;
}
if let EmitSpec::If(ref mut plan) = self.emit {
changed |= optimizer_rule(plan)?;
}
Ok(changed)
}
}
#[derive(Clone)]
pub struct DropStep {}
impl Optimizer for DropStep {}
#[derive(Clone, Debug)]
pub struct PathStep {}
impl Optimizer for PathStep {}
#[derive(Clone, Debug)]
pub struct DedupStep {}
impl Optimizer for DedupStep {}
#[derive(Clone, Debug)]
pub struct FoldStep {}
impl Optimizer for FoldStep {}
#[derive(Clone)]
pub struct NotStep {
pub plan: LogicalPlan,
}
impl Optimizer for NotStep {
fn optimize(&mut self, optimizer_rule: &OptimizerRule) -> Result<bool, StoreError> {
optimizer_rule(&mut self.plan)
}
}
#[derive(Clone)]
pub struct AndStep {
pub plans: Vec<LogicalPlan>,
}
impl Optimizer for AndStep {
fn optimize(&mut self, optimizer_rule: &OptimizerRule) -> Result<bool, StoreError> {
let mut changed = false;
for plan in self.plans.iter_mut() {
changed |= optimizer_rule(plan)?;
}
Ok(changed)
}
}
#[derive(Clone)]
pub struct OrStep {
pub plans: Vec<LogicalPlan>,
}
impl Optimizer for OrStep {
fn optimize(&mut self, optimizer_rule: &OptimizerRule) -> Result<bool, StoreError> {
let mut changed = false;
for plan in self.plans.iter_mut() {
changed |= optimizer_rule(plan)?;
}
Ok(changed)
}
}
#[derive(Clone, Debug)]
pub struct SumStep {}
impl Optimizer for SumStep {}
#[derive(Clone, Debug)]
pub struct MeanStep {}
impl Optimizer for MeanStep {}
#[derive(Clone, Debug)]
pub struct MaxStep {}
impl Optimizer for MaxStep {}
#[derive(Clone, Debug)]
pub struct MinStep {}
impl Optimizer for MinStep {}
#[derive(Clone, Debug)]
pub struct UnfoldStep {}
impl Optimizer for UnfoldStep {}
#[derive(Clone, Debug)]
pub struct AsStep {
pub labels: SmallVec<[SmolStr; STEP_LABEL_INLINE]>,
}
impl Optimizer for AsStep {}
#[derive(Clone, Debug)]
pub struct SelectStep {
pub labels: SmallVec<[SmolStr; STEP_LABEL_INLINE]>,
}
impl Optimizer for SelectStep {}
#[derive(Clone, Debug)]
pub struct RangeStep {
pub lo: i64,
pub hi: i64,
}
impl Optimizer for RangeStep {}
#[derive(Clone, Debug)]
pub struct SkipStep {
pub n: i64,
}
impl Optimizer for SkipStep {}
#[derive(Clone, Debug)]
pub struct TailStep {
pub n: i64,
}
impl Optimizer for TailStep {}
#[derive(Clone, Debug, PartialEq, Eq, Copy)]
pub enum Order {
Asc,
Desc,
}
#[derive(Clone, Debug)]
pub enum OrderKeySpec {
Value,
Property(SmolStr),
}
#[derive(Clone, Debug)]
pub struct OrderKey {
pub spec: OrderKeySpec,
pub order: Order,
}
#[derive(Clone, Debug)]
pub struct OrderStep {
pub keys: SmallVec<[OrderKey; ORDER_KEY_INLINE]>,
}
impl Optimizer for OrderStep {}
#[derive(Clone, Debug)]
pub struct SimplePathStep {}
impl Optimizer for SimplePathStep {}
#[derive(Clone, Debug)]
pub struct CyclicPathStep {}
impl Optimizer for CyclicPathStep {}
#[derive(Clone)]
pub struct ChooseStep {
pub predicate: LogicalPlan,
pub true_choice: LogicalPlan,
pub false_choice: Option<LogicalPlan>,
}
impl Optimizer for ChooseStep {
fn optimize(&mut self, optimizer_rule: &OptimizerRule) -> Result<bool, StoreError> {
let mut changed = optimizer_rule(&mut self.predicate)?;
changed |= optimizer_rule(&mut self.true_choice)?;
if let Some(ref mut fc) = self.false_choice {
changed |= optimizer_rule(fc)?;
}
Ok(changed)
}
}
#[derive(Clone, Debug)]
pub struct GroupStep {
pub key: Option<SmolStr>,
}
impl Optimizer for GroupStep {}
#[derive(Clone, Debug)]
pub struct GroupCountStep {
pub key: Option<SmolStr>,
}
impl Optimizer for GroupCountStep {}
#[derive(Clone, Debug)]
pub struct IdentityStep {}
impl Optimizer for IdentityStep {}
#[derive(Clone, Debug)]
pub struct IdStep {}
impl Optimizer for IdStep {}
#[derive(Clone, Debug)]
pub struct LabelStep {}
impl Optimizer for LabelStep {}
#[derive(Clone, Debug)]
pub struct RankStep {}
impl Optimizer for RankStep {}
#[derive(Clone, Debug)]
pub struct HasRankStep {
pub pred: PrimitivePredicate,
}
impl Optimizer for HasRankStep {}
#[derive(Clone, Debug)]
pub struct ConstantStep {
pub value: Primitive,
}
impl Optimizer for ConstantStep {}
#[derive(Clone)]
pub struct LocalStep {
pub plan: LogicalPlan,
}
impl Optimizer for LocalStep {
fn optimize(&mut self, optimizer_rule: &OptimizerRule) -> Result<bool, StoreError> {
optimizer_rule(&mut self.plan)
}
}
impl Optimizer for LogicalStep {
fn optimize(&mut self, optimizer_rule: &OptimizerRule) -> Result<bool, StoreError> {
let mut changed = false;
match self {
LogicalStep::Where(wh) => changed |= wh.optimize(optimizer_rule)?,
LogicalStep::Union(u) => changed |= u.optimize(optimizer_rule)?,
LogicalStep::Coalesce(c) => changed |= c.optimize(optimizer_rule)?,
LogicalStep::Repeat(r) => changed |= r.optimize(optimizer_rule)?,
LogicalStep::Not(n) => changed |= n.optimize(optimizer_rule)?,
LogicalStep::And(a) => changed |= a.optimize(optimizer_rule)?,
LogicalStep::Or(o) => changed |= o.optimize(optimizer_rule)?,
LogicalStep::Choose(c) => changed |= c.optimize(optimizer_rule)?,
LogicalStep::Local(l) => changed |= l.optimize(optimizer_rule)?,
_ => {}
}
Ok(changed)
}
}
#[derive(Clone)]
pub struct EndVertexFilter {
pub ids: Option<SmallVec<[VertexKey; SMALL_VECTOR_LENGTH]>>,
pub label_preds: Vec<PrimitivePredicate>,
pub property_preds: Vec<(SmolStr, PrimitivePredicate)>,
}
impl Optimizer for EndVertexFilter {}
#[derive(Clone)]
pub struct CoalesceStep {
pub plans: Vec<LogicalPlan>,
}
impl Optimizer for CoalesceStep {
fn optimize(&mut self, optimizer_rule: &OptimizerRule) -> Result<bool, StoreError> {
let mut changed = false;
for plan in self.plans.iter_mut() {
changed |= optimizer_rule(plan)?;
}
Ok(changed)
}
}
#[derive(Clone)]
pub struct CountStep {}
impl Optimizer for CountStep {}
#[derive(Debug, Clone, PartialEq)]
pub struct DegreeStep {
pub direction: DegreeDirection,
}
impl Optimizer for DegreeStep {}
#[derive(Clone)]
pub struct BothStep {
pub labels: SmallVec<[SmolStr; SMALL_VECTOR_LENGTH]>,
pub end_vertex_ids: Option<SmallVec<[VertexKey; SMALL_VECTOR_LENGTH]>>,
}
impl Optimizer for BothStep {}
#[derive(Clone)]
pub struct BothEStep {
pub labels: SmallVec<[SmolStr; SMALL_VECTOR_LENGTH]>,
pub end_vertex_ids: Option<SmallVec<[VertexKey; SMALL_VECTOR_LENGTH]>>,
pub rank: Option<Rank>,
}
impl Optimizer for BothEStep {}
#[derive(Clone)]
pub struct HasLabelStep {
pub pred: PrimitivePredicate,
}
impl Optimizer for HasLabelStep {}
#[derive(Clone)]
pub struct HasPropertyStep {
pub key: PropKey,
pub pred: PrimitivePredicate,
}
impl Optimizer for HasPropertyStep {}
#[derive(Clone)]
pub struct InStep {
pub labels: SmallVec<[SmolStr; SMALL_VECTOR_LENGTH]>,
pub end_vertex_ids: Option<SmallVec<[VertexKey; SMALL_VECTOR_LENGTH]>>,
}
impl Optimizer for InStep {}
#[derive(Clone)]
pub struct InEStep {
pub labels: SmallVec<[SmolStr; SMALL_VECTOR_LENGTH]>,
pub end_vertex_ids: Option<SmallVec<[VertexKey; SMALL_VECTOR_LENGTH]>>,
pub rank: Option<Rank>,
}
impl Optimizer for InEStep {}
#[derive(Clone)]
pub struct OutStep {
pub labels: SmallVec<[SmolStr; SMALL_VECTOR_LENGTH]>,
pub end_vertex_ids: Option<SmallVec<[VertexKey; SMALL_VECTOR_LENGTH]>>,
}
impl Optimizer for OutStep {}
#[derive(Clone)]
pub struct OutEStep {
pub labels: SmallVec<[SmolStr; SMALL_VECTOR_LENGTH]>,
pub end_vertex_ids: Option<SmallVec<[VertexKey; SMALL_VECTOR_LENGTH]>>,
pub rank: Option<Rank>,
}
impl Optimizer for OutEStep {}
#[derive(Clone)]
pub struct InVStep {}
impl Optimizer for InVStep {}
#[derive(Clone)]
pub struct OtherVStep {}
impl Optimizer for OtherVStep {}
#[derive(Clone)]
pub struct OutVStep {}
impl Optimizer for OutVStep {}
#[derive(Clone)]
pub struct ScalarFilterStep {
pub pred: PrimitivePredicate,
}
impl Optimizer for ScalarFilterStep {}
#[derive(Clone)]
pub struct ValuesStep {
pub property_keys: SmallVec<[PropKey; SMALL_VECTOR_LENGTH]>,
}
impl Optimizer for ValuesStep {}
#[derive(Clone)]
pub struct PropertiesStep {
pub property_keys: SmallVec<[PropKey; SMALL_VECTOR_LENGTH]>,
}
impl Optimizer for PropertiesStep {}
#[derive(Clone)]
pub struct WhereStep {
pub plan: LogicalPlan,
}
impl Optimizer for WhereStep {
fn optimize(&mut self, optimizer_rule: &OptimizerRule) -> Result<bool, StoreError> {
optimizer_rule(&mut self.plan)
}
}
#[derive(Clone)]
pub struct UnionStep {
pub plans: SmallVec<[LogicalPlan; SMALL_VECTOR_LENGTH]>,
}
impl Optimizer for UnionStep {
fn optimize(&mut self, optimizer_rule: &OptimizerRule) -> Result<bool, StoreError> {
let mut changed = false;
for plan in self.plans.iter_mut() {
changed |= optimizer_rule(plan)?;
}
Ok(changed)
}
}
#[derive(Clone)]
pub struct AddVStep {
pub label: SmolStr,
pub vertex_id: Option<VertexKey>,
pub properties: SmallVec<[(PropKey, Primitive); VERTEX_PROPS_LENGTH]>,
}
impl Optimizer for AddVStep {}
#[derive(Clone)]
pub struct AddEStep {
pub label: SmolStr,
pub out_v_id: Option<VertexKey>,
pub in_v_id: Option<VertexKey>,
pub properties: SmallVec<[(PropKey, Primitive); VERTEX_PROPS_LENGTH]>,
pub rank: Option<Rank>,
}
impl Optimizer for AddEStep {}
#[derive(Clone)]
pub struct FromStep {
pub vertex_id: VertexKey,
}
impl Optimizer for FromStep {}
#[derive(Clone)]
pub struct ToStep {
pub vertex_id: VertexKey,
}
impl Optimizer for ToStep {}
#[derive(Clone)]
pub struct PropertyStep {
pub prop_key: PropKey,
pub prop_value: Primitive,
}
impl Optimizer for PropertyStep {}
#[derive(Clone)]
pub struct VStep {
pub ids: SmallVec<[VertexKey; SMALL_VECTOR_LENGTH]>,
}
impl Optimizer for VStep {}
#[derive(Clone)]
pub struct EStep {
pub keys: SmallVec<[String; SMALL_VECTOR_LENGTH]>,
}
impl Optimizer for EStep {}
#[derive(Clone)]
pub struct LimitStep {
pub limit: i64,
}
impl Optimizer for LimitStep {}
#[derive(Clone)]
pub struct HasIdStep {
pub pred: PrimitivePredicate,
}
impl Optimizer for HasIdStep {}