1 /**************************************************************************
2    Copyright (c) 2017 sewenew
3 
4    Licensed under the Apache License, Version 2.0 (the "License");
5    you may not use this file except in compliance with the License.
6    You may obtain a copy of the License at
7 
8        http://www.apache.org/licenses/LICENSE-2.0
9 
10    Unless required by applicable law or agreed to in writing, software
11    distributed under the License is distributed on an "AS IS" BASIS,
12    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13    See the License for the specific language governing permissions and
14    limitations under the License.
15  *************************************************************************/
16 
17 #ifndef SEWENEW_REDISPLUSPLUS_QUEUED_REDIS_H
18 #define SEWENEW_REDISPLUSPLUS_QUEUED_REDIS_H
19 
20 #include <cassert>
21 #include <chrono>
22 #include <initializer_list>
23 #include <vector>
24 #include "connection.h"
25 #include "utils.h"
26 #include "reply.h"
27 #include "command.h"
28 #include "redis.h"
29 
30 namespace sw {
31 
32 namespace redis {
33 
34 class QueuedReplies;
35 
36 // If any command throws, QueuedRedis resets the connection, and becomes invalid.
37 // In this case, the only thing we can do is to destory the QueuedRedis object.
38 template <typename Impl>
39 class QueuedRedis {
40 public:
41     QueuedRedis(QueuedRedis &&) = default;
42     QueuedRedis& operator=(QueuedRedis &&) = default;
43 
44     // When it destructs, the underlying *Connection* will be closed,
45     // and any command that has NOT been executed will be ignored.
46     ~QueuedRedis() = default;
47 
48     Redis redis();
49 
50     template <typename Cmd, typename ...Args>
51     auto command(Cmd cmd, Args &&...args)
52         -> typename std::enable_if<!std::is_convertible<Cmd, StringView>::value,
53                                     QueuedRedis&>::type;
54 
55     template <typename ...Args>
56     QueuedRedis& command(const StringView &cmd_name, Args &&...args);
57 
58     template <typename Input>
59     auto command(Input first, Input last)
60         -> typename std::enable_if<IsIter<Input>::value, QueuedRedis&>::type;
61 
62     QueuedReplies exec();
63 
64     void discard();
65 
66     // CONNECTION commands.
67 
auth(const StringView & password)68     QueuedRedis& auth(const StringView &password) {
69         return command(cmd::auth, password);
70     }
71 
echo(const StringView & msg)72     QueuedRedis& echo(const StringView &msg) {
73         return command(cmd::echo, msg);
74     }
75 
ping()76     QueuedRedis& ping() {
77         return command<void (*)(Connection &)>(cmd::ping);
78     }
79 
ping(const StringView & msg)80     QueuedRedis& ping(const StringView &msg) {
81         return command<void (*)(Connection &, const StringView &)>(cmd::ping, msg);
82     }
83 
84     // We DO NOT support the QUIT command. See *Redis::quit* doc for details.
85     //
86     // QueuedRedis& quit();
87 
select(long long idx)88     QueuedRedis& select(long long idx) {
89         return command(cmd::select, idx);
90     }
91 
swapdb(long long idx1,long long idx2)92     QueuedRedis& swapdb(long long idx1, long long idx2) {
93         return command(cmd::swapdb, idx1, idx2);
94     }
95 
96     // SERVER commands.
97 
bgrewriteaof()98     QueuedRedis& bgrewriteaof() {
99         return command(cmd::bgrewriteaof);
100     }
101 
bgsave()102     QueuedRedis& bgsave() {
103         return command(cmd::bgsave);
104     }
105 
dbsize()106     QueuedRedis& dbsize() {
107         return command(cmd::dbsize);
108     }
109 
110     QueuedRedis& flushall(bool async = false) {
111         return command(cmd::flushall, async);
112     }
113 
114     QueuedRedis& flushdb(bool async = false) {
115         return command(cmd::flushdb, async);
116     }
117 
info()118     QueuedRedis& info() {
119         return command<void (*)(Connection &)>(cmd::info);
120     }
121 
info(const StringView & section)122     QueuedRedis& info(const StringView &section) {
123         return command<void (*)(Connection &, const StringView &)>(cmd::info, section);
124     }
125 
lastsave()126     QueuedRedis& lastsave() {
127         return command(cmd::lastsave);
128     }
129 
save()130     QueuedRedis& save() {
131         return command(cmd::save);
132     }
133 
134     // KEY commands.
135 
del(const StringView & key)136     QueuedRedis& del(const StringView &key) {
137         return command(cmd::del, key);
138     }
139 
140     template <typename Input>
del(Input first,Input last)141     QueuedRedis& del(Input first, Input last) {
142         return command(cmd::del_range<Input>, first, last);
143     }
144 
145     template <typename T>
del(std::initializer_list<T> il)146     QueuedRedis& del(std::initializer_list<T> il) {
147         return del(il.begin(), il.end());
148     }
149 
dump(const StringView & key)150     QueuedRedis& dump(const StringView &key) {
151         return command(cmd::dump, key);
152     }
153 
exists(const StringView & key)154     QueuedRedis& exists(const StringView &key) {
155         return command(cmd::exists, key);
156     }
157 
158     template <typename Input>
exists(Input first,Input last)159     QueuedRedis& exists(Input first, Input last) {
160         return command(cmd::exists_range<Input>, first, last);
161     }
162 
163     template <typename T>
exists(std::initializer_list<T> il)164     QueuedRedis& exists(std::initializer_list<T> il) {
165         return exists(il.begin(), il.end());
166     }
167 
expire(const StringView & key,long long timeout)168     QueuedRedis& expire(const StringView &key, long long timeout) {
169         return command(cmd::expire, key, timeout);
170     }
171 
expire(const StringView & key,const std::chrono::seconds & timeout)172     QueuedRedis& expire(const StringView &key,
173                         const std::chrono::seconds &timeout) {
174         return expire(key, timeout.count());
175     }
176 
expireat(const StringView & key,long long timestamp)177     QueuedRedis& expireat(const StringView &key, long long timestamp) {
178         return command(cmd::expireat, key, timestamp);
179     }
180 
expireat(const StringView & key,const std::chrono::time_point<std::chrono::system_clock,std::chrono::seconds> & tp)181     QueuedRedis& expireat(const StringView &key,
182                             const std::chrono::time_point<std::chrono::system_clock,
183                                                             std::chrono::seconds> &tp) {
184         return expireat(key, tp.time_since_epoch().count());
185     }
186 
keys(const StringView & pattern)187     QueuedRedis& keys(const StringView &pattern) {
188         return command(cmd::keys, pattern);
189     }
190 
move(const StringView & key,long long db)191     QueuedRedis& move(const StringView &key, long long db) {
192         return command(cmd::move, key, db);
193     }
194 
persist(const StringView & key)195     QueuedRedis& persist(const StringView &key) {
196         return command(cmd::persist, key);
197     }
198 
pexpire(const StringView & key,long long timeout)199     QueuedRedis& pexpire(const StringView &key, long long timeout) {
200         return command(cmd::pexpire, key, timeout);
201     }
202 
pexpire(const StringView & key,const std::chrono::milliseconds & timeout)203     QueuedRedis& pexpire(const StringView &key,
204                             const std::chrono::milliseconds &timeout) {
205         return pexpire(key, timeout.count());
206     }
207 
pexpireat(const StringView & key,long long timestamp)208     QueuedRedis& pexpireat(const StringView &key, long long timestamp) {
209         return command(cmd::pexpireat, key, timestamp);
210     }
211 
pexpireat(const StringView & key,const std::chrono::time_point<std::chrono::system_clock,std::chrono::milliseconds> & tp)212     QueuedRedis& pexpireat(const StringView &key,
213                             const std::chrono::time_point<std::chrono::system_clock,
214                                                             std::chrono::milliseconds> &tp) {
215         return pexpireat(key, tp.time_since_epoch().count());
216     }
217 
pttl(const StringView & key)218     QueuedRedis& pttl(const StringView &key) {
219         return command(cmd::pttl, key);
220     }
221 
randomkey()222     QueuedRedis& randomkey() {
223         return command(cmd::randomkey);
224     }
225 
rename(const StringView & key,const StringView & newkey)226     QueuedRedis& rename(const StringView &key, const StringView &newkey) {
227         return command(cmd::rename, key, newkey);
228     }
229 
renamenx(const StringView & key,const StringView & newkey)230     QueuedRedis& renamenx(const StringView &key, const StringView &newkey) {
231         return command(cmd::renamenx, key, newkey);
232     }
233 
234     QueuedRedis& restore(const StringView &key,
235                                 const StringView &val,
236                                 long long ttl,
237                                 bool replace = false) {
238         return command(cmd::restore, key, val, ttl, replace);
239     }
240 
241     QueuedRedis& restore(const StringView &key,
242                             const StringView &val,
243                             const std::chrono::milliseconds &ttl = std::chrono::milliseconds{0},
244                             bool replace = false) {
245         return restore(key, val, ttl.count(), replace);
246     }
247 
248     // TODO: sort
249 
scan(long long cursor,const StringView & pattern,long long count)250     QueuedRedis& scan(long long cursor,
251                         const StringView &pattern,
252                         long long count) {
253         return command(cmd::scan, cursor, pattern, count);
254     }
255 
scan(long long cursor)256     QueuedRedis& scan(long long cursor) {
257         return scan(cursor, "*", 10);
258     }
259 
scan(long long cursor,const StringView & pattern)260     QueuedRedis& scan(long long cursor,
261                         const StringView &pattern) {
262         return scan(cursor, pattern, 10);
263     }
264 
scan(long long cursor,long long count)265     QueuedRedis& scan(long long cursor,
266                         long long count) {
267         return scan(cursor, "*", count);
268     }
269 
touch(const StringView & key)270     QueuedRedis& touch(const StringView &key) {
271         return command(cmd::touch, key);
272     }
273 
274     template <typename Input>
touch(Input first,Input last)275     QueuedRedis& touch(Input first, Input last) {
276         return command(cmd::touch_range<Input>, first, last);
277     }
278 
279     template <typename T>
touch(std::initializer_list<T> il)280     QueuedRedis& touch(std::initializer_list<T> il) {
281         return touch(il.begin(), il.end());
282     }
283 
ttl(const StringView & key)284     QueuedRedis& ttl(const StringView &key) {
285         return command(cmd::ttl, key);
286     }
287 
type(const StringView & key)288     QueuedRedis& type(const StringView &key) {
289         return command(cmd::type, key);
290     }
291 
unlink(const StringView & key)292     QueuedRedis& unlink(const StringView &key) {
293         return command(cmd::unlink, key);
294     }
295 
296     template <typename Input>
unlink(Input first,Input last)297     QueuedRedis& unlink(Input first, Input last) {
298         return command(cmd::unlink_range<Input>, first, last);
299     }
300 
301     template <typename T>
unlink(std::initializer_list<T> il)302     QueuedRedis& unlink(std::initializer_list<T> il) {
303         return unlink(il.begin(), il.end());
304     }
305 
wait(long long numslaves,long long timeout)306     QueuedRedis& wait(long long numslaves, long long timeout) {
307         return command(cmd::wait, numslaves, timeout);
308     }
309 
wait(long long numslaves,const std::chrono::milliseconds & timeout)310     QueuedRedis& wait(long long numslaves, const std::chrono::milliseconds &timeout) {
311         return wait(numslaves, timeout.count());
312     }
313 
314     // STRING commands.
315 
append(const StringView & key,const StringView & str)316     QueuedRedis& append(const StringView &key, const StringView &str) {
317         return command(cmd::append, key, str);
318     }
319 
320     QueuedRedis& bitcount(const StringView &key,
321                             long long start = 0,
322                             long long end = -1) {
323         return command(cmd::bitcount, key, start, end);
324     }
325 
bitop(BitOp op,const StringView & destination,const StringView & key)326     QueuedRedis& bitop(BitOp op,
327                         const StringView &destination,
328                         const StringView &key) {
329         return command(cmd::bitop, op, destination, key);
330     }
331 
332     template <typename Input>
bitop(BitOp op,const StringView & destination,Input first,Input last)333     QueuedRedis& bitop(BitOp op,
334                         const StringView &destination,
335                         Input first,
336                         Input last) {
337         return command(cmd::bitop_range<Input>, op, destination, first, last);
338     }
339 
340     template <typename T>
bitop(BitOp op,const StringView & destination,std::initializer_list<T> il)341     QueuedRedis& bitop(BitOp op,
342                         const StringView &destination,
343                         std::initializer_list<T> il) {
344         return bitop(op, destination, il.begin(), il.end());
345     }
346 
347     QueuedRedis& bitpos(const StringView &key,
348                         long long bit,
349                         long long start = 0,
350                         long long end = -1) {
351         return command(cmd::bitpos, key, bit, start, end);
352     }
353 
decr(const StringView & key)354     QueuedRedis& decr(const StringView &key) {
355         return command(cmd::decr, key);
356     }
357 
decrby(const StringView & key,long long decrement)358     QueuedRedis& decrby(const StringView &key, long long decrement) {
359         return command(cmd::decrby, key, decrement);
360     }
361 
get(const StringView & key)362     QueuedRedis& get(const StringView &key) {
363         return command(cmd::get, key);
364     }
365 
getbit(const StringView & key,long long offset)366     QueuedRedis& getbit(const StringView &key, long long offset) {
367         return command(cmd::getbit, key, offset);
368     }
369 
getrange(const StringView & key,long long start,long long end)370     QueuedRedis& getrange(const StringView &key, long long start, long long end) {
371         return command(cmd::getrange, key, start, end);
372     }
373 
getset(const StringView & key,const StringView & val)374     QueuedRedis& getset(const StringView &key, const StringView &val) {
375         return command(cmd::getset, key, val);
376     }
377 
incr(const StringView & key)378     QueuedRedis& incr(const StringView &key) {
379         return command(cmd::incr, key);
380     }
381 
incrby(const StringView & key,long long increment)382     QueuedRedis& incrby(const StringView &key, long long increment) {
383         return command(cmd::incrby, key, increment);
384     }
385 
incrbyfloat(const StringView & key,double increment)386     QueuedRedis& incrbyfloat(const StringView &key, double increment) {
387         return command(cmd::incrbyfloat, key, increment);
388     }
389 
390     template <typename Input>
mget(Input first,Input last)391     QueuedRedis& mget(Input first, Input last) {
392         return command(cmd::mget<Input>, first, last);
393     }
394 
395     template <typename T>
mget(std::initializer_list<T> il)396     QueuedRedis& mget(std::initializer_list<T> il) {
397         return mget(il.begin(), il.end());
398     }
399 
400     template <typename Input>
mset(Input first,Input last)401     QueuedRedis& mset(Input first, Input last) {
402         return command(cmd::mset<Input>, first, last);
403     }
404 
405     template <typename T>
mset(std::initializer_list<T> il)406     QueuedRedis& mset(std::initializer_list<T> il) {
407         return mset(il.begin(), il.end());
408     }
409 
410     template <typename Input>
msetnx(Input first,Input last)411     QueuedRedis& msetnx(Input first, Input last) {
412         return command(cmd::msetnx<Input>, first, last);
413     }
414 
415     template <typename T>
msetnx(std::initializer_list<T> il)416     QueuedRedis& msetnx(std::initializer_list<T> il) {
417         return msetnx(il.begin(), il.end());
418     }
419 
psetex(const StringView & key,long long ttl,const StringView & val)420     QueuedRedis& psetex(const StringView &key,
421                         long long ttl,
422                         const StringView &val) {
423         return command(cmd::psetex, key, ttl, val);
424     }
425 
psetex(const StringView & key,const std::chrono::milliseconds & ttl,const StringView & val)426     QueuedRedis& psetex(const StringView &key,
427                         const std::chrono::milliseconds &ttl,
428                         const StringView &val) {
429         return psetex(key, ttl.count(), val);
430     }
431 
432     QueuedRedis& set(const StringView &key,
433                         const StringView &val,
434                         const std::chrono::milliseconds &ttl = std::chrono::milliseconds(0),
435                         UpdateType type = UpdateType::ALWAYS) {
436         _set_cmd_indexes.push_back(_cmd_num);
437 
438         return command(cmd::set, key, val, ttl.count(), type);
439     }
440 
setex(const StringView & key,long long ttl,const StringView & val)441     QueuedRedis& setex(const StringView &key,
442                         long long ttl,
443                         const StringView &val) {
444         return command(cmd::setex, key, ttl, val);
445     }
446 
setex(const StringView & key,const std::chrono::seconds & ttl,const StringView & val)447     QueuedRedis& setex(const StringView &key,
448                         const std::chrono::seconds &ttl,
449                         const StringView &val) {
450         return setex(key, ttl.count(), val);
451     }
452 
setnx(const StringView & key,const StringView & val)453     QueuedRedis& setnx(const StringView &key, const StringView &val) {
454         return command(cmd::setnx, key, val);
455     }
456 
setrange(const StringView & key,long long offset,const StringView & val)457     QueuedRedis& setrange(const StringView &key,
458                             long long offset,
459                             const StringView &val) {
460         return command(cmd::setrange, key, offset, val);
461     }
462 
strlen(const StringView & key)463     QueuedRedis& strlen(const StringView &key) {
464         return command(cmd::strlen, key);
465     }
466 
467     // LIST commands.
468 
blpop(const StringView & key,long long timeout)469     QueuedRedis& blpop(const StringView &key, long long timeout) {
470         return command(cmd::blpop, key, timeout);
471     }
472 
473     QueuedRedis& blpop(const StringView &key,
474                         const std::chrono::seconds &timeout = std::chrono::seconds{0}) {
475         return blpop(key, timeout.count());
476     }
477 
478     template <typename Input>
blpop(Input first,Input last,long long timeout)479     QueuedRedis& blpop(Input first, Input last, long long timeout) {
480         return command(cmd::blpop_range<Input>, first, last, timeout);
481     }
482 
483     template <typename T>
blpop(std::initializer_list<T> il,long long timeout)484     QueuedRedis& blpop(std::initializer_list<T> il, long long timeout) {
485         return blpop(il.begin(), il.end(), timeout);
486     }
487 
488     template <typename Input>
489     QueuedRedis& blpop(Input first,
490                         Input last,
491                         const std::chrono::seconds &timeout = std::chrono::seconds{0}) {
492         return blpop(first, last, timeout.count());
493     }
494 
495     template <typename T>
496     QueuedRedis& blpop(std::initializer_list<T> il,
497                         const std::chrono::seconds &timeout = std::chrono::seconds{0}) {
498         return blpop(il.begin(), il.end(), timeout);
499     }
500 
brpop(const StringView & key,long long timeout)501     QueuedRedis& brpop(const StringView &key, long long timeout) {
502         return command(cmd::brpop, key, timeout);
503     }
504 
505     QueuedRedis& brpop(const StringView &key,
506                         const std::chrono::seconds &timeout = std::chrono::seconds{0}) {
507         return brpop(key, timeout.count());
508     }
509 
510     template <typename Input>
brpop(Input first,Input last,long long timeout)511     QueuedRedis& brpop(Input first, Input last, long long timeout) {
512         return command(cmd::brpop_range<Input>, first, last, timeout);
513     }
514 
515     template <typename T>
brpop(std::initializer_list<T> il,long long timeout)516     QueuedRedis& brpop(std::initializer_list<T> il, long long timeout) {
517         return brpop(il.begin(), il.end(), timeout);
518     }
519 
520     template <typename Input>
521     QueuedRedis& brpop(Input first,
522                         Input last,
523                         const std::chrono::seconds &timeout = std::chrono::seconds{0}) {
524         return brpop(first, last, timeout.count());
525     }
526 
527     template <typename T>
528     QueuedRedis& brpop(std::initializer_list<T> il,
529                         const std::chrono::seconds &timeout = std::chrono::seconds{0}) {
530         return brpop(il.begin(), il.end(), timeout);
531     }
532 
brpoplpush(const StringView & source,const StringView & destination,long long timeout)533     QueuedRedis& brpoplpush(const StringView &source,
534                             const StringView &destination,
535                             long long timeout) {
536         return command(cmd::brpoplpush, source, destination, timeout);
537     }
538 
539     QueuedRedis& brpoplpush(const StringView &source,
540                             const StringView &destination,
541                             const std::chrono::seconds &timeout = std::chrono::seconds{0}) {
542         return brpoplpush(source, destination, timeout.count());
543     }
544 
lindex(const StringView & key,long long index)545     QueuedRedis& lindex(const StringView &key, long long index) {
546         return command(cmd::lindex, key, index);
547     }
548 
linsert(const StringView & key,InsertPosition position,const StringView & pivot,const StringView & val)549     QueuedRedis& linsert(const StringView &key,
550                             InsertPosition position,
551                             const StringView &pivot,
552                             const StringView &val) {
553         return command(cmd::linsert, key, position, pivot, val);
554     }
555 
llen(const StringView & key)556     QueuedRedis& llen(const StringView &key) {
557         return command(cmd::llen, key);
558     }
559 
lpop(const StringView & key)560     QueuedRedis& lpop(const StringView &key) {
561         return command(cmd::lpop, key);
562     }
563 
lpush(const StringView & key,const StringView & val)564     QueuedRedis& lpush(const StringView &key, const StringView &val) {
565         return command(cmd::lpush, key, val);
566     }
567 
568     template <typename Input>
lpush(const StringView & key,Input first,Input last)569     QueuedRedis& lpush(const StringView &key, Input first, Input last) {
570         return command(cmd::lpush_range<Input>, key, first, last);
571     }
572 
573     template <typename T>
lpush(const StringView & key,std::initializer_list<T> il)574     QueuedRedis& lpush(const StringView &key, std::initializer_list<T> il) {
575         return lpush(key, il.begin(), il.end());
576     }
577 
lpushx(const StringView & key,const StringView & val)578     QueuedRedis& lpushx(const StringView &key, const StringView &val) {
579         return command(cmd::lpushx, key, val);
580     }
581 
lrange(const StringView & key,long long start,long long stop)582     QueuedRedis& lrange(const StringView &key,
583                         long long start,
584                         long long stop) {
585         return command(cmd::lrange, key, start, stop);
586     }
587 
lrem(const StringView & key,long long count,const StringView & val)588     QueuedRedis& lrem(const StringView &key, long long count, const StringView &val) {
589         return command(cmd::lrem, key, count, val);
590     }
591 
lset(const StringView & key,long long index,const StringView & val)592     QueuedRedis& lset(const StringView &key, long long index, const StringView &val) {
593         return command(cmd::lset, key, index, val);
594     }
595 
ltrim(const StringView & key,long long start,long long stop)596     QueuedRedis& ltrim(const StringView &key, long long start, long long stop) {
597         return command(cmd::ltrim, key, start, stop);
598     }
599 
rpop(const StringView & key)600     QueuedRedis& rpop(const StringView &key) {
601         return command(cmd::rpop, key);
602     }
603 
rpoplpush(const StringView & source,const StringView & destination)604     QueuedRedis& rpoplpush(const StringView &source, const StringView &destination) {
605         return command(cmd::rpoplpush, source, destination);
606     }
607 
rpush(const StringView & key,const StringView & val)608     QueuedRedis& rpush(const StringView &key, const StringView &val) {
609         return command(cmd::rpush, key, val);
610     }
611 
612     template <typename Input>
rpush(const StringView & key,Input first,Input last)613     QueuedRedis& rpush(const StringView &key, Input first, Input last) {
614         return command(cmd::rpush_range<Input>, key, first, last);
615     }
616 
617     template <typename T>
rpush(const StringView & key,std::initializer_list<T> il)618     QueuedRedis& rpush(const StringView &key, std::initializer_list<T> il) {
619         return rpush(key, il.begin(), il.end());
620     }
621 
rpushx(const StringView & key,const StringView & val)622     QueuedRedis& rpushx(const StringView &key, const StringView &val) {
623         return command(cmd::rpushx, key, val);
624     }
625 
626     // HASH commands.
627 
hdel(const StringView & key,const StringView & field)628     QueuedRedis& hdel(const StringView &key, const StringView &field) {
629         return command(cmd::hdel, key, field);
630     }
631 
632     template <typename Input>
hdel(const StringView & key,Input first,Input last)633     QueuedRedis& hdel(const StringView &key, Input first, Input last) {
634         return command(cmd::hdel_range<Input>, key, first, last);
635     }
636 
637     template <typename T>
hdel(const StringView & key,std::initializer_list<T> il)638     QueuedRedis& hdel(const StringView &key, std::initializer_list<T> il) {
639         return hdel(key, il.begin(), il.end());
640     }
641 
hexists(const StringView & key,const StringView & field)642     QueuedRedis& hexists(const StringView &key, const StringView &field) {
643         return command(cmd::hexists, key, field);
644     }
645 
hget(const StringView & key,const StringView & field)646     QueuedRedis& hget(const StringView &key, const StringView &field) {
647         return command(cmd::hget, key, field);
648     }
649 
hgetall(const StringView & key)650     QueuedRedis& hgetall(const StringView &key) {
651         return command(cmd::hgetall, key);
652     }
653 
hincrby(const StringView & key,const StringView & field,long long increment)654     QueuedRedis& hincrby(const StringView &key,
655                             const StringView &field,
656                             long long increment) {
657         return command(cmd::hincrby, key, field, increment);
658     }
659 
hincrbyfloat(const StringView & key,const StringView & field,double increment)660     QueuedRedis& hincrbyfloat(const StringView &key,
661                                 const StringView &field,
662                                 double increment) {
663         return command(cmd::hincrbyfloat, key, field, increment);
664     }
665 
hkeys(const StringView & key)666     QueuedRedis& hkeys(const StringView &key) {
667         return command(cmd::hkeys, key);
668     }
669 
hlen(const StringView & key)670     QueuedRedis& hlen(const StringView &key) {
671         return command(cmd::hlen, key);
672     }
673 
674     template <typename Input>
hmget(const StringView & key,Input first,Input last)675     QueuedRedis& hmget(const StringView &key, Input first, Input last) {
676         return command(cmd::hmget<Input>, key, first, last);
677     }
678 
679     template <typename T>
hmget(const StringView & key,std::initializer_list<T> il)680     QueuedRedis& hmget(const StringView &key, std::initializer_list<T> il) {
681         return hmget(key, il.begin(), il.end());
682     }
683 
684     template <typename Input>
hmset(const StringView & key,Input first,Input last)685     QueuedRedis& hmset(const StringView &key, Input first, Input last) {
686         return command(cmd::hmset<Input>, key, first, last);
687     }
688 
689     template <typename T>
hmset(const StringView & key,std::initializer_list<T> il)690     QueuedRedis& hmset(const StringView &key, std::initializer_list<T> il) {
691         return hmset(key, il.begin(), il.end());
692     }
693 
hscan(const StringView & key,long long cursor,const StringView & pattern,long long count)694     QueuedRedis& hscan(const StringView &key,
695                         long long cursor,
696                         const StringView &pattern,
697                         long long count) {
698         return command(cmd::hscan, key, cursor, pattern, count);
699     }
700 
hscan(const StringView & key,long long cursor,const StringView & pattern)701     QueuedRedis& hscan(const StringView &key,
702                         long long cursor,
703                         const StringView &pattern) {
704         return hscan(key, cursor, pattern, 10);
705     }
706 
hscan(const StringView & key,long long cursor,long long count)707     QueuedRedis& hscan(const StringView &key,
708                         long long cursor,
709                         long long count) {
710         return hscan(key, cursor, "*", count);
711     }
712 
hscan(const StringView & key,long long cursor)713     QueuedRedis& hscan(const StringView &key,
714                         long long cursor) {
715         return hscan(key, cursor, "*", 10);
716     }
717 
hset(const StringView & key,const StringView & field,const StringView & val)718     QueuedRedis& hset(const StringView &key, const StringView &field, const StringView &val) {
719         return command(cmd::hset, key, field, val);
720     }
721 
hset(const StringView & key,const std::pair<StringView,StringView> & item)722     QueuedRedis& hset(const StringView &key, const std::pair<StringView, StringView> &item) {
723         return hset(key, item.first, item.second);
724     }
725 
hsetnx(const StringView & key,const StringView & field,const StringView & val)726     QueuedRedis& hsetnx(const StringView &key, const StringView &field, const StringView &val) {
727         return command(cmd::hsetnx, key, field, val);
728     }
729 
hsetnx(const StringView & key,const std::pair<StringView,StringView> & item)730     QueuedRedis& hsetnx(const StringView &key, const std::pair<StringView, StringView> &item) {
731         return hsetnx(key, item.first, item.second);
732     }
733 
hstrlen(const StringView & key,const StringView & field)734     QueuedRedis& hstrlen(const StringView &key, const StringView &field) {
735         return command(cmd::hstrlen, key, field);
736     }
737 
hvals(const StringView & key)738     QueuedRedis& hvals(const StringView &key) {
739         return command(cmd::hvals, key);
740     }
741 
742     // SET commands.
743 
sadd(const StringView & key,const StringView & member)744     QueuedRedis& sadd(const StringView &key, const StringView &member) {
745         return command(cmd::sadd, key, member);
746     }
747 
748     template <typename Input>
sadd(const StringView & key,Input first,Input last)749     QueuedRedis& sadd(const StringView &key, Input first, Input last) {
750         return command(cmd::sadd_range<Input>, key, first, last);
751     }
752 
753     template <typename T>
sadd(const StringView & key,std::initializer_list<T> il)754     QueuedRedis& sadd(const StringView &key, std::initializer_list<T> il) {
755         return sadd(key, il.begin(), il.end());
756     }
757 
scard(const StringView & key)758     QueuedRedis& scard(const StringView &key) {
759         return command(cmd::scard, key);
760     }
761 
762     template <typename Input>
sdiff(Input first,Input last)763     QueuedRedis& sdiff(Input first, Input last) {
764         return command(cmd::sdiff<Input>, first, last);
765     }
766 
767     template <typename T>
sdiff(std::initializer_list<T> il)768     QueuedRedis& sdiff(std::initializer_list<T> il) {
769         return sdiff(il.begin(), il.end());
770     }
771 
sdiffstore(const StringView & destination,const StringView & key)772     QueuedRedis& sdiffstore(const StringView &destination, const StringView &key) {
773         return command(cmd::sdiffstore, destination, key);
774     }
775 
776     template <typename Input>
sdiffstore(const StringView & destination,Input first,Input last)777     QueuedRedis& sdiffstore(const StringView &destination,
778                             Input first,
779                             Input last) {
780         return command(cmd::sdiffstore_range<Input>, destination, first, last);
781     }
782 
783     template <typename T>
sdiffstore(const StringView & destination,std::initializer_list<T> il)784     QueuedRedis& sdiffstore(const StringView &destination, std::initializer_list<T> il) {
785         return sdiffstore(destination, il.begin(), il.end());
786     }
787 
788     template <typename Input>
sinter(Input first,Input last)789     QueuedRedis& sinter(Input first, Input last) {
790         return command(cmd::sinter<Input>, first, last);
791     }
792 
793     template <typename T>
sinter(std::initializer_list<T> il)794     QueuedRedis& sinter(std::initializer_list<T> il) {
795         return sinter(il.begin(), il.end());
796     }
797 
sinterstore(const StringView & destination,const StringView & key)798     QueuedRedis& sinterstore(const StringView &destination, const StringView &key) {
799         return command(cmd::sinterstore, destination, key);
800     }
801 
802     template <typename Input>
sinterstore(const StringView & destination,Input first,Input last)803     QueuedRedis& sinterstore(const StringView &destination,
804                                 Input first,
805                                 Input last) {
806         return command(cmd::sinterstore_range<Input>, destination, first, last);
807     }
808 
809     template <typename T>
sinterstore(const StringView & destination,std::initializer_list<T> il)810     QueuedRedis& sinterstore(const StringView &destination, std::initializer_list<T> il) {
811         return sinterstore(destination, il.begin(), il.end());
812     }
813 
sismember(const StringView & key,const StringView & member)814     QueuedRedis& sismember(const StringView &key, const StringView &member) {
815         return command(cmd::sismember, key, member);
816     }
817 
smembers(const StringView & key)818     QueuedRedis& smembers(const StringView &key) {
819         return command(cmd::smembers, key);
820     }
821 
smove(const StringView & source,const StringView & destination,const StringView & member)822     QueuedRedis& smove(const StringView &source,
823                         const StringView &destination,
824                         const StringView &member) {
825         return command(cmd::smove, source, destination, member);
826     }
827 
spop(const StringView & key)828     QueuedRedis& spop(const StringView &key) {
829         return command(cmd::spop, key);
830     }
831 
spop(const StringView & key,long long count)832     QueuedRedis& spop(const StringView &key, long long count) {
833         return command(cmd::spop_range, key, count);
834     }
835 
srandmember(const StringView & key)836     QueuedRedis& srandmember(const StringView &key) {
837         return command(cmd::srandmember, key);
838     }
839 
srandmember(const StringView & key,long long count)840     QueuedRedis& srandmember(const StringView &key, long long count) {
841         return command(cmd::srandmember_range, key, count);
842     }
843 
srem(const StringView & key,const StringView & member)844     QueuedRedis& srem(const StringView &key, const StringView &member) {
845         return command(cmd::srem, key, member);
846     }
847 
848     template <typename Input>
srem(const StringView & key,Input first,Input last)849     QueuedRedis& srem(const StringView &key, Input first, Input last) {
850         return command(cmd::srem_range<Input>, key, first, last);
851     }
852 
853     template <typename T>
srem(const StringView & key,std::initializer_list<T> il)854     QueuedRedis& srem(const StringView &key, std::initializer_list<T> il) {
855         return srem(key, il.begin(), il.end());
856     }
857 
sscan(const StringView & key,long long cursor,const StringView & pattern,long long count)858     QueuedRedis& sscan(const StringView &key,
859                         long long cursor,
860                         const StringView &pattern,
861                         long long count) {
862         return command(cmd::sscan, key, cursor, pattern, count);
863     }
864 
sscan(const StringView & key,long long cursor,const StringView & pattern)865     QueuedRedis& sscan(const StringView &key,
866                     long long cursor,
867                     const StringView &pattern) {
868         return sscan(key, cursor, pattern, 10);
869     }
870 
sscan(const StringView & key,long long cursor,long long count)871     QueuedRedis& sscan(const StringView &key,
872                         long long cursor,
873                         long long count) {
874         return sscan(key, cursor, "*", count);
875     }
876 
sscan(const StringView & key,long long cursor)877     QueuedRedis& sscan(const StringView &key,
878                         long long cursor) {
879         return sscan(key, cursor, "*", 10);
880     }
881 
882     template <typename Input>
sunion(Input first,Input last)883     QueuedRedis& sunion(Input first, Input last) {
884         return command(cmd::sunion<Input>, first, last);
885     }
886 
887     template <typename T>
sunion(std::initializer_list<T> il)888     QueuedRedis& sunion(std::initializer_list<T> il) {
889         return sunion(il.begin(), il.end());
890     }
891 
sunionstore(const StringView & destination,const StringView & key)892     QueuedRedis& sunionstore(const StringView &destination, const StringView &key) {
893         return command(cmd::sunionstore, destination, key);
894     }
895 
896     template <typename Input>
sunionstore(const StringView & destination,Input first,Input last)897     QueuedRedis& sunionstore(const StringView &destination, Input first, Input last) {
898         return command(cmd::sunionstore_range<Input>, destination, first, last);
899     }
900 
901     template <typename T>
sunionstore(const StringView & destination,std::initializer_list<T> il)902     QueuedRedis& sunionstore(const StringView &destination, std::initializer_list<T> il) {
903         return sunionstore(destination, il.begin(), il.end());
904     }
905 
906     // SORTED SET commands.
907 
bzpopmax(const StringView & key,long long timeout)908     QueuedRedis& bzpopmax(const StringView &key, long long timeout) {
909         return command(cmd::bzpopmax, key, timeout);
910     }
911 
912     QueuedRedis& bzpopmax(const StringView &key,
913                     const std::chrono::seconds &timeout = std::chrono::seconds{0}) {
914         return bzpopmax(key, timeout.count());
915     }
916 
917     template <typename Input>
bzpopmax(Input first,Input last,long long timeout)918     QueuedRedis& bzpopmax(Input first, Input last, long long timeout) {
919         return command(cmd::bzpopmax_range<Input>, first, last, timeout);
920     }
921 
922     template <typename Input>
923     QueuedRedis& bzpopmax(Input first,
924                             Input last,
925                             const std::chrono::seconds &timeout = std::chrono::seconds{0}) {
926         return bzpopmax(first, last, timeout.count());
927     }
928 
929     template <typename T>
bzpopmax(std::initializer_list<T> il,long long timeout)930     QueuedRedis& bzpopmax(std::initializer_list<T> il, long long timeout) {
931         return bzpopmax(il.begin(), il.end(), timeout);
932     }
933 
934     template <typename T>
935     QueuedRedis& bzpopmax(std::initializer_list<T> il,
936                             const std::chrono::seconds &timeout = std::chrono::seconds{0}) {
937         return bzpopmax(il.begin(), il.end(), timeout);
938     }
939 
bzpopmin(const StringView & key,long long timeout)940     QueuedRedis& bzpopmin(const StringView &key, long long timeout) {
941         return command(cmd::bzpopmin, key, timeout);
942     }
943 
944     QueuedRedis& bzpopmin(const StringView &key,
945                             const std::chrono::seconds &timeout = std::chrono::seconds{0}) {
946         return bzpopmin(key, timeout.count());
947     }
948 
949     template <typename Input>
bzpopmin(Input first,Input last,long long timeout)950     QueuedRedis& bzpopmin(Input first, Input last, long long timeout) {
951         return command(cmd::bzpopmin_range<Input>, first, last, timeout);
952     }
953 
954     template <typename Input>
955     QueuedRedis& bzpopmin(Input first,
956                             Input last,
957                             const std::chrono::seconds &timeout = std::chrono::seconds{0}) {
958         return bzpopmin(first, last, timeout.count());
959     }
960 
961     template <typename T>
bzpopmin(std::initializer_list<T> il,long long timeout)962     QueuedRedis& bzpopmin(std::initializer_list<T> il, long long timeout) {
963         return bzpopmin(il.begin(), il.end(), timeout);
964     }
965 
966     template <typename T>
967     QueuedRedis& bzpopmin(std::initializer_list<T> il,
968                             const std::chrono::seconds &timeout = std::chrono::seconds{0}) {
969         return bzpopmin(il.begin(), il.end(), timeout);
970     }
971 
972     // We don't support the INCR option, since you can always use ZINCRBY instead.
973     QueuedRedis& zadd(const StringView &key,
974                         const StringView &member,
975                         double score,
976                         UpdateType type = UpdateType::ALWAYS,
977                         bool changed = false) {
978         return command(cmd::zadd, key, member, score, type, changed);
979     }
980 
981     template <typename Input>
982     QueuedRedis& zadd(const StringView &key,
983                         Input first,
984                         Input last,
985                         UpdateType type = UpdateType::ALWAYS,
986                         bool changed = false) {
987         return command(cmd::zadd_range<Input>, key, first, last, type, changed);
988     }
989 
zcard(const StringView & key)990     QueuedRedis& zcard(const StringView &key) {
991         return command(cmd::zcard, key);
992     }
993 
994     template <typename Interval>
zcount(const StringView & key,const Interval & interval)995     QueuedRedis& zcount(const StringView &key, const Interval &interval) {
996         return command(cmd::zcount<Interval>, key, interval);
997     }
998 
zincrby(const StringView & key,double increment,const StringView & member)999     QueuedRedis& zincrby(const StringView &key, double increment, const StringView &member) {
1000         return command(cmd::zincrby, key, increment, member);
1001     }
1002 
zinterstore(const StringView & destination,const StringView & key,double weight)1003     QueuedRedis& zinterstore(const StringView &destination,
1004                                 const StringView &key,
1005                                 double weight) {
1006         return command(cmd::zinterstore, destination, key, weight);
1007     }
1008 
1009     template <typename Input>
1010     QueuedRedis& zinterstore(const StringView &destination,
1011                                 Input first,
1012                                 Input last,
1013                                 Aggregation type = Aggregation::SUM) {
1014         return command(cmd::zinterstore_range<Input>, destination, first, last, type);
1015     }
1016 
1017     template <typename T>
1018     QueuedRedis& zinterstore(const StringView &destination,
1019                                 std::initializer_list<T> il,
1020                                 Aggregation type = Aggregation::SUM) {
1021         return zinterstore(destination, il.begin(), il.end(), type);
1022     }
1023 
1024     template <typename Interval>
zlexcount(const StringView & key,const Interval & interval)1025     QueuedRedis& zlexcount(const StringView &key, const Interval &interval) {
1026         return command(cmd::zlexcount<Interval>, key, interval);
1027     }
1028 
zpopmax(const StringView & key)1029     QueuedRedis& zpopmax(const StringView &key) {
1030         return command(cmd::zpopmax, key, 1);
1031     }
1032 
zpopmax(const StringView & key,long long count)1033     QueuedRedis& zpopmax(const StringView &key, long long count) {
1034         return command(cmd::zpopmax, key, count);
1035     }
1036 
zpopmin(const StringView & key)1037     QueuedRedis& zpopmin(const StringView &key) {
1038         return command(cmd::zpopmin, key, 1);
1039     }
1040 
zpopmin(const StringView & key,long long count)1041     QueuedRedis& zpopmin(const StringView &key, long long count) {
1042         return command(cmd::zpopmin, key, count);
1043     }
1044 
1045     // NOTE: *QueuedRedis::zrange*'s parameters are different from *Redis::zrange*.
1046     // *Redis::zrange* is overloaded by the output iterator, however, there's no such
1047     // iterator in *QueuedRedis::zrange*. So we have to use an extra parameter: *with_scores*,
1048     // to decide whether we should send *WITHSCORES* option to Redis. This also applies to
1049     // other commands with the *WITHSCORES* option, e.g. *ZRANGEBYSCORE*, *ZREVRANGE*,
1050     // *ZREVRANGEBYSCORE*.
1051     QueuedRedis& zrange(const StringView &key,
1052                         long long start,
1053                         long long stop,
1054                         bool with_scores = false) {
1055         return command(cmd::zrange, key, start, stop, with_scores);
1056     }
1057 
1058     template <typename Interval>
zrangebylex(const StringView & key,const Interval & interval,const LimitOptions & opts)1059     QueuedRedis& zrangebylex(const StringView &key,
1060                                 const Interval &interval,
1061                                 const LimitOptions &opts) {
1062         return command(cmd::zrangebylex<Interval>, key, interval, opts);
1063     }
1064 
1065     template <typename Interval>
zrangebylex(const StringView & key,const Interval & interval)1066     QueuedRedis& zrangebylex(const StringView &key, const Interval &interval) {
1067         return zrangebylex(key, interval, {});
1068     }
1069 
1070     // See comments on *ZRANGE*.
1071     template <typename Interval>
1072     QueuedRedis& zrangebyscore(const StringView &key,
1073                                 const Interval &interval,
1074                                 const LimitOptions &opts,
1075                                 bool with_scores = false) {
1076         return command(cmd::zrangebyscore<Interval>, key, interval, opts, with_scores);
1077     }
1078 
1079     // See comments on *ZRANGE*.
1080     template <typename Interval>
1081     QueuedRedis& zrangebyscore(const StringView &key,
1082                                 const Interval &interval,
1083                                 bool with_scores = false) {
1084         return zrangebyscore(key, interval, {}, with_scores);
1085     }
1086 
zrank(const StringView & key,const StringView & member)1087     QueuedRedis& zrank(const StringView &key, const StringView &member) {
1088         return command(cmd::zrank, key, member);
1089     }
1090 
zrem(const StringView & key,const StringView & member)1091     QueuedRedis& zrem(const StringView &key, const StringView &member) {
1092         return command(cmd::zrem, key, member);
1093     }
1094 
1095     template <typename Input>
zrem(const StringView & key,Input first,Input last)1096     QueuedRedis& zrem(const StringView &key, Input first, Input last) {
1097         return command(cmd::zrem_range<Input>, key, first, last);
1098     }
1099 
1100     template <typename T>
zrem(const StringView & key,std::initializer_list<T> il)1101     QueuedRedis& zrem(const StringView &key, std::initializer_list<T> il) {
1102         return zrem(key, il.begin(), il.end());
1103     }
1104 
1105     template <typename Interval>
zremrangebylex(const StringView & key,const Interval & interval)1106     QueuedRedis& zremrangebylex(const StringView &key, const Interval &interval) {
1107         return command(cmd::zremrangebylex<Interval>, key, interval);
1108     }
1109 
zremrangebyrank(const StringView & key,long long start,long long stop)1110     QueuedRedis& zremrangebyrank(const StringView &key, long long start, long long stop) {
1111         return command(cmd::zremrangebyrank, key, start, stop);
1112     }
1113 
1114     template <typename Interval>
zremrangebyscore(const StringView & key,const Interval & interval)1115     QueuedRedis& zremrangebyscore(const StringView &key, const Interval &interval) {
1116         return command(cmd::zremrangebyscore<Interval>, key, interval);
1117     }
1118 
1119     // See comments on *ZRANGE*.
1120     QueuedRedis& zrevrange(const StringView &key,
1121                             long long start,
1122                             long long stop,
1123                             bool with_scores = false) {
1124         return command(cmd::zrevrange, key, start, stop, with_scores);
1125     }
1126 
1127     template <typename Interval>
zrevrangebylex(const StringView & key,const Interval & interval,const LimitOptions & opts)1128     QueuedRedis& zrevrangebylex(const StringView &key,
1129                                 const Interval &interval,
1130                                 const LimitOptions &opts) {
1131         return command(cmd::zrevrangebylex<Interval>, key, interval, opts);
1132     }
1133 
1134     template <typename Interval>
zrevrangebylex(const StringView & key,const Interval & interval)1135     QueuedRedis& zrevrangebylex(const StringView &key, const Interval &interval) {
1136         return zrevrangebylex(key, interval, {});
1137     }
1138 
1139     // See comments on *ZRANGE*.
1140     template <typename Interval>
1141     QueuedRedis& zrevrangebyscore(const StringView &key,
1142                                     const Interval &interval,
1143                                     const LimitOptions &opts,
1144                                     bool with_scores = false) {
1145         return command(cmd::zrevrangebyscore<Interval>, key, interval, opts, with_scores);
1146     }
1147 
1148     // See comments on *ZRANGE*.
1149     template <typename Interval>
1150     QueuedRedis& zrevrangebyscore(const StringView &key,
1151                                     const Interval &interval,
1152                                     bool with_scores = false) {
1153         return zrevrangebyscore(key, interval, {}, with_scores);
1154     }
1155 
zrevrank(const StringView & key,const StringView & member)1156     QueuedRedis& zrevrank(const StringView &key, const StringView &member) {
1157         return command(cmd::zrevrank, key, member);
1158     }
1159 
zscan(const StringView & key,long long cursor,const StringView & pattern,long long count)1160     QueuedRedis& zscan(const StringView &key,
1161                         long long cursor,
1162                         const StringView &pattern,
1163                         long long count) {
1164         return command(cmd::zscan, key, cursor, pattern, count);
1165     }
1166 
zscan(const StringView & key,long long cursor,const StringView & pattern)1167     QueuedRedis& zscan(const StringView &key,
1168                         long long cursor,
1169                         const StringView &pattern) {
1170         return zscan(key, cursor, pattern, 10);
1171     }
1172 
zscan(const StringView & key,long long cursor,long long count)1173     QueuedRedis& zscan(const StringView &key,
1174                         long long cursor,
1175                         long long count) {
1176         return zscan(key, cursor, "*", count);
1177     }
1178 
zscan(const StringView & key,long long cursor)1179     QueuedRedis& zscan(const StringView &key,
1180                         long long cursor) {
1181         return zscan(key, cursor, "*", 10);
1182     }
1183 
zscore(const StringView & key,const StringView & member)1184     QueuedRedis& zscore(const StringView &key, const StringView &member) {
1185         return command(cmd::zscore, key, member);
1186     }
1187 
zunionstore(const StringView & destination,const StringView & key,double weight)1188     QueuedRedis& zunionstore(const StringView &destination,
1189                                 const StringView &key,
1190                                 double weight) {
1191         return command(cmd::zunionstore, destination, key, weight);
1192     }
1193 
1194     template <typename Input>
1195     QueuedRedis& zunionstore(const StringView &destination,
1196                                 Input first,
1197                                 Input last,
1198                                 Aggregation type = Aggregation::SUM) {
1199         return command(cmd::zunionstore_range<Input>, destination, first, last, type);
1200     }
1201 
1202     template <typename T>
1203     QueuedRedis& zunionstore(const StringView &destination,
1204                                 std::initializer_list<T> il,
1205                                 Aggregation type = Aggregation::SUM) {
1206         return zunionstore(destination, il.begin(), il.end(), type);
1207     }
1208 
1209     // HYPERLOGLOG commands.
1210 
pfadd(const StringView & key,const StringView & element)1211     QueuedRedis& pfadd(const StringView &key, const StringView &element) {
1212         return command(cmd::pfadd, key, element);
1213     }
1214 
1215     template <typename Input>
pfadd(const StringView & key,Input first,Input last)1216     QueuedRedis& pfadd(const StringView &key, Input first, Input last) {
1217         return command(cmd::pfadd_range<Input>, key, first, last);
1218     }
1219 
1220     template <typename T>
pfadd(const StringView & key,std::initializer_list<T> il)1221     QueuedRedis& pfadd(const StringView &key, std::initializer_list<T> il) {
1222         return pfadd(key, il.begin(), il.end());
1223     }
1224 
pfcount(const StringView & key)1225     QueuedRedis& pfcount(const StringView &key) {
1226         return command(cmd::pfcount, key);
1227     }
1228 
1229     template <typename Input>
pfcount(Input first,Input last)1230     QueuedRedis& pfcount(Input first, Input last) {
1231         return command(cmd::pfcount_range<Input>, first, last);
1232     }
1233 
1234     template <typename T>
pfcount(std::initializer_list<T> il)1235     QueuedRedis& pfcount(std::initializer_list<T> il) {
1236         return pfcount(il.begin(), il.end());
1237     }
1238 
pfmerge(const StringView & destination,const StringView & key)1239     QueuedRedis& pfmerge(const StringView &destination, const StringView &key) {
1240         return command(cmd::pfmerge, destination, key);
1241     }
1242 
1243     template <typename Input>
pfmerge(const StringView & destination,Input first,Input last)1244     QueuedRedis& pfmerge(const StringView &destination, Input first, Input last) {
1245         return command(cmd::pfmerge_range<Input>, destination, first, last);
1246     }
1247 
1248     template <typename T>
pfmerge(const StringView & destination,std::initializer_list<T> il)1249     QueuedRedis& pfmerge(const StringView &destination, std::initializer_list<T> il) {
1250         return pfmerge(destination, il.begin(), il.end());
1251     }
1252 
1253     // GEO commands.
1254 
geoadd(const StringView & key,const std::tuple<StringView,double,double> & member)1255     QueuedRedis& geoadd(const StringView &key,
1256                         const std::tuple<StringView, double, double> &member) {
1257         return command(cmd::geoadd, key, member);
1258     }
1259 
1260     template <typename Input>
geoadd(const StringView & key,Input first,Input last)1261     QueuedRedis& geoadd(const StringView &key,
1262                         Input first,
1263                         Input last) {
1264         return command(cmd::geoadd_range<Input>, key, first, last);
1265     }
1266 
1267     template <typename T>
geoadd(const StringView & key,std::initializer_list<T> il)1268     QueuedRedis& geoadd(const StringView &key, std::initializer_list<T> il) {
1269         return geoadd(key, il.begin(), il.end());
1270     }
1271 
1272     QueuedRedis& geodist(const StringView &key,
1273                             const StringView &member1,
1274                             const StringView &member2,
1275                             GeoUnit unit = GeoUnit::M) {
1276         return command(cmd::geodist, key, member1, member2, unit);
1277     }
1278 
1279     template <typename Input>
geohash(const StringView & key,Input first,Input last)1280     QueuedRedis& geohash(const StringView &key, Input first, Input last) {
1281         return command(cmd::geohash_range<Input>, key, first, last);
1282     }
1283 
1284     template <typename T>
geohash(const StringView & key,std::initializer_list<T> il)1285     QueuedRedis& geohash(const StringView &key, std::initializer_list<T> il) {
1286         return geohash(key, il.begin(), il.end());
1287     }
1288 
1289     template <typename Input>
geopos(const StringView & key,Input first,Input last)1290     QueuedRedis& geopos(const StringView &key, Input first, Input last) {
1291         return command(cmd::geopos_range<Input>, key, first, last);
1292     }
1293 
1294     template <typename T>
geopos(const StringView & key,std::initializer_list<T> il)1295     QueuedRedis& geopos(const StringView &key, std::initializer_list<T> il) {
1296         return geopos(key, il.begin(), il.end());
1297     }
1298 
1299     // TODO:
1300     // 1. since we have different overloads for georadius and georadius-store,
1301     //    we might use the GEORADIUS_RO command in the future.
1302     // 2. there're too many parameters for this method, we might refactor it.
georadius(const StringView & key,const std::pair<double,double> & loc,double radius,GeoUnit unit,const StringView & destination,bool store_dist,long long count)1303     QueuedRedis& georadius(const StringView &key,
1304                             const std::pair<double, double> &loc,
1305                             double radius,
1306                             GeoUnit unit,
1307                             const StringView &destination,
1308                             bool store_dist,
1309                             long long count) {
1310         _georadius_cmd_indexes.push_back(_cmd_num);
1311 
1312         return command(cmd::georadius_store,
1313                         key,
1314                         loc,
1315                         radius,
1316                         unit,
1317                         destination,
1318                         store_dist,
1319                         count);
1320     }
1321 
1322     // NOTE: *QueuedRedis::georadius*'s parameters are different from *Redis::georadius*.
1323     // *Redis::georadius* is overloaded by the output iterator, however, there's no such
1324     // iterator in *QueuedRedis::georadius*. So we have to use extra parameters to decide
1325     // whether we should send options to Redis. This also applies to *GEORADIUSBYMEMBER*.
georadius(const StringView & key,const std::pair<double,double> & loc,double radius,GeoUnit unit,long long count,bool asc,bool with_coord,bool with_dist,bool with_hash)1326     QueuedRedis& georadius(const StringView &key,
1327                             const std::pair<double, double> &loc,
1328                             double radius,
1329                             GeoUnit unit,
1330                             long long count,
1331                             bool asc,
1332                             bool with_coord,
1333                             bool with_dist,
1334                             bool with_hash) {
1335         return command(cmd::georadius,
1336                         key,
1337                         loc,
1338                         radius,
1339                         unit,
1340                         count,
1341                         asc,
1342                         with_coord,
1343                         with_dist,
1344                         with_hash);
1345     }
1346 
georadiusbymember(const StringView & key,const StringView & member,double radius,GeoUnit unit,const StringView & destination,bool store_dist,long long count)1347     QueuedRedis& georadiusbymember(const StringView &key,
1348                                     const StringView &member,
1349                                     double radius,
1350                                     GeoUnit unit,
1351                                     const StringView &destination,
1352                                     bool store_dist,
1353                                     long long count) {
1354         _georadius_cmd_indexes.push_back(_cmd_num);
1355 
1356         return command(cmd::georadiusbymember,
1357                         key,
1358                         member,
1359                         radius,
1360                         unit,
1361                         destination,
1362                         store_dist,
1363                         count);
1364     }
1365 
1366     // See the comments on *GEORADIUS*.
georadiusbymember(const StringView & key,const StringView & member,double radius,GeoUnit unit,long long count,bool asc,bool with_coord,bool with_dist,bool with_hash)1367     QueuedRedis& georadiusbymember(const StringView &key,
1368                                     const StringView &member,
1369                                     double radius,
1370                                     GeoUnit unit,
1371                                     long long count,
1372                                     bool asc,
1373                                     bool with_coord,
1374                                     bool with_dist,
1375                                     bool with_hash) {
1376         return command(cmd::georadiusbymember,
1377                         key,
1378                         member,
1379                         radius,
1380                         unit,
1381                         count,
1382                         asc,
1383                         with_coord,
1384                         with_dist,
1385                         with_hash);
1386     }
1387 
1388     // SCRIPTING commands.
1389 
eval(const StringView & script,std::initializer_list<StringView> keys,std::initializer_list<StringView> args)1390     QueuedRedis& eval(const StringView &script,
1391                         std::initializer_list<StringView> keys,
1392                         std::initializer_list<StringView> args) {
1393         return command(cmd::eval, script, keys, args);
1394     }
1395 
evalsha(const StringView & script,std::initializer_list<StringView> keys,std::initializer_list<StringView> args)1396     QueuedRedis& evalsha(const StringView &script,
1397                             std::initializer_list<StringView> keys,
1398                             std::initializer_list<StringView> args) {
1399         return command(cmd::evalsha, script, keys, args);
1400     }
1401 
1402     template <typename Input>
script_exists(Input first,Input last)1403     QueuedRedis& script_exists(Input first, Input last) {
1404         return command(cmd::script_exists_range<Input>, first, last);
1405     }
1406 
1407     template <typename T>
script_exists(std::initializer_list<T> il)1408     QueuedRedis& script_exists(std::initializer_list<T> il) {
1409         return script_exists(il.begin(), il.end());
1410     }
1411 
script_flush()1412     QueuedRedis& script_flush() {
1413         return command(cmd::script_flush);
1414     }
1415 
script_kill()1416     QueuedRedis& script_kill() {
1417         return command(cmd::script_kill);
1418     }
1419 
script_load(const StringView & script)1420     QueuedRedis& script_load(const StringView &script) {
1421         return command(cmd::script_load, script);
1422     }
1423 
1424     // PUBSUB commands.
1425 
publish(const StringView & channel,const StringView & message)1426     QueuedRedis& publish(const StringView &channel, const StringView &message) {
1427         return command(cmd::publish, channel, message);
1428     }
1429 
1430     // Stream commands.
1431 
xack(const StringView & key,const StringView & group,const StringView & id)1432     QueuedRedis& xack(const StringView &key, const StringView &group, const StringView &id) {
1433         return command(cmd::xack, key, group, id);
1434     }
1435 
1436     template <typename Input>
xack(const StringView & key,const StringView & group,Input first,Input last)1437     QueuedRedis& xack(const StringView &key, const StringView &group, Input first, Input last) {
1438         return command(cmd::xack_range<Input>, key, group, first, last);
1439     }
1440 
1441     template <typename T>
xack(const StringView & key,const StringView & group,std::initializer_list<T> il)1442     QueuedRedis& xack(const StringView &key, const StringView &group, std::initializer_list<T> il) {
1443         return xack(key, group, il.begin(), il.end());
1444     }
1445 
1446     template <typename Input>
xadd(const StringView & key,const StringView & id,Input first,Input last)1447     QueuedRedis& xadd(const StringView &key, const StringView &id, Input first, Input last) {
1448         return command(cmd::xadd_range<Input>, key, id, first, last);
1449     }
1450 
1451     template <typename T>
xadd(const StringView & key,const StringView & id,std::initializer_list<T> il)1452     QueuedRedis& xadd(const StringView &key, const StringView &id, std::initializer_list<T> il) {
1453         return xadd(key, id, il.begin(), il.end());
1454     }
1455 
1456     template <typename Input>
1457     QueuedRedis& xadd(const StringView &key,
1458                         const StringView &id,
1459                         Input first,
1460                         Input last,
1461                         long long count,
1462                         bool approx = true) {
1463         return command(cmd::xadd_maxlen_range<Input>, key, id, first, last, count, approx);
1464     }
1465 
1466     template <typename T>
1467     QueuedRedis& xadd(const StringView &key,
1468                         const StringView &id,
1469                         std::initializer_list<T> il,
1470                         long long count,
1471                         bool approx = true) {
1472         return xadd(key, id, il.begin(), il.end(), count, approx);
1473     }
1474 
xclaim(const StringView & key,const StringView & group,const StringView & consumer,const std::chrono::milliseconds & min_idle_time,const StringView & id)1475     QueuedRedis& xclaim(const StringView &key,
1476                         const StringView &group,
1477                         const StringView &consumer,
1478                         const std::chrono::milliseconds &min_idle_time,
1479                         const StringView &id) {
1480         return command(cmd::xclaim, key, group, consumer, min_idle_time.count(), id);
1481     }
1482 
1483     template <typename Input>
xclaim(const StringView & key,const StringView & group,const StringView & consumer,const std::chrono::milliseconds & min_idle_time,Input first,Input last)1484     QueuedRedis& xclaim(const StringView &key,
1485                 const StringView &group,
1486                 const StringView &consumer,
1487                 const std::chrono::milliseconds &min_idle_time,
1488                 Input first,
1489                 Input last) {
1490         return command(cmd::xclaim_range<Input>,
1491                         key,
1492                         group,
1493                         consumer,
1494                         min_idle_time.count(),
1495                         first,
1496                         last);
1497     }
1498 
1499     template <typename T>
xclaim(const StringView & key,const StringView & group,const StringView & consumer,const std::chrono::milliseconds & min_idle_time,std::initializer_list<T> il)1500     QueuedRedis& xclaim(const StringView &key,
1501                 const StringView &group,
1502                 const StringView &consumer,
1503                 const std::chrono::milliseconds &min_idle_time,
1504                 std::initializer_list<T> il) {
1505         return xclaim(key, group, consumer, min_idle_time, il.begin(), il.end());
1506     }
1507 
xdel(const StringView & key,const StringView & id)1508     QueuedRedis& xdel(const StringView &key, const StringView &id) {
1509         return command(cmd::xdel, key, id);
1510     }
1511 
1512     template <typename Input>
xdel(const StringView & key,Input first,Input last)1513     QueuedRedis& xdel(const StringView &key, Input first, Input last) {
1514         return command(cmd::xdel_range<Input>, key, first, last);
1515     }
1516 
1517     template <typename T>
xdel(const StringView & key,std::initializer_list<T> il)1518     QueuedRedis& xdel(const StringView &key, std::initializer_list<T> il) {
1519         return xdel(key, il.begin(), il.end());
1520     }
1521 
1522     QueuedRedis& xgroup_create(const StringView &key,
1523                                 const StringView &group,
1524                                 const StringView &id,
1525                                 bool mkstream = false) {
1526         return command(cmd::xgroup_create, key, group, id, mkstream);
1527     }
1528 
xgroup_setid(const StringView & key,const StringView & group,const StringView & id)1529     QueuedRedis& xgroup_setid(const StringView &key,
1530                                 const StringView &group,
1531                                 const StringView &id) {
1532         return command(cmd::xgroup_setid, key, group, id);
1533     }
1534 
xgroup_destroy(const StringView & key,const StringView & group)1535     QueuedRedis& xgroup_destroy(const StringView &key, const StringView &group) {
1536         return command(cmd::xgroup_destroy, key, group);
1537     }
1538 
xgroup_delconsumer(const StringView & key,const StringView & group,const StringView & consumer)1539     QueuedRedis& xgroup_delconsumer(const StringView &key,
1540                                     const StringView &group,
1541                                     const StringView &consumer) {
1542         return command(cmd::xgroup_delconsumer, key, group, consumer);
1543     }
1544 
xlen(const StringView & key)1545     QueuedRedis& xlen(const StringView &key) {
1546         return command(cmd::xlen, key);
1547     }
1548 
xpending(const StringView & key,const StringView & group)1549     QueuedRedis& xpending(const StringView &key, const StringView &group) {
1550         return command(cmd::xpending, key, group);
1551     }
1552 
xpending(const StringView & key,const StringView & group,const StringView & start,const StringView & end,long long count)1553     QueuedRedis& xpending(const StringView &key,
1554                             const StringView &group,
1555                             const StringView &start,
1556                             const StringView &end,
1557                             long long count) {
1558         return command(cmd::xpending_detail, key, group, start, end, count);
1559     }
1560 
xpending(const StringView & key,const StringView & group,const StringView & start,const StringView & end,long long count,const StringView & consumer)1561     QueuedRedis& xpending(const StringView &key,
1562                             const StringView &group,
1563                             const StringView &start,
1564                             const StringView &end,
1565                             long long count,
1566                             const StringView &consumer) {
1567         return command(cmd::xpending_per_consumer, key, group, start, end, count, consumer);
1568     }
1569 
xrange(const StringView & key,const StringView & start,const StringView & end)1570     QueuedRedis& xrange(const StringView &key,
1571                         const StringView &start,
1572                         const StringView &end) {
1573         return command(cmd::xrange, key, start, end);
1574     }
1575 
xrange(const StringView & key,const StringView & start,const StringView & end,long long count)1576     QueuedRedis& xrange(const StringView &key,
1577                         const StringView &start,
1578                         const StringView &end,
1579                         long long count) {
1580         return command(cmd::xrange, key, start, end, count);
1581     }
1582 
xread(const StringView & key,const StringView & id,long long count)1583     QueuedRedis& xread(const StringView &key, const StringView &id, long long count) {
1584         return command(cmd::xread, key, id, count);
1585     }
1586 
xread(const StringView & key,const StringView & id)1587     QueuedRedis& xread(const StringView &key, const StringView &id) {
1588         return xread(key, id, 0);
1589     }
1590 
1591     template <typename Input>
1592     auto xread(Input first, Input last, long long count)
1593         -> typename std::enable_if<!std::is_convertible<Input, StringView>::value,
1594                                     QueuedRedis&>::type {
1595         return command(cmd::xread_range<Input>, first, last, count);
1596     }
1597 
1598     template <typename Input>
1599     auto xread(Input first, Input last)
1600         -> typename std::enable_if<!std::is_convertible<Input, StringView>::value,
1601                                     QueuedRedis&>::type {
1602         return xread(first, last, 0);
1603     }
1604 
xread(const StringView & key,const StringView & id,const std::chrono::milliseconds & timeout,long long count)1605     QueuedRedis& xread(const StringView &key,
1606                         const StringView &id,
1607                         const std::chrono::milliseconds &timeout,
1608                         long long count) {
1609         return command(cmd::xread_block, key, id, timeout.count(), count);
1610     }
1611 
xread(const StringView & key,const StringView & id,const std::chrono::milliseconds & timeout)1612     QueuedRedis& xread(const StringView &key,
1613                         const StringView &id,
1614                         const std::chrono::milliseconds &timeout) {
1615         return xread(key, id, timeout, 0);
1616     }
1617 
1618     template <typename Input>
1619     auto xread(Input first,
1620                 Input last,
1621                 const std::chrono::milliseconds &timeout,
1622                 long long count)
1623         -> typename std::enable_if<!std::is_convertible<Input, StringView>::value,
1624                                     QueuedRedis&>::type {
1625         return command(cmd::xread_block_range<Input>, first, last, timeout.count(), count);
1626     }
1627 
1628     template <typename Input>
1629     auto xread(Input first,
1630                 Input last,
1631                 const std::chrono::milliseconds &timeout)
1632         -> typename std::enable_if<!std::is_convertible<Input, StringView>::value,
1633                                     QueuedRedis&>::type {
1634         return xread(first, last, timeout, 0);
1635     }
1636 
xreadgroup(const StringView & group,const StringView & consumer,const StringView & key,const StringView & id,long long count,bool noack)1637     QueuedRedis& xreadgroup(const StringView &group,
1638                             const StringView &consumer,
1639                             const StringView &key,
1640                             const StringView &id,
1641                             long long count,
1642                             bool noack) {
1643         return command(cmd::xreadgroup, group, consumer, key, id, count, noack);
1644     }
1645 
xreadgroup(const StringView & group,const StringView & consumer,const StringView & key,const StringView & id,long long count)1646     QueuedRedis& xreadgroup(const StringView &group,
1647                             const StringView &consumer,
1648                             const StringView &key,
1649                             const StringView &id,
1650                             long long count) {
1651         return xreadgroup(group, consumer, key, id, count, false);
1652     }
1653 
1654     template <typename Input>
1655     auto xreadgroup(const StringView &group,
1656                     const StringView &consumer,
1657                     Input first,
1658                     Input last,
1659                     long long count,
1660                     bool noack)
1661         -> typename std::enable_if<!std::is_convertible<Input, StringView>::value,
1662                                     QueuedRedis&>::type {
1663         return command(cmd::xreadgroup_range<Input>, group, consumer, first, last, count, noack);
1664     }
1665 
1666     template <typename Input>
1667     auto xreadgroup(const StringView &group,
1668                     const StringView &consumer,
1669                     Input first,
1670                     Input last,
1671                     long long count)
1672         -> typename std::enable_if<!std::is_convertible<Input, StringView>::value,
1673                                     QueuedRedis&>::type {
1674         return xreadgroup(group, consumer, first ,last, count, false);
1675     }
1676 
1677     template <typename Input>
1678     auto xreadgroup(const StringView &group,
1679                     const StringView &consumer,
1680                     Input first,
1681                     Input last)
1682         -> typename std::enable_if<!std::is_convertible<Input, StringView>::value,
1683                                     QueuedRedis&>::type {
1684         return xreadgroup(group, consumer, first ,last, 0, false);
1685     }
1686 
xreadgroup(const StringView & group,const StringView & consumer,const StringView & key,const StringView & id,const std::chrono::milliseconds & timeout,long long count,bool noack)1687     QueuedRedis& xreadgroup(const StringView &group,
1688                             const StringView &consumer,
1689                             const StringView &key,
1690                             const StringView &id,
1691                             const std::chrono::milliseconds &timeout,
1692                             long long count,
1693                             bool noack) {
1694         return command(cmd::xreadgroup_block,
1695                         group,
1696                         consumer,
1697                         key,
1698                         id,
1699                         timeout.count(),
1700                         count,
1701                         noack);
1702     }
1703 
xreadgroup(const StringView & group,const StringView & consumer,const StringView & key,const StringView & id,const std::chrono::milliseconds & timeout,long long count)1704     QueuedRedis& xreadgroup(const StringView &group,
1705                             const StringView &consumer,
1706                             const StringView &key,
1707                             const StringView &id,
1708                             const std::chrono::milliseconds &timeout,
1709                             long long count) {
1710         return xreadgroup(group, consumer, key, id, timeout, count, false);
1711     }
1712 
xreadgroup(const StringView & group,const StringView & consumer,const StringView & key,const StringView & id,const std::chrono::milliseconds & timeout)1713     QueuedRedis& xreadgroup(const StringView &group,
1714                             const StringView &consumer,
1715                             const StringView &key,
1716                             const StringView &id,
1717                             const std::chrono::milliseconds &timeout) {
1718         return xreadgroup(group, consumer, key, id, timeout, 0, false);
1719     }
1720 
1721     template <typename Input>
1722     auto xreadgroup(const StringView &group,
1723                     const StringView &consumer,
1724                     Input first,
1725                     Input last,
1726                     const std::chrono::milliseconds &timeout,
1727                     long long count,
1728                     bool noack)
1729         -> typename std::enable_if<!std::is_convertible<Input, StringView>::value,
1730                                     QueuedRedis&>::type {
1731         return command(cmd::xreadgroup_block_range<Input>,
1732                         group,
1733                         consumer,
1734                         first,
1735                         last,
1736                         timeout.count(),
1737                         count,
1738                         noack);
1739     }
1740 
1741     template <typename Input>
1742     auto xreadgroup(const StringView &group,
1743                     const StringView &consumer,
1744                     Input first,
1745                     Input last,
1746                     const std::chrono::milliseconds &timeout,
1747                     long long count)
1748         -> typename std::enable_if<!std::is_convertible<Input, StringView>::value,
1749                                     QueuedRedis&>::type {
1750         return xreadgroup(group, consumer, first, last, timeout, count, false);
1751     }
1752 
1753     template <typename Input>
1754     auto xreadgroup(const StringView &group,
1755                     const StringView &consumer,
1756                     Input first,
1757                     Input last,
1758                     const std::chrono::milliseconds &timeout)
1759         -> typename std::enable_if<!std::is_convertible<Input, StringView>::value,
1760                                     QueuedRedis&>::type {
1761         return xreadgroup(group, consumer, first, last, timeout, 0, false);
1762     }
1763 
xrevrange(const StringView & key,const StringView & end,const StringView & start)1764     QueuedRedis& xrevrange(const StringView &key,
1765                             const StringView &end,
1766                             const StringView &start) {
1767         return command(cmd::xrevrange, key, end, start);
1768     }
1769 
xrevrange(const StringView & key,const StringView & end,const StringView & start,long long count)1770     QueuedRedis& xrevrange(const StringView &key,
1771                             const StringView &end,
1772                             const StringView &start,
1773                             long long count) {
1774         return command(cmd::xrevrange, key, end, start, count);
1775     }
1776 
1777     QueuedRedis& xtrim(const StringView &key, long long count, bool approx = true) {
1778         return command(cmd::xtrim, key, count, approx);
1779     }
1780 
1781 private:
1782     friend class Redis;
1783 
1784     friend class RedisCluster;
1785 
1786     template <typename ...Args>
1787     QueuedRedis(const ConnectionSPtr &connection, Args &&...args);
1788 
1789     void _sanity_check() const;
1790 
1791     void _reset();
1792 
1793     void _invalidate();
1794 
1795     void _rewrite_replies(std::vector<ReplyUPtr> &replies) const;
1796 
1797     template <typename Func>
1798     void _rewrite_replies(const std::vector<std::size_t> &indexes,
1799                             Func rewriter,
1800                             std::vector<ReplyUPtr> &replies) const;
1801 
1802     ConnectionSPtr _connection;
1803 
1804     Impl _impl;
1805 
1806     std::size_t _cmd_num = 0;
1807 
1808     std::vector<std::size_t> _set_cmd_indexes;
1809 
1810     std::vector<std::size_t> _georadius_cmd_indexes;
1811 
1812     bool _valid = true;
1813 };
1814 
1815 class QueuedReplies {
1816 public:
1817     std::size_t size() const;
1818 
1819     redisReply& get(std::size_t idx);
1820 
1821     template <typename Result>
1822     Result get(std::size_t idx);
1823 
1824     template <typename Output>
1825     void get(std::size_t idx, Output output);
1826 
1827 private:
1828     template <typename Impl>
1829     friend class QueuedRedis;
1830 
QueuedReplies(std::vector<ReplyUPtr> replies)1831     explicit QueuedReplies(std::vector<ReplyUPtr> replies) : _replies(std::move(replies)) {}
1832 
1833     void _index_check(std::size_t idx) const;
1834 
1835     std::vector<ReplyUPtr> _replies;
1836 };
1837 
1838 }
1839 
1840 }
1841 
1842 #include "queued_redis.hpp"
1843 
1844 #endif // end SEWENEW_REDISPLUSPLUS_QUEUED_REDIS_H
1845