-
Notifications
You must be signed in to change notification settings - Fork 76
feat: scaffolding work of rest catalog client #296
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
c99784e
a37fec7
ceedea3
56ebfb2
ad51137
fa9c60f
c3a992c
1b17be0
f1685be
7267af5
ec69dfa
5f79c97
f3b0fad
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| /* | ||
| * Licensed to the Apache Software Foundation (ASF) under one | ||
| * or more contributor license agreements. See the NOTICE file | ||
| * distributed with this work for additional information | ||
| * regarding copyright ownership. The ASF licenses this file | ||
| * to you under the Apache License, Version 2.0 (the | ||
| * "License"); you may not use this file except in compliance | ||
| * with the License. You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, | ||
| * software distributed under the License is distributed on an | ||
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
| * KIND, either express or implied. See the License for the | ||
| * specific language governing permissions and limitations | ||
| * under the License. | ||
| */ | ||
|
|
||
| #include "iceberg/catalog/rest/catalog_properties.h" | ||
|
|
||
| #include <string_view> | ||
|
|
||
| namespace iceberg::rest { | ||
|
|
||
| std::unique_ptr<RestCatalogProperties> RestCatalogProperties::default_properties() { | ||
| return std::unique_ptr<RestCatalogProperties>(new RestCatalogProperties()); | ||
| } | ||
|
|
||
| std::unique_ptr<RestCatalogProperties> RestCatalogProperties::FromMap( | ||
| const std::unordered_map<std::string, std::string>& properties) { | ||
| auto rest_catalog_config = | ||
| std::unique_ptr<RestCatalogProperties>(new RestCatalogProperties()); | ||
| rest_catalog_config->configs_ = properties; | ||
| return rest_catalog_config; | ||
| } | ||
|
|
||
| std::unordered_map<std::string, std::string> RestCatalogProperties::ExtractHeaders() | ||
| const { | ||
| return Extract(kHeaderPrefix); | ||
| } | ||
|
|
||
| Result<std::string_view> RestCatalogProperties::Uri() const { | ||
| auto it = configs_.find(kUri.key()); | ||
| if (it == configs_.end() || it->second.empty()) { | ||
| return InvalidArgument("Rest catalog configuration property 'uri' is required."); | ||
| } | ||
| return it->second; | ||
| } | ||
|
|
||
| } // namespace iceberg::rest |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,71 @@ | ||
| /* | ||
| * Licensed to the Apache Software Foundation (ASF) under one | ||
| * or more contributor license agreements. See the NOTICE file | ||
| * distributed with this work for additional information | ||
| * regarding copyright ownership. The ASF licenses this file | ||
| * to you under the Apache License, Version 2.0 (the | ||
| * "License"); you may not use this file except in compliance | ||
| * with the License. You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, | ||
| * software distributed under the License is distributed on an | ||
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
| * KIND, either express or implied. See the License for the | ||
| * specific language governing permissions and limitations | ||
| * under the License. | ||
| */ | ||
|
|
||
| #pragma once | ||
|
|
||
| #include <memory> | ||
| #include <string> | ||
| #include <unordered_map> | ||
|
|
||
| #include "iceberg/catalog/rest/iceberg_rest_export.h" | ||
| #include "iceberg/result.h" | ||
| #include "iceberg/util/config.h" | ||
|
|
||
| /// \file iceberg/catalog/rest/catalog_properties.h | ||
| /// \brief RestCatalogProperties implementation for Iceberg REST API. | ||
|
|
||
| namespace iceberg::rest { | ||
|
|
||
| /// \brief Configuration class for a REST Catalog. | ||
| class ICEBERG_REST_EXPORT RestCatalogProperties | ||
| : public ConfigBase<RestCatalogProperties> { | ||
| public: | ||
| template <typename T> | ||
| using Entry = const ConfigBase<RestCatalogProperties>::Entry<T>; | ||
|
|
||
| /// \brief The URI of the REST catalog server. | ||
| inline static Entry<std::string> kUri{"uri", ""}; | ||
| /// \brief The name of the catalog. | ||
| inline static Entry<std::string> kName{"name", ""}; | ||
| /// \brief The warehouse path. | ||
| inline static Entry<std::string> kWarehouse{"warehouse", ""}; | ||
| /// \brief The optional prefix for REST API paths. | ||
| inline static Entry<std::string> kPrefix{"prefix", ""}; | ||
| /// \brief The prefix for HTTP headers. | ||
| inline static constexpr std::string_view kHeaderPrefix = "header."; | ||
|
|
||
| /// \brief Create a default RestCatalogProperties instance. | ||
| static std::unique_ptr<RestCatalogProperties> default_properties(); | ||
|
|
||
| /// \brief Create a RestCatalogProperties instance from a map of key-value pairs. | ||
| static std::unique_ptr<RestCatalogProperties> FromMap( | ||
| const std::unordered_map<std::string, std::string>& properties); | ||
|
|
||
| /// \brief Returns HTTP headers to be added to every request. | ||
| std::unordered_map<std::string, std::string> ExtractHeaders() const; | ||
|
|
||
| /// \brief Get the URI of the REST catalog server. | ||
| /// \return The URI if configured, or an error if not set or empty. | ||
| Result<std::string_view> Uri() const; | ||
|
|
||
| private: | ||
| RestCatalogProperties() = default; | ||
| }; | ||
|
|
||
| } // namespace iceberg::rest | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| /* | ||
| * Licensed to the Apache Software Foundation (ASF) under one | ||
| * or more contributor license agreements. See the NOTICE file | ||
| * distributed with this work for additional information | ||
| * regarding copyright ownership. The ASF licenses this file | ||
| * to you under the Apache License, Version 2.0 (the | ||
| * "License"); you may not use this file except in compliance | ||
| * with the License. You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, | ||
| * software distributed under the License is distributed on an | ||
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
| * KIND, either express or implied. See the License for the | ||
| * specific language governing permissions and limitations | ||
| * under the License. | ||
| */ | ||
|
|
||
| #pragma once | ||
|
|
||
| #include <string> | ||
|
|
||
| #include "iceberg/version.h" | ||
|
|
||
| /// \file iceberg/catalog/rest/constant.h | ||
| /// Constant values for Iceberg REST API. | ||
|
|
||
| namespace iceberg::rest { | ||
|
|
||
| inline const std::string kHeaderContentType = "Content-Type"; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why did you apply this change? I would prefer
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The main reason is that we still need to wrap it with
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So @HeartLinked may need to remove |
||
| inline const std::string kHeaderAccept = "Accept"; | ||
| inline const std::string kHeaderXClientVersion = "X-Client-Version"; | ||
| inline const std::string kHeaderUserAgent = "User-Agent"; | ||
|
|
||
| inline const std::string kMimeTypeApplicationJson = "application/json"; | ||
| inline const std::string kMimeTypeFormUrlEncoded = "application/x-www-form-urlencoded"; | ||
| inline const std::string kUserAgentPrefix = "iceberg-cpp/"; | ||
| inline const std::string kUserAgent = "iceberg-cpp/" ICEBERG_VERSION_STRING; | ||
|
|
||
| inline const std::string kQueryParamParent = "parent"; | ||
| inline const std::string kQueryParamPageToken = "page_token"; | ||
|
|
||
| } // namespace iceberg::rest | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,186 @@ | ||
| /* | ||
| * Licensed to the Apache Software Foundation (ASF) under one | ||
| * or more contributor license agreements. See the NOTICE file | ||
| * distributed with this work for additional information | ||
| * regarding copyright ownership. The ASF licenses this file | ||
| * to you under the Apache License, Version 2.0 (the | ||
| * "License"); you may not use this file except in compliance | ||
| * with the License. You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, | ||
| * software distributed under the License is distributed on an | ||
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
| * KIND, either express or implied. See the License for the | ||
| * specific language governing permissions and limitations | ||
| * under the License. | ||
| */ | ||
|
|
||
| #include "iceberg/catalog/rest/error_handlers.h" | ||
|
|
||
| #include <string_view> | ||
|
|
||
| #include "iceberg/catalog/rest/types.h" | ||
|
|
||
| namespace iceberg::rest { | ||
|
|
||
| namespace { | ||
|
|
||
| constexpr std::string_view kIllegalArgumentException = "IllegalArgumentException"; | ||
| constexpr std::string_view kNoSuchNamespaceException = "NoSuchNamespaceException"; | ||
| constexpr std::string_view kNamespaceNotEmptyException = "NamespaceNotEmptyException"; | ||
|
|
||
| } // namespace | ||
|
|
||
| const std::shared_ptr<DefaultErrorHandler>& DefaultErrorHandler::Instance() { | ||
| static const std::shared_ptr<DefaultErrorHandler> instance{new DefaultErrorHandler()}; | ||
| return instance; | ||
| } | ||
|
|
||
| Status DefaultErrorHandler::Accept(const ErrorModel& error) const { | ||
| switch (error.code) { | ||
| case 400: | ||
| if (error.type == kIllegalArgumentException) { | ||
| return InvalidArgument(error.message); | ||
| } | ||
| return BadRequest("Malformed request: {}", error.message); | ||
| case 401: | ||
| return NotAuthorized("Not authorized: {}", error.message); | ||
| case 403: | ||
| return Forbidden("Forbidden: {}", error.message); | ||
| case 405: | ||
| case 406: | ||
| break; | ||
| case 500: | ||
| return InternalServerError("Server error: {}: {}", error.type, error.message); | ||
| case 501: | ||
| return NotSupported(error.message); | ||
| case 503: | ||
| return ServiceUnavailable("Service unavailable: {}", error.message); | ||
| } | ||
|
|
||
| return RestError("Code: {}, message: {}", error.code, error.message); | ||
| } | ||
|
|
||
| const std::shared_ptr<NamespaceErrorHandler>& NamespaceErrorHandler::Instance() { | ||
| static const std::shared_ptr<NamespaceErrorHandler> instance{ | ||
| new NamespaceErrorHandler()}; | ||
| return instance; | ||
| } | ||
|
|
||
| Status NamespaceErrorHandler::Accept(const ErrorModel& error) const { | ||
| switch (error.code) { | ||
| case 400: | ||
| if (error.type == kNamespaceNotEmptyException) { | ||
| return NamespaceNotEmpty(error.message); | ||
| } | ||
| return BadRequest("Malformed request: {}", error.message); | ||
| case 404: | ||
| return NoSuchNamespace(error.message); | ||
| case 409: | ||
| return AlreadyExists(error.message); | ||
| case 422: | ||
| return RestError("Unable to process: {}", error.message); | ||
| } | ||
|
|
||
| return DefaultErrorHandler::Accept(error); | ||
| } | ||
|
|
||
| const std::shared_ptr<DropNamespaceErrorHandler>& DropNamespaceErrorHandler::Instance() { | ||
| static const std::shared_ptr<DropNamespaceErrorHandler> instance{ | ||
| new DropNamespaceErrorHandler()}; | ||
| return instance; | ||
| } | ||
|
|
||
| Status DropNamespaceErrorHandler::Accept(const ErrorModel& error) const { | ||
| if (error.code == 409) { | ||
| return NamespaceNotEmpty(error.message); | ||
| } | ||
|
|
||
| return NamespaceErrorHandler::Accept(error); | ||
| } | ||
|
|
||
| const std::shared_ptr<TableErrorHandler>& TableErrorHandler::Instance() { | ||
| static const std::shared_ptr<TableErrorHandler> instance{new TableErrorHandler()}; | ||
| return instance; | ||
| } | ||
|
|
||
| Status TableErrorHandler::Accept(const ErrorModel& error) const { | ||
| switch (error.code) { | ||
| case 404: | ||
| if (error.type == kNoSuchNamespaceException) { | ||
| return NoSuchNamespace(error.message); | ||
| } | ||
| return NoSuchTable(error.message); | ||
| case 409: | ||
| return AlreadyExists(error.message); | ||
| } | ||
|
|
||
| return DefaultErrorHandler::Accept(error); | ||
| } | ||
|
|
||
| const std::shared_ptr<ViewErrorHandler>& ViewErrorHandler::Instance() { | ||
| static const std::shared_ptr<ViewErrorHandler> instance{new ViewErrorHandler()}; | ||
| return instance; | ||
| } | ||
|
|
||
| Status ViewErrorHandler::Accept(const ErrorModel& error) const { | ||
| switch (error.code) { | ||
| case 404: | ||
| if (error.type == kNoSuchNamespaceException) { | ||
| return NoSuchNamespace(error.message); | ||
| } | ||
| return NoSuchView(error.message); | ||
| case 409: | ||
| return AlreadyExists(error.message); | ||
| } | ||
|
|
||
| return DefaultErrorHandler::Accept(error); | ||
| } | ||
|
|
||
| const std::shared_ptr<TableCommitErrorHandler>& TableCommitErrorHandler::Instance() { | ||
| static const std::shared_ptr<TableCommitErrorHandler> instance{ | ||
| new TableCommitErrorHandler()}; | ||
| return instance; | ||
| } | ||
|
|
||
| Status TableCommitErrorHandler::Accept(const ErrorModel& error) const { | ||
| switch (error.code) { | ||
| case 404: | ||
| return NoSuchTable(error.message); | ||
| case 409: | ||
| return CommitFailed("Commit failed: {}", error.message); | ||
| case 500: | ||
| case 502: | ||
| case 503: | ||
| case 504: | ||
| return CommitStateUnknown("Service failed: {}: {}", error.code, error.message); | ||
| } | ||
|
|
||
| return DefaultErrorHandler::Accept(error); | ||
| } | ||
|
|
||
| const std::shared_ptr<ViewCommitErrorHandler>& ViewCommitErrorHandler::Instance() { | ||
| static const std::shared_ptr<ViewCommitErrorHandler> instance{ | ||
| new ViewCommitErrorHandler()}; | ||
| return instance; | ||
| } | ||
|
|
||
| Status ViewCommitErrorHandler::Accept(const ErrorModel& error) const { | ||
| switch (error.code) { | ||
| case 404: | ||
| return NoSuchView(error.message); | ||
| case 409: | ||
| return CommitFailed("Commit failed: {}", error.message); | ||
| case 500: | ||
| case 502: | ||
| case 503: | ||
| case 504: | ||
| return CommitStateUnknown("Service failed: {}: {}", error.code, error.message); | ||
| } | ||
|
|
||
| return DefaultErrorHandler::Accept(error); | ||
| } | ||
|
|
||
| } // namespace iceberg::rest |
Uh oh!
There was an error while loading. Please reload this page.