Implement IS NULL and IS NOT NULL
Reviewers: teon.banek, florijan Reviewed By: florijan Subscribers: pullbot Differential Revision: https://phabricator.memgraph.io/D254
This commit is contained in:
parent
fd2780155a
commit
b7ee09785b
@ -347,6 +347,20 @@ class UnaryMinusOperator : public UnaryOperator {
|
||||
using UnaryOperator::UnaryOperator;
|
||||
};
|
||||
|
||||
class IsNullOperator : public UnaryOperator {
|
||||
friend class AstTreeStorage;
|
||||
|
||||
public:
|
||||
void Accept(TreeVisitorBase &visitor) override {
|
||||
visitor.Visit(*this);
|
||||
expression_->Accept(visitor);
|
||||
visitor.PostVisit(*this);
|
||||
}
|
||||
|
||||
protected:
|
||||
using UnaryOperator::UnaryOperator;
|
||||
};
|
||||
|
||||
class Literal : public Expression {
|
||||
friend class AstTreeStorage;
|
||||
|
||||
|
@ -29,6 +29,7 @@ class DivisionOperator;
|
||||
class ModOperator;
|
||||
class UnaryPlusOperator;
|
||||
class UnaryMinusOperator;
|
||||
class IsNullOperator;
|
||||
class NotEqualOperator;
|
||||
class EqualOperator;
|
||||
class LessOperator;
|
||||
@ -48,8 +49,8 @@ using TreeVisitorBase = ::utils::Visitor<
|
||||
AdditionOperator, SubtractionOperator, MultiplicationOperator,
|
||||
DivisionOperator, ModOperator, NotEqualOperator, EqualOperator,
|
||||
LessOperator, GreaterOperator, LessEqualOperator, GreaterEqualOperator,
|
||||
UnaryPlusOperator, UnaryMinusOperator, Identifier, Literal, PropertyLookup,
|
||||
Aggregation, Create, Match, Return, With, Pattern, NodeAtom, EdgeAtom,
|
||||
Delete, Where, SetProperty, SetProperties, SetLabels, RemoveProperty,
|
||||
RemoveLabels>;
|
||||
UnaryPlusOperator, UnaryMinusOperator, IsNullOperator, Identifier, Literal,
|
||||
PropertyLookup, Aggregation, Create, Match, Return, With, Pattern, NodeAtom,
|
||||
EdgeAtom, Delete, Where, SetProperty, SetProperties, SetLabels,
|
||||
RemoveProperty, RemoveLabels>;
|
||||
}
|
||||
|
@ -496,7 +496,21 @@ antlrcpp::Any CypherMainVisitor::visitExpression3(
|
||||
// that child is expression2. Other operations are not implemented at the
|
||||
// moment.
|
||||
// TODO: implement this.
|
||||
if (ctx->children.size() > 1u) {
|
||||
// This is a hack. Unfortunately, grammar for expression3 contains a lot of
|
||||
// different expressions. We should break that production in parts so that
|
||||
// we can easily implement its visitor.
|
||||
Expression *expression = ctx->expression2()[0]->accept(this);
|
||||
if (ctx->children.size() - ctx->SP().size() == 3U && ctx->IS().size() == 1U &&
|
||||
ctx->CYPHERNULL().size() == 1U) {
|
||||
return static_cast<Expression *>(
|
||||
storage_.Create<IsNullOperator>(expression));
|
||||
}
|
||||
if (ctx->children.size() - ctx->SP().size() == 4U && ctx->IS().size() == 1U &&
|
||||
ctx->NOT().size() == 1U && ctx->CYPHERNULL().size() == 1U) {
|
||||
return static_cast<Expression *>(storage_.Create<NotOperator>(
|
||||
storage_.Create<IsNullOperator>(expression)));
|
||||
}
|
||||
if (ctx->children.size() > 1U) {
|
||||
throw NotYetImplemented();
|
||||
}
|
||||
return static_cast<Expression *>(visitChildren(ctx));
|
||||
|
@ -105,6 +105,12 @@ class ExpressionEvaluator : public TreeVisitorBase {
|
||||
UNARY_OPERATOR_VISITOR(UnaryPlusOperator, +);
|
||||
UNARY_OPERATOR_VISITOR(UnaryMinusOperator, -);
|
||||
|
||||
void PostVisit(IsNullOperator &) override {
|
||||
auto expression = PopBack();
|
||||
result_stack_.push_back(
|
||||
TypedValue(expression.type() == TypedValue::Type::Null));
|
||||
}
|
||||
|
||||
#undef BINARY_OPERATOR_VISITOR
|
||||
#undef UNARY_OPERATOR_VISITOR
|
||||
|
||||
|
@ -277,6 +277,30 @@ TEST(CypherMainVisitorTest, ComparisonOperators) {
|
||||
|
||||
#undef CHECK_COMPARISON
|
||||
|
||||
TEST(CypherMainVisitorTest, IsNull) {
|
||||
AstGenerator ast_generator("RETURN 2 iS NulL");
|
||||
auto *query = ast_generator.query_;
|
||||
auto *return_clause = dynamic_cast<Return *>(query->clauses_[0]);
|
||||
auto *is_type_operator = dynamic_cast<IsNullOperator *>(
|
||||
return_clause->named_expressions_[0]->expression_);
|
||||
auto *operand1 = dynamic_cast<Literal *>(is_type_operator->expression_);
|
||||
ASSERT_TRUE(operand1);
|
||||
ASSERT_EQ(operand1->value_.Value<int64_t>(), 2);
|
||||
}
|
||||
|
||||
TEST(CypherMainVisitorTest, IsNotNull) {
|
||||
AstGenerator ast_generator("RETURN 2 iS nOT NulL");
|
||||
auto *query = ast_generator.query_;
|
||||
auto *return_clause = dynamic_cast<Return *>(query->clauses_[0]);
|
||||
auto *not_operator = dynamic_cast<NotOperator *>(
|
||||
return_clause->named_expressions_[0]->expression_);
|
||||
auto *is_type_operator =
|
||||
dynamic_cast<IsNullOperator *>(not_operator->expression_);
|
||||
auto *operand1 = dynamic_cast<Literal *>(is_type_operator->expression_);
|
||||
ASSERT_TRUE(operand1);
|
||||
ASSERT_EQ(operand1->value_.Value<int64_t>(), 2);
|
||||
}
|
||||
|
||||
TEST(CypherMainVisitorTest, NotOperator) {
|
||||
AstGenerator ast_generator("RETURN not true");
|
||||
auto *query = ast_generator.query_;
|
||||
|
@ -232,3 +232,15 @@ TEST(ExpressionEvaluator, UnaryMinusOperator) {
|
||||
op->Accept(eval.eval);
|
||||
ASSERT_EQ(eval.eval.PopBack().Value<int64_t>(), -5);
|
||||
}
|
||||
|
||||
TEST(ExpressionEvaluator, IsNullOperator) {
|
||||
AstTreeStorage storage;
|
||||
NoContextExpressionEvaluator eval;
|
||||
auto *op = storage.Create<IsNullOperator>(storage.Create<Literal>(1));
|
||||
op->Accept(eval.eval);
|
||||
ASSERT_EQ(eval.eval.PopBack().Value<bool>(), false);
|
||||
op =
|
||||
storage.Create<IsNullOperator>(storage.Create<Literal>(TypedValue::Null));
|
||||
op->Accept(eval.eval);
|
||||
ASSERT_EQ(eval.eval.PopBack().Value<bool>(), true);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user