2525
2626#include " iceberg/exception.h"
2727#include " iceberg/util/formatter.h" // IWYU pragma: keep
28+ #include " iceberg/util/macros.h"
29+ #include " iceberg/util/string_utils.h"
2830
2931namespace iceberg {
3032
31- StructType::StructType (std::vector<SchemaField> fields) : fields_(std::move(fields)) {
32- size_t index = 0 ;
33- for (const auto & field : fields_) {
34- auto [it, inserted] = field_id_to_index_.try_emplace (field.field_id (), index);
35- if (!inserted) {
36- throw IcebergError (
37- std::format (" StructType: duplicate field ID {} (field indices {} and {})" ,
38- field.field_id (), it->second , index));
39- }
40-
41- ++index;
42- }
33+ Result<std::optional<std::reference_wrapper<const SchemaField>>>
34+ NestedType::GetFieldByName (std::string_view name) const {
35+ return GetFieldByName (name, true );
4336}
4437
38+ StructType::StructType (std::vector<SchemaField> fields) : fields_(std::move(fields)) {}
39+
4540TypeId StructType::type_id () const { return kTypeId ; }
4641
4742std::string StructType::ToString () const {
@@ -53,27 +48,34 @@ std::string StructType::ToString() const {
5348 return repr;
5449}
5550std::span<const SchemaField> StructType::fields () const { return fields_; }
56- std::optional<std::reference_wrapper<const SchemaField>> StructType::GetFieldById (
51+ Result< std::optional<std::reference_wrapper<const SchemaField> >> StructType::GetFieldById (
5752 int32_t field_id) const {
58- auto it = field_id_to_index_.find (field_id);
59- if (it == field_id_to_index_.end ()) return std::nullopt ;
60- return fields_[it->second ];
53+ ICEBERG_RETURN_UNEXPECTED (InitFieldById ());
54+ auto it = field_by_id_.find (field_id);
55+ if (it == field_by_id_.end ()) return std::nullopt ;
56+ return it->second ;
6157}
62- std::optional<std::reference_wrapper<const SchemaField>> StructType::GetFieldByIndex (
63- int32_t index) const {
58+ Result< std::optional<std::reference_wrapper<const SchemaField>>>
59+ StructType::GetFieldByIndex ( int32_t index) const {
6460 if (index < 0 || index >= static_cast <int32_t >(fields_.size ())) {
6561 return std::nullopt ;
6662 }
6763 return fields_[index];
6864}
69- std::optional<std::reference_wrapper<const SchemaField>> StructType::GetFieldByName (
70- std::string_view name) const {
71- // N.B. duplicate names are not permitted (looking at the Java
72- // implementation) so there is nothing in particular we need to do here
73- for ( const auto & field : fields_) {
74- if (field. name () == name ) {
75- return field ;
65+ Result< std::optional<std::reference_wrapper<const SchemaField>>>
66+ StructType::GetFieldByName ( std::string_view name, bool case_sensitive ) const {
67+ if (case_sensitive) {
68+ ICEBERG_RETURN_UNEXPECTED ( InitFieldByName ());
69+ auto it = field_by_name_. find (name);
70+ if (it != field_by_name_. end () ) {
71+ return it-> second ;
7672 }
73+ return std::nullopt ;
74+ }
75+ ICEBERG_RETURN_UNEXPECTED (InitFieldByLowerCaseName ());
76+ auto it = field_by_lowercase_name_.find (StringUtils::ToLower (name));
77+ if (it != field_by_lowercase_name_.end ()) {
78+ return it->second ;
7779 }
7880 return std::nullopt ;
7981}
@@ -84,6 +86,46 @@ bool StructType::Equals(const Type& other) const {
8486 const auto & struct_ = static_cast <const StructType&>(other);
8587 return fields_ == struct_.fields_ ;
8688}
89+ Status StructType::InitFieldById () const {
90+ if (!field_by_id_.empty ()) {
91+ return {};
92+ }
93+ for (const auto & field : fields_) {
94+ auto [it, inserted] = field_by_id_.try_emplace (field.field_id (), field);
95+ if (!inserted) {
96+ return NotAllowed (" Duplicate field id found: {} (prev name: {}, curr name: {})" ,
97+ field.field_id (), it->second .get ().name (), field.name ());
98+ }
99+ }
100+ return {};
101+ }
102+ Status StructType::InitFieldByName () const {
103+ if (!field_by_name_.empty ()) {
104+ return {};
105+ }
106+ for (const auto & field : fields_) {
107+ auto [it, inserted] = field_by_name_.try_emplace (field.name (), field);
108+ if (!inserted) {
109+ return NotAllowed (" Duplicate field name found: {} (prev id: {}, curr id: {})" ,
110+ it->first , it->second .get ().field_id (), field.field_id ());
111+ }
112+ }
113+ return {};
114+ }
115+ Status StructType::InitFieldByLowerCaseName () const {
116+ if (!field_by_lowercase_name_.empty ()) {
117+ return {};
118+ }
119+ for (const auto & field : fields_) {
120+ auto [it, inserted] =
121+ field_by_lowercase_name_.try_emplace (StringUtils::ToLower (field.name ()), field);
122+ if (!inserted) {
123+ return NotAllowed (" Duplicate field name found: {} (prev id: {}, curr id: {})" ,
124+ it->first , it->second .get ().field_id (), field.field_id ());
125+ }
126+ }
127+ return {};
128+ }
87129
88130ListType::ListType (SchemaField element) : element_(std::move(element)) {
89131 if (element_.name () != kElementName ) {
@@ -105,23 +147,29 @@ std::string ListType::ToString() const {
105147 return repr;
106148}
107149std::span<const SchemaField> ListType::fields () const { return {&element_, 1 }; }
108- std::optional<std::reference_wrapper<const SchemaField>> ListType::GetFieldById (
150+ Result< std::optional<std::reference_wrapper<const SchemaField> >> ListType::GetFieldById (
109151 int32_t field_id) const {
110152 if (field_id == element_.field_id ()) {
111153 return std::cref (element_);
112154 }
113155 return std::nullopt ;
114156}
115- std::optional<std::reference_wrapper<const SchemaField>> ListType::GetFieldByIndex (
116- int index) const {
157+ Result< std::optional<std::reference_wrapper<const SchemaField>>>
158+ ListType::GetFieldByIndex ( int index) const {
117159 if (index == 0 ) {
118160 return std::cref (element_);
119161 }
120162 return std::nullopt ;
121163}
122- std::optional<std::reference_wrapper<const SchemaField>> ListType::GetFieldByName (
123- std::string_view name) const {
124- if (name == element_.name ()) {
164+ Result<std::optional<std::reference_wrapper<const SchemaField>>> ListType::GetFieldByName (
165+ std::string_view name, bool case_sensitive) const {
166+ if (case_sensitive) {
167+ if (name == element_.name ()) {
168+ return std::cref (element_);
169+ }
170+ return std::nullopt ;
171+ }
172+ if (StringUtils::ToLower (name) == StringUtils::ToLower (element_.name ())) {
125173 return std::cref (element_);
126174 }
127175 return std::nullopt ;
@@ -159,7 +207,7 @@ std::string MapType::ToString() const {
159207 return repr;
160208}
161209std::span<const SchemaField> MapType::fields () const { return fields_; }
162- std::optional<std::reference_wrapper<const SchemaField>> MapType::GetFieldById (
210+ Result< std::optional<std::reference_wrapper<const SchemaField> >> MapType::GetFieldById (
163211 int32_t field_id) const {
164212 if (field_id == key ().field_id ()) {
165213 return key ();
@@ -168,7 +216,7 @@ std::optional<std::reference_wrapper<const SchemaField>> MapType::GetFieldById(
168216 }
169217 return std::nullopt ;
170218}
171- std::optional<std::reference_wrapper<const SchemaField>> MapType::GetFieldByIndex (
219+ Result< std::optional<std::reference_wrapper<const SchemaField> >> MapType::GetFieldByIndex (
172220 int32_t index) const {
173221 if (index == 0 ) {
174222 return key ();
@@ -177,11 +225,19 @@ std::optional<std::reference_wrapper<const SchemaField>> MapType::GetFieldByInde
177225 }
178226 return std::nullopt ;
179227}
180- std::optional<std::reference_wrapper<const SchemaField>> MapType::GetFieldByName (
181- std::string_view name) const {
182- if (name == kKeyName ) {
228+ Result<std::optional<std::reference_wrapper<const SchemaField>>> MapType::GetFieldByName (
229+ std::string_view name, bool case_sensitive) const {
230+ if (case_sensitive) {
231+ if (name == kKeyName ) {
232+ return key ();
233+ } else if (name == kValueName ) {
234+ return value ();
235+ }
236+ return std::nullopt ;
237+ }
238+ if (StringUtils::ToLower (name) == StringUtils::ToLower (kKeyName )) {
183239 return key ();
184- } else if (name == kValueName ) {
240+ } else if (StringUtils::ToLower ( name) == StringUtils::ToLower ( kValueName ) ) {
185241 return value ();
186242 }
187243 return std::nullopt ;
0 commit comments