From d0fb4d724214ab258a704dd3a0fc2436af243ba7 Mon Sep 17 00:00:00 2001
From: florijan <florijan@memgraph.io>
Date: Fri, 6 Oct 2017 09:33:12 +0200
Subject: [PATCH] BFS - lower bound support

Summary: This is not a very important functionality, but it turned out simple to do, so let's add it to have a consistent query support.

Reviewers: buda, teon.banek

Reviewed By: teon.banek

Subscribers: pullbot

Differential Revision: https://phabricator.memgraph.io/D862
---
 docs/user_technical/open-cypher.md              |  6 ++----
 src/query/frontend/ast/cypher_main_visitor.cpp  |  2 --
 src/query/plan/operator.cpp                     | 12 ++++++++++--
 .../memgraph_V1/features/memgraph_bfs.feature   | 17 ++++++++++++++++-
 4 files changed, 28 insertions(+), 9 deletions(-)

diff --git a/docs/user_technical/open-cypher.md b/docs/user_technical/open-cypher.md
index 695e04128..373b41cb9 100644
--- a/docs/user_technical/open-cypher.md
+++ b/docs/user_technical/open-cypher.md
@@ -436,10 +436,8 @@ destination node. Furthermore, it's possible to find multiple paths to multiple
 nodes regardless of their length. Also, it is possible to simply go through a node's
 neighbourhood in breadth-first manner.
 
-It is fair to say there are a few drawbacks too. Currently, it isn't possible to get
-all shortest paths to a single node using Memgraph's breadth-first expansion. Also
-property maps (in curly brackets) are not supported with a BFS. These features will
-most likely be included in subsequent Memgraph releases.
+Currently, it isn't possible to get all shortest paths to a single node using
+Memgraph's breadth-first expansion.
 
 #### UNWIND
 
diff --git a/src/query/frontend/ast/cypher_main_visitor.cpp b/src/query/frontend/ast/cypher_main_visitor.cpp
index 8c4aa285e..88ff750ed 100644
--- a/src/query/frontend/ast/cypher_main_visitor.cpp
+++ b/src/query/frontend/ast/cypher_main_visitor.cpp
@@ -570,8 +570,6 @@ antlrcpp::Any CypherMainVisitor::visitVariableExpansion(
     upper = ctx->expression()[1]->accept(this);
   }
 
-  if (is_bfs && lower)
-    throw SemanticException("BFS does not support lower bounds");
   return std::make_tuple(is_bfs, lower, upper);
 }
 
diff --git a/src/query/plan/operator.cpp b/src/query/plan/operator.cpp
index b6dea0846..1ece0799d 100644
--- a/src/query/plan/operator.cpp
+++ b/src/query/plan/operator.cpp
@@ -927,6 +927,10 @@ class ExpandBreadthFirstCursor : public query::plan::Cursor {
         SwitchAccessor(vertex, self_.graph_view_);
         processed_.emplace(vertex, std::experimental::nullopt);
         expand_from_vertex(vertex);
+        lower_bound_ = self_.lower_bound_
+                           ? EvaluateInt(evaluator, self_.lower_bound_,
+                                         "Min depth in breadth-first expansion")
+                           : 1;
         upper_bound_ = self_.upper_bound_
                            ? EvaluateInt(evaluator, self_.upper_bound_,
                                          "Max depth in breadth-first expansion")
@@ -963,6 +967,9 @@ class ExpandBreadthFirstCursor : public query::plan::Cursor {
       if (static_cast<int>(edge_list.size()) < upper_bound_)
         expand_from_vertex(expansion.second);
 
+      if (static_cast<int64_t>(edge_list.size()) < lower_bound_)
+        continue;
+
       // place destination node on the frame, handle existence flag
       if (self_.existing_node_) {
         TypedValue &node = frame[self_.node_symbol_];
@@ -990,8 +997,9 @@ class ExpandBreadthFirstCursor : public query::plan::Cursor {
   GraphDbAccessor &db_;
   const std::unique_ptr<query::plan::Cursor> input_cursor_;
 
-  // maximum depth of the expansion. calculated on each pull
-  // from the input, the initial value is irrelevant.
+  // Depth bounds. Calculated on each pull from the input, the initial value is
+  // irrelevant.
+  int lower_bound_{-1};
   int upper_bound_{-1};
 
   // maps vertices to the edge they got expanded from. it is an optional
diff --git a/tests/qa/tck_engine/tests/memgraph_V1/features/memgraph_bfs.feature b/tests/qa/tck_engine/tests/memgraph_V1/features/memgraph_bfs.feature
index f6c6a457b..8c4e21607 100644
--- a/tests/qa/tck_engine/tests/memgraph_V1/features/memgraph_bfs.feature
+++ b/tests/qa/tck_engine/tests/memgraph_V1/features/memgraph_bfs.feature
@@ -1,6 +1,6 @@
 Feature: Bfs
 
-  Scenario: Test match BFS depth blocked
+  Scenario: Test match BFS upper bound
       Given an empty graph
       And having executed:
           """
@@ -15,6 +15,21 @@ Feature: Bfs
           | '0' | '1.1' |
           | '0' | '1.2' |
 
+  Scenario: Test match BFS lower bound
+      Given an empty graph
+      And having executed:
+          """
+          CREATE (n {a:'0'})-[:r]->({a:'1.1'})-[:r]->({a:'2.1'})-[:r]->({a:'3.1'})
+          """
+      When executing query:
+          """
+          MATCH (n {a:'0'})-[*bfs 2..]->(m) RETURN n.a, m.a
+          """
+      Then the result should be:
+          | n.a | m.a   |
+          | '0' | '2.1' |
+          | '0' | '3.1' |
+
   Scenario: Test match BFS filtered
       Given an empty graph
       And having executed: