10#include <userver/logging/log_extra.hpp>
11#include <userver/utils/assert.hpp>
13#include <userver/storages/redis/base.hpp>
14#include <userver/storages/redis/impl/deadline_propagation_meta.hpp>
15#include <userver/storages/redis/reply_fwd.hpp>
16#include <userver/storages/redis/reply_status.hpp>
20USERVER_NAMESPACE_BEGIN
22namespace storages::
redis {
25class ReplyData
final {
27 using Array = std::vector<ReplyData>;
39 class MovableKeyValues
final {
43 View(ReplyData& key_data, ReplyData& value_data)
noexcept : key_data_(key_data), value_data_(value_data) {}
45 std::string& Key()
noexcept {
return key_data_.GetString(); }
46 std::string& Value()
noexcept {
return value_data_.GetString(); }
50 ReplyData& value_data_;
53 class Iterator
final {
55 constexpr Iterator(Array& array, std::size_t index)
noexcept : array_(array), index_(index) {}
56 Iterator& operator++()
noexcept {
60 bool operator!=(
const Iterator& r)
const noexcept {
return index_ != r.index_; }
61 View operator*()
noexcept {
return {array_[index_ * 2], array_[index_ * 2 + 1]}; }
68 explicit MovableKeyValues(Array& array)
noexcept : array_(array) {}
70 Iterator begin()
const noexcept {
return {array_, 0}; }
71 Iterator end()
const noexcept {
return {array_, size()}; }
73 std::size_t size()
const noexcept {
return array_.size() / 2; }
79 MovableKeyValues GetMovableKeyValues();
81 ReplyData(
const redisReply* reply);
82 ReplyData(Array&& array);
83 ReplyData(std::string s);
85 static ReplyData CreateError(std::string&& error_msg);
86 static ReplyData CreateStatus(std::string&& status_msg);
87 static ReplyData CreateNil();
89 explicit operator
bool()
const noexcept {
return GetType() != Type::kNoReply; }
91 Type GetType()
const noexcept {
92 UASSERT(!data_.valueless_by_exception());
93 return Type(data_.index());
95 std::string GetTypeString()
const;
97 inline bool IsString()
const noexcept {
return GetType() == Type::kString; }
98 inline bool IsArray()
const noexcept {
return GetType() == Type::kArray; }
99 inline bool IsInt()
const noexcept {
return GetType() == Type::kInteger; }
100 inline bool IsNil()
const noexcept {
return GetType() == Type::kNil; }
101 inline bool IsStatus()
const noexcept {
return GetType() == Type::kStatus; }
102 inline bool IsError()
const noexcept {
return GetType() == Type::kError; }
103 bool IsUnusableInstanceError()
const;
104 bool IsReadonlyError()
const;
105 bool IsUnknownCommandError()
const;
107 bool IsErrorMoved()
const {
return IsError() && !GetError().compare(0, 6,
"MOVED "); }
109 bool IsErrorAsk()
const {
return IsError() && !GetError().compare(0, 4,
"ASK "); }
111 bool IsErrorClusterdown()
const {
return IsError() && !GetError().compare(0, 12,
"CLUSTERDOWN "); }
113 const std::string& GetString()
const {
115 return std::get_if<String>(&data_)->GetUnderlying();
118 std::string& GetString() {
120 return std::get_if<String>(&data_)->GetUnderlying();
123 const Array& GetArray()
const {
125 return *std::get_if<Array>(&data_);
130 return *std::get_if<Array>(&data_);
133 std::int64_t GetInt()
const {
135 return *std::get_if<Integer>(&data_);
138 const std::string& GetStatus()
const {
140 return std::get_if<Status>(&data_)->GetUnderlying();
143 std::string& GetStatus() {
145 return std::get_if<Status>(&data_)->GetUnderlying();
148 const std::string& GetError()
const {
150 return std::get_if<Error>(&data_)->GetUnderlying();
153 std::string& GetError() {
155 return std::get_if<Error>(&data_)->GetUnderlying();
158 std::size_t GetSize()
const noexcept;
160 std::string ToDebugString()
const;
161 static std::string TypeToString(Type type);
163 void ExpectType(ReplyData::Type type,
const std::string& request_description = {})
const;
165 void ExpectString(
const std::string& request_description = {})
const;
166 void ExpectArray(
const std::string& request_description = {})
const;
167 void ExpectInt(
const std::string& request_description = {})
const;
168 void ExpectNil(
const std::string& request_description = {})
const;
169 void ExpectStatus(
const std::string& request_description = {})
const;
170 void ExpectStatusEqualTo(
const std::string& expected_status_str,
const std::string& request_description = {})
const;
171 void ExpectError(
const std::string& request_description = {})
const;
174 ReplyData() =
default;
176 [[noreturn]]
void ThrowUnexpectedReplyType(ReplyData::Type expected,
const std::string& request_description)
const;
179 using String = utils::StrongTypedef<
class StringTag, std::string>;
180 using Integer = std::int64_t;
182 using Status = utils::StrongTypedef<
class StatusTag, std::string>;
183 using Error = utils::StrongTypedef<
class ErrorTag, std::string>;
186 std::variant<NoReply, String, Array, Integer, Nil, Status, Error> data_{};
196 const std::string cmd;
200 logging::LogExtra log_extra;
202 DeadlinePropagationMeta deadline_propagation_meta;
204 operator
bool()
const {
return IsOk(); }
206 std::string_view GetStatusString()
const {
207 return (!IsOk() && data.IsError() ? data.GetError() : std::string_view{});
211 bool IsLoggableError()
const;
212 bool IsUnusableInstanceError()
const;
213 bool IsReadonlyError()
const;
214 bool IsUnknownCommandError()
const;
215 const logging::LogExtra& GetLogExtra()
const;
216 void FillSpanTags(
tracing::Span& span)
const;
218 void ExpectIsOk(
const std::string& request_description = {})
const;
220 const std::string& GetRequestDescription(
const std::string& request_description)
const;