Fix clang-tidy warnings, remove commented out code and add HasLabel

functions in ShardRequestManager to avoid throwing bad optional on
expression evaluator
This commit is contained in:
Kostas Kyrimis 2022-11-14 21:22:28 +02:00
parent 213583f916
commit 9e81fe791c
5 changed files with 165 additions and 557 deletions

View File

@ -417,7 +417,7 @@ class ExpressionEvaluator : public ExpressionVisitor<TypedValue> {
TReturnType HasLabelImpl(const VertexAccessor &vertex, const LabelIx &label_ix, QueryEngineTag /*tag*/) {
auto label = typename VertexAccessor::Label{LabelId::FromUint(label_ix.ix)};
auto has_label = vertex.HasLabel(label);
return !has_label;
return has_label;
}
TypedValue Visit(LabelsTest &labels_test) override {

View File

@ -61,12 +61,10 @@ template <typename TypedValueT, typename FunctionContextT, typename Tag, typenam
std::function<TypedValueT(const TypedValueT *arguments, int64_t num_arguments, const FunctionContextT &context)>
NameToFunction(const std::string &function_name);
namespace {
const char kStartsWith[] = "STARTSWITH";
const char kEndsWith[] = "ENDSWITH";
const char kContains[] = "CONTAINS";
const char kId[] = "ID";
} // namespace
inline const char kStartsWith[] = "STARTSWITH";
inline const char kEndsWith[] = "ENDSWITH";
inline const char kContains[] = "CONTAINS";
inline const char kId[] = "ID";
} // namespace memgraph::functions
@ -484,11 +482,11 @@ TypedValueT Properties(const TypedValueT *args, int64_t nargs, const FunctionCon
const auto &value = args[0];
if (value.IsNull()) {
return TypedValueT(ctx.memory);
} else if (value.IsVertex()) {
return get_properties(value.ValueVertex());
} else {
return get_properties(value.ValueEdge());
}
if (value.IsVertex()) {
return get_properties(value.ValueVertex());
}
return get_properties(value.ValueEdge());
}
template <typename TypedValueT, typename FunctionContextT>
@ -497,17 +495,19 @@ TypedValueT Size(const TypedValueT *args, int64_t nargs, const FunctionContextT
const auto &value = args[0];
if (value.IsNull()) {
return TypedValueT(ctx.memory);
} else if (value.IsList()) {
}
if (value.IsList()) {
return TypedValueT(static_cast<int64_t>(value.ValueList().size()), ctx.memory);
} else if (value.IsString()) {
}
if (value.IsString()) {
return TypedValueT(static_cast<int64_t>(value.ValueString().size()), ctx.memory);
} else if (value.IsMap()) {
}
if (value.IsMap()) {
// neo4j doesn't implement size for map, but I don't see a good reason not
// to do it.
return TypedValueT(static_cast<int64_t>(value.ValueMap().size()), ctx.memory);
} else {
return TypedValueT(static_cast<int64_t>(value.ValuePath().edges().size()), ctx.memory);
}
return TypedValueT(static_cast<int64_t>(value.ValuePath().edges().size()), ctx.memory);
}
template <typename TypedValueT, typename FunctionContextT, typename Tag, typename Conv>
@ -527,9 +527,9 @@ TypedValueT StartNode(const TypedValueT *args, int64_t nargs, const FunctionCont
}
}
namespace {
size_t UnwrapDegreeResult(storage::v3::Result<size_t> maybe_degree) {
// This is needed because clang-tidy fails to identify the use of this function in the if-constexpr branch
// NOLINTNEXTLINE(clang-diagnostic-unused-function)
inline size_t UnwrapDegreeResult(storage::v3::Result<size_t> maybe_degree) {
if (maybe_degree.HasError()) {
switch (maybe_degree.GetError()) {
case storage::v3::Error::DELETED_OBJECT:
@ -546,8 +546,6 @@ size_t UnwrapDegreeResult(storage::v3::Result<size_t> maybe_degree) {
return *maybe_degree;
}
} // namespace
template <typename TypedValueT, typename FunctionContextT, typename Tag>
TypedValueT Degree(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) {
FType<TypedValueT, Or<Null, Vertex>>("degree", args, nargs);
@ -599,18 +597,19 @@ TypedValueT ToBoolean(const TypedValueT *args, int64_t nargs, const FunctionCont
const auto &value = args[0];
if (value.IsNull()) {
return TypedValueT(ctx.memory);
} else if (value.IsBool()) {
return TypedValueT(value.ValueBool(), ctx.memory);
} else if (value.IsInt()) {
return TypedValueT(value.ValueInt() != 0L, ctx.memory);
} else {
auto s = utils::ToUpperCase(utils::Trim(value.ValueString()));
if (s == "TRUE") return TypedValueT(true, ctx.memory);
if (s == "FALSE") return TypedValueT(false, ctx.memory);
// I think this is just stupid and that exception should be thrown, but
// neo4j does it this way...
return TypedValueT(ctx.memory);
}
if (value.IsBool()) {
return TypedValueT(value.ValueBool(), ctx.memory);
}
if (value.IsInt()) {
return TypedValueT(value.ValueInt() != 0L, ctx.memory);
}
auto s = utils::ToUpperCase(utils::Trim(value.ValueString()));
if (s == "TRUE") return TypedValueT(true, ctx.memory);
if (s == "FALSE") return TypedValueT(false, ctx.memory);
// I think this is just stupid and that exception should be thrown, but
// neo4j does it this way...
return TypedValueT(ctx.memory);
}
template <typename TypedValueT, typename FunctionContextT>
@ -619,16 +618,17 @@ TypedValueT ToFloat(const TypedValueT *args, int64_t nargs, const FunctionContex
const auto &value = args[0];
if (value.IsNull()) {
return TypedValueT(ctx.memory);
} else if (value.IsInt()) {
}
if (value.IsInt()) {
return TypedValueT(static_cast<double>(value.ValueInt()), ctx.memory);
} else if (value.IsDouble()) {
}
if (value.IsDouble()) {
return TypedValueT(value, ctx.memory);
} else {
try {
return TypedValueT(utils::ParseDouble(utils::Trim(value.ValueString())), ctx.memory);
} catch (const utils::BasicException &) {
return TypedValueT(ctx.memory);
}
}
try {
return TypedValueT(utils::ParseDouble(utils::Trim(value.ValueString())), ctx.memory);
} catch (const utils::BasicException &) {
return TypedValueT(ctx.memory);
}
}
@ -638,20 +638,22 @@ TypedValueT ToInteger(const TypedValueT *args, int64_t nargs, const FunctionCont
const auto &value = args[0];
if (value.IsNull()) {
return TypedValueT(ctx.memory);
} else if (value.IsBool()) {
}
if (value.IsBool()) {
return TypedValueT(value.ValueBool() ? 1L : 0L, ctx.memory);
} else if (value.IsInt()) {
}
if (value.IsInt()) {
return TypedValueT(value, ctx.memory);
} else if (value.IsDouble()) {
}
if (value.IsDouble()) {
return TypedValueT(static_cast<int64_t>(value.ValueDouble()), ctx.memory);
} else {
try {
// Yup, this is correct. String is valid if it has floating point
// number, then it is parsed and converted to int.
return TypedValueT(static_cast<int64_t>(utils::ParseDouble(utils::Trim(value.ValueString()))), ctx.memory);
} catch (const utils::BasicException &) {
return TypedValueT(ctx.memory);
}
}
try {
// Yup, this is correct. String is valid if it has floating point
// number, then it is parsed and converted to int.
return TypedValueT(static_cast<int64_t>(utils::ParseDouble(utils::Trim(value.ValueString()))), ctx.memory);
} catch (const utils::BasicException &) {
return TypedValueT(ctx.memory);
}
}
@ -736,11 +738,11 @@ TypedValueT Keys(const TypedValueT *args, int64_t nargs, const FunctionContextT
const auto &value = args[0];
if (value.IsNull()) {
return TypedValueT(ctx.memory);
} else if (value.IsVertex()) {
return get_keys(value.ValueVertex());
} else {
return get_keys(value.ValueEdge());
}
if (value.IsVertex()) {
return get_keys(value.ValueVertex());
}
return get_keys(value.ValueEdge());
}
template <typename TypedValueT, typename FunctionContextT, typename Tag>
@ -853,13 +855,14 @@ TypedValueT Abs(const TypedValueT *args, int64_t nargs, const FunctionContextT &
const auto &value = args[0];
if (value.IsNull()) {
return TypedValueT(ctx.memory);
} else if (value.IsInt()) {
return TypedValueT(std::abs(value.ValueInt()), ctx.memory);
} else {
return TypedValueT(std::abs(value.ValueDouble()), ctx.memory);
}
if (value.IsInt()) {
return TypedValueT(std::abs(value.ValueInt()), ctx.memory);
}
return TypedValueT(std::abs(value.ValueDouble()), ctx.memory);
}
// NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
#define WRAP_CMATH_FLOAT_FUNCTION(name, lowercased_name) \
template <typename TypedValueT, typename FunctionContextT> \
TypedValueT name(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) { \
@ -867,11 +870,11 @@ TypedValueT Abs(const TypedValueT *args, int64_t nargs, const FunctionContextT &
const auto &value = args[0]; \
if (value.IsNull()) { \
return TypedValueT(ctx.memory); \
} else if (value.IsInt()) { \
return TypedValueT(lowercased_name(value.ValueInt()), ctx.memory); \
} else { \
return TypedValueT(lowercased_name(value.ValueDouble()), ctx.memory); \
} \
if (value.IsInt()) { \
return TypedValueT(lowercased_name(value.ValueInt()), ctx.memory); \
} \
return TypedValueT(lowercased_name(value.ValueDouble()), ctx.memory); \
}
WRAP_CMATH_FLOAT_FUNCTION(Ceil, ceil)
@ -899,9 +902,8 @@ TypedValueT Atan2(const TypedValueT *args, int64_t nargs, const FunctionContextT
auto to_double = [](const TypedValueT &t) -> double {
if (t.IsInt()) {
return t.ValueInt();
} else {
return t.ValueDouble();
}
return t.ValueDouble();
};
double y = to_double(args[0]);
double x = to_double(args[1]);
@ -915,11 +917,11 @@ TypedValueT Sign(const TypedValueT *args, int64_t nargs, const FunctionContextT
const auto &value = args[0];
if (value.IsNull()) {
return TypedValueT(ctx.memory);
} else if (value.IsInt()) {
return sign(value.ValueInt());
} else {
return sign(value.ValueDouble());
}
if (value.IsInt()) {
return sign(value.ValueInt());
}
return sign(value.ValueDouble());
}
template <typename TypedValueT, typename FunctionContextT>
@ -962,7 +964,7 @@ struct StartsWithPredicate {
};
template <typename TypedValueT, typename FunctionContextT>
inline auto StartsWith = StringMatchOperator<StartsWithPredicate<TypedValueT>, TypedValueT, FunctionContextT>;
inline const auto StartsWith = StringMatchOperator<StartsWithPredicate<TypedValueT>, TypedValueT, FunctionContextT>;
// Check if s1 ends with s2.
template <typename TypedValueT>
@ -975,7 +977,7 @@ struct EndsWithPredicate {
};
template <typename TypedValueT, typename FunctionContextT>
inline auto EndsWith = StringMatchOperator<EndsWithPredicate<TypedValueT>, TypedValueT, FunctionContextT>;
inline const auto EndsWith = StringMatchOperator<EndsWithPredicate<TypedValueT>, TypedValueT, FunctionContextT>;
// Check if s1 contains s2.
template <typename TypedValueT>
@ -988,7 +990,7 @@ struct ContainsPredicate {
};
template <typename TypedValueT, typename FunctionContextT>
inline auto Contains = StringMatchOperator<ContainsPredicate<TypedValueT>, TypedValueT, FunctionContextT>;
inline const auto Contains = StringMatchOperator<ContainsPredicate<TypedValueT>, TypedValueT, FunctionContextT>;
template <typename TypedValueT, typename FunctionContextT>
TypedValueT Assert(const TypedValueT *args, int64_t nargs, const FunctionContextT &ctx) {
@ -1026,11 +1028,11 @@ TypedValueT Id(const TypedValueT *args, int64_t nargs, const FunctionContextT &c
const auto &arg = args[0];
if (arg.IsNull()) {
return TypedValueT(ctx.memory);
} else if (arg.IsVertex()) {
return TypedValueT(static_cast<int64_t>(arg.ValueVertex().CypherId()), ctx.memory);
} else {
return TypedValueT(static_cast<int64_t>(arg.ValueEdge().CypherId()), ctx.memory);
}
if (arg.IsVertex()) {
return TypedValueT(static_cast<int64_t>(arg.ValueVertex().CypherId()), ctx.memory);
}
return TypedValueT(static_cast<int64_t>(arg.ValueEdge().CypherId()), ctx.memory);
}
template <typename TypedValueT, typename FunctionContextT>

View File

@ -23,11 +23,11 @@ EdgeTypeId EdgeAccessor::EdgeType() const { return edge.type.id; }
const std::vector<std::pair<PropertyId, Value>> &EdgeAccessor::Properties() const { return edge.properties; }
Value EdgeAccessor::GetProperty(const std::string &prop_name) const {
auto prop_id = manager_->NameToProperty(prop_name);
auto it = std::find_if(edge.properties.begin(), edge.properties.end(), [&](auto &pr) { return prop_id == pr.first; });
if (it == edge.properties.end()) {
if (!manager_->HasProperty(prop_name)) {
return {};
}
auto prop_id = manager_->NameToProperty(prop_name);
auto it = std::find_if(edge.properties.begin(), edge.properties.end(), [&](auto &pr) { return prop_id == pr.first; });
return it->second;
}
@ -88,6 +88,9 @@ Value VertexAccessor::GetProperty(PropertyId prop_id) const {
// NOLINTNEXTLINE(readability-convert-member-functions-to-static)
Value VertexAccessor::GetProperty(const std::string &prop_name) const {
if (!manager_->HasProperty(prop_name)) {
return {};
}
return GetProperty(manager_->NameToProperty(prop_name));
}

View File

@ -129,6 +129,9 @@ class ShardRequestManagerInterface {
virtual const std::string &PropertyToName(memgraph::storage::v3::PropertyId prop) const = 0;
virtual const std::string &LabelToName(memgraph::storage::v3::LabelId label) const = 0;
virtual const std::string &EdgeTypeToName(memgraph::storage::v3::EdgeTypeId type) const = 0;
virtual bool HasProperty(const std::string &name) const = 0;
virtual bool HasEdgeType(const std::string &name) const = 0;
virtual bool HasLabel(const std::string &name) const = 0;
virtual bool IsPrimaryLabel(LabelId label) const = 0;
virtual bool IsPrimaryKey(LabelId primary_label, PropertyId property) const = 0;
};
@ -353,6 +356,12 @@ class ShardRequestManager : public ShardRequestManagerInterface {
return result_rows;
}
bool HasProperty(const std::string &name) const override { return shards_map_.GetPropertyId(name).has_value(); }
bool HasEdgeType(const std::string &name) const override { return shards_map_.GetEdgeTypeId(name).has_value(); }
bool HasLabel(const std::string &name) const override { return shards_map_.GetLabelId(name).has_value(); }
private:
enum class PaginatedResponseState { Pending, PartiallyFinished };

View File

@ -30,6 +30,7 @@
#include "query/v2/frontend/ast/ast.hpp"
#include "query/v2/requests.hpp"
#include "query/v2/shard_request_manager.hpp"
#include "storage/v3/property_value.hpp"
#include "storage/v3/storage.hpp"
#include "utils/exceptions.hpp"
#include "utils/string.hpp"
@ -117,6 +118,12 @@ class MockedShardRequestManager : public memgraph::msgs::ShardRequestManagerInte
return edge_types_.IdToName(id.AsUint());
}
bool HasProperty(const std::string &name) const override { return shards_map_.GetPropertyId(name).has_value(); }
bool HasEdgeType(const std::string &name) const override { return shards_map_.GetEdgeTypeId(name).has_value(); }
bool HasLabel(const std::string &name) const override { return shards_map_.GetLabelId(name).has_value(); }
bool IsPrimaryLabel(LabelId label) const override { return true; }
bool IsPrimaryKey(LabelId primary_label, PropertyId property) const override { return true; }
@ -202,10 +209,6 @@ class ExpressionEvaluatorTest : public ::testing::Test {
ExpressionEvaluatorTest() {}
protected:
// memgraph::storage::Storage db;
// memgraph::storage::Storage::Accessor storage_dba{db.Access()};
// memgraph::query::DbAccessor dba{&storage_dba};
//
AstStorage storage;
memgraph::utils::MonotonicBufferResource mem{1024};
EvaluationContext ctx{.memory = &mem, .timestamp = memgraph::query::v2::QueryTimestamp()};
@ -575,36 +578,33 @@ TEST_F(ExpressionEvaluatorTest, VertexAndEdgeIndexing) {
// TODO(kostasrim) Investigate
// Shall we return null on missing properties? Or shall we throw bad optional access as we do now?
// {
// // Legal indexing, non-existing key.
// auto *op1 = storage.Create<SubscriptOperator>(vertex_id, storage.Create<PrimitiveLiteral>("blah"));
// auto value1 = Eval(op1);
// EXPECT_TRUE(value1.IsNull());
//
// auto *op2 = storage.Create<SubscriptOperator>(edge_id, storage.Create<PrimitiveLiteral>("blah"));
// auto value2 = Eval(op2);
// EXPECT_TRUE(value2.IsNull());
// }
// {
// // Wrong key type.
// auto *op1 = storage.Create<SubscriptOperator>(vertex_id, storage.Create<PrimitiveLiteral>(1));
// EXPECT_THROW(Eval(op1), ExpressionRuntimeException);
//
// auto *op2 = storage.Create<SubscriptOperator>(edge_id, storage.Create<PrimitiveLiteral>(1));
// EXPECT_THROW(Eval(op2), ExpressionRuntimeException);
// }
// {
// // Indexing with Null.
// auto *op1 = storage.Create<SubscriptOperator>(vertex_id,
// storage.Create<PrimitiveLiteral>(memgraph::storage::PropertyValue()));
// auto value1 = Eval(op1);
// EXPECT_TRUE(value1.IsNull());
//
// auto *op2 = storage.Create<SubscriptOperator>(edge_id,
// storage.Create<PrimitiveLiteral>(memgraph::storage::PropertyValue()));
// auto value2 = Eval(op2);
// EXPECT_TRUE(value2.IsNull());
// }
{
// Legal indexing, non-existing key.
auto *op1 = storage.Create<SubscriptOperator>(vertex_id, storage.Create<PrimitiveLiteral>("blah"));
auto value1 = Eval(op1);
EXPECT_TRUE(value1.IsNull());
auto *op2 = storage.Create<SubscriptOperator>(edge_id, storage.Create<PrimitiveLiteral>("blah"));
auto value2 = Eval(op2);
EXPECT_TRUE(value2.IsNull());
}
{
// Wrong key type.
auto *op1 = storage.Create<SubscriptOperator>(vertex_id, storage.Create<PrimitiveLiteral>(1));
EXPECT_THROW(Eval(op1), ExpressionRuntimeException);
auto *op2 = storage.Create<SubscriptOperator>(edge_id, storage.Create<PrimitiveLiteral>(1));
EXPECT_THROW(Eval(op2), ExpressionRuntimeException);
}
{
// Indexing with Null.
auto *op1 = storage.Create<SubscriptOperator>(vertex_id, storage.Create<PrimitiveLiteral>(TypedValue{}));
auto value1 = Eval(op1);
EXPECT_TRUE(value1.IsNull());
auto *op2 = storage.Create<SubscriptOperator>(edge_id, storage.Create<PrimitiveLiteral>(TypedValue{}));
auto value2 = Eval(op2);
EXPECT_TRUE(value2.IsNull());
}
}
TEST_F(ExpressionEvaluatorTest, ListSlicingOperator) {
@ -741,41 +741,31 @@ TEST_F(ExpressionEvaluatorTest, IsNullOperator) {
ASSERT_EQ(val2.ValueBool(), true);
}
// TEST_F(ExpressionEvaluatorTest, LabelsTest) {
// auto v1 = dba.InsertVertex();
// ASSERT_TRUE(v1.AddLabel(dba.NameToLabel("ANIMAL")).HasValue());
// ASSERT_TRUE(v1.AddLabel(dba.NameToLabel("DOG")).HasValue());
// ASSERT_TRUE(v1.AddLabel(dba.NameToLabel("NICE_DOG")).HasValue());
// dba.AdvanceCommand();
// auto *identifier = storage.Create<Identifier>("n");
// auto node_symbol = symbol_table.CreateSymbol("n", true);
// identifier->MapTo(node_symbol);
// frame[node_symbol] = TypedValue(v1);
// {
// auto *op = storage.Create<LabelsTest>(
// identifier, std::vector<LabelIx>{storage.GetLabelIx("DOG"), storage.GetLabelIx("ANIMAL")});
// auto value = Eval(op);
// EXPECT_EQ(value.ValueBool(), true);
// }
// {
// auto *op = storage.Create<LabelsTest>(
// identifier,
// std::vector<LabelIx>{storage.GetLabelIx("DOG"), storage.GetLabelIx("BAD_DOG"),
// storage.GetLabelIx("ANIMAL")});
// auto value = Eval(op);
// EXPECT_EQ(value.ValueBool(), false);
// }
// {
// frame[node_symbol] = TypedValue();
// auto *op = storage.Create<LabelsTest>(
// identifier,
// std::vector<LabelIx>{storage.GetLabelIx("DOG"), storage.GetLabelIx("BAD_DOG"),
// storage.GetLabelIx("ANIMAL")});
// auto value = Eval(op);
// EXPECT_TRUE(value.IsNull());
// }
// }
//
TEST_F(ExpressionEvaluatorTest, LabelsTest) {
Label label{shard_manager->NameToLabel("label1")};
auto v1 = CreateVertex({}, shard_manager.get(), label);
auto *identifier = storage.Create<Identifier>("n");
auto node_symbol = symbol_table.CreateSymbol("n", true);
identifier->MapTo(node_symbol);
frame[node_symbol] = TypedValue(v1);
{
auto *op = storage.Create<LabelsTest>(identifier, std::vector<LabelIx>{LabelIx{"label1", label.id.AsInt()}});
auto value = Eval(op);
EXPECT_EQ(value.ValueBool(), true);
}
{
auto *op = storage.Create<LabelsTest>(identifier, std::vector<LabelIx>{LabelIx{"label2", 10}});
auto value = Eval(op);
EXPECT_EQ(value.ValueBool(), false);
}
{
auto *op = storage.Create<LabelsTest>(identifier, std::vector<LabelIx>{LabelIx{"label2", 10}});
frame[node_symbol] = TypedValue();
auto value = Eval(op);
EXPECT_TRUE(value.IsNull());
}
}
TEST_F(ExpressionEvaluatorTest, Aggregation) {
auto aggr = storage.Create<Aggregation>(storage.Create<PrimitiveLiteral>(42), nullptr, Aggregation::Op::COUNT);
auto aggr_sym = symbol_table.CreateSymbol("aggr", true);
@ -794,11 +784,8 @@ TEST_F(ExpressionEvaluatorTest, ListLiteral) {
auto &result_elems = result.ValueList();
ASSERT_EQ(3, result_elems.size());
EXPECT_TRUE(result_elems[0].IsInt());
;
EXPECT_TRUE(result_elems[1].IsString());
;
EXPECT_TRUE(result_elems[2].IsBool());
;
}
TEST_F(ExpressionEvaluatorTest, ParameterLookup) {
@ -1148,167 +1135,16 @@ class ExpressionEvaluatorPropertyLookup : public ExpressionEvaluatorTest {
}
};
// TODO(kostasrim) These will fail because of memory resource not propagating correctly. This should be done as part of
// polishing the allocators.
// TEST_F(ExpressionEvaluatorPropertyLookup, Vertex) {
// auto v1 = dba.InsertVertex();
// ASSERT_TRUE(v1.SetProperty(prop_age.second, memgraph::storage::PropertyValue(10)).HasValue());
// dba.AdvanceCommand();
// auto v1 = CreateVertex({{prop_age.second, memgraph::msgs::Value(static_cast<int64_t>(32))}}, shard_manager.get());
// frame[symbol] = TypedValue(v1);
// EXPECT_EQ(Value(prop_age).ValueInt(), 10);
// EXPECT_TRUE(Value(prop_height).IsNull());
// }
//
// TEST_F(ExpressionEvaluatorPropertyLookup, Duration) {
// const memgraph::utils::Duration dur({10, 1, 30, 2, 22, 45});
// frame[symbol] = TypedValue(dur);
//
// const std::pair day = std::make_pair("day", dba.NameToProperty("day"));
// const auto total_days = Value(day);
// EXPECT_TRUE(total_days.IsInt());
// EXPECT_EQ(total_days.ValueInt(), 10);
//
// const std::pair hour = std::make_pair("hour", dba.NameToProperty("hour"));
// const auto total_hours = Value(hour);
// EXPECT_TRUE(total_hours.IsInt());
// EXPECT_EQ(total_hours.ValueInt(), 1);
//
// const std::pair minute = std::make_pair("minute", dba.NameToProperty("minute"));
// const auto total_mins = Value(minute);
// EXPECT_TRUE(total_mins.IsInt());
//
// EXPECT_EQ(total_mins.ValueInt(), 1 * 60 + 30);
//
// const std::pair sec = std::make_pair("second", dba.NameToProperty("second"));
// const auto total_secs = Value(sec);
// EXPECT_TRUE(total_secs.IsInt());
// const auto expected_secs = total_mins.ValueInt() * 60 + 2;
// EXPECT_EQ(total_secs.ValueInt(), expected_secs);
//
// const std::pair milli = std::make_pair("millisecond", dba.NameToProperty("millisecond"));
// const auto total_milli = Value(milli);
// EXPECT_TRUE(total_milli.IsInt());
// const auto expected_milli = total_secs.ValueInt() * 1000 + 22;
// EXPECT_EQ(total_milli.ValueInt(), expected_milli);
//
// const std::pair micro = std::make_pair("microsecond", dba.NameToProperty("microsecond"));
// const auto total_micros = Value(micro);
// EXPECT_TRUE(total_micros.IsInt());
// const auto expected_micros = expected_milli * 1000 + 45;
// EXPECT_EQ(total_micros.ValueInt(), expected_micros);
//
// const std::pair nano = std::make_pair("nanosecond", dba.NameToProperty("nanosecond"));
// const auto total_nano = Value(nano);
// EXPECT_TRUE(total_nano.IsInt());
// const auto expected_nano = expected_micros * 1000;
// EXPECT_EQ(total_nano.ValueInt(), expected_nano);
// }
//
// TEST_F(ExpressionEvaluatorPropertyLookup, Date) {
// const memgraph::utils::Date date({1996, 11, 22});
// frame[symbol] = TypedValue(date);
//
// const std::pair year = std::make_pair("year", dba.NameToProperty("year"));
// const auto y = Value(year);
// EXPECT_TRUE(y.IsInt());
// EXPECT_EQ(y.ValueInt(), 1996);
//
// const std::pair month = std::make_pair("month", dba.NameToProperty("month"));
// const auto m = Value(month);
// EXPECT_TRUE(m.IsInt());
// EXPECT_EQ(m.ValueInt(), 11);
//
// const std::pair day = std::make_pair("day", dba.NameToProperty("day"));
// const auto d = Value(day);
// EXPECT_TRUE(d.IsInt());
// EXPECT_EQ(d.ValueInt(), 22);
// }
//
// TEST_F(ExpressionEvaluatorPropertyLookup, LocalTime) {
// const memgraph::utils::LocalTime lt({1, 2, 3, 11, 22});
// frame[symbol] = TypedValue(lt);
//
// const std::pair hour = std::make_pair("hour", dba.NameToProperty("hour"));
// const auto h = Value(hour);
// EXPECT_TRUE(h.IsInt());
// EXPECT_EQ(h.ValueInt(), 1);
//
// const std::pair minute = std::make_pair("minute", dba.NameToProperty("minute"));
// const auto min = Value(minute);
// EXPECT_TRUE(min.IsInt());
// EXPECT_EQ(min.ValueInt(), 2);
//
// const std::pair second = std::make_pair("second", dba.NameToProperty("second"));
// const auto sec = Value(second);
// EXPECT_TRUE(sec.IsInt());
// EXPECT_EQ(sec.ValueInt(), 3);
//
// const std::pair millis = std::make_pair("millisecond", dba.NameToProperty("millisecond"));
// const auto mil = Value(millis);
// EXPECT_TRUE(mil.IsInt());
// EXPECT_EQ(mil.ValueInt(), 11);
//
// const std::pair micros = std::make_pair("microsecond", dba.NameToProperty("microsecond"));
// const auto mic = Value(micros);
// EXPECT_TRUE(mic.IsInt());
// EXPECT_EQ(mic.ValueInt(), 22);
// }
//
// TEST_F(ExpressionEvaluatorPropertyLookup, LocalDateTime) {
// const memgraph::utils::LocalDateTime ldt({1993, 8, 6}, {2, 3, 4, 55, 40});
// frame[symbol] = TypedValue(ldt);
//
// const std::pair year = std::make_pair("year", dba.NameToProperty("year"));
// const auto y = Value(year);
// EXPECT_TRUE(y.IsInt());
// EXPECT_EQ(y.ValueInt(), 1993);
//
// const std::pair month = std::make_pair("month", dba.NameToProperty("month"));
// const auto m = Value(month);
// EXPECT_TRUE(m.IsInt());
// EXPECT_EQ(m.ValueInt(), 8);
//
// const std::pair day = std::make_pair("day", dba.NameToProperty("day"));
// const auto d = Value(day);
// EXPECT_TRUE(d.IsInt());
// EXPECT_EQ(d.ValueInt(), 6);
//
// const std::pair hour = std::make_pair("hour", dba.NameToProperty("hour"));
// const auto h = Value(hour);
// EXPECT_TRUE(h.IsInt());
// EXPECT_EQ(h.ValueInt(), 2);
//
// const std::pair minute = std::make_pair("minute", dba.NameToProperty("minute"));
// const auto min = Value(minute);
// EXPECT_TRUE(min.IsInt());
// EXPECT_EQ(min.ValueInt(), 3);
//
// const std::pair second = std::make_pair("second", dba.NameToProperty("second"));
// const auto sec = Value(second);
// EXPECT_TRUE(sec.IsInt());
// EXPECT_EQ(sec.ValueInt(), 4);
//
// const std::pair millis = std::make_pair("millisecond", dba.NameToProperty("millisecond"));
// const auto mil = Value(millis);
// EXPECT_TRUE(mil.IsInt());
// EXPECT_EQ(mil.ValueInt(), 55);
//
// const std::pair micros = std::make_pair("microsecond", dba.NameToProperty("microsecond"));
// const auto mic = Value(micros);
// EXPECT_TRUE(mic.IsInt());
// EXPECT_EQ(mic.ValueInt(), 40);
// }
//
// TEST_F(ExpressionEvaluatorPropertyLookup, Edge) {
// auto v1 = dba.InsertVertex();
// auto v2 = dba.InsertVertex();
// auto e12 = dba.InsertEdge(&v1, &v2, dba.NameToEdgeType("edge_type"));
// ASSERT_TRUE(e12.HasValue());
// ASSERT_TRUE(e12->SetProperty(prop_age.second, memgraph::storage::PropertyValue(10)).HasValue());
// dba.AdvanceCommand();
// frame[symbol] = TypedValue(*e12);
// EXPECT_EQ(Value(prop_age).ValueInt(), 10);
// EXPECT_TRUE(Value(prop_height).IsNull());
// }
//
// TEST_F(ExpressionEvaluatorPropertyLookup, Edge) {}
TEST_F(ExpressionEvaluatorPropertyLookup, Null) {
frame[symbol] = TypedValue();
EXPECT_TRUE(Value(prop_age).IsNull());
@ -1455,59 +1291,10 @@ TEST_F(FunctionTest, StartNode) {
}
// TODO(kostasrim) Enable this test once we add degree to the accessors
// TEST_F(FunctionTest, Degree) {
// ASSERT_THROW(EvaluateFunction("DEGREE"), ExpressionRuntimeException);
// ASSERT_TRUE(EvaluateFunction("DEGREE", TypedValue()).IsNull());
// auto v1 = dba.InsertVertex();
// auto v2 = dba.InsertVertex();
// auto v3 = dba.InsertVertex();
// auto e12 = dba.InsertEdge(&v1, &v2, dba.NameToEdgeType("t"));
// ASSERT_TRUE(e12.HasValue());
// ASSERT_TRUE(dba.InsertEdge(&v3, &v2, dba.NameToEdgeType("t")).HasValue());
// dba.AdvanceCommand();
// ASSERT_EQ(EvaluateFunction("DEGREE", v1).ValueInt(), 1);
// ASSERT_EQ(EvaluateFunction("DEGREE", v2).ValueInt(), 2);
// ASSERT_EQ(EvaluateFunction("DEGREE", v3).ValueInt(), 1);
// ASSERT_THROW(EvaluateFunction("DEGREE", 2), ExpressionRuntimeException);
// ASSERT_THROW(EvaluateFunction("DEGREE", *e12), ExpressionRuntimeException);
// }
//
// TODO(kostasrim) Enable this test once we add InDegree to the accessors
// TEST_F(FunctionTest, InDegree) {
// ASSERT_THROW(EvaluateFunction("INDEGREE"), ExpressionRuntimeException);
// ASSERT_TRUE(EvaluateFunction("INDEGREE", TypedValue()).IsNull());
// auto v1 = dba.InsertVertex();
// auto v2 = dba.InsertVertex();
// auto v3 = dba.InsertVertex();
// auto e12 = dba.InsertEdge(&v1, &v2, dba.NameToEdgeType("t"));
// ASSERT_TRUE(e12.HasValue());
// ASSERT_TRUE(dba.InsertEdge(&v3, &v2, dba.NameToEdgeType("t")).HasValue());
// dba.AdvanceCommand();
// ASSERT_EQ(EvaluateFunction("INDEGREE", v1).ValueInt(), 0);
// ASSERT_EQ(EvaluateFunction("INDEGREE", v2).ValueInt(), 2);
// ASSERT_EQ(EvaluateFunction("INDEGREE", v3).ValueInt(), 0);
// ASSERT_THROW(EvaluateFunction("INDEGREE", 2), ExpressionRuntimeException);
// ASSERT_THROW(EvaluateFunction("INDEGREE", *e12), ExpressionRuntimeException);
// }
//
// TODO(kostasrim) Enable this test once we add OutDegree to the accessors
// TEST_F(FunctionTest, OutDegree) {
// ASSERT_THROW(EvaluateFunction("OUTDEGREE"), ExpressionRuntimeException);
// ASSERT_TRUE(EvaluateFunction("OUTDEGREE", TypedValue()).IsNull());
// auto v1 = dba.InsertVertex();
// auto v2 = dba.InsertVertex();
// auto v3 = dba.InsertVertex();
// auto e12 = dba.InsertEdge(&v1, &v2, dba.NameToEdgeType("t"));
// ASSERT_TRUE(e12.HasValue());
// ASSERT_TRUE(dba.InsertEdge(&v3, &v2, dba.NameToEdgeType("t")).HasValue());
// dba.AdvanceCommand();
// ASSERT_EQ(EvaluateFunction("OUTDEGREE", v1).ValueInt(), 1);
// ASSERT_EQ(EvaluateFunction("OUTDEGREE", v2).ValueInt(), 0);
// ASSERT_EQ(EvaluateFunction("OUTDEGREE", v3).ValueInt(), 1);
// ASSERT_THROW(EvaluateFunction("OUTDEGREE", 2), ExpressionRuntimeException);
// ASSERT_THROW(EvaluateFunction("OUTDEGREE", *e12), ExpressionRuntimeException);
// }
//
// TEST_F(FunctionTest, Degree) {}
// TEST_F(FunctionTest, InDegree) {}
// TEST_F(FunctionTest, OutDegree) {}
TEST_F(FunctionTest, ToBoolean) {
ASSERT_THROW(EvaluateFunction("TOBOOLEAN"), FunctionRuntimeException);
ASSERT_TRUE(EvaluateFunction("TOBOOLEAN", TypedValue()).IsNull());
@ -1591,42 +1378,8 @@ TEST_F(FunctionTest, Labels) {
}
// TODO(kostasrim) Enable this once we fix accessors Path
// TEST_F(FunctionTest, NodesRelationships) {
// EXPECT_THROW(EvaluateFunction("NODES"), ExpressionRuntimeException);
// EXPECT_THROW(EvaluateFunction("RELATIONSHIPS"), ExpressionRuntimeException);
// EXPECT_TRUE(EvaluateFunction("NODES", TypedValue()).IsNull());
// EXPECT_TRUE(EvaluateFunction("RELATIONSHIPS", TypedValue()).IsNull());
//
// {
// auto v1 = dba.InsertVertex();
// auto v2 = dba.InsertVertex();
// auto v3 = dba.InsertVertex();
// auto e1 = dba.InsertEdge(&v1, &v2, dba.NameToEdgeType("Type"));
// ASSERT_TRUE(e1.HasValue());
// auto e2 = dba.InsertEdge(&v2, &v3, dba.NameToEdgeType("Type"));
// ASSERT_TRUE(e2.HasValue());
// memgraph::query::Path path{v1, *e1, v2, *e2, v3};
// dba.AdvanceCommand();
//
// auto _nodes = EvaluateFunction("NODES", path).ValueList();
// std::vector<memgraph::query::VertexAccessor> nodes;
// for (const auto &node : _nodes) {
// nodes.push_back(node.ValueVertex());
// }
// EXPECT_THAT(nodes, ElementsAre(v1, v2, v3));
//
// auto _edges = EvaluateFunction("RELATIONSHIPS", path).ValueList();
// std::vector<memgraph::query::EdgeAccessor> edges;
// for (const auto &edge : _edges) {
// edges.push_back(edge.ValueEdge());
// }
// EXPECT_THAT(edges, ElementsAre(*e1, *e2));
// }
//
// EXPECT_THROW(EvaluateFunction("NODES", 2), ExpressionRuntimeException);
// EXPECT_THROW(EvaluateFunction("RELATIONSHIPS", 2), ExpressionRuntimeException);
// }
//
// TEST_F(FunctionTest, NodesRelationships) {}
TEST_F(FunctionTest, Range) {
EXPECT_THROW(EvaluateFunction("RANGE"), FunctionRuntimeException);
EXPECT_TRUE(EvaluateFunction("RANGE", 1, 2, TypedValue()).IsNull());
@ -1889,64 +1642,10 @@ TEST_F(FunctionTest, ToStringBool) {
EXPECT_EQ(EvaluateFunction("TOSTRING", false).ValueString(), "false");
}
// TEST_F(FunctionTest, ToStringDate) {
// const auto date = memgraph::utils::Date({1970, 1, 2});
// EXPECT_EQ(EvaluateFunction("TOSTRING", date).ValueString(), "1970-01-02");
// }
//
// TEST_F(FunctionTest, ToStringLocalTime) {
// const auto lt = memgraph::utils::LocalTime({13, 2, 40, 100, 50});
// EXPECT_EQ(EvaluateFunction("TOSTRING", lt).ValueString(), "13:02:40.100050");
// }
//
// TEST_F(FunctionTest, ToStringLocalDateTime) {
// const auto ldt = memgraph::utils::LocalDateTime({1970, 1, 2}, {23, 02, 59});
// EXPECT_EQ(EvaluateFunction("TOSTRING", ldt).ValueString(), "1970-01-02T23:02:59.000000");
// }
//
// TEST_F(FunctionTest, ToStringDuration) {
// memgraph::utils::Duration duration{{.minute = 2, .second = 2, .microsecond = 33}};
// EXPECT_EQ(EvaluateFunction("TOSTRING", duration).ValueString(), "P0DT0H2M2.000033S");
// }
//
TEST_F(FunctionTest, ToStringExceptions) {
EXPECT_THROW(EvaluateFunction("TOSTRING", 1, 2, 3), FunctionRuntimeException);
}
//
// TEST_F(FunctionTest, TimestampVoid) {
// ctx.timestamp = 42;
// EXPECT_EQ(EvaluateFunction("TIMESTAMP").ValueInt(), 42);
// }
//
// TEST_F(FunctionTest, TimestampDate) {
// ctx.timestamp = 42;
// EXPECT_EQ(EvaluateFunction("TIMESTAMP", memgraph::utils::Date({1970, 1, 1})).ValueInt(), 0);
// EXPECT_EQ(EvaluateFunction("TIMESTAMP", memgraph::utils::Date({1971, 1, 1})).ValueInt(), 31536000000000);
// }
//
// TEST_F(FunctionTest, TimestampLocalTime) {
// ctx.timestamp = 42;
// const memgraph::utils::LocalTime time(10000);
// EXPECT_EQ(EvaluateFunction("TIMESTAMP", time).ValueInt(), 10000);
// }
//
// TEST_F(FunctionTest, TimestampLocalDateTime) {
// ctx.timestamp = 42;
// const memgraph::utils::LocalDateTime time(20000);
// EXPECT_EQ(EvaluateFunction("TIMESTAMP", time).ValueInt(), 20000);
// }
//
// TEST_F(FunctionTest, TimestampDuration) {
// ctx.timestamp = 42;
// const memgraph::utils::Duration time(20000);
// EXPECT_EQ(EvaluateFunction("TIMESTAMP", time).ValueInt(), 20000);
// }
//
// TEST_F(FunctionTest, TimestampExceptions) {
// ctx.timestamp = 42;
// EXPECT_THROW(EvaluateFunction("TIMESTAMP", 1).ValueInt(), ExpressionRuntimeException);
// }
//
TEST_F(FunctionTest, Left) {
EXPECT_THROW(EvaluateFunction("LEFT"), FunctionRuntimeException);
@ -2083,110 +1782,5 @@ TEST_F(FunctionTest, FromByteString) {
EXPECT_EQ(EvaluateFunction("FROMBYTESTRING", std::string("\x00\x42", 2)).ValueString(), "0x0042");
}
// TEST_F(FunctionTest, Date) {
// const auto unix_epoch = memgraph::utils::Date({1970, 1, 1});
// EXPECT_EQ(EvaluateFunction("DATE", "1970-01-01").ValueDate(), unix_epoch);
// const auto map_param = TypedValue(
// std::map<std::string, TypedValue>{{"year", TypedValue(1970)}, {"month", TypedValue(1)}, {"day",
// TypedValue(1)}});
// EXPECT_EQ(EvaluateFunction("DATE", map_param).ValueDate(), unix_epoch);
// const auto today = memgraph::utils::CurrentDate();
// EXPECT_EQ(EvaluateFunction("DATE").ValueDate(), today);
//
// EXPECT_THROW(EvaluateFunction("DATE", "{}"), memgraph::utils::BasicException);
// EXPECT_THROW(EvaluateFunction("DATE", std::map<std::string, TypedValue>{{"years", TypedValue(1970)}}),
// ExpressionRuntimeException);
// EXPECT_THROW(EvaluateFunction("DATE", std::map<std::string, TypedValue>{{"mnths", TypedValue(1970)}}),
// ExpressionRuntimeException);
// EXPECT_THROW(EvaluateFunction("DATE", std::map<std::string, TypedValue>{{"dayz", TypedValue(1970)}}),
// ExpressionRuntimeException);
// }
//
// TEST_F(FunctionTest, LocalTime) {
// const auto local_time = memgraph::utils::LocalTime({13, 3, 2, 0, 0});
// EXPECT_EQ(EvaluateFunction("LOCALTIME", "130302").ValueLocalTime(), local_time);
// const auto one_sec_in_microseconds = 1000000;
// const auto map_param = TypedValue(std::map<std::string, TypedValue>{{"hour", TypedValue(1)},
// {"minute", TypedValue(2)},
// {"second", TypedValue(3)},
// {"millisecond", TypedValue(4)},
// {"microsecond", TypedValue(5)}});
// EXPECT_EQ(EvaluateFunction("LOCALTIME", map_param).ValueLocalTime(), memgraph::utils::LocalTime({1, 2, 3, 4, 5}));
// const auto today = memgraph::utils::CurrentLocalTime();
// EXPECT_NEAR(EvaluateFunction("LOCALTIME").ValueLocalTime().MicrosecondsSinceEpoch(),
// today.MicrosecondsSinceEpoch(),
// one_sec_in_microseconds);
//
// EXPECT_THROW(EvaluateFunction("LOCALTIME", "{}"), memgraph::utils::BasicException);
// EXPECT_THROW(EvaluateFunction("LOCALTIME", TypedValue(std::map<std::string, TypedValue>{{"hous",
// TypedValue(1970)}})),
// ExpressionRuntimeException);
// EXPECT_THROW(
// EvaluateFunction("LOCALTIME", TypedValue(std::map<std::string, TypedValue>{{"minut", TypedValue(1970)}})),
// ExpressionRuntimeException);
// EXPECT_THROW(
// EvaluateFunction("LOCALTIME", TypedValue(std::map<std::string, TypedValue>{{"seconds", TypedValue(1970)}})),
// ExpressionRuntimeException);
// }
//
// TEST_F(FunctionTest, LocalDateTime) {
// const auto local_date_time = memgraph::utils::LocalDateTime({1970, 1, 1}, {13, 3, 2, 0, 0});
// EXPECT_EQ(EvaluateFunction("LOCALDATETIME", "1970-01-01T13:03:02").ValueLocalDateTime(), local_date_time);
// const auto today = memgraph::utils::CurrentLocalDateTime();
// const auto one_sec_in_microseconds = 1000000;
// const auto map_param = TypedValue(std::map<std::string, TypedValue>{{"year", TypedValue(1972)},
// {"month", TypedValue(2)},
// {"day", TypedValue(3)},
// {"hour", TypedValue(4)},
// {"minute", TypedValue(5)},
// {"second", TypedValue(6)},
// {"millisecond", TypedValue(7)},
// {"microsecond", TypedValue(8)}});
//
// EXPECT_EQ(EvaluateFunction("LOCALDATETIME", map_param).ValueLocalDateTime(),
// memgraph::utils::LocalDateTime({1972, 2, 3}, {4, 5, 6, 7, 8}));
// EXPECT_NEAR(EvaluateFunction("LOCALDATETIME").ValueLocalDateTime().MicrosecondsSinceEpoch(),
// today.MicrosecondsSinceEpoch(), one_sec_in_microseconds);
// EXPECT_THROW(EvaluateFunction("LOCALDATETIME", "{}"), memgraph::utils::BasicException);
// EXPECT_THROW(
// EvaluateFunction("LOCALDATETIME", TypedValue(std::map<std::string, TypedValue>{{"hours", TypedValue(1970)}})),
// ExpressionRuntimeException);
// EXPECT_THROW(
// EvaluateFunction("LOCALDATETIME", TypedValue(std::map<std::string, TypedValue>{{"seconds",
// TypedValue(1970)}})), ExpressionRuntimeException);
// }
//
// TEST_F(FunctionTest, Duration) {
// const auto map_param = TypedValue(std::map<std::string, TypedValue>{{"day", TypedValue(3)},
// {"hour", TypedValue(4)},
// {"minute", TypedValue(5)},
// {"second", TypedValue(6)},
// {"millisecond", TypedValue(7)},
// {"microsecond", TypedValue(8)}});
//
// EXPECT_EQ(EvaluateFunction("DURATION", map_param).ValueDuration(), memgraph::utils::Duration({3, 4, 5, 6, 7, 8}));
// EXPECT_THROW(EvaluateFunction("DURATION", "{}"), memgraph::utils::BasicException);
// EXPECT_THROW(EvaluateFunction("DURATION", TypedValue(std::map<std::string, TypedValue>{{"hours",
// TypedValue(1970)}})),
// ExpressionRuntimeException);
// EXPECT_THROW(
// EvaluateFunction("DURATION", TypedValue(std::map<std::string, TypedValue>{{"seconds", TypedValue(1970)}})),
// ExpressionRuntimeException);
//
// const auto map_param_negative = TypedValue(std::map<std::string, TypedValue>{{"day", TypedValue(-3)},
// {"hour", TypedValue(-4)},
// {"minute", TypedValue(-5)},
// {"second", TypedValue(-6)},
// {"millisecond", TypedValue(-7)},
// {"microsecond", TypedValue(-8)}});
// EXPECT_EQ(EvaluateFunction("DURATION", map_param_negative).ValueDuration(),
// memgraph::utils::Duration({-3, -4, -5, -6, -7, -8}));
//
// EXPECT_EQ(EvaluateFunction("DURATION", "P4DT4H5M6.2S").ValueDuration(),
// memgraph::utils::Duration({4, 4, 5, 6, 0, 200000}));
// EXPECT_EQ(EvaluateFunction("DURATION", "P3DT4H5M6.100S").ValueDuration(),
// memgraph::utils::Duration({3, 4, 5, 6, 0, 100000}));
// EXPECT_EQ(EvaluateFunction("DURATION", "P3DT4H5M6.100110S").ValueDuration(),
// memgraph::utils::Duration({3, 4, 5, 6, 100, 110}));
// }
// TODO(kostasrim) Add temporal type tests.
} // namespace