From 329818b1b07d9a6e3d7493ea531cc2f697c7a2df Mon Sep 17 00:00:00 2001
From: Matej Ferencevic <matej.ferencevic@memgraph.io>
Date: Tue, 12 Nov 2019 10:47:02 +0100
Subject: [PATCH] Make the Cypher dumper a function

Summary:
The dumper is now a function and doesn't have to worry about any state. The
function streams the Cypher queries directly to the client. This diff also
makes the dumper work with storage v2.

Reviewers: teon.banek

Reviewed By: teon.banek

Subscribers: pullbot

Differential Revision: https://phabricator.memgraph.io/D2545
---
 src/CMakeLists.txt                            |   4 +-
 src/database/single_node/dump.hpp             | 126 ----
 src/{database/single_node => query}/dump.cpp  | 165 ++---
 src/query/dump.hpp                            |  12 +
 .../interpret/awesome_memgraph_functions.cpp  |   3 -
 src/query/interpreter.cpp                     |  14 +-
 src/query/interpreter.hpp                     |  46 +-
 src/query/stream.hpp                          |  56 ++
 tests/unit/CMakeLists.txt                     |   6 +-
 tests/unit/database_dump.cpp                  | 596 -----------------
 tests/unit/query_dump.cpp                     | 632 ++++++++++++++++++
 11 files changed, 799 insertions(+), 861 deletions(-)
 delete mode 100644 src/database/single_node/dump.hpp
 rename src/{database/single_node => query}/dump.cpp (66%)
 create mode 100644 src/query/dump.hpp
 create mode 100644 src/query/stream.hpp
 delete mode 100644 tests/unit/database_dump.cpp
 create mode 100644 tests/unit/query_dump.cpp

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 25cad88ba..019be6617 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -36,7 +36,6 @@ set(mg_single_node_sources
     audit/log.cpp
     data_structures/concurrent/skiplist_gc.cpp
     database/single_node/config.cpp
-    database/single_node/dump.cpp
     database/single_node/graph_db.cpp
     database/single_node/graph_db_accessor.cpp
     durability/single_node/state_delta.cpp
@@ -47,6 +46,7 @@ set(mg_single_node_sources
     glue/auth.cpp
     glue/communication.cpp
     query/common.cpp
+    query/dump.cpp
     query/frontend/ast/cypher_main_visitor.cpp
     query/frontend/ast/pretty_print.cpp
     query/frontend/parsing.cpp
@@ -120,10 +120,10 @@ target_link_libraries(mg-single-node "-Wl,--dynamic-list=${CMAKE_SOURCE_DIR}/inc
 set(mg_single_node_v2_sources
     ${lcp_common_cpp_files}
     audit/log.cpp
-    database/single_node/dump.cpp
     glue/auth.cpp
     glue/communication.cpp
     query/common.cpp
+    query/dump.cpp
     query/frontend/ast/cypher_main_visitor.cpp
     query/frontend/ast/pretty_print.cpp
     query/frontend/parsing.cpp
diff --git a/src/database/single_node/dump.hpp b/src/database/single_node/dump.hpp
deleted file mode 100644
index d6d80c42f..000000000
--- a/src/database/single_node/dump.hpp
+++ /dev/null
@@ -1,126 +0,0 @@
-#pragma once
-
-#include <ostream>
-
-// TODO: Move this whole file to query folder
-#include "query/db_accessor.hpp"
-#ifndef MG_SINGLE_NODE_V2
-#include "storage/common/constraints/unique_constraints.hpp"
-#endif
-
-namespace database {
-
-/// Class which generates sequence of openCypher queries which can be used to
-/// dump the database state.
-///
-/// Currently only dumps index keys, vertices and edges, one-by-one in multiple
-/// queries.
-class CypherDumpGenerator {
- public:
-  explicit CypherDumpGenerator(query::DbAccessor *dba);
-
-  CypherDumpGenerator(const CypherDumpGenerator &other) = delete;
-  // NOLINTNEXTLINE(performance-noexcept-move-constructor)
-  CypherDumpGenerator(CypherDumpGenerator &&other) = default;
-  CypherDumpGenerator &operator=(const CypherDumpGenerator &other) = delete;
-  CypherDumpGenerator &operator=(CypherDumpGenerator &&other) = delete;
-  ~CypherDumpGenerator() = default;
-
-  bool NextQuery(std::ostream *os);
-
- private:
-  // A helper class that keeps container and its iterators.
-  template <typename TContainer>
-  class ContainerState {
-   public:
-    explicit ContainerState(TContainer container)
-        : container_(std::move(container)),
-          current_(container_.begin()),
-          end_(container_.end()),
-          empty_(current_ == end_) {}
-
-    ContainerState(const ContainerState &other) = delete;
-    // NOLINTNEXTLINE(hicpp-noexcept-move,performance-noexcept-move-constructor)
-    ContainerState(ContainerState &&other) = default;
-    ContainerState &operator=(const ContainerState &other) = delete;
-    ContainerState &operator=(ContainerState &&other) = delete;
-    ~ContainerState() = default;
-
-    auto GetCurrentAndAdvance() {
-      auto to_be_returned = current_;
-      if (current_ != end_) ++current_;
-      return to_be_returned;
-    }
-
-    bool ReachedEnd() const { return current_ == end_; }
-
-    // Returns true if the container is empty.
-    bool Empty() const { return empty_; }
-
-   private:
-    TContainer container_;
-
-    using TIterator = decltype(container_.begin());
-    TIterator current_;
-    TIterator end_;
-
-    bool empty_;
-  };
-
-  class EdgesState {
-   private:
-    using TVertices = decltype(std::declval<query::DbAccessor>().Vertices(
-        std::declval<storage::View>()));
-
-   public:
-    explicit EdgesState(TVertices vertices)
-        : vertices_state_(std::move(vertices)) {
-      FindNext();
-    }
-
-    EdgesState(const EdgesState &other) = delete;
-    // NOLINTNEXTLINE(hicpp-noexcept-move,performance-noexcept-move-constructor)
-    EdgesState(EdgesState &&other) = default;
-    EdgesState &operator=(const EdgesState &other) = delete;
-    EdgesState &operator=(EdgesState &&other) = delete;
-    ~EdgesState() = default;
-
-    auto GetCurrentAndAdvance() {
-      auto edge = *current_edge_;
-      FindNext();
-      return edge;
-    }
-
-    bool ReachedEnd() const { return !current_edge_; }
-
-    // Returns true if the container is empty.
-    bool Empty() const { return !current_edge_; }
-
-   private:
-    void FindNext();
-
-    std::optional<ContainerState<TVertices>> vertices_state_;
-    std::optional<ContainerState<std::vector<query::EdgeAccessor>>>
-        edges_list_state_;
-    std::optional<query::EdgeAccessor> current_edge_;
-  };
-
-  query::DbAccessor *dba_;
-
-  bool created_internal_index_;
-  bool cleaned_internal_index_;
-  bool cleaned_internal_label_property_;
-
-#ifndef MG_SINGLE_NODE_V2
-  std::optional<ContainerState<std::vector<LabelPropertyIndex::Key>>>
-      indices_state_;
-  std::optional<
-      ContainerState<std::vector<storage::constraints::ConstraintEntry>>>
-      unique_constraints_state_;
-#endif
-  std::optional<ContainerState<decltype(dba_->Vertices(storage::View::OLD))>>
-      vertices_state_;
-  std::optional<EdgesState> edges_state_;
-};
-
-}  // namespace database
diff --git a/src/database/single_node/dump.cpp b/src/query/dump.cpp
similarity index 66%
rename from src/database/single_node/dump.cpp
rename to src/query/dump.cpp
index 2084ccfaf..c32463209 100644
--- a/src/database/single_node/dump.cpp
+++ b/src/query/dump.cpp
@@ -1,4 +1,4 @@
-#include "database/single_node/dump.hpp"
+#include "query/dump.hpp"
 
 #include <iomanip>
 #include <limits>
@@ -14,7 +14,7 @@
 #include "utils/algorithm.hpp"
 #include "utils/string.hpp"
 
-namespace database {
+namespace query {
 
 namespace {
 
@@ -164,9 +164,28 @@ void DumpEdge(std::ostream *os, query::DbAccessor *dba,
   *os << "]->(v);";
 }
 
-#ifndef MG_SINGLE_NODE_V2
+#ifdef MG_SINGLE_NODE_V2
+void DumpLabelIndex(std::ostream *os, query::DbAccessor *dba,
+                    const storage::LabelId label) {
+  *os << "CREATE INDEX ON :" << dba->LabelToName(label) << ";";
+}
+
+void DumpLabelPropertyIndex(std::ostream *os, query::DbAccessor *dba,
+                            storage::LabelId label,
+                            storage::PropertyId property) {
+  *os << "CREATE INDEX ON :" << dba->LabelToName(label) << "("
+      << dba->PropertyToName(property) << ");";
+}
+
+void DumpExistenceConstraint(std::ostream *os, query::DbAccessor *dba,
+                             storage::LabelId label,
+                             storage::PropertyId property) {
+  *os << "CREATE CONSTRAINT ON (u:" << dba->LabelToName(label)
+      << ") ASSERT EXISTS (u." << dba->PropertyToName(property) << ");";
+}
+#else
 void DumpIndexKey(std::ostream *os, query::DbAccessor *dba,
-                  const LabelPropertyIndex::Key &key) {
+                  const database::LabelPropertyIndex::Key &key) {
   *os << "CREATE INDEX ON :" << dba->LabelToName(key.label_) << "("
       << dba->PropertyToName(key.property_) << ");";
 }
@@ -186,85 +205,79 @@ void DumpUniqueConstraint(
 
 }  // namespace
 
-CypherDumpGenerator::CypherDumpGenerator(query::DbAccessor *dba)
-    : dba_(dba),
-      created_internal_index_(false),
-      cleaned_internal_index_(false),
-      cleaned_internal_label_property_(false) {
-  CHECK(dba);
+void DumpDatabaseToCypherQueries(query::DbAccessor *dba, AnyStream *stream) {
 #ifdef MG_SINGLE_NODE_V2
-  throw utils::NotYetImplemented("Dumping indices and constraints");
-#else
-  indices_state_.emplace(dba->GetIndicesKeys());
-  unique_constraints_state_.emplace(dba->ListUniqueConstraints());
-#endif
-  vertices_state_.emplace(dba->Vertices(storage::View::OLD));
-  edges_state_.emplace(dba->Vertices(storage::View::OLD));
-}
-
-bool CypherDumpGenerator::NextQuery(std::ostream *os) {
-#ifdef MG_SINGLE_NODE_V2
-  if (!vertices_state_->Empty() && !created_internal_index_) {
-#else
-  if (!indices_state_->ReachedEnd()) {
-    DumpIndexKey(os, dba_, *indices_state_->GetCurrentAndAdvance());
-    return true;
-  } else if (!vertices_state_->Empty() && !created_internal_index_) {
-#endif
-    *os << "CREATE INDEX ON :" << kInternalVertexLabel << "("
-        << kInternalPropertyId << ");";
-    created_internal_index_ = true;
-    return true;
-#ifndef MG_SINGLE_NODE_V2
-  } else if (!unique_constraints_state_->ReachedEnd()) {
-    DumpUniqueConstraint(os, dba_,
-                         *unique_constraints_state_->GetCurrentAndAdvance());
-    return true;
-#endif
-  } else if (!vertices_state_->ReachedEnd()) {
-    DumpVertex(os, dba_, *vertices_state_->GetCurrentAndAdvance());
-    return true;
-  } else if (!edges_state_->ReachedEnd()) {
-    DumpEdge(os, dba_, edges_state_->GetCurrentAndAdvance());
-    return true;
-  } else if (!vertices_state_->Empty() && !cleaned_internal_index_) {
-    *os << "DROP INDEX ON :" << kInternalVertexLabel << "("
-        << kInternalPropertyId << ");";
-    cleaned_internal_index_ = true;
-    return true;
-  } else if (!vertices_state_->Empty() && !cleaned_internal_label_property_) {
-    *os << "MATCH (u) REMOVE u:" << kInternalVertexLabel << ", u."
-        << kInternalPropertyId << ";";
-    cleaned_internal_label_property_ = true;
-    return true;
+  {
+    auto info = dba->ListAllIndices();
+    for (const auto &item : info.label) {
+      std::ostringstream os;
+      DumpLabelIndex(&os, dba, item);
+      stream->Result({TypedValue(os.str())});
+    }
+    for (const auto &item : info.label_property) {
+      std::ostringstream os;
+      DumpLabelPropertyIndex(&os, dba, item.first, item.second);
+      stream->Result({TypedValue(os.str())});
+    }
   }
-
-  return false;
-}
-
-void CypherDumpGenerator::EdgesState::FindNext() {
-  current_edge_ = std::nullopt;
-  if (edges_list_state_ && !edges_list_state_->ReachedEnd()) {
-    current_edge_ = *edges_list_state_->GetCurrentAndAdvance();
-    return;
+  {
+    auto info = dba->ListAllConstraints();
+    for (const auto &item : info.existence) {
+      std::ostringstream os;
+      DumpExistenceConstraint(&os, dba, item.first, item.second);
+      stream->Result({TypedValue(os.str())});
+    }
   }
-  while (!vertices_state_->ReachedEnd()) {
-    auto vertex = *vertices_state_->GetCurrentAndAdvance();
+#else
+  for (const auto &item : dba->GetIndicesKeys()) {
+    std::ostringstream os;
+    DumpIndexKey(&os, dba, item);
+    stream->Result({TypedValue(os.str())});
+  }
+  for (const auto &item : dba->ListUniqueConstraints()) {
+    std::ostringstream os;
+    DumpUniqueConstraint(&os, dba, item);
+    stream->Result({TypedValue(os.str())});
+  }
+#endif
+
+  auto vertices = dba->Vertices(storage::View::OLD);
+  bool internal_index_created = false;
+  if (vertices.begin() != vertices.end()) {
+    std::ostringstream os;
+    os << "CREATE INDEX ON :" << kInternalVertexLabel << "("
+       << kInternalPropertyId << ");";
+    stream->Result({TypedValue(os.str())});
+    internal_index_created = true;
+  }
+  for (const auto &vertex : vertices) {
+    std::ostringstream os;
+    DumpVertex(&os, dba, vertex);
+    stream->Result({TypedValue(os.str())});
+  }
+  for (const auto &vertex : vertices) {
     auto maybe_edges = vertex.OutEdges(storage::View::OLD);
     CHECK(maybe_edges.HasValue()) << "Invalid database state!";
-    auto &edges = maybe_edges.GetValue();
-    // We convert the itertools object to a list of edge accessors here because
-    // itertools have suspicious object lifetime handling.
-    std::vector<query::EdgeAccessor> edges_list;
-    for (auto edge : edges) {
-      edges_list.push_back(edge);
+    for (const auto &edge : *maybe_edges) {
+      std::ostringstream os;
+      DumpEdge(&os, dba, edge);
+      stream->Result({TypedValue(os.str())});
     }
-    if (!edges_list.empty()) {
-      edges_list_state_.emplace(std::move(edges_list));
-      current_edge_ = *edges_list_state_->GetCurrentAndAdvance();
-      break;
+  }
+  if (internal_index_created) {
+    {
+      std::ostringstream os;
+      os << "DROP INDEX ON :" << kInternalVertexLabel << "("
+         << kInternalPropertyId << ");";
+      stream->Result({TypedValue(os.str())});
+    }
+    {
+      std::ostringstream os;
+      os << "MATCH (u) REMOVE u:" << kInternalVertexLabel << ", u."
+         << kInternalPropertyId << ";";
+      stream->Result({TypedValue(os.str())});
     }
   }
 }
 
-}  // namespace database
+}  // namespace query
diff --git a/src/query/dump.hpp b/src/query/dump.hpp
new file mode 100644
index 000000000..216916a5c
--- /dev/null
+++ b/src/query/dump.hpp
@@ -0,0 +1,12 @@
+#pragma once
+
+#include <ostream>
+
+#include "query/db_accessor.hpp"
+#include "query/stream.hpp"
+
+namespace query {
+
+void DumpDatabaseToCypherQueries(query::DbAccessor *dba, AnyStream *stream);
+
+}  // namespace query
diff --git a/src/query/interpret/awesome_memgraph_functions.cpp b/src/query/interpret/awesome_memgraph_functions.cpp
index 16a8981ea..f088f33e1 100644
--- a/src/query/interpret/awesome_memgraph_functions.cpp
+++ b/src/query/interpret/awesome_memgraph_functions.cpp
@@ -7,9 +7,6 @@
 #include <functional>
 #include <random>
 
-#ifndef MG_SINGLE_NODE_V2
-#include "database/single_node/dump.hpp"
-#endif
 #include "query/db_accessor.hpp"
 #include "query/exceptions.hpp"
 #include "query/typed_value.hpp"
diff --git a/src/query/interpreter.cpp b/src/query/interpreter.cpp
index a035ab49d..ee09b674c 100644
--- a/src/query/interpreter.cpp
+++ b/src/query/interpreter.cpp
@@ -5,11 +5,11 @@
 #include <glog/logging.h>
 
 #include "auth/auth.hpp"
-#ifndef MG_SINGLE_NODE_HA
-#include "database/single_node/dump.hpp"
-#endif
 #include "glue/auth.hpp"
 #include "glue/communication.hpp"
+#ifndef MG_SINGLE_NODE_HA
+#include "query/dump.hpp"
+#endif
 #include "query/exceptions.hpp"
 #include "query/frontend/ast/cypher_main_visitor.hpp"
 #include "query/frontend/opencypher/parser.hpp"
@@ -797,13 +797,7 @@ PreparedQuery PrepareDumpQuery(
       [interpreter_context](AnyStream *stream) {
         auto dba = interpreter_context->db->Access();
         query::DbAccessor query_dba{&dba};
-        std::ostringstream oss;
-        database::CypherDumpGenerator dump_generator{&query_dba};
-
-        while (dump_generator.NextQuery(&oss)) {
-          stream->Result({TypedValue(oss.str())});
-        }
-
+        DumpDatabaseToCypherQueries(&query_dba, stream);
         return QueryHandlerResult::NOTHING;
       }};
 #else
diff --git a/src/query/interpreter.hpp b/src/query/interpreter.hpp
index ea58f04d7..14d7c747b 100644
--- a/src/query/interpreter.hpp
+++ b/src/query/interpreter.hpp
@@ -11,6 +11,7 @@
 #include "query/frontend/stripped.hpp"
 #include "query/interpret/frame.hpp"
 #include "query/plan/operator.hpp"
+#include "query/stream.hpp"
 #include "utils/memory.hpp"
 #include "utils/skip_list.hpp"
 #include "utils/spin_lock.hpp"
@@ -30,51 +31,6 @@ static constexpr size_t kExecutionMemoryBlockSize = 1U * 1024U * 1024U;
 
 enum class QueryHandlerResult { COMMIT, ABORT, NOTHING };
 
-/**
- * `AnyStream` can wrap *any* type implementing the `Stream` concept into a
- * single type.
- *
- * The type erasure technique is used. The original type which an `AnyStream`
- * was constructed from is "erased", as `AnyStream` is not a class template and
- * doesn't use the type in any way. Client code can then program just for
- * `AnyStream`, rather than using static polymorphism to handle any type
- * implementing the `Stream` concept.
- */
-class AnyStream final {
- public:
-  template <class TStream>
-  AnyStream(TStream *stream, utils::MemoryResource *memory_resource)
-      : content_{utils::Allocator<GenericWrapper<TStream>>{memory_resource}
-                     .template new_object<GenericWrapper<TStream>>(stream),
-                 [memory_resource](Wrapper *ptr) {
-                   utils::Allocator<GenericWrapper<TStream>>{memory_resource}
-                       .template delete_object<GenericWrapper<TStream>>(
-                           static_cast<GenericWrapper<TStream> *>(ptr));
-                 }} {}
-
-  void Result(const std::vector<TypedValue> &values) {
-    content_->Result(values);
-  }
-
- private:
-  struct Wrapper {
-    virtual void Result(const std::vector<TypedValue> &values) = 0;
-  };
-
-  template <class TStream>
-  struct GenericWrapper final : public Wrapper {
-    explicit GenericWrapper(TStream *stream) : stream_{stream} {}
-
-    void Result(const std::vector<TypedValue> &values) override {
-      stream_->Result(values);
-    }
-
-    TStream *stream_;
-  };
-
-  std::unique_ptr<Wrapper, std::function<void(Wrapper *)>> content_;
-};
-
 /**
  * A container for data related to the preparation of a query.
  */
diff --git a/src/query/stream.hpp b/src/query/stream.hpp
new file mode 100644
index 000000000..c7d5de6a3
--- /dev/null
+++ b/src/query/stream.hpp
@@ -0,0 +1,56 @@
+#pragma once
+
+#include <memory>
+#include <vector>
+
+#include "query/typed_value.hpp"
+#include "utils/memory.hpp"
+
+namespace query {
+
+/**
+ * `AnyStream` can wrap *any* type implementing the `Stream` concept into a
+ * single type.
+ *
+ * The type erasure technique is used. The original type which an `AnyStream`
+ * was constructed from is "erased", as `AnyStream` is not a class template and
+ * doesn't use the type in any way. Client code can then program just for
+ * `AnyStream`, rather than using static polymorphism to handle any type
+ * implementing the `Stream` concept.
+ */
+class AnyStream final {
+ public:
+  template <class TStream>
+  AnyStream(TStream *stream, utils::MemoryResource *memory_resource)
+      : content_{utils::Allocator<GenericWrapper<TStream>>{memory_resource}
+                     .template new_object<GenericWrapper<TStream>>(stream),
+                 [memory_resource](Wrapper *ptr) {
+                   utils::Allocator<GenericWrapper<TStream>>{memory_resource}
+                       .template delete_object<GenericWrapper<TStream>>(
+                           static_cast<GenericWrapper<TStream> *>(ptr));
+                 }} {}
+
+  void Result(const std::vector<TypedValue> &values) {
+    content_->Result(values);
+  }
+
+ private:
+  struct Wrapper {
+    virtual void Result(const std::vector<TypedValue> &values) = 0;
+  };
+
+  template <class TStream>
+  struct GenericWrapper final : public Wrapper {
+    explicit GenericWrapper(TStream *stream) : stream_{stream} {}
+
+    void Result(const std::vector<TypedValue> &values) override {
+      stream_->Result(values);
+    }
+
+    TStream *stream_;
+  };
+
+  std::unique_ptr<Wrapper, std::function<void(Wrapper *)>> content_;
+};
+
+}  // namespace query
diff --git a/tests/unit/CMakeLists.txt b/tests/unit/CMakeLists.txt
index 3b85418bb..d4c107f19 100644
--- a/tests/unit/CMakeLists.txt
+++ b/tests/unit/CMakeLists.txt
@@ -36,9 +36,6 @@ target_link_libraries(${test_prefix}concurrent_map mg-single-node kvstore_dummy_
 add_unit_test(cypher_main_visitor.cpp)
 target_link_libraries(${test_prefix}cypher_main_visitor mg-single-node kvstore_dummy_lib)
 
-add_unit_test(database_dump.cpp)
-target_link_libraries(${test_prefix}database_dump mg-single-node kvstore_dummy_lib)
-
 add_unit_test(database_key_index.cpp)
 target_link_libraries(${test_prefix}database_key_index mg-single-node kvstore_dummy_lib)
 
@@ -117,6 +114,9 @@ target_link_libraries(${test_prefix}query_expression_evaluator mg-single-node kv
 add_unit_test(plan_pretty_print.cpp)
 target_link_libraries(${test_prefix}plan_pretty_print mg-single-node kvstore_dummy_lib)
 
+add_unit_test(query_dump.cpp)
+target_link_libraries(${test_prefix}query_dump mg-single-node kvstore_dummy_lib)
+
 add_unit_test(query_pretty_print.cpp)
 target_link_libraries(${test_prefix}query_pretty_print mg-single-node kvstore_dummy_lib)
 
diff --git a/tests/unit/database_dump.cpp b/tests/unit/database_dump.cpp
deleted file mode 100644
index 2312c1ca9..000000000
--- a/tests/unit/database_dump.cpp
+++ /dev/null
@@ -1,596 +0,0 @@
-#include <gtest/gtest.h>
-
-#include <map>
-#include <set>
-#include <vector>
-
-#include <glog/logging.h>
-
-#include "communication/result_stream_faker.hpp"
-#include "database/graph_db.hpp"
-#include "database/graph_db_accessor.hpp"
-#include "database/single_node/dump.hpp"
-#include "query/interpreter.hpp"
-#include "query/typed_value.hpp"
-#include "storage/common/types/property_value.hpp"
-
-using database::CypherDumpGenerator;
-using database::GraphDbAccessor;
-
-const char *kPropertyId = "property_id";
-
-const char *kCreateInternalIndex = "CREATE INDEX ON :__mg_vertex__(__mg_id__);";
-const char *kDropInternalIndex = "DROP INDEX ON :__mg_vertex__(__mg_id__);";
-const char *kRemoveInternalLabelProperty =
-    "MATCH (u) REMOVE u:__mg_vertex__, u.__mg_id__;";
-
-// A helper struct that contains info about database that is used to compare
-// two databases (to check if their states are the same). It is assumed that
-// each vertex and each edge have unique integer property under key
-// `kPropertyId`.
-struct DatabaseState {
-  struct Vertex {
-    int64_t id;
-    std::set<std::string> labels;
-    std::map<std::string, PropertyValue> props;
-  };
-
-  struct Edge {
-    int64_t from, to;
-    std::string edge_type;
-    std::map<std::string, PropertyValue> props;
-  };
-
-  struct IndexKey {
-    std::string label;
-    std::string property;
-  };
-
-  struct UniqueConstraint {
-    std::string label;
-    std::set<std::string> props;
-  };
-
-  std::set<Vertex> vertices;
-  std::set<Edge> edges;
-  std::set<IndexKey> indices;
-  std::set<UniqueConstraint> constraints;
-};
-
-bool operator<(const DatabaseState::Vertex &first,
-               const DatabaseState::Vertex &second) {
-  if (first.id != second.id) return first.id < second.id;
-  if (first.labels != second.labels) return first.labels < second.labels;
-  return first.props < second.props;
-}
-
-bool operator<(const DatabaseState::Edge &first,
-               const DatabaseState::Edge &second) {
-  if (first.from != second.from) return first.from < second.from;
-  if (first.to != second.to) return first.to < second.to;
-  if (first.edge_type != second.edge_type)
-    return first.edge_type < second.edge_type;
-  return first.props < second.props;
-}
-
-bool operator<(const DatabaseState::IndexKey &first,
-               const DatabaseState::IndexKey &second) {
-  if (first.label != second.label) return first.label < second.label;
-  return first.property < second.property;
-}
-
-bool operator<(const DatabaseState::UniqueConstraint &first,
-               const DatabaseState::UniqueConstraint &second) {
-  if (first.label != second.label) return first.label < second.label;
-  return first.props < second.props;
-}
-
-bool operator==(const DatabaseState::Vertex &first,
-                const DatabaseState::Vertex &second) {
-  return first.id == second.id && first.labels == second.labels &&
-         first.props == second.props;
-}
-
-bool operator==(const DatabaseState::Edge &first,
-                const DatabaseState::Edge &second) {
-  return first.from == second.from && first.to == second.to &&
-         first.edge_type == second.edge_type && first.props == second.props;
-}
-
-bool operator==(const DatabaseState::IndexKey &first,
-                const DatabaseState::IndexKey &second) {
-  return first.label == second.label && first.property == second.property;
-}
-
-bool operator==(const DatabaseState::UniqueConstraint &first,
-                const DatabaseState::UniqueConstraint &second) {
-  return first.label == second.label && first.props == second.props;
-}
-
-bool operator==(const DatabaseState &first, const DatabaseState &second) {
-  return first.vertices == second.vertices && first.edges == second.edges &&
-         first.indices == second.indices;
-}
-
-// Returns next query if the end is not reached, otherwise returns an empty
-// string.
-std::string DumpNext(CypherDumpGenerator *dump) {
-  std::ostringstream oss;
-  if (dump->NextQuery(&oss)) return oss.str();
-  return "";
-}
-
-class DatabaseEnvironment {
- public:
-  DatabaseEnvironment()
-      : interpreter_context_{&db_}, interpreter_{&interpreter_context_} {}
-
-  GraphDbAccessor Access() { return db_.Access(); }
-
-  DatabaseState GetState() {
-    // Capture all vertices
-    std::map<storage::Gid, int64_t> gid_mapping;
-    std::set<DatabaseState::Vertex> vertices;
-    auto dba = db_.Access();
-    for (const auto &vertex : dba.Vertices(false)) {
-      std::set<std::string> labels;
-      for (const auto &label : vertex.labels()) {
-        labels.insert(dba.LabelName(label));
-      }
-      std::map<std::string, PropertyValue> props;
-      for (const auto &kv : vertex.Properties()) {
-        props.emplace(dba.PropertyName(kv.first), kv.second);
-      }
-      CHECK(props.count(kPropertyId) == 1);
-      const auto id = props[kPropertyId].ValueInt();
-      gid_mapping[vertex.gid()] = id;
-      vertices.insert({id, labels, props});
-    }
-
-    // Capture all edges
-    std::set<DatabaseState::Edge> edges;
-    for (const auto &edge : dba.Edges(false)) {
-      const auto &edge_type_name = dba.EdgeTypeName(edge.EdgeType());
-      std::map<std::string, PropertyValue> props;
-      for (const auto &kv : edge.Properties()) {
-        props.emplace(dba.PropertyName(kv.first), kv.second);
-      }
-      const auto from = gid_mapping[edge.from().gid()];
-      const auto to = gid_mapping[edge.to().gid()];
-      edges.insert({from, to, edge_type_name, props});
-    }
-
-    // Capture all indices
-    std::set<DatabaseState::IndexKey> indices;
-    for (const auto &key : dba.GetIndicesKeys()) {
-      indices.insert(
-          {dba.LabelName(key.label_), dba.PropertyName(key.property_)});
-    }
-
-    // Capture all unique constraints
-    std::set<DatabaseState::UniqueConstraint> constraints;
-    for (const auto &constraint : dba.ListUniqueConstraints()) {
-      std::set<std::string> props;
-      for (const auto &prop : constraint.properties) {
-        props.insert(dba.PropertyName(prop));
-      }
-      constraints.insert({dba.LabelName(constraint.label), props});
-    }
-
-    return {vertices, edges, indices, constraints};
-  }
-
-  /**
-   * Execute the given query and commit the transaction.
-   *
-   * Return the query stream.
-   */
-  auto Execute(const std::string &query) {
-    ResultStreamFaker stream;
-
-    auto [header, _] = interpreter_.Prepare(query, {});
-    stream.Header(header);
-    auto summary = interpreter_.PullAll(&stream);
-    stream.Summary(summary);
-
-    return stream;
-  }
-
- private:
-  database::GraphDb db_;
-  query::InterpreterContext interpreter_context_;
-  query::Interpreter interpreter_;
-};
-
-VertexAccessor CreateVertex(GraphDbAccessor *dba,
-                            const std::vector<std::string> &labels,
-                            const std::map<std::string, PropertyValue> &props,
-                            bool add_property_id = true) {
-  CHECK(dba);
-  auto vertex = dba->InsertVertex();
-  for (const auto &label_name : labels) {
-    vertex.add_label(dba->Label(label_name));
-  }
-  for (const auto &kv : props) {
-    vertex.PropsSet(dba->Property(kv.first), kv.second);
-  }
-  if (add_property_id) {
-    vertex.PropsSet(dba->Property(kPropertyId),
-                    PropertyValue(vertex.gid().AsInt()));
-  }
-  return vertex;
-}
-
-EdgeAccessor CreateEdge(GraphDbAccessor *dba, VertexAccessor from,
-                        VertexAccessor to, const std::string &edge_type_name,
-                        const std::map<std::string, PropertyValue> &props,
-                        bool add_property_id = true) {
-  CHECK(dba);
-  auto edge = dba->InsertEdge(from, to, dba->EdgeType(edge_type_name));
-  for (const auto &kv : props) {
-    edge.PropsSet(dba->Property(kv.first), kv.second);
-  }
-  if (add_property_id) {
-    edge.PropsSet(dba->Property(kPropertyId),
-                  PropertyValue(edge.gid().AsInt()));
-  }
-  return edge;
-}
-
-// NOLINTNEXTLINE(hicpp-special-member-functions)
-TEST(DumpTest, EmptyGraph) {
-  DatabaseEnvironment db;
-  auto dba = db.Access();
-  query::DbAccessor query_dba(&dba);
-  CypherDumpGenerator dump(&query_dba);
-  EXPECT_EQ(DumpNext(&dump), "");
-}
-
-// NOLINTNEXTLINE(hicpp-special-member-functions)
-TEST(DumpTest, SingleVertex) {
-  DatabaseEnvironment db;
-  {
-    auto dba = db.Access();
-    CreateVertex(&dba, {}, {}, false);
-    dba.Commit();
-  }
-
-  {
-    auto dba = db.Access();
-    query::DbAccessor query_dba(&dba);
-    CypherDumpGenerator dump(&query_dba);
-    EXPECT_EQ(DumpNext(&dump), kCreateInternalIndex);
-    EXPECT_EQ(DumpNext(&dump), "CREATE (:__mg_vertex__ {__mg_id__: 0});");
-    EXPECT_EQ(DumpNext(&dump), kDropInternalIndex);
-    EXPECT_EQ(DumpNext(&dump), kRemoveInternalLabelProperty);
-    EXPECT_EQ(DumpNext(&dump), "");
-  }
-}
-
-// NOLINTNEXTLINE(hicpp-special-member-functions)
-TEST(DumpTest, VertexWithSingleLabel) {
-  DatabaseEnvironment db;
-  {
-    auto dba = db.Access();
-    CreateVertex(&dba, {"Label1"}, {}, false);
-    dba.Commit();
-  }
-
-  {
-    auto dba = db.Access();
-    query::DbAccessor query_dba(&dba);
-    CypherDumpGenerator dump(&query_dba);
-    EXPECT_EQ(DumpNext(&dump), kCreateInternalIndex);
-    EXPECT_EQ(DumpNext(&dump),
-              "CREATE (:__mg_vertex__:Label1 {__mg_id__: 0});");
-    EXPECT_EQ(DumpNext(&dump), kDropInternalIndex);
-    EXPECT_EQ(DumpNext(&dump), kRemoveInternalLabelProperty);
-    EXPECT_EQ(DumpNext(&dump), "");
-  }
-}
-
-// NOLINTNEXTLINE(hicpp-special-member-functions)
-TEST(DumpTest, VertexWithMultipleLabels) {
-  DatabaseEnvironment db;
-  {
-    auto dba = db.Access();
-    CreateVertex(&dba, {"Label1", "Label2"}, {}, false);
-    dba.Commit();
-  }
-
-  {
-    auto dba = db.Access();
-    query::DbAccessor query_dba(&dba);
-    CypherDumpGenerator dump(&query_dba);
-    EXPECT_EQ(DumpNext(&dump), kCreateInternalIndex);
-    EXPECT_EQ(DumpNext(&dump),
-              "CREATE (:__mg_vertex__:Label1:Label2 {__mg_id__: 0});");
-    EXPECT_EQ(DumpNext(&dump), kDropInternalIndex);
-    EXPECT_EQ(DumpNext(&dump), kRemoveInternalLabelProperty);
-    EXPECT_EQ(DumpNext(&dump), "");
-  }
-}
-
-// NOLINTNEXTLINE(hicpp-special-member-functions)
-TEST(DumpTest, VertexWithSingleProperty) {
-  DatabaseEnvironment db;
-  {
-    auto dba = db.Access();
-    CreateVertex(&dba, {}, {{"prop", PropertyValue(42)}}, false);
-    dba.Commit();
-  }
-
-  {
-    auto dba = db.Access();
-    query::DbAccessor query_dba(&dba);
-    CypherDumpGenerator dump(&query_dba);
-    EXPECT_EQ(DumpNext(&dump), kCreateInternalIndex);
-    EXPECT_EQ(DumpNext(&dump),
-              "CREATE (:__mg_vertex__ {__mg_id__: 0, prop: 42});");
-    EXPECT_EQ(DumpNext(&dump), kDropInternalIndex);
-    EXPECT_EQ(DumpNext(&dump), kRemoveInternalLabelProperty);
-    EXPECT_EQ(DumpNext(&dump), "");
-  }
-}
-
-// NOLINTNEXTLINE(hicpp-special-member-functions)
-TEST(DumpTest, MultipleVertices) {
-  DatabaseEnvironment db;
-  {
-    auto dba = db.Access();
-    CreateVertex(&dba, {}, {}, false);
-    CreateVertex(&dba, {}, {}, false);
-    CreateVertex(&dba, {}, {}, false);
-    dba.Commit();
-  }
-
-  {
-    auto dba = db.Access();
-    query::DbAccessor query_dba(&dba);
-    CypherDumpGenerator dump(&query_dba);
-    EXPECT_EQ(DumpNext(&dump), kCreateInternalIndex);
-    EXPECT_EQ(DumpNext(&dump), "CREATE (:__mg_vertex__ {__mg_id__: 0});");
-    EXPECT_EQ(DumpNext(&dump), "CREATE (:__mg_vertex__ {__mg_id__: 1});");
-    EXPECT_EQ(DumpNext(&dump), "CREATE (:__mg_vertex__ {__mg_id__: 2});");
-    EXPECT_EQ(DumpNext(&dump), kDropInternalIndex);
-    EXPECT_EQ(DumpNext(&dump), kRemoveInternalLabelProperty);
-    EXPECT_EQ(DumpNext(&dump), "");
-  }
-}
-
-// NOLINTNEXTLINE(hicpp-special-member-functions)
-TEST(DumpTest, SingleEdge) {
-  DatabaseEnvironment db;
-  {
-    auto dba = db.Access();
-    auto u = CreateVertex(&dba, {}, {}, false);
-    auto v = CreateVertex(&dba, {}, {}, false);
-    CreateEdge(&dba, u, v, "EdgeType", {}, false);
-    dba.Commit();
-  }
-
-  {
-    auto dba = db.Access();
-    query::DbAccessor query_dba(&dba);
-    CypherDumpGenerator dump(&query_dba);
-    EXPECT_EQ(DumpNext(&dump), kCreateInternalIndex);
-    EXPECT_EQ(DumpNext(&dump), "CREATE (:__mg_vertex__ {__mg_id__: 0});");
-    EXPECT_EQ(DumpNext(&dump), "CREATE (:__mg_vertex__ {__mg_id__: 1});");
-    EXPECT_EQ(DumpNext(&dump),
-              "MATCH (u:__mg_vertex__), (v:__mg_vertex__) WHERE u.__mg_id__ = "
-              "0 AND v.__mg_id__ = 1 CREATE (u)-[:EdgeType]->(v);");
-    EXPECT_EQ(DumpNext(&dump), kDropInternalIndex);
-    EXPECT_EQ(DumpNext(&dump), kRemoveInternalLabelProperty);
-    EXPECT_EQ(DumpNext(&dump), "");
-  }
-}
-
-// NOLINTNEXTLINE(hicpp-special-member-functions)
-TEST(DumpTest, MultipleEdges) {
-  DatabaseEnvironment db;
-  {
-    auto dba = db.Access();
-    auto u = CreateVertex(&dba, {}, {}, false);
-    auto v = CreateVertex(&dba, {}, {}, false);
-    auto w = CreateVertex(&dba, {}, {}, false);
-    CreateEdge(&dba, u, v, "EdgeType", {}, false);
-    CreateEdge(&dba, v, u, "EdgeType", {}, false);
-    CreateEdge(&dba, v, w, "EdgeType", {}, false);
-    dba.Commit();
-  }
-
-  {
-    auto dba = db.Access();
-    query::DbAccessor query_dba(&dba);
-    CypherDumpGenerator dump(&query_dba);
-    EXPECT_EQ(DumpNext(&dump), kCreateInternalIndex);
-    EXPECT_EQ(DumpNext(&dump), "CREATE (:__mg_vertex__ {__mg_id__: 0});");
-    EXPECT_EQ(DumpNext(&dump), "CREATE (:__mg_vertex__ {__mg_id__: 1});");
-    EXPECT_EQ(DumpNext(&dump), "CREATE (:__mg_vertex__ {__mg_id__: 2});");
-    EXPECT_EQ(DumpNext(&dump),
-              "MATCH (u:__mg_vertex__), (v:__mg_vertex__) WHERE u.__mg_id__ = "
-              "0 AND v.__mg_id__ = 1 CREATE (u)-[:EdgeType]->(v);");
-    EXPECT_EQ(DumpNext(&dump),
-              "MATCH (u:__mg_vertex__), (v:__mg_vertex__) WHERE u.__mg_id__ = "
-              "1 AND v.__mg_id__ = 0 CREATE (u)-[:EdgeType]->(v);");
-    EXPECT_EQ(DumpNext(&dump),
-              "MATCH (u:__mg_vertex__), (v:__mg_vertex__) WHERE u.__mg_id__ = "
-              "1 AND v.__mg_id__ = 2 CREATE (u)-[:EdgeType]->(v);");
-    EXPECT_EQ(DumpNext(&dump), kDropInternalIndex);
-    EXPECT_EQ(DumpNext(&dump), kRemoveInternalLabelProperty);
-    EXPECT_EQ(DumpNext(&dump), "");
-  }
-}
-
-// NOLINTNEXTLINE(hicpp-special-member-functions)
-TEST(DumpTest, EdgeWithProperties) {
-  DatabaseEnvironment db;
-  {
-    auto dba = db.Access();
-    auto u = CreateVertex(&dba, {}, {}, false);
-    auto v = CreateVertex(&dba, {}, {}, false);
-    CreateEdge(&dba, u, v, "EdgeType", {{"prop", PropertyValue(13)}}, false);
-    dba.Commit();
-  }
-
-  {
-    auto dba = db.Access();
-    query::DbAccessor query_dba(&dba);
-    CypherDumpGenerator dump(&query_dba);
-    EXPECT_EQ(DumpNext(&dump), kCreateInternalIndex);
-    EXPECT_EQ(DumpNext(&dump), "CREATE (:__mg_vertex__ {__mg_id__: 0});");
-    EXPECT_EQ(DumpNext(&dump), "CREATE (:__mg_vertex__ {__mg_id__: 1});");
-    EXPECT_EQ(DumpNext(&dump),
-              "MATCH (u:__mg_vertex__), (v:__mg_vertex__) WHERE u.__mg_id__ = "
-              "0 AND v.__mg_id__ = 1 CREATE (u)-[:EdgeType {prop: 13}]->(v);");
-    EXPECT_EQ(DumpNext(&dump), kDropInternalIndex);
-    EXPECT_EQ(DumpNext(&dump), kRemoveInternalLabelProperty);
-    EXPECT_EQ(DumpNext(&dump), "");
-  }
-}
-
-// NOLINTNEXTLINE(hicpp-special-member-functions)
-TEST(DumpTest, IndicesKeys) {
-  DatabaseEnvironment db;
-  {
-    auto dba = db.Access();
-    CreateVertex(&dba, {"Label1", "Label2"}, {{"p", PropertyValue(1)}}, false);
-    dba.BuildIndex(dba.Label("Label1"), dba.Property("prop"));
-    dba.BuildIndex(dba.Label("Label2"), dba.Property("prop"));
-    dba.Commit();
-  }
-
-  {
-    auto dba = db.Access();
-    query::DbAccessor query_dba(&dba);
-    CypherDumpGenerator dump(&query_dba);
-    EXPECT_EQ(DumpNext(&dump), "CREATE INDEX ON :Label1(prop);");
-    EXPECT_EQ(DumpNext(&dump), "CREATE INDEX ON :Label2(prop);");
-    EXPECT_EQ(DumpNext(&dump), kCreateInternalIndex);
-    EXPECT_EQ(DumpNext(&dump),
-              "CREATE (:__mg_vertex__:Label1:Label2 {__mg_id__: 0, p: 1});");
-    EXPECT_EQ(DumpNext(&dump), kDropInternalIndex);
-    EXPECT_EQ(DumpNext(&dump), kRemoveInternalLabelProperty);
-    EXPECT_EQ(DumpNext(&dump), "");
-  }
-}
-
-// NOLINTNEXTLINE(hicpp-special-member-functions)
-TEST(DumpTest, UniqueConstraints) {
-  DatabaseEnvironment db;
-  {
-    auto dba = db.Access();
-    CreateVertex(&dba, {"Label"}, {{"prop", PropertyValue(1)}}, false);
-    dba.BuildUniqueConstraint(dba.Label("Label"), {dba.Property("prop")});
-    // Create one with multiple properties.
-    dba.BuildUniqueConstraint(dba.Label("Label"),
-                              {dba.Property("prop1"), dba.Property("prop2")});
-    dba.Commit();
-  }
-
-  {
-    auto dba = db.Access();
-    query::DbAccessor query_dba(&dba);
-    CypherDumpGenerator dump(&query_dba);
-    EXPECT_EQ(DumpNext(&dump), kCreateInternalIndex);
-    EXPECT_EQ(DumpNext(&dump),
-              "CREATE CONSTRAINT ON (u:Label) ASSERT u.prop IS UNIQUE;");
-    EXPECT_EQ(
-        DumpNext(&dump),
-        "CREATE CONSTRAINT ON (u:Label) ASSERT u.prop1, u.prop2 IS UNIQUE;");
-    EXPECT_EQ(DumpNext(&dump),
-              "CREATE (:__mg_vertex__:Label {__mg_id__: 0, prop: 1});");
-    EXPECT_EQ(DumpNext(&dump), kDropInternalIndex);
-    EXPECT_EQ(DumpNext(&dump), kRemoveInternalLabelProperty);
-    EXPECT_EQ(DumpNext(&dump), "");
-  }
-}
-
-// NOLINTNEXTLINE(hicpp-special-member-functions)
-TEST(DumpTest, CheckStateVertexWithMultipleProperties) {
-  DatabaseEnvironment db;
-  {
-    auto dba = db.Access();
-    std::map<std::string, PropertyValue> prop1 = {
-        {"nested1", PropertyValue(1337)}, {"nested2", PropertyValue(3.14)}};
-    CreateVertex(
-        &dba, {"Label1", "Label2"},
-        {{"prop1", PropertyValue(prop1)}, {"prop2", PropertyValue("$'\t'")}});
-    dba.Commit();
-  }
-
-  DatabaseEnvironment db_dump;
-  {
-    auto dba = db.Access();
-    query::DbAccessor query_dba(&dba);
-    CypherDumpGenerator dump(&query_dba);
-
-    std::string cmd;
-    while (!(cmd = DumpNext(&dump)).empty()) {
-      db_dump.Execute(cmd);
-    }
-  }
-  EXPECT_EQ(db.GetState(), db_dump.GetState());
-}
-
-// NOLINTNEXTLINE(hicpp-special-member-functions)
-TEST(DumpTest, CheckStateSimpleGraph) {
-  DatabaseEnvironment db;
-  {
-    auto dba = db.Access();
-    auto u = CreateVertex(&dba, {"Person"}, {{"name", PropertyValue("Ivan")}});
-    auto v = CreateVertex(&dba, {"Person"}, {{"name", PropertyValue("Josko")}});
-    auto w = CreateVertex(
-        &dba, {"Person"},
-        {{"name", PropertyValue("Bosko")}, {"id", PropertyValue(0)}});
-    auto z = CreateVertex(
-        &dba, {"Person"},
-        {{"name", PropertyValue("Buha")}, {"id", PropertyValue(1)}});
-    CreateEdge(&dba, u, v, "Knows", {});
-    CreateEdge(&dba, v, w, "Knows", {{"how_long", PropertyValue(5)}});
-    CreateEdge(&dba, w, u, "Knows", {{"how", PropertyValue("distant past")}});
-    CreateEdge(&dba, v, u, "Knows", {});
-    CreateEdge(&dba, v, u, "Likes", {});
-    CreateEdge(&dba, z, u, "Knows", {});
-    CreateEdge(&dba, w, z, "Knows", {{"how", PropertyValue("school")}});
-    CreateEdge(&dba, w, z, "Likes", {{"how", PropertyValue("very much")}});
-
-    // Create few indices
-    dba.BuildUniqueConstraint(dba.Label("Person"), {dba.Property("name")});
-    dba.BuildIndex(dba.Label("Person"), dba.Property("id"));
-    dba.BuildIndex(dba.Label("Person"), dba.Property("unexisting_property"));
-  }
-
-  const auto &db_initial_state = db.GetState();
-  DatabaseEnvironment db_dump;
-  {
-    auto dba = db.Access();
-    query::DbAccessor query_dba(&dba);
-    CypherDumpGenerator dump(&query_dba);
-
-    std::string cmd;
-    while (!(cmd = DumpNext(&dump)).empty()) {
-      db_dump.Execute(cmd);
-    }
-  }
-  EXPECT_EQ(db.GetState(), db_dump.GetState());
-  // Make sure that dump function doesn't make changes on the database.
-  EXPECT_EQ(db.GetState(), db_initial_state);
-}
-
-// NOLINTNEXTLINE(hicpp-special-member-functions)
-TEST(DumpTest, ExecuteDumpDatabase) {
-  DatabaseEnvironment db;
-  {
-    auto dba = db.Access();
-    CreateVertex(&dba, {}, {}, false);
-    dba.Commit();
-  }
-
-  {
-    auto stream = db.Execute("DUMP DATABASE");
-    EXPECT_EQ(stream.GetResults().size(), 4U);
-    ASSERT_EQ(stream.GetHeader().size(), 1U);
-    EXPECT_EQ(stream.GetHeader()[0], "QUERY");
-  }
-}
diff --git a/tests/unit/query_dump.cpp b/tests/unit/query_dump.cpp
new file mode 100644
index 000000000..851870303
--- /dev/null
+++ b/tests/unit/query_dump.cpp
@@ -0,0 +1,632 @@
+#include <gtest/gtest.h>
+
+#include <map>
+#include <set>
+#include <vector>
+
+#include <glog/logging.h>
+
+#include "communication/result_stream_faker.hpp"
+#include "database/graph_db.hpp"
+#include "database/graph_db_accessor.hpp"
+#include "query/dump.hpp"
+#include "query/interpreter.hpp"
+#include "query/typed_value.hpp"
+#include "storage/common/types/property_value.hpp"
+
+using database::GraphDbAccessor;
+
+const char *kPropertyId = "property_id";
+
+const char *kCreateInternalIndex = "CREATE INDEX ON :__mg_vertex__(__mg_id__);";
+const char *kDropInternalIndex = "DROP INDEX ON :__mg_vertex__(__mg_id__);";
+const char *kRemoveInternalLabelProperty =
+    "MATCH (u) REMOVE u:__mg_vertex__, u.__mg_id__;";
+
+// A helper struct that contains info about database that is used to compare
+// two databases (to check if their states are the same). It is assumed that
+// each vertex and each edge have unique integer property under key
+// `kPropertyId`.
+struct DatabaseState {
+  struct Vertex {
+    int64_t id;
+    std::set<std::string> labels;
+    std::map<std::string, PropertyValue> props;
+  };
+
+  struct Edge {
+    int64_t from, to;
+    std::string edge_type;
+    std::map<std::string, PropertyValue> props;
+  };
+
+  struct IndexKey {
+    std::string label;
+    std::string property;
+  };
+
+  struct UniqueConstraint {
+    std::string label;
+    std::set<std::string> props;
+  };
+
+  std::set<Vertex> vertices;
+  std::set<Edge> edges;
+  std::set<IndexKey> indices;
+  std::set<UniqueConstraint> constraints;
+};
+
+bool operator<(const DatabaseState::Vertex &first,
+               const DatabaseState::Vertex &second) {
+  if (first.id != second.id) return first.id < second.id;
+  if (first.labels != second.labels) return first.labels < second.labels;
+  return first.props < second.props;
+}
+
+bool operator<(const DatabaseState::Edge &first,
+               const DatabaseState::Edge &second) {
+  if (first.from != second.from) return first.from < second.from;
+  if (first.to != second.to) return first.to < second.to;
+  if (first.edge_type != second.edge_type)
+    return first.edge_type < second.edge_type;
+  return first.props < second.props;
+}
+
+bool operator<(const DatabaseState::IndexKey &first,
+               const DatabaseState::IndexKey &second) {
+  if (first.label != second.label) return first.label < second.label;
+  return first.property < second.property;
+}
+
+bool operator<(const DatabaseState::UniqueConstraint &first,
+               const DatabaseState::UniqueConstraint &second) {
+  if (first.label != second.label) return first.label < second.label;
+  return first.props < second.props;
+}
+
+bool operator==(const DatabaseState::Vertex &first,
+                const DatabaseState::Vertex &second) {
+  return first.id == second.id && first.labels == second.labels &&
+         first.props == second.props;
+}
+
+bool operator==(const DatabaseState::Edge &first,
+                const DatabaseState::Edge &second) {
+  return first.from == second.from && first.to == second.to &&
+         first.edge_type == second.edge_type && first.props == second.props;
+}
+
+bool operator==(const DatabaseState::IndexKey &first,
+                const DatabaseState::IndexKey &second) {
+  return first.label == second.label && first.property == second.property;
+}
+
+bool operator==(const DatabaseState::UniqueConstraint &first,
+                const DatabaseState::UniqueConstraint &second) {
+  return first.label == second.label && first.props == second.props;
+}
+
+bool operator==(const DatabaseState &first, const DatabaseState &second) {
+  return first.vertices == second.vertices && first.edges == second.edges &&
+         first.indices == second.indices;
+}
+
+DatabaseState GetState(database::GraphDb *db) {
+  // Capture all vertices
+  std::map<storage::Gid, int64_t> gid_mapping;
+  std::set<DatabaseState::Vertex> vertices;
+  auto dba = db->Access();
+  for (const auto &vertex : dba.Vertices(false)) {
+    std::set<std::string> labels;
+    for (const auto &label : vertex.labels()) {
+      labels.insert(dba.LabelName(label));
+    }
+    std::map<std::string, PropertyValue> props;
+    for (const auto &kv : vertex.Properties()) {
+      props.emplace(dba.PropertyName(kv.first), kv.second);
+    }
+    CHECK(props.count(kPropertyId) == 1);
+    const auto id = props[kPropertyId].ValueInt();
+    gid_mapping[vertex.gid()] = id;
+    vertices.insert({id, labels, props});
+  }
+
+  // Capture all edges
+  std::set<DatabaseState::Edge> edges;
+  for (const auto &edge : dba.Edges(false)) {
+    const auto &edge_type_name = dba.EdgeTypeName(edge.EdgeType());
+    std::map<std::string, PropertyValue> props;
+    for (const auto &kv : edge.Properties()) {
+      props.emplace(dba.PropertyName(kv.first), kv.second);
+    }
+    const auto from = gid_mapping[edge.from().gid()];
+    const auto to = gid_mapping[edge.to().gid()];
+    edges.insert({from, to, edge_type_name, props});
+  }
+
+  // Capture all indices
+  std::set<DatabaseState::IndexKey> indices;
+  for (const auto &key : dba.GetIndicesKeys()) {
+    indices.insert(
+        {dba.LabelName(key.label_), dba.PropertyName(key.property_)});
+  }
+
+  // Capture all unique constraints
+  std::set<DatabaseState::UniqueConstraint> constraints;
+  for (const auto &constraint : dba.ListUniqueConstraints()) {
+    std::set<std::string> props;
+    for (const auto &prop : constraint.properties) {
+      props.insert(dba.PropertyName(prop));
+    }
+    constraints.insert({dba.LabelName(constraint.label), props});
+  }
+
+  return {vertices, edges, indices, constraints};
+}
+
+auto Execute(database::GraphDb *db, const std::string &query) {
+  query::InterpreterContext context(db);
+  query::Interpreter interpreter(&context);
+  ResultStreamFaker stream;
+
+  auto [header, _] = interpreter.Prepare(query, {});
+  stream.Header(header);
+  auto summary = interpreter.PullAll(&stream);
+  stream.Summary(summary);
+
+  return stream;
+}
+
+VertexAccessor CreateVertex(GraphDbAccessor *dba,
+                            const std::vector<std::string> &labels,
+                            const std::map<std::string, PropertyValue> &props,
+                            bool add_property_id = true) {
+  CHECK(dba);
+  auto vertex = dba->InsertVertex();
+  for (const auto &label_name : labels) {
+    vertex.add_label(dba->Label(label_name));
+  }
+  for (const auto &kv : props) {
+    vertex.PropsSet(dba->Property(kv.first), kv.second);
+  }
+  if (add_property_id) {
+    vertex.PropsSet(dba->Property(kPropertyId),
+                    PropertyValue(vertex.gid().AsInt()));
+  }
+  return vertex;
+}
+
+EdgeAccessor CreateEdge(GraphDbAccessor *dba, VertexAccessor from,
+                        VertexAccessor to, const std::string &edge_type_name,
+                        const std::map<std::string, PropertyValue> &props,
+                        bool add_property_id = true) {
+  CHECK(dba);
+  auto edge = dba->InsertEdge(from, to, dba->EdgeType(edge_type_name));
+  for (const auto &kv : props) {
+    edge.PropsSet(dba->Property(kv.first), kv.second);
+  }
+  if (add_property_id) {
+    edge.PropsSet(dba->Property(kPropertyId),
+                  PropertyValue(edge.gid().AsInt()));
+  }
+  return edge;
+}
+
+template <class... TArgs>
+void VerifyQueries(
+    const std::vector<std::vector<communication::bolt::Value>> &results,
+    TArgs &&... args) {
+  std::vector<std::string> expected{std::forward<TArgs>(args)...};
+  std::vector<std::string> got;
+  got.reserve(results.size());
+  for (const auto &result : results) {
+    ASSERT_EQ(result.size(), 1);
+    ASSERT_TRUE(result[0].IsString());
+    got.push_back(result[0].ValueString());
+  }
+  ASSERT_EQ(got, expected);
+}
+
+// NOLINTNEXTLINE(hicpp-special-member-functions)
+TEST(DumpTest, EmptyGraph) {
+  database::GraphDb db;
+  ResultStreamFaker stream;
+  query::AnyStream query_stream(&stream, utils::NewDeleteResource());
+  {
+    auto acc = db.Access();
+    query::DbAccessor dba(&acc);
+    query::DumpDatabaseToCypherQueries(&dba, &query_stream);
+  }
+  ASSERT_EQ(stream.GetResults().size(), 0);
+}
+
+// NOLINTNEXTLINE(hicpp-special-member-functions)
+TEST(DumpTest, SingleVertex) {
+  database::GraphDb db;
+  {
+    auto dba = db.Access();
+    CreateVertex(&dba, {}, {}, false);
+    dba.Commit();
+  }
+
+  {
+    ResultStreamFaker stream;
+    query::AnyStream query_stream(&stream, utils::NewDeleteResource());
+    {
+      auto acc = db.Access();
+      query::DbAccessor dba(&acc);
+      query::DumpDatabaseToCypherQueries(&dba, &query_stream);
+    }
+    VerifyQueries(stream.GetResults(), kCreateInternalIndex,
+                  "CREATE (:__mg_vertex__ {__mg_id__: 0});", kDropInternalIndex,
+                  kRemoveInternalLabelProperty);
+  }
+}
+
+// NOLINTNEXTLINE(hicpp-special-member-functions)
+TEST(DumpTest, VertexWithSingleLabel) {
+  database::GraphDb db;
+  {
+    auto dba = db.Access();
+    CreateVertex(&dba, {"Label1"}, {}, false);
+    dba.Commit();
+  }
+
+  {
+    ResultStreamFaker stream;
+    query::AnyStream query_stream(&stream, utils::NewDeleteResource());
+    {
+      auto acc = db.Access();
+      query::DbAccessor dba(&acc);
+      query::DumpDatabaseToCypherQueries(&dba, &query_stream);
+    }
+    VerifyQueries(stream.GetResults(), kCreateInternalIndex,
+                  "CREATE (:__mg_vertex__:Label1 {__mg_id__: 0});",
+                  kDropInternalIndex, kRemoveInternalLabelProperty);
+  }
+}
+
+// NOLINTNEXTLINE(hicpp-special-member-functions)
+TEST(DumpTest, VertexWithMultipleLabels) {
+  database::GraphDb db;
+  {
+    auto dba = db.Access();
+    CreateVertex(&dba, {"Label1", "Label2"}, {}, false);
+    dba.Commit();
+  }
+
+  {
+    ResultStreamFaker stream;
+    query::AnyStream query_stream(&stream, utils::NewDeleteResource());
+    {
+      auto acc = db.Access();
+      query::DbAccessor dba(&acc);
+      query::DumpDatabaseToCypherQueries(&dba, &query_stream);
+    }
+    VerifyQueries(stream.GetResults(), kCreateInternalIndex,
+                  "CREATE (:__mg_vertex__:Label1:Label2 {__mg_id__: 0});",
+                  kDropInternalIndex, kRemoveInternalLabelProperty);
+  }
+}
+
+// NOLINTNEXTLINE(hicpp-special-member-functions)
+TEST(DumpTest, VertexWithSingleProperty) {
+  database::GraphDb db;
+  {
+    auto dba = db.Access();
+    CreateVertex(&dba, {}, {{"prop", PropertyValue(42)}}, false);
+    dba.Commit();
+  }
+
+  {
+    ResultStreamFaker stream;
+    query::AnyStream query_stream(&stream, utils::NewDeleteResource());
+    {
+      auto acc = db.Access();
+      query::DbAccessor dba(&acc);
+      query::DumpDatabaseToCypherQueries(&dba, &query_stream);
+    }
+    VerifyQueries(stream.GetResults(), kCreateInternalIndex,
+                  "CREATE (:__mg_vertex__ {__mg_id__: 0, prop: 42});",
+                  kDropInternalIndex, kRemoveInternalLabelProperty);
+  }
+}
+
+// NOLINTNEXTLINE(hicpp-special-member-functions)
+TEST(DumpTest, MultipleVertices) {
+  database::GraphDb db;
+  {
+    auto dba = db.Access();
+    CreateVertex(&dba, {}, {}, false);
+    CreateVertex(&dba, {}, {}, false);
+    CreateVertex(&dba, {}, {}, false);
+    dba.Commit();
+  }
+
+  {
+    ResultStreamFaker stream;
+    query::AnyStream query_stream(&stream, utils::NewDeleteResource());
+    {
+      auto acc = db.Access();
+      query::DbAccessor dba(&acc);
+      query::DumpDatabaseToCypherQueries(&dba, &query_stream);
+    }
+    VerifyQueries(stream.GetResults(), kCreateInternalIndex,
+                  "CREATE (:__mg_vertex__ {__mg_id__: 0});",
+                  "CREATE (:__mg_vertex__ {__mg_id__: 1});",
+                  "CREATE (:__mg_vertex__ {__mg_id__: 2});", kDropInternalIndex,
+                  kRemoveInternalLabelProperty);
+  }
+}
+
+// NOLINTNEXTLINE(hicpp-special-member-functions)
+TEST(DumpTest, SingleEdge) {
+  database::GraphDb db;
+  {
+    auto dba = db.Access();
+    auto u = CreateVertex(&dba, {}, {}, false);
+    auto v = CreateVertex(&dba, {}, {}, false);
+    CreateEdge(&dba, u, v, "EdgeType", {}, false);
+    dba.Commit();
+  }
+
+  {
+    ResultStreamFaker stream;
+    query::AnyStream query_stream(&stream, utils::NewDeleteResource());
+    {
+      auto acc = db.Access();
+      query::DbAccessor dba(&acc);
+      query::DumpDatabaseToCypherQueries(&dba, &query_stream);
+    }
+    VerifyQueries(
+        stream.GetResults(), kCreateInternalIndex,
+        "CREATE (:__mg_vertex__ {__mg_id__: 0});",
+        "CREATE (:__mg_vertex__ {__mg_id__: 1});",
+        "MATCH (u:__mg_vertex__), (v:__mg_vertex__) WHERE u.__mg_id__ = 0 AND "
+        "v.__mg_id__ = 1 CREATE (u)-[:EdgeType]->(v);",
+        kDropInternalIndex, kRemoveInternalLabelProperty);
+  }
+}
+
+// NOLINTNEXTLINE(hicpp-special-member-functions)
+TEST(DumpTest, MultipleEdges) {
+  database::GraphDb db;
+  {
+    auto dba = db.Access();
+    auto u = CreateVertex(&dba, {}, {}, false);
+    auto v = CreateVertex(&dba, {}, {}, false);
+    auto w = CreateVertex(&dba, {}, {}, false);
+    CreateEdge(&dba, u, v, "EdgeType", {}, false);
+    CreateEdge(&dba, v, u, "EdgeType", {}, false);
+    CreateEdge(&dba, v, w, "EdgeType", {}, false);
+    dba.Commit();
+  }
+
+  {
+    ResultStreamFaker stream;
+    query::AnyStream query_stream(&stream, utils::NewDeleteResource());
+    {
+      auto acc = db.Access();
+      query::DbAccessor dba(&acc);
+      query::DumpDatabaseToCypherQueries(&dba, &query_stream);
+    }
+    VerifyQueries(
+        stream.GetResults(), kCreateInternalIndex,
+        "CREATE (:__mg_vertex__ {__mg_id__: 0});",
+        "CREATE (:__mg_vertex__ {__mg_id__: 1});",
+        "CREATE (:__mg_vertex__ {__mg_id__: 2});",
+        "MATCH (u:__mg_vertex__), (v:__mg_vertex__) WHERE u.__mg_id__ = 0 AND "
+        "v.__mg_id__ = 1 CREATE (u)-[:EdgeType]->(v);",
+        "MATCH (u:__mg_vertex__), (v:__mg_vertex__) WHERE u.__mg_id__ = 1 AND "
+        "v.__mg_id__ = 0 CREATE (u)-[:EdgeType]->(v);",
+        "MATCH (u:__mg_vertex__), (v:__mg_vertex__) WHERE u.__mg_id__ = 1 AND "
+        "v.__mg_id__ = 2 CREATE (u)-[:EdgeType]->(v);",
+        kDropInternalIndex, kRemoveInternalLabelProperty);
+  }
+}
+
+// NOLINTNEXTLINE(hicpp-special-member-functions)
+TEST(DumpTest, EdgeWithProperties) {
+  database::GraphDb db;
+  {
+    auto dba = db.Access();
+    auto u = CreateVertex(&dba, {}, {}, false);
+    auto v = CreateVertex(&dba, {}, {}, false);
+    CreateEdge(&dba, u, v, "EdgeType", {{"prop", PropertyValue(13)}}, false);
+    dba.Commit();
+  }
+
+  {
+    ResultStreamFaker stream;
+    query::AnyStream query_stream(&stream, utils::NewDeleteResource());
+    {
+      auto acc = db.Access();
+      query::DbAccessor dba(&acc);
+      query::DumpDatabaseToCypherQueries(&dba, &query_stream);
+    }
+    VerifyQueries(
+        stream.GetResults(), kCreateInternalIndex,
+        "CREATE (:__mg_vertex__ {__mg_id__: 0});",
+        "CREATE (:__mg_vertex__ {__mg_id__: 1});",
+        "MATCH (u:__mg_vertex__), (v:__mg_vertex__) WHERE u.__mg_id__ = 0 AND "
+        "v.__mg_id__ = 1 CREATE (u)-[:EdgeType {prop: 13}]->(v);",
+        kDropInternalIndex, kRemoveInternalLabelProperty);
+  }
+}
+
+// NOLINTNEXTLINE(hicpp-special-member-functions)
+TEST(DumpTest, IndicesKeys) {
+  database::GraphDb db;
+  {
+    auto dba = db.Access();
+    CreateVertex(&dba, {"Label1", "Label2"}, {{"p", PropertyValue(1)}}, false);
+    dba.BuildIndex(dba.Label("Label1"), dba.Property("prop"));
+    dba.BuildIndex(dba.Label("Label2"), dba.Property("prop"));
+    dba.Commit();
+  }
+
+  {
+    ResultStreamFaker stream;
+    query::AnyStream query_stream(&stream, utils::NewDeleteResource());
+    {
+      auto acc = db.Access();
+      query::DbAccessor dba(&acc);
+      query::DumpDatabaseToCypherQueries(&dba, &query_stream);
+    }
+    VerifyQueries(stream.GetResults(), "CREATE INDEX ON :Label1(prop);",
+                  "CREATE INDEX ON :Label2(prop);", kCreateInternalIndex,
+                  "CREATE (:__mg_vertex__:Label1:Label2 {__mg_id__: 0, p: 1});",
+                  kDropInternalIndex, kRemoveInternalLabelProperty);
+  }
+}
+
+// NOLINTNEXTLINE(hicpp-special-member-functions)
+TEST(DumpTest, UniqueConstraints) {
+  database::GraphDb db;
+  {
+    auto dba = db.Access();
+    CreateVertex(&dba, {"Label"}, {{"prop", PropertyValue(1)}}, false);
+    dba.BuildUniqueConstraint(dba.Label("Label"), {dba.Property("prop")});
+    // Create one with multiple properties.
+    dba.BuildUniqueConstraint(dba.Label("Label"),
+                              {dba.Property("prop1"), dba.Property("prop2")});
+    dba.Commit();
+  }
+
+  {
+    ResultStreamFaker stream;
+    query::AnyStream query_stream(&stream, utils::NewDeleteResource());
+    {
+      auto acc = db.Access();
+      query::DbAccessor dba(&acc);
+      query::DumpDatabaseToCypherQueries(&dba, &query_stream);
+    }
+    VerifyQueries(
+        stream.GetResults(),
+        "CREATE CONSTRAINT ON (u:Label) ASSERT u.prop IS UNIQUE;",
+        "CREATE CONSTRAINT ON (u:Label) ASSERT u.prop1, u.prop2 IS UNIQUE;",
+        kCreateInternalIndex,
+        "CREATE (:__mg_vertex__:Label {__mg_id__: 0, prop: 1});",
+        kDropInternalIndex, kRemoveInternalLabelProperty);
+  }
+}
+
+// NOLINTNEXTLINE(hicpp-special-member-functions)
+TEST(DumpTest, CheckStateVertexWithMultipleProperties) {
+  database::GraphDb db;
+  {
+    auto dba = db.Access();
+    std::map<std::string, PropertyValue> prop1 = {
+        {"nested1", PropertyValue(1337)}, {"nested2", PropertyValue(3.14)}};
+    CreateVertex(
+        &dba, {"Label1", "Label2"},
+        {{"prop1", PropertyValue(prop1)}, {"prop2", PropertyValue("$'\t'")}});
+    dba.Commit();
+  }
+
+  database::GraphDb db_dump;
+  {
+    ResultStreamFaker stream;
+    query::AnyStream query_stream(&stream, utils::NewDeleteResource());
+    {
+      auto acc = db.Access();
+      query::DbAccessor dba(&acc);
+      query::DumpDatabaseToCypherQueries(&dba, &query_stream);
+    }
+    const auto &results = stream.GetResults();
+    ASSERT_GE(results.size(), 1);
+    for (const auto &item : results) {
+      ASSERT_EQ(item.size(), 1);
+      ASSERT_TRUE(item[0].IsString());
+      Execute(&db_dump, item[0].ValueString());
+    }
+  }
+  ASSERT_EQ(GetState(&db), GetState(&db_dump));
+}
+
+// NOLINTNEXTLINE(hicpp-special-member-functions)
+TEST(DumpTest, CheckStateSimpleGraph) {
+  database::GraphDb db;
+  {
+    auto dba = db.Access();
+    auto u = CreateVertex(&dba, {"Person"}, {{"name", PropertyValue("Ivan")}});
+    auto v = CreateVertex(&dba, {"Person"}, {{"name", PropertyValue("Josko")}});
+    auto w = CreateVertex(
+        &dba, {"Person"},
+        {{"name", PropertyValue("Bosko")}, {"id", PropertyValue(0)}});
+    auto z = CreateVertex(
+        &dba, {"Person"},
+        {{"name", PropertyValue("Buha")}, {"id", PropertyValue(1)}});
+    CreateEdge(&dba, u, v, "Knows", {});
+    CreateEdge(&dba, v, w, "Knows", {{"how_long", PropertyValue(5)}});
+    CreateEdge(&dba, w, u, "Knows", {{"how", PropertyValue("distant past")}});
+    CreateEdge(&dba, v, u, "Knows", {});
+    CreateEdge(&dba, v, u, "Likes", {});
+    CreateEdge(&dba, z, u, "Knows", {});
+    CreateEdge(&dba, w, z, "Knows", {{"how", PropertyValue("school")}});
+    CreateEdge(&dba, w, z, "Likes", {{"how", PropertyValue("very much")}});
+    dba.Commit();
+  }
+  {
+    auto dba = db.Access();
+    dba.BuildUniqueConstraint(dba.Label("Person"), {dba.Property("name")});
+    dba.BuildIndex(dba.Label("Person"), dba.Property("id"));
+    dba.BuildIndex(dba.Label("Person"), dba.Property("unexisting_property"));
+    dba.Commit();
+  }
+
+  const auto &db_initial_state = GetState(&db);
+  database::GraphDb db_dump;
+  {
+    ResultStreamFaker stream;
+    query::AnyStream query_stream(&stream, utils::NewDeleteResource());
+    {
+      auto acc = db.Access();
+      query::DbAccessor dba(&acc);
+      query::DumpDatabaseToCypherQueries(&dba, &query_stream);
+    }
+    const auto &results = stream.GetResults();
+    // Indices and constraints are 3 queries and there must be at least one more
+    // query for the data.
+    ASSERT_GE(results.size(), 4);
+    for (const auto &item : results) {
+      ASSERT_EQ(item.size(), 1);
+      ASSERT_TRUE(item[0].IsString());
+      Execute(&db_dump, item[0].ValueString());
+    }
+  }
+  ASSERT_EQ(GetState(&db), GetState(&db_dump));
+  // Make sure that dump function doesn't make changes on the database.
+  ASSERT_EQ(GetState(&db), db_initial_state);
+}
+
+// NOLINTNEXTLINE(hicpp-special-member-functions)
+TEST(DumpTest, ExecuteDumpDatabase) {
+  database::GraphDb db;
+  {
+    auto dba = db.Access();
+    CreateVertex(&dba, {}, {}, false);
+    dba.Commit();
+  }
+
+  {
+    auto stream = Execute(&db, "DUMP DATABASE");
+    const auto &header = stream.GetHeader();
+    const auto &results = stream.GetResults();
+    ASSERT_EQ(header.size(), 1U);
+    EXPECT_EQ(header[0], "QUERY");
+    EXPECT_EQ(results.size(), 4U);
+    for (const auto &item : results) {
+      EXPECT_EQ(item.size(), 1);
+      EXPECT_TRUE(item[0].IsString());
+    }
+    EXPECT_EQ(results[0][0].ValueString(),
+              "CREATE INDEX ON :__mg_vertex__(__mg_id__);");
+    EXPECT_EQ(results[1][0].ValueString(),
+              "CREATE (:__mg_vertex__ {__mg_id__: 0});");
+    EXPECT_EQ(results[2][0].ValueString(),
+              "DROP INDEX ON :__mg_vertex__(__mg_id__);");
+    EXPECT_EQ(results[3][0].ValueString(),
+              "MATCH (u) REMOVE u:__mg_vertex__, u.__mg_id__;");
+  }
+}