@@ -74,6 +74,33 @@ Result<CatalogConfig> FetchServerConfig(const ResourcePaths& paths,
7474 return CatalogConfigFromJson (json);
7575}
7676
77+ #define ICEBERG_ENDPOINT_CHECK (endpoints, endpoint ) \
78+ do { \
79+ if (!endpoints.contains (endpoint)) { \
80+ return NotSupported (" Not supported endpoint: {}" , endpoint.ToString ()); \
81+ } \
82+ } while (0 )
83+
84+ Result<bool > CaptureNoSuchObject (const auto & status, ErrorKind kind) {
85+ ICEBERG_DCHECK (kind == ErrorKind::kNoSuchTable || kind == ErrorKind::kNoSuchNamespace ,
86+ " Invalid kind for CaptureNoSuchObject" );
87+ if (status.has_value ()) {
88+ return true ;
89+ }
90+ if (status.error ().kind == kind) {
91+ return false ;
92+ }
93+ return std::unexpected (status.error ());
94+ }
95+
96+ Result<bool > CaptureNoSuchTable (const auto & status) {
97+ return CaptureNoSuchObject (status, ErrorKind::kNoSuchTable );
98+ }
99+
100+ Result<bool > CaptureNoSuchNamespace (const auto & status) {
101+ return CaptureNoSuchObject (status, ErrorKind::kNoSuchNamespace );
102+ }
103+
77104} // namespace
78105
79106RestCatalog::~RestCatalog () = default ;
@@ -126,9 +153,7 @@ RestCatalog::RestCatalog(std::unique_ptr<RestCatalogProperties> config,
126153std::string_view RestCatalog::name () const { return name_; }
127154
128155Result<std::vector<Namespace>> RestCatalog::ListNamespaces (const Namespace& ns) const {
129- ICEBERG_RETURN_UNEXPECTED (
130- CheckEndpoint (supported_endpoints_, Endpoint::ListNamespaces ()));
131-
156+ ICEBERG_ENDPOINT_CHECK (supported_endpoints_, Endpoint::ListNamespaces ());
132157 ICEBERG_ASSIGN_OR_RAISE (auto path, paths_->Namespaces ());
133158 std::vector<Namespace> result;
134159 std::string next_token;
@@ -157,9 +182,7 @@ Result<std::vector<Namespace>> RestCatalog::ListNamespaces(const Namespace& ns)
157182
158183Status RestCatalog::CreateNamespace (
159184 const Namespace& ns, const std::unordered_map<std::string, std::string>& properties) {
160- ICEBERG_RETURN_UNEXPECTED (
161- CheckEndpoint (supported_endpoints_, Endpoint::CreateNamespace ()));
162-
185+ ICEBERG_ENDPOINT_CHECK (supported_endpoints_, Endpoint::CreateNamespace ());
163186 ICEBERG_ASSIGN_OR_RAISE (auto path, paths_->Namespaces ());
164187 CreateNamespaceRequest request{.namespace_ = ns, .properties = properties};
165188 ICEBERG_ASSIGN_OR_RAISE (auto json_request, ToJsonString (ToJson (request)));
@@ -173,9 +196,7 @@ Status RestCatalog::CreateNamespace(
173196
174197Result<std::unordered_map<std::string, std::string>> RestCatalog::GetNamespaceProperties (
175198 const Namespace& ns) const {
176- ICEBERG_RETURN_UNEXPECTED (
177- CheckEndpoint (supported_endpoints_, Endpoint::GetNamespaceProperties ()));
178-
199+ ICEBERG_ENDPOINT_CHECK (supported_endpoints_, Endpoint::GetNamespaceProperties ());
179200 ICEBERG_ASSIGN_OR_RAISE (auto path, paths_->Namespace_ (ns));
180201 ICEBERG_ASSIGN_OR_RAISE (const auto response,
181202 client_->Get (path, /* params=*/ {}, /* headers=*/ {},
@@ -186,48 +207,29 @@ Result<std::unordered_map<std::string, std::string>> RestCatalog::GetNamespacePr
186207}
187208
188209Status RestCatalog::DropNamespace (const Namespace& ns) {
189- ICEBERG_RETURN_UNEXPECTED (
190- CheckEndpoint (supported_endpoints_, Endpoint::DropNamespace ()));
210+ ICEBERG_ENDPOINT_CHECK (supported_endpoints_, Endpoint::DropNamespace ());
191211 ICEBERG_ASSIGN_OR_RAISE (auto path, paths_->Namespace_ (ns));
192- ICEBERG_ASSIGN_OR_RAISE (
193- const auto response ,
194- client_-> Delete (path, /* headers= */ {}, *DropNamespaceErrorHandler::Instance ()));
212+ ICEBERG_ASSIGN_OR_RAISE (const auto response,
213+ client_-> Delete (path, /* params= */ {}, /* headers= */ {} ,
214+ *DropNamespaceErrorHandler::Instance ()));
195215 return {};
196216}
197217
198218Result<bool > RestCatalog::NamespaceExists (const Namespace& ns) const {
199- auto check = CheckEndpoint (supported_endpoints_, Endpoint::NamespaceExists ());
200- if (!check.has_value ()) {
219+ if (!supported_endpoints_.contains (Endpoint::NamespaceExists ())) {
201220 // Fall back to GetNamespaceProperties
202- auto result = GetNamespaceProperties (ns);
203- if (!result.has_value () && result.error ().kind == ErrorKind::kNoSuchNamespace ) {
204- return false ;
205- }
206- ICEBERG_RETURN_UNEXPECTED (result);
207- // GET succeeded, namespace exists
208- return true ;
221+ return CaptureNoSuchNamespace (GetNamespaceProperties (ns));
209222 }
210223
211224 ICEBERG_ASSIGN_OR_RAISE (auto path, paths_->Namespace_ (ns));
212- auto response_or_error =
213- client_->Head (path, /* headers=*/ {}, *NamespaceErrorHandler::Instance ());
214- if (!response_or_error.has_value ()) {
215- const auto & error = response_or_error.error ();
216- // catch NoSuchNamespaceException/404 and return false
217- if (error.kind == ErrorKind::kNoSuchNamespace ) {
218- return false ;
219- }
220- ICEBERG_RETURN_UNEXPECTED (response_or_error);
221- }
222- return true ;
225+ return CaptureNoSuchNamespace (
226+ client_->Head (path, /* headers=*/ {}, *NamespaceErrorHandler::Instance ()));
223227}
224228
225229Status RestCatalog::UpdateNamespaceProperties (
226230 const Namespace& ns, const std::unordered_map<std::string, std::string>& updates,
227231 const std::unordered_set<std::string>& removals) {
228- ICEBERG_RETURN_UNEXPECTED (
229- CheckEndpoint (supported_endpoints_, Endpoint::UpdateNamespace ()));
230-
232+ ICEBERG_ENDPOINT_CHECK (supported_endpoints_, Endpoint::UpdateNamespace ());
231233 ICEBERG_ASSIGN_OR_RAISE (auto path, paths_->NamespaceProperties (ns));
232234 UpdateNamespacePropertiesRequest request{
233235 .removals = std::vector<std::string>(removals.begin (), removals.end ()),
@@ -252,7 +254,7 @@ Result<std::shared_ptr<Table>> RestCatalog::CreateTable(
252254 const std::shared_ptr<PartitionSpec>& spec, const std::shared_ptr<SortOrder>& order,
253255 const std::string& location,
254256 const std::unordered_map<std::string, std::string>& properties) {
255- ICEBERG_RETURN_UNEXPECTED ( CheckEndpoint ( supported_endpoints_, Endpoint::CreateTable () ));
257+ ICEBERG_ENDPOINT_CHECK ( supported_endpoints_, Endpoint::CreateTable ());
256258 ICEBERG_ASSIGN_OR_RAISE (auto path, paths_->Tables (identifier.ns ));
257259
258260 CreateTableRequest request{
@@ -294,24 +296,57 @@ Result<std::shared_ptr<Transaction>> RestCatalog::StageCreateTable(
294296 return NotImplemented (" Not implemented" );
295297}
296298
297- Status RestCatalog::DropTable ([[maybe_unused]] const TableIdentifier& identifier,
298- [[maybe_unused]] bool purge) {
299- return NotImplemented (" Not implemented" );
299+ Status RestCatalog::DropTable (const TableIdentifier& identifier, bool purge) {
300+ ICEBERG_ENDPOINT_CHECK (supported_endpoints_, Endpoint::DeleteTable ());
301+ ICEBERG_ASSIGN_OR_RAISE (auto path, paths_->Table (identifier));
302+
303+ std::unordered_map<std::string, std::string> params;
304+ if (purge) {
305+ params[" purgeRequested" ] = " true" ;
306+ }
307+ ICEBERG_ASSIGN_OR_RAISE (
308+ const auto response,
309+ client_->Delete (path, params, /* headers=*/ {}, *TableErrorHandler::Instance ()));
310+ return {};
300311}
301312
302- Result<bool > RestCatalog::TableExists (
303- [[maybe_unused]] const TableIdentifier& identifier) const {
304- return NotImplemented (" Not implemented" );
313+ Result<bool > RestCatalog::TableExists (const TableIdentifier& identifier) const {
314+ if (!supported_endpoints_.contains (Endpoint::TableExists ())) {
315+ // Fall back to call LoadTable
316+ return CaptureNoSuchTable (LoadTableInternal (identifier));
317+ }
318+
319+ ICEBERG_ASSIGN_OR_RAISE (auto path, paths_->Table (identifier));
320+ return CaptureNoSuchTable (
321+ client_->Head (path, /* headers=*/ {}, *TableErrorHandler::Instance ()));
305322}
306323
307324Status RestCatalog::RenameTable ([[maybe_unused]] const TableIdentifier& from,
308325 [[maybe_unused]] const TableIdentifier& to) {
309326 return NotImplemented (" Not implemented" );
310327}
311328
312- Result<std::shared_ptr<Table>> RestCatalog::LoadTable (
313- [[maybe_unused]] const TableIdentifier& identifier) {
314- return NotImplemented (" Not implemented" );
329+ Result<std::string> RestCatalog::LoadTableInternal (
330+ const TableIdentifier& identifier) const {
331+ ICEBERG_ENDPOINT_CHECK (supported_endpoints_, Endpoint::LoadTable ());
332+ ICEBERG_ASSIGN_OR_RAISE (auto path, paths_->Table (identifier));
333+ ICEBERG_ASSIGN_OR_RAISE (
334+ const auto response,
335+ client_->Get (path, /* params=*/ {}, /* headers=*/ {}, *TableErrorHandler::Instance ()));
336+ return response.body ();
337+ }
338+
339+ Result<std::shared_ptr<Table>> RestCatalog::LoadTable (const TableIdentifier& identifier) {
340+ ICEBERG_ENDPOINT_CHECK (supported_endpoints_, Endpoint::LoadTable ());
341+ ICEBERG_ASSIGN_OR_RAISE (auto path, paths_->Table (identifier));
342+
343+ ICEBERG_ASSIGN_OR_RAISE (const auto body, LoadTableInternal (identifier));
344+ ICEBERG_ASSIGN_OR_RAISE (auto json, FromJsonString (body));
345+ ICEBERG_ASSIGN_OR_RAISE (auto load_result, LoadTableResultFromJson (json));
346+
347+ return Table::Make (identifier, std::move (load_result.metadata ),
348+ std::move (load_result.metadata_location ), file_io_,
349+ shared_from_this ());
315350}
316351
317352Result<std::shared_ptr<Table>> RestCatalog::RegisterTable (
0 commit comments