diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4ea2b5e76..d329e9163 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -11,7 +11,7 @@
* Map indexing supported.
* `assert` function added.
* Use \u to specify 4 digit codepoint and \U for 8 digit
-* `counter` function added.
+* `counter` and `counterSet` functions added.
### Bug Fixes and Other Changes
diff --git a/docs/user_technical/open-cypher.md b/docs/user_technical/open-cypher.md
index acafd3a23..4059927df 100644
--- a/docs/user_technical/open-cypher.md
+++ b/docs/user_technical/open-cypher.md
@@ -501,6 +501,7 @@ functions.
`all` | Check if all elements of a list satisfy a predicate.
The syntax is: `all(variable IN list WHERE predicate)`.
`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.
#### String Operators
diff --git a/src/database/graph_db_accessor.cpp b/src/database/graph_db_accessor.cpp
index 0064de484..7d96f7e01 100644
--- a/src/database/graph_db_accessor.cpp
+++ b/src/database/graph_db_accessor.cpp
@@ -334,3 +334,10 @@ int64_t GraphDbAccessor::Counter(const std::string &name) {
.emplace(name, std::make_tuple(name), std::make_tuple(0))
.first->second.fetch_add(1);
}
+
+void GraphDbAccessor::CounterSet(const std::string &name, int64_t value) {
+ auto name_counter_pair = db_.counters_.access()
+ .emplace(name, std::make_tuple(name), std::make_tuple(value));
+ if (!name_counter_pair.second)
+ name_counter_pair.first->second.store(value);
+}
diff --git a/src/database/graph_db_accessor.hpp b/src/database/graph_db_accessor.hpp
index 8c27cee36..19c3d131a 100644
--- a/src/database/graph_db_accessor.hpp
+++ b/src/database/graph_db_accessor.hpp
@@ -568,6 +568,13 @@ class GraphDbAccessor {
*/
int64_t Counter(const std::string &name);
+ /**
+ * Sets the counter with the given name to the given value. Returns nothing.
+ * If the counter with the given name does not exist, a new counter is
+ * created and set to the given value.
+ */
+ void CounterSet(const std::string &name, int64_t value);
+
private:
/**
* Insert this vertex into corresponding label and label+property (if it
diff --git a/src/query/interpret/awesome_memgraph_functions.cpp b/src/query/interpret/awesome_memgraph_functions.cpp
index 0c773eaf5..14dcf7e2d 100644
--- a/src/query/interpret/awesome_memgraph_functions.cpp
+++ b/src/query/interpret/awesome_memgraph_functions.cpp
@@ -532,6 +532,19 @@ TypedValue Counter(const std::vector &args, GraphDbAccessor &dba) {
return dba.Counter(args[0].ValueString());
}
+
+TypedValue CounterSet(const std::vector &args, GraphDbAccessor &dba) {
+ if (args.size() != 2U) {
+ throw QueryRuntimeException("counterSet takes two arguments");
+ }
+ if (!args[0].IsString())
+ throw QueryRuntimeException("first counterSet argument must be a string");
+ if (!args[1].IsInt())
+ throw QueryRuntimeException("first counterSet argument must be an int");
+
+ dba.CounterSet(args[0].ValueString(), args[1].ValueInt());
+ return TypedValue::Null;
+}
} // annonymous namespace
std::function &, GraphDbAccessor &)>
@@ -576,6 +589,7 @@ NameToFunction(const std::string &function_name) {
if (function_name == kContains) return Contains;
if (function_name == "ASSERT") return Assert;
if (function_name == "COUNTER") return Counter;
+ if (function_name == "COUNTERSET") return CounterSet;
return nullptr;
}
} // namespace query
diff --git a/tests/qa/tck_engine/tests/memgraph_V1/features/functions.feature b/tests/qa/tck_engine/tests/memgraph_V1/features/functions.feature
index 7e252b3f3..4a6eaafec 100644
--- a/tests/qa/tck_engine/tests/memgraph_V1/features/functions.feature
+++ b/tests/qa/tck_engine/tests/memgraph_V1/features/functions.feature
@@ -707,3 +707,15 @@ Feature: Functions
| 1 | 0 |
| 2 | 1 |
+
+ Scenario: CounterSet test:
+ When executing query:
+ """
+ WITH counter("n") AS zero
+ WITH counter("n") AS one, zero
+ WITH counterSet("n", 42) AS nothing, zero, one
+ RETURN counter("n") AS n, zero, one, counter("n2") AS n2
+ """
+ Then the result should be:
+ | n | zero | one | n2 |
+ | 42 | 0 | 1 | 0 |
diff --git a/tests/unit/query_expression_evaluator.cpp b/tests/unit/query_expression_evaluator.cpp
index 4d350736c..e61f9f6de 100644
--- a/tests/unit/query_expression_evaluator.cpp
+++ b/tests/unit/query_expression_evaluator.cpp
@@ -1218,4 +1218,21 @@ TEST(ExpressionEvaluator, FunctionCounter) {
EXPECT_EQ(EvaluateFunction("COUNTER", {"c2"}, dbms).ValueInt(), 1);
}
+TEST(ExpressionEvaluator, FunctionCounterSet) {
+ Dbms dbms;
+ EXPECT_THROW(EvaluateFunction("COUNTERSET", {}, dbms), QueryRuntimeException);
+ EXPECT_THROW(EvaluateFunction("COUNTERSET", {"a"}, dbms),
+ QueryRuntimeException);
+ EXPECT_THROW(EvaluateFunction("COUNTERSET", {"a", "b"}, dbms),
+ QueryRuntimeException);
+ EXPECT_THROW(EvaluateFunction("COUNTERSET", {"a", 11, 12}, dbms),
+ QueryRuntimeException);
+ EXPECT_EQ(EvaluateFunction("COUNTER", {"c1"}, dbms).ValueInt(), 0);
+ EvaluateFunction("COUNTERSET", {"c1", 12}, dbms);
+ EXPECT_EQ(EvaluateFunction("COUNTER", {"c1"}, dbms).ValueInt(), 12);
+ EvaluateFunction("COUNTERSET", {"c2", 42}, dbms);
+ EXPECT_EQ(EvaluateFunction("COUNTER", {"c2"}, dbms).ValueInt(), 42);
+ EXPECT_EQ(EvaluateFunction("COUNTER", {"c1"}, dbms).ValueInt(), 13);
+ EXPECT_EQ(EvaluateFunction("COUNTER", {"c2"}, dbms).ValueInt(), 43);
+}
} // namespace