github.com/vescale/zgraph@v0.0.0-20230410094002-959c02d50f95/parser/parser_test.go (about)

     1  package parser_test
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  	"testing"
     7  
     8  	"github.com/stretchr/testify/require"
     9  	"github.com/vescale/zgraph/parser"
    10  	"github.com/vescale/zgraph/parser/format"
    11  )
    12  
    13  type testCase struct {
    14  	src     string
    15  	ok      bool
    16  	restore string
    17  }
    18  
    19  func TestQuery(t *testing.T) {
    20  	table := []testCase{
    21  		{"SELECT label(n) AS lbl, COUNT(*) FROM MATCH (n) GROUP BY lbl ORDER BY COUNT(*) DESC", true, "SELECT LABEL(`n`) AS `lbl`,COUNT(1) FROM MATCH (`n`) GROUP BY `lbl` ORDER BY COUNT(1) DESC"},
    22  		{`SELECT label(n) AS srcLbl, label(e) AS edgeLbl, label(m) AS dstLbl, COUNT(*)
    23  		   FROM MATCH (n) -[e]-> (m)
    24  		GROUP BY srcLbl, edgeLbl, dstLbl
    25  		ORDER BY COUNT(*) DESC`, true, "SELECT LABEL(`n`) AS `srcLbl`,LABEL(`e`) AS `edgeLbl`,LABEL(`m`) AS `dstLbl`,COUNT(1) FROM MATCH (`n`) -[`e`]-> (`m`) GROUP BY `srcLbl`,`edgeLbl`,`dstLbl` ORDER BY COUNT(1) DESC"},
    26  		{"SELECT n.name, n.dob FROM MATCH (n:Person)", true, "SELECT `n`.`name`,`n`.`dob` FROM MATCH (`n`:`Person`)"},
    27  		{"SELECT a.name AS a, b.name AS b FROM MATCH (a:Person) -[e:knows]-> (b:Person)", true, "SELECT `a`.`name` AS `a`,`b`.`name` AS `b` FROM MATCH (`a`:`Person`) -[`e`:`knows`]-> (`b`:`Person`)"},
    28  		{"SELECT n.name, n.dob FROM MATCH (n:Person|University)", true, "SELECT `n`.`name`,`n`.`dob` FROM MATCH (`n`:`Person`|`University`)"},
    29  		{"SELECT n.name, n.dob FROM MATCH (n)", true, "SELECT `n`.`name`,`n`.`dob` FROM MATCH (`n`)"},
    30  		{"SELECT n.name, n.dob FROM MATCH (n) WHERE n.dob > DATE '1995-01-01'", true, "SELECT `n`.`name`,`n`.`dob` FROM MATCH (`n`) WHERE `n`.`dob`>DATE '1995-01-01'"},
    31  		{"SELECT m.name AS name, m.dob AS dob FROM MATCH (n) -[e]-> (m) WHERE n.name = 'Kathrine' AND n.dob <= m.dob", true, "SELECT `m`.`name` AS `name`,`m`.`dob` AS `dob` FROM MATCH (`n`) -[`e`]-> (`m`) WHERE `n`.`name`='Kathrine' AND `n`.`dob`<=`m`.`dob`"},
    32  		{"SELECT p2.name AS friend, u.name AS university FROM MATCH (u:University) <-[:studentOf]- (p1:Person) -[:knows]-> (p2:Person) -[:studentOf]-> (u) WHERE p1.name = 'Lee'", true, "SELECT `p2`.`name` AS `friend`,`u`.`name` AS `university` FROM MATCH (`u`:`University`) <-[:`studentOf`]- (`p1`:`Person`) -[:`knows`]-> (`p2`:`Person`) -[:`studentOf`]-> (`u`) WHERE `p1`.`name`='Lee'"},
    33  		{`SELECT p2.name AS friend, u.name AS university
    34    FROM MATCH (p1:Person) -[:knows]-> (p2:Person)
    35       , MATCH (p1) -[:studentOf]-> (u:University)
    36       , MATCH (p2) -[:studentOf]-> (u)
    37   WHERE p1.name = 'Lee'`, true, "SELECT `p2`.`name` AS `friend`,`u`.`name` AS `university` FROM MATCH (`p1`:`Person`) -[:`knows`]-> (`p2`:`Person`),MATCH (`p1`) -[:`studentOf`]-> (`u`:`University`),MATCH (`p2`) -[:`studentOf`]-> (`u`) WHERE `p1`.`name`='Lee'"},
    38  		{`SELECT p1.name AS p1, p2.name AS p2, p3.name AS p3
    39    FROM MATCH (p1:Person) -[:knows]-> (p2:Person) -[:knows]-> (p3:Person)
    40   WHERE p1.name = 'Lee'`, true, "SELECT `p1`.`name` AS `p1`,`p2`.`name` AS `p2`,`p3`.`name` AS `p3` FROM MATCH (`p1`:`Person`) -[:`knows`]-> (`p2`:`Person`) -[:`knows`]-> (`p3`:`Person`) WHERE `p1`.`name`='Lee'"},
    41  		{`SELECT p1.name AS p1, p2.name AS p2, p3.name AS p3
    42    FROM MATCH (p1:Person) -[:knows]-> (p2:Person) -[:knows]-> (p3:Person)
    43   WHERE p1.name = 'Lee' AND p1 <> p3`, true, "SELECT `p1`.`name` AS `p1`,`p2`.`name` AS `p2`,`p3`.`name` AS `p3` FROM MATCH (`p1`:`Person`) -[:`knows`]-> (`p2`:`Person`) -[:`knows`]-> (`p3`:`Person`) WHERE `p1`.`name`='Lee' AND `p1`<>`p3`"},
    44  		{`SELECT p1.name AS p1, p2.name AS p2, p3.name AS p3
    45    FROM MATCH (p1:Person) -[:knows]-> (p2:Person) -[:knows]-> (p3:Person)
    46   WHERE p1.name = 'Lee' AND ALL_DIFFERENT(p1, p3)`, true, "SELECT `p1`.`name` AS `p1`,`p2`.`name` AS `p2`,`p3`.`name` AS `p3` FROM MATCH (`p1`:`Person`) -[:`knows`]-> (`p2`:`Person`) -[:`knows`]-> (`p3`:`Person`) WHERE `p1`.`name`='Lee' AND ALL_DIFFERENT(`p1`, `p3`)"},
    47  		{`SELECT p1.name AS p1, p2.name AS p2, e1 = e2
    48    FROM MATCH (p1:Person) -[e1:knows]-> (riya:Person)
    49       , MATCH (p2:Person) -[e2:knows]-> (riya)
    50   WHERE riya.name = 'Riya'`, true, "SELECT `p1`.`name` AS `p1`,`p2`.`name` AS `p2`,`e1`=`e2` FROM MATCH (`p1`:`Person`) -[`e1`:`knows`]-> (`riya`:`Person`),MATCH (`p2`:`Person`) -[`e2`:`knows`]-> (`riya`) WHERE `riya`.`name`='Riya'"},
    51  		{"SELECT * FROM MATCH (n) -[e1]- (m) -[e2]- (o)", true, "SELECT * FROM MATCH (`n`) -[`e1`]- (`m`) -[`e2`]- (`o`)"},
    52  		{"SELECT n, m, n.age AS age FROM MATCH (n:Person) -[e:friend_of]-> (m:Person)", true, "SELECT `n`,`m`,`n`.`age` AS `age` FROM MATCH (`n`:`Person`) -[`e`:`friend_of`]-> (`m`:`Person`)"},
    53  		{"SELECT n.age * 2 - 1 AS pivot, n.name, n FROM MATCH (n:Person) -> (m:Car) ORDER BY pivot", true, "SELECT `n`.`age`*2-1 AS `pivot`,`n`.`name`,`n` FROM MATCH (`n`:`Person`) -> (`m`:`Car`) ORDER BY `pivot`"},
    54  		{"SELECT * FROM MATCH (n:Person) -> (m) -> (w), MATCH (n) -> (w) -> (m)", true, "SELECT * FROM MATCH (`n`:`Person`) -> (`m`) -> (`w`),MATCH (`n`) -> (`w`) -> (`m`)"},
    55  		{"SELECT n, m, w FROM MATCH (n:Person) -> (m) -> (w), MATCH (n) -> (w) -> (m)", true, "SELECT `n`,`m`,`w` FROM MATCH (`n`:`Person`) -> (`m`) -> (`w`),MATCH (`n`) -> (`w`) -> (`m`)"},
    56  		{`SELECT p.first_name, p.last_name
    57      FROM MATCH (p:Person) ON my_graph
    58  ORDER BY p.first_name, p.last_name`, true, "SELECT `p`.`first_name`,`p`.`last_name` FROM MATCH (`p`:`Person`) ON `my_graph` ORDER BY `p`.`first_name`,`p`.`last_name`"},
    59  		{"SELECT p.first_name, p.last_name FROM MATCH (p:Person) ORDER BY p.first_name, p.last_name", true, "SELECT `p`.`first_name`,`p`.`last_name` FROM MATCH (`p`:`Person`) ORDER BY `p`.`first_name`,`p`.`last_name`"},
    60  		{"SELECT * FROM MATCH (n) -[e1]-> (m1), MATCH (n) -[e2]-> (m2)", true, "SELECT * FROM MATCH (`n`) -[`e1`]-> (`m1`),MATCH (`n`) -[`e2`]-> (`m2`)"},
    61  		{"SELECT * FROM MATCH (n1) -[e1]-> (n2) -[e2]-> (n3) -[e3]-> (n4)", true, "SELECT * FROM MATCH (`n1`) -[`e1`]-> (`n2`) -[`e2`]-> (`n3`) -[`e3`]-> (`n4`)"},
    62  		{"SELECT * FROM MATCH (n1) -[e1]-> (n2), MATCH (n2) -[e2]-> (n3), MATCH (n3) -[e3]-> (n4)", true, "SELECT * FROM MATCH (`n1`) -[`e1`]-> (`n2`),MATCH (`n2`) -[`e2`]-> (`n3`),MATCH (`n3`) -[`e3`]-> (`n4`)"},
    63  		{"SELECT * FROM MATCH (n1) -[e1]-> (n2) <-[e2]- (n3)", true, "SELECT * FROM MATCH (`n1`) -[`e1`]-> (`n2`) <-[`e2`]- (`n3`)"},
    64  		{"SELECT * FROM MATCH (n1) -> (m1), MATCH (n2) -> (m2)", true, "SELECT * FROM MATCH (`n1`) -> (`m1`),MATCH (`n2`) -> (`m2`)"},
    65  		{"SELECT * FROM MATCH (x:Person) -[e:likes|knows]-> (y:Person)", true, "SELECT * FROM MATCH (`x`:`Person`) -[`e`:`likes`|`knows`]-> (`y`:`Person`)"},
    66  		{"SELECT * FROM MATCH (:Person) -[:likes|knows]-> (:Person)", true, "SELECT * FROM MATCH (:`Person`) -[:`likes`|`knows`]-> (:`Person`)"},
    67  		{"SELECT y.name FROM MATCH (x) -> (y) WHERE x.name = 'Jake' AND y.age > 25", true, "SELECT `y`.`name` FROM MATCH (`x`) -> (`y`) WHERE `x`.`name`='Jake' AND `y`.`age`>25"},
    68  		{"SELECT y.name FROM MATCH (x) -> (y) WHERE y.age > 25 AND x.name = 'Jake'", true, "SELECT `y`.`name` FROM MATCH (`x`) -> (`y`) WHERE `y`.`age`>25 AND `x`.`name`='Jake'"},
    69  		{"SELECT n.first_name, COUNT(*), AVG(n.age) FROM MATCH (n:Person) GROUP BY n.first_name", true, "SELECT `n`.`first_name`,COUNT(1),AVG(`n`.`age`) FROM MATCH (`n`:`Person`) GROUP BY `n`.`first_name`"},
    70  		{"SELECT n.first_name, n.last_name, COUNT(*) FROM MATCH (n:Person) GROUP BY n.first_name, n.last_name", true, "SELECT `n`.`first_name`,`n`.`last_name`,COUNT(1) FROM MATCH (`n`:`Person`) GROUP BY `n`.`first_name`,`n`.`last_name`"},
    71  		{`SELECT n.prop1, n.prop2, COUNT(*)
    72      FROM MATCH (n)
    73  GROUP BY n.prop1, n.prop2
    74    HAVING n.prop1 IS NOT NULL AND n.prop2 IS NOT NULL`, true, "SELECT `n`.`prop1`,`n`.`prop2`,COUNT(1) FROM MATCH (`n`) GROUP BY `n`.`prop1`,`n`.`prop2` HAVING `n`.`prop1` IS NOT NULL AND `n`.`prop2` IS NOT NULL"},
    75  		{" SELECT n.age, COUNT(*) FROM MATCH (n) GROUP BY n.age ORDER BY n.age", true, "SELECT `n`.`age`,COUNT(1) FROM MATCH (`n`) GROUP BY `n`.`age` ORDER BY `n`.`age`"},
    76  		{`SELECT label(owner),
    77  		      COUNT(*) AS numTransactions,
    78  		      SUM(out.amount) AS totalOutgoing,
    79  		      LISTAGG(out.amount, ', ') AS amounts
    80  		 FROM MATCH (a:Account) -[:owner]-> (owner:Person|Company)
    81  		    , MATCH (a) -[out:transaction]-> (:Account)
    82  		GROUP BY label(owner)
    83  		ORDER BY label(owner)`, true, "SELECT LABEL(`owner`),COUNT(1) AS `numTransactions`,SUM(`out`.`amount`) AS `totalOutgoing`,LISTAGG(`out`.`amount`, ', ') AS `amounts` FROM MATCH (`a`:`Account`) -[:`owner`]-> (`owner`:`Person`|`Company`),MATCH (`a`) -[`out`:`transaction`]-> (:`Account`) GROUP BY LABEL(`owner`) ORDER BY LABEL(`owner`)"},
    84  		{`SELECT COUNT(*) AS numTransactions,
    85         SUM(out.amount) AS totalOutgoing,
    86         LISTAGG(out.amount, ', ') AS amounts
    87    FROM MATCH (a:Account) -[:owner]-> (owner:Person|Company)
    88       , MATCH (a) -[out:transaction]-> (:Account)`, true, "SELECT COUNT(1) AS `numTransactions`,SUM(`out`.`amount`) AS `totalOutgoing`,LISTAGG(`out`.`amount`, ', ') AS `amounts` FROM MATCH (`a`:`Account`) -[:`owner`]-> (`owner`:`Person`|`Company`),MATCH (`a`) -[`out`:`transaction`]-> (:`Account`)"},
    89  		{"SELECT COUNT(*) FROM MATCH (m:Person)", true, "SELECT COUNT(1) FROM MATCH (`m`:`Person`)"},
    90  		{"SELECT AVG(DISTINCT m.age) FROM MATCH (m:Person)", true, "SELECT AVG(DISTINCT `m`.`age`) FROM MATCH (`m`:`Person`)"},
    91  		{"SELECT n.name FROM MATCH (n) -[:has_friend]-> (m) GROUP BY n HAVING COUNT(m) > 10", true, "SELECT `n`.`name` FROM MATCH (`n`) -[:`has_friend`]-> (`m`) GROUP BY `n` HAVING COUNT(`m`)>10"},
    92  		{"SELECT n.name FROM MATCH (n:Person) ORDER BY n.age ASC", true, "SELECT `n`.`name` FROM MATCH (`n`:`Person`) ORDER BY `n`.`age` ASC"},
    93  		{"SELECT f.name FROM MATCH (f:Person) ORDER BY f.age ASC, f.salary DESC", true, "SELECT `f`.`name` FROM MATCH (`f`:`Person`) ORDER BY `f`.`age` ASC,`f`.`salary` DESC"},
    94  		{"SELECT n FROM MATCH (n) LIMIT 10 OFFSET 5", true, "SELECT `n` FROM MATCH (`n`) LIMIT 5,10"},
    95  		{`SELECT a.number AS a,
    96         b.number AS b,
    97         COUNT(e) AS pathLength,
    98         ARRAY_AGG(e.amount) AS amounts
    99    FROM MATCH ANY SHORTEST (a:Account) -[e:transaction]->* (b:Account)
   100   WHERE a.number = 10039 AND b.number = 2090`, true, "SELECT `a`.`number` AS `a`,`b`.`number` AS `b`,COUNT(`e`) AS `pathLength`,ARRAY_AGG(`e`.`amount`) AS `amounts` FROM MATCH ANY SHORTEST (`a`:`Account`) -[`e`:`transaction`]->* (`b`:`Account`) WHERE `a`.`number`=10039 AND `b`.`number`=2090"},
   101  		{`SELECT dst.number
   102      FROM MATCH ANY (src:Account) -[e]->+ (dst:Account)
   103     WHERE src.number = 8021
   104  ORDER BY dst.number`, true, "SELECT `dst`.`number` FROM MATCH ANY (`src`:`Account`) -[`e`]->+ (`dst`:`Account`) WHERE `src`.`number`=8021 ORDER BY `dst`.`number`"},
   105  		{`SELECT dst.number, LISTAGG(e.amount, ' + ') || ' = ', SUM(e.amount)
   106      FROM MATCH ANY (src:Account) -[e]->+ (dst:Account)
   107     WHERE src.number = 8021
   108  ORDER BY dst.number`, true, "SELECT `dst`.`number`,LISTAGG(`e`.`amount`, ' + ')||' = ',SUM(`e`.`amount`) FROM MATCH ANY (`src`:`Account`) -[`e`]->+ (`dst`:`Account`) WHERE `src`.`number`=8021 ORDER BY `dst`.`number`"},
   109  		{`SELECT c.name
   110    FROM MATCH (c:Class) -/:subclass_of*/-> (arrayList:Class)
   111   WHERE arrayList.name = 'ArrayList'`, true, "SELECT `c`.`name` FROM MATCH (`c`:`Class`) -/:`subclass_of`*/-> (`arrayList`:`Class`) WHERE `arrayList`.`name`='ArrayList'"},
   112  		{`SELECT y.name
   113    FROM MATCH (x:Person) -/:likes*/-> (y)
   114   WHERE x.name = 'Amy'`, true, "SELECT `y`.`name` FROM MATCH (`x`:`Person`) -/:`likes`*/-> (`y`) WHERE `x`.`name`='Amy'"},
   115  		{`SELECT y.name
   116    FROM MATCH (x:Person) -/:likes+/-> (y)
   117   WHERE x.name = 'Amy'`, true, "SELECT `y`.`name` FROM MATCH (`x`:`Person`) -/:`likes`+/-> (`y`) WHERE `x`.`name`='Amy'"},
   118  		{`SELECT y.name
   119    FROM MATCH (x:Person) -/:knows+/-> (y)
   120   WHERE x.name = 'Judith'`, true, "SELECT `y`.`name` FROM MATCH (`x`:`Person`) -/:`knows`+/-> (`y`) WHERE `x`.`name`='Judith'"},
   121  		{`SELECT y.name
   122    FROM MATCH (x:Person) -/:knows?/-> (y)
   123   WHERE x.name = 'Judith'`, true, "SELECT `y`.`name` FROM MATCH (`x`:`Person`) -/:`knows`?/-> (`y`) WHERE `x`.`name`='Judith'"},
   124  		{`SELECT y.name
   125    FROM MATCH (x:Person) -/:likes{2}/-> (y)
   126   WHERE x.name = 'Amy'`, true, "SELECT `y`.`name` FROM MATCH (`x`:`Person`) -/:`likes`{2}/-> (`y`) WHERE `x`.`name`='Amy'"},
   127  		{`SELECT y.name
   128    FROM MATCH (x:Person) -/:likes{2,}/-> (y)
   129   WHERE x.name = 'Amy'`, true, "SELECT `y`.`name` FROM MATCH (`x`:`Person`) -/:`likes`{2,}/-> (`y`) WHERE `x`.`name`='Amy'"},
   130  		{`SELECT y.name
   131    FROM MATCH (x:Person) -/:likes{1,2}/-> (y)
   132   WHERE x.name = 'Amy'`, true, "SELECT `y`.`name` FROM MATCH (`x`:`Person`) -/:`likes`{1,2}/-> (`y`) WHERE `x`.`name`='Amy'"},
   133  		{`SELECT y.name
   134    FROM MATCH (x:Person) -/:knows{,2}/-> (y)
   135   WHERE x.name = 'Judith'`, true, "SELECT `y`.`name` FROM MATCH (`x`:`Person`) -/:`knows`{,2}/-> (`y`) WHERE `x`.`name`='Judith'"},
   136  		{`SELECT src, SUM(e.weight), dst
   137    FROM MATCH ANY SHORTEST (src) -[e]->* (dst)
   138   WHERE src.age < dst.age`, true, "SELECT `src`,SUM(`e`.`weight`),`dst` FROM MATCH ANY SHORTEST (`src`) -[`e`]->* (`dst`) WHERE `src`.`age`<`dst`.`age`"},
   139  		{`SELECT src, ARRAY_AGG(e.weight), dst
   140    FROM MATCH ANY SHORTEST (src) (-[e]-> WHERE e.weight > 10)* (dst)`, true, "SELECT `src`,ARRAY_AGG(`e`.`weight`),`dst` FROM MATCH ANY SHORTEST (`src`) (-[`e`]-> WHERE `e`.`weight`>10)* (`dst`)"},
   141  		{`SELECT src, ARRAY_AGG(e.weight), dst
   142    FROM MATCH ANY SHORTEST (src) -[e]->* (dst) WHERE SUM(e.cost) < 100`, true, "SELECT `src`,ARRAY_AGG(`e`.`weight`),`dst` FROM MATCH ANY SHORTEST (`src`) -[`e`]->* (`dst`) WHERE SUM(`e`.`cost`)<100"},
   143  		{`SELECT LISTAGG(e.amount, ' + ') || ' = ', SUM(e.amount) AS total_amount
   144      FROM MATCH ALL SHORTEST (a:Account) -[e:transaction]->* (b:Account)
   145     WHERE a.number = 10039 AND b.number = 2090
   146  ORDER BY total_amount`, true, "SELECT LISTAGG(`e`.`amount`, ' + ')||' = ',SUM(`e`.`amount`) AS `total_amount` FROM MATCH ALL SHORTEST (`a`:`Account`) -[`e`:`transaction`]->* (`b`:`Account`) WHERE `a`.`number`=10039 AND `b`.`number`=2090 ORDER BY `total_amount`"},
   147  		{`SELECT src, SUM(e.weight), dst
   148    FROM MATCH TOP 3 SHORTEST (src) -[e]->* (dst)
   149   WHERE src.age < dst.age`, true, "SELECT `src`,SUM(`e`.`weight`),`dst` FROM MATCH TOP 3 SHORTEST (`src`) -[`e`]->* (`dst`) WHERE `src`.`age`<`dst`.`age`"},
   150  		{`SELECT src, ARRAY_AGG(e.weight), ARRAY_AGG(v1.age), ARRAY_AGG(v2.age), dst
   151    FROM MATCH TOP 3 SHORTEST (src) ((v1) -[e]-> (v2))* (dst)
   152   WHERE src.age < dst.age`, true, "SELECT `src`,ARRAY_AGG(`e`.`weight`),ARRAY_AGG(`v1`.`age`),ARRAY_AGG(`v2`.`age`),`dst` FROM MATCH TOP 3 SHORTEST (`src`) ((`v1`) -[`e`]-> (`v2`))* (`dst`) WHERE `src`.`age`<`dst`.`age`"},
   153  		{`SELECT ARRAY_AGG(e1.weight), ARRAY_AGG(e2.weight)
   154    FROM MATCH (start) -> (src)
   155       , MATCH TOP 3 SHORTEST (src) (-[e1]->)* (mid)
   156       , MATCH ANY SHORTEST (mid) (-[e2]->)* (dst)
   157       , MATCH (dst) -> (end)`, true, "SELECT ARRAY_AGG(`e1`.`weight`),ARRAY_AGG(`e2`.`weight`) FROM MATCH (`start`) -> (`src`),MATCH TOP 3 SHORTEST (`src`) -[`e1`]->* (`mid`),MATCH ANY SHORTEST (`mid`) -[`e2`]->* (`dst`),MATCH (`dst`) -> (`end`)"},
   158  		{`SELECT COUNT(e) AS num_hops
   159         , SUM(e.amount) AS total_amount
   160         , ARRAY_AGG(e.amount) AS amounts_along_path
   161      FROM MATCH TOP 7 SHORTEST (a:Account) -[e:transaction]->* (b:Account)
   162     WHERE a.number = 10039 AND a = b
   163  ORDER BY num_hops, total_amount`, true, "SELECT COUNT(`e`) AS `num_hops`,SUM(`e`.`amount`) AS `total_amount`,ARRAY_AGG(`e`.`amount`) AS `amounts_along_path` FROM MATCH TOP 7 SHORTEST (`a`:`Account`) -[`e`:`transaction`]->* (`b`:`Account`) WHERE `a`.`number`=10039 AND `a`=`b` ORDER BY `num_hops`,`total_amount`"},
   164  		{`SELECT COUNT(e) AS num_hops
   165         , SUM(e.amount) AS total_amount
   166         , ARRAY_AGG(e.amount) AS amounts_along_path
   167      FROM MATCH TOP 7 SHORTEST (a:Account) -[e:transaction]->* (b:Account)
   168     WHERE a.number = 10039 AND a = b AND COUNT(DISTINCT e) = COUNT(e) AND COUNT(e) > 0
   169  ORDER BY num_hops, total_amount`, true, "SELECT COUNT(`e`) AS `num_hops`,SUM(`e`.`amount`) AS `total_amount`,ARRAY_AGG(`e`.`amount`) AS `amounts_along_path` FROM MATCH TOP 7 SHORTEST (`a`:`Account`) -[`e`:`transaction`]->* (`b`:`Account`) WHERE `a`.`number`=10039 AND `a`=`b` AND COUNT(DISTINCT `e`)=COUNT(`e`) AND COUNT(`e`)>0 ORDER BY `num_hops`,`total_amount`"},
   170  		{`SELECT COUNT(e) AS num_hops
   171       , SUM(e.amount) AS total_amount
   172       , ARRAY_AGG(e.amount) AS amounts_along_path
   173    FROM MATCH ANY CHEAPEST (a:Account) (-[e:transaction]-> COST e.amount)* (b:Account)
   174   WHERE a.number = 10039 AND b.number = 2090`, true, "SELECT COUNT(`e`) AS `num_hops`,SUM(`e`.`amount`) AS `total_amount`,ARRAY_AGG(`e`.`amount`) AS `amounts_along_path` FROM MATCH ANY CHEAPEST (`a`:`Account`) (-[`e`:`transaction`]-> COST `e`.`amount`)* (`b`:`Account`) WHERE `a`.`number`=10039 AND `b`.`number`=2090"},
   175  		{`SELECT COUNT(e) AS num_hops
   176       , SUM(e.amount) AS total_amount
   177       , ARRAY_AGG(e.amount) AS amounts_along_path
   178    FROM MATCH ANY CHEAPEST (a:Account) (-[e:transaction]- COST e.amount)* (b:Account)
   179   WHERE a.number = 10039 AND b.number = 2090`, true, "SELECT COUNT(`e`) AS `num_hops`,SUM(`e`.`amount`) AS `total_amount`,ARRAY_AGG(`e`.`amount`) AS `amounts_along_path` FROM MATCH ANY CHEAPEST (`a`:`Account`) (-[`e`:`transaction`]- COST `e`.`amount`)* (`b`:`Account`) WHERE `a`.`number`=10039 AND `b`.`number`=2090"},
   180  		{`SELECT COUNT(e) AS num_hops
   181       , SUM(e.amount) AS total_amount
   182       , ARRAY_AGG(e.amount) AS amounts_along_path
   183    FROM MATCH ANY CHEAPEST (p1:Person) (-[e:owner|transaction]-
   184                                        COST CASE
   185                                               WHEN e.amount IS NULL THEN 1
   186                                               ELSE e.amount
   187                                             END)* (p2:Person)
   188   WHERE p1.name = 'Nikita' AND p2.name = 'Liam'`, true, "SELECT COUNT(`e`) AS `num_hops`,SUM(`e`.`amount`) AS `total_amount`,ARRAY_AGG(`e`.`amount`) AS `amounts_along_path` FROM MATCH ANY CHEAPEST (`p1`:`Person`) (-[`e`:`owner`|`transaction`]- COST CASE WHEN `e`.`amount` IS NULL THEN 1 ELSE `e`.`amount` END)* (`p2`:`Person`) WHERE `p1`.`name`='Nikita' AND `p2`.`name`='Liam'"},
   189  		{`SELECT COUNT(e) AS num_hops
   190         , SUM(e.amount) AS total_amount
   191         , ARRAY_AGG(e.amount) AS amounts_along_path
   192      FROM MATCH TOP 3 CHEAPEST (a:Account) (-[e:transaction]-> COST e.amount)* (a)
   193     WHERE a.number = 10039
   194  ORDER BY total_amount`, true, "SELECT COUNT(`e`) AS `num_hops`,SUM(`e`.`amount`) AS `total_amount`,ARRAY_AGG(`e`.`amount`) AS `amounts_along_path` FROM MATCH TOP 3 CHEAPEST (`a`:`Account`) (-[`e`:`transaction`]-> COST `e`.`amount`)* (`a`) WHERE `a`.`number`=10039 ORDER BY `total_amount`"},
   195  		{`SELECT COUNT(e) AS num_hops
   196         , ARRAY_AGG( CASE label(n_x)
   197                        WHEN 'Person' THEN n_x.name
   198                        WHEN 'Company' THEN n_x.name
   199                        WHEN 'Account' THEN CAST(n_x.number AS STRING)
   200                      END ) AS names_or_numbers
   201         , SUM( CASE label(n_x) WHEN 'Person' THEN 8 ELSE 1 END ) AS total_cost
   202      FROM MATCH TOP 4 CHEAPEST
   203            (a:Account)
   204              (-[e]- (n_x) COST CASE label(n_x) WHEN 'Person' THEN 3 ELSE 1 END)*
   205                (c:Company)
   206     WHERE a.number = 10039 AND c.name = 'Oracle'
   207  ORDER BY total_cost`, true, "SELECT COUNT(`e`) AS `num_hops`,ARRAY_AGG(CASE LABEL(`n_x`) WHEN 'Person' THEN `n_x`.`name` WHEN 'Company' THEN `n_x`.`name` WHEN 'Account' THEN CAST(`n_x`.`number` AS STRING) END) AS `names_or_numbers`,SUM(CASE LABEL(`n_x`) WHEN 'Person' THEN 8 ELSE 1 END) AS `total_cost` FROM MATCH TOP 4 CHEAPEST (`a`:`Account`) (-[`e`]- (`n_x`) COST CASE LABEL(`n_x`) WHEN 'Person' THEN 3 ELSE 1 END)* (`c`:`Company`) WHERE `a`.`number`=10039 AND `c`.`name`='Oracle' ORDER BY `total_cost`"},
   208  		{`SELECT LISTAGG(e.amount, ' + ') || ' = ', SUM(e.amount) AS total_amount
   209      FROM MATCH ALL (a:Account) -[e:transaction]->{,7} (b:Account)
   210     WHERE a.number = 10039 AND b.number = 2090
   211  ORDER BY total_amount`, true, "SELECT LISTAGG(`e`.`amount`, ' + ')||' = ',SUM(`e`.`amount`) AS `total_amount` FROM MATCH ALL (`a`:`Account`) -[`e`:`transaction`]->{,7} (`b`:`Account`) WHERE `a`.`number`=10039 AND `b`.`number`=2090 ORDER BY `total_amount`"},
   212  		{`SELECT SUM(COUNT(e)) AS sumOfPathLengths
   213    FROM MATCH ANY SHORTEST (a:Account) -[e:transaction]->* (b:Account)
   214   WHERE a.number = 10039 AND (b.number = 1001 OR b.number = 2090)`, true, "SELECT SUM(COUNT(`e`)) AS `sumOfPathLengths` FROM MATCH ANY SHORTEST (`a`:`Account`) -[`e`:`transaction`]->* (`b`:`Account`) WHERE `a`.`number`=10039 AND (`b`.`number`=1001 OR `b`.`number`=2090)"},
   215  		{`SELECT b.number AS b,
   216           COUNT(e) AS pathLength,
   217           ARRAY_AGG(e.amount) AS transactions
   218      FROM MATCH ANY SHORTEST (a:Account) -[e:transaction]->* (b:Account)
   219     WHERE a.number = 10039 AND
   220           (b.number = 8021 OR b.number = 1001 OR b.number = 2090) AND
   221           COUNT(e) <= 2
   222  ORDER BY pathLength`, true, "SELECT `b`.`number` AS `b`,COUNT(`e`) AS `pathLength`,ARRAY_AGG(`e`.`amount`) AS `transactions` FROM MATCH ANY SHORTEST (`a`:`Account`) -[`e`:`transaction`]->* (`b`:`Account`) WHERE `a`.`number`=10039 AND (`b`.`number`=8021 OR `b`.`number`=1001 OR `b`.`number`=2090) AND COUNT(`e`)<=2 ORDER BY `pathLength`"},
   223  		{`SELECT COUNT(e) AS pathLength,
   224           COUNT(*) AS cnt
   225      FROM MATCH ANY SHORTEST (a:Account) -[e:transaction]->* (b:Account)
   226     WHERE (a.number = 10039 OR a.number = 8021) AND
   227           (b.number = 1001 OR b.number = 2090)
   228  GROUP BY COUNT(e)
   229  ORDER BY pathLength`, true, "SELECT COUNT(`e`) AS `pathLength`,COUNT(1) AS `cnt` FROM MATCH ANY SHORTEST (`a`:`Account`) -[`e`:`transaction`]->* (`b`:`Account`) WHERE (`a`.`number`=10039 OR `a`.`number`=8021) AND (`b`.`number`=1001 OR `b`.`number`=2090) GROUP BY COUNT(`e`) ORDER BY `pathLength`"},
   230  		{`SELECT fof.name, COUNT(friend) AS num_common_friends
   231    FROM MATCH (p:Person) -[:has_friend]-> (friend:Person) -[:has_friend]-> (fof:Person)
   232   WHERE NOT EXISTS ( SELECT * FROM MATCH (p) -[:has_friend]-> (fof) )`, true, "SELECT `fof`.`name`,COUNT(`friend`) AS `num_common_friends` FROM MATCH (`p`:`Person`) -[:`has_friend`]-> (`friend`:`Person`) -[:`has_friend`]-> (`fof`:`Person`) WHERE NOT EXISTS (SELECT * FROM MATCH (`p`) -[:`has_friend`]-> (`fof`))"},
   233  		{`SELECT a.name
   234    FROM MATCH (a)
   235   WHERE a.age > ( SELECT AVG(b.age) FROM MATCH (a) -[:friendOf]-> (b) )`, true, "SELECT `a`.`name` FROM MATCH (`a`) WHERE `a`.`age`>(SELECT AVG(`b`.`age`) FROM MATCH (`a`) -[:`friendOf`]-> (`b`))"},
   236  		{`SELECT p.name AS name
   237         , ( SELECT SUM(t.amount)
   238               FROM MATCH (a) <-[t:transaction]- (:Account)
   239                       ON financial_transactions
   240           ) AS sum_incoming
   241         , ( SELECT SUM(t.amount)
   242               FROM MATCH (a) -[t:transaction]-> (:Account)
   243                       ON financial_transactions
   244           ) AS sum_outgoing
   245         , ( SELECT COUNT(DISTINCT p2)
   246               FROM MATCH (a) -[t:transaction]- (:Account) -[:owner]-> (p2:Person)
   247                       ON financial_transactions
   248              WHERE p2 <> p
   249           ) AS num_persons_transacted_with
   250         , ( SELECT COUNT(DISTINCT c)
   251               FROM MATCH (a) -[t:transaction]- (:Account) -[:owner]-> (c:Company)
   252                       ON financial_transactions
   253           ) AS num_companies_transacted_with
   254      FROM MATCH (p:Person) <-[:owner]- (a:Account) ON financial_transactions
   255  ORDER BY sum_outgoing + sum_incoming DESC`, true, "SELECT `p`.`name` AS `name`,(SELECT SUM(`t`.`amount`) FROM MATCH (`a`) <-[`t`:`transaction`]- (:`Account`) ON `financial_transactions`) AS `sum_incoming`,(SELECT SUM(`t`.`amount`) FROM MATCH (`a`) -[`t`:`transaction`]-> (:`Account`) ON `financial_transactions`) AS `sum_outgoing`,(SELECT COUNT(DISTINCT `p2`) FROM MATCH (`a`) -[`t`:`transaction`]- (:`Account`) -[:`owner`]-> (`p2`:`Person`) ON `financial_transactions` WHERE `p2`<>`p`) AS `num_persons_transacted_with`,(SELECT COUNT(DISTINCT `c`) FROM MATCH (`a`) -[`t`:`transaction`]- (:`Account`) -[:`owner`]-> (`c`:`Company`) ON `financial_transactions`) AS `num_companies_transacted_with` FROM MATCH (`p`:`Person`) <-[:`owner`]- (`a`:`Account`) ON `financial_transactions` ORDER BY `sum_outgoing`+`sum_incoming` DESC"},
   256  		{`SELECT p.name AS name
   257         , ( SELECT SUM(t.amount)
   258               FROM MATCH (a) <-[t:transaction]- (:Account)
   259           ) AS sum_incoming
   260         , ( SELECT SUM(t.amount)
   261               FROM MATCH (a) -[t:transaction]-> (:Account)
   262           ) AS sum_outgoing
   263         , ( SELECT COUNT(DISTINCT p2)
   264               FROM MATCH (a) -[t:transaction]- (:Account) -[:owner]-> (p2:Person)
   265              WHERE p2 <> p
   266           ) AS num_persons_transacted_with
   267         , ( SELECT COUNT(DISTINCT c)
   268               FROM MATCH (a) -[t:transaction]- (:Account) -[:owner]-> (c:Company)
   269           ) AS num_companies_transacted_with
   270      FROM MATCH (p:Person) <-[:owner]- (a:Account)
   271  ORDER BY sum_outgoing + sum_incoming DESC`, true, "SELECT `p`.`name` AS `name`,(SELECT SUM(`t`.`amount`) FROM MATCH (`a`) <-[`t`:`transaction`]- (:`Account`)) AS `sum_incoming`,(SELECT SUM(`t`.`amount`) FROM MATCH (`a`) -[`t`:`transaction`]-> (:`Account`)) AS `sum_outgoing`,(SELECT COUNT(DISTINCT `p2`) FROM MATCH (`a`) -[`t`:`transaction`]- (:`Account`) -[:`owner`]-> (`p2`:`Person`) WHERE `p2`<>`p`) AS `num_persons_transacted_with`,(SELECT COUNT(DISTINCT `c`) FROM MATCH (`a`) -[`t`:`transaction`]- (:`Account`) -[:`owner`]-> (`c`:`Company`)) AS `num_companies_transacted_with` FROM MATCH (`p`:`Person`) <-[:`owner`]- (`a`:`Account`) ORDER BY `sum_outgoing`+`sum_incoming` DESC"},
   272  		{`PATH has_parent AS () -[:has_father|has_mother]-> (:Person)
   273  SELECT ancestor.name
   274    FROM MATCH (p1:Person) -/:has_parent+/-> (ancestor)
   275       , MATCH (p2:Person) -/:has_parent+/-> (ancestor)
   276   WHERE p1.name = 'Mario'
   277     AND p2.name = 'Luigi'`, true, "PATH `has_parent` AS () -[:`has_father`|`has_mother`]-> (:`Person`) SELECT `ancestor`.`name` FROM MATCH (`p1`:`Person`) -/:`has_parent`+/-> (`ancestor`),MATCH (`p2`:`Person`) -/:`has_parent`+/-> (`ancestor`) WHERE `p1`.`name`='Mario' AND `p2`.`name`='Luigi'"},
   278  		{`PATH connects_to AS (:Generator) -[:has_connector]-> (c:Connector) <-[:has_connector]- (:Generator)
   279                  WHERE c.status = 'OPERATIONAL'
   280  SELECT generatorA.location, generatorB.location
   281    FROM MATCH (generatorA) -/:connects_to+/-> (generatorB)`, true, "PATH `connects_to` AS (:`Generator`) -[:`has_connector`]-> (`c`:`Connector`) <-[:`has_connector`]- (:`Generator`) WHERE `c`.`status`='OPERATIONAL' SELECT `generatorA`.`location`,`generatorB`.`location` FROM MATCH (`generatorA`) -/:`connects_to`+/-> (`generatorB`)"},
   282  		{`PATH macro1 AS (v1:Generator) -[e1:has_connector]-> (v2:Connector)
   283  SELECT COUNT(*)
   284  FROM MATCH (generatorA) <-/:macro1+/- (generatorB)
   285  WHERE generatorA.name = 'AEH382'`, true, "PATH `macro1` AS (`v1`:`Generator`) -[`e1`:`has_connector`]-> (`v2`:`Connector`) SELECT COUNT(1) FROM MATCH (`generatorA`) <-/:`macro1`+/- (`generatorB`) WHERE `generatorA`.`name`='AEH382'"},
   286  		{`PATH macro1 AS (v2:Connector) <-[e1:has_connector]- (v1:Generator)
   287  SELECT COUNT(*)
   288  FROM MATCH (generatorA) -/:macro1+/-> (generatorB)
   289  WHERE generatorA.name = 'AEH382'`, true, "PATH `macro1` AS (`v2`:`Connector`) <-[`e1`:`has_connector`]- (`v1`:`Generator`) SELECT COUNT(1) FROM MATCH (`generatorA`) -/:`macro1`+/-> (`generatorB`) WHERE `generatorA`.`name`='AEH382'"},
   290  	}
   291  	RunTest(t, table)
   292  }
   293  
   294  func TestLiteral(t *testing.T) {
   295  	table := []testCase{
   296  		{"SELECT DATE '2017-01-01' FROM MATCH ()", true, "SELECT DATE '2017-01-01' FROM MATCH ()"},
   297  		{"SELECT TIME '12:34:56' FROM MATCH ()", true, "SELECT TIME '12:34:56' FROM MATCH ()"},
   298  		{"SELECT TIME '12:34:56+01:00' FROM MATCH ()", true, "SELECT TIME '12:34:56+01:00' FROM MATCH ()"},
   299  		{"SELECT TIME '12:34:56-07:00' FROM MATCH ()", true, "SELECT TIME '12:34:56-07:00' FROM MATCH ()"},
   300  		{"SELECT TIMESTAMP '2017-01-01 12:34:56' FROM MATCH ()", true, "SELECT TIMESTAMP '2017-01-01 12:34:56' FROM MATCH ()"},
   301  		{"SELECT TIMESTAMP '2017-01-01 12:34:56+01:00' FROM MATCH ()", true, "SELECT TIMESTAMP '2017-01-01 12:34:56+01:00' FROM MATCH ()"},
   302  		{"SELECT TIMESTAMP '2017-01-01 12:34:56-07:00' FROM MATCH ()", true, "SELECT TIMESTAMP '2017-01-01 12:34:56-07:00' FROM MATCH ()"},
   303  		{"SELECT INTERVAL 1 YEAR FROM MATCH ()", true, "SELECT INTERVAL 1 YEAR FROM MATCH ()"},
   304  		{"SELECT INTERVAL 2 MONTH FROM MATCH ()", true, "SELECT INTERVAL 2 MONTH FROM MATCH ()"},
   305  		{"SELECT INTERVAL 3 DAY FROM MATCH ()", true, "SELECT INTERVAL 3 DAY FROM MATCH ()"},
   306  		{"SELECT INTERVAL 4 HOUR FROM MATCH ()", true, "SELECT INTERVAL 4 HOUR FROM MATCH ()"},
   307  		{"SELECT INTERVAL 5 MINUTE FROM MATCH ()", true, "SELECT INTERVAL 5 MINUTE FROM MATCH ()"},
   308  	}
   309  	RunTest(t, table)
   310  }
   311  
   312  func TestDDL(t *testing.T) {
   313  	table := []testCase{
   314  		{
   315  			"CREATE GRAPH g1",
   316  			true,
   317  			"CREATE GRAPH `g1`",
   318  		},
   319  		{
   320  			"DROP GRAPH g1",
   321  			true,
   322  			"DROP GRAPH `g1`",
   323  		},
   324  		{
   325  			`CREATE LABEL l`,
   326  			true,
   327  			"CREATE LABEL `l`",
   328  		},
   329  		{
   330  			`Drop LABEL l`,
   331  			true,
   332  			"DROP LABEL `l`",
   333  		},
   334  		{
   335  			`show graphs`,
   336  			true,
   337  			"SHOW GRAPHS",
   338  		},
   339  		{
   340  			`show labels`,
   341  			true,
   342  			"SHOW LABELS",
   343  		},
   344  		{
   345  			`show labels in g1`,
   346  			true,
   347  			"SHOW LABELS IN `g1`",
   348  		},
   349  	}
   350  	RunTest(t, table)
   351  }
   352  
   353  func TestModify(t *testing.T) {
   354  	table := []testCase{
   355  		{
   356  			"INSERT VERTEX x, VERTEX x",
   357  			true,
   358  			"INSERT VERTEX `x`,VERTEX `x`",
   359  		},
   360  		{
   361  			"INSERT VERTEX x LABELS ( Male, Female ) PROPERTIES ( x.age = 22 )",
   362  			true,
   363  			"INSERT VERTEX `x` LABELS (`Male`, `Female`) PROPERTIES (`x`.`age` = 22)",
   364  		},
   365  		{
   366  			"INSERT VERTEX x LABELS ( Male ) PROPERTIES ( x.age = y.age ) FROM MATCH (y:Male)",
   367  			true,
   368  			"INSERT VERTEX `x` LABELS (`Male`) PROPERTIES (`x`.`age` = `y`.`age`) FROM MATCH (`y`:`Male`)",
   369  		},
   370  		{
   371  			`INSERT VERTEX x LABELS ( Profession ) PROPERTIES ( x.name = y.profession )
   372  			FROM MATCH (y:Person)
   373  		GROUP BY y.profession`,
   374  			true,
   375  			"INSERT VERTEX `x` LABELS (`Profession`) PROPERTIES (`x`.`name` = `y`.`profession`) FROM MATCH (`y`:`Person`) GROUP BY `y`.`profession`",
   376  		},
   377  		{
   378  			`INSERT EDGE e BETWEEN x AND y
   379  			FROM MATCH (x)
   380  			   , MATCH (y)
   381  		   WHERE id(x) = 1 AND id(y) = 2 `,
   382  			true,
   383  			"INSERT EDGE `e` BETWEEN `x` AND `y` FROM MATCH (`x`),MATCH (`y`) WHERE ID(`x`)=1 AND ID(`y`)=2",
   384  		},
   385  		{
   386  			`INSERT EDGE e BETWEEN x AND y LABELS ( knows )
   387  			FROM MATCH (x:Person)
   388  			   , MATCH (y:Person)
   389  		   WHERE id(x) = 1 AND id(y) = 2`,
   390  			true,
   391  			"INSERT EDGE `e` BETWEEN `x` AND `y` LABELS (`knows`) FROM MATCH (`x`:`Person`),MATCH (`y`:`Person`) WHERE ID(`x`)=1 AND ID(`y`)=2",
   392  		},
   393  		{
   394  			"INSERT VERTEX v PROPERTIES ( v.age = 22 )",
   395  			true,
   396  			"INSERT VERTEX `v` PROPERTIES (`v`.`age` = 22)",
   397  		},
   398  		{
   399  			`INSERT EDGE e BETWEEN x AND y LABELS ( knows ) PROPERTIES ( e.since = DATE '2017-09-21' )
   400  			FROM MATCH (x:Person)
   401  			   , MATCH (y:Person)
   402  		   WHERE id(x) = 1 AND id(y) = 2`,
   403  			true,
   404  			"INSERT EDGE `e` BETWEEN `x` AND `y` LABELS (`knows`) PROPERTIES (`e`.`since` = DATE '2017-09-21') FROM MATCH (`x`:`Person`),MATCH (`y`:`Person`) WHERE ID(`x`)=1 AND ID(`y`)=2",
   405  		},
   406  		{
   407  			`INSERT
   408  			VERTEX v LABELS ( Male ) PROPERTIES ( v.age = 23, v.name = 'John' ),
   409  			VERTEX u LABELS ( Female ) PROPERTIES ( u.age = 24, u.name = 'Jane' )`,
   410  			true,
   411  			"INSERT VERTEX `v` LABELS (`Male`) PROPERTIES (`v`.`age` = 23, `v`.`name` = 'John'),VERTEX `u` LABELS (`Female`) PROPERTIES (`u`.`age` = 24, `u`.`name` = 'Jane')",
   412  		},
   413  		{
   414  			`INSERT VERTEX x LABELS ( Person ) PROPERTIES ( x.name = 'John' )
   415  			, EDGE e BETWEEN x AND y LABELS ( knows ) PROPERTIES ( e.since = DATE '2017-09-21' )
   416  		 FROM MATCH (y)
   417  		WHERE y.name = 'Jane'`,
   418  			true,
   419  			"INSERT VERTEX `x` LABELS (`Person`) PROPERTIES (`x`.`name` = 'John'),EDGE `e` BETWEEN `x` AND `y` LABELS (`knows`) PROPERTIES (`e`.`since` = DATE '2017-09-21') FROM MATCH (`y`) WHERE `y`.`name`='Jane'",
   420  		},
   421  		{
   422  			`INSERT EDGE e BETWEEN x AND y
   423  			FROM MATCH (x)
   424  			   , MATCH (y) -> (z)
   425  		   WHERE id(x) = 1`,
   426  			true,
   427  			"INSERT EDGE `e` BETWEEN `x` AND `y` FROM MATCH (`x`),MATCH (`y`) -> (`z`) WHERE ID(`x`)=1",
   428  		},
   429  		{
   430  			`UPDATE x SET ( x.age = 42 )
   431    FROM MATCH (x:Person)
   432   WHERE x.name = 'John'`,
   433  			true,
   434  			"UPDATE `x` SET (`x`.`age` = 42) FROM MATCH (`x`:`Person`) WHERE `x`.`name`='John'",
   435  		},
   436  		{
   437  			`UPDATE v SET ( v.carOwner = TRUE )
   438       , u SET ( u.weight = 3500 )
   439       , e SET ( e.since = DATE '2010-01-03' )
   440    FROM MATCH (v:Person) <-[e:belongs_to]- (u:Car)
   441   WHERE v.name = 'John'`,
   442  			true,
   443  			"UPDATE `v` SET (`v`.`carOwner` = TRUE),`u` SET (`u`.`weight` = 3500),`e` SET (`e`.`since` = DATE '2010-01-03') FROM MATCH (`v`:`Person`) <-[`e`:`belongs_to`]- (`u`:`Car`) WHERE `v`.`name`='John'",
   444  		},
   445  		{
   446  			`UPDATE x SET ( x.a = y.b, x.b = 12 ) FROM MATCH (x) -> (y)`,
   447  			true,
   448  			"UPDATE `x` SET (`x`.`a` = `y`.`b`, `x`.`b` = 12) FROM MATCH (`x`) -> (`y`)",
   449  		},
   450  		{
   451  			`UPDATE x SET ( x.a = y.a ) FROM MATCH (x) -> (y)`,
   452  			true,
   453  			"UPDATE `x` SET (`x`.`a` = `y`.`a`) FROM MATCH (`x`) -> (`y`)",
   454  		},
   455  		{
   456  			`UPDATE v SET ( v.a = 65 - v.age )
   457    FROM MATCH (v:Person) -> (u:Person)
   458   WHERE v.name = 'John'`,
   459  			true,
   460  			"UPDATE `v` SET (`v`.`a` = 65-`v`.`age`) FROM MATCH (`v`:`Person`) -> (`u`:`Person`) WHERE `v`.`name`='John'",
   461  		},
   462  		{
   463  			`UPDATE v SET ( v.a = 65 - u.age )
   464    FROM MATCH (v:Person) -> (u:Person)
   465   WHERE v.name = 'John'`,
   466  			true,
   467  			"UPDATE `v` SET (`v`.`a` = 65-`u`.`age`) FROM MATCH (`v`:`Person`) -> (`u`:`Person`) WHERE `v`.`name`='John'",
   468  		},
   469  		{
   470  			`DELETE e FROM MATCH () -[e]-> ()`,
   471  			true,
   472  			"DELETE `e` FROM MATCH () -[`e`]-> ()",
   473  		},
   474  		{
   475  			`DELETE x, y FROM MATCH (x) -> (y)`,
   476  			true,
   477  			"DELETE `x`,`y` FROM MATCH (`x`) -> (`y`)",
   478  		},
   479  		{
   480  			`DELETE x FROM MATCH (x) WHERE id(x) = 11`,
   481  			true,
   482  			"DELETE `x` FROM MATCH (`x`) WHERE ID(`x`)=11",
   483  		},
   484  		{
   485  			`DELETE x FROM MATCH (x)`,
   486  			true,
   487  			"DELETE `x` FROM MATCH (`x`)",
   488  		},
   489  		//		{
   490  		//			`INSERT EDGE e BETWEEN x AND y
   491  		//UPDATE y SET ( y.a = 12 )
   492  		//  FROM MATCH (x), MATCH (y)
   493  		// WHERE id(x) = 1 AND id(y) = 2
   494  		//`,
   495  		//			true,
   496  		//			"INSERT EDGE `e` BETWEEN `x` AND `y` UPDATE `y` SET (`y`.`a` = 12) FROM MATCH (`x`),MATCH (`y`) WHERE ID(`x`)=1 AND ID(`y`)=2",
   497  		//		},
   498  	}
   499  	RunTest(t, table)
   500  }
   501  
   502  func RunTest(t *testing.T, table []testCase) {
   503  	p := parser.New()
   504  	for _, tbl := range table {
   505  		_, _, err := p.Parse(tbl.src)
   506  		if !tbl.ok {
   507  			require.Errorf(t, err, "source %v", tbl.src)
   508  			continue
   509  		}
   510  		require.NoErrorf(t, err, "source %v", tbl.src)
   511  		// restore correctness test
   512  		if tbl.ok {
   513  			RunRestoreTest(t, tbl.src, tbl.restore)
   514  		}
   515  	}
   516  }
   517  
   518  func RunRestoreTest(t *testing.T, sourceSQLs, expectSQLs string) {
   519  	var sb strings.Builder
   520  	p := parser.New()
   521  	comment := fmt.Sprintf("source %v", sourceSQLs)
   522  	stmts, _, err := p.Parse(sourceSQLs)
   523  	require.NoErrorf(t, err, "source %v", sourceSQLs)
   524  	restoreSQLs := ""
   525  	for _, stmt := range stmts {
   526  		sb.Reset()
   527  		err = stmt.Restore(format.NewRestoreCtx(format.DefaultRestoreFlags, &sb))
   528  		require.NoError(t, err, comment)
   529  		restoreSQL := sb.String()
   530  		comment = fmt.Sprintf("source %v; restore %v", sourceSQLs, restoreSQL)
   531  		restoreStmt, err := p.ParseOneStmt(restoreSQL)
   532  		require.NoError(t, err, comment)
   533  		_ = restoreStmt
   534  		// require.Equal(t, stmt, restoreStmt, comment) // TODO: compare stmt and restoreStmt
   535  		if restoreSQLs != "" {
   536  			restoreSQLs += "; "
   537  		}
   538  		restoreSQLs += restoreSQL
   539  
   540  	}
   541  	require.Equalf(t, expectSQLs, restoreSQLs, "restore %v; expect %v", restoreSQLs, expectSQLs)
   542  }