|
11 | 11 | use rust_decimal::Decimal as RustDecimal;
|
12 | 12 |
|
13 | 13 | use std::fmt;
|
| 14 | +use std::num::NonZeroU32; |
14 | 15 |
|
15 | 16 | #[cfg(feature = "serde")]
|
16 | 17 | use serde::{Deserialize, Serialize};
|
@@ -401,6 +402,8 @@ pub enum Expr {
|
401 | 402 | Path(AstNode<Path>),
|
402 | 403 | Call(AstNode<Call>),
|
403 | 404 | CallAgg(AstNode<CallAgg>),
|
| 405 | + /// <expr> MATCH <graph_pattern> |
| 406 | + GraphMatch(AstNode<GraphMatch>), |
404 | 407 |
|
405 | 408 | /// Query, e.g. `UNION` | `EXCEPT` | `INTERSECT` | `SELECT` and their parts.
|
406 | 409 | Query(AstNode<Query>),
|
@@ -832,6 +835,164 @@ pub enum JoinSpec {
|
832 | 835 | Natural,
|
833 | 836 | }
|
834 | 837 |
|
| 838 | +/// `<expr> MATCH <graph_pattern>` |
| 839 | +#[derive(Visit, Clone, Debug, PartialEq)] |
| 840 | +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] |
| 841 | +pub struct GraphMatch { |
| 842 | + pub expr: Box<Expr>, |
| 843 | + pub graph_expr: Box<AstNode<GraphMatchExpr>>, |
| 844 | +} |
| 845 | + |
| 846 | +/// The direction of an edge |
| 847 | +/// | Orientation | Edge pattern | Abbreviation | |
| 848 | +/// |---------------------------+--------------+--------------| |
| 849 | +/// | Pointing left | <−[ spec ]− | <− | |
| 850 | +/// | Undirected | ~[ spec ]~ | ~ | |
| 851 | +/// | Pointing right | −[ spec ]−> | −> | |
| 852 | +/// | Left or undirected | <~[ spec ]~ | <~ | |
| 853 | +/// | Undirected or right | ~[ spec ]~> | ~> | |
| 854 | +/// | Left or right | <−[ spec ]−> | <−> | |
| 855 | +/// | Left, undirected or right | −[ spec ]− | − | |
| 856 | +/// |
| 857 | +/// Fig. 5. Table of edge patterns: |
| 858 | +/// https://arxiv.org/abs/2112.06217 |
| 859 | +#[derive(Clone, Debug, PartialEq, Eq)] |
| 860 | +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] |
| 861 | +pub enum GraphMatchDirection { |
| 862 | + Left, |
| 863 | + Undirected, |
| 864 | + Right, |
| 865 | + LeftOrUndirected, |
| 866 | + UndirectedOrRight, |
| 867 | + LeftOrRight, |
| 868 | + LeftOrUndirectedOrRight, |
| 869 | +} |
| 870 | + |
| 871 | +/// A part of a graph pattern |
| 872 | +#[derive(Clone, Debug, PartialEq)] |
| 873 | +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] |
| 874 | +pub enum GraphMatchPatternPart { |
| 875 | + /// A single node in a graph pattern. |
| 876 | + Node(AstNode<GraphMatchNode>), |
| 877 | + |
| 878 | + /// A single edge in a graph pattern. |
| 879 | + Edge(AstNode<GraphMatchEdge>), |
| 880 | + |
| 881 | + /// A sub-pattern. |
| 882 | + Pattern(AstNode<GraphMatchPattern>), |
| 883 | +} |
| 884 | + |
| 885 | +/// A quantifier for graph edges or patterns. (e.g., the `{2,5}` in `MATCH (x)->{2,5}(y)`) |
| 886 | +#[derive(Clone, Debug, PartialEq, Eq)] |
| 887 | +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] |
| 888 | +pub struct GraphMatchQuantifier { |
| 889 | + pub lower: u32, |
| 890 | + pub upper: Option<NonZeroU32>, |
| 891 | +} |
| 892 | + |
| 893 | +/// A path restrictor |
| 894 | +/// | Keyword | Description |
| 895 | +/// |----------------+-------------- |
| 896 | +/// | TRAIL | No repeated edges. |
| 897 | +/// | ACYCLIC | No repeated nodes. |
| 898 | +/// | SIMPLE | No repeated nodes, except that the first and last nodes may be the same. |
| 899 | +/// |
| 900 | +/// Fig. 7. Table of restrictors: |
| 901 | +/// https://arxiv.org/abs/2112.06217 |
| 902 | +#[derive(Clone, Debug, PartialEq, Eq)] |
| 903 | +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] |
| 904 | +pub enum GraphMatchRestrictor { |
| 905 | + Trail, |
| 906 | + Acyclic, |
| 907 | + Simple, |
| 908 | +} |
| 909 | + |
| 910 | +/// A single node in a graph pattern. |
| 911 | +#[derive(Visit, Clone, Debug, PartialEq)] |
| 912 | +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] |
| 913 | +pub struct GraphMatchNode { |
| 914 | + /// an optional node pre-filter, e.g.: `WHERE c.name='Alarm'` in `MATCH (c WHERE c.name='Alarm')` |
| 915 | + pub prefilter: Option<Box<Expr>>, |
| 916 | + /// the optional element variable of the node match, e.g.: `x` in `MATCH (x)` |
| 917 | + #[visit(skip)] |
| 918 | + pub variable: Option<SymbolPrimitive>, |
| 919 | + /// the optional label(s) to match for the node, e.g.: `Entity` in `MATCH (x:Entity)` |
| 920 | + #[visit(skip)] |
| 921 | + pub label: Option<Vec<SymbolPrimitive>>, |
| 922 | +} |
| 923 | + |
| 924 | +/// A single edge in a graph pattern. |
| 925 | +#[derive(Visit, Clone, Debug, PartialEq)] |
| 926 | +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] |
| 927 | +pub struct GraphMatchEdge { |
| 928 | + /// edge direction |
| 929 | + #[visit(skip)] |
| 930 | + pub direction: GraphMatchDirection, |
| 931 | + /// an optional quantifier for the edge match |
| 932 | + #[visit(skip)] |
| 933 | + pub quantifier: Option<AstNode<GraphMatchQuantifier>>, |
| 934 | + /// an optional edge pre-filter, e.g.: `WHERE t.capacity>100` in `MATCH −[t:hasSupply WHERE t.capacity>100]−>` |
| 935 | + pub prefilter: Option<Box<Expr>>, |
| 936 | + /// the optional element variable of the edge match, e.g.: `t` in `MATCH −[t]−>` |
| 937 | + #[visit(skip)] |
| 938 | + pub variable: Option<SymbolPrimitive>, |
| 939 | + /// the optional label(s) to match for the edge. e.g.: `Target` in `MATCH −[t:Target]−>` |
| 940 | + #[visit(skip)] |
| 941 | + pub label: Option<Vec<SymbolPrimitive>>, |
| 942 | +} |
| 943 | + |
| 944 | +/// A single graph match pattern. |
| 945 | +#[derive(Visit, Clone, Debug, PartialEq)] |
| 946 | +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] |
| 947 | +pub struct GraphMatchPattern { |
| 948 | + #[visit(skip)] |
| 949 | + pub restrictor: Option<GraphMatchRestrictor>, |
| 950 | + /// an optional quantifier for the entire pattern match |
| 951 | + #[visit(skip)] |
| 952 | + pub quantifier: Option<AstNode<GraphMatchQuantifier>>, |
| 953 | + /// an optional pattern pre-filter, e.g.: `WHERE a.name=b.name` in `MATCH [(a)->(b) WHERE a.name=b.name]` |
| 954 | + pub prefilter: Option<Box<Expr>>, |
| 955 | + /// the optional element variable of the pattern, e.g.: `p` in `MATCH p = (a) −[t]−> (b)` |
| 956 | + #[visit(skip)] |
| 957 | + pub variable: Option<SymbolPrimitive>, |
| 958 | + /// the ordered pattern parts |
| 959 | + #[visit(skip)] |
| 960 | + pub parts: Vec<GraphMatchPatternPart>, |
| 961 | +} |
| 962 | + |
| 963 | +/// A path selector |
| 964 | +/// | Keyword |
| 965 | +/// |------------------ |
| 966 | +/// | ANY SHORTEST |
| 967 | +/// | ALL SHORTEST |
| 968 | +/// | ANY |
| 969 | +/// | ANY k |
| 970 | +/// | SHORTEST k |
| 971 | +/// | SHORTEST k GROUP |
| 972 | +/// |
| 973 | +/// Fig. 8. Table of restrictors: |
| 974 | +/// https://arxiv.org/abs/2112.06217 |
| 975 | +#[derive(Clone, Debug, PartialEq, Eq)] |
| 976 | +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] |
| 977 | +pub enum GraphMatchSelector { |
| 978 | + AnyShortest, |
| 979 | + AllShortest, |
| 980 | + Any, |
| 981 | + AnyK(NonZeroU32), |
| 982 | + ShortestK(NonZeroU32), |
| 983 | + ShortestKGroup(NonZeroU32), |
| 984 | +} |
| 985 | + |
| 986 | +/// A graph match clause as defined in GPML |
| 987 | +/// See https://arxiv.org/abs/2112.06217 |
| 988 | +#[derive(Visit, Clone, Debug, PartialEq)] |
| 989 | +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] |
| 990 | +pub struct GraphMatchExpr { |
| 991 | + #[visit(skip)] |
| 992 | + pub selector: Option<GraphMatchSelector>, |
| 993 | + pub patterns: Vec<AstNode<GraphMatchPattern>>, |
| 994 | +} |
| 995 | + |
835 | 996 | /// GROUP BY <`grouping_strategy`> <`group_key`>[, <`group_key`>]... \[AS <symbol>\]
|
836 | 997 | #[derive(Visit, Clone, Debug, PartialEq)]
|
837 | 998 | #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
|
0 commit comments