From 619486511ddcd4f619cc7c868d529751fe01e9c4 Mon Sep 17 00:00:00 2001 From: Josh Pschorr Date: Tue, 18 Mar 2025 14:55:16 -0700 Subject: [PATCH 1/6] Import 'Add experimental draft support for GPML-style graph query parsing' --- .../src/ast_to_dot.rs | 1 + partiql-ast/src/ast.rs | 161 ++++++++++++ partiql-ast/src/pretty.rs | 3 + partiql-ast/src/visit.rs | 38 +++ partiql-parser/benches/bench_parse.rs | 17 ++ partiql-parser/src/lexer/mod.rs | 14 +- partiql-parser/src/lexer/partiql.rs | 31 ++- partiql-parser/src/parse/mod.rs | 157 ++++++++++- partiql-parser/src/parse/partiql.lalrpop | 246 +++++++++++++++++- 9 files changed, 647 insertions(+), 21 deletions(-) diff --git a/extension/partiql-extension-visualize/src/ast_to_dot.rs b/extension/partiql-extension-visualize/src/ast_to_dot.rs index 82d477dd..7f013a20 100644 --- a/extension/partiql-extension-visualize/src/ast_to_dot.rs +++ b/extension/partiql-extension-visualize/src/ast_to_dot.rs @@ -165,6 +165,7 @@ impl ToDot for AstToDot { Expr::CallAgg(c) => self.to_dot(&mut expr_subgraph, c), Expr::Query(q) => self.to_dot(&mut expr_subgraph, q), Expr::Error => todo!(), + Expr::GraphMatch(_) => todo!(), } } } diff --git a/partiql-ast/src/ast.rs b/partiql-ast/src/ast.rs index 3b641072..2c26f56a 100644 --- a/partiql-ast/src/ast.rs +++ b/partiql-ast/src/ast.rs @@ -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), Call(AstNode), CallAgg(AstNode), + /// MATCH + GraphMatch(AstNode), /// Query, e.g. `UNION` | `EXCEPT` | `INTERSECT` | `SELECT` and their parts. Query(AstNode), @@ -832,6 +835,164 @@ pub enum JoinSpec { Natural, } +/// ` MATCH ` +#[derive(Visit, Clone, Debug, PartialEq)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +pub struct GraphMatch { + pub expr: Box, + pub graph_expr: Box>, +} + +/// 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), + + /// A single edge in a graph pattern. + Edge(AstNode), + + /// A sub-pattern. + Pattern(AstNode), +} + +/// 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, +} + +/// 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>, + /// the optional element variable of the node match, e.g.: `x` in `MATCH (x)` + #[visit(skip)] + pub variable: Option, + /// the optional label(s) to match for the node, e.g.: `Entity` in `MATCH (x:Entity)` + #[visit(skip)] + pub label: Option>, +} + +/// 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>, + /// an optional edge pre-filter, e.g.: `WHERE t.capacity>100` in `MATCH −[t:hasSupply WHERE t.capacity>100]−>` + pub prefilter: Option>, + /// the optional element variable of the edge match, e.g.: `t` in `MATCH −[t]−>` + #[visit(skip)] + pub variable: Option, + /// the optional label(s) to match for the edge. e.g.: `Target` in `MATCH −[t:Target]−>` + #[visit(skip)] + pub label: Option>, +} + +/// 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, + /// an optional quantifier for the entire pattern match + #[visit(skip)] + pub quantifier: Option>, + /// an optional pattern pre-filter, e.g.: `WHERE a.name=b.name` in `MATCH [(a)->(b) WHERE a.name=b.name]` + pub prefilter: Option>, + /// the optional element variable of the pattern, e.g.: `p` in `MATCH p = (a) −[t]−> (b)` + #[visit(skip)] + pub variable: Option, + /// the ordered pattern parts + #[visit(skip)] + pub parts: Vec, +} + +/// 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), +} + +/// 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, + pub patterns: Vec>, +} + /// GROUP BY <`grouping_strategy`> <`group_key`>[, <`group_key`>]... \[AS \] #[derive(Visit, Clone, Debug, PartialEq)] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] diff --git a/partiql-ast/src/pretty.rs b/partiql-ast/src/pretty.rs index 4f04fcb0..7974f1ed 100644 --- a/partiql-ast/src/pretty.rs +++ b/partiql-ast/src/pretty.rs @@ -329,6 +329,9 @@ impl PrettyDoc for Expr { Expr::Error => { unreachable!(); } + Expr::GraphMatch(_inner) => { + todo!("inner.pretty_doc(arena)") + } } .group() } diff --git a/partiql-ast/src/visit.rs b/partiql-ast/src/visit.rs index cd709596..0ec91fbc 100644 --- a/partiql-ast/src/visit.rs +++ b/partiql-ast/src/visit.rs @@ -513,6 +513,44 @@ pub trait Visitor<'ast> { fn exit_join_spec(&mut self, _join_spec: &'ast ast::JoinSpec) -> Traverse { Traverse::Continue } + + fn enter_graph_match(&mut self, _graph_pattern: &'ast ast::GraphMatch) -> Traverse { + Traverse::Continue + } + fn exit_graph_match(&mut self, _graph_pattern: &'ast ast::GraphMatch) -> Traverse { + Traverse::Continue + } + fn enter_graph_match_expr(&mut self, _graph_pattern: &'ast ast::GraphMatchExpr) -> Traverse { + Traverse::Continue + } + fn exit_graph_match_expr(&mut self, _graph_pattern: &'ast ast::GraphMatchExpr) -> Traverse { + Traverse::Continue + } + fn enter_graph_match_pattern( + &mut self, + _graph_pattern: &'ast ast::GraphMatchPattern, + ) -> Traverse { + Traverse::Continue + } + fn exit_graph_match_pattern( + &mut self, + _graph_pattern: &'ast ast::GraphMatchPattern, + ) -> Traverse { + Traverse::Continue + } + fn enter_graph_match_node(&mut self, _graph_pattern: &'ast ast::GraphMatchNode) -> Traverse { + Traverse::Continue + } + fn exit_graph_match_node(&mut self, _graph_pattern: &'ast ast::GraphMatchNode) -> Traverse { + Traverse::Continue + } + fn enter_graph_match_edge(&mut self, _graph_pattern: &'ast ast::GraphMatchEdge) -> Traverse { + Traverse::Continue + } + fn exit_graph_match_edge(&mut self, _graph_pattern: &'ast ast::GraphMatchEdge) -> Traverse { + Traverse::Continue + } + fn enter_group_by_expr(&mut self, _group_by_expr: &'ast ast::GroupByExpr) -> Traverse { Traverse::Continue } diff --git a/partiql-parser/benches/bench_parse.rs b/partiql-parser/benches/bench_parse.rs index 40a5daaf..e00db348 100644 --- a/partiql-parser/benches/bench_parse.rs +++ b/partiql-parser/benches/bench_parse.rs @@ -34,6 +34,20 @@ const Q_COMPLEX_FEXPR: &str = r#" AS deltas FROM SOURCE_VIEW_DELTA_FULL_TRANSACTIONS delta_full_transactions "#; +const Q_COMPLEX_MATCH: &str = r#" + SELECT ( + SELECT numRec, data + FROM + (deltaGraph MATCH (t) -[:hasChange]-> (dt), (dt) -[:checkPointedBy]-> (t1)), + ( + SELECT foo(u.id), bar(review), rindex + FROM delta.data as u CROSS JOIN UNPIVOT u.reviews as review AT rindex + ) as data, + delta.numRec as numRec + ) + AS deltas FROM SOURCE_VIEW_DELTA_FULL_TRANSACTIONS delta_full_transactions + "#; + fn parse_bench(c: &mut Criterion) { fn parse(text: &str) -> ParserResult { Parser::default().parse(text) @@ -45,6 +59,9 @@ fn parse_bench(c: &mut Criterion) { c.bench_function("parse-complex-fexpr", |b| { b.iter(|| parse(black_box(Q_COMPLEX_FEXPR))) }); + c.bench_function("parse-complex-match", |b| { + b.iter(|| parse(black_box(Q_COMPLEX_MATCH))) + }); } criterion_group! { diff --git a/partiql-parser/src/lexer/mod.rs b/partiql-parser/src/lexer/mod.rs index f48c953d..c16de096 100644 --- a/partiql-parser/src/lexer/mod.rs +++ b/partiql-parser/src/lexer/mod.rs @@ -89,7 +89,8 @@ mod tests { "WiTH Where Value uSiNg Unpivot UNION True Select right Preserve pivoT Outer Order Or \ On Offset Nulls Null Not Natural Missing Limit Like Left Lateral Last Join \ Intersect Is Inner In Having Group From For Full First False Except Escape Desc \ - Cross Table Time Timestamp Date By Between At As And Asc All Values Case When Then Else End"; + Cross Table Time Timestamp Date By Between At As And Asc All Values Case When Then Else End \ + Match Any Shortest Trail Acyclic Simple"; let symbols = symbols.split(' ').chain(primitives.split(' ')); let keywords = keywords.split(' '); @@ -111,7 +112,7 @@ mod tests { "", "GROUP", "", "FROM", "FOR", "FULL", "FIRST", "FALSE", "EXCEPT", "ESCAPE", "DESC", "CROSS", "TABLE", "TIME", "TIMESTAMP", "DATE", "BY", "BETWEEN", "AT", "AS", "AND", "ASC", "ALL", "VALUES", - "CASE", "WHEN", "THEN", "ELSE", "END" + "CASE", "WHEN", "THEN", "ELSE", "END", "MATCH", "ANY", "SHORTEST", "TRAIL", "ACYCLIC", "SIMPLE" ]; let displayed = toks .into_iter() @@ -408,8 +409,7 @@ mod tests { /// the following test will need to be modified. #[test] fn select_non_reserved_keywords() -> Result<(), ParseError<'static, BytePosition>> { - let query = - "SELECT acyclic, BoTh, DOMAIN, SiMpLe, Trail, leading, TRailing, USER\nfrom @\"foo\""; + let query = "SELECT BoTh, DOMAIN, leading, TRailing, USER\nfrom @\"foo\""; let mut offset_tracker = LineOffsetTracker::default(); let lexer = PartiqlLexer::new(query, &mut offset_tracker); let toks: Vec<_> = lexer.collect::>()?; @@ -417,16 +417,10 @@ mod tests { assert_eq!( vec![ Token::Select, - Token::UnquotedIdent("acyclic"), - Token::Comma, Token::UnquotedIdent("BoTh"), Token::Comma, Token::UnquotedIdent("DOMAIN"), Token::Comma, - Token::UnquotedIdent("SiMpLe"), - Token::Comma, - Token::UnquotedIdent("Trail"), - Token::Comma, Token::UnquotedIdent("leading"), Token::Comma, Token::UnquotedIdent("TRailing"), diff --git a/partiql-parser/src/lexer/partiql.rs b/partiql-parser/src/lexer/partiql.rs index 3440a92a..10856454 100644 --- a/partiql-parser/src/lexer/partiql.rs +++ b/partiql-parser/src/lexer/partiql.rs @@ -213,6 +213,8 @@ pub enum Token<'input> { Caret, #[token(".")] Period, + #[token("~")] + Tilde, #[token("||")] DblPipe, @@ -260,12 +262,16 @@ pub enum Token<'input> { EmbeddedDoc(&'input str), // Keywords + #[regex("(?i:Acyclic)")] + Acyclic, #[regex("(?i:All)")] All, #[regex("(?i:Asc)")] Asc, #[regex("(?i:And)")] And, + #[regex("(?i:Any)")] + Any, #[regex("(?i:As)")] As, #[regex("(?i:At)")] @@ -330,6 +336,8 @@ pub enum Token<'input> { Like, #[regex("(?i:Limit)")] Limit, + #[regex("(?i:Match)")] + Match, #[regex("(?i:Missing)")] Missing, #[regex("(?i:Natural)")] @@ -370,8 +378,14 @@ pub enum Token<'input> { Time, #[regex("(?i:Timestamp)")] Timestamp, + #[regex("(?i:Simple)")] + Simple, + #[regex("(?i:Shortest)")] + Shortest, #[regex("(?i:Then)")] Then, + #[regex("(?i:Trail)")] + Trail, #[regex("(?i:True)")] True, #[regex("(?i:Union)")] @@ -400,9 +414,11 @@ impl Token<'_> { pub fn is_keyword(&self) -> bool { matches!( self, - Token::All + Token::Acyclic + | Token::All | Token::Asc | Token::And + | Token::Any | Token::As | Token::At | Token::Between @@ -431,6 +447,7 @@ impl Token<'_> { | Token::Left | Token::Like | Token::Limit + | Token::Match | Token::Missing | Token::Natural | Token::Not @@ -451,7 +468,10 @@ impl Token<'_> { | Token::Table | Token::Time | Token::Timestamp + | Token::Simple + | Token::Shortest | Token::Then + | Token::Trail | Token::Union | Token::Unpivot | Token::Using @@ -497,6 +517,7 @@ impl fmt::Display for Token<'_> { Token::Slash => write!(f, "/"), Token::Caret => write!(f, "^"), Token::Period => write!(f, "."), + Token::Tilde => write!(f, "~"), Token::DblPipe => write!(f, "||"), Token::UnquotedIdent(id) => write!(f, "<{id}:UNQUOTED_IDENT>"), Token::QuotedIdent(id) => write!(f, "<{id}:QUOTED_IDENT>"), @@ -510,9 +531,11 @@ impl fmt::Display for Token<'_> { Token::EmbeddedDoc(txt) => write!(f, "<```{txt}```:DOC>"), Token::EmptyEmbeddedDocQuote => write!(f, "<``:DOC>"), - Token::All + Token::Acyclic + | Token::All | Token::Asc | Token::And + | Token::Any | Token::As | Token::At | Token::Between @@ -545,6 +568,7 @@ impl fmt::Display for Token<'_> { | Token::Left | Token::Like | Token::Limit + | Token::Match | Token::Missing | Token::Natural | Token::Not @@ -565,7 +589,10 @@ impl fmt::Display for Token<'_> { | Token::Table | Token::Time | Token::Timestamp + | Token::Simple + | Token::Shortest | Token::Then + | Token::Trail | Token::True | Token::Union | Token::Unpivot diff --git a/partiql-parser/src/parse/mod.rs b/partiql-parser/src/parse/mod.rs index f8407a80..48341141 100644 --- a/partiql-parser/src/parse/mod.rs +++ b/partiql-parser/src/parse/mod.rs @@ -743,14 +743,6 @@ mod tests { ); } - #[test] - fn graph_pattern_matching() { - parse!(r"SELECT acyclic, trail, simple FROM t"); - parse!(r"AcYcLiC"); - parse!(r"TrAiL"); - parse!(r"SiMpLe"); - } - #[test] fn user_public_domain() { parse!(r"SELECT user, puBlIC, DOMAIN FROM USER, pUbLIc, domain"); @@ -760,6 +752,155 @@ mod tests { } } + mod graph { + use super::*; + + #[test] + fn no_labels() { + parse!(r#"SELECT 1 FROM my_graph MATCH ()"#); + parse!(r#"SELECT 1 FROM (my_graph MATCH ())"#); + + parse!(r#"SELECT 1 FROM my_graph MATCH () WHERE contains_value('1')"#); + parse!(r#"SELECT 1 FROM (my_graph MATCH ()) WHERE contains_value('1')"#); + + parse!(r#"SELECT x.info AS info FROM my_graph MATCH (x) WHERE x.name LIKE 'foo'"#); + parse!(r#"SELECT x.info AS info FROM (my_graph MATCH (x)) WHERE x.name LIKE 'foo'"#); + // TODO fails due to edge first + // parse!(r#"SELECT 1 FROM (g MATCH -[]->) "#); + } + + #[test] + fn lone_match_expr() { + parse!(r#"(MyGraph MATCH (x))"#); + parse!(r#"(MyGraph MATCH (x), (y) )"#); + // TODO fails due to edge first + //parse!(r#"(MyGraph MATCH (x), -[u]-> )"#); + } + + #[test] + fn labelled_nodes() { + parse!(r#"SELECT x AS target FROM my_graph MATCH (x:Label) WHERE x.has_data = true"#); + } + + #[test] + fn edges() { + parse!(r#"SELECT a,b FROM g MATCH (a:A) -[e:E]-> (b:B)"#); + parse!(r#"SELECT a,b FROM g MATCH (a:A) -> (b:B)"#); + parse!(r#"SELECT a,b FROM g MATCH (a:A) ~[e:E]~ (b:B)"#); + parse!(r#"SELECT a,b FROM g MATCH (a:A) ~ (b:B)"#); + parse!(r#"SELECT a,b FROM g MATCH (a:A) <-[e:E]- (b:B)"#); + parse!(r#"SELECT a,b FROM g MATCH (a:A) <- (b:B)"#); + parse!(r#"SELECT a,b FROM g MATCH (a:A) ~[e:E]~> (b:B)"#); + parse!(r#"SELECT a,b FROM g MATCH (a:A) ~> (b:B)"#); + parse!(r#"SELECT a,b FROM g MATCH (a:A) <~[e:E]~ (b:B)"#); + parse!(r#"SELECT a,b FROM g MATCH (a:A) <~ (b:B)"#); + parse!(r#"SELECT a,b FROM g MATCH (a:A) <-[e:E]-> (b:B)"#); + parse!(r#"SELECT a,b FROM g MATCH (a:A) <-> (b:B)"#); + parse!(r#"SELECT a,b FROM g MATCH (a:A) -[e:E]- (b:B)"#); + parse!(r#"SELECT a,b FROM g MATCH (a:A) - (b:B)"#); + } + + #[test] + fn quantifiers() { + parse!(r#"SELECT a,b FROM g MATCH (a:A)-[:edge]->*(b:B)"#); + parse!(r#"SELECT a,b FROM g MATCH (a:A)<-[:edge]-+(b:B)"#); + parse!(r#"SELECT a,b FROM g MATCH (a:A)~[:edge]~{5,}(b:B)"#); + parse!(r#"SELECT a,b FROM g MATCH (a:A)-[e:edge]-{2,6}(b:B)"#); + parse!(r#"SELECT a,b FROM g MATCH (a:A)->*(b:B)"#); + parse!(r#"SELECT a,b FROM g MATCH (a:A)<-+(b:B)"#); + parse!(r#"SELECT a,b FROM g MATCH (a:A)~{5,}(b:B)"#); + parse!(r#"SELECT a,b FROM g MATCH (a:A)-{2,6}(b:B)"#); + } + + #[test] + fn patterns() { + parse!( + r#"SELECT the_a.name AS src, the_b.name AS dest FROM my_graph MATCH (the_a:a) -[the_y:y]-> (the_b:b) WHERE the_y.score > 10"# + ); + parse!(r#""SELECT a,b FROM g MATCH (a)-[:has]->()-[:contains]->(b)""#); + parse!(r#"SELECT a,b FROM (g MATCH (a) -[:has]-> (x), (x)-[:contains]->(b))"#); + } + + #[test] + fn path_var() { + parse!(r#"SELECT a,b FROM (g MATCH p = (a:A) -[e:E]-> (b:B))"#); + } + + #[test] + fn paranthesized() { + parse!( + r#"SELECT a,b FROM (g MATCH [(a:A)-[e:Edge]->(b:A) WHERE a.owner=b.owner]{2,5})"# + ); + parse!(r#"SELECT a,b FROM (g MATCH pathVar = (a:A)[()-[e:Edge]->()]{1,3}(b:B))"#); + + // brackets + parse!(r#"SELECT a,b FROM (g MATCH pathVar = (a:A)[-[e:Edge]->]*(b:B))"#); + // parens + parse!(r#"SELECT a,b FROM (g MATCH pathVar = (a:A)(-[e:Edge]->)*(b:B))"#); + } + + #[test] + fn filters() { + parse!( + r#"SELECT u as banCandidate FROM g MATCH (p:Post Where p.isFlagged = true) <-[:createdPost]- (u:User WHERE u.isBanned = false AND u.karma < 20) -[:createdComment]->(c:Comment WHERE c.isFlagged = true) WHERE p.title LIKE '%considered harmful%'"# + ); + } + + #[test] + fn restrictors() { + parse!( + r#"SELECT p FROM g MATCH TRAIL p = (a WHERE a.owner='Dave') -[t:Transfer]-> * (b WHERE b.owner='Aretha')"# + ); + parse!( + r#"SELECT p FROM g MATCH SIMPLE p = (a WHERE a.owner='Dave') -[t:Transfer]-> * (b WHERE b.owner='Aretha')"# + ); + parse!( + r#"SELECT p FROM g MATCH ACYCLIC p = (a WHERE a.owner='Dave') -[t:Transfer]-> * (b WHERE b.owner='Aretha')"# + ); + } + + #[test] + fn selectors() { + parse!( + r#"SELECT p FROM g MATCH ANY SHORTEST p = (a WHERE a.owner='Dave') -[t:Transfer]-> * (b WHERE b.owner='Aretha')"# + ); + parse!( + r#"SELECT p FROM g MATCH ALL SHORTEST p = (a WHERE a.owner='Dave') -[t:Transfer]-> * (b WHERE b.owner='Aretha')"# + ); + parse!( + r#"SELECT p FROM g MATCH ANY p = (a WHERE a.owner='Dave') -[t:Transfer]-> * (b WHERE b.owner='Aretha')"# + ); + parse!( + r#"SELECT p FROM g MATCH ANY 5 p = (a WHERE a.owner='Dave') -[t:Transfer]-> * (b WHERE b.owner='Aretha')"# + ); + parse!( + r#"SELECT p FROM g MATCH SHORTEST 5 p = (a WHERE a.owner='Dave') -[t:Transfer]-> * (b WHERE b.owner='Aretha')"# + ); + parse!( + r#"SELECT p FROM g MATCH SHORTEST 5 GROUP p = (a WHERE a.owner='Dave') -[t:Transfer]-> * (b WHERE b.owner='Aretha')"# + ); + } + + #[test] + fn match_and_join() { + parse!( + r#"SELECT a,b,c, t1.x as x, t2.y as y FROM (graph MATCH (a) -> (b), (a) -> (c)), table1 as t1, table2 as t2"# + ); + } + + #[test] + fn union() { + parse!(r#"(MyGraph MATCH (x)) UNION SELECT * FROM tbl1"#); + parse!(r#"SELECT * FROM tbl1 UNION (MyGraph MATCH (x))"#); + } + + #[test] + fn etc() { + parse!("SELECT * FROM g MATCH ALL SHORTEST [ (x)-[e]->*(y) ]"); + parse!("SELECT * FROM g MATCH ALL SHORTEST [ TRAIL (x)-[e]->*(y) ]"); + } + } + mod errors { use super::*; use crate::error::{LexError, UnexpectedToken, UnexpectedTokenData}; diff --git a/partiql-parser/src/parse/partiql.lalrpop b/partiql-parser/src/parse/partiql.lalrpop index 11057b75..6f38114e 100644 --- a/partiql-parser/src/parse/partiql.lalrpop +++ b/partiql-parser/src/parse/partiql.lalrpop @@ -333,7 +333,16 @@ TableBaseReference: ast::AstNode = { at_alias, by_alias }, lo..hi) - } + }, + => { + state.node(ast::FromLet { + expr: Box::new(e), + kind: ast::FromLetKind::Scan, + as_alias, + at_alias, + by_alias + }, lo..hi) + }, } #[inline] @@ -742,6 +751,7 @@ ExprPrecedence09: Synth = { }, lo..hi) )) }, + , , } @@ -750,6 +760,41 @@ LikeEscape: Box = { "ESCAPE" => Box::new(e.data) } +#[inline] +GraphMatchExpr: Synth = { + "(" "MATCH" ")" => { + Synth::empty(ast::Expr::GraphMatch( + state.node(ast::GraphMatch { + expr: Box::new(l.data), + graph_expr: Box::new(r), + }, lo..hi) + )) + } +} + +#[inline] +GraphMatchExprNoParens: ast::Expr = { + "MATCH" => + ast::Expr::GraphMatch( + state.node(ast::GraphMatch { + expr: Box::new(l.data), + graph_expr: Box::new(r), + }, lo..hi) + ) +} + +GraphMatch: ast::AstNode = { + => { + state.node(ast::GraphMatchExpr{selector, patterns: vec![patterns]}, lo..hi) + }, +} + +GraphMatchList: ast::AstNode = { + > => { + state.node(ast::GraphMatchExpr{selector, patterns: patterns}, lo..hi) + } +} + ExprPrecedence08: Synth = { "||" => Synth::empty(ast::Expr::BinOp( @@ -947,6 +992,198 @@ SubQueryAst: ast::AstNode = { => state.node(subq, lo..hi), } + + +// ------------------------------------------------------------------------------ // +// // +// GPML Expression // +// // +// ------------------------------------------------------------------------------ // + +//#[inline] +MatchPatternSelector: ast::GraphMatchSelector = { + "ANY" "SHORTEST" => ast::GraphMatchSelector::AnyShortest, + "ALL" "SHORTEST" => ast::GraphMatchSelector::AllShortest, + "ANY" => { + // TODO handle bad number parse + k.map(|n| ast::GraphMatchSelector::AnyK(n.parse().unwrap())).unwrap_or(ast::GraphMatchSelector::Any) + }, + "SHORTEST" => { + // TODO handle bad number parse + ast::GraphMatchSelector::ShortestK(k.parse().unwrap()) + }, + "SHORTEST" "GROUP" => { + // TODO handle bad number parse + ast::GraphMatchSelector::ShortestKGroup(k.parse().unwrap()) + } +} + +MatchPattern: ast::AstNode = { + => { + state.node(ast::GraphMatchPattern{ + restrictor, + quantifier: None, + prefilter: None, + variable, + parts, + }, lo..hi) + }, + "(" ")" => { + state.node(ast::GraphMatchPattern{ + quantifier, + prefilter, + ..pattern.node + }, lo..hi) + }, + "[" "]" => { + state.node(ast::GraphMatchPattern{ + quantifier, + prefilter, + ..pattern.node + }, lo..hi) + }, +} + +MatchPatternNested: ast::AstNode = { + => { + state.node(ast::GraphMatchPattern{ + restrictor, + quantifier: None, + prefilter: None, + variable, + parts, + }, lo..hi) + } +} + +//#[inline] +MatchPatternRestrictor: ast::GraphMatchRestrictor = { + "TRAIL" => ast::GraphMatchRestrictor::Trail, + "ACYCLIC" => ast::GraphMatchRestrictor::Acyclic, + "SIMPLE" => ast::GraphMatchRestrictor::Simple, +} + +//#[inline] +MatchPatternParts: Vec = { + => { + let node = ast::GraphMatchPatternPart::Node(n); + std::iter::once(node).chain(parts.into_iter().flatten()).collect() + } +} + +//#[inline] +MatchPatternPartsNested: Vec = { + , + , + => vec![ast::GraphMatchPatternPart::Edge(e)], +} + +MatchPatternPartContinue: Vec = { + => vec![ast::GraphMatchPatternPart::Edge(e),ast::GraphMatchPatternPart::Node(n)], + => vec![ast::GraphMatchPatternPart::Pattern(p),ast::GraphMatchPatternPart::Node(n)], +} + +MatchPatternPartParen: ast::AstNode = { + "(" ")" => { + state.node(ast::GraphMatchPattern { + prefilter, + quantifier, + ..pattern.node + }, lo..hi) + }, + "[" "]" => { + state.node(ast::GraphMatchPattern { + prefilter, + quantifier, + ..pattern.node + }, lo..hi) + }, +} + +//#[inline] +MatchPatternQuantifier: ast::AstNode = { + "+" => state.node(ast::GraphMatchQuantifier{ lower:0, upper:None }, lo..hi), + "*" => state.node(ast::GraphMatchQuantifier{ lower:1, upper:None }, lo..hi), + "{" "," "}" => { + // TODO error on invalid literal + state.node(ast::GraphMatchQuantifier{ lower: lower.parse().unwrap(), upper: upper.map(|n| n.parse().unwrap()) }, lo..hi) + }, +} + +MatchPatternPartNode: ast::AstNode = { + "(" ")" => { + state.node(ast::GraphMatchNode { + prefilter, + variable, + label, + }, lo..hi) + }, +} + +MatchPatternPartEdge: ast::AstNode = { + => state.node(ast::GraphMatchEdge{ quantifier, ..spec}, lo..hi), + => state.node(ast::GraphMatchEdge{ quantifier, ..spec}, lo..hi), +} + +MatchPatternPartEdgeWSpec: ast::GraphMatchEdge = { + "-" "-" ">" => ast::GraphMatchEdge{ direction: ast::GraphMatchDirection::Right, ..spec}, + "~" "~" => ast::GraphMatchEdge{ direction: ast::GraphMatchDirection::Undirected, ..spec}, + "<" "-" "-" => ast::GraphMatchEdge{ direction: ast::GraphMatchDirection::Left, ..spec}, + "~" "~" ">" => ast::GraphMatchEdge{ direction: ast::GraphMatchDirection::UndirectedOrRight, ..spec}, + "<" "~" "~" => ast::GraphMatchEdge{ direction: ast::GraphMatchDirection::LeftOrUndirected, ..spec}, + "<" "-" "-" ">" => ast::GraphMatchEdge{ direction: ast::GraphMatchDirection::LeftOrRight, ..spec}, + "-" "-" => ast::GraphMatchEdge{ direction: ast::GraphMatchDirection::LeftOrUndirectedOrRight, ..spec}, +} + +MatchPatternPartEdgeSpec: ast::GraphMatchEdge = { + "[" "]" => { + ast::GraphMatchEdge { + direction: ast::GraphMatchDirection::Undirected, + quantifier: None, + prefilter, + variable, + label, + } + } +} + +MatchPatternPartEdgeAbbr: ast::GraphMatchEdge = { + "-" ">" => ast::GraphMatchEdge{ direction: ast::GraphMatchDirection::Right, quantifier: None, prefilter: None, variable: None, label: Default::default() }, + "~" => ast::GraphMatchEdge{ direction: ast::GraphMatchDirection::Undirected, quantifier: None, prefilter: None, variable: None, label: Default::default() }, + "<" "-" => ast::GraphMatchEdge{ direction: ast::GraphMatchDirection::Left, quantifier: None, prefilter: None, variable: None, label: Default::default() }, + "~" ">" => ast::GraphMatchEdge{ direction: ast::GraphMatchDirection::UndirectedOrRight, quantifier: None, prefilter: None, variable: None, label: Default::default() }, + "<" "~" => ast::GraphMatchEdge{ direction: ast::GraphMatchDirection::LeftOrUndirected, quantifier: None, prefilter: None, variable: None, label: Default::default() }, + "<" "-" ">" => ast::GraphMatchEdge{ direction: ast::GraphMatchDirection::LeftOrRight, quantifier: None, prefilter: None, variable: None, label: Default::default() }, + "-" => ast::GraphMatchEdge{ direction: ast::GraphMatchDirection::LeftOrUndirectedOrRight, quantifier: None, prefilter: None, variable: None, label: Default::default() }, +} + +//#[inline] +MatchPatternPartName: ast::SymbolPrimitive = { + => { + ast::SymbolPrimitive { + value: name.to_owned(), + case: ast::CaseSensitivity::CaseSensitive + } + } +} + +//#[inline] // TODO conjunction/disjunction/negation +MatchPatternPartLabel: Vec = { + ":" => vec![l] +} + +//#[inline] +MatchPatternPartPrefilter: Box = { + "WHERE" +} + +//#[inline] +MatchPatternPathVariable: ast::SymbolPrimitive = { + "=" +} + + + // ------------------------------------------------------------------------------ // // // // Case Expression // @@ -1467,6 +1704,7 @@ extern { "==" => lexer::Token::EqualEqual, "!=" => lexer::Token::BangEqual, "<>" => lexer::Token::LessGreater, + "~" => lexer::Token::Tilde, "<" => lexer::Token::LessThan, ">" => lexer::Token::GreaterThan, @@ -1486,9 +1724,11 @@ extern { "EmbeddedDoc" => lexer::Token::EmbeddedDoc(<&'input str>), // Keywords + "ACYCLIC" => lexer::Token::Acyclic, "ALL" => lexer::Token::All, "ASC" => lexer::Token::Asc, "AND" => lexer::Token::And, + "ANY" => lexer::Token::Any, "AS" => lexer::Token::As, "AT" => lexer::Token::At, "BETWEEN" => lexer::Token::Between, @@ -1521,6 +1761,7 @@ extern { "LEFT" => lexer::Token::Left, "LIKE" => lexer::Token::Like, "LIMIT" => lexer::Token::Limit, + "MATCH" => lexer::Token::Match, "MISSING" => lexer::Token::Missing, "NATURAL" => lexer::Token::Natural, "NOT" => lexer::Token::Not, @@ -1541,7 +1782,10 @@ extern { "TABLE" => lexer::Token::Table, "TIME" => lexer::Token::Time, "TIMESTAMP" => lexer::Token::Timestamp, + "SIMPLE" => lexer::Token::Simple, + "SHORTEST" => lexer::Token::Shortest, "THEN" => lexer::Token::Then, + "TRAIL" => lexer::Token::Trail, "TRUE" => lexer::Token::True, "UNION" => lexer::Token::Union, "UNPIVOT" => lexer::Token::Unpivot, From b9340a7f64bfcc4e478463475c6999ee2c06f27f Mon Sep 17 00:00:00 2001 From: Josh Pschorr Date: Wed, 19 Mar 2025 15:21:15 -0700 Subject: [PATCH 2/6] Add pretty-printing for GPML --- partiql-ast/src/pretty.rs | 245 +++++++++++++++++- partiql-common/src/pretty.rs | 22 ++ partiql-parser/src/parse/partiql.lalrpop | 4 +- partiql/Cargo.toml | 1 + partiql/tests/pretty.rs | 201 +++++++++++++- .../tests/snapshots/pretty__graph_edge_1.snap | 33 +++ .../snapshots/pretty__graph_edge_10.snap | 32 +++ .../snapshots/pretty__graph_edge_11.snap | 33 +++ .../snapshots/pretty__graph_edge_12.snap | 32 +++ .../snapshots/pretty__graph_edge_13.snap | 33 +++ .../snapshots/pretty__graph_edge_14.snap | 32 +++ .../tests/snapshots/pretty__graph_edge_2.snap | 32 +++ .../tests/snapshots/pretty__graph_edge_3.snap | 33 +++ .../tests/snapshots/pretty__graph_edge_4.snap | 32 +++ .../tests/snapshots/pretty__graph_edge_5.snap | 33 +++ .../tests/snapshots/pretty__graph_edge_6.snap | 32 +++ .../tests/snapshots/pretty__graph_edge_7.snap | 33 +++ .../tests/snapshots/pretty__graph_edge_8.snap | 32 +++ .../tests/snapshots/pretty__graph_edge_9.snap | 33 +++ .../tests/snapshots/pretty__graph_etc_1.snap | 35 +++ .../tests/snapshots/pretty__graph_etc_2.snap | 35 +++ .../snapshots/pretty__graph_filters_1.snap | 53 ++++ .../pretty__graph_match_and_join_1.snap | 49 ++++ .../pretty__graph_parenthesized_1.snap | 34 +++ .../pretty__graph_parenthesized_2.snap | 33 +++ .../pretty__graph_parenthesized_3.snap | 33 +++ .../pretty__graph_parenthesized_4.snap | 33 +++ .../snapshots/pretty__graph_path_var_1.snap | 33 +++ .../snapshots/pretty__graph_patterns_1.snap | 42 +++ .../snapshots/pretty__graph_patterns_2.snap | 33 +++ .../snapshots/pretty__graph_patterns_3.snap | 37 +++ .../pretty__graph_quantifiers_1.snap | 33 +++ .../pretty__graph_quantifiers_2.snap | 33 +++ .../pretty__graph_quantifiers_3.snap | 33 +++ .../pretty__graph_quantifiers_4.snap | 33 +++ .../pretty__graph_quantifiers_5.snap | 32 +++ .../pretty__graph_quantifiers_6.snap | 32 +++ .../pretty__graph_quantifiers_7.snap | 33 +++ .../pretty__graph_quantifiers_8.snap | 33 +++ .../pretty__graph_restrictors_1.snap | 33 +++ .../pretty__graph_restrictors_2.snap | 33 +++ .../pretty__graph_restrictors_3.snap | 33 +++ .../snapshots/pretty__graph_selectors_1.snap | 36 +++ .../snapshots/pretty__graph_selectors_2.snap | 36 +++ .../snapshots/pretty__graph_selectors_3.snap | 35 +++ .../snapshots/pretty__graph_selectors_4.snap | 35 +++ .../snapshots/pretty__graph_selectors_5.snap | 36 +++ .../snapshots/pretty__graph_selectors_6.snap | 36 +++ .../snapshots/pretty__graph_union_1.snap | 43 +++ .../snapshots/pretty__graph_union_2.snap | 43 +++ 50 files changed, 2027 insertions(+), 12 deletions(-) create mode 100644 partiql/tests/snapshots/pretty__graph_edge_1.snap create mode 100644 partiql/tests/snapshots/pretty__graph_edge_10.snap create mode 100644 partiql/tests/snapshots/pretty__graph_edge_11.snap create mode 100644 partiql/tests/snapshots/pretty__graph_edge_12.snap create mode 100644 partiql/tests/snapshots/pretty__graph_edge_13.snap create mode 100644 partiql/tests/snapshots/pretty__graph_edge_14.snap create mode 100644 partiql/tests/snapshots/pretty__graph_edge_2.snap create mode 100644 partiql/tests/snapshots/pretty__graph_edge_3.snap create mode 100644 partiql/tests/snapshots/pretty__graph_edge_4.snap create mode 100644 partiql/tests/snapshots/pretty__graph_edge_5.snap create mode 100644 partiql/tests/snapshots/pretty__graph_edge_6.snap create mode 100644 partiql/tests/snapshots/pretty__graph_edge_7.snap create mode 100644 partiql/tests/snapshots/pretty__graph_edge_8.snap create mode 100644 partiql/tests/snapshots/pretty__graph_edge_9.snap create mode 100644 partiql/tests/snapshots/pretty__graph_etc_1.snap create mode 100644 partiql/tests/snapshots/pretty__graph_etc_2.snap create mode 100644 partiql/tests/snapshots/pretty__graph_filters_1.snap create mode 100644 partiql/tests/snapshots/pretty__graph_match_and_join_1.snap create mode 100644 partiql/tests/snapshots/pretty__graph_parenthesized_1.snap create mode 100644 partiql/tests/snapshots/pretty__graph_parenthesized_2.snap create mode 100644 partiql/tests/snapshots/pretty__graph_parenthesized_3.snap create mode 100644 partiql/tests/snapshots/pretty__graph_parenthesized_4.snap create mode 100644 partiql/tests/snapshots/pretty__graph_path_var_1.snap create mode 100644 partiql/tests/snapshots/pretty__graph_patterns_1.snap create mode 100644 partiql/tests/snapshots/pretty__graph_patterns_2.snap create mode 100644 partiql/tests/snapshots/pretty__graph_patterns_3.snap create mode 100644 partiql/tests/snapshots/pretty__graph_quantifiers_1.snap create mode 100644 partiql/tests/snapshots/pretty__graph_quantifiers_2.snap create mode 100644 partiql/tests/snapshots/pretty__graph_quantifiers_3.snap create mode 100644 partiql/tests/snapshots/pretty__graph_quantifiers_4.snap create mode 100644 partiql/tests/snapshots/pretty__graph_quantifiers_5.snap create mode 100644 partiql/tests/snapshots/pretty__graph_quantifiers_6.snap create mode 100644 partiql/tests/snapshots/pretty__graph_quantifiers_7.snap create mode 100644 partiql/tests/snapshots/pretty__graph_quantifiers_8.snap create mode 100644 partiql/tests/snapshots/pretty__graph_restrictors_1.snap create mode 100644 partiql/tests/snapshots/pretty__graph_restrictors_2.snap create mode 100644 partiql/tests/snapshots/pretty__graph_restrictors_3.snap create mode 100644 partiql/tests/snapshots/pretty__graph_selectors_1.snap create mode 100644 partiql/tests/snapshots/pretty__graph_selectors_2.snap create mode 100644 partiql/tests/snapshots/pretty__graph_selectors_3.snap create mode 100644 partiql/tests/snapshots/pretty__graph_selectors_4.snap create mode 100644 partiql/tests/snapshots/pretty__graph_selectors_5.snap create mode 100644 partiql/tests/snapshots/pretty__graph_selectors_6.snap create mode 100644 partiql/tests/snapshots/pretty__graph_union_1.snap create mode 100644 partiql/tests/snapshots/pretty__graph_union_2.snap diff --git a/partiql-ast/src/pretty.rs b/partiql-ast/src/pretty.rs index 7974f1ed..f8ee2a60 100644 --- a/partiql-ast/src/pretty.rs +++ b/partiql-ast/src/pretty.rs @@ -1,10 +1,11 @@ use crate::ast::*; use partiql_common::pretty::{ - pretty_list, pretty_parenthesized_doc, pretty_prefixed_doc, pretty_seperated, - pretty_seperated_doc, pretty_seq, pretty_seq_doc, PrettyDoc, PRETTY_INDENT_MINOR_NEST, - PRETTY_INDENT_SUBORDINATE_CLAUSE_NEST, + pretty_bracketed_doc, pretty_list, pretty_parenthesized_doc, pretty_prefixed_doc, + pretty_seperated, pretty_seperated_doc, pretty_seq, pretty_seq_doc, pretty_surrounded_doc, + PrettyDoc, PRETTY_INDENT_MINOR_NEST, PRETTY_INDENT_SUBORDINATE_CLAUSE_NEST, }; use pretty::{DocAllocator, DocBuilder}; +use std::borrow::Cow; impl PrettyDoc for AstNode where T: PrettyDoc, @@ -316,9 +317,8 @@ impl PrettyDoc for Expr { Expr::Sexp(inner) => inner.pretty_doc(arena), Expr::Path(inner) => inner.pretty_doc(arena), Expr::Call(inner) => inner.pretty_doc(arena), - Expr::CallAgg(inner) => inner.pretty_doc(arena), - + Expr::GraphMatch(inner) => inner.pretty_doc(arena), Expr::Query(inner) => { let inner = inner.pretty_doc(arena).group(); arena @@ -329,9 +329,6 @@ impl PrettyDoc for Expr { Expr::Error => { unreachable!(); } - Expr::GraphMatch(_inner) => { - todo!("inner.pretty_doc(arena)") - } } .group() } @@ -1000,6 +997,238 @@ impl PrettyDoc for Join { } } +impl PrettyDoc for GraphMatch { + fn pretty_doc<'b, D, A>(&'b self, arena: &'b D) -> DocBuilder<'b, D, A> + where + D: DocAllocator<'b, A>, + D::Doc: Clone, + A: Clone, + { + let head = arena.intersperse( + [self.expr.pretty_doc(arena), arena.text("MATCH")], + arena.space(), + ); + let patterns = self.graph_expr.pretty_doc(arena); + let match_expr = arena.intersperse([head, patterns], arena.space()); + + let parens_needed = self.graph_expr.node.patterns.len() > 1; + if parens_needed { + pretty_parenthesized_doc(match_expr, arena) + } else { + match_expr + } + } +} + +impl PrettyDoc for GraphMatchExpr { + fn pretty_doc<'b, D, A>(&'b self, arena: &'b D) -> DocBuilder<'b, D, A> + where + D: DocAllocator<'b, A>, + D::Doc: Clone, + A: Clone, + { + let selector = self.selector.clone().map(|s| { + let parts: Vec> = match s { + GraphMatchSelector::AnyShortest => vec!["ANY".into(), "SHORTEST".into()], + GraphMatchSelector::AllShortest => vec!["ALL".into(), "SHORTEST".into()], + GraphMatchSelector::Any => vec!["ANY".into()], + GraphMatchSelector::AnyK(k) => vec!["ANY".into(), k.to_string().into()], + GraphMatchSelector::ShortestK(k) => vec!["SHORTEST".into(), k.to_string().into()], + GraphMatchSelector::ShortestKGroup(k) => { + vec!["SHORTEST".into(), k.to_string().into(), "GROUP".into()] + } + }; + + arena.intersperse(parts, arena.space()).group() + }); + let patterns = pretty_list(&self.patterns, PRETTY_INDENT_MINOR_NEST, arena); + if let Some(selector) = selector { + arena.intersperse([selector, patterns], arena.softline()) + } else { + patterns + } + .group() + } +} + +impl PrettyDoc for GraphMatchPattern { + fn pretty_doc<'b, D, A>(&'b self, arena: &'b D) -> DocBuilder<'b, D, A> + where + D: DocAllocator<'b, A>, + D::Doc: Clone, + A: Clone, + { + let pattern = pretty_seperated( + arena.nil().append(arena.space()), + &self.parts, + PRETTY_INDENT_MINOR_NEST, + arena, + ); + let mut doc = if let Some(r) = &self.restrictor { + match r { + GraphMatchRestrictor::Trail => arena.text("TRAIL"), + GraphMatchRestrictor::Acyclic => arena.text("ACYCLIC"), + GraphMatchRestrictor::Simple => arena.text("SIMPLE"), + } + .append(arena.space()) + } else { + arena.nil() + }; + + let pattern = if let Some(v) = &self.variable { + arena.intersperse( + [arena.text(&v.value), arena.text("="), pattern], + arena.space(), + ) + } else { + pattern + }; + doc = doc.append(pattern); + + let brackets = + self.restrictor.is_some() || self.quantifier.is_some() || self.prefilter.is_some(); + + if brackets { + let doc = if let Some(filter) = &self.prefilter { + arena.intersperse( + [doc, arena.text("WHERE"), filter.pretty_doc(arena)], + arena.space(), + ) + } else { + doc + }; + let bracketed = pretty_bracketed_doc(doc, arena); + if let Some(postfix) = &self.quantifier { + arena.concat([bracketed, postfix.pretty_doc(arena)]) + } else { + bracketed + } + } else { + doc + } + .group() + } +} + +impl PrettyDoc for GraphMatchPatternPart { + fn pretty_doc<'b, D, A>(&'b self, arena: &'b D) -> DocBuilder<'b, D, A> + where + D: DocAllocator<'b, A>, + D::Doc: Clone, + A: Clone, + { + match self { + GraphMatchPatternPart::Node(n) => n.pretty_doc(arena), + GraphMatchPatternPart::Edge(e) => e.pretty_doc(arena), + GraphMatchPatternPart::Pattern(p) => p.pretty_doc(arena), + } + } +} + +impl PrettyDoc for GraphMatchNode { + fn pretty_doc<'b, D, A>(&'b self, arena: &'b D) -> DocBuilder<'b, D, A> + where + D: DocAllocator<'b, A>, + D::Doc: Clone, + A: Clone, + { + let mut spec = arena.nil(); + if let Some(r) = &self.variable { + spec = spec.append(arena.text(&r.value)); + } + if let Some(l) = &self.label { + debug_assert_eq!(l.len(), 1); // TODO + spec = spec.append(arena.text(":")).append(arena.text(&l[0].value)); + } + if let Some(r) = &self.prefilter { + let parts = [spec, arena.text("WHERE"), r.pretty_doc(arena)]; + spec = arena.intersperse(parts, arena.space()).into(); + } + pretty_surrounded_doc(spec, "(", ")", arena) + } +} + +impl PrettyDoc for GraphMatchEdge { + fn pretty_doc<'b, D, A>(&'b self, arena: &'b D) -> DocBuilder<'b, D, A> + where + D: DocAllocator<'b, A>, + D::Doc: Clone, + A: Clone, + { + let mut spec = None; + if let Some(r) = &self.variable { + spec = spec + .unwrap_or_else(|| arena.nil()) + .append(arena.text(&r.value)) + .into(); + } + if let Some(l) = &self.label { + debug_assert_eq!(l.len(), 1); // TODO + spec = spec + .unwrap_or_else(|| arena.nil()) + .append(arena.text(":")) + .append(arena.text(&l[0].value)) + .into(); + } + if let Some(r) = &self.prefilter { + let parts = [ + spec.unwrap_or_else(|| arena.nil()), + arena.text("WHERE"), + r.pretty_doc(arena), + ]; + spec = arena.intersperse(parts, arena.space()).into(); + } + + let mut edge = if let Some(spec) = spec { + let (prefix, suffix) = match self.direction { + GraphMatchDirection::Right => ("-[", "]->"), + GraphMatchDirection::Left => ("<-[", "]-"), + GraphMatchDirection::Undirected => ("~[", "]~"), + GraphMatchDirection::UndirectedOrRight => ("~[", "]~>"), + GraphMatchDirection::LeftOrUndirected => ("<~[", "]~"), + GraphMatchDirection::LeftOrRight => ("<-[", "]->"), + GraphMatchDirection::LeftOrUndirectedOrRight => ("-[", "]-"), + }; + pretty_surrounded_doc(spec, prefix, suffix, arena) + } else { + let edge = match self.direction { + GraphMatchDirection::Right => "->", + GraphMatchDirection::Left => "<-", + GraphMatchDirection::Undirected => "~", + GraphMatchDirection::UndirectedOrRight => "~>", + GraphMatchDirection::LeftOrUndirected => "<~", + GraphMatchDirection::LeftOrRight => "<->", + GraphMatchDirection::LeftOrUndirectedOrRight => "-", + }; + arena.text(edge) + }; + if let Some(q) = &self.quantifier { + edge = arena.concat([edge, q.pretty_doc(arena)]); + } + edge.group() + } +} + +impl PrettyDoc for GraphMatchQuantifier { + fn pretty_doc<'b, D, A>(&'b self, arena: &'b D) -> DocBuilder<'b, D, A> + where + D: DocAllocator<'b, A>, + D::Doc: Clone, + A: Clone, + { + let GraphMatchQuantifier { lower, upper } = &self; + match (lower, upper) { + (0, None) => arena.text("*"), + (1, None) => arena.text("+"), + (l, u) => { + let l = Cow::Owned(l.to_string()); + let u = u.map(|u| Cow::Owned(u.to_string())).unwrap_or("".into()); + pretty_surrounded_doc(arena.concat([l, ",".into(), u]), "{", "}", arena) + } + } + } +} + impl PrettyDoc for Let { fn pretty_doc<'b, D, A>(&'b self, _arena: &'b D) -> DocBuilder<'b, D, A> where diff --git a/partiql-common/src/pretty.rs b/partiql-common/src/pretty.rs index ecdf2f06..fd259e3c 100644 --- a/partiql-common/src/pretty.rs +++ b/partiql-common/src/pretty.rs @@ -196,6 +196,28 @@ where pretty_surrounded_doc(doc, "(", ")", arena) } +#[inline] +pub fn pretty_sp_bracketed_doc<'b, E, D, A>(doc: E, arena: &'b D) -> DocBuilder<'b, D, A> +where + E: Pretty<'b, D, A>, + D: DocAllocator<'b, A>, + D::Doc: Clone, + A: Clone, +{ + pretty_surrounded_doc(doc, "[ ", " ]", arena) +} + +#[inline] +pub fn pretty_bracketed_doc<'b, E, D, A>(doc: E, arena: &'b D) -> DocBuilder<'b, D, A> +where + E: Pretty<'b, D, A>, + D: DocAllocator<'b, A>, + D::Doc: Clone, + A: Clone, +{ + pretty_surrounded_doc(doc, "[", "]", arena) +} + #[inline] pub fn pretty_seq_doc<'i, 'b, I, E, D, A>( seq: I, diff --git a/partiql-parser/src/parse/partiql.lalrpop b/partiql-parser/src/parse/partiql.lalrpop index 6f38114e..272bd5bc 100644 --- a/partiql-parser/src/parse/partiql.lalrpop +++ b/partiql-parser/src/parse/partiql.lalrpop @@ -1102,8 +1102,8 @@ MatchPatternPartParen: ast::AstNode = { //#[inline] MatchPatternQuantifier: ast::AstNode = { - "+" => state.node(ast::GraphMatchQuantifier{ lower:0, upper:None }, lo..hi), - "*" => state.node(ast::GraphMatchQuantifier{ lower:1, upper:None }, lo..hi), + "*" => state.node(ast::GraphMatchQuantifier{ lower:0, upper:None }, lo..hi), + "+" => state.node(ast::GraphMatchQuantifier{ lower:1, upper:None }, lo..hi), "{" "," "}" => { // TODO error on invalid literal state.node(ast::GraphMatchQuantifier{ lower: lower.parse().unwrap(), upper: upper.map(|n| n.parse().unwrap()) }, lo..hi) diff --git a/partiql/Cargo.toml b/partiql/Cargo.toml index c5386189..daaef656 100644 --- a/partiql/Cargo.toml +++ b/partiql/Cargo.toml @@ -34,6 +34,7 @@ partiql-logical-planner = { path = "../partiql-logical-planner" } partiql-eval = { path = "../partiql-eval" } partiql-extension-value-functions = { path = "../extension/partiql-extension-value-functions" } partiql-extension-ion = { path = "../extension/partiql-extension-ion" } +once_cell = "1" ion-rs_old = { version = "0.18", package = "ion-rs" } diff --git a/partiql/tests/pretty.rs b/partiql/tests/pretty.rs index 6b2d58c0..2f53820c 100644 --- a/partiql/tests/pretty.rs +++ b/partiql/tests/pretty.rs @@ -15,8 +15,11 @@ fn pretty_print_test(name: &str, statement: &str) { assert!(res.is_ok()); let res = res.unwrap(); - pretty_print_output_test(name, statement, &res.ast); + // First test that the pretty printed version is parseable pretty_print_roundtrip_test(&res.ast); + + // Then snapshot the pretty printed version + pretty_print_output_test(name, statement, &res.ast); } #[track_caller] @@ -41,7 +44,6 @@ fn pretty_print_output_test(name: &str, statement: &str, statement_ast: &AstNode #[track_caller] fn pretty_print_roundtrip_test(statement_ast: &AstNode) { let pretty = statement_ast.to_pretty_string(40).unwrap(); - let reparsed = parse(pretty.as_str()); assert!(reparsed.is_ok()); @@ -294,6 +296,201 @@ fn pretty_ands_and_ors() { ); } +mod graph { + use once_cell::sync::Lazy; + use std::collections::HashMap; + use std::sync::atomic::{AtomicU32, Ordering}; + use std::sync::Mutex; + static COUNTS: Lazy>> = + Lazy::new(|| HashMap::default().into()); + + macro_rules! parse_test { + ($k:literal, $q:expr) => {{ + let k = $k; + let mut counts = match COUNTS.lock() { + Ok(guard) => guard, + Err(poisoned) => poisoned.into_inner(), + }; + let count = counts + .entry(k.to_string()) + .or_insert_with(|| AtomicU32::new(1)); + let next = count.fetch_add(1, Ordering::SeqCst); + drop(counts); + + super::pretty_print_test(&format!("graph_{k}_{next}"), $q); + }}; + } + #[test] + fn edge() { + macro_rules! parse { + ($q:expr) => {{ + parse_test!("edge", $q) + }}; + } + + parse!(r#"SELECT a,b FROM g MATCH (a:A) -[e:E]-> (b:B)"#); + parse!(r#"SELECT a,b FROM g MATCH (a:A) -> (b:B)"#); + parse!(r#"SELECT a,b FROM g MATCH (a:A) ~[e:E]~ (b:B)"#); + parse!(r#"SELECT a,b FROM g MATCH (a:A) ~ (b:B)"#); + parse!(r#"SELECT a,b FROM g MATCH (a:A) <-[e:E]- (b:B)"#); + parse!(r#"SELECT a,b FROM g MATCH (a:A) <- (b:B)"#); + parse!(r#"SELECT a,b FROM g MATCH (a:A) ~[e:E]~> (b:B)"#); + parse!(r#"SELECT a,b FROM g MATCH (a:A) ~> (b:B)"#); + parse!(r#"SELECT a,b FROM g MATCH (a:A) <~[e:E]~ (b:B)"#); + parse!(r#"SELECT a,b FROM g MATCH (a:A) <~ (b:B)"#); + parse!(r#"SELECT a,b FROM g MATCH (a:A) <-[e:E]-> (b:B)"#); + parse!(r#"SELECT a,b FROM g MATCH (a:A) <-> (b:B)"#); + parse!(r#"SELECT a,b FROM g MATCH (a:A) -[e:E]- (b:B)"#); + parse!(r#"SELECT a,b FROM g MATCH (a:A) - (b:B)"#); + } + #[test] + fn quantifiers() { + macro_rules! parse { + ($q:expr) => {{ + parse_test!("quantifiers", $q) + }}; + } + parse!(r#"SELECT a,b FROM g MATCH (a:A)-[:edge]->*(b:B)"#); + parse!(r#"SELECT a,b FROM g MATCH (a:A)<-[:edge]-+(b:B)"#); + parse!(r#"SELECT a,b FROM g MATCH (a:A)~[:edge]~{5,}(b:B)"#); + parse!(r#"SELECT a,b FROM g MATCH (a:A)-[e:edge]-{2,6}(b:B)"#); + parse!(r#"SELECT a,b FROM g MATCH (a:A)->*(b:B)"#); + parse!(r#"SELECT a,b FROM g MATCH (a:A)<-+(b:B)"#); + parse!(r#"SELECT a,b FROM g MATCH (a:A)~{5,}(b:B)"#); + parse!(r#"SELECT a,b FROM g MATCH (a:A)-{2,6}(b:B)"#); + } + #[test] + fn patterns() { + macro_rules! parse { + ($q:expr) => {{ + parse_test!("patterns", $q) + }}; + } + parse!( + r#"SELECT the_a.name AS src, the_b.name AS dest FROM my_graph MATCH (the_a:a) -[the_y:y]-> (the_b:b) WHERE the_y.score > 10"# + ); + parse!(r#"SELECT a,b FROM g MATCH (a)-[:has]->()-[:contains]->(b)"#); + parse!(r#"SELECT a,b FROM (g MATCH (a) -[:has]-> (x), (x)-[:contains]->(b))"#); + } + #[test] + fn path_var() { + macro_rules! parse { + ($q:expr) => {{ + parse_test!("path_var", $q) + }}; + } + + parse!(r#"SELECT a,b FROM (g MATCH p = (a:A) -[e:E]-> (b:B))"#); + } + #[test] + fn parenthesized() { + macro_rules! parse { + ($q:expr) => {{ + parse_test!("parenthesized", $q) + }}; + } + + parse!(r#"SELECT a,b FROM (g MATCH [(a:A)-[e:Edge]->(b:A) WHERE a.owner=b.owner]{2,5})"#); + parse!(r#"SELECT a,b FROM (g MATCH pathVar = (a:A)[()-[e:Edge]->()]{1,3}(b:B))"#); + + // brackets + parse!(r#"SELECT a,b FROM (g MATCH pathVar = (a:A)[-[e:Edge]->]*(b:B))"#); + // parens + parse!(r#"SELECT a,b FROM (g MATCH pathVar = (a:A)(-[e:Edge]->)*(b:B))"#); + } + #[test] + fn filters() { + macro_rules! parse { + ($q:expr) => {{ + parse_test!("filters", $q) + }}; + } + + parse!( + r#"SELECT u as banCandidate FROM g MATCH (p:Post Where p.isFlagged = true) <-[:createdPost]- (u:User WHERE u.isBanned = false AND u.karma < 20) -[:createdComment]->(c:Comment WHERE c.isFlagged = true) WHERE p.title LIKE '%considered harmful%'"# + ); + } + #[test] + fn restrictors() { + macro_rules! parse { + ($q:expr) => {{ + parse_test!("restrictors", $q) + }}; + } + + parse!( + r#"SELECT p FROM g MATCH TRAIL p = (a WHERE a.owner='Dave') -[t:Transfer]-> * (b WHERE b.owner='Aretha')"# + ); + parse!( + r#"SELECT p FROM g MATCH SIMPLE p = (a WHERE a.owner='Dave') -[t:Transfer]-> * (b WHERE b.owner='Aretha')"# + ); + parse!( + r#"SELECT p FROM g MATCH ACYCLIC p = (a WHERE a.owner='Dave') -[t:Transfer]-> * (b WHERE b.owner='Aretha')"# + ); + } + #[test] + fn selectors() { + macro_rules! parse { + ($q:expr) => {{ + parse_test!("selectors", $q) + }}; + } + + parse!( + r#"SELECT p FROM g MATCH ANY SHORTEST p = (a WHERE a.owner='Dave') -[t:Transfer]-> * (b WHERE b.owner='Aretha')"# + ); + parse!( + r#"SELECT p FROM g MATCH ALL SHORTEST p = (a WHERE a.owner='Dave') -[t:Transfer]-> * (b WHERE b.owner='Aretha')"# + ); + parse!( + r#"SELECT p FROM g MATCH ANY p = (a WHERE a.owner='Dave') -[t:Transfer]-> * (b WHERE b.owner='Aretha')"# + ); + parse!( + r#"SELECT p FROM g MATCH ANY 5 p = (a WHERE a.owner='Dave') -[t:Transfer]-> * (b WHERE b.owner='Aretha')"# + ); + parse!( + r#"SELECT p FROM g MATCH SHORTEST 5 p = (a WHERE a.owner='Dave') -[t:Transfer]-> * (b WHERE b.owner='Aretha')"# + ); + parse!( + r#"SELECT p FROM g MATCH SHORTEST 5 GROUP p = (a WHERE a.owner='Dave') -[t:Transfer]-> * (b WHERE b.owner='Aretha')"# + ); + } + #[test] + fn match_and_join() { + macro_rules! parse { + ($q:expr) => {{ + parse_test!("match_and_join", $q) + }}; + } + + parse!( + r#"SELECT a,b,c, t1.x as x, t2.y as y FROM (graph MATCH (a) -> (b), (a) -> (c)), table1 as t1, table2 as t2"# + ); + } + #[test] + fn union() { + macro_rules! parse { + ($q:expr) => {{ + parse_test!("union", $q) + }}; + } + + parse!(r#"(MyGraph MATCH (x)) UNION SELECT * FROM tbl1"#); + parse!(r#"SELECT * FROM tbl1 UNION (MyGraph MATCH (x))"#); + } + #[test] + fn etc() { + macro_rules! parse { + ($q:expr) => {{ + parse_test!("etc", $q) + }}; + } + + parse!("SELECT * FROM g MATCH ALL SHORTEST [ (x)-[e]->*(y) ]"); + parse!("SELECT * FROM g MATCH ALL SHORTEST [ TRAIL (x)-[e]->*(y) ]"); + } +} + #[test] fn pretty_exclude() { pretty_print_test( diff --git a/partiql/tests/snapshots/pretty__graph_edge_1.snap b/partiql/tests/snapshots/pretty__graph_edge_1.snap new file mode 100644 index 00000000..639eca91 --- /dev/null +++ b/partiql/tests/snapshots/pretty__graph_edge_1.snap @@ -0,0 +1,33 @@ +--- +source: partiql/tests/pretty.rs +expression: doc +--- +======================================================================================================================================================================================================== +SELECT a,b FROM g MATCH (a:A) -[e:E]-> (b:B) +======================================================================================================================================================================================================== + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +SELECT a, b FROM g MATCH (a:A) -[e:E]-> (b:B) + +------------------------------------------------------------------------------------------------------------------------ +SELECT a, b FROM g MATCH (a:A) -[e:E]-> (b:B) + +-------------------------------------------------------------------------------- +SELECT a, b FROM g MATCH (a:A) -[e:E]-> (b:B) + +---------------------------------------- +SELECT a, b +FROM g MATCH (a:A) -[e:E]-> (b:B) + +------------------------------ +SELECT a, b +FROM g MATCH (a:A) -[e:E]-> (b:B) + +-------------------- +SELECT a, b +FROM g MATCH (a:A) -[e:E]-> (b:B) + +---------- +SELECT a, + b +FROM g MATCH (a:A) -[e:E]-> (b:B) diff --git a/partiql/tests/snapshots/pretty__graph_edge_10.snap b/partiql/tests/snapshots/pretty__graph_edge_10.snap new file mode 100644 index 00000000..256f8fb9 --- /dev/null +++ b/partiql/tests/snapshots/pretty__graph_edge_10.snap @@ -0,0 +1,32 @@ +--- +source: partiql/tests/pretty.rs +expression: doc +--- +======================================================================================================================================================================================================== +SELECT a,b FROM g MATCH (a:A) <~ (b:B) +======================================================================================================================================================================================================== + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +SELECT a, b FROM g MATCH (a:A) <~ (b:B) + +------------------------------------------------------------------------------------------------------------------------ +SELECT a, b FROM g MATCH (a:A) <~ (b:B) + +-------------------------------------------------------------------------------- +SELECT a, b FROM g MATCH (a:A) <~ (b:B) + +---------------------------------------- +SELECT a, b FROM g MATCH (a:A) <~ (b:B) + +------------------------------ +SELECT a, b +FROM g MATCH (a:A) <~ (b:B) + +-------------------- +SELECT a, b +FROM g MATCH (a:A) <~ (b:B) + +---------- +SELECT a, + b +FROM g MATCH (a:A) <~ (b:B) diff --git a/partiql/tests/snapshots/pretty__graph_edge_11.snap b/partiql/tests/snapshots/pretty__graph_edge_11.snap new file mode 100644 index 00000000..9593d28a --- /dev/null +++ b/partiql/tests/snapshots/pretty__graph_edge_11.snap @@ -0,0 +1,33 @@ +--- +source: partiql/tests/pretty.rs +expression: doc +--- +======================================================================================================================================================================================================== +SELECT a,b FROM g MATCH (a:A) <-[e:E]-> (b:B) +======================================================================================================================================================================================================== + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +SELECT a, b FROM g MATCH (a:A) <-[e:E]-> (b:B) + +------------------------------------------------------------------------------------------------------------------------ +SELECT a, b FROM g MATCH (a:A) <-[e:E]-> (b:B) + +-------------------------------------------------------------------------------- +SELECT a, b FROM g MATCH (a:A) <-[e:E]-> (b:B) + +---------------------------------------- +SELECT a, b +FROM g MATCH (a:A) <-[e:E]-> (b:B) + +------------------------------ +SELECT a, b +FROM g MATCH (a:A) <-[e:E]-> (b:B) + +-------------------- +SELECT a, b +FROM g MATCH (a:A) <-[e:E]-> (b:B) + +---------- +SELECT a, + b +FROM g MATCH (a:A) <-[e:E]-> (b:B) diff --git a/partiql/tests/snapshots/pretty__graph_edge_12.snap b/partiql/tests/snapshots/pretty__graph_edge_12.snap new file mode 100644 index 00000000..cb897a11 --- /dev/null +++ b/partiql/tests/snapshots/pretty__graph_edge_12.snap @@ -0,0 +1,32 @@ +--- +source: partiql/tests/pretty.rs +expression: doc +--- +======================================================================================================================================================================================================== +SELECT a,b FROM g MATCH (a:A) <-> (b:B) +======================================================================================================================================================================================================== + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +SELECT a, b FROM g MATCH (a:A) <-> (b:B) + +------------------------------------------------------------------------------------------------------------------------ +SELECT a, b FROM g MATCH (a:A) <-> (b:B) + +-------------------------------------------------------------------------------- +SELECT a, b FROM g MATCH (a:A) <-> (b:B) + +---------------------------------------- +SELECT a, b FROM g MATCH (a:A) <-> (b:B) + +------------------------------ +SELECT a, b +FROM g MATCH (a:A) <-> (b:B) + +-------------------- +SELECT a, b +FROM g MATCH (a:A) <-> (b:B) + +---------- +SELECT a, + b +FROM g MATCH (a:A) <-> (b:B) diff --git a/partiql/tests/snapshots/pretty__graph_edge_13.snap b/partiql/tests/snapshots/pretty__graph_edge_13.snap new file mode 100644 index 00000000..a4256ceb --- /dev/null +++ b/partiql/tests/snapshots/pretty__graph_edge_13.snap @@ -0,0 +1,33 @@ +--- +source: partiql/tests/pretty.rs +expression: doc +--- +======================================================================================================================================================================================================== +SELECT a,b FROM g MATCH (a:A) -[e:E]- (b:B) +======================================================================================================================================================================================================== + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +SELECT a, b FROM g MATCH (a:A) -[e:E]- (b:B) + +------------------------------------------------------------------------------------------------------------------------ +SELECT a, b FROM g MATCH (a:A) -[e:E]- (b:B) + +-------------------------------------------------------------------------------- +SELECT a, b FROM g MATCH (a:A) -[e:E]- (b:B) + +---------------------------------------- +SELECT a, b +FROM g MATCH (a:A) -[e:E]- (b:B) + +------------------------------ +SELECT a, b +FROM g MATCH (a:A) -[e:E]- (b:B) + +-------------------- +SELECT a, b +FROM g MATCH (a:A) -[e:E]- (b:B) + +---------- +SELECT a, + b +FROM g MATCH (a:A) -[e:E]- (b:B) diff --git a/partiql/tests/snapshots/pretty__graph_edge_14.snap b/partiql/tests/snapshots/pretty__graph_edge_14.snap new file mode 100644 index 00000000..0320ba41 --- /dev/null +++ b/partiql/tests/snapshots/pretty__graph_edge_14.snap @@ -0,0 +1,32 @@ +--- +source: partiql/tests/pretty.rs +expression: doc +--- +======================================================================================================================================================================================================== +SELECT a,b FROM g MATCH (a:A) - (b:B) +======================================================================================================================================================================================================== + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +SELECT a, b FROM g MATCH (a:A) - (b:B) + +------------------------------------------------------------------------------------------------------------------------ +SELECT a, b FROM g MATCH (a:A) - (b:B) + +-------------------------------------------------------------------------------- +SELECT a, b FROM g MATCH (a:A) - (b:B) + +---------------------------------------- +SELECT a, b FROM g MATCH (a:A) - (b:B) + +------------------------------ +SELECT a, b +FROM g MATCH (a:A) - (b:B) + +-------------------- +SELECT a, b +FROM g MATCH (a:A) - (b:B) + +---------- +SELECT a, + b +FROM g MATCH (a:A) - (b:B) diff --git a/partiql/tests/snapshots/pretty__graph_edge_2.snap b/partiql/tests/snapshots/pretty__graph_edge_2.snap new file mode 100644 index 00000000..0583a7cf --- /dev/null +++ b/partiql/tests/snapshots/pretty__graph_edge_2.snap @@ -0,0 +1,32 @@ +--- +source: partiql/tests/pretty.rs +expression: doc +--- +======================================================================================================================================================================================================== +SELECT a,b FROM g MATCH (a:A) -> (b:B) +======================================================================================================================================================================================================== + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +SELECT a, b FROM g MATCH (a:A) -> (b:B) + +------------------------------------------------------------------------------------------------------------------------ +SELECT a, b FROM g MATCH (a:A) -> (b:B) + +-------------------------------------------------------------------------------- +SELECT a, b FROM g MATCH (a:A) -> (b:B) + +---------------------------------------- +SELECT a, b FROM g MATCH (a:A) -> (b:B) + +------------------------------ +SELECT a, b +FROM g MATCH (a:A) -> (b:B) + +-------------------- +SELECT a, b +FROM g MATCH (a:A) -> (b:B) + +---------- +SELECT a, + b +FROM g MATCH (a:A) -> (b:B) diff --git a/partiql/tests/snapshots/pretty__graph_edge_3.snap b/partiql/tests/snapshots/pretty__graph_edge_3.snap new file mode 100644 index 00000000..a834241c --- /dev/null +++ b/partiql/tests/snapshots/pretty__graph_edge_3.snap @@ -0,0 +1,33 @@ +--- +source: partiql/tests/pretty.rs +expression: doc +--- +======================================================================================================================================================================================================== +SELECT a,b FROM g MATCH (a:A) ~[e:E]~ (b:B) +======================================================================================================================================================================================================== + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +SELECT a, b FROM g MATCH (a:A) ~[e:E]~ (b:B) + +------------------------------------------------------------------------------------------------------------------------ +SELECT a, b FROM g MATCH (a:A) ~[e:E]~ (b:B) + +-------------------------------------------------------------------------------- +SELECT a, b FROM g MATCH (a:A) ~[e:E]~ (b:B) + +---------------------------------------- +SELECT a, b +FROM g MATCH (a:A) ~[e:E]~ (b:B) + +------------------------------ +SELECT a, b +FROM g MATCH (a:A) ~[e:E]~ (b:B) + +-------------------- +SELECT a, b +FROM g MATCH (a:A) ~[e:E]~ (b:B) + +---------- +SELECT a, + b +FROM g MATCH (a:A) ~[e:E]~ (b:B) diff --git a/partiql/tests/snapshots/pretty__graph_edge_4.snap b/partiql/tests/snapshots/pretty__graph_edge_4.snap new file mode 100644 index 00000000..8633bf06 --- /dev/null +++ b/partiql/tests/snapshots/pretty__graph_edge_4.snap @@ -0,0 +1,32 @@ +--- +source: partiql/tests/pretty.rs +expression: doc +--- +======================================================================================================================================================================================================== +SELECT a,b FROM g MATCH (a:A) ~ (b:B) +======================================================================================================================================================================================================== + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +SELECT a, b FROM g MATCH (a:A) ~ (b:B) + +------------------------------------------------------------------------------------------------------------------------ +SELECT a, b FROM g MATCH (a:A) ~ (b:B) + +-------------------------------------------------------------------------------- +SELECT a, b FROM g MATCH (a:A) ~ (b:B) + +---------------------------------------- +SELECT a, b FROM g MATCH (a:A) ~ (b:B) + +------------------------------ +SELECT a, b +FROM g MATCH (a:A) ~ (b:B) + +-------------------- +SELECT a, b +FROM g MATCH (a:A) ~ (b:B) + +---------- +SELECT a, + b +FROM g MATCH (a:A) ~ (b:B) diff --git a/partiql/tests/snapshots/pretty__graph_edge_5.snap b/partiql/tests/snapshots/pretty__graph_edge_5.snap new file mode 100644 index 00000000..a22ebbaf --- /dev/null +++ b/partiql/tests/snapshots/pretty__graph_edge_5.snap @@ -0,0 +1,33 @@ +--- +source: partiql/tests/pretty.rs +expression: doc +--- +======================================================================================================================================================================================================== +SELECT a,b FROM g MATCH (a:A) <-[e:E]- (b:B) +======================================================================================================================================================================================================== + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +SELECT a, b FROM g MATCH (a:A) <-[e:E]- (b:B) + +------------------------------------------------------------------------------------------------------------------------ +SELECT a, b FROM g MATCH (a:A) <-[e:E]- (b:B) + +-------------------------------------------------------------------------------- +SELECT a, b FROM g MATCH (a:A) <-[e:E]- (b:B) + +---------------------------------------- +SELECT a, b +FROM g MATCH (a:A) <-[e:E]- (b:B) + +------------------------------ +SELECT a, b +FROM g MATCH (a:A) <-[e:E]- (b:B) + +-------------------- +SELECT a, b +FROM g MATCH (a:A) <-[e:E]- (b:B) + +---------- +SELECT a, + b +FROM g MATCH (a:A) <-[e:E]- (b:B) diff --git a/partiql/tests/snapshots/pretty__graph_edge_6.snap b/partiql/tests/snapshots/pretty__graph_edge_6.snap new file mode 100644 index 00000000..0d745ef6 --- /dev/null +++ b/partiql/tests/snapshots/pretty__graph_edge_6.snap @@ -0,0 +1,32 @@ +--- +source: partiql/tests/pretty.rs +expression: doc +--- +======================================================================================================================================================================================================== +SELECT a,b FROM g MATCH (a:A) <- (b:B) +======================================================================================================================================================================================================== + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +SELECT a, b FROM g MATCH (a:A) <- (b:B) + +------------------------------------------------------------------------------------------------------------------------ +SELECT a, b FROM g MATCH (a:A) <- (b:B) + +-------------------------------------------------------------------------------- +SELECT a, b FROM g MATCH (a:A) <- (b:B) + +---------------------------------------- +SELECT a, b FROM g MATCH (a:A) <- (b:B) + +------------------------------ +SELECT a, b +FROM g MATCH (a:A) <- (b:B) + +-------------------- +SELECT a, b +FROM g MATCH (a:A) <- (b:B) + +---------- +SELECT a, + b +FROM g MATCH (a:A) <- (b:B) diff --git a/partiql/tests/snapshots/pretty__graph_edge_7.snap b/partiql/tests/snapshots/pretty__graph_edge_7.snap new file mode 100644 index 00000000..6c8fa391 --- /dev/null +++ b/partiql/tests/snapshots/pretty__graph_edge_7.snap @@ -0,0 +1,33 @@ +--- +source: partiql/tests/pretty.rs +expression: doc +--- +======================================================================================================================================================================================================== +SELECT a,b FROM g MATCH (a:A) ~[e:E]~> (b:B) +======================================================================================================================================================================================================== + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +SELECT a, b FROM g MATCH (a:A) ~[e:E]~> (b:B) + +------------------------------------------------------------------------------------------------------------------------ +SELECT a, b FROM g MATCH (a:A) ~[e:E]~> (b:B) + +-------------------------------------------------------------------------------- +SELECT a, b FROM g MATCH (a:A) ~[e:E]~> (b:B) + +---------------------------------------- +SELECT a, b +FROM g MATCH (a:A) ~[e:E]~> (b:B) + +------------------------------ +SELECT a, b +FROM g MATCH (a:A) ~[e:E]~> (b:B) + +-------------------- +SELECT a, b +FROM g MATCH (a:A) ~[e:E]~> (b:B) + +---------- +SELECT a, + b +FROM g MATCH (a:A) ~[e:E]~> (b:B) diff --git a/partiql/tests/snapshots/pretty__graph_edge_8.snap b/partiql/tests/snapshots/pretty__graph_edge_8.snap new file mode 100644 index 00000000..e078818c --- /dev/null +++ b/partiql/tests/snapshots/pretty__graph_edge_8.snap @@ -0,0 +1,32 @@ +--- +source: partiql/tests/pretty.rs +expression: doc +--- +======================================================================================================================================================================================================== +SELECT a,b FROM g MATCH (a:A) ~> (b:B) +======================================================================================================================================================================================================== + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +SELECT a, b FROM g MATCH (a:A) ~> (b:B) + +------------------------------------------------------------------------------------------------------------------------ +SELECT a, b FROM g MATCH (a:A) ~> (b:B) + +-------------------------------------------------------------------------------- +SELECT a, b FROM g MATCH (a:A) ~> (b:B) + +---------------------------------------- +SELECT a, b FROM g MATCH (a:A) ~> (b:B) + +------------------------------ +SELECT a, b +FROM g MATCH (a:A) ~> (b:B) + +-------------------- +SELECT a, b +FROM g MATCH (a:A) ~> (b:B) + +---------- +SELECT a, + b +FROM g MATCH (a:A) ~> (b:B) diff --git a/partiql/tests/snapshots/pretty__graph_edge_9.snap b/partiql/tests/snapshots/pretty__graph_edge_9.snap new file mode 100644 index 00000000..5daabb45 --- /dev/null +++ b/partiql/tests/snapshots/pretty__graph_edge_9.snap @@ -0,0 +1,33 @@ +--- +source: partiql/tests/pretty.rs +expression: doc +--- +======================================================================================================================================================================================================== +SELECT a,b FROM g MATCH (a:A) <~[e:E]~ (b:B) +======================================================================================================================================================================================================== + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +SELECT a, b FROM g MATCH (a:A) <~[e:E]~ (b:B) + +------------------------------------------------------------------------------------------------------------------------ +SELECT a, b FROM g MATCH (a:A) <~[e:E]~ (b:B) + +-------------------------------------------------------------------------------- +SELECT a, b FROM g MATCH (a:A) <~[e:E]~ (b:B) + +---------------------------------------- +SELECT a, b +FROM g MATCH (a:A) <~[e:E]~ (b:B) + +------------------------------ +SELECT a, b +FROM g MATCH (a:A) <~[e:E]~ (b:B) + +-------------------- +SELECT a, b +FROM g MATCH (a:A) <~[e:E]~ (b:B) + +---------- +SELECT a, + b +FROM g MATCH (a:A) <~[e:E]~ (b:B) diff --git a/partiql/tests/snapshots/pretty__graph_etc_1.snap b/partiql/tests/snapshots/pretty__graph_etc_1.snap new file mode 100644 index 00000000..9decaa51 --- /dev/null +++ b/partiql/tests/snapshots/pretty__graph_etc_1.snap @@ -0,0 +1,35 @@ +--- +source: partiql/tests/pretty.rs +expression: doc +--- +======================================================================================================================================================================================================== +SELECT * FROM g MATCH ALL SHORTEST [ (x)-[e]->*(y) ] +======================================================================================================================================================================================================== + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +SELECT * FROM g MATCH ALL SHORTEST (x) -[e]->* (y) + +------------------------------------------------------------------------------------------------------------------------ +SELECT * FROM g MATCH ALL SHORTEST (x) -[e]->* (y) + +-------------------------------------------------------------------------------- +SELECT * FROM g MATCH ALL SHORTEST (x) -[e]->* (y) + +---------------------------------------- +SELECT * FROM g MATCH ALL SHORTEST + (x) -[e]->* (y) + +------------------------------ +SELECT * +FROM g MATCH ALL SHORTEST + (x) -[e]->* (y) + +-------------------- +SELECT * +FROM g MATCH ALL SHORTEST + (x) -[e]->* (y) + +---------- +SELECT * +FROM g MATCH ALL SHORTEST + (x) -[e]->* (y) diff --git a/partiql/tests/snapshots/pretty__graph_etc_2.snap b/partiql/tests/snapshots/pretty__graph_etc_2.snap new file mode 100644 index 00000000..b6bf459b --- /dev/null +++ b/partiql/tests/snapshots/pretty__graph_etc_2.snap @@ -0,0 +1,35 @@ +--- +source: partiql/tests/pretty.rs +expression: doc +--- +======================================================================================================================================================================================================== +SELECT * FROM g MATCH ALL SHORTEST [ TRAIL (x)-[e]->*(y) ] +======================================================================================================================================================================================================== + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +SELECT * FROM g MATCH ALL SHORTEST [TRAIL (x) -[e]->* (y)] + +------------------------------------------------------------------------------------------------------------------------ +SELECT * FROM g MATCH ALL SHORTEST [TRAIL (x) -[e]->* (y)] + +-------------------------------------------------------------------------------- +SELECT * FROM g MATCH ALL SHORTEST [TRAIL (x) -[e]->* (y)] + +---------------------------------------- +SELECT * FROM g MATCH ALL SHORTEST + [TRAIL (x) -[e]->* (y)] + +------------------------------ +SELECT * +FROM g MATCH ALL SHORTEST + [TRAIL (x) -[e]->* (y)] + +-------------------- +SELECT * +FROM g MATCH ALL SHORTEST + [TRAIL (x) -[e]->* (y)] + +---------- +SELECT * +FROM g MATCH ALL SHORTEST + [TRAIL (x) -[e]->* (y)] diff --git a/partiql/tests/snapshots/pretty__graph_filters_1.snap b/partiql/tests/snapshots/pretty__graph_filters_1.snap new file mode 100644 index 00000000..1728cc9b --- /dev/null +++ b/partiql/tests/snapshots/pretty__graph_filters_1.snap @@ -0,0 +1,53 @@ +--- +source: partiql/tests/pretty.rs +expression: doc +--- +======================================================================================================================================================================================================== +SELECT u as banCandidate FROM g MATCH (p:Post Where p.isFlagged = true) <-[:createdPost]- (u:User WHERE u.isBanned = false AND u.karma < 20) -[:createdComment]->(c:Comment WHERE c.isFlagged = true) WHERE p.title LIKE '%considered harmful%' +======================================================================================================================================================================================================== + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +SELECT u AS banCandidate FROM g MATCH (p:Post WHERE (p.isFlagged = true)) <-[:createdPost]- (u:User WHERE ((u.isBanned = false) AND + (u.karma < 20))) -[:createdComment]-> (c:Comment WHERE (c.isFlagged = true)) +WHERE p.title LIKE '%considered harmful%' + +------------------------------------------------------------------------------------------------------------------------ +SELECT u AS banCandidate +FROM g MATCH (p:Post WHERE (p.isFlagged = true)) <-[:createdPost]- (u:User WHERE ((u.isBanned = false) AND + (u.karma < 20))) -[:createdComment]-> (c:Comment WHERE (c.isFlagged = true)) +WHERE p.title LIKE '%considered harmful%' + +-------------------------------------------------------------------------------- +SELECT u AS banCandidate +FROM g MATCH (p:Post WHERE (p.isFlagged = true)) <-[:createdPost]- (u:User WHERE ((u.isBanned = false) + AND + (u.karma < 20))) -[:createdComment]-> (c:Comment WHERE (c.isFlagged = true)) +WHERE p.title LIKE '%considered harmful%' + +---------------------------------------- +SELECT u AS banCandidate +FROM g MATCH (p:Post WHERE (p.isFlagged = true)) <-[:createdPost]- (u:User WHERE ((u.isBanned = false) + AND + (u.karma < 20))) -[:createdComment]-> (c:Comment WHERE (c.isFlagged = true)) +WHERE p.title LIKE '%considered harmful%' + +------------------------------ +SELECT u AS banCandidate +FROM g MATCH (p:Post WHERE (p.isFlagged = true)) <-[:createdPost]- (u:User WHERE ((u.isBanned = false) + AND + (u.karma < 20))) -[:createdComment]-> (c:Comment WHERE (c.isFlagged = true)) +WHERE p.title LIKE '%considered harmful%' + +-------------------- +SELECT u AS banCandidate +FROM g MATCH (p:Post WHERE (p.isFlagged = true)) <-[:createdPost]- (u:User WHERE ((u.isBanned = false) + AND + (u.karma < 20))) -[:createdComment]-> (c:Comment WHERE (c.isFlagged = true)) +WHERE p.title LIKE '%considered harmful%' + +---------- +SELECT u AS banCandidate +FROM g MATCH (p:Post WHERE (p.isFlagged = true)) <-[:createdPost]- (u:User WHERE ((u.isBanned = false) + AND + (u.karma < 20))) -[:createdComment]-> (c:Comment WHERE (c.isFlagged = true)) +WHERE p.title LIKE '%considered harmful%' diff --git a/partiql/tests/snapshots/pretty__graph_match_and_join_1.snap b/partiql/tests/snapshots/pretty__graph_match_and_join_1.snap new file mode 100644 index 00000000..6941298e --- /dev/null +++ b/partiql/tests/snapshots/pretty__graph_match_and_join_1.snap @@ -0,0 +1,49 @@ +--- +source: partiql/tests/pretty.rs +expression: doc +--- +======================================================================================================================================================================================================== +SELECT a,b,c, t1.x as x, t2.y as y FROM (graph MATCH (a) -> (b), (a) -> (c)), table1 as t1, table2 as t2 +======================================================================================================================================================================================================== + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +SELECT a, b, c, t1.x AS x, t2.y AS y FROM (graph MATCH (a) -> (b), (a) -> (c)), table1 AS t1, table2 AS t2 + +------------------------------------------------------------------------------------------------------------------------ +SELECT a, b, c, t1.x AS x, t2.y AS y FROM (graph MATCH (a) -> (b), (a) -> (c)), table1 AS t1, table2 AS t2 + +-------------------------------------------------------------------------------- +SELECT a, b, c, t1.x AS x, t2.y AS y FROM (graph MATCH (a) -> (b), (a) -> (c)), + table1 AS t1, table2 AS t2 + +---------------------------------------- +SELECT a, b, c, t1.x AS x, t2.y AS y +FROM (graph MATCH (a) -> (b), + (a) -> (c)), table1 AS t1, + table2 AS t2 + +------------------------------ +SELECT a, b, c, t1.x AS x, + t2.y AS y +FROM (graph MATCH (a) -> (b), + (a) -> (c)), table1 AS t1, + table2 AS t2 + +-------------------- +SELECT a, b, c, + t1.x AS x, + t2.y AS y +FROM (graph MATCH (a) -> (b), + (a) -> (c)), + table1 AS t1, + table2 AS t2 + +---------- +SELECT a, + b, c, + t1.x AS x, + t2.y AS y +FROM (graph MATCH (a) -> (b), + (a) -> (c)), + table1 AS t1, + table2 AS t2 diff --git a/partiql/tests/snapshots/pretty__graph_parenthesized_1.snap b/partiql/tests/snapshots/pretty__graph_parenthesized_1.snap new file mode 100644 index 00000000..5511722c --- /dev/null +++ b/partiql/tests/snapshots/pretty__graph_parenthesized_1.snap @@ -0,0 +1,34 @@ +--- +source: partiql/tests/pretty.rs +expression: doc +--- +======================================================================================================================================================================================================== +SELECT a,b FROM (g MATCH [(a:A)-[e:Edge]->(b:A) WHERE a.owner=b.owner]{2,5}) +======================================================================================================================================================================================================== + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +SELECT a, b FROM g MATCH [(a:A) -[e:Edge]-> (b:A) WHERE (a.owner = b.owner)]{2,5} + +------------------------------------------------------------------------------------------------------------------------ +SELECT a, b FROM g MATCH [(a:A) -[e:Edge]-> (b:A) WHERE (a.owner = b.owner)]{2,5} + +-------------------------------------------------------------------------------- +SELECT a, b +FROM g MATCH [(a:A) -[e:Edge]-> (b:A) WHERE (a.owner = b.owner)]{2,5} + +---------------------------------------- +SELECT a, b +FROM g MATCH [(a:A) -[e:Edge]-> (b:A) WHERE (a.owner = b.owner)]{2,5} + +------------------------------ +SELECT a, b +FROM g MATCH [(a:A) -[e:Edge]-> (b:A) WHERE (a.owner = b.owner)]{2,5} + +-------------------- +SELECT a, b +FROM g MATCH [(a:A) -[e:Edge]-> (b:A) WHERE (a.owner = b.owner)]{2,5} + +---------- +SELECT a, + b +FROM g MATCH [(a:A) -[e:Edge]-> (b:A) WHERE (a.owner = b.owner)]{2,5} diff --git a/partiql/tests/snapshots/pretty__graph_parenthesized_2.snap b/partiql/tests/snapshots/pretty__graph_parenthesized_2.snap new file mode 100644 index 00000000..6b78d858 --- /dev/null +++ b/partiql/tests/snapshots/pretty__graph_parenthesized_2.snap @@ -0,0 +1,33 @@ +--- +source: partiql/tests/pretty.rs +expression: doc +--- +======================================================================================================================================================================================================== +SELECT a,b FROM (g MATCH pathVar = (a:A)[()-[e:Edge]->()]{1,3}(b:B)) +======================================================================================================================================================================================================== + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +SELECT a, b FROM g MATCH pathVar = (a:A) [() -[e:Edge]-> ()]{1,3} (b:B) + +------------------------------------------------------------------------------------------------------------------------ +SELECT a, b FROM g MATCH pathVar = (a:A) [() -[e:Edge]-> ()]{1,3} (b:B) + +-------------------------------------------------------------------------------- +SELECT a, b FROM g MATCH pathVar = (a:A) [() -[e:Edge]-> ()]{1,3} (b:B) + +---------------------------------------- +SELECT a, b +FROM g MATCH pathVar = (a:A) [() -[e:Edge]-> ()]{1,3} (b:B) + +------------------------------ +SELECT a, b +FROM g MATCH pathVar = (a:A) [() -[e:Edge]-> ()]{1,3} (b:B) + +-------------------- +SELECT a, b +FROM g MATCH pathVar = (a:A) [() -[e:Edge]-> ()]{1,3} (b:B) + +---------- +SELECT a, + b +FROM g MATCH pathVar = (a:A) [() -[e:Edge]-> ()]{1,3} (b:B) diff --git a/partiql/tests/snapshots/pretty__graph_parenthesized_3.snap b/partiql/tests/snapshots/pretty__graph_parenthesized_3.snap new file mode 100644 index 00000000..2b735026 --- /dev/null +++ b/partiql/tests/snapshots/pretty__graph_parenthesized_3.snap @@ -0,0 +1,33 @@ +--- +source: partiql/tests/pretty.rs +expression: doc +--- +======================================================================================================================================================================================================== +SELECT a,b FROM (g MATCH pathVar = (a:A)[-[e:Edge]->]*(b:B)) +======================================================================================================================================================================================================== + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +SELECT a, b FROM g MATCH pathVar = (a:A) [-[e:Edge]->]* (b:B) + +------------------------------------------------------------------------------------------------------------------------ +SELECT a, b FROM g MATCH pathVar = (a:A) [-[e:Edge]->]* (b:B) + +-------------------------------------------------------------------------------- +SELECT a, b FROM g MATCH pathVar = (a:A) [-[e:Edge]->]* (b:B) + +---------------------------------------- +SELECT a, b +FROM g MATCH pathVar = (a:A) [-[e:Edge]->]* (b:B) + +------------------------------ +SELECT a, b +FROM g MATCH pathVar = (a:A) [-[e:Edge]->]* (b:B) + +-------------------- +SELECT a, b +FROM g MATCH pathVar = (a:A) [-[e:Edge]->]* (b:B) + +---------- +SELECT a, + b +FROM g MATCH pathVar = (a:A) [-[e:Edge]->]* (b:B) diff --git a/partiql/tests/snapshots/pretty__graph_parenthesized_4.snap b/partiql/tests/snapshots/pretty__graph_parenthesized_4.snap new file mode 100644 index 00000000..ca5d1a08 --- /dev/null +++ b/partiql/tests/snapshots/pretty__graph_parenthesized_4.snap @@ -0,0 +1,33 @@ +--- +source: partiql/tests/pretty.rs +expression: doc +--- +======================================================================================================================================================================================================== +SELECT a,b FROM (g MATCH pathVar = (a:A)(-[e:Edge]->)*(b:B)) +======================================================================================================================================================================================================== + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +SELECT a, b FROM g MATCH pathVar = (a:A) [-[e:Edge]->]* (b:B) + +------------------------------------------------------------------------------------------------------------------------ +SELECT a, b FROM g MATCH pathVar = (a:A) [-[e:Edge]->]* (b:B) + +-------------------------------------------------------------------------------- +SELECT a, b FROM g MATCH pathVar = (a:A) [-[e:Edge]->]* (b:B) + +---------------------------------------- +SELECT a, b +FROM g MATCH pathVar = (a:A) [-[e:Edge]->]* (b:B) + +------------------------------ +SELECT a, b +FROM g MATCH pathVar = (a:A) [-[e:Edge]->]* (b:B) + +-------------------- +SELECT a, b +FROM g MATCH pathVar = (a:A) [-[e:Edge]->]* (b:B) + +---------- +SELECT a, + b +FROM g MATCH pathVar = (a:A) [-[e:Edge]->]* (b:B) diff --git a/partiql/tests/snapshots/pretty__graph_path_var_1.snap b/partiql/tests/snapshots/pretty__graph_path_var_1.snap new file mode 100644 index 00000000..d87bdb1d --- /dev/null +++ b/partiql/tests/snapshots/pretty__graph_path_var_1.snap @@ -0,0 +1,33 @@ +--- +source: partiql/tests/pretty.rs +expression: doc +--- +======================================================================================================================================================================================================== +SELECT a,b FROM (g MATCH p = (a:A) -[e:E]-> (b:B)) +======================================================================================================================================================================================================== + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +SELECT a, b FROM g MATCH p = (a:A) -[e:E]-> (b:B) + +------------------------------------------------------------------------------------------------------------------------ +SELECT a, b FROM g MATCH p = (a:A) -[e:E]-> (b:B) + +-------------------------------------------------------------------------------- +SELECT a, b FROM g MATCH p = (a:A) -[e:E]-> (b:B) + +---------------------------------------- +SELECT a, b +FROM g MATCH p = (a:A) -[e:E]-> (b:B) + +------------------------------ +SELECT a, b +FROM g MATCH p = (a:A) -[e:E]-> (b:B) + +-------------------- +SELECT a, b +FROM g MATCH p = (a:A) -[e:E]-> (b:B) + +---------- +SELECT a, + b +FROM g MATCH p = (a:A) -[e:E]-> (b:B) diff --git a/partiql/tests/snapshots/pretty__graph_patterns_1.snap b/partiql/tests/snapshots/pretty__graph_patterns_1.snap new file mode 100644 index 00000000..ad81d1f6 --- /dev/null +++ b/partiql/tests/snapshots/pretty__graph_patterns_1.snap @@ -0,0 +1,42 @@ +--- +source: partiql/tests/pretty.rs +expression: doc +--- +======================================================================================================================================================================================================== +SELECT the_a.name AS src, the_b.name AS dest FROM my_graph MATCH (the_a:a) -[the_y:y]-> (the_b:b) WHERE the_y.score > 10 +======================================================================================================================================================================================================== + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +SELECT the_a.name AS src, the_b.name AS dest FROM my_graph MATCH (the_a:a) -[the_y:y]-> (the_b:b) WHERE (the_y.score > 10) + +------------------------------------------------------------------------------------------------------------------------ +SELECT the_a.name AS src, the_b.name AS dest FROM my_graph MATCH (the_a:a) -[the_y:y]-> (the_b:b) +WHERE (the_y.score > 10) + +-------------------------------------------------------------------------------- +SELECT the_a.name AS src, the_b.name AS dest +FROM my_graph MATCH (the_a:a) -[the_y:y]-> (the_b:b) WHERE (the_y.score > 10) + +---------------------------------------- +SELECT the_a.name AS src, + the_b.name AS dest +FROM my_graph MATCH (the_a:a) -[the_y:y]-> (the_b:b) +WHERE (the_y.score > 10) + +------------------------------ +SELECT the_a.name AS src, + the_b.name AS dest +FROM my_graph MATCH (the_a:a) -[the_y:y]-> (the_b:b) +WHERE (the_y.score > 10) + +-------------------- +SELECT the_a.name AS src, + the_b.name AS dest +FROM my_graph MATCH (the_a:a) -[the_y:y]-> (the_b:b) +WHERE (the_y.score > 10) + +---------- +SELECT the_a.name AS src, + the_b.name AS dest +FROM my_graph MATCH (the_a:a) -[the_y:y]-> (the_b:b) +WHERE (the_y.score > 10) diff --git a/partiql/tests/snapshots/pretty__graph_patterns_2.snap b/partiql/tests/snapshots/pretty__graph_patterns_2.snap new file mode 100644 index 00000000..cfd693da --- /dev/null +++ b/partiql/tests/snapshots/pretty__graph_patterns_2.snap @@ -0,0 +1,33 @@ +--- +source: partiql/tests/pretty.rs +expression: doc +--- +======================================================================================================================================================================================================== +SELECT a,b FROM g MATCH (a)-[:has]->()-[:contains]->(b) +======================================================================================================================================================================================================== + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +SELECT a, b FROM g MATCH (a) -[:has]-> () -[:contains]-> (b) + +------------------------------------------------------------------------------------------------------------------------ +SELECT a, b FROM g MATCH (a) -[:has]-> () -[:contains]-> (b) + +-------------------------------------------------------------------------------- +SELECT a, b FROM g MATCH (a) -[:has]-> () -[:contains]-> (b) + +---------------------------------------- +SELECT a, b +FROM g MATCH (a) -[:has]-> () -[:contains]-> (b) + +------------------------------ +SELECT a, b +FROM g MATCH (a) -[:has]-> () -[:contains]-> (b) + +-------------------- +SELECT a, b +FROM g MATCH (a) -[:has]-> () -[:contains]-> (b) + +---------- +SELECT a, + b +FROM g MATCH (a) -[:has]-> () -[:contains]-> (b) diff --git a/partiql/tests/snapshots/pretty__graph_patterns_3.snap b/partiql/tests/snapshots/pretty__graph_patterns_3.snap new file mode 100644 index 00000000..1f6fffa4 --- /dev/null +++ b/partiql/tests/snapshots/pretty__graph_patterns_3.snap @@ -0,0 +1,37 @@ +--- +source: partiql/tests/pretty.rs +expression: doc +--- +======================================================================================================================================================================================================== +SELECT a,b FROM (g MATCH (a) -[:has]-> (x), (x)-[:contains]->(b)) +======================================================================================================================================================================================================== + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +SELECT a, b FROM (g MATCH (a) -[:has]-> (x), (x) -[:contains]-> (b)) + +------------------------------------------------------------------------------------------------------------------------ +SELECT a, b FROM (g MATCH (a) -[:has]-> (x), (x) -[:contains]-> (b)) + +-------------------------------------------------------------------------------- +SELECT a, b FROM (g MATCH (a) -[:has]-> (x), (x) -[:contains]-> (b)) + +---------------------------------------- +SELECT a, b +FROM (g MATCH (a) -[:has]-> (x), + (x) -[:contains]-> (b)) + +------------------------------ +SELECT a, b +FROM (g MATCH (a) -[:has]-> (x), + (x) -[:contains]-> (b)) + +-------------------- +SELECT a, b +FROM (g MATCH (a) -[:has]-> (x), + (x) -[:contains]-> (b)) + +---------- +SELECT a, + b +FROM (g MATCH (a) -[:has]-> (x), + (x) -[:contains]-> (b)) diff --git a/partiql/tests/snapshots/pretty__graph_quantifiers_1.snap b/partiql/tests/snapshots/pretty__graph_quantifiers_1.snap new file mode 100644 index 00000000..6847fb0f --- /dev/null +++ b/partiql/tests/snapshots/pretty__graph_quantifiers_1.snap @@ -0,0 +1,33 @@ +--- +source: partiql/tests/pretty.rs +expression: doc +--- +======================================================================================================================================================================================================== +SELECT a,b FROM g MATCH (a:A)-[:edge]->*(b:B) +======================================================================================================================================================================================================== + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +SELECT a, b FROM g MATCH (a:A) -[:edge]->* (b:B) + +------------------------------------------------------------------------------------------------------------------------ +SELECT a, b FROM g MATCH (a:A) -[:edge]->* (b:B) + +-------------------------------------------------------------------------------- +SELECT a, b FROM g MATCH (a:A) -[:edge]->* (b:B) + +---------------------------------------- +SELECT a, b +FROM g MATCH (a:A) -[:edge]->* (b:B) + +------------------------------ +SELECT a, b +FROM g MATCH (a:A) -[:edge]->* (b:B) + +-------------------- +SELECT a, b +FROM g MATCH (a:A) -[:edge]->* (b:B) + +---------- +SELECT a, + b +FROM g MATCH (a:A) -[:edge]->* (b:B) diff --git a/partiql/tests/snapshots/pretty__graph_quantifiers_2.snap b/partiql/tests/snapshots/pretty__graph_quantifiers_2.snap new file mode 100644 index 00000000..21c67d7f --- /dev/null +++ b/partiql/tests/snapshots/pretty__graph_quantifiers_2.snap @@ -0,0 +1,33 @@ +--- +source: partiql/tests/pretty.rs +expression: doc +--- +======================================================================================================================================================================================================== +SELECT a,b FROM g MATCH (a:A)<-[:edge]-+(b:B) +======================================================================================================================================================================================================== + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +SELECT a, b FROM g MATCH (a:A) <-[:edge]-+ (b:B) + +------------------------------------------------------------------------------------------------------------------------ +SELECT a, b FROM g MATCH (a:A) <-[:edge]-+ (b:B) + +-------------------------------------------------------------------------------- +SELECT a, b FROM g MATCH (a:A) <-[:edge]-+ (b:B) + +---------------------------------------- +SELECT a, b +FROM g MATCH (a:A) <-[:edge]-+ (b:B) + +------------------------------ +SELECT a, b +FROM g MATCH (a:A) <-[:edge]-+ (b:B) + +-------------------- +SELECT a, b +FROM g MATCH (a:A) <-[:edge]-+ (b:B) + +---------- +SELECT a, + b +FROM g MATCH (a:A) <-[:edge]-+ (b:B) diff --git a/partiql/tests/snapshots/pretty__graph_quantifiers_3.snap b/partiql/tests/snapshots/pretty__graph_quantifiers_3.snap new file mode 100644 index 00000000..79c1a025 --- /dev/null +++ b/partiql/tests/snapshots/pretty__graph_quantifiers_3.snap @@ -0,0 +1,33 @@ +--- +source: partiql/tests/pretty.rs +expression: doc +--- +======================================================================================================================================================================================================== +SELECT a,b FROM g MATCH (a:A)~[:edge]~{5,}(b:B) +======================================================================================================================================================================================================== + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +SELECT a, b FROM g MATCH (a:A) ~[:edge]~{5,} (b:B) + +------------------------------------------------------------------------------------------------------------------------ +SELECT a, b FROM g MATCH (a:A) ~[:edge]~{5,} (b:B) + +-------------------------------------------------------------------------------- +SELECT a, b FROM g MATCH (a:A) ~[:edge]~{5,} (b:B) + +---------------------------------------- +SELECT a, b +FROM g MATCH (a:A) ~[:edge]~{5,} (b:B) + +------------------------------ +SELECT a, b +FROM g MATCH (a:A) ~[:edge]~{5,} (b:B) + +-------------------- +SELECT a, b +FROM g MATCH (a:A) ~[:edge]~{5,} (b:B) + +---------- +SELECT a, + b +FROM g MATCH (a:A) ~[:edge]~{5,} (b:B) diff --git a/partiql/tests/snapshots/pretty__graph_quantifiers_4.snap b/partiql/tests/snapshots/pretty__graph_quantifiers_4.snap new file mode 100644 index 00000000..47e8802c --- /dev/null +++ b/partiql/tests/snapshots/pretty__graph_quantifiers_4.snap @@ -0,0 +1,33 @@ +--- +source: partiql/tests/pretty.rs +expression: doc +--- +======================================================================================================================================================================================================== +SELECT a,b FROM g MATCH (a:A)-[e:edge]-{2,6}(b:B) +======================================================================================================================================================================================================== + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +SELECT a, b FROM g MATCH (a:A) -[e:edge]-{2,6} (b:B) + +------------------------------------------------------------------------------------------------------------------------ +SELECT a, b FROM g MATCH (a:A) -[e:edge]-{2,6} (b:B) + +-------------------------------------------------------------------------------- +SELECT a, b FROM g MATCH (a:A) -[e:edge]-{2,6} (b:B) + +---------------------------------------- +SELECT a, b +FROM g MATCH (a:A) -[e:edge]-{2,6} (b:B) + +------------------------------ +SELECT a, b +FROM g MATCH (a:A) -[e:edge]-{2,6} (b:B) + +-------------------- +SELECT a, b +FROM g MATCH (a:A) -[e:edge]-{2,6} (b:B) + +---------- +SELECT a, + b +FROM g MATCH (a:A) -[e:edge]-{2,6} (b:B) diff --git a/partiql/tests/snapshots/pretty__graph_quantifiers_5.snap b/partiql/tests/snapshots/pretty__graph_quantifiers_5.snap new file mode 100644 index 00000000..13dbbc8a --- /dev/null +++ b/partiql/tests/snapshots/pretty__graph_quantifiers_5.snap @@ -0,0 +1,32 @@ +--- +source: partiql/tests/pretty.rs +expression: doc +--- +======================================================================================================================================================================================================== +SELECT a,b FROM g MATCH (a:A)->*(b:B) +======================================================================================================================================================================================================== + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +SELECT a, b FROM g MATCH (a:A) ->* (b:B) + +------------------------------------------------------------------------------------------------------------------------ +SELECT a, b FROM g MATCH (a:A) ->* (b:B) + +-------------------------------------------------------------------------------- +SELECT a, b FROM g MATCH (a:A) ->* (b:B) + +---------------------------------------- +SELECT a, b FROM g MATCH (a:A) ->* (b:B) + +------------------------------ +SELECT a, b +FROM g MATCH (a:A) ->* (b:B) + +-------------------- +SELECT a, b +FROM g MATCH (a:A) ->* (b:B) + +---------- +SELECT a, + b +FROM g MATCH (a:A) ->* (b:B) diff --git a/partiql/tests/snapshots/pretty__graph_quantifiers_6.snap b/partiql/tests/snapshots/pretty__graph_quantifiers_6.snap new file mode 100644 index 00000000..50da64d9 --- /dev/null +++ b/partiql/tests/snapshots/pretty__graph_quantifiers_6.snap @@ -0,0 +1,32 @@ +--- +source: partiql/tests/pretty.rs +expression: doc +--- +======================================================================================================================================================================================================== +SELECT a,b FROM g MATCH (a:A)<-+(b:B) +======================================================================================================================================================================================================== + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +SELECT a, b FROM g MATCH (a:A) <-+ (b:B) + +------------------------------------------------------------------------------------------------------------------------ +SELECT a, b FROM g MATCH (a:A) <-+ (b:B) + +-------------------------------------------------------------------------------- +SELECT a, b FROM g MATCH (a:A) <-+ (b:B) + +---------------------------------------- +SELECT a, b FROM g MATCH (a:A) <-+ (b:B) + +------------------------------ +SELECT a, b +FROM g MATCH (a:A) <-+ (b:B) + +-------------------- +SELECT a, b +FROM g MATCH (a:A) <-+ (b:B) + +---------- +SELECT a, + b +FROM g MATCH (a:A) <-+ (b:B) diff --git a/partiql/tests/snapshots/pretty__graph_quantifiers_7.snap b/partiql/tests/snapshots/pretty__graph_quantifiers_7.snap new file mode 100644 index 00000000..78e9be73 --- /dev/null +++ b/partiql/tests/snapshots/pretty__graph_quantifiers_7.snap @@ -0,0 +1,33 @@ +--- +source: partiql/tests/pretty.rs +expression: doc +--- +======================================================================================================================================================================================================== +SELECT a,b FROM g MATCH (a:A)~{5,}(b:B) +======================================================================================================================================================================================================== + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +SELECT a, b FROM g MATCH (a:A) ~{5,} (b:B) + +------------------------------------------------------------------------------------------------------------------------ +SELECT a, b FROM g MATCH (a:A) ~{5,} (b:B) + +-------------------------------------------------------------------------------- +SELECT a, b FROM g MATCH (a:A) ~{5,} (b:B) + +---------------------------------------- +SELECT a, b +FROM g MATCH (a:A) ~{5,} (b:B) + +------------------------------ +SELECT a, b +FROM g MATCH (a:A) ~{5,} (b:B) + +-------------------- +SELECT a, b +FROM g MATCH (a:A) ~{5,} (b:B) + +---------- +SELECT a, + b +FROM g MATCH (a:A) ~{5,} (b:B) diff --git a/partiql/tests/snapshots/pretty__graph_quantifiers_8.snap b/partiql/tests/snapshots/pretty__graph_quantifiers_8.snap new file mode 100644 index 00000000..b6dcfb89 --- /dev/null +++ b/partiql/tests/snapshots/pretty__graph_quantifiers_8.snap @@ -0,0 +1,33 @@ +--- +source: partiql/tests/pretty.rs +expression: doc +--- +======================================================================================================================================================================================================== +SELECT a,b FROM g MATCH (a:A)-{2,6}(b:B) +======================================================================================================================================================================================================== + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +SELECT a, b FROM g MATCH (a:A) -{2,6} (b:B) + +------------------------------------------------------------------------------------------------------------------------ +SELECT a, b FROM g MATCH (a:A) -{2,6} (b:B) + +-------------------------------------------------------------------------------- +SELECT a, b FROM g MATCH (a:A) -{2,6} (b:B) + +---------------------------------------- +SELECT a, b +FROM g MATCH (a:A) -{2,6} (b:B) + +------------------------------ +SELECT a, b +FROM g MATCH (a:A) -{2,6} (b:B) + +-------------------- +SELECT a, b +FROM g MATCH (a:A) -{2,6} (b:B) + +---------- +SELECT a, + b +FROM g MATCH (a:A) -{2,6} (b:B) diff --git a/partiql/tests/snapshots/pretty__graph_restrictors_1.snap b/partiql/tests/snapshots/pretty__graph_restrictors_1.snap new file mode 100644 index 00000000..b7210d36 --- /dev/null +++ b/partiql/tests/snapshots/pretty__graph_restrictors_1.snap @@ -0,0 +1,33 @@ +--- +source: partiql/tests/pretty.rs +expression: doc +--- +======================================================================================================================================================================================================== +SELECT p FROM g MATCH TRAIL p = (a WHERE a.owner='Dave') -[t:Transfer]-> * (b WHERE b.owner='Aretha') +======================================================================================================================================================================================================== + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +SELECT p FROM g MATCH [TRAIL p = (a WHERE (a.owner = 'Dave')) -[t:Transfer]->* (b WHERE (b.owner = 'Aretha'))] + +------------------------------------------------------------------------------------------------------------------------ +SELECT p FROM g MATCH [TRAIL p = (a WHERE (a.owner = 'Dave')) -[t:Transfer]->* (b WHERE (b.owner = 'Aretha'))] + +-------------------------------------------------------------------------------- +SELECT p +FROM g MATCH [TRAIL p = (a WHERE (a.owner = 'Dave')) -[t:Transfer]->* (b WHERE (b.owner = 'Aretha'))] + +---------------------------------------- +SELECT p +FROM g MATCH [TRAIL p = (a WHERE (a.owner = 'Dave')) -[t:Transfer]->* (b WHERE (b.owner = 'Aretha'))] + +------------------------------ +SELECT p +FROM g MATCH [TRAIL p = (a WHERE (a.owner = 'Dave')) -[t:Transfer]->* (b WHERE (b.owner = 'Aretha'))] + +-------------------- +SELECT p +FROM g MATCH [TRAIL p = (a WHERE (a.owner = 'Dave')) -[t:Transfer]->* (b WHERE (b.owner = 'Aretha'))] + +---------- +SELECT p +FROM g MATCH [TRAIL p = (a WHERE (a.owner = 'Dave')) -[t:Transfer]->* (b WHERE (b.owner = 'Aretha'))] diff --git a/partiql/tests/snapshots/pretty__graph_restrictors_2.snap b/partiql/tests/snapshots/pretty__graph_restrictors_2.snap new file mode 100644 index 00000000..4d5757db --- /dev/null +++ b/partiql/tests/snapshots/pretty__graph_restrictors_2.snap @@ -0,0 +1,33 @@ +--- +source: partiql/tests/pretty.rs +expression: doc +--- +======================================================================================================================================================================================================== +SELECT p FROM g MATCH SIMPLE p = (a WHERE a.owner='Dave') -[t:Transfer]-> * (b WHERE b.owner='Aretha') +======================================================================================================================================================================================================== + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +SELECT p FROM g MATCH [SIMPLE p = (a WHERE (a.owner = 'Dave')) -[t:Transfer]->* (b WHERE (b.owner = 'Aretha'))] + +------------------------------------------------------------------------------------------------------------------------ +SELECT p FROM g MATCH [SIMPLE p = (a WHERE (a.owner = 'Dave')) -[t:Transfer]->* (b WHERE (b.owner = 'Aretha'))] + +-------------------------------------------------------------------------------- +SELECT p +FROM g MATCH [SIMPLE p = (a WHERE (a.owner = 'Dave')) -[t:Transfer]->* (b WHERE (b.owner = 'Aretha'))] + +---------------------------------------- +SELECT p +FROM g MATCH [SIMPLE p = (a WHERE (a.owner = 'Dave')) -[t:Transfer]->* (b WHERE (b.owner = 'Aretha'))] + +------------------------------ +SELECT p +FROM g MATCH [SIMPLE p = (a WHERE (a.owner = 'Dave')) -[t:Transfer]->* (b WHERE (b.owner = 'Aretha'))] + +-------------------- +SELECT p +FROM g MATCH [SIMPLE p = (a WHERE (a.owner = 'Dave')) -[t:Transfer]->* (b WHERE (b.owner = 'Aretha'))] + +---------- +SELECT p +FROM g MATCH [SIMPLE p = (a WHERE (a.owner = 'Dave')) -[t:Transfer]->* (b WHERE (b.owner = 'Aretha'))] diff --git a/partiql/tests/snapshots/pretty__graph_restrictors_3.snap b/partiql/tests/snapshots/pretty__graph_restrictors_3.snap new file mode 100644 index 00000000..4005bf39 --- /dev/null +++ b/partiql/tests/snapshots/pretty__graph_restrictors_3.snap @@ -0,0 +1,33 @@ +--- +source: partiql/tests/pretty.rs +expression: doc +--- +======================================================================================================================================================================================================== +SELECT p FROM g MATCH ACYCLIC p = (a WHERE a.owner='Dave') -[t:Transfer]-> * (b WHERE b.owner='Aretha') +======================================================================================================================================================================================================== + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +SELECT p FROM g MATCH [ACYCLIC p = (a WHERE (a.owner = 'Dave')) -[t:Transfer]->* (b WHERE (b.owner = 'Aretha'))] + +------------------------------------------------------------------------------------------------------------------------ +SELECT p FROM g MATCH [ACYCLIC p = (a WHERE (a.owner = 'Dave')) -[t:Transfer]->* (b WHERE (b.owner = 'Aretha'))] + +-------------------------------------------------------------------------------- +SELECT p +FROM g MATCH [ACYCLIC p = (a WHERE (a.owner = 'Dave')) -[t:Transfer]->* (b WHERE (b.owner = 'Aretha'))] + +---------------------------------------- +SELECT p +FROM g MATCH [ACYCLIC p = (a WHERE (a.owner = 'Dave')) -[t:Transfer]->* (b WHERE (b.owner = 'Aretha'))] + +------------------------------ +SELECT p +FROM g MATCH [ACYCLIC p = (a WHERE (a.owner = 'Dave')) -[t:Transfer]->* (b WHERE (b.owner = 'Aretha'))] + +-------------------- +SELECT p +FROM g MATCH [ACYCLIC p = (a WHERE (a.owner = 'Dave')) -[t:Transfer]->* (b WHERE (b.owner = 'Aretha'))] + +---------- +SELECT p +FROM g MATCH [ACYCLIC p = (a WHERE (a.owner = 'Dave')) -[t:Transfer]->* (b WHERE (b.owner = 'Aretha'))] diff --git a/partiql/tests/snapshots/pretty__graph_selectors_1.snap b/partiql/tests/snapshots/pretty__graph_selectors_1.snap new file mode 100644 index 00000000..095dee2c --- /dev/null +++ b/partiql/tests/snapshots/pretty__graph_selectors_1.snap @@ -0,0 +1,36 @@ +--- +source: partiql/tests/pretty.rs +expression: doc +--- +======================================================================================================================================================================================================== +SELECT p FROM g MATCH ANY SHORTEST p = (a WHERE a.owner='Dave') -[t:Transfer]-> * (b WHERE b.owner='Aretha') +======================================================================================================================================================================================================== + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +SELECT p FROM g MATCH ANY SHORTEST p = (a WHERE (a.owner = 'Dave')) -[t:Transfer]->* (b WHERE (b.owner = 'Aretha')) + +------------------------------------------------------------------------------------------------------------------------ +SELECT p FROM g MATCH ANY SHORTEST p = (a WHERE (a.owner = 'Dave')) -[t:Transfer]->* (b WHERE (b.owner = 'Aretha')) + +-------------------------------------------------------------------------------- +SELECT p FROM g MATCH ANY SHORTEST + p = (a WHERE (a.owner = 'Dave')) -[t:Transfer]->* (b WHERE (b.owner = 'Aretha')) + +---------------------------------------- +SELECT p FROM g MATCH ANY SHORTEST + p = (a WHERE (a.owner = 'Dave')) -[t:Transfer]->* (b WHERE (b.owner = 'Aretha')) + +------------------------------ +SELECT p +FROM g MATCH ANY SHORTEST + p = (a WHERE (a.owner = 'Dave')) -[t:Transfer]->* (b WHERE (b.owner = 'Aretha')) + +-------------------- +SELECT p +FROM g MATCH ANY SHORTEST + p = (a WHERE (a.owner = 'Dave')) -[t:Transfer]->* (b WHERE (b.owner = 'Aretha')) + +---------- +SELECT p +FROM g MATCH ANY SHORTEST + p = (a WHERE (a.owner = 'Dave')) -[t:Transfer]->* (b WHERE (b.owner = 'Aretha')) diff --git a/partiql/tests/snapshots/pretty__graph_selectors_2.snap b/partiql/tests/snapshots/pretty__graph_selectors_2.snap new file mode 100644 index 00000000..72deb5ca --- /dev/null +++ b/partiql/tests/snapshots/pretty__graph_selectors_2.snap @@ -0,0 +1,36 @@ +--- +source: partiql/tests/pretty.rs +expression: doc +--- +======================================================================================================================================================================================================== +SELECT p FROM g MATCH ALL SHORTEST p = (a WHERE a.owner='Dave') -[t:Transfer]-> * (b WHERE b.owner='Aretha') +======================================================================================================================================================================================================== + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +SELECT p FROM g MATCH ALL SHORTEST p = (a WHERE (a.owner = 'Dave')) -[t:Transfer]->* (b WHERE (b.owner = 'Aretha')) + +------------------------------------------------------------------------------------------------------------------------ +SELECT p FROM g MATCH ALL SHORTEST p = (a WHERE (a.owner = 'Dave')) -[t:Transfer]->* (b WHERE (b.owner = 'Aretha')) + +-------------------------------------------------------------------------------- +SELECT p FROM g MATCH ALL SHORTEST + p = (a WHERE (a.owner = 'Dave')) -[t:Transfer]->* (b WHERE (b.owner = 'Aretha')) + +---------------------------------------- +SELECT p FROM g MATCH ALL SHORTEST + p = (a WHERE (a.owner = 'Dave')) -[t:Transfer]->* (b WHERE (b.owner = 'Aretha')) + +------------------------------ +SELECT p +FROM g MATCH ALL SHORTEST + p = (a WHERE (a.owner = 'Dave')) -[t:Transfer]->* (b WHERE (b.owner = 'Aretha')) + +-------------------- +SELECT p +FROM g MATCH ALL SHORTEST + p = (a WHERE (a.owner = 'Dave')) -[t:Transfer]->* (b WHERE (b.owner = 'Aretha')) + +---------- +SELECT p +FROM g MATCH ALL SHORTEST + p = (a WHERE (a.owner = 'Dave')) -[t:Transfer]->* (b WHERE (b.owner = 'Aretha')) diff --git a/partiql/tests/snapshots/pretty__graph_selectors_3.snap b/partiql/tests/snapshots/pretty__graph_selectors_3.snap new file mode 100644 index 00000000..35bf53a8 --- /dev/null +++ b/partiql/tests/snapshots/pretty__graph_selectors_3.snap @@ -0,0 +1,35 @@ +--- +source: partiql/tests/pretty.rs +expression: doc +--- +======================================================================================================================================================================================================== +SELECT p FROM g MATCH ANY p = (a WHERE a.owner='Dave') -[t:Transfer]-> * (b WHERE b.owner='Aretha') +======================================================================================================================================================================================================== + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +SELECT p FROM g MATCH ANY p = (a WHERE (a.owner = 'Dave')) -[t:Transfer]->* (b WHERE (b.owner = 'Aretha')) + +------------------------------------------------------------------------------------------------------------------------ +SELECT p FROM g MATCH ANY p = (a WHERE (a.owner = 'Dave')) -[t:Transfer]->* (b WHERE (b.owner = 'Aretha')) + +-------------------------------------------------------------------------------- +SELECT p FROM g MATCH ANY + p = (a WHERE (a.owner = 'Dave')) -[t:Transfer]->* (b WHERE (b.owner = 'Aretha')) + +---------------------------------------- +SELECT p FROM g MATCH ANY + p = (a WHERE (a.owner = 'Dave')) -[t:Transfer]->* (b WHERE (b.owner = 'Aretha')) + +------------------------------ +SELECT p FROM g MATCH ANY + p = (a WHERE (a.owner = 'Dave')) -[t:Transfer]->* (b WHERE (b.owner = 'Aretha')) + +-------------------- +SELECT p +FROM g MATCH ANY + p = (a WHERE (a.owner = 'Dave')) -[t:Transfer]->* (b WHERE (b.owner = 'Aretha')) + +---------- +SELECT p +FROM g MATCH ANY + p = (a WHERE (a.owner = 'Dave')) -[t:Transfer]->* (b WHERE (b.owner = 'Aretha')) diff --git a/partiql/tests/snapshots/pretty__graph_selectors_4.snap b/partiql/tests/snapshots/pretty__graph_selectors_4.snap new file mode 100644 index 00000000..c67b0d9e --- /dev/null +++ b/partiql/tests/snapshots/pretty__graph_selectors_4.snap @@ -0,0 +1,35 @@ +--- +source: partiql/tests/pretty.rs +expression: doc +--- +======================================================================================================================================================================================================== +SELECT p FROM g MATCH ANY 5 p = (a WHERE a.owner='Dave') -[t:Transfer]-> * (b WHERE b.owner='Aretha') +======================================================================================================================================================================================================== + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +SELECT p FROM g MATCH ANY 5 p = (a WHERE (a.owner = 'Dave')) -[t:Transfer]->* (b WHERE (b.owner = 'Aretha')) + +------------------------------------------------------------------------------------------------------------------------ +SELECT p FROM g MATCH ANY 5 p = (a WHERE (a.owner = 'Dave')) -[t:Transfer]->* (b WHERE (b.owner = 'Aretha')) + +-------------------------------------------------------------------------------- +SELECT p FROM g MATCH ANY 5 + p = (a WHERE (a.owner = 'Dave')) -[t:Transfer]->* (b WHERE (b.owner = 'Aretha')) + +---------------------------------------- +SELECT p FROM g MATCH ANY 5 + p = (a WHERE (a.owner = 'Dave')) -[t:Transfer]->* (b WHERE (b.owner = 'Aretha')) + +------------------------------ +SELECT p FROM g MATCH ANY 5 + p = (a WHERE (a.owner = 'Dave')) -[t:Transfer]->* (b WHERE (b.owner = 'Aretha')) + +-------------------- +SELECT p +FROM g MATCH ANY 5 + p = (a WHERE (a.owner = 'Dave')) -[t:Transfer]->* (b WHERE (b.owner = 'Aretha')) + +---------- +SELECT p +FROM g MATCH ANY 5 + p = (a WHERE (a.owner = 'Dave')) -[t:Transfer]->* (b WHERE (b.owner = 'Aretha')) diff --git a/partiql/tests/snapshots/pretty__graph_selectors_5.snap b/partiql/tests/snapshots/pretty__graph_selectors_5.snap new file mode 100644 index 00000000..907a697d --- /dev/null +++ b/partiql/tests/snapshots/pretty__graph_selectors_5.snap @@ -0,0 +1,36 @@ +--- +source: partiql/tests/pretty.rs +expression: doc +--- +======================================================================================================================================================================================================== +SELECT p FROM g MATCH SHORTEST 5 p = (a WHERE a.owner='Dave') -[t:Transfer]-> * (b WHERE b.owner='Aretha') +======================================================================================================================================================================================================== + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +SELECT p FROM g MATCH SHORTEST 5 p = (a WHERE (a.owner = 'Dave')) -[t:Transfer]->* (b WHERE (b.owner = 'Aretha')) + +------------------------------------------------------------------------------------------------------------------------ +SELECT p FROM g MATCH SHORTEST 5 p = (a WHERE (a.owner = 'Dave')) -[t:Transfer]->* (b WHERE (b.owner = 'Aretha')) + +-------------------------------------------------------------------------------- +SELECT p FROM g MATCH SHORTEST 5 + p = (a WHERE (a.owner = 'Dave')) -[t:Transfer]->* (b WHERE (b.owner = 'Aretha')) + +---------------------------------------- +SELECT p FROM g MATCH SHORTEST 5 + p = (a WHERE (a.owner = 'Dave')) -[t:Transfer]->* (b WHERE (b.owner = 'Aretha')) + +------------------------------ +SELECT p +FROM g MATCH SHORTEST 5 + p = (a WHERE (a.owner = 'Dave')) -[t:Transfer]->* (b WHERE (b.owner = 'Aretha')) + +-------------------- +SELECT p +FROM g MATCH SHORTEST 5 + p = (a WHERE (a.owner = 'Dave')) -[t:Transfer]->* (b WHERE (b.owner = 'Aretha')) + +---------- +SELECT p +FROM g MATCH SHORTEST 5 + p = (a WHERE (a.owner = 'Dave')) -[t:Transfer]->* (b WHERE (b.owner = 'Aretha')) diff --git a/partiql/tests/snapshots/pretty__graph_selectors_6.snap b/partiql/tests/snapshots/pretty__graph_selectors_6.snap new file mode 100644 index 00000000..e99309bd --- /dev/null +++ b/partiql/tests/snapshots/pretty__graph_selectors_6.snap @@ -0,0 +1,36 @@ +--- +source: partiql/tests/pretty.rs +expression: doc +--- +======================================================================================================================================================================================================== +SELECT p FROM g MATCH SHORTEST 5 GROUP p = (a WHERE a.owner='Dave') -[t:Transfer]-> * (b WHERE b.owner='Aretha') +======================================================================================================================================================================================================== + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +SELECT p FROM g MATCH SHORTEST 5 GROUP p = (a WHERE (a.owner = 'Dave')) -[t:Transfer]->* (b WHERE (b.owner = 'Aretha')) + +------------------------------------------------------------------------------------------------------------------------ +SELECT p FROM g MATCH SHORTEST 5 GROUP p = (a WHERE (a.owner = 'Dave')) -[t:Transfer]->* (b WHERE (b.owner = 'Aretha')) + +-------------------------------------------------------------------------------- +SELECT p FROM g MATCH SHORTEST 5 GROUP + p = (a WHERE (a.owner = 'Dave')) -[t:Transfer]->* (b WHERE (b.owner = 'Aretha')) + +---------------------------------------- +SELECT p FROM g MATCH SHORTEST 5 GROUP + p = (a WHERE (a.owner = 'Dave')) -[t:Transfer]->* (b WHERE (b.owner = 'Aretha')) + +------------------------------ +SELECT p +FROM g MATCH SHORTEST 5 GROUP + p = (a WHERE (a.owner = 'Dave')) -[t:Transfer]->* (b WHERE (b.owner = 'Aretha')) + +-------------------- +SELECT p +FROM g MATCH SHORTEST 5 GROUP + p = (a WHERE (a.owner = 'Dave')) -[t:Transfer]->* (b WHERE (b.owner = 'Aretha')) + +---------- +SELECT p +FROM g MATCH SHORTEST 5 GROUP + p = (a WHERE (a.owner = 'Dave')) -[t:Transfer]->* (b WHERE (b.owner = 'Aretha')) diff --git a/partiql/tests/snapshots/pretty__graph_union_1.snap b/partiql/tests/snapshots/pretty__graph_union_1.snap new file mode 100644 index 00000000..2c2005a2 --- /dev/null +++ b/partiql/tests/snapshots/pretty__graph_union_1.snap @@ -0,0 +1,43 @@ +--- +source: partiql/tests/pretty.rs +expression: doc +--- +======================================================================================================================================================================================================== +(MyGraph MATCH (x)) UNION SELECT * FROM tbl1 +======================================================================================================================================================================================================== + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +(MyGraph MATCH (x)) +UNION +(SELECT * FROM tbl1) + +------------------------------------------------------------------------------------------------------------------------ +(MyGraph MATCH (x)) +UNION +(SELECT * FROM tbl1) + +-------------------------------------------------------------------------------- +(MyGraph MATCH (x)) +UNION +(SELECT * FROM tbl1) + +---------------------------------------- +(MyGraph MATCH (x)) +UNION +(SELECT * FROM tbl1) + +------------------------------ +(MyGraph MATCH (x)) +UNION +(SELECT * FROM tbl1) + +-------------------- +(MyGraph MATCH (x)) +UNION +(SELECT * FROM tbl1) + +---------- +(MyGraph MATCH (x)) +UNION +(SELECT * + FROM tbl1) diff --git a/partiql/tests/snapshots/pretty__graph_union_2.snap b/partiql/tests/snapshots/pretty__graph_union_2.snap new file mode 100644 index 00000000..1164ea58 --- /dev/null +++ b/partiql/tests/snapshots/pretty__graph_union_2.snap @@ -0,0 +1,43 @@ +--- +source: partiql/tests/pretty.rs +expression: doc +--- +======================================================================================================================================================================================================== +SELECT * FROM tbl1 UNION (MyGraph MATCH (x)) +======================================================================================================================================================================================================== + +------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ +(SELECT * FROM tbl1) +UNION +(MyGraph MATCH (x)) + +------------------------------------------------------------------------------------------------------------------------ +(SELECT * FROM tbl1) +UNION +(MyGraph MATCH (x)) + +-------------------------------------------------------------------------------- +(SELECT * FROM tbl1) +UNION +(MyGraph MATCH (x)) + +---------------------------------------- +(SELECT * FROM tbl1) +UNION +(MyGraph MATCH (x)) + +------------------------------ +(SELECT * FROM tbl1) +UNION +(MyGraph MATCH (x)) + +-------------------- +(SELECT * FROM tbl1) +UNION +(MyGraph MATCH (x)) + +---------- +(SELECT * + FROM tbl1) +UNION +(MyGraph MATCH (x)) From 3ae912fea0f2018ae7d965e13f4985873e32ba57 Mon Sep 17 00:00:00 2001 From: Josh Pschorr Date: Wed, 19 Mar 2025 16:21:56 -0700 Subject: [PATCH 3/6] Add non-reserved keywords for some GPML keywords --- partiql-parser/src/parse/partiql.lalrpop | 25 ++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/partiql-parser/src/parse/partiql.lalrpop b/partiql-parser/src/parse/partiql.lalrpop index 272bd5bc..df131416 100644 --- a/partiql-parser/src/parse/partiql.lalrpop +++ b/partiql-parser/src/parse/partiql.lalrpop @@ -1312,6 +1312,8 @@ FunctionCall: CallSite = { #[inline] FunctionName: ast::SymbolPrimitive = { , + => + ast::SymbolPrimitive { value: ident.to_owned(), case: ast::CaseSensitivity::CaseInsensitive } } #[inline] @@ -1437,6 +1439,10 @@ VarRef: ast::AstNode = { name: ast::SymbolPrimitive { value: ident.to_owned(), case: ast::CaseSensitivity::CaseSensitive }, qualifier: ast::ScopeQualifier::Unqualified },lo..hi), + => state.node(ast::VarRef { + name: ast::SymbolPrimitive { value: ident.to_owned(), case: ast::CaseSensitivity::CaseInsensitive }, + qualifier: ast::ScopeQualifier::Unqualified + },lo..hi), } ExcludePath: ast::AstNode = { @@ -1668,6 +1674,25 @@ ByIdent: ast::SymbolPrimitive = { // // // ------------------------------------------------------------------------------ // +#[inline] +VarNonReservedKeyword: &'static str = { + +} + +#[inline] +FnNonReservedKeyword: &'static str = { + +} + +#[inline] +NonReservedKeyword: &'static str = { + "ACYCLIC" => "ACYCLIC", + "ANY" => "ANY", + "SIMPLE" => "SIMPLE", + "SHORTEST" => "SHORTEST", + "TRAIL" => "TRAIL", +} + // The lexer is external; See [`lexer.rs`] for its definition. // // See also http://lalrpop.github.io/lalrpop/lexer_tutorial/002_writing_custom_lexer.html From 4a691323828a9b89fd6d5e8a5d0fca4cbcfa9529 Mon Sep 17 00:00:00 2001 From: Josh Pschorr Date: Wed, 19 Mar 2025 16:33:08 -0700 Subject: [PATCH 4/6] cleanup & clippy --- partiql-ast/src/pretty.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/partiql-ast/src/pretty.rs b/partiql-ast/src/pretty.rs index f8ee2a60..a18222f9 100644 --- a/partiql-ast/src/pretty.rs +++ b/partiql-ast/src/pretty.rs @@ -1142,7 +1142,7 @@ impl PrettyDoc for GraphMatchNode { } if let Some(r) = &self.prefilter { let parts = [spec, arena.text("WHERE"), r.pretty_doc(arena)]; - spec = arena.intersperse(parts, arena.space()).into(); + spec = arena.intersperse(parts, arena.space()); } pretty_surrounded_doc(spec, "(", ")", arena) } @@ -1176,7 +1176,7 @@ impl PrettyDoc for GraphMatchEdge { arena.text("WHERE"), r.pretty_doc(arena), ]; - spec = arena.intersperse(parts, arena.space()).into(); + spec = Some(arena.intersperse(parts, arena.space())); } let mut edge = if let Some(spec) = spec { From 1402d942007f5f3fe2dca477965aacf607bd7dd0 Mon Sep 17 00:00:00 2001 From: Josh Pschorr Date: Thu, 20 Mar 2025 11:15:44 -0700 Subject: [PATCH 5/6] Add non-reserved keyword handling to function preprocessing --- partiql-parser/src/lexer/partiql.rs | 12 ++++++++++++ partiql-parser/src/preprocessor.rs | 11 ++++++++--- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/partiql-parser/src/lexer/partiql.rs b/partiql-parser/src/lexer/partiql.rs index 10856454..a8a494f9 100644 --- a/partiql-parser/src/lexer/partiql.rs +++ b/partiql-parser/src/lexer/partiql.rs @@ -411,6 +411,18 @@ pub enum Token<'input> { } impl Token<'_> { + pub fn is_var_non_reserved(&self) -> bool { + matches!( + self, + Token::Acyclic | Token::Any | Token::Simple | Token::Shortest | Token::Trail + ) + } + pub fn is_fn_non_reserved(&self) -> bool { + matches!( + self, + Token::Acyclic | Token::Any | Token::Simple | Token::Shortest | Token::Trail + ) + } pub fn is_keyword(&self) -> bool { matches!( self, diff --git a/partiql-parser/src/preprocessor.rs b/partiql-parser/src/preprocessor.rs index d89ea621..079b3dc8 100644 --- a/partiql-parser/src/preprocessor.rs +++ b/partiql-parser/src/preprocessor.rs @@ -131,7 +131,7 @@ mod built_ins { pub(crate) fn built_in_aggs() -> FnExpr<'static> { FnExpr { - // TODO: currently needs to be manually kept in-sync with parsers's `KNOWN_AGGREGATES` + // TODO: currently needs to be manually kept in-sync with parser's `KNOWN_AGGREGATES` fn_names: vec!["count", "avg", "min", "max", "sum", "any", "some", "every"], #[rustfmt::skip] patterns: vec![ @@ -320,10 +320,15 @@ where #[inline] fn parse_fn_expr( &mut self, - (tok, _): BufferedToken<'input>, + (tok, tok_txt): BufferedToken<'input>, next_idx: usize, ) -> (SpannedToken<'input>, Option>) { - if let (_, Token::UnquotedIdent(id) | Token::QuotedIdent(id), _) = tok { + let fn_candidate = match &tok { + (_, Token::UnquotedIdent(id) | Token::QuotedIdent(id), _) => Some(*id), + (_, tok, _) => tok.is_fn_non_reserved().then_some(tok_txt), + }; + + if let Some(id) = fn_candidate { if let Some(((_, Token::OpenParen, _), _)) = self.parser.peek_n(next_idx) { if let Some(fn_expr) = self.fn_exprs.find(id) { let replacement = match self.rewrite_fn_expr(fn_expr) { From 440d5acf51917f4338da4d91f614d0a6c7ff56c7 Mon Sep 17 00:00:00 2001 From: Josh Pschorr Date: Fri, 21 Mar 2025 13:23:36 -0700 Subject: [PATCH 6/6] Error on usage of `MATCH` syntax --- partiql-logical-planner/src/lower.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/partiql-logical-planner/src/lower.rs b/partiql-logical-planner/src/lower.rs index 55d46ae2..a89c34e6 100644 --- a/partiql-logical-planner/src/lower.rs +++ b/partiql-logical-planner/src/lower.rs @@ -6,11 +6,11 @@ use partiql_ast::ast; use partiql_ast::ast::{ Assignment, Bag, BagOpExpr, BagOperator, Between, BinOp, BinOpKind, Call, CallAgg, CallArg, CallArgNamed, CaseSensitivity, CreateIndex, CreateTable, Ddl, DdlOp, Delete, Dml, DmlOp, - DropIndex, DropTable, Exclusion, Expr, FromClause, FromLet, FromLetKind, GroupByExpr, GroupKey, - GroupingStrategy, Insert, InsertValue, Item, Join, JoinKind, JoinSpec, Like, List, Lit, - NullOrderingSpec, OnConflict, OrderByExpr, OrderingSpec, Path, PathStep, ProjectExpr, - Projection, ProjectionKind, Query, QuerySet, Remove, SearchedCase, Select, Set, SetQuantifier, - Sexp, SimpleCase, SortSpec, Struct, SymbolPrimitive, UniOp, UniOpKind, VarRef, + DropIndex, DropTable, Exclusion, Expr, FromClause, FromLet, FromLetKind, GraphMatch, + GroupByExpr, GroupKey, GroupingStrategy, Insert, InsertValue, Item, Join, JoinKind, JoinSpec, + Like, List, Lit, NullOrderingSpec, OnConflict, OrderByExpr, OrderingSpec, Path, PathStep, + ProjectExpr, Projection, ProjectionKind, Query, QuerySet, Remove, SearchedCase, Select, Set, + SetQuantifier, Sexp, SimpleCase, SortSpec, Struct, SymbolPrimitive, UniOp, UniOpKind, VarRef, }; use partiql_ast::visit::{Traverse, Visit, Visitor}; use partiql_logical as logical; @@ -1894,6 +1894,10 @@ impl<'ast> Visitor<'ast> for AstToLogical<'_> { })); Traverse::Continue } + + fn enter_graph_match(&mut self, _graph_pattern: &'ast GraphMatch) -> Traverse { + not_yet_implemented_fault!(self, "MATCH expression"); + } } fn lit_to_lit(lit: &Lit) -> Result {