Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/iceberg/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@ set(ICEBERG_INCLUDES "$<BUILD_INTERFACE:${PROJECT_BINARY_DIR}/src>"
set(ICEBERG_SOURCES
catalog/in_memory_catalog.cc
expression/expression.cc
expression/expressions.cc
expression/literal.cc
expression/predicate.cc
expression/term.cc
file_reader.cc
file_writer.cc
inheritable_metadata.cc
Expand Down
124 changes: 114 additions & 10 deletions src/iceberg/expression/expression.cc
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@
#include "iceberg/expression/expression.h"

#include <format>
#include <utility>

#include "iceberg/util/formatter_internal.h"
#include "iceberg/util/macros.h"

namespace iceberg {

Expand All @@ -29,15 +33,15 @@ const std::shared_ptr<True>& True::Instance() {
return instance;
}

std::shared_ptr<Expression> True::Negate() const { return False::Instance(); }
Result<std::shared_ptr<Expression>> True::Negate() const { return False::Instance(); }

// False implementation
const std::shared_ptr<False>& False::Instance() {
static const std::shared_ptr<False> instance = std::shared_ptr<False>(new False());
return instance;
}

std::shared_ptr<Expression> False::Negate() const { return True::Instance(); }
Result<std::shared_ptr<Expression>> False::Negate() const { return True::Instance(); }

// And implementation
And::And(std::shared_ptr<Expression> left, std::shared_ptr<Expression> right)
Expand All @@ -47,11 +51,11 @@ std::string And::ToString() const {
return std::format("({} and {})", left_->ToString(), right_->ToString());
}

std::shared_ptr<Expression> And::Negate() const {
Result<std::shared_ptr<Expression>> And::Negate() const {
// De Morgan's law: not(A and B) = (not A) or (not B)
auto left_negated = left_->Negate();
auto right_negated = right_->Negate();
return std::make_shared<Or>(left_negated, right_negated);
ICEBERG_ASSIGN_OR_RAISE(auto left_negated, left_->Negate());
ICEBERG_ASSIGN_OR_RAISE(auto right_negated, right_->Negate());
return std::make_shared<Or>(std::move(left_negated), std::move(right_negated));
}

bool And::Equals(const Expression& expr) const {
Expand All @@ -71,11 +75,11 @@ std::string Or::ToString() const {
return std::format("({} or {})", left_->ToString(), right_->ToString());
}

std::shared_ptr<Expression> Or::Negate() const {
Result<std::shared_ptr<Expression>> Or::Negate() const {
// De Morgan's law: not(A or B) = (not A) and (not B)
auto left_negated = left_->Negate();
auto right_negated = right_->Negate();
return std::make_shared<And>(left_negated, right_negated);
ICEBERG_ASSIGN_OR_RAISE(auto left_negated, left_->Negate());
ICEBERG_ASSIGN_OR_RAISE(auto right_negated, right_->Negate());
return std::make_shared<And>(std::move(left_negated), std::move(right_negated));
}

bool Or::Equals(const Expression& expr) const {
Expand All @@ -87,4 +91,104 @@ bool Or::Equals(const Expression& expr) const {
return false;
}

std::string_view ToString(Expression::Operation op) {
switch (op) {
case Expression::Operation::kAnd:
return "AND";
case Expression::Operation::kOr:
return "OR";
case Expression::Operation::kTrue:
return "TRUE";
case Expression::Operation::kFalse:
return "FALSE";
case Expression::Operation::kIsNull:
return "IS_NULL";
case Expression::Operation::kNotNull:
return "NOT_NULL";
case Expression::Operation::kIsNan:
return "IS_NAN";
case Expression::Operation::kNotNan:
return "NOT_NAN";
case Expression::Operation::kLt:
return "LT";
case Expression::Operation::kLtEq:
return "LT_EQ";
case Expression::Operation::kGt:
return "GT";
case Expression::Operation::kGtEq:
return "GT_EQ";
case Expression::Operation::kEq:
return "EQ";
case Expression::Operation::kNotEq:
return "NOT_EQ";
case Expression::Operation::kIn:
return "IN";
case Expression::Operation::kNotIn:
return "NOT_IN";
case Expression::Operation::kStartsWith:
return "STARTS_WITH";
case Expression::Operation::kNotStartsWith:
return "NOT_STARTS_WITH";
case Expression::Operation::kCount:
return "COUNT";
case Expression::Operation::kNot:
return "NOT";
case Expression::Operation::kCountStar:
return "COUNT_STAR";
case Expression::Operation::kMax:
return "MAX";
case Expression::Operation::kMin:
return "MIN";
}
std::unreachable();
}

Result<Expression::Operation> Negate(Expression::Operation op) {
switch (op) {
case Expression::Operation::kIsNull:
return Expression::Operation::kNotNull;
case Expression::Operation::kNotNull:
return Expression::Operation::kIsNull;
case Expression::Operation::kIsNan:
return Expression::Operation::kNotNan;
case Expression::Operation::kNotNan:
return Expression::Operation::kIsNan;
case Expression::Operation::kLt:
return Expression::Operation::kGtEq;
case Expression::Operation::kLtEq:
return Expression::Operation::kGt;
case Expression::Operation::kGt:
return Expression::Operation::kLtEq;
case Expression::Operation::kGtEq:
return Expression::Operation::kLt;
case Expression::Operation::kEq:
return Expression::Operation::kNotEq;
case Expression::Operation::kNotEq:
return Expression::Operation::kEq;
case Expression::Operation::kIn:
return Expression::Operation::kNotIn;
case Expression::Operation::kNotIn:
return Expression::Operation::kIn;
case Expression::Operation::kStartsWith:
return Expression::Operation::kNotStartsWith;
case Expression::Operation::kNotStartsWith:
return Expression::Operation::kStartsWith;
case Expression::Operation::kTrue:
return Expression::Operation::kFalse;
case Expression::Operation::kFalse:
return Expression::Operation::kTrue;
case Expression::Operation::kAnd:
return Expression::Operation::kOr;
case Expression::Operation::kOr:
return Expression::Operation::kAnd;
case Expression::Operation::kNot:
case Expression::Operation::kCountStar:
case Expression::Operation::kMax:
case Expression::Operation::kMin:
case Expression::Operation::kCount:
return InvalidArgument("No negation for operation: {}", op);
}
std::unreachable();
}

} // namespace iceberg
25 changes: 16 additions & 9 deletions src/iceberg/expression/expression.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,14 @@
#include <memory>
#include <string>

#include "iceberg/exception.h"
#include "iceberg/iceberg_export.h"
#include "iceberg/result.h"
#include "iceberg/util/formattable.h"

namespace iceberg {

/// \brief Represents a boolean expression tree.
class ICEBERG_EXPORT Expression {
class ICEBERG_EXPORT Expression : public util::Formattable {
public:
/// Operation types for expressions
enum class Operation {
Expand Down Expand Up @@ -66,8 +67,8 @@ class ICEBERG_EXPORT Expression {
virtual Operation op() const = 0;

/// \brief Returns the negation of this expression, equivalent to not(this).
virtual std::shared_ptr<Expression> Negate() const {
throw IcebergError("Expression cannot be negated");
virtual Result<std::shared_ptr<Expression>> Negate() const {
return NotSupported("Expression cannot be negated");
}

/// \brief Returns whether this expression will accept the same values as another.
Expand All @@ -78,7 +79,7 @@ class ICEBERG_EXPORT Expression {
return false;
}

virtual std::string ToString() const { return "Expression"; }
std::string ToString() const override { return "Expression"; }
};

/// \brief An Expression that is always true.
Expand All @@ -93,7 +94,7 @@ class ICEBERG_EXPORT True : public Expression {

std::string ToString() const override { return "true"; }

std::shared_ptr<Expression> Negate() const override;
Result<std::shared_ptr<Expression>> Negate() const override;

bool Equals(const Expression& other) const override {
return other.op() == Operation::kTrue;
Expand All @@ -113,7 +114,7 @@ class ICEBERG_EXPORT False : public Expression {

std::string ToString() const override { return "false"; }

std::shared_ptr<Expression> Negate() const override;
Result<std::shared_ptr<Expression>> Negate() const override;

bool Equals(const Expression& other) const override {
return other.op() == Operation::kFalse;
Expand Down Expand Up @@ -149,7 +150,7 @@ class ICEBERG_EXPORT And : public Expression {

std::string ToString() const override;

std::shared_ptr<Expression> Negate() const override;
Result<std::shared_ptr<Expression>> Negate() const override;

bool Equals(const Expression& other) const override;

Expand Down Expand Up @@ -184,7 +185,7 @@ class ICEBERG_EXPORT Or : public Expression {

std::string ToString() const override;

std::shared_ptr<Expression> Negate() const override;
Result<std::shared_ptr<Expression>> Negate() const override;

bool Equals(const Expression& other) const override;

Expand All @@ -193,4 +194,10 @@ class ICEBERG_EXPORT Or : public Expression {
std::shared_ptr<Expression> right_;
};

/// \brief Returns a string representation of an expression operation.
ICEBERG_EXPORT std::string_view ToString(Expression::Operation op);

/// \brief Returns the negated operation.
ICEBERG_EXPORT Result<Expression::Operation> Negate(Expression::Operation op);

} // namespace iceberg
Loading
Loading