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;
|
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 {
|
class Literal : public Expression {
|
||||||
friend class AstTreeStorage;
|
friend class AstTreeStorage;
|
||||||
|
|
||||||
|
@ -29,6 +29,7 @@ class DivisionOperator;
|
|||||||
class ModOperator;
|
class ModOperator;
|
||||||
class UnaryPlusOperator;
|
class UnaryPlusOperator;
|
||||||
class UnaryMinusOperator;
|
class UnaryMinusOperator;
|
||||||
|
class IsNullOperator;
|
||||||
class NotEqualOperator;
|
class NotEqualOperator;
|
||||||
class EqualOperator;
|
class EqualOperator;
|
||||||
class LessOperator;
|
class LessOperator;
|
||||||
@ -48,8 +49,8 @@ using TreeVisitorBase = ::utils::Visitor<
|
|||||||
AdditionOperator, SubtractionOperator, MultiplicationOperator,
|
AdditionOperator, SubtractionOperator, MultiplicationOperator,
|
||||||
DivisionOperator, ModOperator, NotEqualOperator, EqualOperator,
|
DivisionOperator, ModOperator, NotEqualOperator, EqualOperator,
|
||||||
LessOperator, GreaterOperator, LessEqualOperator, GreaterEqualOperator,
|
LessOperator, GreaterOperator, LessEqualOperator, GreaterEqualOperator,
|
||||||
UnaryPlusOperator, UnaryMinusOperator, Identifier, Literal, PropertyLookup,
|
UnaryPlusOperator, UnaryMinusOperator, IsNullOperator, Identifier, Literal,
|
||||||
Aggregation, Create, Match, Return, With, Pattern, NodeAtom, EdgeAtom,
|
PropertyLookup, Aggregation, Create, Match, Return, With, Pattern, NodeAtom,
|
||||||
Delete, Where, SetProperty, SetProperties, SetLabels, RemoveProperty,
|
EdgeAtom, Delete, Where, SetProperty, SetProperties, SetLabels,
|
||||||
RemoveLabels>;
|
RemoveProperty, RemoveLabels>;
|
||||||
}
|
}
|
||||||
|
@ -496,7 +496,21 @@ antlrcpp::Any CypherMainVisitor::visitExpression3(
|
|||||||
// that child is expression2. Other operations are not implemented at the
|
// that child is expression2. Other operations are not implemented at the
|
||||||
// moment.
|
// moment.
|
||||||
// TODO: implement this.
|
// 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();
|
throw NotYetImplemented();
|
||||||
}
|
}
|
||||||
return static_cast<Expression *>(visitChildren(ctx));
|
return static_cast<Expression *>(visitChildren(ctx));
|
||||||
|
@ -105,6 +105,12 @@ class ExpressionEvaluator : public TreeVisitorBase {
|
|||||||
UNARY_OPERATOR_VISITOR(UnaryPlusOperator, +);
|
UNARY_OPERATOR_VISITOR(UnaryPlusOperator, +);
|
||||||
UNARY_OPERATOR_VISITOR(UnaryMinusOperator, -);
|
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 BINARY_OPERATOR_VISITOR
|
||||||
#undef UNARY_OPERATOR_VISITOR
|
#undef UNARY_OPERATOR_VISITOR
|
||||||
|
|
||||||
|
@ -277,6 +277,30 @@ TEST(CypherMainVisitorTest, ComparisonOperators) {
|
|||||||
|
|
||||||
#undef CHECK_COMPARISON
|
#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) {
|
TEST(CypherMainVisitorTest, NotOperator) {
|
||||||
AstGenerator ast_generator("RETURN not true");
|
AstGenerator ast_generator("RETURN not true");
|
||||||
auto *query = ast_generator.query_;
|
auto *query = ast_generator.query_;
|
||||||
|
@ -232,3 +232,15 @@ TEST(ExpressionEvaluator, UnaryMinusOperator) {
|
|||||||
op->Accept(eval.eval);
|
op->Accept(eval.eval);
|
||||||
ASSERT_EQ(eval.eval.PopBack().Value<int64_t>(), -5);
|
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