userver: userver/storages/redis/impl/reply.hpp Source File
Loading...
Searching...
No Matches
reply.hpp
1#pragma once
2
3#include <cassert>
4#include <string>
5#include <vector>
6
7#include <userver/logging/log_extra.hpp>
8#include <userver/utils/assert.hpp>
9
10#include <userver/storages/redis/impl/base.hpp>
11#include <userver/storages/redis/impl/reply_status.hpp>
12
13struct redisReply;
14
15USERVER_NAMESPACE_BEGIN
16
17namespace redis {
18
19class ReplyData final {
20 public:
21 using Array = std::vector<ReplyData>;
22
23 enum class Type {
24 kNoReply,
25 kString,
26 kArray,
27 kInteger,
28 kNil,
29 kStatus,
30 kError,
31 };
32
33 class KeyValues final {
34 public:
35 class KeyValue final {
36 public:
37 KeyValue(const Array& array, size_t index)
38 : array_(array), index_(index) {}
39
40 std::string Key() const { return array_[index_ * 2].GetString(); }
41 std::string Value() const { return array_[index_ * 2 + 1].GetString(); }
42
43 private:
44 const Array& array_;
45 size_t index_;
46 };
47
48 class KeyValueIt final {
49 public:
50 KeyValueIt(const Array& array, size_t index)
51 : array_(array), index_(index) {}
52 KeyValueIt& operator++() {
53 ++index_;
54 return *this;
55 }
56 bool operator!=(const KeyValueIt& r) const { return index_ != r.index_; }
57 KeyValue operator*() const { return {array_, index_}; }
58
59 private:
60 const Array& array_;
61 size_t index_;
62 };
63
64 explicit KeyValues(const Array& array) : array_(array) {}
65
66 KeyValueIt begin() const { return {array_, 0}; }
67 KeyValueIt end() const { return {array_, size()}; }
68
69 size_t size() const { return array_.size() / 2; }
70
71 private:
72 const Array& array_;
73 };
74
75 class MovableKeyValues final {
76 public:
77 class MovableKeyValue final {
78 public:
79 MovableKeyValue(ReplyData& key_data, ReplyData& value_data)
80 : key_data_(key_data), value_data_(value_data) {}
81
82 std::string& Key() { return key_data_.GetString(); }
83 std::string& Value() { return value_data_.GetString(); }
84
85 private:
86 ReplyData& key_data_;
87 ReplyData& value_data_;
88 };
89
90 class MovableKeyValueIt final {
91 public:
92 MovableKeyValueIt(Array& array, size_t index)
93 : array_(array), index_(index) {}
94 MovableKeyValueIt& operator++() {
95 ++index_;
96 return *this;
97 }
98 bool operator!=(const MovableKeyValueIt& r) const {
99 return index_ != r.index_;
100 }
101 MovableKeyValue operator*() {
102 return {array_[index_ * 2], array_[index_ * 2 + 1]};
103 }
104
105 private:
106 Array& array_;
107 size_t index_;
108 };
109
110 explicit MovableKeyValues(Array& array) : array_(array) {}
111
112 MovableKeyValueIt begin() const { return {array_, 0}; }
113 MovableKeyValueIt end() const { return {array_, size()}; }
114
115 size_t size() const { return array_.size() / 2; }
116
117 private:
118 Array& array_;
119 };
120
121 MovableKeyValues GetMovableKeyValues();
122
123 ReplyData(const redisReply* reply);
124 ReplyData(Array&& array);
125 ReplyData(std::string s);
126 ReplyData(int value);
127 static ReplyData CreateError(std::string&& error_msg);
128 static ReplyData CreateStatus(std::string&& status_msg);
129 static ReplyData CreateNil();
130
131 explicit operator bool() const { return type_ != Type::kNoReply; }
132
133 Type GetType() const { return type_; }
134 std::string GetTypeString() const;
135
136 inline bool IsString() const { return type_ == Type::kString; }
137 inline bool IsArray() const { return type_ == Type::kArray; }
138 inline bool IsInt() const { return type_ == Type::kInteger; }
139 inline bool IsNil() const { return type_ == Type::kNil; }
140 inline bool IsStatus() const { return type_ == Type::kStatus; }
141 inline bool IsError() const { return type_ == Type::kError; }
142 bool IsUnusableInstanceError() const;
143 bool IsReadonlyError() const;
144 bool IsUnknownCommandError() const;
145
146 bool IsErrorMoved() const {
147 return IsError() && !string_.compare(0, 6, "MOVED ");
148 }
149
150 bool IsErrorAsk() const {
151 return IsError() && !string_.compare(0, 4, "ASK ");
152 }
153
154 const std::string& GetString() const {
155 UASSERT(IsString());
156 return string_;
157 }
158
159 std::string& GetString() {
160 UASSERT(IsString());
161 return string_;
162 }
163
164 const Array& GetArray() const {
165 UASSERT(IsArray());
166 return array_;
167 }
168
169 Array& GetArray() {
170 UASSERT(IsArray());
171 return array_;
172 }
173
174 int64_t GetInt() const {
175 UASSERT(IsInt());
176 return integer_;
177 }
178
179 const std::string& GetStatus() const {
180 UASSERT(IsStatus());
181 return string_;
182 }
183
184 std::string& GetStatus() {
185 UASSERT(IsStatus());
186 return string_;
187 }
188
189 const std::string& GetError() const {
190 UASSERT(IsError());
191 return string_;
192 }
193
194 std::string& GetError() {
195 UASSERT(IsError());
196 return string_;
197 }
198
199 const ReplyData& operator[](size_t idx) const {
200 UASSERT(IsArray());
201 return array_.at(idx);
202 }
203
204 ReplyData& operator[](size_t idx) {
205 UASSERT(IsArray());
206 return array_.at(idx);
207 }
208
209 size_t GetSize() const;
210
211 std::string ToDebugString() const;
212 KeyValues GetKeyValues() const;
213 static std::string TypeToString(Type type);
214
215 void ExpectType(ReplyData::Type type,
216 const std::string& request_description = {}) const;
217
218 void ExpectString(const std::string& request_description = {}) const;
219 void ExpectArray(const std::string& request_description = {}) const;
220 void ExpectInt(const std::string& request_description = {}) const;
221 void ExpectNil(const std::string& request_description = {}) const;
222 void ExpectStatus(const std::string& request_description = {}) const;
223 void ExpectStatusEqualTo(const std::string& expected_status_str,
224 const std::string& request_description = {}) const;
225 void ExpectError(const std::string& request_description = {}) const;
226
227 private:
228 ReplyData() = default;
229
230 [[noreturn]] void ThrowUnexpectedReplyType(
231 ReplyData::Type expected, const std::string& request_description) const;
232
233 Type type_ = Type::kNoReply;
234
235 int64_t integer_{};
236 Array array_;
237 std::string string_;
238};
239
240class Reply final {
241 public:
242 Reply(std::string cmd, redisReply* redis_reply, ReplyStatus status);
243 Reply(std::string cmd, redisReply* redis_reply, ReplyStatus status,
244 std::string status_string);
245 Reply(std::string cmd, ReplyData&& data);
246
247 std::string server;
248 ServerId server_id;
249 std::string cmd;
250 ReplyData data;
251 ReplyStatus status;
252 std::string status_string;
253 double time = 0.0;
254 logging::LogExtra log_extra;
255
256 operator bool() const { return IsOk(); }
257
258 bool IsOk() const;
259 bool IsLoggableError() const;
260 bool IsUnusableInstanceError() const;
261 bool IsReadonlyError() const;
262 bool IsUnknownCommandError() const;
263 const logging::LogExtra& GetLogExtra() const;
264 void FillSpanTags(tracing::Span& span) const;
265
266 void ExpectIsOk(const std::string& request_description = {}) const;
267 void ExpectType(ReplyData::Type type,
268 const std::string& request_description = {}) const;
269
270 void ExpectString(const std::string& request_description = {}) const;
271 void ExpectArray(const std::string& request_description = {}) const;
272 void ExpectInt(const std::string& request_description = {}) const;
273 void ExpectNil(const std::string& request_description = {}) const;
274 void ExpectStatus(const std::string& request_description = {}) const;
275 void ExpectStatusEqualTo(const std::string& expected_status_str,
276 const std::string& request_description = {}) const;
277 void ExpectError(const std::string& request_description = {}) const;
278
279 const std::string& GetRequestDescription(
280 const std::string& request_description) const;
281};
282
283} // namespace redis
284
285USERVER_NAMESPACE_END