1919
2020#include " iceberg/catalog/rest/validator.h"
2121
22+ #include < algorithm>
2223#include < format>
23- #include < ranges>
24- #include < unordered_set>
25- #include < utility>
2624
2725#include " iceberg/catalog/rest/types.h"
2826#include " iceberg/result.h"
27+ #include " iceberg/util/macros.h"
2928
3029namespace iceberg ::rest {
3130
@@ -40,18 +39,20 @@ Status Validator::Validate(const CatalogConfig& config) {
4039}
4140
4241Status Validator::Validate (const ErrorModel& error) {
43- if (error.message .empty () || error.type .empty ()) [[unlikely]] {
42+ if (error.message .empty () || error.type .empty ()) {
4443 return Invalid (" Invalid error model: missing required fields" );
4544 }
4645
47- if (error.code < 400 || error.code > 600 ) [[unlikely]] {
48- return Invalid (" Invalid error model: code must be between 400 and 600" );
46+ if (error.code < 400 || error.code > 600 ) {
47+ return Invalid (" Invalid error model: code {} is out of range [400, 600] " , error. code );
4948 }
5049
5150 // stack is optional, no validation needed
5251 return {};
5352}
5453
54+ // We don't validate the error field because ErrorModel::Validate has been called in the
55+ // FromJson.
5556Status Validator::Validate (const ErrorResponse& response) { return {}; }
5657
5758// Namespace operations
@@ -66,30 +67,38 @@ Status Validator::Validate(const GetNamespaceResponse& response) { return {}; }
6667
6768Status Validator::Validate (const UpdateNamespacePropertiesRequest& request) {
6869 // keys in updates and removals must not overlap
69- if (request.removals .empty () || request.updates .empty ()) [[unlikely]] {
70+ if (request.removals .empty () || request.updates .empty ()) {
7071 return {};
7172 }
7273
73- std::unordered_set<std::string> remove_set (request.removals .begin (),
74- request.removals .end ());
75- std::vector<std::string> common;
76-
77- for (const std::string& k : request.updates | std::views::keys) {
78- if (remove_set.contains (k)) {
79- common.push_back (k);
74+ auto extract_and_sort = [](const auto & container, auto key_extractor) {
75+ std::vector<std::string_view> result;
76+ result.reserve (container.size ());
77+ for (const auto & item : container) {
78+ result.push_back (std::string_view{key_extractor (item)});
8079 }
81- }
80+ std::ranges::sort (result);
81+ return result;
82+ };
83+
84+ auto sorted_removals =
85+ extract_and_sort (request.removals , [](const auto & s) -> const auto & { return s; });
86+ auto sorted_update_keys = extract_and_sort (
87+ request.updates , [](const auto & pair) -> const auto & { return pair.first ; });
88+
89+ std::vector<std::string_view> common;
90+ std::ranges::set_intersection (sorted_removals, sorted_update_keys,
91+ std::back_inserter (common));
8292
8393 if (!common.empty ()) {
8494 std::string keys;
85- bool first = true ;
86- for (const std::string& s : common) {
87- if (!std::exchange (first, false )) keys += " , " ;
88- keys += s;
95+ for (size_t i = 0 ; i < common.size (); ++i) {
96+ if (i) keys += " , " ;
97+ keys += common[i];
8998 }
9099
91100 return Invalid (
92- " Invalid namespace properties update: cannot simultaneously set and remove keys: "
101+ " Invalid namespace update: cannot simultaneously set and remove keys: "
93102 " [{}]" ,
94103 keys);
95104 }
@@ -105,34 +114,34 @@ Status Validator::Validate(const UpdateNamespacePropertiesResponse& response) {
105114Status Validator::Validate (const ListTablesResponse& response) { return {}; }
106115
107116Status Validator::Validate (const LoadTableResult& result) {
108- if (!result.metadata ) [[unlikely]] {
117+ if (!result.metadata ) {
109118 return Invalid (" Invalid metadata: null" );
110119 }
111120 return {};
112121}
113122
114123Status Validator::Validate (const RegisterTableRequest& request) {
115- if (request.name .empty ()) [[unlikely]] {
116- return Invalid (" Invalid table name: empty " );
124+ if (request.name .empty ()) {
125+ return Invalid (" Missing table name" );
117126 }
118127
119- if (request.metadata_location .empty ()) [[unlikely]] {
120- return Invalid (" Invalid metadata location: empty " );
128+ if (request.metadata_location .empty ()) {
129+ return Invalid (" Empty metadata location" );
121130 }
122131
123132 return {};
124133}
125134
126135Status Validator::Validate (const RenameTableRequest& request) {
127- if (request.source .ns .levels .empty () || request.source .name .empty ()) [[unlikely]] {
128- return Invalid (" Invalid source identifier" );
129- }
136+ ICEBERG_RETURN_UNEXPECTED (Validate (request.source ));
137+ ICEBERG_RETURN_UNEXPECTED (Validate (request.destination ));
138+ return {};
139+ }
130140
131- if (request. destination . ns . levels . empty () || request. destination . name . empty ())
132- [[unlikely]] {
133- return Invalid (" Invalid destination identifier" );
141+ Status Validator::Validate ( const TableIdentifier& identifier) {
142+ if (identifier. name . empty ()) {
143+ return Invalid (" Invalid table identifier: missing table name " );
134144 }
135-
136145 return {};
137146}
138147
0 commit comments