sql_utils/common/status_payload_utils.h (70 lines of code) (raw):

/* * Copyright 2023 Google LLC * * Licensed 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. */ #ifndef THIRD_PARTY_PY_BIGQUERY_ML_UTILS_SQL_UTILS_COMMON_STATUS_PAYLOAD_UTILS_H_ #define THIRD_PARTY_PY_BIGQUERY_ML_UTILS_SQL_UTILS_COMMON_STATUS_PAYLOAD_UTILS_H_ #include <string> #include "sql_utils/base/logging.h" #include "google/protobuf/message.h" #include "absl/memory/memory.h" #include "absl/strings/cord.h" #include "absl/strings/str_cat.h" #include "sql_utils/base/status.h" #include "sql_utils/base/status_payload.h" namespace bigquery_ml_utils { namespace internal { // Whether the given status has any payload at all. bool HasPayload(const absl::Status& status); // Gets the number payloads. int GetPayloadCount(const absl::Status& status); template <class T> std::string GetTypeUrl() { return bigquery_ml_utils_base::GetTypeUrl<T>(); } // Whether the given status has exactly one payload of type T. template <class T> bool HasPayloadWithType(const absl::Status& status) { return status.GetPayload(bigquery_ml_utils_base::GetTypeUrl<T>()).has_value(); } // Gets the payload of type T from the status proto. Results undefined if // the status does not contain a payload of the given type, but will not crash. template <class T> T GetPayload(const absl::Status& status) { std::optional<absl::Cord> payload = status.GetPayload(GetTypeUrl<T>()); if (!payload.has_value()) { return T(); } T proto; if (!proto.ParseFromString(std::string(*payload))) { proto.Clear(); // Prefer empty over partial?? } return proto; } // Mutates `status` by removing any attached payload of type T. template <class T> void ErasePayloadTyped(absl::Status* status) { status->ErasePayload(GetTypeUrl<T>()); } // Attaches the given payload. This will overwrite any previous payload with // the same type. template <class T> void AttachPayload(absl::Status* status, const T& payload) { bigquery_ml_utils_base::AttachPayload<T>(status, payload); } // Creates a human readable string from the status payload (or empty if there // is no payload). Exact form is not defined. std::string PayloadToString(const absl::Status& status); // Creates a human readable string from the status, including its payload. // Exact form is not defined. std::string StatusToString(const absl::Status& status); inline absl::Status AppendMessage(const absl::Status& status, absl::string_view msg) { absl::string_view merged_msg_view = msg; std::string merged_msg; if (!status.message().empty()) { absl::StrAppend(&merged_msg, status.message(), "; ", msg); merged_msg_view = merged_msg; } absl::Status merged_status(status.code(), merged_msg_view); return merged_status; } // Update the current status with a new status. To ensure no error is ignored, // requires that if neither status is OK, then both should share the same code. // 1. If the new status is OK: NOOP // 2. Otherwise: // a. If the current status is OK, the new one takes over. // b. Both statuses are not OK. The message of the new status is appended to // the current one. inline void UpdateStatus(absl::Status* status, const absl::Status& new_status) { SQL_DCHECK_NE(status, nullptr); if (new_status.ok()) { return; } if (status->ok()) { *status = new_status; return; } SQL_DCHECK_EQ(status->code(), new_status.code()); *status = AppendMessage(*status, new_status.message()); } } // namespace internal } // namespace bigquery_ml_utils #endif // THIRD_PARTY_PY_BIGQUERY_ML_UTILS_SQL_UTILS_COMMON_STATUS_PAYLOAD_UTILS_H_