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 #include "redis_cluster.h"
18 #include <hiredis/hiredis.h>
19 #include "command.h"
20 #include "errors.h"
21 #include "queued_redis.h"
22 
23 namespace sw {
24 
25 namespace redis {
26 
RedisCluster(const std::string & uri)27 RedisCluster::RedisCluster(const std::string &uri) : RedisCluster(ConnectionOptions(uri)) {}
28 
redis(const StringView & hash_tag)29 Redis RedisCluster::redis(const StringView &hash_tag) {
30     auto opts = _pool.connection_options(hash_tag);
31     return Redis(std::make_shared<Connection>(opts));
32 }
33 
pipeline(const StringView & hash_tag)34 Pipeline RedisCluster::pipeline(const StringView &hash_tag) {
35     auto opts = _pool.connection_options(hash_tag);
36     return Pipeline(std::make_shared<Connection>(opts));
37 }
38 
transaction(const StringView & hash_tag,bool piped)39 Transaction RedisCluster::transaction(const StringView &hash_tag, bool piped) {
40     auto opts = _pool.connection_options(hash_tag);
41     return Transaction(std::make_shared<Connection>(opts), piped);
42 }
43 
subscriber()44 Subscriber RedisCluster::subscriber() {
45     auto opts = _pool.connection_options();
46     return Subscriber(Connection(opts));
47 }
48 
49 // KEY commands.
50 
del(const StringView & key)51 long long RedisCluster::del(const StringView &key) {
52     auto reply = command(cmd::del, key);
53 
54     return reply::parse<long long>(*reply);
55 }
56 
dump(const StringView & key)57 OptionalString RedisCluster::dump(const StringView &key) {
58     auto reply = command(cmd::dump, key);
59 
60     return reply::parse<OptionalString>(*reply);
61 }
62 
exists(const StringView & key)63 long long RedisCluster::exists(const StringView &key) {
64     auto reply = command(cmd::exists, key);
65 
66     return reply::parse<long long>(*reply);
67 }
68 
expire(const StringView & key,long long timeout)69 bool RedisCluster::expire(const StringView &key, long long timeout) {
70     auto reply = command(cmd::expire, key, timeout);
71 
72     return reply::parse<bool>(*reply);
73 }
74 
expireat(const StringView & key,long long timestamp)75 bool RedisCluster::expireat(const StringView &key, long long timestamp) {
76     auto reply = command(cmd::expireat, key, timestamp);
77 
78     return reply::parse<bool>(*reply);
79 }
80 
persist(const StringView & key)81 bool RedisCluster::persist(const StringView &key) {
82     auto reply = command(cmd::persist, key);
83 
84     return reply::parse<bool>(*reply);
85 }
86 
pexpire(const StringView & key,long long timeout)87 bool RedisCluster::pexpire(const StringView &key, long long timeout) {
88     auto reply = command(cmd::pexpire, key, timeout);
89 
90     return reply::parse<bool>(*reply);
91 }
92 
pexpireat(const StringView & key,long long timestamp)93 bool RedisCluster::pexpireat(const StringView &key, long long timestamp) {
94     auto reply = command(cmd::pexpireat, key, timestamp);
95 
96     return reply::parse<bool>(*reply);
97 }
98 
pttl(const StringView & key)99 long long RedisCluster::pttl(const StringView &key) {
100     auto reply = command(cmd::pttl, key);
101 
102     return reply::parse<long long>(*reply);
103 }
104 
rename(const StringView & key,const StringView & newkey)105 void RedisCluster::rename(const StringView &key, const StringView &newkey) {
106     auto reply = command(cmd::rename, key, newkey);
107 
108     reply::parse<void>(*reply);
109 }
110 
renamenx(const StringView & key,const StringView & newkey)111 bool RedisCluster::renamenx(const StringView &key, const StringView &newkey) {
112     auto reply = command(cmd::renamenx, key, newkey);
113 
114     return reply::parse<bool>(*reply);
115 }
116 
restore(const StringView & key,const StringView & val,long long ttl,bool replace)117 void RedisCluster::restore(const StringView &key,
118                     const StringView &val,
119                     long long ttl,
120                     bool replace) {
121     auto reply = command(cmd::restore, key, val, ttl, replace);
122 
123     reply::parse<void>(*reply);
124 }
125 
touch(const StringView & key)126 long long RedisCluster::touch(const StringView &key) {
127     auto reply = command(cmd::touch, key);
128 
129     return reply::parse<long long>(*reply);
130 }
131 
ttl(const StringView & key)132 long long RedisCluster::ttl(const StringView &key) {
133     auto reply = command(cmd::ttl, key);
134 
135     return reply::parse<long long>(*reply);
136 }
137 
type(const StringView & key)138 std::string RedisCluster::type(const StringView &key) {
139     auto reply = command(cmd::type, key);
140 
141     return reply::parse<std::string>(*reply);
142 }
143 
unlink(const StringView & key)144 long long RedisCluster::unlink(const StringView &key) {
145     auto reply = command(cmd::unlink, key);
146 
147     return reply::parse<long long>(*reply);
148 }
149 
150 // STRING commands.
151 
append(const StringView & key,const StringView & val)152 long long RedisCluster::append(const StringView &key, const StringView &val) {
153     auto reply = command(cmd::append, key, val);
154 
155     return reply::parse<long long>(*reply);
156 }
157 
bitcount(const StringView & key,long long start,long long end)158 long long RedisCluster::bitcount(const StringView &key, long long start, long long end) {
159     auto reply = command(cmd::bitcount, key, start, end);
160 
161     return reply::parse<long long>(*reply);
162 }
163 
bitop(BitOp op,const StringView & destination,const StringView & key)164 long long RedisCluster::bitop(BitOp op, const StringView &destination, const StringView &key) {
165     auto reply = _command(cmd::bitop, destination, op, destination, key);
166 
167     return reply::parse<long long>(*reply);
168 }
169 
bitpos(const StringView & key,long long bit,long long start,long long end)170 long long RedisCluster::bitpos(const StringView &key,
171                             long long bit,
172                             long long start,
173                             long long end) {
174     auto reply = command(cmd::bitpos, key, bit, start, end);
175 
176     return reply::parse<long long>(*reply);
177 }
178 
decr(const StringView & key)179 long long RedisCluster::decr(const StringView &key) {
180     auto reply = command(cmd::decr, key);
181 
182     return reply::parse<long long>(*reply);
183 }
184 
decrby(const StringView & key,long long decrement)185 long long RedisCluster::decrby(const StringView &key, long long decrement) {
186     auto reply = command(cmd::decrby, key, decrement);
187 
188     return reply::parse<long long>(*reply);
189 }
190 
get(const StringView & key)191 OptionalString RedisCluster::get(const StringView &key) {
192     auto reply = command(cmd::get, key);
193 
194     return reply::parse<OptionalString>(*reply);
195 }
196 
getbit(const StringView & key,long long offset)197 long long RedisCluster::getbit(const StringView &key, long long offset) {
198     auto reply = command(cmd::getbit, key, offset);
199 
200     return reply::parse<long long>(*reply);
201 }
202 
getrange(const StringView & key,long long start,long long end)203 std::string RedisCluster::getrange(const StringView &key, long long start, long long end) {
204     auto reply = command(cmd::getrange, key, start, end);
205 
206     return reply::parse<std::string>(*reply);
207 }
208 
getset(const StringView & key,const StringView & val)209 OptionalString RedisCluster::getset(const StringView &key, const StringView &val) {
210     auto reply = command(cmd::getset, key, val);
211 
212     return reply::parse<OptionalString>(*reply);
213 }
214 
incr(const StringView & key)215 long long RedisCluster::incr(const StringView &key) {
216     auto reply = command(cmd::incr, key);
217 
218     return reply::parse<long long>(*reply);
219 }
220 
incrby(const StringView & key,long long increment)221 long long RedisCluster::incrby(const StringView &key, long long increment) {
222     auto reply = command(cmd::incrby, key, increment);
223 
224     return reply::parse<long long>(*reply);
225 }
226 
incrbyfloat(const StringView & key,double increment)227 double RedisCluster::incrbyfloat(const StringView &key, double increment) {
228     auto reply = command(cmd::incrbyfloat, key, increment);
229 
230     return reply::parse<double>(*reply);
231 }
232 
psetex(const StringView & key,long long ttl,const StringView & val)233 void RedisCluster::psetex(const StringView &key,
234                         long long ttl,
235                         const StringView &val) {
236     auto reply = command(cmd::psetex, key, ttl, val);
237 
238     reply::parse<void>(*reply);
239 }
240 
set(const StringView & key,const StringView & val,const std::chrono::milliseconds & ttl,UpdateType type)241 bool RedisCluster::set(const StringView &key,
242                     const StringView &val,
243                     const std::chrono::milliseconds &ttl,
244                     UpdateType type) {
245     auto reply = command(cmd::set, key, val, ttl.count(), type);
246 
247     reply::rewrite_set_reply(*reply);
248 
249     return reply::parse<bool>(*reply);
250 }
251 
setex(const StringView & key,long long ttl,const StringView & val)252 void RedisCluster::setex(const StringView &key,
253                     long long ttl,
254                     const StringView &val) {
255     auto reply = command(cmd::setex, key, ttl, val);
256 
257     reply::parse<void>(*reply);
258 }
259 
setnx(const StringView & key,const StringView & val)260 bool RedisCluster::setnx(const StringView &key, const StringView &val) {
261     auto reply = command(cmd::setnx, key, val);
262 
263     return reply::parse<bool>(*reply);
264 }
265 
setrange(const StringView & key,long long offset,const StringView & val)266 long long RedisCluster::setrange(const StringView &key, long long offset, const StringView &val) {
267     auto reply = command(cmd::setrange, key, offset, val);
268 
269     return reply::parse<long long>(*reply);
270 }
271 
strlen(const StringView & key)272 long long RedisCluster::strlen(const StringView &key) {
273     auto reply = command(cmd::strlen, key);
274 
275     return reply::parse<long long>(*reply);
276 }
277 
278 // LIST commands.
279 
blpop(const StringView & key,long long timeout)280 OptionalStringPair RedisCluster::blpop(const StringView &key, long long timeout) {
281     auto reply = command(cmd::blpop, key, timeout);
282 
283     return reply::parse<OptionalStringPair>(*reply);
284 }
285 
blpop(const StringView & key,const std::chrono::seconds & timeout)286 OptionalStringPair RedisCluster::blpop(const StringView &key, const std::chrono::seconds &timeout) {
287     return blpop(key, timeout.count());
288 }
289 
brpop(const StringView & key,long long timeout)290 OptionalStringPair RedisCluster::brpop(const StringView &key, long long timeout) {
291     auto reply = command(cmd::brpop, key, timeout);
292 
293     return reply::parse<OptionalStringPair>(*reply);
294 }
295 
brpop(const StringView & key,const std::chrono::seconds & timeout)296 OptionalStringPair RedisCluster::brpop(const StringView &key, const std::chrono::seconds &timeout) {
297     return brpop(key, timeout.count());
298 }
299 
brpoplpush(const StringView & source,const StringView & destination,long long timeout)300 OptionalString RedisCluster::brpoplpush(const StringView &source,
301                                     const StringView &destination,
302                                     long long timeout) {
303     auto reply = command(cmd::brpoplpush, source, destination, timeout);
304 
305     return reply::parse<OptionalString>(*reply);
306 }
307 
lindex(const StringView & key,long long index)308 OptionalString RedisCluster::lindex(const StringView &key, long long index) {
309     auto reply = command(cmd::lindex, key, index);
310 
311     return reply::parse<OptionalString>(*reply);
312 }
313 
linsert(const StringView & key,InsertPosition position,const StringView & pivot,const StringView & val)314 long long RedisCluster::linsert(const StringView &key,
315                             InsertPosition position,
316                             const StringView &pivot,
317                             const StringView &val) {
318     auto reply = command(cmd::linsert, key, position, pivot, val);
319 
320     return reply::parse<long long>(*reply);
321 }
322 
llen(const StringView & key)323 long long RedisCluster::llen(const StringView &key) {
324     auto reply = command(cmd::llen, key);
325 
326     return reply::parse<long long>(*reply);
327 }
328 
lpop(const StringView & key)329 OptionalString RedisCluster::lpop(const StringView &key) {
330     auto reply = command(cmd::lpop, key);
331 
332     return reply::parse<OptionalString>(*reply);
333 }
334 
lpush(const StringView & key,const StringView & val)335 long long RedisCluster::lpush(const StringView &key, const StringView &val) {
336     auto reply = command(cmd::lpush, key, val);
337 
338     return reply::parse<long long>(*reply);
339 }
340 
lpushx(const StringView & key,const StringView & val)341 long long RedisCluster::lpushx(const StringView &key, const StringView &val) {
342     auto reply = command(cmd::lpushx, key, val);
343 
344     return reply::parse<long long>(*reply);
345 }
346 
lrem(const StringView & key,long long count,const StringView & val)347 long long RedisCluster::lrem(const StringView &key, long long count, const StringView &val) {
348     auto reply = command(cmd::lrem, key, count, val);
349 
350     return reply::parse<long long>(*reply);
351 }
352 
lset(const StringView & key,long long index,const StringView & val)353 void RedisCluster::lset(const StringView &key, long long index, const StringView &val) {
354     auto reply = command(cmd::lset, key, index, val);
355 
356     reply::parse<void>(*reply);
357 }
358 
ltrim(const StringView & key,long long start,long long stop)359 void RedisCluster::ltrim(const StringView &key, long long start, long long stop) {
360     auto reply = command(cmd::ltrim, key, start, stop);
361 
362     reply::parse<void>(*reply);
363 }
364 
rpop(const StringView & key)365 OptionalString RedisCluster::rpop(const StringView &key) {
366     auto reply = command(cmd::rpop, key);
367 
368     return reply::parse<OptionalString>(*reply);
369 }
370 
rpoplpush(const StringView & source,const StringView & destination)371 OptionalString RedisCluster::rpoplpush(const StringView &source, const StringView &destination) {
372     auto reply = command(cmd::rpoplpush, source, destination);
373 
374     return reply::parse<OptionalString>(*reply);
375 }
376 
rpush(const StringView & key,const StringView & val)377 long long RedisCluster::rpush(const StringView &key, const StringView &val) {
378     auto reply = command(cmd::rpush, key, val);
379 
380     return reply::parse<long long>(*reply);
381 }
382 
rpushx(const StringView & key,const StringView & val)383 long long RedisCluster::rpushx(const StringView &key, const StringView &val) {
384     auto reply = command(cmd::rpushx, key, val);
385 
386     return reply::parse<long long>(*reply);
387 }
388 
hdel(const StringView & key,const StringView & field)389 long long RedisCluster::hdel(const StringView &key, const StringView &field) {
390     auto reply = command(cmd::hdel, key, field);
391 
392     return reply::parse<long long>(*reply);
393 }
394 
hexists(const StringView & key,const StringView & field)395 bool RedisCluster::hexists(const StringView &key, const StringView &field) {
396     auto reply = command(cmd::hexists, key, field);
397 
398     return reply::parse<bool>(*reply);
399 }
400 
hget(const StringView & key,const StringView & field)401 OptionalString RedisCluster::hget(const StringView &key, const StringView &field) {
402     auto reply = command(cmd::hget, key, field);
403 
404     return reply::parse<OptionalString>(*reply);
405 }
406 
hincrby(const StringView & key,const StringView & field,long long increment)407 long long RedisCluster::hincrby(const StringView &key, const StringView &field, long long increment) {
408     auto reply = command(cmd::hincrby, key, field, increment);
409 
410     return reply::parse<long long>(*reply);
411 }
412 
hincrbyfloat(const StringView & key,const StringView & field,double increment)413 double RedisCluster::hincrbyfloat(const StringView &key, const StringView &field, double increment) {
414     auto reply = command(cmd::hincrbyfloat, key, field, increment);
415 
416     return reply::parse<double>(*reply);
417 }
418 
hlen(const StringView & key)419 long long RedisCluster::hlen(const StringView &key) {
420     auto reply = command(cmd::hlen, key);
421 
422     return reply::parse<long long>(*reply);
423 }
424 
hset(const StringView & key,const StringView & field,const StringView & val)425 bool RedisCluster::hset(const StringView &key, const StringView &field, const StringView &val) {
426     auto reply = command(cmd::hset, key, field, val);
427 
428     return reply::parse<bool>(*reply);
429 }
430 
hset(const StringView & key,const std::pair<StringView,StringView> & item)431 bool RedisCluster::hset(const StringView &key, const std::pair<StringView, StringView> &item) {
432     return hset(key, item.first, item.second);
433 }
434 
hsetnx(const StringView & key,const StringView & field,const StringView & val)435 bool RedisCluster::hsetnx(const StringView &key, const StringView &field, const StringView &val) {
436     auto reply = command(cmd::hsetnx, key, field, val);
437 
438     return reply::parse<bool>(*reply);
439 }
440 
hsetnx(const StringView & key,const std::pair<StringView,StringView> & item)441 bool RedisCluster::hsetnx(const StringView &key, const std::pair<StringView, StringView> &item) {
442     return hsetnx(key, item.first, item.second);
443 }
444 
hstrlen(const StringView & key,const StringView & field)445 long long RedisCluster::hstrlen(const StringView &key, const StringView &field) {
446     auto reply = command(cmd::hstrlen, key, field);
447 
448     return reply::parse<long long>(*reply);
449 }
450 
451 // SET commands.
452 
sadd(const StringView & key,const StringView & member)453 long long RedisCluster::sadd(const StringView &key, const StringView &member) {
454     auto reply = command(cmd::sadd, key, member);
455 
456     return reply::parse<long long>(*reply);
457 }
458 
scard(const StringView & key)459 long long RedisCluster::scard(const StringView &key) {
460     auto reply = command(cmd::scard, key);
461 
462     return reply::parse<long long>(*reply);
463 }
464 
sdiffstore(const StringView & destination,const StringView & key)465 long long RedisCluster::sdiffstore(const StringView &destination, const StringView &key) {
466     auto reply = command(cmd::sdiffstore, destination, key);
467 
468     return reply::parse<long long>(*reply);
469 }
470 
sinterstore(const StringView & destination,const StringView & key)471 long long RedisCluster::sinterstore(const StringView &destination, const StringView &key) {
472     auto reply = command(cmd::sinterstore, destination, key);
473 
474     return reply::parse<long long>(*reply);
475 }
476 
sismember(const StringView & key,const StringView & member)477 bool RedisCluster::sismember(const StringView &key, const StringView &member) {
478     auto reply = command(cmd::sismember, key, member);
479 
480     return reply::parse<bool>(*reply);
481 }
482 
smove(const StringView & source,const StringView & destination,const StringView & member)483 bool RedisCluster::smove(const StringView &source,
484                     const StringView &destination,
485                     const StringView &member) {
486     auto reply = command(cmd::smove, source, destination, member);
487 
488     return reply::parse<bool>(*reply);
489 }
490 
spop(const StringView & key)491 OptionalString RedisCluster::spop(const StringView &key) {
492     auto reply = command(cmd::spop, key);
493 
494     return reply::parse<OptionalString>(*reply);
495 }
496 
srandmember(const StringView & key)497 OptionalString RedisCluster::srandmember(const StringView &key) {
498     auto reply = command(cmd::srandmember, key);
499 
500     return reply::parse<OptionalString>(*reply);
501 }
502 
srem(const StringView & key,const StringView & member)503 long long RedisCluster::srem(const StringView &key, const StringView &member) {
504     auto reply = command(cmd::srem, key, member);
505 
506     return reply::parse<long long>(*reply);
507 }
508 
sunionstore(const StringView & destination,const StringView & key)509 long long RedisCluster::sunionstore(const StringView &destination, const StringView &key) {
510     auto reply = command(cmd::sunionstore, destination, key);
511 
512     return reply::parse<long long>(*reply);
513 }
514 
515 // SORTED SET commands.
516 
bzpopmax(const StringView & key,long long timeout)517 auto RedisCluster::bzpopmax(const StringView &key, long long timeout)
518     -> Optional<std::tuple<std::string, std::string, double>> {
519     auto reply = command(cmd::bzpopmax, key, timeout);
520 
521     return reply::parse<Optional<std::tuple<std::string, std::string, double>>>(*reply);
522 }
523 
bzpopmin(const StringView & key,long long timeout)524 auto RedisCluster::bzpopmin(const StringView &key, long long timeout)
525     -> Optional<std::tuple<std::string, std::string, double>> {
526     auto reply = command(cmd::bzpopmin, key, timeout);
527 
528     return reply::parse<Optional<std::tuple<std::string, std::string, double>>>(*reply);
529 }
530 
zadd(const StringView & key,const StringView & member,double score,UpdateType type,bool changed)531 long long RedisCluster::zadd(const StringView &key,
532                         const StringView &member,
533                         double score,
534                         UpdateType type,
535                         bool changed) {
536     auto reply = command(cmd::zadd, key, member, score, type, changed);
537 
538     return reply::parse<long long>(*reply);
539 }
540 
zcard(const StringView & key)541 long long RedisCluster::zcard(const StringView &key) {
542     auto reply = command(cmd::zcard, key);
543 
544     return reply::parse<long long>(*reply);
545 }
546 
zincrby(const StringView & key,double increment,const StringView & member)547 double RedisCluster::zincrby(const StringView &key, double increment, const StringView &member) {
548     auto reply = command(cmd::zincrby, key, increment, member);
549 
550     return reply::parse<double>(*reply);
551 }
552 
zinterstore(const StringView & destination,const StringView & key,double weight)553 long long RedisCluster::zinterstore(const StringView &destination,
554                                     const StringView &key,
555                                     double weight) {
556     auto reply = command(cmd::zinterstore, destination, key, weight);
557 
558     return reply::parse<long long>(*reply);
559 }
560 
zpopmax(const StringView & key)561 Optional<std::pair<std::string, double>> RedisCluster::zpopmax(const StringView &key) {
562     auto reply = command(cmd::zpopmax, key, 1);
563 
564     return reply::parse<Optional<std::pair<std::string, double>>>(*reply);
565 }
566 
zpopmin(const StringView & key)567 Optional<std::pair<std::string, double>> RedisCluster::zpopmin(const StringView &key) {
568     auto reply = command(cmd::zpopmin, key, 1);
569 
570     return reply::parse<Optional<std::pair<std::string, double>>>(*reply);
571 }
572 
zrank(const StringView & key,const StringView & member)573 OptionalLongLong RedisCluster::zrank(const StringView &key, const StringView &member) {
574     auto reply = command(cmd::zrank, key, member);
575 
576     return reply::parse<OptionalLongLong>(*reply);
577 }
578 
zrem(const StringView & key,const StringView & member)579 long long RedisCluster::zrem(const StringView &key, const StringView &member) {
580     auto reply = command(cmd::zrem, key, member);
581 
582     return reply::parse<long long>(*reply);
583 }
584 
zremrangebyrank(const StringView & key,long long start,long long stop)585 long long RedisCluster::zremrangebyrank(const StringView &key, long long start, long long stop) {
586     auto reply = command(cmd::zremrangebyrank, key, start, stop);
587 
588     return reply::parse<long long>(*reply);
589 }
590 
zrevrank(const StringView & key,const StringView & member)591 OptionalLongLong RedisCluster::zrevrank(const StringView &key, const StringView &member) {
592     auto reply = command(cmd::zrevrank, key, member);
593 
594     return reply::parse<OptionalLongLong>(*reply);
595 }
596 
zscore(const StringView & key,const StringView & member)597 OptionalDouble RedisCluster::zscore(const StringView &key, const StringView &member) {
598     auto reply = command(cmd::zscore, key, member);
599 
600     return reply::parse<OptionalDouble>(*reply);
601 }
602 
zunionstore(const StringView & destination,const StringView & key,double weight)603 long long RedisCluster::zunionstore(const StringView &destination,
604                                     const StringView &key,
605                                     double weight) {
606     auto reply = command(cmd::zunionstore, destination, key, weight);
607 
608     return reply::parse<long long>(*reply);
609 }
610 
611 // HYPERLOGLOG commands.
612 
pfadd(const StringView & key,const StringView & element)613 bool RedisCluster::pfadd(const StringView &key, const StringView &element) {
614     auto reply = command(cmd::pfadd, key, element);
615 
616     return reply::parse<bool>(*reply);
617 }
618 
pfcount(const StringView & key)619 long long RedisCluster::pfcount(const StringView &key) {
620     auto reply = command(cmd::pfcount, key);
621 
622     return reply::parse<long long>(*reply);
623 }
624 
pfmerge(const StringView & destination,const StringView & key)625 void RedisCluster::pfmerge(const StringView &destination, const StringView &key) {
626     auto reply = command(cmd::pfmerge, destination, key);
627 
628     reply::parse<void>(*reply);
629 }
630 
631 // GEO commands.
632 
geoadd(const StringView & key,const std::tuple<StringView,double,double> & member)633 long long RedisCluster::geoadd(const StringView &key,
634                         const std::tuple<StringView, double, double> &member) {
635     auto reply = command(cmd::geoadd, key, member);
636 
637     return reply::parse<long long>(*reply);
638 }
639 
geodist(const StringView & key,const StringView & member1,const StringView & member2,GeoUnit unit)640 OptionalDouble RedisCluster::geodist(const StringView &key,
641                                 const StringView &member1,
642                                 const StringView &member2,
643                                 GeoUnit unit) {
644     auto reply = command(cmd::geodist, key, member1, member2, unit);
645 
646     return reply::parse<OptionalDouble>(*reply);
647 }
648 
georadius(const StringView & key,const std::pair<double,double> & loc,double radius,GeoUnit unit,const StringView & destination,bool store_dist,long long count)649 OptionalLongLong RedisCluster::georadius(const StringView &key,
650                                     const std::pair<double, double> &loc,
651                                     double radius,
652                                     GeoUnit unit,
653                                     const StringView &destination,
654                                     bool store_dist,
655                                     long long count) {
656     auto reply = command(cmd::georadius_store,
657                             key,
658                             loc,
659                             radius,
660                             unit,
661                             destination,
662                             store_dist,
663                             count);
664 
665     reply::rewrite_georadius_reply(*reply);
666 
667     return reply::parse<OptionalLongLong>(*reply);
668 }
669 
georadiusbymember(const StringView & key,const StringView & member,double radius,GeoUnit unit,const StringView & destination,bool store_dist,long long count)670 OptionalLongLong RedisCluster::georadiusbymember(const StringView &key,
671                                             const StringView &member,
672                                             double radius,
673                                             GeoUnit unit,
674                                             const StringView &destination,
675                                             bool store_dist,
676                                             long long count) {
677     auto reply = command(cmd::georadiusbymember_store,
678                             key,
679                             member,
680                             radius,
681                             unit,
682                             destination,
683                             store_dist,
684                             count);
685 
686     reply::rewrite_georadius_reply(*reply);
687 
688     return reply::parse<OptionalLongLong>(*reply);
689 }
690 
691 // PUBSUB commands.
692 
publish(const StringView & channel,const StringView & message)693 long long RedisCluster::publish(const StringView &channel, const StringView &message) {
694     auto reply = command(cmd::publish, channel, message);
695 
696     return reply::parse<long long>(*reply);
697 }
698 
699 // Stream commands.
700 
xack(const StringView & key,const StringView & group,const StringView & id)701 long long RedisCluster::xack(const StringView &key, const StringView &group, const StringView &id) {
702     auto reply = command(cmd::xack, key, group, id);
703 
704     return reply::parse<long long>(*reply);
705 }
706 
xdel(const StringView & key,const StringView & id)707 long long RedisCluster::xdel(const StringView &key, const StringView &id) {
708     auto reply = command(cmd::xdel, key, id);
709 
710     return reply::parse<long long>(*reply);
711 }
712 
xgroup_create(const StringView & key,const StringView & group,const StringView & id,bool mkstream)713 void RedisCluster::xgroup_create(const StringView &key,
714                                     const StringView &group,
715                                     const StringView &id,
716                                     bool mkstream) {
717     auto reply = command(cmd::xgroup_create, key, group, id, mkstream);
718 
719     reply::parse<void>(*reply);
720 }
721 
xgroup_setid(const StringView & key,const StringView & group,const StringView & id)722 void RedisCluster::xgroup_setid(const StringView &key,
723                                 const StringView &group,
724                                 const StringView &id) {
725     auto reply = command(cmd::xgroup_setid, key, group, id);
726 
727     reply::parse<void>(*reply);
728 }
729 
xgroup_destroy(const StringView & key,const StringView & group)730 long long RedisCluster::xgroup_destroy(const StringView &key, const StringView &group) {
731     auto reply = command(cmd::xgroup_destroy, key, group);
732 
733     return reply::parse<long long>(*reply);
734 }
735 
xgroup_delconsumer(const StringView & key,const StringView & group,const StringView & consumer)736 long long RedisCluster::xgroup_delconsumer(const StringView &key,
737                                             const StringView &group,
738                                             const StringView &consumer) {
739     auto reply = command(cmd::xgroup_delconsumer, key, group, consumer);
740 
741     return reply::parse<long long>(*reply);
742 }
743 
xlen(const StringView & key)744 long long RedisCluster::xlen(const StringView &key) {
745     auto reply = command(cmd::xlen, key);
746 
747     return reply::parse<long long>(*reply);
748 }
749 
xtrim(const StringView & key,long long count,bool approx)750 long long RedisCluster::xtrim(const StringView &key, long long count, bool approx) {
751     auto reply = command(cmd::xtrim, key, count, approx);
752 
753     return reply::parse<long long>(*reply);
754 }
755 
_asking(Connection & connection)756 void RedisCluster::_asking(Connection &connection) {
757     // Send ASKING command.
758     connection.send("ASKING");
759 
760     auto reply = connection.recv();
761 
762     assert(reply);
763 
764     reply::parse<void>(*reply);
765 }
766 
767 }
768 
769 }
770