-
Notifications
You must be signed in to change notification settings - Fork 9
Add support for GPML-style graph query parsing #548
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
6194865
Import 'Add experimental draft support for GPML-style graph query par…
jpschorr b9340a7
Add pretty-printing for GPML
jpschorr 3ae912f
Add non-reserved keywords for some GPML keywords
jpschorr 4a69132
cleanup & clippy
jpschorr 1402d94
Add non-reserved keyword handling to function preprocessing
jpschorr 440d5ac
Error on usage of `MATCH` syntax
jpschorr File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,6 +11,7 @@ | |
use rust_decimal::Decimal as RustDecimal; | ||
|
||
use std::fmt; | ||
use std::num::NonZeroU32; | ||
|
||
#[cfg(feature = "serde")] | ||
use serde::{Deserialize, Serialize}; | ||
|
@@ -401,6 +402,8 @@ pub enum Expr { | |
Path(AstNode<Path>), | ||
Call(AstNode<Call>), | ||
CallAgg(AstNode<CallAgg>), | ||
/// <expr> MATCH <graph_pattern> | ||
GraphMatch(AstNode<GraphMatch>), | ||
|
||
/// Query, e.g. `UNION` | `EXCEPT` | `INTERSECT` | `SELECT` and their parts. | ||
Query(AstNode<Query>), | ||
|
@@ -832,6 +835,164 @@ pub enum JoinSpec { | |
Natural, | ||
} | ||
|
||
/// `<expr> MATCH <graph_pattern>` | ||
#[derive(Visit, Clone, Debug, PartialEq)] | ||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] | ||
pub struct GraphMatch { | ||
alancai98 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
pub expr: Box<Expr>, | ||
pub graph_expr: Box<AstNode<GraphMatchExpr>>, | ||
} | ||
|
||
/// The direction of an edge | ||
/// | Orientation | Edge pattern | Abbreviation | | ||
/// |---------------------------+--------------+--------------| | ||
/// | Pointing left | <−[ spec ]− | <− | | ||
/// | Undirected | ~[ spec ]~ | ~ | | ||
/// | Pointing right | −[ spec ]−> | −> | | ||
/// | Left or undirected | <~[ spec ]~ | <~ | | ||
/// | Undirected or right | ~[ spec ]~> | ~> | | ||
/// | Left or right | <−[ spec ]−> | <−> | | ||
/// | Left, undirected or right | −[ spec ]− | − | | ||
/// | ||
/// Fig. 5. Table of edge patterns: | ||
/// https://arxiv.org/abs/2112.06217 | ||
#[derive(Clone, Debug, PartialEq, Eq)] | ||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] | ||
pub enum GraphMatchDirection { | ||
Left, | ||
Undirected, | ||
Right, | ||
LeftOrUndirected, | ||
UndirectedOrRight, | ||
LeftOrRight, | ||
LeftOrUndirectedOrRight, | ||
} | ||
|
||
/// A part of a graph pattern | ||
#[derive(Clone, Debug, PartialEq)] | ||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] | ||
pub enum GraphMatchPatternPart { | ||
/// A single node in a graph pattern. | ||
Node(AstNode<GraphMatchNode>), | ||
|
||
/// A single edge in a graph pattern. | ||
Edge(AstNode<GraphMatchEdge>), | ||
|
||
/// A sub-pattern. | ||
Pattern(AstNode<GraphMatchPattern>), | ||
} | ||
|
||
/// A quantifier for graph edges or patterns. (e.g., the `{2,5}` in `MATCH (x)->{2,5}(y)`) | ||
#[derive(Clone, Debug, PartialEq, Eq)] | ||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] | ||
pub struct GraphMatchQuantifier { | ||
pub lower: u32, | ||
pub upper: Option<NonZeroU32>, | ||
} | ||
|
||
/// A path restrictor | ||
/// | Keyword | Description | ||
/// |----------------+-------------- | ||
/// | TRAIL | No repeated edges. | ||
/// | ACYCLIC | No repeated nodes. | ||
/// | SIMPLE | No repeated nodes, except that the first and last nodes may be the same. | ||
/// | ||
/// Fig. 7. Table of restrictors: | ||
/// https://arxiv.org/abs/2112.06217 | ||
#[derive(Clone, Debug, PartialEq, Eq)] | ||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] | ||
pub enum GraphMatchRestrictor { | ||
Trail, | ||
Acyclic, | ||
Simple, | ||
} | ||
|
||
/// A single node in a graph pattern. | ||
#[derive(Visit, Clone, Debug, PartialEq)] | ||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] | ||
pub struct GraphMatchNode { | ||
/// an optional node pre-filter, e.g.: `WHERE c.name='Alarm'` in `MATCH (c WHERE c.name='Alarm')` | ||
pub prefilter: Option<Box<Expr>>, | ||
/// the optional element variable of the node match, e.g.: `x` in `MATCH (x)` | ||
#[visit(skip)] | ||
pub variable: Option<SymbolPrimitive>, | ||
/// the optional label(s) to match for the node, e.g.: `Entity` in `MATCH (x:Entity)` | ||
#[visit(skip)] | ||
pub label: Option<Vec<SymbolPrimitive>>, | ||
} | ||
|
||
/// A single edge in a graph pattern. | ||
#[derive(Visit, Clone, Debug, PartialEq)] | ||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] | ||
pub struct GraphMatchEdge { | ||
/// edge direction | ||
#[visit(skip)] | ||
pub direction: GraphMatchDirection, | ||
/// an optional quantifier for the edge match | ||
#[visit(skip)] | ||
pub quantifier: Option<AstNode<GraphMatchQuantifier>>, | ||
/// an optional edge pre-filter, e.g.: `WHERE t.capacity>100` in `MATCH −[t:hasSupply WHERE t.capacity>100]−>` | ||
pub prefilter: Option<Box<Expr>>, | ||
/// the optional element variable of the edge match, e.g.: `t` in `MATCH −[t]−>` | ||
#[visit(skip)] | ||
pub variable: Option<SymbolPrimitive>, | ||
/// the optional label(s) to match for the edge. e.g.: `Target` in `MATCH −[t:Target]−>` | ||
#[visit(skip)] | ||
pub label: Option<Vec<SymbolPrimitive>>, | ||
} | ||
|
||
/// A single graph match pattern. | ||
#[derive(Visit, Clone, Debug, PartialEq)] | ||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] | ||
pub struct GraphMatchPattern { | ||
#[visit(skip)] | ||
pub restrictor: Option<GraphMatchRestrictor>, | ||
/// an optional quantifier for the entire pattern match | ||
#[visit(skip)] | ||
pub quantifier: Option<AstNode<GraphMatchQuantifier>>, | ||
/// an optional pattern pre-filter, e.g.: `WHERE a.name=b.name` in `MATCH [(a)->(b) WHERE a.name=b.name]` | ||
pub prefilter: Option<Box<Expr>>, | ||
/// the optional element variable of the pattern, e.g.: `p` in `MATCH p = (a) −[t]−> (b)` | ||
#[visit(skip)] | ||
pub variable: Option<SymbolPrimitive>, | ||
/// the ordered pattern parts | ||
#[visit(skip)] | ||
pub parts: Vec<GraphMatchPatternPart>, | ||
} | ||
|
||
/// A path selector | ||
/// | Keyword | ||
/// |------------------ | ||
/// | ANY SHORTEST | ||
/// | ALL SHORTEST | ||
/// | ANY | ||
/// | ANY k | ||
/// | SHORTEST k | ||
/// | SHORTEST k GROUP | ||
/// | ||
/// Fig. 8. Table of restrictors: | ||
/// https://arxiv.org/abs/2112.06217 | ||
#[derive(Clone, Debug, PartialEq, Eq)] | ||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] | ||
pub enum GraphMatchSelector { | ||
AnyShortest, | ||
AllShortest, | ||
Any, | ||
AnyK(NonZeroU32), | ||
ShortestK(NonZeroU32), | ||
ShortestKGroup(NonZeroU32), | ||
Comment on lines
+981
to
+983
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. does the GPML paper require the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The shortest 0 paths are the empty set. |
||
} | ||
|
||
/// A graph match clause as defined in GPML | ||
/// See https://arxiv.org/abs/2112.06217 | ||
#[derive(Visit, Clone, Debug, PartialEq)] | ||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] | ||
pub struct GraphMatchExpr { | ||
#[visit(skip)] | ||
pub selector: Option<GraphMatchSelector>, | ||
pub patterns: Vec<AstNode<GraphMatchPattern>>, | ||
} | ||
|
||
/// GROUP BY <`grouping_strategy`> <`group_key`>[, <`group_key`>]... \[AS <symbol>\] | ||
#[derive(Visit, Clone, Debug, PartialEq)] | ||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] | ||
|
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.