openCypher Pattern Support in GSQL

We have extended GSQL to support openCypher patterns in the FROM clause.

GSQL maintains its SELECT-FROM-WHERE block structure, but TigerGraph allows the following new syntax in the FROM clause

This is in addition to the standard GSQL patterns, which will continue to be supported

openCypher’s vertex pattern notation

(v:VType) which now gets translated internally to standard GSQL’s VType:v.

Both v and VType are optional.

VType can be a disjunction.

openCypher’s edge patterns notation

[e:EType] which now gets translated internally to standard GSQL’s (EType:e).

Both e and EType are optional.

EType can be a disjunction.

openCypher’s property condition notation

GSQL also handles openCypher’s property condition notation (which is applicable to both vertex and edge patterns)

x {prop_1: val_1, …, prop_n: val_n}

by translating into a WHERE clause condition:

x.prop_1 == val_1 AND … AND x.prop_n == val_n

Examples

CREATE  QUERY test_03 () FOR GRAPH G SYNTAX V3 {
    SELECT n, COUNT(fr) AS friendsCount INTO T
    FROM (n {name: "John"})-[:FRIEND]-(fr)
    HAVING friendsCount > 3;
    PRINT T;
}
CREATE  QUERY test_07 () FOR GRAPH G SYNTAX V3 {
    SELECT friend_of_a_friend.name AS fofName INTO T
    FROM (user:Person {name: "Adam"})-[r1:FRIEND]-()-[r2:FRIEND]-(friend_of_a_friend) ;
    PRINT T;
}
For queries with cypher patterns to be accepted, the user needs to declare them under V3 syntax (using cypher patterns with V2 or V1 syntax declaration leads to syntax error). V3 queries are pre-processed into V2 queries (the V2 version is written to the log after the cypher pattern normalization).
CREATE QUERY test_03 () FOR GRAPH G SYNTAX V2 {
    SELECT n, COUNT(fr) AS friendsCount INTO T
    from   :n -(FRIEND)- :fr  WHERE n.name == "John"
    HAVING friendsCount > 3;
    PRINT T;
}

Now after cypher pattern normalization:

CREATE  QUERY test_07 () FOR GRAPH G SYNTAX _V2 {
    SELECT friend_of_a_friend.name AS fofName INTO T
    from   Person:user -(FRIEND:r1)-  -(FRIEND:r2)- :friend_of_a_friend
    WHERE user.name == "Adam" ;
    PRINT T;
}
If the original input is V2 or V1, the cypher preprocessor is never invoked, so it will not affect standard GSQL queries.

More examples below:

CREATE  QUERY test_03 () FOR GRAPH G SYNTAX V3 {
    XXX =
    SELECT  n
    FROM    (n)-[:friend]-(fr);
    PRINT XXX;
}
CREATE  QUERY test_99 () FOR GRAPH G SYNTAX V3 {
    SELECT  n.name INTO T  FROM  (n)
    ORDER BY n.name
    LIMIT 3;
    PRINT T;
}
CREATE  QUERY test_98 () FOR GRAPH G SYNTAX V3 {
    SELECT  n.name INTO T  FROM  (n)
    ORDER BY n.name
    LIMIT 3;
    PRINT T;
}
CREATE  QUERY test_40 () FOR GRAPH G SYNTAX V3
{
    SELECT
    CASE
        WHEN n.eyes == "blue" THEN 1
        WHEN n.age < 40 THEN 2
    ELSE 3 END AS result INTO T  FROM  (n) ;
    PRINT T;
}
CREATE  QUERY test_40a () FOR GRAPH G SYNTAX V3 {
    SELECT
    CASE n.eyes
        WHEN "blue" THEN 1
        WHEN "brown" THEN 2
    ELSE 3 END AS result INTO T  FROM  (n) ;
    PRINT T;
}
CREATE  QUERY test_22 () FOR GRAPH G SYNTAX V3 {
    SELECT actor, count(movie) AS nrOfMovies INTO T
    FROM (actor:Person)-[:ACTED_IN]->(movie:Movie);
    PRINT T;
}
CREATE  QUERY test_21 () FOR GRAPH G SYNTAX V3 {
    SELECT actor.name, actor.age INTO T
    FROM  (actor:Person {name: "Charlie Sheen"})-[:ACTED_IN]->(movie:Movie);
}
CREATE  QUERY test_195b () FOR GRAPH G SYNTAX V3 {
    SELECT  n INTO T  FROM  (n) WHERE n.email == "//This is NOT a comment";
    PRINT T;
}
CREATE  QUERY test_164 () FOR GRAPH G SYNTAX V3 {
    SELECT  a.type  INTO T  FROM  (a)
    WHERE a.name == "Alice";
    PRINT T;
}
CREATE  QUERY test_162 () FOR GRAPH G SYNTAX V3 {
    SELECT  sum(n.age) INTO T  FROM  (n:Person) ;
    PRINT T;
}
CREATE  QUERY test_161 () FOR GRAPH G SYNTAX V3 {
    SELECT n.age INTO T  FROM  (n)
    WHERE n.name IN ("A" "B" "C");
    PRINT T;
}
CREATE  QUERY test_158 () FOR GRAPH G SYNTAX V3 {
    SELECT  min(n.age) INTO T  FROM  (n:Person) ;
    PRINT T;
}
CREATE  QUERY test_157 () FOR GRAPH G SYNTAX V3 {
    SELECT  min(n.age) INTO T  FROM  (n:Person) ;
    PRINT T;
}
CREATE  QUERY test_156 () FOR GRAPH G SYNTAX V3 {
    SELECT  max(n.age) INTO T  FROM  (n:Person) ;
    PRINT T;
}
CREATE  QUERY test_154b () FOR GRAPH G SYNTAX V3 {
    SELECT  count(n.age) INTO T  FROM  (n:Person) ;
    PRINT T;
}
CREATE  QUERY test_154a () FOR GRAPH G SYNTAX V3 {
    SELECT  count(n.age) INTO T  FROM  (n:Person) ;
    PRINT T;
}
CREATE  QUERY test_153 () FOR GRAPH G SYNTAX V3 {
    SELECT  n.type , n.age, count(*) INTO T  FROM  (n {name: "A"})-[]->(x) ;
    PRINT T;
}
CREATE  QUERY test_153b () FOR GRAPH G SYNTAX V3 {
    SELECT  r.type , count(*) INTO T  FROM  (n {name: "A"})-[r]->() ;
    PRINT T;
}
CREATE  QUERY test_153a () FOR GRAPH G SYNTAX V3 {
    SELECT  r.type , count(*) INTO T  FROM  (n {name: "A"})-[r]->() ;
    PRINT T;
}
CREATE  QUERY test_151 () FOR GRAPH G SYNTAX V3 {
    SELECT  avg(n.age) INTO T  FROM  (n:Person) ;
    PRINT T;
}
CREATE  QUERY test_149 () FOR GRAPH G SYNTAX V3 {
    SELECT  r.type  INTO T  FROM  (n)-[r]->()
    WHERE n.name == "Alice";
    PRINT T;
}
CREATE  QUERY test_145 () FOR GRAPH G SYNTAX V3 {
    SELECT  length(a.name) INTO T  FROM  (a)
    WHERE length(a.name)> 6;
    PRINT T;
}
CREATE  QUERY test_141 () FOR GRAPH G SYNTAX V3 {
    SELECT  getvid(a) INTO T  FROM  (a) ;
    PRINT T;
}
CREATE  QUERY test_12 () FOR GRAPH G SYNTAX V3 {
    SELECT  remote_friend.name INTO T  FROM  (me)-[:KNOWS*1..2]-(remote_friend)
    WHERE me.name == "Filipa";
    PRINT T;
}
CREATE  QUERY test_107 () FOR GRAPH G SYNTAX V3 {
    DELETE n   FROM  (n:Person {name: "Andres"}) ;
}
CREATE  QUERY test_107a () FOR GRAPH G SYNTAX V3 {
    DELETE r   FROM  (n {name: "Andres"})-[r:KNOWS]->() ;
}
CREATE  QUERY test_104 () FOR GRAPH G SYNTAX V3 {
    DELETE n   FROM  (n:Person) ;
}
CREATE  QUERY test_08 () FOR GRAPH G SYNTAX V3 {
    SELECT friend_of_a_friend.name AS fofName INTO T
    FROM   (fr)-[r2:friend]-(friend_of_a_friend) ;
    PRINT T;
}
CREATE  QUERY test_07 () FOR GRAPH G SYNTAX V3 {
    SELECT friend_of_a_friend.name AS fofName INTO T
    FROM   (user:Person {name: "Adam"})-[r1:friend]-()-[r2:friend]-(friend_of_a_friend) ;
    PRINT T;
}
CREATE  QUERY test_07a () FOR GRAPH G SYNTAX V3 {
    SELECT friend_of_a_friend.name AS fofName INTO T
    FROM   (fr)-[r2:friend]-(friend_of_a_friend) ;
    PRINT T;
}
CREATE  QUERY test_03 () FOR GRAPH G SYNTAX V3 {
    SELECT  n, COUNT(fr) AS friendsCount INTO T
    FROM    (n {name: "John"})-[:friend]-(fr)
    HAVING  friendsCount > 3;
    PRINT T;
}
CREATE  QUERY test_154 () FOR GRAPH G SYNTAX V3 {
    SELECT  count(x) INTO T  FROM  (n {name: "A"})-[]->(x) ;
    PRINT T;
}
CREATE  QUERY test_multiple_match_where() FOR GRAPH G SYNTAX V3 {
    SELECT  n, count(f) AS fCount, count(fof) AS fofCount INTO T
    FROM    (n {name: "John"})-[:friend]-(f), (f)-[:friend]-(fof)
    WHERE   f.age < 21 AND  fof.age < 21
    HAVING  fCount > 3 AND fofCount > 13;
    PRINT T;
}
CREATE  QUERY test_kleened_wildcard() FOR GRAPH G SYNTAX V3 {
    SELECT DISTINCT p, hollywood INTO T
    FROM   (p:Person {name: "Kevin Bacon"})-[:_*1..3]-(hollywood) ;
    PRINT T;
}
CREATE  QUERY test_kleene_no_type() FOR GRAPH G SYNTAX V3 {
    SELECT DISTINCT p, hollywood INTO T
    FROM   (p:Person {name: "Kevin Bacon"})-[*1..3]-(hollywood) ;
    PRINT T;
}
CREATE  QUERY test_empty_edge_pattern_right() FOR GRAPH G SYNTAX V3 {
    SELECT DISTINCT p, x INTO T
    FROM   (p:Person {name: "Kevin Bacon"}) --> (x) ;
    PRINT T;
}