Skip to content

Commit 5d16ec0

Browse files
committed
Add pretty-printing for simplified path patterns
1 parent 6233184 commit 5d16ec0

23 files changed

+775
-37
lines changed

partiql-ast/src/ast/graph.rs

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -156,9 +156,6 @@ pub struct GraphMatchEdge {
156156
/// edge direction
157157
#[visit(skip)]
158158
pub direction: GraphMatchDirection,
159-
/// an optional quantifier for the edge match
160-
#[visit(skip)]
161-
pub quantifier: Option<AstNode<GraphMatchQuantifier>>,
162159
/// the optional element variable of the edge match, e.g.: `t` in `MATCH −[t]−>`
163160
#[visit(skip)]
164161
pub variable: Option<SymbolPrimitive>,
@@ -257,25 +254,34 @@ pub enum GraphMatchSimplifiedPattern {
257254
Multiset(Vec<AstNode<GraphMatchSimplifiedPattern>>),
258255

259256
Path(Vec<AstNode<GraphMatchSimplifiedPattern>>),
257+
Sub(Box<AstNode<GraphMatchSimplifiedPattern>>),
260258

261259
Conjunction(Vec<AstNode<GraphMatchSimplifiedPattern>>),
262260

263261
Questioned(Box<AstNode<GraphMatchSimplifiedPattern>>),
264-
Quantified(
265-
Box<AstNode<GraphMatchSimplifiedPattern>>,
266-
AstNode<GraphMatchQuantifier>,
267-
),
262+
Quantified(GraphMatchSimplifiedPatternQuantified),
268263

269264
/// Direction override
270-
Direction(
271-
GraphMatchDirection,
272-
Box<AstNode<GraphMatchSimplifiedPattern>>,
273-
),
265+
Direction(GraphMatchSimplifiedPatternDirected),
274266

275267
Negated(Box<AstNode<GraphMatchSimplifiedPattern>>),
276268
Label(SymbolPrimitive),
277269
}
278270

271+
#[derive(Clone, Debug, PartialEq)]
272+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
273+
pub struct GraphMatchSimplifiedPatternQuantified {
274+
pub path: Box<AstNode<GraphMatchSimplifiedPattern>>,
275+
pub quant: AstNode<GraphMatchQuantifier>,
276+
}
277+
278+
#[derive(Clone, Debug, PartialEq)]
279+
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
280+
pub struct GraphMatchSimplifiedPatternDirected {
281+
pub dir: GraphMatchDirection,
282+
pub path: Box<AstNode<GraphMatchSimplifiedPattern>>,
283+
}
284+
279285
#[derive(Clone, Debug, PartialEq, Eq)]
280286
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
281287
pub enum GraphPathPrefix {

partiql-ast/src/pretty/graph.rs

Lines changed: 106 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use crate::ast::*;
2+
use crate::pretty::pretty_parenthesized_expr;
23
use partiql_common::pretty::{
34
pretty_doc_list, pretty_list, pretty_parenthesized_doc, pretty_surrounded,
45
pretty_surrounded_doc, PrettyDoc, PRETTY_INDENT_MINOR_NEST,
@@ -348,13 +349,101 @@ impl PrettyDoc for GraphMatchPathPattern {
348349
GraphMatchPathPattern::Quantified(GraphMatchPathPatternQuantified { path, quant }) => {
349350
arena.concat([path.pretty_doc(arena), quant.pretty_doc(arena)])
350351
}
352+
GraphMatchPathPattern::Questioned(p) => {
353+
arena.concat([p.pretty_doc(arena), arena.text("?")])
354+
}
351355
GraphMatchPathPattern::Sub(path) => pretty_surrounded(path, "(", ")", arena),
352356
GraphMatchPathPattern::Node(node) => node.pretty_doc(arena),
353357
GraphMatchPathPattern::Edge(edge) => edge.pretty_doc(arena),
354-
GraphMatchPathPattern::Union(_) => todo!("{:?}", self),
355-
GraphMatchPathPattern::Multiset(_) => todo!("{:?}", self),
356-
GraphMatchPathPattern::Questioned(_) => todo!("{:?}", self),
357-
GraphMatchPathPattern::Simplified(_) => todo!("{:?}", self),
358+
GraphMatchPathPattern::Union(u) => {
359+
arena.intersperse(u.iter().map(|l| l.pretty_doc(arena)), arena.text(" | "))
360+
}
361+
GraphMatchPathPattern::Multiset(s) => {
362+
arena.intersperse(s.iter().map(|l| l.pretty_doc(arena)), arena.text(" |+| "))
363+
}
364+
GraphMatchPathPattern::Simplified(simplified) => simplified.pretty_doc(arena),
365+
}
366+
}
367+
}
368+
369+
impl PrettyDoc for GraphMatchSimplified {
370+
fn pretty_doc<'b, D, A>(&'b self, arena: &'b D) -> DocBuilder<'b, D, A>
371+
where
372+
D: DocAllocator<'b, A>,
373+
D::Doc: Clone,
374+
A: Clone,
375+
{
376+
let ends = match self.dir {
377+
GraphMatchDirection::Left => ["<-/", "/-"],
378+
GraphMatchDirection::Undirected => ["~/", "/~"],
379+
GraphMatchDirection::Right => ["-/", "/->"],
380+
GraphMatchDirection::LeftOrUndirected => ["<~/", "/~"],
381+
GraphMatchDirection::UndirectedOrRight => ["~/", "/~>"],
382+
GraphMatchDirection::LeftOrRight => ["<-/", "/->"],
383+
GraphMatchDirection::LeftOrUndirectedOrRight => ["-/", "/-"],
384+
};
385+
386+
let parts = [
387+
arena.text(ends[0]),
388+
self.pattern.pretty_doc(arena),
389+
arena.text(ends[1]),
390+
];
391+
arena.intersperse(parts, arena.space()).group()
392+
}
393+
}
394+
395+
impl PrettyDoc for GraphMatchSimplifiedPattern {
396+
fn pretty_doc<'b, D, A>(&'b self, arena: &'b D) -> DocBuilder<'b, D, A>
397+
where
398+
D: DocAllocator<'b, A>,
399+
D::Doc: Clone,
400+
A: Clone,
401+
{
402+
match self {
403+
GraphMatchSimplifiedPattern::Union(u) => {
404+
arena.intersperse(u.iter().map(|l| l.pretty_doc(arena)), arena.text(" | "))
405+
}
406+
GraphMatchSimplifiedPattern::Multiset(s) => {
407+
arena.intersperse(s.iter().map(|l| l.pretty_doc(arena)), arena.text(" |+| "))
408+
}
409+
GraphMatchSimplifiedPattern::Path(path) => {
410+
arena.intersperse(path.iter().map(|e| e.pretty_doc(arena)), arena.space())
411+
}
412+
GraphMatchSimplifiedPattern::Sub(path) => pretty_surrounded(path, "(", ")", arena),
413+
GraphMatchSimplifiedPattern::Conjunction(c) => {
414+
arena.intersperse(c.iter().map(|l| l.pretty_doc(arena)), arena.text("&"))
415+
}
416+
GraphMatchSimplifiedPattern::Questioned(p) => {
417+
arena.concat([p.pretty_doc(arena), arena.text("?")])
418+
}
419+
GraphMatchSimplifiedPattern::Quantified(GraphMatchSimplifiedPatternQuantified {
420+
path,
421+
quant,
422+
}) => arena.concat([path.pretty_doc(arena), quant.pretty_doc(arena)]),
423+
GraphMatchSimplifiedPattern::Direction(GraphMatchSimplifiedPatternDirected {
424+
dir,
425+
path,
426+
}) => {
427+
let path = path.pretty_doc(arena);
428+
let parts = match dir {
429+
GraphMatchDirection::Left => vec![arena.text("<"), path],
430+
GraphMatchDirection::Undirected => vec![arena.text("~"), path],
431+
GraphMatchDirection::Right => vec![path, arena.text(">")],
432+
GraphMatchDirection::LeftOrUndirected => vec![arena.text("<~"), path],
433+
GraphMatchDirection::UndirectedOrRight => {
434+
vec![arena.text("~"), path, arena.text(">")]
435+
}
436+
GraphMatchDirection::LeftOrRight => {
437+
vec![arena.text("<"), path, arena.text(">")]
438+
}
439+
GraphMatchDirection::LeftOrUndirectedOrRight => vec![arena.text("-"), path],
440+
};
441+
arena.concat(parts).group()
442+
}
443+
GraphMatchSimplifiedPattern::Negated(l) => {
444+
arena.concat([arena.text("!"), l.pretty_doc(arena)])
445+
}
446+
GraphMatchSimplifiedPattern::Label(l) => arena.text(&l.value),
358447
}
359448
}
360449
}
@@ -425,7 +514,7 @@ impl PrettyDoc for GraphMatchEdge {
425514
.flatten()
426515
.collect::<Vec<_>>();
427516

428-
let mut edge = if !parts.is_empty() {
517+
let edge = if !parts.is_empty() {
429518
let (prefix, suffix) = match self.direction {
430519
GraphMatchDirection::Right => ("-[", "]->"),
431520
GraphMatchDirection::Left => ("<-[", "]-"),
@@ -449,9 +538,6 @@ impl PrettyDoc for GraphMatchEdge {
449538
};
450539
arena.text(edge)
451540
};
452-
if let Some(q) = &self.quantifier {
453-
edge = arena.concat([edge, q.pretty_doc(arena)]);
454-
}
455541
edge.group()
456542
}
457543
}
@@ -465,10 +551,18 @@ impl PrettyDoc for GraphMatchLabel {
465551
{
466552
match self {
467553
GraphMatchLabel::Name(name) => arena.text(&name.value),
468-
GraphMatchLabel::Wildcard => todo!("{:?}", self),
469-
GraphMatchLabel::Negated(_) => todo!("{:?}", self),
470-
GraphMatchLabel::Conjunction(_) => todo!("{:?}", self),
471-
GraphMatchLabel::Disjunction(_) => todo!("{:?}", self),
554+
GraphMatchLabel::Wildcard => arena.text("%"),
555+
GraphMatchLabel::Negated(l) => {
556+
arena.concat([arena.text("!"), pretty_parenthesized_expr(l, 0, arena)])
557+
}
558+
GraphMatchLabel::Conjunction(c) => pretty_parenthesized_doc(
559+
arena.intersperse(c.iter().map(|l| l.pretty_doc(arena)), arena.text("&")),
560+
arena,
561+
),
562+
GraphMatchLabel::Disjunction(d) => pretty_parenthesized_doc(
563+
arena.intersperse(d.iter().map(|l| l.pretty_doc(arena)), arena.text("|")),
564+
arena,
565+
),
472566
}
473567
}
474568
}

partiql-logical-planner/src/graph.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -325,9 +325,6 @@ impl GraphToLogical {
325325
&self,
326326
edge: &ast::GraphMatchEdge,
327327
) -> Result<Vec<MatchElement>, String> {
328-
if edge.quantifier.is_some() {
329-
not_yet_implemented_result!("MATCH edge quantifiers are not yet supported.");
330-
}
331328
if edge.where_clause.is_some() {
332329
not_yet_implemented_result!("MATCH edge where_clauses are not yet supported.");
333330
}

partiql-parser/src/parse/partiql.lalrpop

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -577,15 +577,14 @@ GraphFullEdgePattern: ast::AstNode<ast::GraphMatchEdge> = {
577577
GraphEdgePatternFiller: ast::GraphMatchEdge = {
578578
<pat:GraphElementPatternFiller> => {
579579
let ast::GraphMatchElement{variable, label, where_clause} = pat;
580-
ast::GraphMatchEdge {direction: ast::GraphMatchDirection::Undirected, quantifier: None, variable, label, where_clause}
580+
ast::GraphMatchEdge {direction: ast::GraphMatchDirection::Undirected, variable, label, where_clause}
581581
}
582582
}
583583

584584
GraphAbbreviatedEdgePattern: ast::AstNode<ast::GraphMatchEdge> = {
585585
<lo:@L> <direction:GraphAbbreviatedEdgePatternEdge> <hi:@R> => {
586586
state.node(ast::GraphMatchEdge {
587587
direction,
588-
quantifier: None,
589588
variable: None,
590589
label: None,
591590
where_clause: None,
@@ -757,19 +756,27 @@ GraphSimplifiedConjunction: ast::AstNode<ast::GraphMatchSimplifiedPattern> = {
757756

758757
GraphSimplifiedFactorHigh: ast::AstNode<ast::GraphMatchSimplifiedPattern> = {
759758
<GraphSimplifiedTertiary>,
760-
<lo:@L> <s:GraphSimplifiedTertiary> <q:GraphPatternQuantifier> <hi:@R> => state.node(ast::GraphMatchSimplifiedPattern::Quantified(Box::new(s), q), lo..hi),
759+
<lo:@L> <s:GraphSimplifiedTertiary> <quant:GraphPatternQuantifier> <hi:@R> =>
760+
state.node(ast::GraphMatchSimplifiedPattern::Quantified(ast::GraphMatchSimplifiedPatternQuantified{path: Box::new(s), quant}), lo..hi),
761761
<lo:@L> <s:GraphSimplifiedTertiary> "?" <hi:@R> => state.node(ast::GraphMatchSimplifiedPattern::Questioned(Box::new(s)), lo..hi),
762762
}
763763

764764
GraphSimplifiedTertiary: ast::AstNode<ast::GraphMatchSimplifiedPattern> = {
765765
<GraphSimplifiedSecondary>,
766-
<lo:@L> "<" <s:GraphSimplifiedSecondary> <hi:@R> => state.node(ast::GraphMatchSimplifiedPattern::Direction(ast::GraphMatchDirection::Left, Box::new(s)), lo..hi),
767-
<lo:@L> "~" <s:GraphSimplifiedSecondary> <hi:@R> => state.node(ast::GraphMatchSimplifiedPattern::Direction(ast::GraphMatchDirection::Undirected, Box::new(s)), lo..hi),
768-
<lo:@L> <s:GraphSimplifiedSecondary> ">" <hi:@R> => state.node(ast::GraphMatchSimplifiedPattern::Direction(ast::GraphMatchDirection::Right, Box::new(s)), lo..hi),
769-
<lo:@L> "<~" <s:GraphSimplifiedSecondary> <hi:@R> => state.node(ast::GraphMatchSimplifiedPattern::Direction(ast::GraphMatchDirection::LeftOrUndirected, Box::new(s)), lo..hi),
770-
<lo:@L> "~" <s:GraphSimplifiedSecondary> ">" <hi:@R> => state.node(ast::GraphMatchSimplifiedPattern::Direction(ast::GraphMatchDirection::UndirectedOrRight, Box::new(s)), lo..hi),
771-
<lo:@L> "<" <s:GraphSimplifiedSecondary> ">" <hi:@R> => state.node(ast::GraphMatchSimplifiedPattern::Direction(ast::GraphMatchDirection::LeftOrRight, Box::new(s)), lo..hi),
772-
<lo:@L> "-" <s:GraphSimplifiedSecondary> <hi:@R> => state.node(ast::GraphMatchSimplifiedPattern::Direction(ast::GraphMatchDirection::LeftOrUndirectedOrRight, Box::new(s)), lo..hi),
766+
<lo:@L> "<" <s:GraphSimplifiedSecondary> <hi:@R>
767+
=> state.node(ast::GraphMatchSimplifiedPattern::Direction(ast::GraphMatchSimplifiedPatternDirected{dir: ast::GraphMatchDirection::Left, path: Box::new(s)}), lo..hi),
768+
<lo:@L> "~" <s:GraphSimplifiedSecondary> <hi:@R>
769+
=> state.node(ast::GraphMatchSimplifiedPattern::Direction(ast::GraphMatchSimplifiedPatternDirected{dir: ast::GraphMatchDirection::Undirected, path: Box::new(s)}), lo..hi),
770+
<lo:@L> <s:GraphSimplifiedSecondary> ">" <hi:@R>
771+
=> state.node(ast::GraphMatchSimplifiedPattern::Direction(ast::GraphMatchSimplifiedPatternDirected{dir: ast::GraphMatchDirection::Right, path: Box::new(s)}), lo..hi),
772+
<lo:@L> "<~" <s:GraphSimplifiedSecondary> <hi:@R>
773+
=> state.node(ast::GraphMatchSimplifiedPattern::Direction(ast::GraphMatchSimplifiedPatternDirected{dir: ast::GraphMatchDirection::LeftOrUndirected, path: Box::new(s)}), lo..hi),
774+
<lo:@L> "~" <s:GraphSimplifiedSecondary> ">" <hi:@R>
775+
=> state.node(ast::GraphMatchSimplifiedPattern::Direction(ast::GraphMatchSimplifiedPatternDirected{dir: ast::GraphMatchDirection::UndirectedOrRight, path: Box::new(s)}), lo..hi),
776+
<lo:@L> "<" <s:GraphSimplifiedSecondary> ">" <hi:@R>
777+
=> state.node(ast::GraphMatchSimplifiedPattern::Direction(ast::GraphMatchSimplifiedPatternDirected{dir: ast::GraphMatchDirection::LeftOrRight, path: Box::new(s)}), lo..hi),
778+
<lo:@L> "-" <s:GraphSimplifiedSecondary> <hi:@R>
779+
=> state.node(ast::GraphMatchSimplifiedPattern::Direction(ast::GraphMatchSimplifiedPatternDirected{dir: ast::GraphMatchDirection::LeftOrUndirectedOrRight, path: Box::new(s)}), lo..hi),
773780
}
774781

775782
GraphSimplifiedSecondary: ast::AstNode<ast::GraphMatchSimplifiedPattern> = {
@@ -785,7 +792,7 @@ GraphSimplifiedSecondary: ast::AstNode<ast::GraphMatchSimplifiedPattern> = {
785792
#[inline]
786793
GraphSimplifiedPrimary: ast::AstNode<ast::GraphMatchSimplifiedPattern> = {
787794
<lo:@L> <l:GraphLabelName> <hi:@R> => state.node(ast::GraphMatchSimplifiedPattern::Label(l), lo..hi),
788-
"(" <GraphSimplifiedContents> ")",
795+
<lo:@L> "(" <path:GraphSimplifiedContents> ")" <hi:@R> => state.node(ast::GraphMatchSimplifiedPattern::Sub(Box::new(path)), lo..hi),
789796
}
790797

791798
// 10.10

partiql/tests/pretty.rs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,23 @@ mod graph {
342342
parse!(r#"SELECT a,b FROM (g MATCH (a:A) -[e:E]- (b:B))"#);
343343
parse!(r#"SELECT a,b FROM (g MATCH (a:A) - (b:B))"#);
344344
}
345+
346+
#[test]
347+
fn labels() {
348+
macro_rules! parse {
349+
($q:expr) => {{
350+
parse_test!("labels", $q)
351+
}};
352+
}
353+
354+
parse!(r#"SELECT a,b FROM (g MATCH (a:%) -[e:%]-> (b:%))"#);
355+
parse!(r#"SELECT a,b FROM (g MATCH (a:!Z) -[e:!D]-> (b:!Y))"#);
356+
parse!(r#"SELECT a,b FROM (g MATCH (a:A|Z) -[e:E|D]-> (b:B|Y))"#);
357+
parse!(r#"SELECT a,b FROM (g MATCH (a:A&Z) -[e:E&D]-> (b:B&Y))"#);
358+
359+
parse!(r#"SELECT a,b FROM (g MATCH (a:(A|Z)&!Y) -[e:E&!D]-> (b:%&!(!B)))"#);
360+
}
361+
345362
#[test]
346363
fn quantifiers() {
347364
macro_rules! parse {
@@ -357,6 +374,7 @@ mod graph {
357374
parse!(r#"SELECT a,b FROM (g MATCH (a:A)<-+(b:B))"#);
358375
parse!(r#"SELECT a,b FROM (g MATCH (a:A)~{5,}(b:B))"#);
359376
parse!(r#"SELECT a,b FROM (g MATCH (a:A)-{2,6}(b:B))"#);
377+
parse!(r#"SELECT a,b FROM (g MATCH (a:A) -? (b:B))"#);
360378
}
361379
#[test]
362380
fn patterns() {
@@ -423,6 +441,14 @@ mod graph {
423441
)
424442
WHERE p.title LIKE '%considered harmful%'"#
425443
);
444+
parse!(
445+
r#"SELECT u as banCandidate
446+
FROM (g MATCH
447+
(p:Post Where p.isFlagged = true)
448+
<-[e:createdPost where e.isMobile = true]-
449+
(u)
450+
)"#
451+
);
426452
}
427453
#[test]
428454
fn path_mode() {
@@ -516,6 +542,8 @@ mod graph {
516542
WHERE x.foo = 'bar'
517543
)"
518544
);
545+
parse!("SELECT * FROM (g MATCH ( (x)-[e]->*(y) ) | (z) ~ (q) )");
546+
parse!("SELECT * FROM (g MATCH ( (x)-[e]->*(y) ) |+| (z) ~ (q) )");
519547
}
520548
#[test]
521549
fn shapes() {
@@ -609,6 +637,23 @@ mod graph {
609637
)"
610638
);
611639
}
640+
#[test]
641+
fn simplified() {
642+
macro_rules! parse {
643+
($q:expr) => {{
644+
parse_test!("simplified", $q)
645+
}};
646+
}
647+
parse!("SELECT * FROM (g MATCH <-/ start&begin fin> /- )");
648+
parse!("SELECT * FROM (g MATCH ~/ !begin -fin /~ )");
649+
parse!("SELECT * FROM (g MATCH -/ start <fin /-> )");
650+
parse!("SELECT * FROM (g MATCH <~/ start <~fin |+| begin ~fin> /~ )");
651+
parse!("SELECT * FROM (g MATCH ~/ start <fin> | begin -fin /~> )");
652+
parse!("SELECT * FROM (g MATCH <-/ start? intermediate{1,} fin /-> )");
653+
parse!("SELECT * FROM (g MATCH <-/ start? intermediate* fin /-> )");
654+
parse!("SELECT * FROM (g MATCH <-/ edge+ fin /-> )");
655+
parse!("SELECT * FROM (g MATCH -/ start !(intermediate other){2,3} fin /- )");
656+
}
612657
}
613658

614659
#[test]
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
---
2+
source: partiql/tests/pretty.rs
3+
expression: doc
4+
---
5+
========================================================================================================================================================================================================
6+
SELECT * FROM (g MATCH ( (x)-[e]->*(y) ) | (z) ~ (q) )
7+
========================================================================================================================================================================================================
8+
9+
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
10+
SELECT * FROM (g MATCH ((x) -[e]->* (y)) | (z) ~ (q))
11+
12+
------------------------------------------------------------------------------------------------------------------------
13+
SELECT * FROM (g MATCH ((x) -[e]->* (y)) | (z) ~ (q))
14+
15+
--------------------------------------------------------------------------------
16+
SELECT * FROM (g MATCH ((x) -[e]->* (y)) | (z) ~ (q))
17+
18+
----------------------------------------
19+
SELECT *
20+
FROM (g MATCH ((x) -[e]->* (y)) | (z) ~ (q))
21+
22+
------------------------------
23+
SELECT *
24+
FROM (g MATCH ((x) -[e]->* (y)) | (z) ~ (q))
25+
26+
--------------------
27+
SELECT *
28+
FROM (g MATCH ((x) -[e]->* (y)) | (z) ~ (q))
29+
30+
----------
31+
SELECT *
32+
FROM (g MATCH ((x) -[e]->* (y)) | (z) ~ (q))

0 commit comments

Comments
 (0)