Skip to content
Closed
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
43 changes: 43 additions & 0 deletions src/iceberg/type.cc
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,16 @@

namespace iceberg {

namespace {
bool StringEqualsCaseInsensitive(std::string_view lhs, std::string_view rhs) {
if (lhs.size() != rhs.size()) {
return false;
}
return std::equal(lhs.begin(), lhs.end(), rhs.begin(),
[](char a, char b) { return std::tolower(a) == std::tolower(b); });
}
Comment on lines +32 to +38
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the bad thing is that this could only uses ascii, I suggest import icu or utf8 libs ( or even boost::locale?) for this scenerio

} // namespace

StructType::StructType(std::vector<SchemaField> fields) : fields_(std::move(fields)) {
size_t index = 0;
for (const auto& field : fields_) {
Expand Down Expand Up @@ -59,13 +69,15 @@ std::optional<std::reference_wrapper<const SchemaField>> StructType::GetFieldByI
if (it == field_id_to_index_.end()) return std::nullopt;
return fields_[it->second];
}

std::optional<std::reference_wrapper<const SchemaField>> StructType::GetFieldByIndex(
int32_t index) const {
if (index < 0 || index >= static_cast<int32_t>(fields_.size())) {
return std::nullopt;
}
return fields_[index];
}

std::optional<std::reference_wrapper<const SchemaField>> StructType::GetFieldByName(
std::string_view name) const {
// N.B. duplicate names are not permitted (looking at the Java
Expand All @@ -77,6 +89,17 @@ std::optional<std::reference_wrapper<const SchemaField>> StructType::GetFieldByN
}
return std::nullopt;
}

std::optional<std::reference_wrapper<const SchemaField>>
StructType::GetFieldByNameCaseInsensitive(std::string_view name) const {
for (const auto& field : fields_) {
if (StringEqualsCaseInsensitive(field.name(), name)) {
return std::cref(field);
}
}
return std::nullopt;
}

bool StructType::Equals(const Type& other) const {
if (other.type_id() != TypeId::kStruct) {
return false;
Expand Down Expand Up @@ -126,6 +149,15 @@ std::optional<std::reference_wrapper<const SchemaField>> ListType::GetFieldByNam
}
return std::nullopt;
}

std::optional<std::reference_wrapper<const SchemaField>>
ListType::GetFieldByNameCaseInsensitive(std::string_view name) const {
if (StringEqualsCaseInsensitive(element_.name(), name)) {
return std::cref(element_);
}
return std::nullopt;
}

bool ListType::Equals(const Type& other) const {
if (other.type_id() != TypeId::kList) {
return false;
Expand Down Expand Up @@ -186,6 +218,17 @@ std::optional<std::reference_wrapper<const SchemaField>> MapType::GetFieldByName
}
return std::nullopt;
}

std::optional<std::reference_wrapper<const SchemaField>>
MapType::GetFieldByNameCaseInsensitive(std::string_view name) const {
if (StringEqualsCaseInsensitive(kKeyName, name)) {
return key();
} else if (StringEqualsCaseInsensitive(kValueName, name)) {
return value();
}
return std::nullopt;
}

bool MapType::Equals(const Type& other) const {
if (other.type_id() != TypeId::kMap) {
return false;
Expand Down
9 changes: 9 additions & 0 deletions src/iceberg/type.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,9 @@ class ICEBERG_EXPORT NestedType : public Type {
/// \note This is currently O(n) complexity.
[[nodiscard]] virtual std::optional<std::reference_wrapper<const SchemaField>>
GetFieldByName(std::string_view name) const = 0;

[[nodiscard]] virtual std::optional<std::reference_wrapper<const SchemaField>>
GetFieldByNameCaseInsensitive(std::string_view name) const = 0;
};

/// \defgroup type-nested Nested Types
Expand All @@ -115,6 +118,8 @@ class ICEBERG_EXPORT StructType : public NestedType {
int32_t index) const override;
std::optional<std::reference_wrapper<const SchemaField>> GetFieldByName(
std::string_view name) const override;
std::optional<std::reference_wrapper<const SchemaField>> GetFieldByNameCaseInsensitive(
std::string_view name) const override;

protected:
bool Equals(const Type& other) const override;
Expand Down Expand Up @@ -146,6 +151,8 @@ class ICEBERG_EXPORT ListType : public NestedType {
int32_t index) const override;
std::optional<std::reference_wrapper<const SchemaField>> GetFieldByName(
std::string_view name) const override;
std::optional<std::reference_wrapper<const SchemaField>> GetFieldByNameCaseInsensitive(
std::string_view name) const override;

protected:
bool Equals(const Type& other) const override;
Expand Down Expand Up @@ -178,6 +185,8 @@ class ICEBERG_EXPORT MapType : public NestedType {
int32_t index) const override;
std::optional<std::reference_wrapper<const SchemaField>> GetFieldByName(
std::string_view name) const override;
std::optional<std::reference_wrapper<const SchemaField>> GetFieldByNameCaseInsensitive(
std::string_view name) const override;

protected:
bool Equals(const Type& other) const override;
Expand Down
14 changes: 14 additions & 0 deletions test/type_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -318,11 +318,17 @@ TEST(TypeTest, List) {
ASSERT_THAT(list.GetFieldById(5), ::testing::Optional(field));
ASSERT_THAT(list.GetFieldByIndex(0), ::testing::Optional(field));
ASSERT_THAT(list.GetFieldByName("element"), ::testing::Optional(field));
ASSERT_THAT(list.GetFieldByNameCaseInsensitive("element"),
::testing::Optional(field));
ASSERT_THAT(list.GetFieldByNameCaseInsensitive("ELEMENT"),
::testing::Optional(field));

ASSERT_EQ(std::nullopt, list.GetFieldById(0));
ASSERT_EQ(std::nullopt, list.GetFieldByIndex(1));
ASSERT_EQ(std::nullopt, list.GetFieldByIndex(-1));
ASSERT_EQ(std::nullopt, list.GetFieldByName("foo"));
ASSERT_EQ(std::nullopt, list.GetFieldByNameCaseInsensitive("foo"));
ASSERT_EQ(std::nullopt, list.GetFieldByNameCaseInsensitive("FOO"));
}
ASSERT_THAT(
[]() {
Expand All @@ -347,12 +353,15 @@ TEST(TypeTest, Map) {
ASSERT_THAT(map.GetFieldByIndex(0), ::testing::Optional(key));
ASSERT_THAT(map.GetFieldByIndex(1), ::testing::Optional(value));
ASSERT_THAT(map.GetFieldByName("key"), ::testing::Optional(key));
ASSERT_THAT(map.GetFieldByNameCaseInsensitive("kEY"), ::testing::Optional(key));
ASSERT_THAT(map.GetFieldByName("value"), ::testing::Optional(value));
ASSERT_THAT(map.GetFieldByName("vALUE"), ::testing::Optional(value));

ASSERT_EQ(std::nullopt, map.GetFieldById(0));
ASSERT_EQ(std::nullopt, map.GetFieldByIndex(2));
ASSERT_EQ(std::nullopt, map.GetFieldByIndex(-1));
ASSERT_EQ(std::nullopt, map.GetFieldByName("element"));
ASSERT_EQ(std::nullopt, map.GetFieldByName("elemENt"));
}
ASSERT_THAT(
[]() {
Expand Down Expand Up @@ -386,12 +395,17 @@ TEST(TypeTest, Struct) {
ASSERT_THAT(struct_.GetFieldByIndex(0), ::testing::Optional(field1));
ASSERT_THAT(struct_.GetFieldByIndex(1), ::testing::Optional(field2));
ASSERT_THAT(struct_.GetFieldByName("foo"), ::testing::Optional(field1));
ASSERT_THAT(struct_.GetFieldByName("FOO"), ::testing::Optional(field1));
ASSERT_THAT(struct_.GetFieldByName("bar"), ::testing::Optional(field2));
ASSERT_THAT(struct_.GetFieldByNameCaseInsensitive("bar"),
::testing::Optional(field2));

ASSERT_EQ(std::nullopt, struct_.GetFieldById(0));
ASSERT_EQ(std::nullopt, struct_.GetFieldByIndex(2));
ASSERT_EQ(std::nullopt, struct_.GetFieldByIndex(-1));
ASSERT_EQ(std::nullopt, struct_.GetFieldByName("element"));
ASSERT_EQ(std::nullopt, struct_.GetFieldByNameCaseInsensitive("element"));
ASSERT_EQ(std::nullopt, struct_.GetFieldByNameCaseInsensitive("ELEMENT"));
}
ASSERT_THAT(
[]() {
Expand Down
Loading