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