Skip to content

Commit 68298ed

Browse files
committed
feat:add init expression interface.
1 parent d54d079 commit 68298ed

File tree

6 files changed

+395
-0
lines changed

6 files changed

+395
-0
lines changed

src/iceberg/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ set(ICEBERG_INCLUDES "$<BUILD_INTERFACE:${PROJECT_BINARY_DIR}/src>"
2020
set(ICEBERG_SOURCES
2121
arrow_c_data_internal.cc
2222
demo.cc
23+
expression.cc
2324
schema.cc
2425
schema_field.cc
2526
schema_internal.cc

src/iceberg/error.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ enum class ErrorKind {
3838
kNotImplemented,
3939
kUnknownError,
4040
kNotSupported,
41+
kInvalidExpression,
42+
kInvalidOperatorType,
4143
};
4244

4345
/// \brief Error with a kind and a message.

src/iceberg/expression.cc

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
#include "iceberg/expression.h"
21+
22+
#include <unordered_map>
23+
24+
namespace iceberg {
25+
26+
expected<Expression::Operation, Error> Expression::FromString(
27+
const std::string& operation_type) {
28+
std::string lowercase_op = operation_type;
29+
std::transform(lowercase_op.begin(), lowercase_op.end(), lowercase_op.begin(),
30+
[](unsigned char c) { return std::tolower(c); });
31+
32+
static const std::unordered_map<std::string, Operation> op_map = {
33+
{"true", Operation::kTrue},
34+
{"false", Operation::kFalse},
35+
{"is_null", Operation::kIsNull},
36+
{"not_null", Operation::kNotNull},
37+
{"is_nan", Operation::kIsNan},
38+
{"not_nan", Operation::kNotNan},
39+
{"lt", Operation::kLt},
40+
{"lt_eq", Operation::kLtEq},
41+
{"gt", Operation::kGt},
42+
{"gt_eq", Operation::kGtEq},
43+
{"eq", Operation::kEq},
44+
{"not_eq", Operation::kNotEq},
45+
{"in", Operation::kIn},
46+
{"not_in", Operation::kNotIn},
47+
{"not", Operation::kNot},
48+
{"and", Operation::kAnd},
49+
{"or", Operation::kOr},
50+
{"starts_with", Operation::kStartsWith},
51+
{"not_starts_with", Operation::kNotStartsWith},
52+
{"count", Operation::kCount},
53+
{"count_star", Operation::kCountStar},
54+
{"max", Operation::kMax},
55+
{"min", Operation::kMin}};
56+
57+
auto it = op_map.find(lowercase_op);
58+
if (it == op_map.end()) {
59+
return unexpected<Error>(
60+
{ErrorKind::kInvalidOperatorType, "Unknown operation type: " + operation_type});
61+
}
62+
return it->second;
63+
}
64+
65+
expected<Expression::Operation, Error> Expression::Negate(Operation op) {
66+
switch (op) {
67+
case Operation::kTrue:
68+
return Operation::kFalse;
69+
case Operation::kFalse:
70+
return Operation::kTrue;
71+
case Operation::kIsNull:
72+
return Operation::kNotNull;
73+
case Operation::kNotNull:
74+
return Operation::kIsNull;
75+
case Operation::kIsNan:
76+
return Operation::kNotNan;
77+
case Operation::kNotNan:
78+
return Operation::kIsNan;
79+
case Operation::kLt:
80+
return Operation::kGtEq;
81+
case Operation::kLtEq:
82+
return Operation::kGt;
83+
case Operation::kGt:
84+
return Operation::kLtEq;
85+
case Operation::kGtEq:
86+
return Operation::kLt;
87+
case Operation::kEq:
88+
return Operation::kNotEq;
89+
case Operation::kNotEq:
90+
return Operation::kEq;
91+
case Operation::kIn:
92+
return Operation::kNotIn;
93+
case Operation::kNotIn:
94+
return Operation::kIn;
95+
case Operation::kStartsWith:
96+
return Operation::kNotStartsWith;
97+
case Operation::kNotStartsWith:
98+
return Operation::kStartsWith;
99+
default:
100+
return unexpected<Error>(
101+
{ErrorKind::kInvalidOperatorType, "No negation defined for operation"});
102+
}
103+
}
104+
105+
expected<Expression::Operation, Error> Expression::FlipLR(Operation op) {
106+
switch (op) {
107+
case Operation::kLt:
108+
return Operation::kGt;
109+
case Operation::kLtEq:
110+
return Operation::kGtEq;
111+
case Operation::kGt:
112+
return Operation::kLt;
113+
case Operation::kGtEq:
114+
return Operation::kLtEq;
115+
case Operation::kEq:
116+
return Operation::kEq;
117+
case Operation::kNotEq:
118+
return Operation::kNotEq;
119+
case Operation::kAnd:
120+
return Operation::kAnd;
121+
case Operation::kOr:
122+
return Operation::kOr;
123+
default:
124+
return unexpected<Error>(
125+
{ErrorKind::kInvalidOperatorType, "No left-right flip for operation"});
126+
}
127+
}
128+
129+
} // namespace iceberg

src/iceberg/expression.h

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
20+
#pragma once
21+
22+
/// \file iceberg/expression.h
23+
/// Boolean expression tree for Iceberg table operations.
24+
25+
#include <string>
26+
27+
#include "iceberg/error.h"
28+
#include "iceberg/expected.h"
29+
#include "iceberg/iceberg_export.h"
30+
31+
namespace iceberg {
32+
33+
/// \brief Represents a boolean expression tree.
34+
class ICEBERG_EXPORT Expression {
35+
public:
36+
/// Operation types for expressions
37+
enum class Operation {
38+
kTrue,
39+
kFalse,
40+
kIsNull,
41+
kNotNull,
42+
kIsNan,
43+
kNotNan,
44+
kLt,
45+
kLtEq,
46+
kGt,
47+
kGtEq,
48+
kEq,
49+
kNotEq,
50+
kIn,
51+
kNotIn,
52+
kNot,
53+
kAnd,
54+
kOr,
55+
kStartsWith,
56+
kNotStartsWith,
57+
kCount,
58+
kCountStar,
59+
kMax,
60+
kMin
61+
};
62+
63+
virtual ~Expression() = default;
64+
65+
/// \brief Returns the operation for an expression node.
66+
[[nodiscard]] virtual Operation Op() const = 0;
67+
68+
/// \brief Returns the negation of this expression, equivalent to not(this).
69+
[[nodiscard]] virtual expected<std::shared_ptr<Expression>, Error> Negate() const {
70+
return unexpected<Error>(
71+
{ErrorKind::kInvalidExpression, "This expression cannot be negated"});
72+
}
73+
74+
/// \brief Returns whether this expression will accept the same values as another.
75+
///
76+
/// If this returns true, the expressions are guaranteed to return the same evaluation
77+
/// for the same input. However, if this returns false the expressions may return the
78+
/// same evaluation for the same input. That is, expressions may be equivalent even if
79+
/// this returns false.
80+
///
81+
/// For best results, rewrite not and bind expressions before calling this method.
82+
///
83+
/// \param other another expression
84+
/// \return true if the expressions are equivalent
85+
[[nodiscard]] virtual bool IsEquivalentTo(const Expression& other) const {
86+
// only bound predicates can be equivalent
87+
return false;
88+
}
89+
90+
/// \brief Convert operation string to enum
91+
static expected<Operation, Error> FromString(const std::string& operation_type);
92+
93+
/// \brief Returns the operation used when this is negated.
94+
static expected<Operation, Error> Negate(Operation op);
95+
96+
/// \brief Returns the equivalent operation when the left and right operands are
97+
/// exchanged.
98+
static expected<Operation, Error> FlipLR(Operation op);
99+
};
100+
101+
} // namespace iceberg

test/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,11 @@ target_sources(expected_test PRIVATE expected_test.cc)
3939
target_link_libraries(expected_test PRIVATE iceberg_static GTest::gtest_main GTest::gmock)
4040
add_test(NAME expected_test COMMAND expected_test)
4141

42+
add_executable(expression_test)
43+
target_sources(expression_test PRIVATE expression_test.cc)
44+
target_link_libraries(expression_test PRIVATE iceberg_static GTest::gtest_main GTest::gmock)
45+
add_test(NAME expression_test COMMAND expression_test)
46+
4247
if(ICEBERG_BUILD_BUNDLE)
4348
add_executable(avro_test)
4449
target_sources(avro_test PRIVATE avro_test.cc)

0 commit comments

Comments
 (0)