Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci_build_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ jobs:
# to format and use the output.
- name: Cargo Test of the conformance tests (can fail) and save to json file
continue-on-error: true
run: cargo test --verbose --package partiql-conformance-tests --features "conformance_test" --release -- -Z unstable-options --format json > ${{ env.CARGO_TEST_RESULT_NAME }}
run: cargo test --verbose --package partiql-conformance-tests --features "conformance_test, experimental" --release -- -Z unstable-options --format json > ${{ env.CARGO_TEST_RESULT_NAME }}
# Create a conformance report from the `cargo test` json file
- run: cargo run --features report_tool --bin generate_cts_report ${{ env.CARGO_TEST_RESULT_NAME }} ${GITHUB_SHA} ${{ env.CONFORMANCE_REPORT_NAME }}
# Upload conformance report for comparison with future runs
Expand Down
1 change: 1 addition & 0 deletions partiql-ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -945,6 +945,7 @@ pub struct GraphMatchEdge {
#[derive(Visit, Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct GraphMatchPattern {
/// an optional restrictor for the entire pattern match
#[visit(skip)]
pub restrictor: Option<GraphMatchRestrictor>,
/// an optional quantifier for the entire pattern match
Expand Down
56 changes: 52 additions & 4 deletions partiql-eval/src/eval/expr/graph_match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,19 +46,67 @@ impl BindEvalExpr for EvalGraphMatch {
#[cfg(test)]
mod tests {
use crate::eval::expr::{BindEvalExpr, EvalGlobalVarRef, EvalGraphMatch};
use crate::eval::graph::bind_name::FreshBinder;
use crate::eval::graph::plan::{
BindSpec, DirectionFilter, EdgeFilter, ElementFilterBuilder, NodeFilter, NodeMatch,
PathMatch, PathPatternMatch, StepFilter, TripleFilter,
BindSpec, DirectionFilter, EdgeFilter, LabelFilter, NodeFilter, NodeMatch, PathMatch,
PathPatternMatch, StepFilter, TripleFilter, ValueFilter,
};
use crate::eval::graph::string_graph::StringGraphTypes;
use crate::eval::graph::types::GraphTypes;
use crate::eval::{BasicContext, MapBindings};
use crate::test_value::TestValue;
use partiql_catalog::context::SystemContext;
use partiql_common::pretty::ToPretty;

use partiql_logical::graph::bind_name::FreshBinder;
use partiql_value::{tuple, BindingsName, DateTime, Value};

impl<GT: GraphTypes> From<PathMatch<GT>> for PathPatternMatch<GT> {
fn from(value: PathMatch<GT>) -> Self {
Self::Match(value)
}
}

impl<GT: GraphTypes> From<NodeMatch<GT>> for PathPatternMatch<GT> {
fn from(value: NodeMatch<GT>) -> Self {
Self::Node(value)
}
}

pub trait ElementFilterBuilder<GT: GraphTypes> {
fn any() -> Self;
fn labeled(label: GT::Label) -> Self;
}

impl<GT: GraphTypes> ElementFilterBuilder<GT> for NodeFilter<GT> {
fn any() -> Self {
Self {
label: LabelFilter::Always,
filter: ValueFilter::Always,
}
}

fn labeled(label: GT::Label) -> Self {
Self {
label: LabelFilter::Named(label),
filter: ValueFilter::Always,
}
}
}

impl<GT: GraphTypes> ElementFilterBuilder<GT> for EdgeFilter<GT> {
fn any() -> Self {
Self {
label: LabelFilter::Always,
filter: ValueFilter::Always,
}
}
fn labeled(label: GT::Label) -> Self {
Self {
label: LabelFilter::Named(label),
filter: ValueFilter::Always,
}
}
}

/*
A simple 3-node, 3-edge graph which is intended to be able to be exactly matched by:
```(graph MATCH
Expand Down
19 changes: 16 additions & 3 deletions partiql-eval/src/eval/graph/evaluator.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use crate::eval::graph::bind_name::BindNameExt;
use crate::eval::graph::engine::GraphEngine;
use crate::eval::graph::result::{
GraphElement, NodeBinding, PathBinding, PathPatternBinding, PathPatternNodes,
GraphElement, NodeBinding, PathBinding, PathPatternBinding, PathPatternNodes, Triple,
};
use partiql_logical::graph::bind_name::BindNameExt;

use fxhash::FxBuildHasher;
use indexmap::IndexMap;
Expand Down Expand Up @@ -92,7 +92,20 @@ impl<GT: GraphTypes, G: GraphEngine<GT>> GraphEvaluator<GT, G> {
fn eval_path_pattern(&self, matcher: PathPatternMatch<GT>) -> PathPatternBinding<GT> {
match matcher {
PathPatternMatch::Node(n) => self.eval_node(n).into(),
PathPatternMatch::Match(m) => self.eval_path(m).into(),
PathPatternMatch::Match(m) => {
let PathBinding {
matcher,
mut bindings,
} = self.eval_path(m);

// if edge is cyclic, filter triples
let (n1, _, n2) = &matcher.binders;
if n1 == n2 {
bindings.retain(|Triple { lhs, e: _, rhs }| lhs == rhs)
}

PathBinding { matcher, bindings }.into()
}
PathPatternMatch::Concat(ms) => ms
.into_iter()
.map(|p| self.eval_path_pattern(p))
Expand Down
1 change: 0 additions & 1 deletion partiql-eval/src/eval/graph/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
pub(crate) mod bind_name;
pub(crate) mod engine;
pub(crate) mod evaluator;
pub(crate) mod plan;
Expand Down
74 changes: 0 additions & 74 deletions partiql-eval/src/eval/graph/plan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ use std::fmt::Debug;
use std::hash::Hash;

/// A plan specification for an edge's direction filtering.
#[allow(dead_code)] // TODO remove once graph planning is implemented
#[allow(clippy::upper_case_acronyms)]
#[derive(Debug, Clone, Copy)]
pub enum DirectionFilter {
Expand Down Expand Up @@ -66,29 +65,13 @@ pub struct StepFilter<GT: GraphTypes> {
pub triple: TripleFilter<GT>,
}

/// A plan specification for 'path patterns' (i.e., sequences of 'node edge node's) matching.
#[allow(dead_code)] // TODO remove once graph planning is implemented
#[derive(Debug, Clone)]
pub struct PathPatternFilter<GT: GraphTypes> {
pub head: NodeFilter<GT>,
pub tail: Vec<(DirectionFilter, EdgeFilter<GT>, NodeFilter<GT>)>,
}

/// A plan specification for node matching.
#[derive(Debug, Clone)]
pub struct NodeMatch<GT: GraphTypes> {
pub binder: BindSpec<GT>,
pub spec: NodeFilter<GT>,
}

/// A plan specification for edge matching.
#[allow(dead_code)] // TODO remove once graph planning is implemented
#[derive(Debug, Clone)]
pub struct EdgeMatch<GT: GraphTypes> {
pub binder: BindSpec<GT>,
pub spec: EdgeFilter<GT>,
}

/// A plan specification for path (i.e., node, edge, node) matching.
#[derive(Debug, Clone)]
pub struct PathMatch<GT: GraphTypes> {
Expand All @@ -97,63 +80,13 @@ pub struct PathMatch<GT: GraphTypes> {
}

/// A plan specification for path patterns (i.e., sequences of [`PathMatch`]s) matching.
#[allow(dead_code)] // TODO remove once graph planning is implemented
#[derive(Debug, Clone)]
pub enum PathPatternMatch<GT: GraphTypes> {
Node(NodeMatch<GT>),
Match(PathMatch<GT>),
Concat(Vec<PathPatternMatch<GT>>),
}

impl<GT: GraphTypes> From<PathMatch<GT>> for PathPatternMatch<GT> {
fn from(value: PathMatch<GT>) -> Self {
Self::Match(value)
}
}

impl<GT: GraphTypes> From<NodeMatch<GT>> for PathPatternMatch<GT> {
fn from(value: NodeMatch<GT>) -> Self {
Self::Node(value)
}
}

#[allow(dead_code)] // TODO remove once graph planning is implemented
pub trait ElementFilterBuilder<GT: GraphTypes> {
fn any() -> Self;
fn labeled(label: GT::Label) -> Self;
}

impl<GT: GraphTypes> ElementFilterBuilder<GT> for NodeFilter<GT> {
fn any() -> Self {
Self {
label: LabelFilter::Always,
filter: ValueFilter::Always,
}
}

fn labeled(label: GT::Label) -> Self {
Self {
label: LabelFilter::Named(label),
filter: ValueFilter::Always,
}
}
}

impl<GT: GraphTypes> ElementFilterBuilder<GT> for EdgeFilter<GT> {
fn any() -> Self {
Self {
label: LabelFilter::Always,
filter: ValueFilter::Always,
}
}
fn labeled(label: GT::Label) -> Self {
Self {
label: LabelFilter::Named(label),
filter: ValueFilter::Always,
}
}
}

/// A trait for converting between plans parameterized by different [`GraphTypes`]
pub trait GraphPlanConvert<In: GraphTypes, Out: GraphTypes>: Debug {
fn convert_pathpattern_match(&self, matcher: &PathPatternMatch<In>) -> PathPatternMatch<Out> {
Expand Down Expand Up @@ -211,13 +144,6 @@ pub trait GraphPlanConvert<In: GraphTypes, Out: GraphTypes>: Debug {
}
}

#[allow(dead_code)] // TODO remove once graph planning is implemented
fn convert_edge_match(&self, edge: &EdgeMatch<In>) -> EdgeMatch<Out> {
EdgeMatch {
binder: self.convert_binder(&edge.binder),
spec: self.convert_edge_filter(&edge.spec),
}
}
fn convert_label_filter(&self, node: &LabelFilter<In>) -> LabelFilter<Out>;
fn convert_binder(&self, binder: &BindSpec<In>) -> BindSpec<Out>;
}
50 changes: 25 additions & 25 deletions partiql-eval/src/plan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -794,37 +794,37 @@ impl<'c> EvaluatorPlanner<'c> {
}

fn plan_graph_plan(
pattern: &partiql_logical::PathPatternMatch,
pattern: &logical::graph::PathPatternMatch,
) -> Result<eval::graph::plan::PathPatternMatch<StringGraphTypes>, PlanningError> {
use eval::graph::plan as physical;
use partiql_logical as logical;

fn plan_bind_spec(
pattern: &logical::BindSpec,
pattern: &logical::graph::BindSpec,
) -> Result<physical::BindSpec<StringGraphTypes>, PlanningError> {
Ok(physical::BindSpec(pattern.0.clone()))
}

fn plan_label_filter(
pattern: &logical::LabelFilter,
pattern: &logical::graph::LabelFilter,
) -> Result<physical::LabelFilter<StringGraphTypes>, PlanningError> {
Ok(match pattern {
logical::LabelFilter::Always => physical::LabelFilter::Always,
logical::LabelFilter::Never => physical::LabelFilter::Never,
logical::LabelFilter::Named(n) => physical::LabelFilter::Named(n.clone()),
logical::graph::LabelFilter::Always => physical::LabelFilter::Always,
logical::graph::LabelFilter::Never => physical::LabelFilter::Never,
logical::graph::LabelFilter::Named(n) => physical::LabelFilter::Named(n.clone()),
})
}

fn plan_value_filter(
pattern: &logical::ValueFilter,
pattern: &logical::graph::ValueFilter,
) -> Result<physical::ValueFilter, PlanningError> {
Ok(match pattern {
logical::ValueFilter::Always => physical::ValueFilter::Always,
logical::graph::ValueFilter::Always => physical::ValueFilter::Always,
})
}

fn plan_node_filter(
pattern: &logical::NodeFilter,
pattern: &logical::graph::NodeFilter,
) -> Result<physical::NodeFilter<StringGraphTypes>, PlanningError> {
Ok(physical::NodeFilter {
label: plan_label_filter(&pattern.label)?,
Expand All @@ -833,7 +833,7 @@ fn plan_graph_plan(
}

fn plan_edge_filter(
pattern: &logical::EdgeFilter,
pattern: &logical::graph::EdgeFilter,
) -> Result<physical::EdgeFilter<StringGraphTypes>, PlanningError> {
Ok(physical::EdgeFilter {
label: plan_label_filter(&pattern.label)?,
Expand All @@ -842,16 +842,16 @@ fn plan_graph_plan(
}

fn plan_step_filter(
pattern: &logical::StepFilter,
pattern: &logical::graph::StepFilter,
) -> Result<physical::StepFilter<StringGraphTypes>, PlanningError> {
let dir = match pattern.dir {
logical::DirectionFilter::L => physical::DirectionFilter::L,
logical::DirectionFilter::R => physical::DirectionFilter::R,
logical::DirectionFilter::U => physical::DirectionFilter::U,
logical::DirectionFilter::LU => physical::DirectionFilter::LU,
logical::DirectionFilter::UR => physical::DirectionFilter::UR,
logical::DirectionFilter::LR => physical::DirectionFilter::LR,
logical::DirectionFilter::LUR => physical::DirectionFilter::LUR,
logical::graph::DirectionFilter::L => physical::DirectionFilter::L,
logical::graph::DirectionFilter::R => physical::DirectionFilter::R,
logical::graph::DirectionFilter::U => physical::DirectionFilter::U,
logical::graph::DirectionFilter::LU => physical::DirectionFilter::LU,
logical::graph::DirectionFilter::UR => physical::DirectionFilter::UR,
logical::graph::DirectionFilter::LR => physical::DirectionFilter::LR,
logical::graph::DirectionFilter::LUR => physical::DirectionFilter::LUR,
};
Ok(physical::StepFilter {
dir,
Expand All @@ -860,7 +860,7 @@ fn plan_graph_plan(
}

fn plan_triple_filter(
pattern: &logical::TripleFilter,
pattern: &logical::graph::TripleFilter,
) -> Result<physical::TripleFilter<StringGraphTypes>, PlanningError> {
Ok(physical::TripleFilter {
lhs: plan_node_filter(&pattern.lhs)?,
Expand All @@ -870,7 +870,7 @@ fn plan_graph_plan(
}

fn plan_node_match(
pattern: &logical::NodeMatch,
pattern: &logical::graph::NodeMatch,
) -> Result<physical::NodeMatch<StringGraphTypes>, PlanningError> {
Ok(physical::NodeMatch {
binder: plan_bind_spec(&pattern.binder)?,
Expand All @@ -879,7 +879,7 @@ fn plan_graph_plan(
}

fn plan_path_match(
pattern: &logical::PathMatch,
pattern: &logical::graph::PathMatch,
) -> Result<physical::PathMatch<StringGraphTypes>, PlanningError> {
let (l, m, r) = &pattern.binders;
let binders = (plan_bind_spec(l)?, plan_bind_spec(m)?, plan_bind_spec(r)?);
Expand All @@ -890,16 +890,16 @@ fn plan_graph_plan(
}

fn plan_path_pattern_match(
pattern: &logical::PathPatternMatch,
pattern: &logical::graph::PathPatternMatch,
) -> Result<physical::PathPatternMatch<StringGraphTypes>, PlanningError> {
Ok(match pattern {
logical::PathPatternMatch::Node(n) => {
logical::graph::PathPatternMatch::Node(n) => {
physical::PathPatternMatch::Node(plan_node_match(n)?)
}
logical::PathPatternMatch::Match(m) => {
logical::graph::PathPatternMatch::Match(m) => {
physical::PathPatternMatch::Match(plan_path_match(m)?)
}
logical::PathPatternMatch::Concat(ms) => {
logical::graph::PathPatternMatch::Concat(ms) => {
let ms: Result<Vec<_>, _> = ms.iter().map(plan_path_pattern_match).collect();
physical::PathPatternMatch::Concat(ms?)
}
Expand Down
Loading
Loading