Skip to content

Commit e977898

Browse files
committed
refactor: use factory pattern and throw exception for expression
1 parent 5cbf3df commit e977898

File tree

9 files changed

+298
-71
lines changed

9 files changed

+298
-71
lines changed

src/iceberg/exception.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,12 @@ class ICEBERG_EXPORT IcebergError : public std::runtime_error {
3838
explicit IcebergError(const std::string& what) : std::runtime_error(what) {}
3939
};
4040

41+
/// \brief Exception thrown when expression construction fails.
42+
class ICEBERG_EXPORT ExpressionError : public IcebergError {
43+
public:
44+
explicit ExpressionError(const std::string& what) : IcebergError(what) {}
45+
};
46+
4147
#define ICEBERG_CHECK(condition, ...) \
4248
do { \
4349
if (!(condition)) [[unlikely]] { \

src/iceberg/expression/expression.cc

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,22 @@ const std::shared_ptr<False>& False::Instance() {
4545
Result<std::shared_ptr<Expression>> False::Negate() const { return True::Instance(); }
4646

4747
// And implementation
48+
Result<std::unique_ptr<And>> And::Make(std::shared_ptr<Expression> left,
49+
std::shared_ptr<Expression> right) {
50+
if (!left) {
51+
return InvalidArgument("And expression left operand cannot be null");
52+
}
53+
if (!right) {
54+
return InvalidArgument("And expression right operand cannot be null");
55+
}
56+
return std::unique_ptr<And>(new And(std::move(left), std::move(right)));
57+
}
58+
4859
And::And(std::shared_ptr<Expression> left, std::shared_ptr<Expression> right)
49-
: left_(std::move(left)), right_(std::move(right)) {}
60+
: left_(std::move(left)), right_(std::move(right)) {
61+
ICEBERG_DCHECK(left_ != nullptr, "And left operand cannot be null");
62+
ICEBERG_DCHECK(right_ != nullptr, "And right operand cannot be null");
63+
}
5064

5165
std::string And::ToString() const {
5266
return std::format("({} and {})", left_->ToString(), right_->ToString());
@@ -56,7 +70,9 @@ Result<std::shared_ptr<Expression>> And::Negate() const {
5670
// De Morgan's law: not(A and B) = (not A) or (not B)
5771
ICEBERG_ASSIGN_OR_RAISE(auto left_negated, left_->Negate());
5872
ICEBERG_ASSIGN_OR_RAISE(auto right_negated, right_->Negate());
59-
return std::make_shared<Or>(std::move(left_negated), std::move(right_negated));
73+
ICEBERG_ASSIGN_OR_RAISE(auto or_expr,
74+
Or::Make(std::move(left_negated), std::move(right_negated)));
75+
return std::shared_ptr<Expression>(std::move(or_expr));
6076
}
6177

6278
bool And::Equals(const Expression& expr) const {
@@ -69,8 +85,22 @@ bool And::Equals(const Expression& expr) const {
6985
}
7086

7187
// Or implementation
88+
Result<std::unique_ptr<Or>> Or::Make(std::shared_ptr<Expression> left,
89+
std::shared_ptr<Expression> right) {
90+
if (!left) {
91+
return InvalidArgument("Or expression left operand cannot be null");
92+
}
93+
if (!right) {
94+
return InvalidArgument("Or expression right operand cannot be null");
95+
}
96+
return std::unique_ptr<Or>(new Or(std::move(left), std::move(right)));
97+
}
98+
7299
Or::Or(std::shared_ptr<Expression> left, std::shared_ptr<Expression> right)
73-
: left_(std::move(left)), right_(std::move(right)) {}
100+
: left_(std::move(left)), right_(std::move(right)) {
101+
ICEBERG_DCHECK(left_ != nullptr, "Or left operand cannot be null");
102+
ICEBERG_DCHECK(right_ != nullptr, "Or right operand cannot be null");
103+
}
74104

75105
std::string Or::ToString() const {
76106
return std::format("({} or {})", left_->ToString(), right_->ToString());
@@ -80,7 +110,9 @@ Result<std::shared_ptr<Expression>> Or::Negate() const {
80110
// De Morgan's law: not(A or B) = (not A) and (not B)
81111
ICEBERG_ASSIGN_OR_RAISE(auto left_negated, left_->Negate());
82112
ICEBERG_ASSIGN_OR_RAISE(auto right_negated, right_->Negate());
83-
return std::make_shared<And>(std::move(left_negated), std::move(right_negated));
113+
ICEBERG_ASSIGN_OR_RAISE(auto and_expr,
114+
And::Make(std::move(left_negated), std::move(right_negated)));
115+
return std::shared_ptr<Expression>(std::move(and_expr));
84116
}
85117

86118
bool Or::Equals(const Expression& expr) const {
@@ -93,7 +125,16 @@ bool Or::Equals(const Expression& expr) const {
93125
}
94126

95127
// Not implementation
96-
Not::Not(std::shared_ptr<Expression> child) : child_(std::move(child)) {}
128+
Result<std::unique_ptr<Not>> Not::Make(std::shared_ptr<Expression> child) {
129+
if (!child) {
130+
return InvalidArgument("Not expression child cannot be null");
131+
}
132+
return std::unique_ptr<Not>(new Not(std::move(child)));
133+
}
134+
135+
Not::Not(std::shared_ptr<Expression> child) : child_(std::move(child)) {
136+
ICEBERG_DCHECK(child_ != nullptr, "Not child expression cannot be null");
137+
}
97138

98139
std::string Not::ToString() const { return std::format("not({})", child_->ToString()); }
99140

src/iceberg/expression/expression.h

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -130,11 +130,14 @@ class ICEBERG_EXPORT False : public Expression {
130130
/// evaluate to true.
131131
class ICEBERG_EXPORT And : public Expression {
132132
public:
133-
/// \brief Constructs an And expression from two sub-expressions.
133+
/// \brief Creates an And expression from two sub-expressions.
134134
///
135135
/// \param left The left operand of the AND expression
136136
/// \param right The right operand of the AND expression
137-
And(std::shared_ptr<Expression> left, std::shared_ptr<Expression> right);
137+
/// \return A Result containing a unique pointer to And, or an error if either parameter
138+
/// is nullptr
139+
static Result<std::unique_ptr<And>> Make(std::shared_ptr<Expression> left,
140+
std::shared_ptr<Expression> right);
138141

139142
/// \brief Returns the left operand of the AND expression.
140143
///
@@ -155,6 +158,8 @@ class ICEBERG_EXPORT And : public Expression {
155158
bool Equals(const Expression& other) const override;
156159

157160
private:
161+
And(std::shared_ptr<Expression> left, std::shared_ptr<Expression> right);
162+
158163
std::shared_ptr<Expression> left_;
159164
std::shared_ptr<Expression> right_;
160165
};
@@ -165,11 +170,14 @@ class ICEBERG_EXPORT And : public Expression {
165170
/// evaluates to true.
166171
class ICEBERG_EXPORT Or : public Expression {
167172
public:
168-
/// \brief Constructs an Or expression from two sub-expressions.
173+
/// \brief Creates an Or expression from two sub-expressions.
169174
///
170175
/// \param left The left operand of the OR expression
171176
/// \param right The right operand of the OR expression
172-
Or(std::shared_ptr<Expression> left, std::shared_ptr<Expression> right);
177+
/// \return A Result containing a unique pointer to Or, or an error if either parameter
178+
/// is nullptr
179+
static Result<std::unique_ptr<Or>> Make(std::shared_ptr<Expression> left,
180+
std::shared_ptr<Expression> right);
173181

174182
/// \brief Returns the left operand of the OR expression.
175183
///
@@ -190,6 +198,8 @@ class ICEBERG_EXPORT Or : public Expression {
190198
bool Equals(const Expression& other) const override;
191199

192200
private:
201+
Or(std::shared_ptr<Expression> left, std::shared_ptr<Expression> right);
202+
193203
std::shared_ptr<Expression> left_;
194204
std::shared_ptr<Expression> right_;
195205
};
@@ -199,10 +209,11 @@ class ICEBERG_EXPORT Or : public Expression {
199209
/// This expression negates its child expression.
200210
class ICEBERG_EXPORT Not : public Expression {
201211
public:
202-
/// \brief Constructs a Not expression from a child expression.
212+
/// \brief Creates a Not expression from a child expression.
203213
///
204214
/// \param child The expression to negate
205-
explicit Not(std::shared_ptr<Expression> child);
215+
/// \return A Result containing a unique pointer to Not, or an error if child is nullptr
216+
static Result<std::unique_ptr<Not>> Make(std::shared_ptr<Expression> child);
206217

207218
/// \brief Returns the child expression.
208219
///
@@ -218,6 +229,8 @@ class ICEBERG_EXPORT Not : public Expression {
218229
bool Equals(const Expression& other) const override;
219230

220231
private:
232+
explicit Not(std::shared_ptr<Expression> child);
233+
221234
std::shared_ptr<Expression> child_;
222235
};
223236

src/iceberg/expression/expressions.cc

Lines changed: 47 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -41,41 +41,72 @@ std::shared_ptr<Expression> Expressions::Not(std::shared_ptr<Expression> child)
4141
return not_expr.child();
4242
}
4343

44-
return std::make_shared<::iceberg::Not>(std::move(child));
44+
auto result = ::iceberg::Not::Make(std::move(child));
45+
if (!result) {
46+
throw ExpressionError(result.error().message);
47+
}
48+
return {std::move(result.value())};
4549
}
4650

4751
// Transform functions
4852

4953
std::shared_ptr<UnboundTransform> Expressions::Bucket(std::string name,
5054
int32_t num_buckets) {
51-
return std::make_shared<UnboundTransform>(Ref(std::move(name)),
52-
Transform::Bucket(num_buckets));
55+
auto result =
56+
UnboundTransform::Make(Ref(std::move(name)), Transform::Bucket(num_buckets));
57+
if (!result) {
58+
throw ExpressionError(result.error().message);
59+
}
60+
return {std::move(result.value())};
5361
}
5462

5563
std::shared_ptr<UnboundTransform> Expressions::Year(std::string name) {
56-
return std::make_shared<UnboundTransform>(Ref(std::move(name)), Transform::Year());
64+
auto result = UnboundTransform::Make(Ref(std::move(name)), Transform::Year());
65+
if (!result) {
66+
throw ExpressionError(result.error().message);
67+
}
68+
return {std::move(result.value())};
5769
}
5870

5971
std::shared_ptr<UnboundTransform> Expressions::Month(std::string name) {
60-
return std::make_shared<UnboundTransform>(Ref(std::move(name)), Transform::Month());
72+
auto result = UnboundTransform::Make(Ref(std::move(name)), Transform::Month());
73+
if (!result) {
74+
throw ExpressionError(result.error().message);
75+
}
76+
return {std::move(result.value())};
6177
}
6278

6379
std::shared_ptr<UnboundTransform> Expressions::Day(std::string name) {
64-
return std::make_shared<UnboundTransform>(Ref(std::move(name)), Transform::Day());
80+
auto result = UnboundTransform::Make(Ref(std::move(name)), Transform::Day());
81+
if (!result) {
82+
throw ExpressionError(result.error().message);
83+
}
84+
return {std::move(result.value())};
6585
}
6686

6787
std::shared_ptr<UnboundTransform> Expressions::Hour(std::string name) {
68-
return std::make_shared<UnboundTransform>(Ref(std::move(name)), Transform::Hour());
88+
auto result = UnboundTransform::Make(Ref(std::move(name)), Transform::Hour());
89+
if (!result) {
90+
throw ExpressionError(result.error().message);
91+
}
92+
return {std::move(result.value())};
6993
}
7094

7195
std::shared_ptr<UnboundTransform> Expressions::Truncate(std::string name, int32_t width) {
72-
return std::make_shared<UnboundTransform>(Ref(std::move(name)),
73-
Transform::Truncate(width));
96+
auto result = UnboundTransform::Make(Ref(std::move(name)), Transform::Truncate(width));
97+
if (!result) {
98+
throw ExpressionError(result.error().message);
99+
}
100+
return {std::move(result.value())};
74101
}
75102

76103
std::shared_ptr<UnboundTransform> Expressions::Transform(
77104
std::string name, std::shared_ptr<::iceberg::Transform> transform) {
78-
return std::make_shared<UnboundTransform>(Ref(std::move(name)), std::move(transform));
105+
auto result = UnboundTransform::Make(Ref(std::move(name)), std::move(transform));
106+
if (!result) {
107+
throw ExpressionError(result.error().message);
108+
}
109+
return {std::move(result.value())};
79110
}
80111

81112
// Template implementations for unary predicates
@@ -327,11 +358,15 @@ std::shared_ptr<False> Expressions::AlwaysFalse() { return False::Instance(); }
327358
// Utilities
328359

329360
std::shared_ptr<NamedReference> Expressions::Ref(std::string name) {
330-
return std::make_shared<NamedReference>(std::move(name));
361+
auto result = NamedReference::Make(std::move(name));
362+
if (!result) {
363+
throw ExpressionError(result.error().message);
364+
}
365+
return {std::move(result.value())};
331366
}
332367

333368
Literal Expressions::Lit(Literal::Value value, std::shared_ptr<PrimitiveType> type) {
334-
throw IcebergError("Literal creation is not implemented");
369+
throw ExpressionError("Literal creation is not implemented");
335370
}
336371

337372
} // namespace iceberg

src/iceberg/expression/expressions.h

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,17 @@
2727
#include <string>
2828
#include <vector>
2929

30+
#include "iceberg/exception.h"
3031
#include "iceberg/expression/literal.h"
3132
#include "iceberg/expression/predicate.h"
3233
#include "iceberg/expression/term.h"
3334
#include "iceberg/iceberg_export.h"
3435

3536
namespace iceberg {
3637

37-
/// \brief Factory methods for creating expressions.
38+
/// \brief Factory methods for quickly creating expressions. Unlike most APIs in this
39+
/// codebase that return Result<T>, these factory methods throw ExpressionError exceptions
40+
/// on failures to provide a more convenient API for expression construction.
3841
class ICEBERG_EXPORT Expressions {
3942
public:
4043
// Logical operations
@@ -60,7 +63,11 @@ class ICEBERG_EXPORT Expressions {
6063
return left;
6164
}
6265

63-
return std::make_shared<::iceberg::And>(std::move(left), std::move(right));
66+
auto result = ::iceberg::And::Make(std::move(left), std::move(right));
67+
if (!result) {
68+
throw ExpressionError(result.error().message);
69+
}
70+
return {std::move(result.value())};
6471
} else {
6572
return And(And(std::move(left), std::move(right)), std::forward<Args>(args)...);
6673
}
@@ -86,7 +93,11 @@ class ICEBERG_EXPORT Expressions {
8693
return left;
8794
}
8895

89-
return std::make_shared<::iceberg::Or>(std::move(left), std::move(right));
96+
auto result = ::iceberg::Or::Make(std::move(left), std::move(right));
97+
if (!result) {
98+
throw ExpressionError(result.error().message);
99+
}
100+
return {std::move(result.value())};
90101
} else {
91102
return Or(Or(std::move(left), std::move(right)), std::forward<Args>(args)...);
92103
}

0 commit comments

Comments
 (0)