From cfb987a90cf959a3483ba508faa73fb3ccec50ae Mon Sep 17 00:00:00 2001 From: Mislav Bradac Date: Fri, 5 May 2017 12:16:04 +0200 Subject: [PATCH] Evaluate epressions EdgeTypeTest and LabelsTest Reviewers: florijan, teon.banek Reviewed By: teon.banek Subscribers: pullbot Differential Revision: https://phabricator.memgraph.io/D345 --- src/query/frontend/ast/ast.hpp | 5 +- src/query/interpret/eval.hpp | 45 +++++++++ tests/unit/query_expression_evaluator.cpp | 110 +++++++++++++++++++++- 3 files changed, 158 insertions(+), 2 deletions(-) diff --git a/src/query/frontend/ast/ast.hpp b/src/query/frontend/ast/ast.hpp index 80c673892..f21ee36a6 100644 --- a/src/query/frontend/ast/ast.hpp +++ b/src/query/frontend/ast/ast.hpp @@ -526,7 +526,10 @@ class EdgeTypeTest : public Expression { protected: EdgeTypeTest(int uid, Expression *expression, std::vector edge_types) - : Expression(uid), expression_(expression), edge_types_(edge_types) {} + : Expression(uid), expression_(expression), edge_types_(edge_types) { + debug_assert(edge_types.size(), + "EdgeTypeTest must have at least one edge_type"); + } }; class Function : public Expression { diff --git a/src/query/interpret/eval.hpp b/src/query/interpret/eval.hpp index f2727f3a2..0aa8cb1a3 100644 --- a/src/query/interpret/eval.hpp +++ b/src/query/interpret/eval.hpp @@ -200,6 +200,51 @@ class ExpressionEvaluator : public TreeVisitorBase { } } + void PostVisit(LabelsTest &labels_test) override { + auto expression_result = PopBack(); + switch (expression_result.type()) { + case TypedValue::Type::Null: + result_stack_.emplace_back(TypedValue::Null); + break; + case TypedValue::Type::Vertex: { + auto vertex = expression_result.Value(); + for (const auto label : labels_test.labels_) { + if (!vertex.has_label(label)) { + result_stack_.emplace_back(false); + return; + } + } + result_stack_.emplace_back(true); + break; + } + default: + throw TypedValueException("Expected Node in labels test"); + } + } + + void PostVisit(EdgeTypeTest &edge_type_test) override { + auto expression_result = PopBack(); + switch (expression_result.type()) { + case TypedValue::Type::Null: + result_stack_.emplace_back(TypedValue::Null); + break; + case TypedValue::Type::Edge: { + auto real_edge_type = + expression_result.Value().edge_type(); + for (const auto edge_type : edge_type_test.edge_types_) { + if (edge_type == real_edge_type) { + result_stack_.emplace_back(true); + return; + } + } + result_stack_.emplace_back(false); + break; + } + default: + throw TypedValueException("Expected Edge in edge type test"); + } + } + void Visit(PrimitiveLiteral &literal) override { // TODO: no need to evaluate constants, we can write it to frame in one // of the previous phases. diff --git a/tests/unit/query_expression_evaluator.cpp b/tests/unit/query_expression_evaluator.cpp index f04c1b703..b1e7debd8 100644 --- a/tests/unit/query_expression_evaluator.cpp +++ b/tests/unit/query_expression_evaluator.cpp @@ -7,11 +7,13 @@ #include "gtest/gtest.h" #include "database/graph_db_accessor.hpp" +#include "database/graph_db_datatypes.hpp" #include "dbms/dbms.hpp" #include "query/frontend/ast/ast.hpp" #include "query/frontend/opencypher/parser.hpp" #include "query/interpret/awesome_memgraph_functions.hpp" #include "query/interpret/eval.hpp" +#include "query/interpret/frame.hpp" using namespace query; using testing::Pair; @@ -22,7 +24,7 @@ namespace { struct NoContextExpressionEvaluator { NoContextExpressionEvaluator() {} - Frame frame{0}; + Frame frame{128}; SymbolTable symbol_table; Dbms dbms; std::unique_ptr dba = dbms.active(); @@ -428,6 +430,112 @@ TEST(ExpressionEvaluator, IsNullOperator) { ASSERT_EQ(eval.eval.PopBack().Value(), true); } +TEST(ExpressionEvaluator, PropertyLookup) { + AstTreeStorage storage; + NoContextExpressionEvaluator eval; + Dbms dbms; + auto dba = dbms.active(); + auto v1 = dba->insert_vertex(); + v1.PropsSet(dba->property("age"), 10); + auto *identifier = storage.Create("n"); + auto node_symbol = eval.symbol_table.CreateSymbol("n"); + eval.symbol_table[*identifier] = node_symbol; + eval.frame[node_symbol] = v1; + { + auto *op = storage.Create(identifier, dba->property("age")); + op->Accept(eval.eval); + EXPECT_EQ(eval.eval.PopBack().Value(), 10); + } + { + auto *op = + storage.Create(identifier, dba->property("height")); + op->Accept(eval.eval); + EXPECT_TRUE(eval.eval.PopBack().IsNull()); + } + { + eval.frame[node_symbol] = TypedValue::Null; + auto *op = storage.Create(identifier, dba->property("age")); + op->Accept(eval.eval); + EXPECT_TRUE(eval.eval.PopBack().IsNull()); + } +} + +TEST(ExpressionEvaluator, LabelsTest) { + AstTreeStorage storage; + NoContextExpressionEvaluator eval; + Dbms dbms; + auto dba = dbms.active(); + auto v1 = dba->insert_vertex(); + v1.add_label(dba->label("ANIMAL")); + v1.add_label(dba->label("DOG")); + v1.add_label(dba->label("NICE_DOG")); + auto *identifier = storage.Create("n"); + auto node_symbol = eval.symbol_table.CreateSymbol("n"); + eval.symbol_table[*identifier] = node_symbol; + eval.frame[node_symbol] = v1; + { + auto *op = storage.Create( + identifier, std::vector{dba->label("DOG"), + dba->label("ANIMAL")}); + op->Accept(eval.eval); + EXPECT_EQ(eval.eval.PopBack().Value(), true); + } + { + auto *op = storage.Create( + identifier, + std::vector{ + dba->label("DOG"), dba->label("BAD_DOG"), dba->label("ANIMAL")}); + op->Accept(eval.eval); + EXPECT_EQ(eval.eval.PopBack().Value(), false); + } + { + eval.frame[node_symbol] = TypedValue::Null; + auto *op = storage.Create( + identifier, + std::vector{ + dba->label("DOG"), dba->label("BAD_DOG"), dba->label("ANIMAL")}); + op->Accept(eval.eval); + EXPECT_TRUE(eval.eval.PopBack().IsNull()); + } +} + +TEST(ExpressionEvaluator, EdgeTypeTest) { + AstTreeStorage storage; + NoContextExpressionEvaluator eval; + Dbms dbms; + auto dba = dbms.active(); + auto v1 = dba->insert_vertex(); + auto v2 = dba->insert_vertex(); + auto e = dba->insert_edge(v1, v2, dba->edge_type("TYPE1")); + auto *identifier = storage.Create("e"); + auto edge_symbol = eval.symbol_table.CreateSymbol("e"); + eval.symbol_table[*identifier] = edge_symbol; + eval.frame[edge_symbol] = e; + { + auto *op = storage.Create( + identifier, std::vector{ + dba->edge_type("TYPE0"), dba->edge_type("TYPE1"), + dba->edge_type("TYPE2")}); + op->Accept(eval.eval); + EXPECT_EQ(eval.eval.PopBack().Value(), true); + } + { + auto *op = storage.Create( + identifier, std::vector{ + dba->edge_type("TYPE0"), dba->edge_type("TYPE2")}); + op->Accept(eval.eval); + EXPECT_EQ(eval.eval.PopBack().Value(), false); + } + { + eval.frame[edge_symbol] = TypedValue::Null; + auto *op = storage.Create( + identifier, std::vector{ + dba->edge_type("TYPE0"), dba->edge_type("TYPE2")}); + op->Accept(eval.eval); + EXPECT_TRUE(eval.eval.PopBack().IsNull()); + } +} + TEST(ExpressionEvaluator, Aggregation) { AstTreeStorage storage; auto aggr = storage.Create(storage.Create(42),