From 48e446688f7ef4104253dde8238b492894ca156c Mon Sep 17 00:00:00 2001
From: florijan <florijan@memgraph.io>
Date: Sat, 16 Sep 2017 14:08:52 +0200
Subject: [PATCH] IndexInfo function added

Summary:
- Keys() functions in the indices can't be const because ConcurrentMap doesn't provide const accessors (and they are broken in skiplist) :D
- no cucumber tests because many tests create indices so it's hard to say what's inside and what not

Reviewers: buda, mislav.bradac

Reviewed By: mislav.bradac

Subscribers: pullbot

Differential Revision: https://phabricator.memgraph.io/D797
---
 CHANGELOG.md                                  |  1 +
 docs/user_technical/open-cypher.md            |  1 +
 src/database/graph_db_accessor.cpp            | 16 ++++++++++++++++
 src/database/graph_db_accessor.hpp            |  5 +++++
 src/database/indexes/key_index.hpp            | 10 ++++++++++
 src/database/indexes/label_property_index.hpp | 10 ++++++++++
 .../interpret/awesome_memgraph_functions.cpp  | 10 ++++++++++
 tests/unit/query_expression_evaluator.cpp     | 19 +++++++++++++++++++
 8 files changed, 72 insertions(+)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index d329e9163..dfa931945 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -12,6 +12,7 @@
 * `assert` function added.
 * Use \u to specify 4 digit codepoint and \U for 8 digit
 * `counter` and `counterSet` functions added.
+* `indexInfo` function added.
 
 ### Bug Fixes and Other Changes
 
diff --git a/docs/user_technical/open-cypher.md b/docs/user_technical/open-cypher.md
index 4059927df..0488e3325 100644
--- a/docs/user_technical/open-cypher.md
+++ b/docs/user_technical/open-cypher.md
@@ -502,6 +502,7 @@ functions.
  `assert`     | Raises an exception reported to the client if the given argument is not `true`.
  `counter`    | Generates integers that are guaranteed to be unique on the database level, for the given counter name.
  `counterSet` | Sets the counter with the given name to the given value.
+ `indexInfo`  | Returns a list of all the indexes available in the database. The list includes indexes that are not yet ready for use (they are concurrently being built by another transaction).
 
 #### String Operators
 
diff --git a/src/database/graph_db_accessor.cpp b/src/database/graph_db_accessor.cpp
index 7d96f7e01..01cb7b1a6 100644
--- a/src/database/graph_db_accessor.cpp
+++ b/src/database/graph_db_accessor.cpp
@@ -341,3 +341,19 @@ void GraphDbAccessor::CounterSet(const std::string &name, int64_t value) {
   if (!name_counter_pair.second)
     name_counter_pair.first->second.store(value);
 }
+
+std::vector<std::string> GraphDbAccessor::IndexInfo() const {
+  std::vector<std::string> info;
+  for (GraphDbTypes::Label label : db_.labels_index_.Keys()) {
+    info.emplace_back(":" + LabelName(label));
+  }
+
+  // Edge indices are not shown because they are never used.
+
+  for (LabelPropertyIndex::Key key : db_.label_property_index_.Keys()) {
+    info.emplace_back(fmt::format(":{}({})", LabelName(key.label_),
+                                  PropertyName(key.property_)));
+  }
+
+  return info;
+}
diff --git a/src/database/graph_db_accessor.hpp b/src/database/graph_db_accessor.hpp
index 19c3d131a..5423f79df 100644
--- a/src/database/graph_db_accessor.hpp
+++ b/src/database/graph_db_accessor.hpp
@@ -575,6 +575,11 @@ class GraphDbAccessor {
    */
   void CounterSet(const std::string &name, int64_t value);
 
+  /*
+   * Returns a list of index names present in the database.
+   */
+  std::vector<std::string> IndexInfo() const;
+
  private:
   /**
    * Insert this vertex into corresponding label and label+property (if it
diff --git a/src/database/indexes/key_index.hpp b/src/database/indexes/key_index.hpp
index 8d44869f5..19365e8a5 100644
--- a/src/database/indexes/key_index.hpp
+++ b/src/database/indexes/key_index.hpp
@@ -96,6 +96,16 @@ class KeyIndex {
         });
   }
 
+  /**
+   * Returns a vector of keys present in this index.
+   */
+  std::vector<TKey> Keys() {
+    std::vector<TKey> keys;
+    for (auto &kv : indices_.access())
+      keys.push_back(kv.first);
+    return keys;
+  }
+
  private:
   /**
    * @brief - Contains vlist and record pointers.
diff --git a/src/database/indexes/label_property_index.hpp b/src/database/indexes/label_property_index.hpp
index d75b8dda3..008df6ace 100644
--- a/src/database/indexes/label_property_index.hpp
+++ b/src/database/indexes/label_property_index.hpp
@@ -389,6 +389,16 @@ class LabelPropertyIndex {
     return indices;
   }
 
+  /**
+   * Returns a vector of keys present in this index.
+   */
+  std::vector<Key> Keys() {
+    std::vector<Key> keys;
+    for (auto &kv : indices_.access())
+      keys.push_back(kv.first);
+    return keys;
+  }
+
  private:
   /**
    * @brief - Contains value, vlist and vertex record to distinguish between
diff --git a/src/query/interpret/awesome_memgraph_functions.cpp b/src/query/interpret/awesome_memgraph_functions.cpp
index 14dcf7e2d..00a044046 100644
--- a/src/query/interpret/awesome_memgraph_functions.cpp
+++ b/src/query/interpret/awesome_memgraph_functions.cpp
@@ -545,6 +545,15 @@ TypedValue CounterSet(const std::vector<TypedValue> &args, GraphDbAccessor &dba)
   dba.CounterSet(args[0].ValueString(), args[1].ValueInt());
   return TypedValue::Null;
 }
+
+TypedValue IndexInfo(const std::vector<TypedValue> &args,
+                     GraphDbAccessor &dba) {
+  if (args.size() != 0U)
+    throw QueryRuntimeException("indexInfo takes zero arguments");
+
+  auto info = dba.IndexInfo();
+  return std::vector<TypedValue>(info.begin(), info.end());
+}
 }  // annonymous namespace
 
 std::function<TypedValue(const std::vector<TypedValue> &, GraphDbAccessor &)>
@@ -590,6 +599,7 @@ NameToFunction(const std::string &function_name) {
   if (function_name == "ASSERT") return Assert;
   if (function_name == "COUNTER") return Counter;
   if (function_name == "COUNTERSET") return CounterSet;
+  if (function_name == "INDEXINFO") return IndexInfo;
   return nullptr;
 }
 }  // namespace query
diff --git a/tests/unit/query_expression_evaluator.cpp b/tests/unit/query_expression_evaluator.cpp
index e61f9f6de..123d34ea2 100644
--- a/tests/unit/query_expression_evaluator.cpp
+++ b/tests/unit/query_expression_evaluator.cpp
@@ -1235,4 +1235,23 @@ TEST(ExpressionEvaluator, FunctionCounterSet) {
   EXPECT_EQ(EvaluateFunction("COUNTER", {"c1"}, dbms).ValueInt(), 13);
   EXPECT_EQ(EvaluateFunction("COUNTER", {"c2"}, dbms).ValueInt(), 43);
 }
+
+TEST(ExpressionEvaluator, FunctionIndexInfo) {
+  Dbms dbms;
+  EXPECT_THROW(EvaluateFunction("INDEXINFO", {1}, dbms), QueryRuntimeException);
+  EXPECT_EQ(EvaluateFunction("INDEXINFO", {}, dbms).ValueList().size(), 0);
+  auto dba = dbms.active();
+  dba->InsertVertex().add_label(dba->Label("l1"));
+  {
+    auto info = ToList<std::string>(EvaluateFunction("INDEXINFO", {}, dbms));
+    EXPECT_EQ(info.size(), 1);
+    EXPECT_EQ(info[0], ":l1");
+  }
+  {
+    dba->BuildIndex(dba->Label("l1"), dba->Property("prop"));
+    auto info = ToList<std::string>(EvaluateFunction("INDEXINFO", {}, dbms));
+    EXPECT_EQ(info.size(), 2);
+    EXPECT_THAT(info, testing::UnorderedElementsAre(":l1", ":l1(prop)"));
+  }
+}
 }  // namespace