#
# Copyright (c) 2015-2018 "Neo Technology,"
# Network Engine for Objects in Lund AB [http://neotechnology.com]
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

Feature: MatchAcceptance2

  Scenario: Do not return non-existent nodes
    Given an empty graph
    When executing query:
      """
      MATCH (n)
      RETURN n
      """
    Then the result should be:
      | n |
    And no side effects

  Scenario: Do not return non-existent relationships
    Given an empty graph
    When executing query:
      """
      MATCH ()-[r]->()
      RETURN r
      """
    Then the result should be:
      | r |
    And no side effects

  Scenario: Do not fail when evaluating predicates with illegal operations if the AND'ed predicate evaluates to false
    Given an empty graph
    And having executed:
      """
      CREATE (root:Root {name: 'x'}),
             (child1:TextNode {id: 'text'}),
             (child2:IntNode {id: 0})
      CREATE (root)-[:T]->(child1),
             (root)-[:T]->(child2)
      """
    When executing query:
      """
      MATCH (:Root {name: 'x'})-->(i:TextNode)
      WHERE i.id > 'te'
      RETURN i
      """
    Then the result should be:
      | i                        |
      | (:TextNode {id: 'text'}) |
    And no side effects

  Scenario: Do not fail when evaluating predicates with illegal operations if the OR'd predicate evaluates to true
    Given an empty graph
    And having executed:
      """
      CREATE (root:Root {name: 'x'}),
             (child1:TextNode {id: 'text'}),
             (child2:IntNode {id: 0})
      CREATE (root)-[:T]->(child1),
             (root)-[:T]->(child2)
      """
    When executing query:
      """
      MATCH (:Root {name: 'x'})-->(i)
      WHERE exists(i.id) OR i.id > 'te'
      RETURN i
      """
    Then the result should be:
      | i                        |
      | (:TextNode {id: 'text'}) |
      | (:IntNode {id: 0})       |
    And no side effects

  Scenario: Aggregation with named paths
    Given an empty graph
    And having executed:
      """
      CREATE (n1 {num: 1}), (n2 {num: 2}),
             (n3 {num: 3}), (n4 {num: 4})
      CREATE (n1)-[:T]->(n2),
             (n3)-[:T]->(n4)
      """
    When executing query:
      """
      MATCH p = ()-[*]->()
      WITH count(*) AS count, p AS p
      WITH nodes(p) AS nodes
      RETURN *
      """
    Then the result should be:
      | nodes                    |
      | [({num: 1}), ({num: 2})] |
      | [({num: 3}), ({num: 4})] |
    And no side effects

  Scenario: Zero-length variable length pattern in the middle of the pattern
    Given an empty graph
    And having executed:
      """
      CREATE (a {name: 'A'}), (b {name: 'B'}),
             (c {name: 'C'}), ({name: 'D'}),
             ({name: 'E'})
      CREATE (a)-[:CONTAINS]->(b),
             (b)-[:FRIEND]->(c)
      """
    When executing query:
      """
      MATCH (a {name: 'A'})-[:CONTAINS*0..1]->(b)-[:FRIEND*0..1]->(c)
      RETURN a, b, c
      """
    Then the result should be:
      | a             | b             | c             |
      | ({name: 'A'}) | ({name: 'A'}) | ({name: 'A'}) |
      | ({name: 'A'}) | ({name: 'B'}) | ({name: 'B'}) |
      | ({name: 'A'}) | ({name: 'B'}) | ({name: 'C'}) |
    And no side effects

  Scenario: Simple variable length pattern
    Given an empty graph
    And having executed:
      """
      CREATE (a {name: 'A'}), (b {name: 'B'}),
             (c {name: 'C'}), (d {name: 'D'})
      CREATE (a)-[:CONTAINS]->(b),
             (b)-[:CONTAINS]->(c),
             (c)-[:CONTAINS]->(d)
      """
    When executing query:
      """
      MATCH (a {name: 'A'})-[*]->(x)
      RETURN x
      """
    Then the result should be:
      | x             |
      | ({name: 'B'}) |
      | ({name: 'C'}) |
      | ({name: 'D'}) |
    And no side effects

  Scenario: Variable length relationship without lower bound
    Given an empty graph
    And having executed:
      """
      CREATE (a {name: 'A'}), (b {name: 'B'}),
             (c {name: 'C'})
      CREATE (a)-[:KNOWS]->(b),
             (b)-[:KNOWS]->(c)
      """
    When executing query:
      """
      MATCH p = ({name: 'A'})-[:KNOWS*..2]->()
      RETURN p
      """
    Then the result should be:
      | p                                                               |
      | <({name: 'A'})-[:KNOWS]->({name: 'B'})>                         |
      | <({name: 'A'})-[:KNOWS]->({name: 'B'})-[:KNOWS]->({name: 'C'})> |
    And no side effects

  Scenario: Variable length relationship without bounds
    Given an empty graph
    And having executed:
      """
      CREATE (a {name: 'A'}), (b {name: 'B'}),
             (c {name: 'C'})
      CREATE (a)-[:KNOWS]->(b),
             (b)-[:KNOWS]->(c)
      """
    When executing query:
      """
      MATCH p = ({name: 'A'})-[:KNOWS*..]->()
      RETURN p
      """
    Then the result should be:
      | p                                                               |
      | <({name: 'A'})-[:KNOWS]->({name: 'B'})>                         |
      | <({name: 'A'})-[:KNOWS]->({name: 'B'})-[:KNOWS]->({name: 'C'})> |
    And no side effects

  Scenario: Returning bound nodes that are not part of the pattern
    Given an empty graph
    And having executed:
      """
      CREATE (a {name: 'A'}), (b {name: 'B'}),
             (c {name: 'C'})
      CREATE (a)-[:KNOWS]->(b)
      """
    When executing query:
      """
      MATCH (a {name: 'A'}), (c {name: 'C'})
      MATCH (a)-->(b)
      RETURN a, b, c
      """
    Then the result should be:
      | a             | b             | c             |
      | ({name: 'A'}) | ({name: 'B'}) | ({name: 'C'}) |
    And no side effects

  Scenario: Two bound nodes pointing to the same node
    Given an empty graph
    And having executed:
      """
      CREATE (a {name: 'A'}), (b {name: 'B'}),
             (x1 {name: 'x1'}), (x2 {name: 'x2'})
      CREATE (a)-[:KNOWS]->(x1),
             (a)-[:KNOWS]->(x2),
             (b)-[:KNOWS]->(x1),
             (b)-[:KNOWS]->(x2)
      """
    When executing query:
      """
      MATCH (a {name: 'A'}), (b {name: 'B'})
      MATCH (a)-->(x)<-->(b)
      RETURN x
      """
    Then the result should be:
      | x              |
      | ({name: 'x1'}) |
      | ({name: 'x2'}) |
    And no side effects

  Scenario: Three bound nodes pointing to the same node
    Given an empty graph
    And having executed:
      """
      CREATE (a {name: 'A'}), (b {name: 'B'}), (c {name: 'C'}),
             (x1 {name: 'x1'}), (x2 {name: 'x2'})
      CREATE (a)-[:KNOWS]->(x1),
             (a)-[:KNOWS]->(x2),
             (b)-[:KNOWS]->(x1),
             (b)-[:KNOWS]->(x2),
             (c)-[:KNOWS]->(x1),
             (c)-[:KNOWS]->(x2)
      """
    When executing query:
      """
      MATCH (a {name: 'A'}), (b {name: 'B'}), (c {name: 'C'})
      MATCH (a)-->(x), (b)-->(x), (c)-->(x)
      RETURN x
      """
    Then the result should be:
      | x              |
      | ({name: 'x1'}) |
      | ({name: 'x2'}) |
    And no side effects

  Scenario: Three bound nodes pointing to the same node with extra connections
    Given an empty graph
    And having executed:
      """
      CREATE (a {name: 'a'}), (b {name: 'b'}), (c {name: 'c'}),
             (d {name: 'd'}), (e {name: 'e'}), (f {name: 'f'}),
             (g {name: 'g'}), (h {name: 'h'}), (i {name: 'i'}),
             (j {name: 'j'}), (k {name: 'k'})
      CREATE (a)-[:KNOWS]->(d),
             (a)-[:KNOWS]->(e),
             (a)-[:KNOWS]->(f),
             (a)-[:KNOWS]->(g),
             (a)-[:KNOWS]->(i),
             (b)-[:KNOWS]->(d),
             (b)-[:KNOWS]->(e),
             (b)-[:KNOWS]->(f),
             (b)-[:KNOWS]->(h),
             (b)-[:KNOWS]->(k),
             (c)-[:KNOWS]->(d),
             (c)-[:KNOWS]->(e),
             (c)-[:KNOWS]->(h),
             (c)-[:KNOWS]->(g),
             (c)-[:KNOWS]->(j)
      """
    When executing query:
      """
      MATCH (a {name: 'a'}), (b {name: 'b'}), (c {name: 'c'})
      MATCH (a)-->(x), (b)-->(x), (c)-->(x)
      RETURN x
      """
    Then the result should be:
      | x             |
      | ({name: 'd'}) |
      | ({name: 'e'}) |
    And no side effects

  Scenario: MATCH with OPTIONAL MATCH in longer pattern
    Given an empty graph
    And having executed:
      """
      CREATE (a {name: 'A'}), (b {name: 'B'}), (c {name: 'C'})
      CREATE (a)-[:KNOWS]->(b),
             (b)-[:KNOWS]->(c)
      """
    When executing query:
      """
      MATCH (a {name: 'A'})
      OPTIONAL MATCH (a)-[:KNOWS]->()-[:KNOWS]->(foo)
      RETURN foo
      """
    Then the result should be:
      | foo           |
      | ({name: 'C'}) |
    And no side effects

  Scenario: Optionally matching named paths
    Given an empty graph
    And having executed:
      """
      CREATE (a {name: 'A'}), (b {name: 'B'}), (c {name: 'C'})
      CREATE (a)-[:X]->(b)
      """
    When executing query:
      """
      MATCH (a {name: 'A'}), (x)
      WHERE x.name IN ['B', 'C']
      OPTIONAL MATCH p = (a)-->(x)
      RETURN x, p
      """
    Then the result should be:
      | x             | p                                   |
      | ({name: 'B'}) | <({name: 'A'})-[:X]->({name: 'B'})> |
      | ({name: 'C'}) | null                                |
    And no side effects

  Scenario: Optionally matching named paths with single and variable length patterns
    Given an empty graph
    And having executed:
      """
      CREATE (a {name: 'A'}), (b {name: 'B'})
      CREATE (a)-[:X]->(b)
      """
    When executing query:
      """
      MATCH (a {name: 'A'})
      OPTIONAL MATCH p = (a)-->(b)-[*]->(c)
      RETURN p
      """
    Then the result should be:
      | p    |
      | null |
    And no side effects

  Scenario: Optionally matching named paths with variable length patterns
    Given an empty graph
    And having executed:
      """
      CREATE (a {name: 'A'}), (b {name: 'B'}), (c {name: 'C'})
      CREATE (a)-[:X]->(b)
      """
    When executing query:
      """
      MATCH (a {name: 'A'}), (x)
      WHERE x.name IN ['B', 'C']
      OPTIONAL MATCH p = (a)-[r*]->(x)
      RETURN r, x, p
      """
    Then the result should be:
      | r      | x             | p                                   |
      | [[:X]] | ({name: 'B'}) | <({name: 'A'})-[:X]->({name: 'B'})> |
      | null   | ({name: 'C'}) | null                                |
    And no side effects

  Scenario: Matching variable length patterns from a bound node
    Given an empty graph
    And having executed:
      """
      CREATE (a:A), (b), (c)
      CREATE (a)-[:X]->(b),
             (b)-[:Y]->(c)
      """
    When executing query:
      """
      MATCH (a:A)
      MATCH (a)-[r*2]->()
      RETURN r
      """
    Then the result should be (ignoring element order for lists):
      | r            |
      | [[:X], [:Y]] |
    And no side effects

  Scenario: Excluding connected nodes
    Given an empty graph
    And having executed:
      """
      CREATE (a:A), (b:B {id: 1}), (:B {id: 2})
      CREATE (a)-[:T]->(b)
      """
    When executing query:
      """
      MATCH (a:A), (other:B)
      OPTIONAL MATCH (a)-[r]->(other)
      WITH other WHERE r IS NULL
      RETURN other
      """
    Then the result should be:
      | other        |
      | (:B {id: 2}) |
    And no side effects

  Scenario: Do not fail when predicates on optionally matched and missed nodes are invalid
    Given an empty graph
    And having executed:
      """
      CREATE (a), (b {name: 'Mark'})
      CREATE (a)-[:T]->(b)
      """
    When executing query:
      """
      MATCH (n)-->(x0)
      OPTIONAL MATCH (x0)-->(x1)
      WHERE x1.foo = 'bar'
      RETURN x0.name
      """
    Then the result should be:
      | x0.name |
      | 'Mark'  |
    And no side effects

  Scenario: MATCH and OPTIONAL MATCH on same pattern
    Given an empty graph
    And having executed:
      """
      CREATE (a {name: 'A'}), (b:B {name: 'B'}), (c:C {name: 'C'})
      CREATE (a)-[:T]->(b),
             (a)-[:T]->(c)
      """
    When executing query:
      """
      MATCH (a)-->(b)
      WHERE b:B
      OPTIONAL MATCH (a)-->(c)
      WHERE c:C
      RETURN a.name
      """
    Then the result should be:
      | a.name |
      | 'A'    |
    And no side effects

  Scenario: Matching using an undirected pattern
    Given an empty graph
    And having executed:
      """
      CREATE (:A {id: 0})-[:ADMIN]->(:B {id: 1})
      """
    When executing query:
      """
      MATCH (a)-[:ADMIN]-(b)
      WHERE a:A
      RETURN a.id, b.id
      """
    Then the result should be:
      | a.id | b.id |
      | 0    | 1    |
    And no side effects

  Scenario: Matching all nodes
    Given an empty graph
    And having executed:
      """
      CREATE (:A), (:B)
      """
    When executing query:
      """
      MATCH (n)
      RETURN n
      """
    Then the result should be:
      | n    |
      | (:A) |
      | (:B) |
    And no side effects

  Scenario: Comparing nodes for equality
    Given an empty graph
    And having executed:
      """
      CREATE (:A), (:B)
      """
    When executing query:
      """
      MATCH (a), (b)
      WHERE a <> b
      RETURN a, b
      """
    Then the result should be:
      | a    | b    |
      | (:A) | (:B) |
      | (:B) | (:A) |
    And no side effects

  Scenario: Matching using self-referencing pattern returns no result
    Given an empty graph
    And having executed:
      """
      CREATE (a), (b), (c)
      CREATE (a)-[:T]->(b),
             (b)-[:T]->(c)
      """
    When executing query:
      """
      MATCH (a)-->(b), (b)-->(b)
      RETURN b
      """
    Then the result should be:
      | b |
    And no side effects

  Scenario: Variable length relationship in OPTIONAL MATCH
    Given an empty graph
    And having executed:
      """
      CREATE (:A), (:B)
      """
    When executing query:
      """
      MATCH (a:A), (b:B)
      OPTIONAL MATCH (a)-[r*]-(b)
      WHERE r IS NULL
        AND a <> b
      RETURN b
      """
    Then the result should be:
      | b    |
      | (:B) |
    And no side effects

  Scenario: Matching using relationship predicate with multiples of the same type
    Given an empty graph
    And having executed:
      """
      CREATE (a:A), (b:B)
      CREATE (a)-[:T]->(b)
      """
    When executing query:
      """
      MATCH (a)-[:T|:T]->(b)
      RETURN b
      """
    Then the result should be:
      | b    |
      | (:B) |
    And no side effects

  Scenario: ORDER BY with LIMIT
    Given an empty graph
    And having executed:
      """
      CREATE (a:A), (n1 {x: 1}), (n2 {x: 2}),
             (m1), (m2)
      CREATE (a)-[:T]->(n1),
             (n1)-[:T]->(m1),
             (a)-[:T]->(n2),
             (n2)-[:T]->(m2)
      """
    When executing query:
      """
      MATCH (a:A)-->(n)-->(m)
      RETURN n.x, count(*)
        ORDER BY n.x
        LIMIT 1000
      """
    Then the result should be, in order:
      | n.x | count(*) |
      | 1   | 1        |
      | 2   | 1        |
    And no side effects

  Scenario: Simple node property predicate
    Given an empty graph
    And having executed:
      """
      CREATE ({foo: 'bar'})
      """
    When executing query:
      """
      MATCH (n)
      WHERE n.foo = 'bar'
      RETURN n
      """
    Then the result should be:
      | n              |
      | ({foo: 'bar'}) |
    And no side effects

  Scenario: Handling direction of named paths
    Given an empty graph
    And having executed:
      """
      CREATE (a:A)-[:T]->(b:B)
      """
    When executing query:
      """
      MATCH p = (b)<--(a)
      RETURN p
      """
    Then the result should be:
      | p                 |
      | <(:B)<-[:T]-(:A)> |
    And no side effects

  Scenario: Simple OPTIONAL MATCH on empty graph
    Given an empty graph
    When executing query:
      """
      OPTIONAL MATCH (n)
      RETURN n
      """
    Then the result should be:
      | n    |
      | null |
    And no side effects

  Scenario: OPTIONAL MATCH with previously bound nodes
    Given an empty graph
    And having executed:
      """
      CREATE ()
      """
    When executing query:
      """
      MATCH (n)
      OPTIONAL MATCH (n)-[:NOT_EXIST]->(x)
      RETURN n, x
      """
    Then the result should be:
      | n  | x    |
      | () | null |
    And no side effects

  Scenario: `collect()` filtering nulls
    Given an empty graph
    And having executed:
      """
      CREATE ()
      """
    When executing query:
      """
      MATCH (n)
      OPTIONAL MATCH (n)-[:NOT_EXIST]->(x)
      RETURN n, collect(x)
      """
    Then the result should be:
      | n  | collect(x) |
      | () | []         |
    And no side effects

  Scenario: Multiple anonymous nodes in a pattern
    Given an empty graph
    And having executed:
      """
      CREATE (:A)
      """
    When executing query:
      """
      MATCH (a)<--()<--(b)-->()-->(c)
      WHERE a:A
      RETURN c
      """
    Then the result should be:
      | c |
    And no side effects

  Scenario: Matching a relationship pattern using a label predicate
    Given an empty graph
    And having executed:
      """
      CREATE (a), (b1:Foo), (b2)
      CREATE (a)-[:T]->(b1),
             (a)-[:T]->(b2)
      """
    When executing query:
      """
      MATCH (a)-->(b:Foo)
      RETURN b
      """
    Then the result should be:
      | b      |
      | (:Foo) |
    And no side effects

  Scenario: Matching a relationship pattern using a label predicate on both sides
    Given an empty graph
    And having executed:
      """
      CREATE (:A)-[:T1]->(:B),
             (:B)-[:T2]->(:A),
             (:B)-[:T3]->(:B),
             (:A)-[:T4]->(:A)
      """
    When executing query:
      """
      MATCH (:A)-[r]->(:B)
      RETURN r
      """
    Then the result should be:
      | r     |
      | [:T1] |
    And no side effects

  Scenario: Matching nodes using multiple labels
    Given an empty graph
    And having executed:
      """
      CREATE (:A:B:C), (:A:B), (:A:C), (:B:C),
             (:A), (:B), (:C)
      """
    When executing query:
      """
      MATCH (a:A:B:C)
      RETURN a
      """
    Then the result should be:
      | a        |
      | (:A:B:C) |
    And no side effects

  Scenario: Returning label predicate expression
    Given an empty graph
    And having executed:
      """
      CREATE (), (:Foo)
      """
    When executing query:
      """
      MATCH (n)
      RETURN (n:Foo)
      """
    Then the result should be:
      | (n:Foo) |
      | true    |
      | false   |
    And no side effects

  Scenario: Matching with many predicates and larger pattern
    Given an empty graph
    And having executed:
      """
      CREATE (advertiser {name: 'advertiser1', id: 0}),
             (thing {name: 'Color', id: 1}),
             (red {name: 'red'}),
             (p1 {name: 'product1'}),
             (p2 {name: 'product4'})
      CREATE (advertiser)-[:ADV_HAS_PRODUCT]->(p1),
             (advertiser)-[:ADV_HAS_PRODUCT]->(p2),
             (thing)-[:AA_HAS_VALUE]->(red),
             (p1)-[:AP_HAS_VALUE]->(red),
             (p2)-[:AP_HAS_VALUE]->(red)
      """
    And parameters are:
      | 1 | 0 |
      | 2 | 1 |
    When executing query:
      """
      MATCH (advertiser)-[:ADV_HAS_PRODUCT]->(out)-[:AP_HAS_VALUE]->(red)<-[:AA_HAS_VALUE]-(a)
      WHERE advertiser.id = $1
        AND a.id = $2
        AND red.name = 'red'
        AND out.name = 'product1'
      RETURN out.name
      """
    Then the result should be:
      | out.name   |
      | 'product1' |
    And no side effects

  Scenario: Matching using a simple pattern with label predicate
    Given an empty graph
    And having executed:
      """
      CREATE (a:Person {name: 'Alice'}), (b:Person {name: 'Bob'}),
             (c), (d)
      CREATE (a)-[:T]->(c),
             (b)-[:T]->(d)
      """
    When executing query:
      """
      MATCH (n:Person)-->()
      WHERE n.name = 'Bob'
      RETURN n
      """
    Then the result should be:
      | n                       |
      | (:Person {name: 'Bob'}) |
    And no side effects

  Scenario: Matching disconnected patterns
    Given an empty graph
    And having executed:
      """
      CREATE (a:A), (b:B), (c:C)
      CREATE (a)-[:T]->(b),
             (a)-[:T]->(c)
      """
    When executing query:
      """
      MATCH (a)-->(b)
      MATCH (c)-->(d)
      RETURN a, b, c, d
      """
    Then the result should be:
      | a    | b    | c    | d    |
      | (:A) | (:B) | (:A) | (:B) |
      | (:A) | (:B) | (:A) | (:C) |
      | (:A) | (:C) | (:A) | (:B) |
      | (:A) | (:C) | (:A) | (:C) |
    And no side effects

  Scenario: Non-optional matches should not return nulls
    Given an empty graph
    And having executed:
      """
      CREATE (a:A), (b:B {id: 1}), (c:C {id: 2}), (d:D)
      CREATE (a)-[:T]->(b),
             (a)-[:T]->(c),
             (a)-[:T]->(d),
             (b)-[:T]->(c),
             (b)-[:T]->(d),
             (c)-[:T]->(d)
      """
    When executing query:
      """
      MATCH (a)--(b)--(c)--(d)--(a), (b)--(d)
      WHERE a.id = 1
        AND c.id = 2
      RETURN d
      """
    Then the result should be:
      | d    |
      | (:A) |
      | (:D) |
    And no side effects

  Scenario: Handling cyclic patterns
    Given an empty graph
    And having executed:
      """
      CREATE (a {name: 'a'}), (b {name: 'b'}), (c {name: 'c'})
      CREATE (a)-[:A]->(b),
             (b)-[:B]->(a),
             (b)-[:B]->(c)
      """
    When executing query:
      """
      MATCH (a)-[:A]->()-[:B]->(a)
      RETURN a.name
      """
    Then the result should be:
      | a.name |
      | 'a'    |
    And no side effects

  Scenario: Handling cyclic patterns when separated into two parts
    Given an empty graph
    And having executed:
      """
      CREATE (a {name: 'a'}), (b {name: 'b'}), (c {name: 'c'})
      CREATE (a)-[:A]->(b),
             (b)-[:B]->(a),
             (b)-[:B]->(c)
      """
    When executing query:
      """
      MATCH (a)-[:A]->(b), (b)-[:B]->(a)
      RETURN a.name
      """
    Then the result should be:
      | a.name |
      | 'a'    |
    And no side effects

  Scenario: Handling fixed-length variable length pattern
    Given an empty graph
    And having executed:
      """
      CREATE ()-[:T]->()
      """
    When executing query:
      """
      MATCH (a)-[r*1..1]->(b)
      RETURN r
      """
    Then the result should be:
      | r      |
      | [[:T]] |
    And no side effects

  Scenario: Matching from null nodes should return no results owing to finding no matches
    Given an empty graph
    When executing query:
      """
      OPTIONAL MATCH (a)
      WITH a
      MATCH (a)-->(b)
      RETURN b
      """
    Then the result should be:
      | b |
    And no side effects

  Scenario: Matching from null nodes should return no results owing to matches being filtered out
    Given an empty graph
    And having executed:
      """
      CREATE ()-[:T]->()
      """
    When executing query:
      """
      OPTIONAL MATCH (a:Label)
      WITH a
      MATCH (a)-->(b)
      RETURN b
      """
    Then the result should be:
      | b |
    And no side effects

  Scenario: Optionally matching from null nodes should return null
    Given an empty graph
    When executing query:
      """
      OPTIONAL MATCH (a)
      WITH a
      OPTIONAL MATCH (a)-->(b)
      RETURN b
      """
    Then the result should be:
      | b    |
      | null |
    And no side effects

  Scenario: OPTIONAL MATCH returns null
    Given an empty graph
    When executing query:
      """
      OPTIONAL MATCH (a)
      RETURN a
      """
    Then the result should be:
      | a    |
      | null |
    And no side effects

  Scenario: Zero-length named path
    Given an empty graph
    And having executed:
      """
      CREATE ()
      """
    When executing query:
      """
      MATCH p = (a)
      RETURN p
      """
    Then the result should be:
      | p    |
      | <()> |
    And no side effects

  Scenario: Variable-length named path
    Given an empty graph
    And having executed:
      """
      CREATE ()
      """
    When executing query:
      """
      MATCH p = ()-[*0..]->()
      RETURN p
      """
    Then the result should be:
      | p    |
      | <()> |
    And no side effects

  Scenario: Matching with aggregation
    Given an empty graph
    And having executed:
      """
      CREATE ({prop: 42})
      """
    When executing query:
      """
      MATCH (n)
      RETURN n.prop AS n, count(n) AS count
      """
    Then the result should be:
      | n  | count |
      | 42 | 1     |
    And no side effects

  Scenario: Matching using a relationship that is already bound
    Given an empty graph
    And having executed:
      """
      CREATE ()-[:T1]->(),
             ()-[:T2]->()
      """
    When executing query:
      """
      MATCH ()-[r1]->()
      WITH r1 AS r2
      MATCH ()-[r2]->()
      RETURN r2 AS rel
      """
    Then the result should be:
      | rel   |
      | [:T1] |
      | [:T2] |
    And no side effects

  Scenario: Matching using a relationship that is already bound, in conjunction with aggregation
    Given an empty graph
    And having executed:
      """
      CREATE ()-[:T1]->(),
             ()-[:T2]->()
      """
    When executing query:
      """
      MATCH ()-[r1]->()
      WITH r1 AS r2, count(*) AS c
        ORDER BY c
      MATCH ()-[r2]->()
      RETURN r2 AS rel
      """
    Then the result should be:
      | rel   |
      | [:T1] |
      | [:T2] |
    And no side effects

  Scenario: Matching using a relationship that is already bound, in conjunction with aggregation and ORDER BY
    Given an empty graph
    And having executed:
      """
      CREATE ()-[:T1 {id: 0}]->(),
             ()-[:T2 {id: 1}]->()
      """
    When executing query:
      """
      MATCH (a)-[r]->(b)
      WITH a, r, b, count(*) AS c
        ORDER BY c
      MATCH (a)-[r]->(b)
      RETURN r AS rel
        ORDER BY rel.id
      """
    Then the result should be, in order:
      | rel           |
      | [:T1 {id: 0}] |
      | [:T2 {id: 1}] |
    And no side effects

  Scenario: Matching with LIMIT and optionally matching using a relationship that is already bound
    Given an empty graph
    And having executed:
      """
      CREATE (:A)-[:T]->(:B)
      """
    When executing query:
      """
      MATCH ()-[r]->()
      WITH r
        LIMIT 1
      OPTIONAL MATCH (a2)-[r]->(b2)
      RETURN a2, r, b2
      """
    Then the result should be:
      | a2   | r    | b2   |
      | (:A) | [:T] | (:B) |
    And no side effects

  Scenario: Matching with LIMIT and optionally matching using a relationship and node that are both already bound
    Given an empty graph
    And having executed:
      """
      CREATE (:A)-[:T]->(:B)
      """
    When executing query:
      """
      MATCH (a1)-[r]->()
      WITH r, a1
        LIMIT 1
      OPTIONAL MATCH (a1)-[r]->(b2)
      RETURN a1, r, b2
      """
    Then the result should be:
      | a1   | r    | b2   |
      | (:A) | [:T] | (:B) |
    And no side effects

  Scenario: Matching with LIMIT, then matching again using a relationship and node that are both already bound along with an additional predicate
    Given an empty graph
    And having executed:
      """
      CREATE ()-[:T]->()
      """
    When executing query:
      """
      MATCH (a1)-[r]->()
      WITH r, a1
        LIMIT 1
      MATCH (a1:X)-[r]->(b2)
      RETURN a1, r, b2
      """
    Then the result should be:
      | a1 | r | b2 |
    And no side effects

  Scenario: Matching with LIMIT and predicates, then matching again using a relationship and node that are both already bound along with a duplicate predicate
    Given an empty graph
    And having executed:
      """
      CREATE (:X:Y)-[:T]->()
      """
    When executing query:
      """
      MATCH (a1:X:Y)-[r]->()
      WITH r, a1
        LIMIT 1
      MATCH (a1:Y)-[r]->(b2)
      RETURN a1, r, b2
      """
    Then the result should be:
      | a1     | r    | b2 |
      | (:X:Y) | [:T] | () |
    And no side effects

  Scenario: Matching twice with conflicting relationship types on same relationship
    Given an empty graph
    And having executed:
      """
      CREATE ()-[:T]->()
      """
    When executing query:
      """
      MATCH (a1)-[r:T]->()
      WITH r, a1
        LIMIT 1
      MATCH (a1)-[r:Y]->(b2)
      RETURN a1, r, b2
      """
    Then the result should be:
      | a1 | r | b2 |
    And no side effects

  Scenario: Matching twice with duplicate relationship types on same relationship
    Given an empty graph
    And having executed:
      """
      CREATE (:A)-[:T]->(:B)
      """
    When executing query:
      """
      MATCH (a1)-[r:T]->() WITH r, a1
      LIMIT 1
      MATCH (a1)-[r:T]->(b2)
      RETURN a1, r, b2
      """
    Then the result should be:
      | a1   | r    | b2   |
      | (:A) | [:T] | (:B) |
    And no side effects

  Scenario: Matching relationships into a list and matching variable length using the list
    Given an empty graph
    And having executed:
      """
      CREATE (a:A), (b:B), (c:C)
      CREATE (a)-[:Y]->(b),
             (b)-[:Y]->(c)
      """
    When executing query:
      """
      MATCH ()-[r1]->()-[r2]->()
      WITH [r1, r2] AS rs
        LIMIT 1
      MATCH (first)-[rs*]->(second)
      RETURN first, second
      """
    Then the result should be:
      | first | second |
      | (:A)  | (:C)   |
    And no side effects

  Scenario: Matching relationships into a list and matching variable length using the list, with bound nodes
    Given an empty graph
    And having executed:
      """
      CREATE (a:A), (b:B), (c:C)
      CREATE (a)-[:Y]->(b),
             (b)-[:Y]->(c)
      """
    When executing query:
      """
      MATCH (a)-[r1]->()-[r2]->(b)
      WITH [r1, r2] AS rs, a AS first, b AS second
        LIMIT 1
      MATCH (first)-[rs*]->(second)
      RETURN first, second
      """
    Then the result should be:
      | first | second |
      | (:A)  | (:C)   |
    And no side effects

  Scenario: Matching relationships into a list and matching variable length using the list, with bound nodes, wrong direction
    Given an empty graph
    And having executed:
      """
      CREATE (a:A), (b:B), (c:C)
      CREATE (a)-[:Y]->(b),
             (b)-[:Y]->(c)
      """
    When executing query:
      """
      MATCH (a)-[r1]->()-[r2]->(b)
      WITH [r1, r2] AS rs, a AS second, b AS first
        LIMIT 1
      MATCH (first)-[rs*]->(second)
      RETURN first, second
      """
    Then the result should be:
      | first | second |
    And no side effects

  Scenario: Matching and optionally matching with bound nodes in reverse direction
    Given an empty graph
    And having executed:
      """
      CREATE (:A)-[:T]->(:B)
      """
    When executing query:
      """
      MATCH (a1)-[r]->()
      WITH r, a1
        LIMIT 1
      OPTIONAL MATCH (a1)<-[r]-(b2)
      RETURN a1, r, b2
      """
    Then the result should be:
      | a1   | r    | b2   |
      | (:A) | [:T] | null |
    And no side effects

  Scenario: Matching and optionally matching with unbound nodes and equality predicate in reverse direction
    Given an empty graph
    And having executed:
      """
      CREATE (:A)-[:T]->(:B)
      """
    When executing query:
      """
      MATCH (a1)-[r]->()
      WITH r, a1
        LIMIT 1
      OPTIONAL MATCH (a2)<-[r]-(b2)
      WHERE a1 = a2
      RETURN a1, r, b2, a2
      """
    Then the result should be:
      | a1   | r    | b2   | a2   |
      | (:A) | [:T] | null | null |
    And no side effects

  Scenario: Fail when using property access on primitive type
    Given an empty graph
    And having executed:
      """
      CREATE ({prop: 42})
      """
    When executing query:
      """
      MATCH (n)
      WITH n.prop AS n2
      RETURN n2.prop
      """
    Then a TypeError should be raised at runtime: PropertyAccessOnNonMap

  Scenario: Matching and returning ordered results, with LIMIT
    Given an empty graph
    And having executed:
      """
      CREATE ({bar: 1}), ({bar: 3}), ({bar: 2})
      """
    When executing query:
      """
      MATCH (foo)
      RETURN foo.bar AS x
        ORDER BY x DESC
        LIMIT 4
      """
    Then the result should be, in order:
      | x |
      | 3 |
      | 2 |
      | 1 |
    And no side effects

  Scenario: Counting an empty graph
    Given an empty graph
    When executing query:
      """
      MATCH (a)
      RETURN count(a) > 0
      """
    Then the result should be:
      | count(a) > 0 |
      | false        |
    And no side effects

  Scenario: Matching variable length pattern with property predicate
    Given an empty graph
    And having executed:
      """
      CREATE (a:Artist:A), (b:Artist:B), (c:Artist:C)
      CREATE (a)-[:WORKED_WITH {year: 1987}]->(b),
             (b)-[:WORKED_WITH {year: 1988}]->(c)
      """
    When executing query:
      """
      MATCH (a:Artist)-[:WORKED_WITH* {year: 1988}]->(b:Artist)
      RETURN *
      """
    Then the result should be:
      | a           | b           |
      | (:Artist:B) | (:Artist:C) |
    And no side effects

  Scenario: Variable length pattern checking labels on endnodes
    Given an empty graph
    And having executed:
      """
      CREATE (a:Label {id: 0}), (b:Label {id: 1}), (c:Label {id: 2})
      CREATE (a)-[:T]->(b),
             (b)-[:T]->(c)
      """
    When executing query:
      """
      MATCH (a), (b)
      WHERE a.id = 0
        AND (a)-[:T]->(b:Label)
        OR (a)-[:T*]->(b:MissingLabel)
      RETURN DISTINCT b
      """
    Then the result should be:
      | b                |
      | (:Label {id: 1}) |
    And no side effects

  Scenario: Variable length pattern with label predicate on both sides
    Given an empty graph
    And having executed:
      """
      CREATE (a:Blue), (b:Red), (c:Green), (d:Yellow)
      CREATE (a)-[:T]->(b),
             (b)-[:T]->(c),
             (b)-[:T]->(d)
      """
    When executing query:
      """
      MATCH (a:Blue)-[r*]->(b:Green)
      RETURN count(r)
      """
    Then the result should be:
      | count(r) |
      | 1        |
    And no side effects

  Scenario: Undirected named path
    Given an empty graph
    And having executed:
      """
      CREATE (a:Movie), (b)
      CREATE (b)-[:T]->(a)
      """
    When executing query:
      """
      MATCH p = (n:Movie)--(m)
      RETURN p
        LIMIT 1
      """
    Then the result should be:
      | p                   |
      | <(:Movie)<-[:T]-()> |
    And no side effects

  Scenario: Named path with WITH
    Given an empty graph
    And having executed:
      """
      CREATE ()
      """
    When executing query:
      """
      MATCH p = (a)
      WITH p
      RETURN p
      """
    Then the result should be:
      | p    |
      | <()> |
    And no side effects

  Scenario: Named path with alternating directed/undirected relationships
    Given an empty graph
    And having executed:
      """
      CREATE (a:A), (b:B), (c:C)
      CREATE (b)-[:T]->(a),
             (c)-[:T]->(b)
      """
    When executing query:
      """
      MATCH p = (n)-->(m)--(o)
      RETURN p
      """
    Then the result should be:
      | p                            |
      | <(:C)-[:T]->(:B)-[:T]->(:A)> |
    And no side effects

  Scenario: Named path with multiple alternating directed/undirected relationships
    Given an empty graph
    And having executed:
      """
      CREATE (a:A), (b:B), (c:C), (d:D)
      CREATE (b)-[:T]->(a),
             (c)-[:T]->(b),
             (d)-[:T]->(c)
      """
    When executing query:
      """
      MATCH path = (n)-->(m)--(o)--(p)
      RETURN path
      """
    Then the result should be:
      | path                                    |
      | <(:D)-[:T]->(:C)-[:T]->(:B)-[:T]->(:A)> |
    And no side effects

  Scenario: Named path with undirected fixed variable length pattern
    Given an empty graph
    And having executed:
      """
      CREATE (db1:Start), (db2:End), (mid), (other)
      CREATE (mid)-[:CONNECTED_TO]->(db1),
             (mid)-[:CONNECTED_TO]->(db2),
             (mid)-[:CONNECTED_TO]->(db2),
             (mid)-[:CONNECTED_TO]->(other),
             (mid)-[:CONNECTED_TO]->(other)
      """
    When executing query:
      """
      MATCH topRoute = (:Start)<-[:CONNECTED_TO]-()-[:CONNECTED_TO*3..3]-(:End)
      RETURN topRoute
      """
    Then the result should be:
      | topRoute                                                                                       |
      | <(:Start)<-[:CONNECTED_TO]-()-[:CONNECTED_TO]->()<-[:CONNECTED_TO]-()-[:CONNECTED_TO]->(:End)> |
      | <(:Start)<-[:CONNECTED_TO]-()-[:CONNECTED_TO]->()<-[:CONNECTED_TO]-()-[:CONNECTED_TO]->(:End)> |
      | <(:Start)<-[:CONNECTED_TO]-()-[:CONNECTED_TO]->()<-[:CONNECTED_TO]-()-[:CONNECTED_TO]->(:End)> |
      | <(:Start)<-[:CONNECTED_TO]-()-[:CONNECTED_TO]->()<-[:CONNECTED_TO]-()-[:CONNECTED_TO]->(:End)> |
    And no side effects

  Scenario: Returning a node property value
    Given an empty graph
    And having executed:
      """
      CREATE ({prop: 1})
      """
    When executing query:
      """
      MATCH (a)
      RETURN a.prop
      """
    Then the result should be:
      | a.prop |
      | 1      |
    And no side effects

  Scenario: Returning a relationship property value
    Given an empty graph
    And having executed:
      """
      CREATE ()-[:T {prop: 1}]->()
      """
    When executing query:
      """
      MATCH ()-[r]->()
      RETURN r.prop
      """
    Then the result should be:
      | r.prop |
      | 1      |
    And no side effects

  Scenario: Projecting nodes and relationships
    Given an empty graph
    And having executed:
      """
      CREATE (a:A), (b:B)
      CREATE (a)-[:T]->(b)
      """
    When executing query:
      """
      MATCH (a)-[r]->()
      RETURN a AS foo, r AS bar
      """
    Then the result should be:
      | foo  | bar  |
      | (:A) | [:T] |
    And no side effects

  Scenario: Missing node property should become null
    Given an empty graph
    And having executed:
      """
      CREATE ({foo: 1})
      """
    When executing query:
      """
      MATCH (a)
      RETURN a.bar
      """
    Then the result should be:
      | a.bar |
      | null  |
    And no side effects

  Scenario: Missing relationship property should become null
    Given an empty graph
    And having executed:
      """
      CREATE ()-[:T {foo: 1}]->()
      """
    When executing query:
      """
      MATCH ()-[r]->()
      RETURN r.bar
      """
    Then the result should be:
      | r.bar |
      | null  |
    And no side effects

  Scenario: Returning multiple node property values
    Given an empty graph
    And having executed:
      """
      CREATE ({name: 'Philip J. Fry', age: 2046, seasons: [1, 2, 3, 4, 5, 6, 7]})
      """
    When executing query:
      """
      MATCH (a)
      RETURN a.name, a.age, a.seasons
      """
    Then the result should be:
      | a.name          | a.age | a.seasons             |
      | 'Philip J. Fry' | 2046  | [1, 2, 3, 4, 5, 6, 7] |
    And no side effects

  Scenario: Adding a property and a literal in projection
    Given an empty graph
    And having executed:
      """
      CREATE ({prop: 1})
      """
    When executing query:
      """
      MATCH (a)
      RETURN a.prop + 1 AS foo
      """
    Then the result should be:
      | foo |
      | 2   |
    And no side effects

  Scenario: Adding list properties in projection
    Given an empty graph
    And having executed:
      """
      CREATE ({prop1: [1, 2, 3], prop2: [4, 5]})
      """
    When executing query:
      """
      MATCH (a)
      RETURN a.prop2 + a.prop1 AS foo
      """
    Then the result should be:
      | foo             |
      | [4, 5, 1, 2, 3] |
    And no side effects

  Scenario: Variable length relationship variables are lists of relationships
    Given an empty graph
    And having executed:
      """
      CREATE (a), (b), (c)
      CREATE (a)-[:T]->(b)
      """
    When executing query:
      """
      MATCH ()-[r*0..1]-()
      RETURN last(r) AS l
      """
    Then the result should be:
      | l    |
      | [:T] |
      | [:T] |
      | null |
      | null |
      | null |
    And no side effects

  Scenario: Variable length patterns and nulls
    Given an empty graph
    And having executed:
      """
      CREATE (a:A), (b:B)
      """
    When executing query:
      """
      MATCH (a:A)
      OPTIONAL MATCH (a)-[:FOO]->(b:B)
      OPTIONAL MATCH (b)<-[:BAR*]-(c:B)
      RETURN a, b, c
      """
    Then the result should be:
      | a    | b    | c    |
      | (:A) | null | null |
    And no side effects

  Scenario: Projecting a list of nodes and relationships
    Given an empty graph
    And having executed:
      """
      CREATE (a:A), (b:B)
      CREATE (a)-[:T]->(b)
      """
    When executing query:
      """
      MATCH (n)-[r]->(m)
      RETURN [n, r, m] AS r
      """
    Then the result should be:
      | r                  |
      | [(:A), [:T], (:B)] |
    And no side effects

  Scenario: Projecting a map of nodes and relationships
    Given an empty graph
    And having executed:
      """
      CREATE (a:A), (b:B)
      CREATE (a)-[:T]->(b)
      """
    When executing query:
      """
      MATCH (n)-[r]->(m)
      RETURN {node1: n, rel: r, node2: m} AS m
      """
    Then the result should be:
      | m                                     |
      | {node1: (:A), rel: [:T], node2: (:B)} |
    And no side effects

  Scenario: Respecting direction when matching existing path
    Given an empty graph
    And having executed:
      """
      CREATE (a {prop: 'a'}), (b {prop: 'b'})
      CREATE (a)-[:T]->(b)
      """
    When executing query:
      """
      MATCH p = ({prop: 'a'})-->({prop: 'b'})
      RETURN p
      """
    Then the result should be:
      | p                                   |
      | <({prop: 'a'})-[:T]->({prop: 'b'})> |
    And no side effects

  Scenario: Respecting direction when matching non-existent path
    Given an empty graph
    And having executed:
      """
      CREATE (a {prop: 'a'}), (b {prop: 'b'})
      CREATE (a)-[:T]->(b)
      """
    When executing query:
      """
      MATCH p = ({prop: 'a'})<--({prop: 'b'})
      RETURN p
      """
    Then the result should be:
      | p |
    And no side effects

  Scenario: Respecting direction when matching non-existent path with multiple directions
    Given an empty graph
    And having executed:
      """
      CREATE (a), (b)
      CREATE (a)-[:T]->(b),
             (b)-[:T]->(a)
      """
    When executing query:
      """
      MATCH p = (n)-->(k)<--(n)
      RETURN p
      """
    Then the result should be:
      | p |
    And no side effects

  Scenario: Matching path with both directions should respect other directions
    Given an empty graph
    And having executed:
      """
      CREATE (a:A), (b:B)
      CREATE (a)-[:T1]->(b),
             (b)-[:T2]->(a)
      """
    When executing query:
      """
      MATCH p = (n)<-->(k)<--(n)
      RETURN p
      """
    Then the result should be:
      | p                              |
      | <(:A)<-[:T2]-(:B)<-[:T1]-(:A)> |
      | <(:B)<-[:T1]-(:A)<-[:T2]-(:B)> |
    And no side effects

  Scenario: Matching path with multiple bidirectional relationships
    Given an empty graph
    And having executed:
      """
      CREATE (a:A), (b:B)
      CREATE (a)-[:T1]->(b),
             (b)-[:T2]->(a)
      """
    When executing query:
      """
      MATCH p=(n)<-->(k)<-->(n)
      RETURN p
      """
    Then the result should be:
      | p                              |
      | <(:A)<-[:T2]-(:B)<-[:T1]-(:A)> |
      | <(:A)-[:T1]->(:B)-[:T2]->(:A)> |
      | <(:B)<-[:T1]-(:A)<-[:T2]-(:B)> |
      | <(:B)-[:T2]->(:A)-[:T1]->(:B)> |
    And no side effects

  Scenario: Matching nodes with many labels
    Given an empty graph
    And having executed:
      """
      CREATE (a:A:B:C:D:E:F:G:H:I:J:K:L:M),
             (b:U:V:W:X:Y:Z)
      CREATE (a)-[:T]->(b)
      """
    When executing query:
      """
      MATCH (n:A:B:C:D:E:F:G:H:I:J:K:L:M)-[:T]->(m:Z:Y:X:W:V:U)
      RETURN n, m
      """
    Then the result should be:
      | n                            | m              |
      | (:A:B:C:D:E:F:G:H:I:J:K:L:M) | (:Z:Y:X:W:V:U) |
    And no side effects

  Scenario: Matching longer variable length paths
    Given an empty graph
    And having executed:
      """
      CREATE (a {prop: 'start'}), (b {prop: 'end'})
      WITH *
      UNWIND range(1, 20) AS i
      CREATE (n {prop: i})
      WITH [a] + collect(n) + [b] AS nodeList
      UNWIND range(0, size(nodeList) - 2, 1) AS i
      WITH nodeList[i] AS n1, nodeList[i+1] AS n2
      CREATE (n1)-[:T]->(n2)
      """
    When executing query:
      """
      MATCH (n {prop: 'start'})-[:T*]->(m {prop: 'end'})
      RETURN m
      """
    Then the result should be:
      | m               |
      | ({prop: 'end'}) |
    And no side effects

  Scenario: Counting rows after MATCH, MERGE, OPTIONAL MATCH
    Given an empty graph
    And having executed:
      """
      CREATE (a:A), (b:B)
      CREATE (a)-[:T1]->(b),
             (b)-[:T2]->(a)
      """
    When executing query:
      """
      MATCH (a)
      MERGE (b)
      WITH *
      OPTIONAL MATCH (a)--(b)
      RETURN count(*)
      """
    Then the result should be:
      | count(*) |
      | 6        |
    And no side effects

  Scenario: Matching a self-loop
    Given an empty graph
    And having executed:
      """
      CREATE (a)
      CREATE (a)-[:T]->(a)
      """
    When executing query:
      """
      MATCH ()-[r]-()
      RETURN type(r) AS r
      """
    Then the result should be:
      | r   |
      | 'T' |
    And no side effects
