1 /* 2 * Hunt - A redis client library for D programming language. 3 * 4 * Copyright (C) 2018-2019 HuntLabs 5 * 6 * Website: https://www.huntlabs.net/ 7 * 8 * Licensed under the Apache-2.0 License. 9 * 10 */ 11 12 module hunt.redis.Redis; 13 14 import hunt.redis.BinaryRedis; 15 import hunt.redis.BinaryRedisPubSub; 16 import hunt.redis.BitOP; 17 import hunt.redis.BitPosParams; 18 import hunt.redis.BuilderFactory; 19 import hunt.redis.Client; 20 import hunt.redis.ClusterReset; 21 import hunt.redis.GeoCoordinate; 22 import hunt.redis.GeoRadiusResponse; 23 import hunt.redis.GeoUnit; 24 import hunt.redis.HostAndPort; 25 import hunt.redis.ListPosition; 26 import hunt.redis.Module; 27 import hunt.redis.Pipeline; 28 import hunt.redis.Protocol; 29 import hunt.redis.RedisMonitor; 30 import hunt.redis.RedisPubSub; 31 import hunt.redis.RedisShardInfo; 32 import hunt.redis.ScanParams; 33 import hunt.redis.ScanResult; 34 import hunt.redis.SortingParams; 35 import hunt.redis.StreamEntry; 36 import hunt.redis.StreamEntryID; 37 import hunt.redis.StreamPendingEntry; 38 import hunt.redis.Transaction; 39 import hunt.redis.Tuple; 40 import hunt.redis.ZParams; 41 42 import hunt.redis.commands.AdvancedRedisCommands; 43 import hunt.redis.commands.BasicCommands; 44 import hunt.redis.commands.ClusterCommands; 45 import hunt.redis.commands.RedisCommands; 46 import hunt.redis.commands.ModuleCommands; 47 import hunt.redis.commands.MultiKeyCommands; 48 import hunt.redis.Protocol; 49 import hunt.redis.commands.ScriptingCommands; 50 import hunt.redis.commands.SentinelCommands; 51 import hunt.redis.params.ClientKillParams; 52 import hunt.redis.params.GeoRadiusParam; 53 import hunt.redis.params.MigrateParams; 54 import hunt.redis.params.SetParams; 55 import hunt.redis.params.ZAddParams; 56 import hunt.redis.params.ZIncrByParams; 57 import hunt.redis.util.SafeEncoder; 58 import hunt.redis.util.Slowlog; 59 60 import hunt.Byte; 61 import hunt.collection; 62 import hunt.Double; 63 import hunt.Long; 64 import hunt.Exceptions; 65 import hunt.logging.ConsoleLogger; 66 import hunt.net.util.HttpURI; 67 68 import std.conv; 69 70 71 /** 72 * 73 */ 74 class Redis : BinaryRedis, RedisCommands, MultiKeyCommands, 75 AdvancedRedisCommands, ScriptingCommands, BasicCommands, 76 ClusterCommands, SentinelCommands, ModuleCommands { 77 78 // protected RedisPoolAbstract dataSource = null; 79 80 this() { 81 super(); 82 } 83 84 this(string host) { 85 super(host); 86 } 87 88 this(HostAndPort hp) { 89 super(hp); 90 } 91 92 this(string host, int port) { 93 super(host, port); 94 } 95 96 this(string host, int port, bool ssl) { 97 super(host, port, ssl); 98 } 99 100 // this(string host, int port, bool ssl, 101 // SSLSocketFactory sslSocketFactory, SSLParameters sslParameters, 102 // HostnameVerifier hostnameVerifier) { 103 // super(host, port, ssl, sslSocketFactory, sslParameters, hostnameVerifier); 104 // } 105 106 this(string host, int port, int timeout) { 107 super(host, port, timeout); 108 } 109 110 this(string host, int port, int timeout, bool ssl) { 111 super(host, port, timeout, ssl); 112 } 113 114 // this(string host, int port, int timeout, bool ssl, 115 // SSLSocketFactory sslSocketFactory, SSLParameters sslParameters, 116 // HostnameVerifier hostnameVerifier) { 117 // super(host, port, timeout, ssl, sslSocketFactory, sslParameters, hostnameVerifier); 118 // } 119 120 this(string host, int port, int connectionTimeout, int soTimeout) { 121 super(host, port, connectionTimeout, soTimeout); 122 } 123 124 this(string host, int port, int connectionTimeout, int soTimeout, 125 bool ssl) { 126 super(host, port, connectionTimeout, soTimeout, ssl); 127 } 128 129 // this(string host, int port, int connectionTimeout, int soTimeout, 130 // bool ssl, SSLSocketFactory sslSocketFactory, SSLParameters sslParameters, 131 // HostnameVerifier hostnameVerifier) { 132 // super(host, port, connectionTimeout, soTimeout, ssl, sslSocketFactory, sslParameters, 133 // hostnameVerifier); 134 // } 135 136 this(RedisShardInfo shardInfo) { 137 super(shardInfo); 138 } 139 140 this(HttpURI uri) { 141 super(uri); 142 } 143 144 // this(HttpURI uri, SSLSocketFactory sslSocketFactory, SSLParameters sslParameters, 145 // HostnameVerifier hostnameVerifier) { 146 // super(uri, sslSocketFactory, sslParameters, hostnameVerifier); 147 // } 148 149 this(HttpURI uri, int timeout) { 150 super(uri, timeout); 151 } 152 153 // this(HttpURI uri, int timeout, SSLSocketFactory sslSocketFactory, 154 // SSLParameters sslParameters, HostnameVerifier hostnameVerifier) { 155 // super(uri, timeout, sslSocketFactory, sslParameters, hostnameVerifier); 156 // } 157 158 this(HttpURI uri, int connectionTimeout, int soTimeout) { 159 super(uri, connectionTimeout, soTimeout); 160 } 161 162 // this(HttpURI uri, int connectionTimeout, int soTimeout, 163 // SSLSocketFactory sslSocketFactory, SSLParameters sslParameters, 164 // HostnameVerifier hostnameVerifier) { 165 // super(uri, connectionTimeout, soTimeout, sslSocketFactory, sslParameters, hostnameVerifier); 166 // } 167 168 /** 169 * Works same as <tt>ping()</tt> but returns argument message instead of <tt>PONG</tt>. 170 * @param message 171 * @return message 172 */ 173 string ping(string message) { 174 checkIsInMultiOrPipeline(); 175 client.ping(message); 176 return client.getBulkReply(); 177 } 178 alias ping = BinaryRedis.ping; 179 180 181 /** 182 * Set the string value as value of the key. The string can't be longer than 1073741824 bytes (1 183 * GB). 184 * <p> 185 * Time complexity: O(1) 186 * @param key 187 * @param value 188 * @return Status code reply 189 */ 190 string set(string key, string value) { 191 checkIsInMultiOrPipeline(); 192 client.set(key, value); 193 return client.getStatusCodeReply(); 194 } 195 alias set = BinaryRedis.set; 196 197 /** 198 * Set the string value as value of the key. The string can't be longer than 1073741824 bytes (1 199 * GB). 200 * @param key 201 * @param value 202 * @param params NX|XX, NX -- Only set the key if it does not already exist. XX -- Only set the 203 * key if it already exist. EX|PX, expire time units: EX = seconds; PX = milliseconds 204 * @return Status code reply 205 */ 206 string set(string key, string value, SetParams params) { 207 checkIsInMultiOrPipeline(); 208 client.set(key, value, params); 209 return client.getStatusCodeReply(); 210 } 211 212 /** 213 * Get the value of the specified key. If the key does not exist null is returned. If the value 214 * stored at key is not a string an error is returned because GET can only handle string values. 215 * <p> 216 * Time complexity: O(1) 217 * @param key 218 * @return Bulk reply 219 */ 220 string get(string key) { 221 checkIsInMultiOrPipeline(); 222 client.get(key); 223 return client.getBulkReply(); 224 } 225 alias get = BinaryRedis.get; 226 227 /** 228 * Test if the specified keys exist. The command returns the number of keys exist. 229 * Time complexity: O(N) 230 * @param keys 231 * @return Integer reply, specifically: an integer greater than 0 if one or more keys exist, 232 * 0 if none of the specified keys exist. 233 */ 234 Long exists(string[] keys...) { 235 checkIsInMultiOrPipeline(); 236 client.exists(keys); 237 return client.getIntegerReply(); 238 } 239 alias exists = BinaryRedis.exists; 240 241 /** 242 * Test if the specified key exists. The command returns true if the key exists, otherwise false is 243 * returned. Note that even keys set with an empty string as value will return true. Time 244 * complexity: O(1) 245 * @param key 246 * @return bool reply, true if the key exists, otherwise false 247 */ 248 // override 249 bool exists(string key) { 250 checkIsInMultiOrPipeline(); 251 client.exists(key); 252 return client.getIntegerReply() == 1; 253 } 254 255 /** 256 * Remove the specified keys. If a given key does not exist no operation is performed for this 257 * key. The command returns the number of keys removed. Time complexity: O(1) 258 * @param keys 259 * @return Integer reply, specifically: an integer greater than 0 if one or more keys were removed 260 * 0 if none of the specified key existed 261 */ 262 Long del(string[] keys...) { 263 checkIsInMultiOrPipeline(); 264 client.del(keys); 265 return client.getIntegerReply(); 266 } 267 alias del = BinaryRedis.del; 268 269 Long del(string key) { 270 checkIsInMultiOrPipeline(); 271 client.del(key); 272 return client.getIntegerReply(); 273 } 274 275 /** 276 * This command is very similar to DEL: it removes the specified keys. Just like DEL a key is 277 * ignored if it does not exist. However the command performs the actual memory reclaiming in a 278 * different thread, so it is not blocking, while DEL is. This is where the command name comes 279 * from: the command just unlinks the keys from the keyspace. The actual removal will happen later 280 * asynchronously. 281 * <p> 282 * Time complexity: O(1) for each key removed regardless of its size. Then the command does O(N) 283 * work in a different thread in order to reclaim memory, where N is the number of allocations the 284 * deleted objects where composed of. 285 * @param keys 286 * @return Integer reply: The number of keys that were unlinked 287 */ 288 Long unlink(string[] keys...) { 289 checkIsInMultiOrPipeline(); 290 client.unlink(keys); 291 return client.getIntegerReply(); 292 } 293 alias unlink = BinaryRedis.unlink; 294 295 Long unlink(string key) { 296 client.unlink(key); 297 return client.getIntegerReply(); 298 } 299 300 /** 301 * Return the type of the value stored at key in form of a string. The type can be one of "none", 302 * "string", "list", "set". "none" is returned if the key does not exist. Time complexity: O(1) 303 * @param key 304 * @return Status code reply, specifically: "none" if the key does not exist "string" if the key 305 * contains a string value "list" if the key contains a List value "set" if the key 306 * contains a Set value "zset" if the key contains a Sorted Set value "hash" if the key 307 * contains a Hash value 308 */ 309 string type(string key) { 310 checkIsInMultiOrPipeline(); 311 client.type(key); 312 return client.getStatusCodeReply(); 313 } 314 alias type = BinaryRedis.type; 315 316 Set!(string) keys(string pattern) { 317 checkIsInMultiOrPipeline(); 318 client.keys(pattern); 319 return BuilderFactory.STRING_SET.build(cast(Object)client.getBinaryMultiBulkReply()); 320 } 321 alias keys = BinaryRedis.keys; 322 323 /** 324 * Return a randomly selected key from the currently selected DB. 325 * <p> 326 * Time complexity: O(1) 327 * @return Singe line reply, specifically the randomly selected key or an empty string is the 328 * database is empty 329 */ 330 string randomKey() { 331 checkIsInMultiOrPipeline(); 332 client.randomKey(); 333 return client.getBulkReply(); 334 } 335 336 /** 337 * Atomically renames the key oldkey to newkey. If the source and destination name are the same an 338 * error is returned. If newkey already exists it is overwritten. 339 * <p> 340 * Time complexity: O(1) 341 * @param oldkey 342 * @param newkey 343 * @return Status code repy 344 */ 345 string rename(string oldkey, string newkey) { 346 checkIsInMultiOrPipeline(); 347 client.rename(oldkey, newkey); 348 return client.getStatusCodeReply(); 349 } 350 alias rename = BinaryRedis.rename; 351 352 /** 353 * Rename oldkey into newkey but fails if the destination key newkey already exists. 354 * <p> 355 * Time complexity: O(1) 356 * @param oldkey 357 * @param newkey 358 * @return Integer reply, specifically: 1 if the key was renamed 0 if the target key already exist 359 */ 360 // override 361 Long renamenx(string oldkey, string newkey) { 362 checkIsInMultiOrPipeline(); 363 client.renamenx(oldkey, newkey); 364 return client.getIntegerReply(); 365 } 366 367 /** 368 * Set a timeout on the specified key. After the timeout the key will be automatically deleted by 369 * the server. A key with an associated timeout is said to be volatile in Redis terminology. 370 * <p> 371 * Volatile keys are stored on disk like the other keys, the timeout is persistent too like all the 372 * other aspects of the dataset. Saving a dataset containing expires and stopping the server does 373 * not stop the flow of time as Redis stores on disk the time when the key will no longer be 374 * available as Unix time, and not the remaining seconds. 375 * <p> 376 * Since Redis 2.1.3 you can update the value of the timeout of a key already having an expire 377 * set. It is also possible to undo the expire at all turning the key into a normal key using the 378 * {@link #persist(string) PERSIST} command. 379 * <p> 380 * Time complexity: O(1) 381 * @see <a href="http://redis.io/commands/expire">Expire Command</a> 382 * @param key 383 * @param seconds 384 * @return Integer reply, specifically: 1: the timeout was set. 0: the timeout was not set since 385 * the key already has an associated timeout (this may happen only in Redis versions < 386 * 2.1.3, Redis >= 2.1.3 will happily update the timeout), or the key does not exist. 387 */ 388 Long expire(string key, int seconds) { 389 checkIsInMultiOrPipeline(); 390 client.expire(key, seconds); 391 return client.getIntegerReply(); 392 } 393 alias expire = BinaryRedis.expire; 394 395 /** 396 * EXPIREAT works exactly like {@link #expire(string, int) EXPIRE} but instead to get the number of 397 * seconds representing the Time To Live of the key as a second argument (that is a relative way 398 * of specifying the TTL), it takes an absolute one in the form of a UNIX timestamp (Number of 399 * seconds elapsed since 1 Gen 1970). 400 * <p> 401 * EXPIREAT was introduced in order to implement the Append Only File persistence mode so that 402 * EXPIRE commands are automatically translated into EXPIREAT commands for the append only file. 403 * Of course EXPIREAT can also used by programmers that need a way to simply specify that a given 404 * key should expire at a given time in the future. 405 * <p> 406 * Since Redis 2.1.3 you can update the value of the timeout of a key already having an expire 407 * set. It is also possible to undo the expire at all turning the key into a normal key using the 408 * {@link #persist(string) PERSIST} command. 409 * <p> 410 * Time complexity: O(1) 411 * @see <a href="http://redis.io/commands/expire">Expire Command</a> 412 * @param key 413 * @param unixTime 414 * @return Integer reply, specifically: 1: the timeout was set. 0: the timeout was not set since 415 * the key already has an associated timeout (this may happen only in Redis versions < 416 * 2.1.3, Redis >= 2.1.3 will happily update the timeout), or the key does not exist. 417 */ 418 Long expireAt(string key, long unixTime) { 419 checkIsInMultiOrPipeline(); 420 client.expireAt(key, unixTime); 421 return client.getIntegerReply(); 422 } 423 alias expireAt = BinaryRedis.expireAt; 424 425 /** 426 * The TTL command returns the remaining time to live in seconds of a key that has an 427 * {@link #expire(string, int) EXPIRE} set. This introspection capability allows a Redis client to 428 * check how many seconds a given key will continue to be part of the dataset. 429 * @param key 430 * @return Integer reply, returns the remaining time to live in seconds of a key that has an 431 * EXPIRE. In Redis 2.6 or older, if the Key does not exists or does not have an 432 * associated expire, -1 is returned. In Redis 2.8 or newer, if the Key does not have an 433 * associated expire, -1 is returned or if the Key does not exists, -2 is returned. 434 */ 435 Long ttl(string key) { 436 checkIsInMultiOrPipeline(); 437 client.ttl(key); 438 return client.getIntegerReply(); 439 } 440 alias ttl = BinaryRedis.ttl; 441 442 /** 443 * Alters the last access time of a key(s). A key is ignored if it does not exist. 444 * Time complexity: O(N) where N is the number of keys that will be touched. 445 * @param keys 446 * @return Integer reply: The number of keys that were touched. 447 */ 448 Long touch(string[] keys...) { 449 checkIsInMultiOrPipeline(); 450 client.touch(keys); 451 return client.getIntegerReply(); 452 } 453 alias touch = BinaryRedis.touch; 454 455 Long touch(string key) { 456 checkIsInMultiOrPipeline(); 457 client.touch(key); 458 return client.getIntegerReply(); 459 } 460 alias touch = BinaryRedis.touch; 461 462 /** 463 * Move the specified key from the currently selected DB to the specified destination DB. Note 464 * that this command returns 1 only if the key was successfully moved, and 0 if the target key was 465 * already there or if the source key was not found at all, so it is possible to use MOVE as a 466 * locking primitive. 467 * @param key 468 * @param dbIndex 469 * @return Integer reply, specifically: 1 if the key was moved 0 if the key was not moved because 470 * already present on the target DB or was not found in the current DB. 471 */ 472 Long move(string key, int dbIndex) { 473 checkIsInMultiOrPipeline(); 474 client.move(key, dbIndex); 475 return client.getIntegerReply(); 476 } 477 alias move = BinaryRedis.move; 478 479 /** 480 * GETSET is an atomic set this value and return the old value command. Set key to the string 481 * value and return the old value stored at key. The string can't be longer than 1073741824 bytes 482 * (1 GB). 483 * <p> 484 * Time complexity: O(1) 485 * @param key 486 * @param value 487 * @return Bulk reply 488 */ 489 string getSet(string key, string value) { 490 checkIsInMultiOrPipeline(); 491 client.getSet(key, value); 492 return client.getBulkReply(); 493 } 494 alias getSet = BinaryRedis.getSet; 495 496 /** 497 * Get the values of all the specified keys. If one or more keys don't exist or is not of type 498 * string, a 'nil' value is returned instead of the value of the specified key, but the operation 499 * never fails. 500 * <p> 501 * Time complexity: O(1) for every key 502 * @param keys 503 * @return Multi bulk reply 504 */ 505 List!(string) mget(string[] keys...) { 506 checkIsInMultiOrPipeline(); 507 client.mget(keys); 508 return client.getMultiBulkReply(); 509 } 510 alias mget = BinaryRedis.mget; 511 512 /** 513 * SETNX works exactly like {@link #set(string, string) SET} with the only difference that if the 514 * key already exists no operation is performed. SETNX actually means "SET if Not eXists". 515 * <p> 516 * Time complexity: O(1) 517 * @param key 518 * @param value 519 * @return Integer reply, specifically: 1 if the key was set 0 if the key was not set 520 */ 521 Long setnx(string key, string value) { 522 checkIsInMultiOrPipeline(); 523 client.setnx(key, value); 524 return client.getIntegerReply(); 525 } 526 alias setnx = BinaryRedis.setnx; 527 528 /** 529 * The command is exactly equivalent to the following group of commands: 530 * {@link #set(string, string) SET} + {@link #expire(string, int) EXPIRE}. The operation is 531 * atomic. 532 * <p> 533 * Time complexity: O(1) 534 * @param key 535 * @param seconds 536 * @param value 537 * @return Status code reply 538 */ 539 string setex(string key, int seconds, string value) { 540 checkIsInMultiOrPipeline(); 541 client.setex(key, seconds, value); 542 return client.getStatusCodeReply(); 543 } 544 alias setex = BinaryRedis.setex; 545 546 /** 547 * Set the the respective keys to the respective values. MSET will replace old values with new 548 * values, while {@link #msetnx(string...) MSETNX} will not perform any operation at all even if 549 * just a single key already exists. 550 * <p> 551 * Because of this semantic MSETNX can be used in order to set different keys representing 552 * different fields of an unique logic object in a way that ensures that either all the fields or 553 * none at all are set. 554 * <p> 555 * Both MSET and MSETNX are atomic operations. This means that for instance if the keys A and B 556 * are modified, another client talking to Redis can either see the changes to both A and B at 557 * once, or no modification at all. 558 * @see #msetnx(string...) 559 * @param keysvalues 560 * @return Status code reply Basically +OK as MSET can't fail 561 */ 562 string mset(string[] keysvalues...) { 563 checkIsInMultiOrPipeline(); 564 client.mset(keysvalues); 565 return client.getStatusCodeReply(); 566 } 567 alias mset = BinaryRedis.mset; 568 569 /** 570 * Set the the respective keys to the respective values. {@link #mset(string...) MSET} will 571 * replace old values with new values, while MSETNX will not perform any operation at all even if 572 * just a single key already exists. 573 * <p> 574 * Because of this semantic MSETNX can be used in order to set different keys representing 575 * different fields of an unique logic object in a way that ensures that either all the fields or 576 * none at all are set. 577 * <p> 578 * Both MSET and MSETNX are atomic operations. This means that for instance if the keys A and B 579 * are modified, another client talking to Redis can either see the changes to both A and B at 580 * once, or no modification at all. 581 * @see #mset(string...) 582 * @param keysvalues 583 * @return Integer reply, specifically: 1 if the all the keys were set 0 if no key was set (at 584 * least one key already existed) 585 */ 586 Long msetnx(string[] keysvalues...) { 587 checkIsInMultiOrPipeline(); 588 client.msetnx(keysvalues); 589 return client.getIntegerReply(); 590 } 591 alias msetnx = BinaryRedis.msetnx; 592 593 /** 594 * IDECRBY work just like {@link #decr(string) INCR} but instead to decrement by 1 the decrement 595 * is integer. 596 * <p> 597 * INCR commands are limited to 64 bit signed integers. 598 * <p> 599 * Note: this is actually a string operation, that is, in Redis there are not "integer" types. 600 * Simply the string stored at the key is parsed as a base 10 64 bit signed integer, incremented, 601 * and then converted back as a string. 602 * <p> 603 * Time complexity: O(1) 604 * @see #incr(string) 605 * @see #decr(string) 606 * @see #incrBy(string, long) 607 * @param key 608 * @param decrement 609 * @return Integer reply, this commands will reply with the new value of key after the increment. 610 */ 611 Long decrBy(string key, long decrement) { 612 checkIsInMultiOrPipeline(); 613 client.decrBy(key, decrement); 614 return client.getIntegerReply(); 615 } 616 alias decrBy = BinaryRedis.decrBy; 617 618 /** 619 * Decrement the number stored at key by one. If the key does not exist or contains a value of a 620 * wrong type, set the key to the value of "0" before to perform the decrement operation. 621 * <p> 622 * INCR commands are limited to 64 bit signed integers. 623 * <p> 624 * Note: this is actually a string operation, that is, in Redis there are not "integer" types. 625 * Simply the string stored at the key is parsed as a base 10 64 bit signed integer, incremented, 626 * and then converted back as a string. 627 * <p> 628 * Time complexity: O(1) 629 * @see #incr(string) 630 * @see #incrBy(string, long) 631 * @see #decrBy(string, long) 632 * @param key 633 * @return Integer reply, this commands will reply with the new value of key after the increment. 634 */ 635 Long decr(string key) { 636 checkIsInMultiOrPipeline(); 637 client.decr(key); 638 return client.getIntegerReply(); 639 } 640 alias decr = BinaryRedis.decr; 641 642 /** 643 * INCRBY work just like {@link #incr(string) INCR} but instead to increment by 1 the increment is 644 * integer. 645 * <p> 646 * INCR commands are limited to 64 bit signed integers. 647 * <p> 648 * Note: this is actually a string operation, that is, in Redis there are not "integer" types. 649 * Simply the string stored at the key is parsed as a base 10 64 bit signed integer, incremented, 650 * and then converted back as a string. 651 * <p> 652 * Time complexity: O(1) 653 * @see #incr(string) 654 * @see #decr(string) 655 * @see #decrBy(string, long) 656 * @param key 657 * @param increment 658 * @return Integer reply, this commands will reply with the new value of key after the increment. 659 */ 660 Long incrBy(string key, long increment) { 661 checkIsInMultiOrPipeline(); 662 client.incrBy(key, increment); 663 return client.getIntegerReply(); 664 } 665 alias incrBy = BinaryRedis.incrBy; 666 667 /** 668 * INCRBYFLOAT 669 * <p> 670 * INCRBYFLOAT commands are limited to double precision floating point values. 671 * <p> 672 * Note: this is actually a string operation, that is, in Redis there are not "double" types. 673 * Simply the string stored at the key is parsed as a base double precision floating point value, 674 * incremented, and then converted back as a string. There is no DECRYBYFLOAT but providing a 675 * negative value will work as expected. 676 * <p> 677 * Time complexity: O(1) 678 * @param key 679 * @param increment 680 * @return Double reply, this commands will reply with the new value of key after the increment. 681 */ 682 Double incrByFloat(string key, double increment) { 683 checkIsInMultiOrPipeline(); 684 client.incrByFloat(key, increment); 685 string dval = client.getBulkReply(); 686 return (dval !is null ? new Double(dval) : null); 687 } 688 alias incrByFloat = BinaryRedis.incrByFloat; 689 690 /** 691 * Increment the number stored at key by one. If the key does not exist or contains a value of a 692 * wrong type, set the key to the value of "0" before to perform the increment operation. 693 * <p> 694 * INCR commands are limited to 64 bit signed integers. 695 * <p> 696 * Note: this is actually a string operation, that is, in Redis there are not "integer" types. 697 * Simply the string stored at the key is parsed as a base 10 64 bit signed integer, incremented, 698 * and then converted back as a string. 699 * <p> 700 * Time complexity: O(1) 701 * @see #incrBy(string, long) 702 * @see #decr(string) 703 * @see #decrBy(string, long) 704 * @param key 705 * @return Integer reply, this commands will reply with the new value of key after the increment. 706 */ 707 Long incr(string key) { 708 checkIsInMultiOrPipeline(); 709 client.incr(key); 710 return client.getIntegerReply(); 711 } 712 alias incr = BinaryRedis.incr; 713 714 /** 715 * If the key already exists and is a string, this command appends the provided value at the end 716 * of the string. If the key does not exist it is created and set as an empty string, so APPEND 717 * will be very similar to SET in this special case. 718 * <p> 719 * Time complexity: O(1). The amortized time complexity is O(1) assuming the appended value is 720 * small and the already present value is of any size, since the dynamic string library used by 721 * Redis will double the free space available on every reallocation. 722 * @param key 723 * @param value 724 * @return Integer reply, specifically the total length of the string after the append operation. 725 */ 726 Long append(string key, string value) { 727 checkIsInMultiOrPipeline(); 728 client.append(key, value); 729 return client.getIntegerReply(); 730 } 731 alias append = BinaryRedis.append; 732 733 /** 734 * Return a subset of the string from offset start to offset end (both offsets are inclusive). 735 * Negative offsets can be used in order to provide an offset starting from the end of the string. 736 * So -1 means the last char, -2 the penultimate and so forth. 737 * <p> 738 * The function handles out of range requests without raising an error, but just limiting the 739 * resulting range to the actual length of the string. 740 * <p> 741 * Time complexity: O(start+n) (with start being the start index and n the total length of the 742 * requested range). Note that the lookup part of this command is O(1) so for small strings this 743 * is actually an O(1) command. 744 * @param key 745 * @param start 746 * @param end 747 * @return Bulk reply 748 */ 749 string substr(string key, int start, int end) { 750 checkIsInMultiOrPipeline(); 751 client.substr(key, start, end); 752 return client.getBulkReply(); 753 } 754 alias substr = BinaryRedis.substr; 755 756 /** 757 * Set the specified hash field to the specified value. 758 * <p> 759 * If key does not exist, a new key holding a hash is created. 760 * <p> 761 * <b>Time complexity:</b> O(1) 762 * @param key 763 * @param field 764 * @param value 765 * @return If the field already exists, and the HSET just produced an update of the value, 0 is 766 * returned, otherwise if a new field is created 1 is returned. 767 */ 768 Long hset(string key, string field, string value) { 769 checkIsInMultiOrPipeline(); 770 client.hset(key, field, value); 771 return client.getIntegerReply(); 772 } 773 alias hset = BinaryRedis.hset; 774 775 Long hset(string key, Map!(string, string) hash) { 776 checkIsInMultiOrPipeline(); 777 client.hset(key, hash); 778 return client.getIntegerReply(); 779 } 780 781 /** 782 * If key holds a hash, retrieve the value associated to the specified field. 783 * <p> 784 * If the field is not found or the key does not exist, a special 'nil' value is returned. 785 * <p> 786 * <b>Time complexity:</b> O(1) 787 * @param key 788 * @param field 789 * @return Bulk reply 790 */ 791 string hget(string key, string field) { 792 checkIsInMultiOrPipeline(); 793 client.hget(key, field); 794 return client.getBulkReply(); 795 } 796 alias hget = BinaryRedis.hget; 797 798 /** 799 * Set the specified hash field to the specified value if the field not exists. <b>Time 800 * complexity:</b> O(1) 801 * @param key 802 * @param field 803 * @param value 804 * @return If the field already exists, 0 is returned, otherwise if a new field is created 1 is 805 * returned. 806 */ 807 Long hsetnx(string key, string field, string value) { 808 checkIsInMultiOrPipeline(); 809 client.hsetnx(key, field, value); 810 return client.getIntegerReply(); 811 } 812 alias hsetnx = BinaryRedis.hsetnx; 813 814 /** 815 * Set the respective fields to the respective values. HMSET replaces old values with new values. 816 * <p> 817 * If key does not exist, a new key holding a hash is created. 818 * <p> 819 * <b>Time complexity:</b> O(N) (with N being the number of fields) 820 * @param key 821 * @param hash 822 * @return Return OK or Exception if hash is empty 823 */ 824 string hmset(string key, Map!(string, string) hash) { 825 checkIsInMultiOrPipeline(); 826 client.hmset(key, hash); 827 return client.getStatusCodeReply(); 828 } 829 alias hmset = BinaryRedis.hmset; 830 831 /** 832 * Retrieve the values associated to the specified fields. 833 * <p> 834 * If some of the specified fields do not exist, nil values are returned. Non existing keys are 835 * considered like empty hashes. 836 * <p> 837 * <b>Time complexity:</b> O(N) (with N being the number of fields) 838 * @param key 839 * @param fields 840 * @return Multi Bulk Reply specifically a list of all the values associated with the specified 841 * fields, in the same order of the request. 842 */ 843 List!(string) hmget(string key, string[] fields...) { 844 checkIsInMultiOrPipeline(); 845 client.hmget(key, fields); 846 return client.getMultiBulkReply(); 847 } 848 alias hmget = BinaryRedis.hmget; 849 850 /** 851 * Increment the number stored at field in the hash at key by value. If key does not exist, a new 852 * key holding a hash is created. If field does not exist or holds a string, the value is set to 0 853 * before applying the operation. Since the value argument is signed you can use this command to 854 * perform both increments and decrements. 855 * <p> 856 * The range of values supported by HINCRBY is limited to 64 bit signed integers. 857 * <p> 858 * <b>Time complexity:</b> O(1) 859 * @param key 860 * @param field 861 * @param value 862 * @return Integer reply The new value at field after the increment operation. 863 */ 864 Long hincrBy(string key, string field, long value) { 865 checkIsInMultiOrPipeline(); 866 client.hincrBy(key, field, value); 867 return client.getIntegerReply(); 868 } 869 alias hincrBy = BinaryRedis.hincrBy; 870 871 /** 872 * Increment the number stored at field in the hash at key by a double precision floating point 873 * value. If key does not exist, a new key holding a hash is created. If field does not exist or 874 * holds a string, the value is set to 0 before applying the operation. Since the value argument 875 * is signed you can use this command to perform both increments and decrements. 876 * <p> 877 * The range of values supported by HINCRBYFLOAT is limited to double precision floating point 878 * values. 879 * <p> 880 * <b>Time complexity:</b> O(1) 881 * @param key 882 * @param field 883 * @param value 884 * @return Double precision floating point reply The new value at field after the increment 885 * operation. 886 */ 887 Double hincrByFloat(string key, string field, double value) { 888 checkIsInMultiOrPipeline(); 889 client.hincrByFloat(key, field, value); 890 string dval = client.getBulkReply(); 891 return (dval !is null ? new Double(dval) : null); 892 } 893 alias hincrByFloat = BinaryRedis.hincrByFloat; 894 895 /** 896 * Test for existence of a specified field in a hash. <b>Time complexity:</b> O(1) 897 * @param key 898 * @param field 899 * @return Return true if the hash stored at key contains the specified field. Return false if the key is 900 * not found or the field is not present. 901 */ 902 // override 903 bool hexists(string key, string field) { 904 checkIsInMultiOrPipeline(); 905 client.hexists(key, field); 906 return client.getIntegerReply() == 1; 907 } 908 alias hexists = BinaryRedis.hexists; 909 910 /** 911 * Remove the specified field from an hash stored at key. 912 * <p> 913 * <b>Time complexity:</b> O(1) 914 * @param key 915 * @param fields 916 * @return If the field was present in the hash it is deleted and 1 is returned, otherwise 0 is 917 * returned and no operation is performed. 918 */ 919 Long hdel(string key, string[] fields...) { 920 checkIsInMultiOrPipeline(); 921 client.hdel(key, fields); 922 return client.getIntegerReply(); 923 } 924 alias hdel = BinaryRedis.hdel; 925 926 /** 927 * Return the number of items in a hash. 928 * <p> 929 * <b>Time complexity:</b> O(1) 930 * @param key 931 * @return The number of entries (fields) contained in the hash stored at key. If the specified 932 * key does not exist, 0 is returned assuming an empty hash. 933 */ 934 Long hlen(string key) { 935 checkIsInMultiOrPipeline(); 936 client.hlen(key); 937 return client.getIntegerReply(); 938 } 939 alias hlen = BinaryRedis.hlen; 940 941 /** 942 * Return all the fields in a hash. 943 * <p> 944 * <b>Time complexity:</b> O(N), where N is the total number of entries 945 * @param key 946 * @return All the fields names contained into a hash. 947 */ 948 Set!(string) hkeys(string key) { 949 checkIsInMultiOrPipeline(); 950 client.hkeys(key); 951 return BuilderFactory.STRING_SET.build(cast(Object)client.getBinaryMultiBulkReply()); 952 } 953 alias hkeys = BinaryRedis.hkeys; 954 955 /** 956 * Return all the values in a hash. 957 * <p> 958 * <b>Time complexity:</b> O(N), where N is the total number of entries 959 * @param key 960 * @return All the fields values contained into a hash. 961 */ 962 List!(string) hvals(string key) { 963 checkIsInMultiOrPipeline(); 964 client.hvals(key); 965 List!(string) lresult = client.getMultiBulkReply(); 966 return lresult; 967 } 968 alias hvals = BinaryRedis.hvals; 969 970 /** 971 * Return all the fields and associated values in a hash. 972 * <p> 973 * <b>Time complexity:</b> O(N), where N is the total number of entries 974 * @param key 975 * @return All the fields and values contained into a hash. 976 */ 977 Map!(string, string) hgetAll(string key) { 978 checkIsInMultiOrPipeline(); 979 client.hgetAll(key); 980 return BuilderFactory.STRING_MAP.build(cast(Object)client.getBinaryMultiBulkReply()); 981 } 982 alias hgetAll = BinaryRedis.hgetAll; 983 984 /** 985 * Add the string value to the head (LPUSH) or tail (RPUSH) of the list stored at key. If the key 986 * does not exist an empty list is created just before the append operation. If the key exists but 987 * is not a List an error is returned. 988 * <p> 989 * Time complexity: O(1) 990 * @param key 991 * @param strings 992 * @return Integer reply, specifically, the number of elements inside the list after the push 993 * operation. 994 */ 995 Long rpush(string key, string[] strings...) { 996 checkIsInMultiOrPipeline(); 997 client.rpush(key, strings); 998 return client.getIntegerReply(); 999 } 1000 alias rpush = BinaryRedis.rpush; 1001 1002 /** 1003 * Add the string value to the head (LPUSH) or tail (RPUSH) of the list stored at key. If the key 1004 * does not exist an empty list is created just before the append operation. If the key exists but 1005 * is not a List an error is returned. 1006 * <p> 1007 * Time complexity: O(1) 1008 * @param key 1009 * @param strings 1010 * @return Integer reply, specifically, the number of elements inside the list after the push 1011 * operation. 1012 */ 1013 Long lpush(string key, string[] strings...) { 1014 checkIsInMultiOrPipeline(); 1015 client.lpush(key, strings); 1016 return client.getIntegerReply(); 1017 } 1018 alias lpush = BinaryRedis.lpush; 1019 1020 /** 1021 * Return the length of the list stored at the specified key. If the key does not exist zero is 1022 * returned (the same behaviour as for empty lists). If the value stored at key is not a list an 1023 * error is returned. 1024 * <p> 1025 * Time complexity: O(1) 1026 * @param key 1027 * @return The length of the list. 1028 */ 1029 Long llen(string key) { 1030 checkIsInMultiOrPipeline(); 1031 client.llen(key); 1032 return client.getIntegerReply(); 1033 } 1034 alias llen = BinaryRedis.llen; 1035 1036 /** 1037 * Return the specified elements of the list stored at the specified key. Start and end are 1038 * zero-based indexes. 0 is the first element of the list (the list head), 1 the next element and 1039 * so on. 1040 * <p> 1041 * For example LRANGE foobar 0 2 will return the first three elements of the list. 1042 * <p> 1043 * start and end can also be negative numbers indicating offsets from the end of the list. For 1044 * example -1 is the last element of the list, -2 the penultimate element and so on. 1045 * <p> 1046 * <b>Consistency with range functions in various programming languages</b> 1047 * <p> 1048 * Note that if you have a list of numbers from 0 to 100, LRANGE 0 10 will return 11 elements, 1049 * that is, rightmost item is included. This may or may not be consistent with behavior of 1050 * range-related functions in your programming language of choice (think Ruby's Range.new, 1051 * Array#slice or Python's range() function). 1052 * <p> 1053 * LRANGE behavior is consistent with one of Tcl. 1054 * <p> 1055 * <b>Out-of-range indexes</b> 1056 * <p> 1057 * Indexes out of range will not produce an error: if start is over the end of the list, or start 1058 * > end, an empty list is returned. If end is over the end of the list Redis will threat it 1059 * just like the last element of the list. 1060 * <p> 1061 * Time complexity: O(start+n) (with n being the length of the range and start being the start 1062 * offset) 1063 * @param key 1064 * @param start 1065 * @param stop 1066 * @return Multi bulk reply, specifically a list of elements in the specified range. 1067 */ 1068 List!(string) lrange(string key, long start, long stop) { 1069 checkIsInMultiOrPipeline(); 1070 client.lrange(key, start, stop); 1071 return client.getMultiBulkReply(); 1072 } 1073 alias lrange = BinaryRedis.lrange; 1074 1075 /** 1076 * Trim an existing list so that it will contain only the specified range of elements specified. 1077 * Start and end are zero-based indexes. 0 is the first element of the list (the list head), 1 the 1078 * next element and so on. 1079 * <p> 1080 * For example LTRIM foobar 0 2 will modify the list stored at foobar key so that only the first 1081 * three elements of the list will remain. 1082 * <p> 1083 * start and end can also be negative numbers indicating offsets from the end of the list. For 1084 * example -1 is the last element of the list, -2 the penultimate element and so on. 1085 * <p> 1086 * Indexes out of range will not produce an error: if start is over the end of the list, or start 1087 * > end, an empty list is left as value. If end over the end of the list Redis will threat it 1088 * just like the last element of the list. 1089 * <p> 1090 * Hint: the obvious use of LTRIM is together with LPUSH/RPUSH. For example: 1091 * <p> 1092 * {@code lpush("mylist", "someelement"); ltrim("mylist", 0, 99); * } 1093 * <p> 1094 * The above two commands will push elements in the list taking care that the list will not grow 1095 * without limits. This is very useful when using Redis to store logs for example. It is important 1096 * to note that when used in this way LTRIM is an O(1) operation because in the average case just 1097 * one element is removed from the tail of the list. 1098 * <p> 1099 * Time complexity: O(n) (with n being len of list - len of range) 1100 * @param key 1101 * @param start 1102 * @param stop 1103 * @return Status code reply 1104 */ 1105 string ltrim(string key, long start, long stop) { 1106 checkIsInMultiOrPipeline(); 1107 client.ltrim(key, start, stop); 1108 return client.getStatusCodeReply(); 1109 } 1110 alias ltrim = BinaryRedis.ltrim; 1111 1112 /** 1113 * Return the specified element of the list stored at the specified key. 0 is the first element, 1 1114 * the second and so on. Negative indexes are supported, for example -1 is the last element, -2 1115 * the penultimate and so on. 1116 * <p> 1117 * If the value stored at key is not of list type an error is returned. If the index is out of 1118 * range a 'nil' reply is returned. 1119 * <p> 1120 * Note that even if the average time complexity is O(n) asking for the first or the last element 1121 * of the list is O(1). 1122 * <p> 1123 * Time complexity: O(n) (with n being the length of the list) 1124 * @param key 1125 * @param index 1126 * @return Bulk reply, specifically the requested element 1127 */ 1128 string lindex(string key, long index) { 1129 checkIsInMultiOrPipeline(); 1130 client.lindex(key, index); 1131 return client.getBulkReply(); 1132 } 1133 alias lindex = BinaryRedis.lindex; 1134 1135 /** 1136 * Set a new value as the element at index position of the List at key. 1137 * <p> 1138 * Out of range indexes will generate an error. 1139 * <p> 1140 * Similarly to other list commands accepting indexes, the index can be negative to access 1141 * elements starting from the end of the list. So -1 is the last element, -2 is the penultimate, 1142 * and so forth. 1143 * <p> 1144 * <b>Time complexity:</b> 1145 * <p> 1146 * O(N) (with N being the length of the list), setting the first or last elements of the list is 1147 * O(1). 1148 * @see #lindex(string, long) 1149 * @param key 1150 * @param index 1151 * @param value 1152 * @return Status code reply 1153 */ 1154 string lset(string key, long index, string value) { 1155 checkIsInMultiOrPipeline(); 1156 client.lset(key, index, value); 1157 return client.getStatusCodeReply(); 1158 } 1159 alias lset = BinaryRedis.lset; 1160 1161 /** 1162 * Remove the first count occurrences of the value element from the list. If count is zero all the 1163 * elements are removed. If count is negative elements are removed from tail to head, instead to 1164 * go from head to tail that is the normal behaviour. So for example LREM with count -2 and hello 1165 * as value to remove against the list (a,b,c,hello,x,hello,hello) will leave the list 1166 * (a,b,c,hello,x). The number of removed elements is returned as an integer, see below for more 1167 * information about the returned value. Note that non existing keys are considered like empty 1168 * lists by LREM, so LREM against non existing keys will always return 0. 1169 * <p> 1170 * Time complexity: O(N) (with N being the length of the list) 1171 * @param key 1172 * @param count 1173 * @param value 1174 * @return Integer Reply, specifically: The number of removed elements if the operation succeeded 1175 */ 1176 Long lrem(string key, long count, string value) { 1177 checkIsInMultiOrPipeline(); 1178 client.lrem(key, count, value); 1179 return client.getIntegerReply(); 1180 } 1181 alias lrem = BinaryRedis.lrem; 1182 1183 /** 1184 * Atomically return and remove the first (LPOP) or last (RPOP) element of the list. For example 1185 * if the list contains the elements "a","b","c" LPOP will return "a" and the list will become 1186 * "b","c". 1187 * <p> 1188 * If the key does not exist or the list is already empty the special value 'nil' is returned. 1189 * @see #rpop(string) 1190 * @param key 1191 * @return Bulk reply 1192 */ 1193 string lpop(string key) { 1194 checkIsInMultiOrPipeline(); 1195 client.lpop(key); 1196 return client.getBulkReply(); 1197 } 1198 alias lpop = BinaryRedis.lpop; 1199 1200 /** 1201 * Atomically return and remove the first (LPOP) or last (RPOP) element of the list. For example 1202 * if the list contains the elements "a","b","c" RPOP will return "c" and the list will become 1203 * "a","b". 1204 * <p> 1205 * If the key does not exist or the list is already empty the special value 'nil' is returned. 1206 * @see #lpop(string) 1207 * @param key 1208 * @return Bulk reply 1209 */ 1210 string rpop(string key) { 1211 checkIsInMultiOrPipeline(); 1212 client.rpop(key); 1213 return client.getBulkReply(); 1214 } 1215 alias rpop = BinaryRedis.rpop; 1216 1217 /** 1218 * Atomically return and remove the last (tail) element of the srckey list, and push the element 1219 * as the first (head) element of the dstkey list. For example if the source list contains the 1220 * elements "a","b","c" and the destination list contains the elements "foo","bar" after an 1221 * RPOPLPUSH command the content of the two lists will be "a","b" and "c","foo","bar". 1222 * <p> 1223 * If the key does not exist or the list is already empty the special value 'nil' is returned. If 1224 * the srckey and dstkey are the same the operation is equivalent to removing the last element 1225 * from the list and pushing it as first element of the list, so it's a "list rotation" command. 1226 * <p> 1227 * Time complexity: O(1) 1228 * @param srckey 1229 * @param dstkey 1230 * @return Bulk reply 1231 */ 1232 string rpoplpush(string srckey, string dstkey) { 1233 checkIsInMultiOrPipeline(); 1234 client.rpoplpush(srckey, dstkey); 1235 return client.getBulkReply(); 1236 } 1237 alias rpoplpush = BinaryRedis.rpoplpush; 1238 1239 /** 1240 * Add the specified member to the set value stored at key. If member is already a member of the 1241 * set no operation is performed. If key does not exist a new set with the specified member as 1242 * sole member is created. If the key exists but does not hold a set value an error is returned. 1243 * <p> 1244 * Time complexity O(1) 1245 * @param key 1246 * @param members 1247 * @return Integer reply, specifically: 1 if the new element was added 0 if the element was 1248 * already a member of the set 1249 */ 1250 Long sadd(string key, string[] members...) { 1251 checkIsInMultiOrPipeline(); 1252 client.sadd(key, members); 1253 return client.getIntegerReply(); 1254 } 1255 alias sadd = BinaryRedis.sadd; 1256 1257 /** 1258 * Return all the members (elements) of the set value stored at key. This is just syntax glue for 1259 * {@link #sinter(string...) SINTER}. 1260 * <p> 1261 * Time complexity O(N) 1262 * @param key 1263 * @return Multi bulk reply 1264 */ 1265 Set!(string) smembers(string key) { 1266 checkIsInMultiOrPipeline(); 1267 client.smembers(key); 1268 List!(string) members = client.getMultiBulkReply(); 1269 return new SetFromList!string(members); 1270 } 1271 alias smembers = BinaryRedis.smembers; 1272 1273 /** 1274 * Remove the specified member from the set value stored at key. If member was not a member of the 1275 * set no operation is performed. If key does not hold a set value an error is returned. 1276 * <p> 1277 * Time complexity O(1) 1278 * @param key 1279 * @param members 1280 * @return Integer reply, specifically: 1 if the new element was removed 0 if the new element was 1281 * not a member of the set 1282 */ 1283 Long srem(string key, string[] members...) { 1284 checkIsInMultiOrPipeline(); 1285 client.srem(key, members); 1286 return client.getIntegerReply(); 1287 } 1288 alias srem = BinaryRedis.srem; 1289 1290 /** 1291 * Remove a random element from a Set returning it as return value. If the Set is empty or the key 1292 * does not exist, a nil object is returned. 1293 * <p> 1294 * The {@link #srandmember(string)} command does a similar work but the returned element is not 1295 * removed from the Set. 1296 * <p> 1297 * Time complexity O(1) 1298 * @param key 1299 * @return Bulk reply 1300 */ 1301 string spop(string key) { 1302 checkIsInMultiOrPipeline(); 1303 client.spop(key); 1304 return client.getBulkReply(); 1305 } 1306 alias spop = BinaryRedis.spop; 1307 1308 Set!(string) spop(string key, long count) { 1309 checkIsInMultiOrPipeline(); 1310 client.spop(key, count); 1311 List!(string) members = client.getMultiBulkReply(); 1312 if (members is null) return null; 1313 return new SetFromList!string(members); 1314 } 1315 1316 /** 1317 * Move the specified member from the set at srckey to the set at dstkey. This operation is 1318 * atomic, in every given moment the element will appear to be in the source or destination set 1319 * for accessing clients. 1320 * <p> 1321 * If the source set does not exist or does not contain the specified element no operation is 1322 * performed and zero is returned, otherwise the element is removed from the source set and added 1323 * to the destination set. On success one is returned, even if the element was already present in 1324 * the destination set. 1325 * <p> 1326 * An error is raised if the source or destination keys contain a non Set value. 1327 * <p> 1328 * Time complexity O(1) 1329 * @param srckey 1330 * @param dstkey 1331 * @param member 1332 * @return Integer reply, specifically: 1 if the element was moved 0 if the element was not found 1333 * on the first set and no operation was performed 1334 */ 1335 Long smove(string srckey, string dstkey, string member) { 1336 checkIsInMultiOrPipeline(); 1337 client.smove(srckey, dstkey, member); 1338 return client.getIntegerReply(); 1339 } 1340 alias smove = BinaryRedis.smove; 1341 1342 /** 1343 * Return the set cardinality (number of elements). If the key does not exist 0 is returned, like 1344 * for empty sets. 1345 * @param key 1346 * @return Integer reply, specifically: the cardinality (number of elements) of the set as an 1347 * integer. 1348 */ 1349 Long scard(string key) { 1350 checkIsInMultiOrPipeline(); 1351 client.scard(key); 1352 return client.getIntegerReply(); 1353 } 1354 alias scard = BinaryRedis.scard; 1355 1356 /** 1357 * Return true if member is a member of the set stored at key, otherwise false is returned. 1358 * <p> 1359 * Time complexity O(1) 1360 * @param key 1361 * @param member 1362 * @return bool reply, specifically: true if the element is a member of the set false if the element 1363 * is not a member of the set OR if the key does not exist 1364 */ 1365 bool sismember(string key, string member) { 1366 checkIsInMultiOrPipeline(); 1367 client.sismember(key, member); 1368 return client.getIntegerReply() == 1; 1369 } 1370 alias sismember = BinaryRedis.sismember; 1371 1372 /** 1373 * Return the members of a set resulting from the intersection of all the sets hold at the 1374 * specified keys. Like in {@link #lrange(string, long, long) LRANGE} the result is sent to the 1375 * client as a multi-bulk reply (see the protocol specification for more information). If just a 1376 * single key is specified, then this command produces the same result as 1377 * {@link #smembers(string) SMEMBERS}. Actually SMEMBERS is just syntax sugar for SINTER. 1378 * <p> 1379 * Non existing keys are considered like empty sets, so if one of the keys is missing an empty set 1380 * is returned (since the intersection with an empty set always is an empty set). 1381 * <p> 1382 * Time complexity O(N*M) worst case where N is the cardinality of the smallest set and M the 1383 * number of sets 1384 * @param keys 1385 * @return Multi bulk reply, specifically the list of common elements. 1386 */ 1387 Set!(string) sinter(string[] keys...) { 1388 checkIsInMultiOrPipeline(); 1389 client.sinter(keys); 1390 List!(string) members = client.getMultiBulkReply(); 1391 return new SetFromList!string(members); 1392 } 1393 alias sinter = BinaryRedis.sinter; 1394 1395 /** 1396 * This command works exactly like {@link #sinter(string...) SINTER} but instead of being returned 1397 * the resulting set is stored as dstkey. 1398 * <p> 1399 * Time complexity O(N*M) worst case where N is the cardinality of the smallest set and M the 1400 * number of sets 1401 * @param dstkey 1402 * @param keys 1403 * @return Status code reply 1404 */ 1405 Long sinterstore(string dstkey, string[] keys...) { 1406 checkIsInMultiOrPipeline(); 1407 client.sinterstore(dstkey, keys); 1408 return client.getIntegerReply(); 1409 } 1410 alias sinterstore = BinaryRedis.sinterstore; 1411 1412 /** 1413 * Return the members of a set resulting from the union of all the sets hold at the specified 1414 * keys. Like in {@link #lrange(string, long, long) LRANGE} the result is sent to the client as a 1415 * multi-bulk reply (see the protocol specification for more information). If just a single key is 1416 * specified, then this command produces the same result as {@link #smembers(string) SMEMBERS}. 1417 * <p> 1418 * Non existing keys are considered like empty sets. 1419 * <p> 1420 * Time complexity O(N) where N is the total number of elements in all the provided sets 1421 * @param keys 1422 * @return Multi bulk reply, specifically the list of common elements. 1423 */ 1424 Set!(string) sunion(string[] keys...) { 1425 checkIsInMultiOrPipeline(); 1426 client.sunion(keys); 1427 List!(string) members = client.getMultiBulkReply(); 1428 return new SetFromList!string(members); 1429 } 1430 alias sunion = BinaryRedis.sunion; 1431 1432 /** 1433 * This command works exactly like {@link #sunion(string...) SUNION} but instead of being returned 1434 * the resulting set is stored as dstkey. Any existing value in dstkey will be over-written. 1435 * <p> 1436 * Time complexity O(N) where N is the total number of elements in all the provided sets 1437 * @param dstkey 1438 * @param keys 1439 * @return Status code reply 1440 */ 1441 Long sunionstore(string dstkey, string[] keys...) { 1442 checkIsInMultiOrPipeline(); 1443 client.sunionstore(dstkey, keys); 1444 return client.getIntegerReply(); 1445 } 1446 alias sunionstore = BinaryRedis.sunionstore; 1447 1448 /** 1449 * Return the difference between the Set stored at key1 and all the Sets key2, ..., keyN 1450 * <p> 1451 * <b>Example:</b> 1452 * 1453 * <pre> 1454 * key1 = [x, a, b, c] 1455 * key2 = [c] 1456 * key3 = [a, d] 1457 * SDIFF key1,key2,key3 => [x, b] 1458 * </pre> 1459 * 1460 * Non existing keys are considered like empty sets. 1461 * <p> 1462 * <b>Time complexity:</b> 1463 * <p> 1464 * O(N) with N being the total number of elements of all the sets 1465 * @param keys 1466 * @return Return the members of a set resulting from the difference between the first set 1467 * provided and all the successive sets. 1468 */ 1469 Set!(string) sdiff(string[] keys...) { 1470 checkIsInMultiOrPipeline(); 1471 client.sdiff(keys); 1472 return BuilderFactory.STRING_SET.build(cast(Object)client.getBinaryMultiBulkReply()); 1473 } 1474 1475 /** 1476 * This command works exactly like {@link #sdiff(string...) SDIFF} but instead of being returned 1477 * the resulting set is stored in dstkey. 1478 * @param dstkey 1479 * @param keys 1480 * @return Status code reply 1481 */ 1482 Long sdiffstore(string dstkey, string[] keys...) { 1483 checkIsInMultiOrPipeline(); 1484 client.sdiffstore(dstkey, keys); 1485 return client.getIntegerReply(); 1486 } 1487 alias sdiffstore = BinaryRedis.sdiffstore; 1488 1489 /** 1490 * Return a random element from a Set, without removing the element. If the Set is empty or the 1491 * key does not exist, a nil object is returned. 1492 * <p> 1493 * The SPOP command does a similar work but the returned element is popped (removed) from the Set. 1494 * <p> 1495 * Time complexity O(1) 1496 * @param key 1497 * @return Bulk reply 1498 */ 1499 string srandmember(string key) { 1500 checkIsInMultiOrPipeline(); 1501 client.srandmember(key); 1502 return client.getBulkReply(); 1503 } 1504 alias srandmember = BinaryRedis.srandmember; 1505 1506 List!(string) srandmember(string key, int count) { 1507 checkIsInMultiOrPipeline(); 1508 client.srandmember(key, count); 1509 return client.getMultiBulkReply(); 1510 } 1511 1512 /** 1513 * Add the specified member having the specified score to the sorted set stored at key. If member 1514 * is already a member of the sorted set the score is updated, and the element reinserted in the 1515 * right position to ensure sorting. If key does not exist a new sorted set with the specified 1516 * member as sole member is created. If the key exists but does not hold a sorted set value an 1517 * error is returned. 1518 * <p> 1519 * The score value can be the string representation of a double precision floating point number. 1520 * <p> 1521 * Time complexity O(log(N)) with N being the number of elements in the sorted set 1522 * @param key 1523 * @param score 1524 * @param member 1525 * @return Integer reply, specifically: 1 if the new element was added 0 if the element was 1526 * already a member of the sorted set and the score was updated 1527 */ 1528 Long zadd(string key, double score, string member) { 1529 checkIsInMultiOrPipeline(); 1530 client.zadd(key, score, member); 1531 return client.getIntegerReply(); 1532 } 1533 alias zadd = BinaryRedis.zadd; 1534 1535 Long zadd(string key, double score, string member, 1536 ZAddParams params) { 1537 checkIsInMultiOrPipeline(); 1538 client.zadd(key, score, member, params); 1539 return client.getIntegerReply(); 1540 } 1541 1542 Long zadd(string key, Map!(string, double) scoreMembers) { 1543 checkIsInMultiOrPipeline(); 1544 client.zadd(key, scoreMembers); 1545 return client.getIntegerReply(); 1546 } 1547 1548 Long zadd(string key, Map!(string, double) scoreMembers, ZAddParams params) { 1549 checkIsInMultiOrPipeline(); 1550 client.zadd(key, scoreMembers, params); 1551 return client.getIntegerReply(); 1552 } 1553 1554 string[] zrange(string key, long start, long stop) { 1555 checkIsInMultiOrPipeline(); 1556 client.zrange(key, start, stop); 1557 List!(string) members = client.getMultiBulkReply(); 1558 // return new SetFromList!string(members); 1559 return members.toArray(); 1560 } 1561 alias zrange = BinaryRedis.zrange; 1562 1563 /** 1564 * Remove the specified member from the sorted set value stored at key. If member was not a member 1565 * of the set no operation is performed. If key does not not hold a set value an error is 1566 * returned. 1567 * <p> 1568 * Time complexity O(log(N)) with N being the number of elements in the sorted set 1569 * @param key 1570 * @param members 1571 * @return Integer reply, specifically: 1 if the new element was removed 0 if the new element was 1572 * not a member of the set 1573 */ 1574 Long zrem(string key, string[] members...) { 1575 checkIsInMultiOrPipeline(); 1576 client.zrem(key, members); 1577 return client.getIntegerReply(); 1578 } 1579 alias zrem = BinaryRedis.zrem; 1580 1581 /** 1582 * If member already exists in the sorted set adds the increment to its score and updates the 1583 * position of the element in the sorted set accordingly. If member does not already exist in the 1584 * sorted set it is added with increment as score (that is, like if the previous score was 1585 * virtually zero). If key does not exist a new sorted set with the specified member as sole 1586 * member is created. If the key exists but does not hold a sorted set value an error is returned. 1587 * <p> 1588 * The score value can be the string representation of a double precision floating point number. 1589 * It's possible to provide a negative value to perform a decrement. 1590 * <p> 1591 * For an introduction to sorted sets check the Introduction to Redis data types page. 1592 * <p> 1593 * Time complexity O(log(N)) with N being the number of elements in the sorted set 1594 * @param key 1595 * @param increment 1596 * @param member 1597 * @return The new score 1598 */ 1599 double zincrby(string key, double increment, string member) { 1600 checkIsInMultiOrPipeline(); 1601 client.zincrby(key, increment, member); 1602 Double r = BuilderFactory.DOUBLE.build(cast(Object)client.getOne()); 1603 return r.value(); 1604 } 1605 alias zincrby = BinaryRedis.zincrby; 1606 1607 double zincrby(string key, double increment, string member, ZIncrByParams params) { 1608 checkIsInMultiOrPipeline(); 1609 client.zincrby(key, increment, member, params); 1610 Double r = BuilderFactory.DOUBLE.build(cast(Object)client.getOne()); 1611 return r.value(); 1612 } 1613 1614 /** 1615 * Return the rank (or index) of member in the sorted set at key, with scores being ordered from 1616 * low to high. 1617 * <p> 1618 * When the given member does not exist in the sorted set, the special value 'nil' is returned. 1619 * The returned rank (or index) of the member is 0-based for both commands. 1620 * <p> 1621 * <b>Time complexity:</b> 1622 * <p> 1623 * O(log(N)) 1624 * @see #zrevrank(string, string) 1625 * @param key 1626 * @param member 1627 * @return Integer reply or a nil bulk reply, specifically: the rank of the element as an integer 1628 * reply if the element exists. A nil bulk reply if there is no such element. 1629 */ 1630 Long zrank(string key, string member) { 1631 checkIsInMultiOrPipeline(); 1632 client.zrank(key, member); 1633 return client.getIntegerReply(); 1634 } 1635 alias zrank = BinaryRedis.zrank; 1636 1637 /** 1638 * Return the rank (or index) of member in the sorted set at key, with scores being ordered from 1639 * high to low. 1640 * <p> 1641 * When the given member does not exist in the sorted set, the special value 'nil' is returned. 1642 * The returned rank (or index) of the member is 0-based for both commands. 1643 * <p> 1644 * <b>Time complexity:</b> 1645 * <p> 1646 * O(log(N)) 1647 * @see #zrank(string, string) 1648 * @param key 1649 * @param member 1650 * @return Integer reply or a nil bulk reply, specifically: the rank of the element as an integer 1651 * reply if the element exists. A nil bulk reply if there is no such element. 1652 */ 1653 Long zrevrank(string key, string member) { 1654 checkIsInMultiOrPipeline(); 1655 client.zrevrank(key, member); 1656 return client.getIntegerReply(); 1657 } 1658 alias zrevrank = BinaryRedis.zrevrank; 1659 1660 string[] zrevrange(string key, long start, long stop) { 1661 checkIsInMultiOrPipeline(); 1662 client.zrevrange(key, start, stop); 1663 List!(string) members = client.getMultiBulkReply(); 1664 return members.toArray(); 1665 // return new SetFromList!string(members); 1666 } 1667 alias zrevrange = BinaryRedis.zrevrange; 1668 1669 Set!(Tuple) zrangeWithScores(string key, long start, long stop) { 1670 checkIsInMultiOrPipeline(); 1671 client.zrangeWithScores(key, start, stop); 1672 return getTupledSet(); 1673 } 1674 alias zrangeWithScores = BinaryRedis.zrangeWithScores; 1675 1676 Set!(Tuple) zrevrangeWithScores(string key, long start, long stop) { 1677 checkIsInMultiOrPipeline(); 1678 client.zrevrangeWithScores(key, start, stop); 1679 return getTupledSet(); 1680 } 1681 alias zrevrangeWithScores = BinaryRedis.zrevrangeWithScores; 1682 1683 /** 1684 * Return the sorted set cardinality (number of elements). If the key does not exist 0 is 1685 * returned, like for empty sorted sets. 1686 * <p> 1687 * Time complexity O(1) 1688 * @param key 1689 * @return the cardinality (number of elements) of the set as an integer. 1690 */ 1691 Long zcard(string key) { 1692 checkIsInMultiOrPipeline(); 1693 client.zcard(key); 1694 return client.getIntegerReply(); 1695 } 1696 alias zcard = BinaryRedis.zcard; 1697 1698 /** 1699 * Return the score of the specified element of the sorted set at key. If the specified element 1700 * does not exist in the sorted set, or the key does not exist at all, a special 'nil' value is 1701 * returned. 1702 * <p> 1703 * <b>Time complexity:</b> O(1) 1704 * @param key 1705 * @param member 1706 * @return the score 1707 */ 1708 Double zscore(string key, string member) { 1709 checkIsInMultiOrPipeline(); 1710 client.zscore(key, member); 1711 return BuilderFactory.DOUBLE.build(cast(Object)client.getOne()); 1712 } 1713 alias zscore = BinaryRedis.zscore; 1714 1715 string watch(string[] keys...) { 1716 client.watch(keys); 1717 return client.getStatusCodeReply(); 1718 } 1719 alias watch = BinaryRedis.watch; 1720 1721 /** 1722 * Sort a Set or a List. 1723 * <p> 1724 * Sort the elements contained in the List, Set, or Sorted Set value at key. By default sorting is 1725 * numeric with elements being compared as double precision floating point numbers. This is the 1726 * simplest form of SORT. 1727 * @see #sort(string, string) 1728 * @see #sort(string, SortingParams) 1729 * @see #sort(string, SortingParams, string) 1730 * @param key 1731 * @return Assuming the Set/List at key contains a list of numbers, the return value will be the 1732 * list of numbers ordered from the smallest to the biggest number. 1733 */ 1734 List!(string) sort(string key) { 1735 checkIsInMultiOrPipeline(); 1736 client.sort(key); 1737 return client.getMultiBulkReply(); 1738 } 1739 alias sort = BinaryRedis.sort; 1740 1741 /** 1742 * Sort a Set or a List accordingly to the specified parameters. 1743 * <p> 1744 * <b>examples:</b> 1745 * <p> 1746 * Given are the following sets and key/values: 1747 * 1748 * <pre> 1749 * x = [1, 2, 3] 1750 * y = [a, b, c] 1751 * 1752 * k1 = z 1753 * k2 = y 1754 * k3 = x 1755 * 1756 * w1 = 9 1757 * w2 = 8 1758 * w3 = 7 1759 * </pre> 1760 * 1761 * Sort Order: 1762 * 1763 * <pre> 1764 * sort(x) or sort(x, sp.asc()) 1765 * -> [1, 2, 3] 1766 * 1767 * sort(x, sp.desc()) 1768 * -> [3, 2, 1] 1769 * 1770 * sort(y) 1771 * -> [c, a, b] 1772 * 1773 * sort(y, sp.alpha()) 1774 * -> [a, b, c] 1775 * 1776 * sort(y, sp.alpha().desc()) 1777 * -> [c, a, b] 1778 * </pre> 1779 * 1780 * Limit (e.g. for Pagination): 1781 * 1782 * <pre> 1783 * sort(x, sp.limit(0, 2)) 1784 * -> [1, 2] 1785 * 1786 * sort(y, sp.alpha().desc().limit(1, 2)) 1787 * -> [b, a] 1788 * </pre> 1789 * 1790 * Sorting by external keys: 1791 * 1792 * <pre> 1793 * sort(x, sb.by(w*)) 1794 * -> [3, 2, 1] 1795 * 1796 * sort(x, sb.by(w*).desc()) 1797 * -> [1, 2, 3] 1798 * </pre> 1799 * 1800 * Getting external keys: 1801 * 1802 * <pre> 1803 * sort(x, sp.by(w*).get(k*)) 1804 * -> [x, y, z] 1805 * 1806 * sort(x, sp.by(w*).get(#).get(k*)) 1807 * -> [3, x, 2, y, 1, z] 1808 * </pre> 1809 * @see #sort(string) 1810 * @see #sort(string, SortingParams, string) 1811 * @param key 1812 * @param sortingParameters 1813 * @return a list of sorted elements. 1814 */ 1815 List!(string) sort(string key, SortingParams sortingParameters) { 1816 checkIsInMultiOrPipeline(); 1817 client.sort(key, sortingParameters); 1818 return client.getMultiBulkReply(); 1819 } 1820 1821 /** 1822 * BLPOP (and BRPOP) is a blocking list pop primitive. You can see this commands as blocking 1823 * versions of LPOP and RPOP able to block if the specified keys don't exist or contain empty 1824 * lists. 1825 * <p> 1826 * The following is a description of the exact semantic. We describe BLPOP but the two commands 1827 * are identical, the only difference is that BLPOP pops the element from the left (head) of the 1828 * list, and BRPOP pops from the right (tail). 1829 * <p> 1830 * <b>Non blocking behavior</b> 1831 * <p> 1832 * When BLPOP is called, if at least one of the specified keys contain a non empty list, an 1833 * element is popped from the head of the list and returned to the caller together with the name 1834 * of the key (BLPOP returns a two elements array, the first element is the key, the second the 1835 * popped value). 1836 * <p> 1837 * Keys are scanned from left to right, so for instance if you issue BLPOP list1 list2 list3 0 1838 * against a dataset where list1 does not exist but list2 and list3 contain non empty lists, BLPOP 1839 * guarantees to return an element from the list stored at list2 (since it is the first non empty 1840 * list starting from the left). 1841 * <p> 1842 * <b>Blocking behavior</b> 1843 * <p> 1844 * If none of the specified keys exist or contain non empty lists, BLPOP blocks until some other 1845 * client performs a LPUSH or an RPUSH operation against one of the lists. 1846 * <p> 1847 * Once new data is present on one of the lists, the client finally returns with the name of the 1848 * key unblocking it and the popped value. 1849 * <p> 1850 * When blocking, if a non-zero timeout is specified, the client will unblock returning a nil 1851 * special value if the specified amount of seconds passed without a push operation against at 1852 * least one of the specified keys. 1853 * <p> 1854 * The timeout argument is interpreted as an integer value. A timeout of zero means instead to 1855 * block forever. 1856 * <p> 1857 * <b>Multiple clients blocking for the same keys</b> 1858 * <p> 1859 * Multiple clients can block for the same key. They are put into a queue, so the first to be 1860 * served will be the one that started to wait earlier, in a first-blpopping first-served fashion. 1861 * <p> 1862 * <b>blocking POP inside a MULTI/EXEC transaction</b> 1863 * <p> 1864 * BLPOP and BRPOP can be used with pipelining (sending multiple commands and reading the replies 1865 * in batch), but it does not make sense to use BLPOP or BRPOP inside a MULTI/EXEC block (a Redis 1866 * transaction). 1867 * <p> 1868 * The behavior of BLPOP inside MULTI/EXEC when the list is empty is to return a multi-bulk nil 1869 * reply, exactly what happens when the timeout is reached. If you like science fiction, think at 1870 * it like if inside MULTI/EXEC the time will flow at infinite speed :) 1871 * <p> 1872 * Time complexity: O(1) 1873 * @see #brpop(int, string...) 1874 * @param timeout 1875 * @param keys 1876 * @return BLPOP returns a two-elements array via a multi bulk reply in order to return both the 1877 * unblocking key and the popped value. 1878 * <p> 1879 * When a non-zero timeout is specified, and the BLPOP operation timed out, the return 1880 * value is a nil multi bulk reply. Most client values will return false or nil 1881 * accordingly to the programming language used. 1882 */ 1883 List!(string) blpop(int timeout, string[] keys...) { 1884 return blpop(getArgsAddTimeout(timeout, keys)); 1885 } 1886 alias blpop = BinaryRedis.blpop; 1887 1888 private string[] getArgsAddTimeout(int timeout, string[] keys) { 1889 int keyCount = cast(int)keys.length; 1890 string[] args = new string[keyCount + 1]; 1891 for (int at = 0; at != keyCount; ++at) { 1892 args[at] = keys[at]; 1893 } 1894 1895 args[keyCount] = to!string(timeout); 1896 return args; 1897 } 1898 1899 List!(string) blpop(string[] args...) { 1900 checkIsInMultiOrPipeline(); 1901 client.blpop(args); 1902 client.setTimeoutInfinite(); 1903 try { 1904 return client.getMultiBulkReply(); 1905 } finally { 1906 client.rollbackTimeout(); 1907 } 1908 } 1909 1910 List!(string) brpop(string[] args...) { 1911 checkIsInMultiOrPipeline(); 1912 client.brpop(args); 1913 client.setTimeoutInfinite(); 1914 try { 1915 return client.getMultiBulkReply(); 1916 } finally { 1917 client.rollbackTimeout(); 1918 } 1919 } 1920 alias brpop = BinaryRedis.brpop; 1921 1922 /** 1923 * Sort a Set or a List accordingly to the specified parameters and store the result at dstkey. 1924 * @see #sort(string, SortingParams) 1925 * @see #sort(string) 1926 * @see #sort(string, string) 1927 * @param key 1928 * @param sortingParameters 1929 * @param dstkey 1930 * @return The number of elements of the list at dstkey. 1931 */ 1932 Long sort(string key, SortingParams sortingParameters, string dstkey) { 1933 checkIsInMultiOrPipeline(); 1934 client.sort(key, sortingParameters, dstkey); 1935 return client.getIntegerReply(); 1936 } 1937 alias sort = BinaryRedis.sort; 1938 1939 /** 1940 * Sort a Set or a List and Store the Result at dstkey. 1941 * <p> 1942 * Sort the elements contained in the List, Set, or Sorted Set value at key and store the result 1943 * at dstkey. By default sorting is numeric with elements being compared as double precision 1944 * floating point numbers. This is the simplest form of SORT. 1945 * @see #sort(string) 1946 * @see #sort(string, SortingParams) 1947 * @see #sort(string, SortingParams, string) 1948 * @param key 1949 * @param dstkey 1950 * @return The number of elements of the list at dstkey. 1951 */ 1952 Long sort(string key, string dstkey) { 1953 checkIsInMultiOrPipeline(); 1954 client.sort(key, dstkey); 1955 return client.getIntegerReply(); 1956 } 1957 1958 /** 1959 * BLPOP (and BRPOP) is a blocking list pop primitive. You can see this commands as blocking 1960 * versions of LPOP and RPOP able to block if the specified keys don't exist or contain empty 1961 * lists. 1962 * <p> 1963 * The following is a description of the exact semantic. We describe BLPOP but the two commands 1964 * are identical, the only difference is that BLPOP pops the element from the left (head) of the 1965 * list, and BRPOP pops from the right (tail). 1966 * <p> 1967 * <b>Non blocking behavior</b> 1968 * <p> 1969 * When BLPOP is called, if at least one of the specified keys contain a non empty list, an 1970 * element is popped from the head of the list and returned to the caller together with the name 1971 * of the key (BLPOP returns a two elements array, the first element is the key, the second the 1972 * popped value). 1973 * <p> 1974 * Keys are scanned from left to right, so for instance if you issue BLPOP list1 list2 list3 0 1975 * against a dataset where list1 does not exist but list2 and list3 contain non empty lists, BLPOP 1976 * guarantees to return an element from the list stored at list2 (since it is the first non empty 1977 * list starting from the left). 1978 * <p> 1979 * <b>Blocking behavior</b> 1980 * <p> 1981 * If none of the specified keys exist or contain non empty lists, BLPOP blocks until some other 1982 * client performs a LPUSH or an RPUSH operation against one of the lists. 1983 * <p> 1984 * Once new data is present on one of the lists, the client finally returns with the name of the 1985 * key unblocking it and the popped value. 1986 * <p> 1987 * When blocking, if a non-zero timeout is specified, the client will unblock returning a nil 1988 * special value if the specified amount of seconds passed without a push operation against at 1989 * least one of the specified keys. 1990 * <p> 1991 * The timeout argument is interpreted as an integer value. A timeout of zero means instead to 1992 * block forever. 1993 * <p> 1994 * <b>Multiple clients blocking for the same keys</b> 1995 * <p> 1996 * Multiple clients can block for the same key. They are put into a queue, so the first to be 1997 * served will be the one that started to wait earlier, in a first-blpopping first-served fashion. 1998 * <p> 1999 * <b>blocking POP inside a MULTI/EXEC transaction</b> 2000 * <p> 2001 * BLPOP and BRPOP can be used with pipelining (sending multiple commands and reading the replies 2002 * in batch), but it does not make sense to use BLPOP or BRPOP inside a MULTI/EXEC block (a Redis 2003 * transaction). 2004 * <p> 2005 * The behavior of BLPOP inside MULTI/EXEC when the list is empty is to return a multi-bulk nil 2006 * reply, exactly what happens when the timeout is reached. If you like science fiction, think at 2007 * it like if inside MULTI/EXEC the time will flow at infinite speed :) 2008 * <p> 2009 * Time complexity: O(1) 2010 * @see #blpop(int, string...) 2011 * @param timeout 2012 * @param keys 2013 * @return BLPOP returns a two-elements array via a multi bulk reply in order to return both the 2014 * unblocking key and the popped value. 2015 * <p> 2016 * When a non-zero timeout is specified, and the BLPOP operation timed out, the return 2017 * value is a nil multi bulk reply. Most client values will return false or nil 2018 * accordingly to the programming language used. 2019 */ 2020 List!(string) brpop(int timeout, string[] keys...) { 2021 return brpop(getArgsAddTimeout(timeout, keys)); 2022 } 2023 alias brpop = BinaryRedis.brpop; 2024 2025 Long zcount(string key, double min, double max) { 2026 checkIsInMultiOrPipeline(); 2027 client.zcount(key, min, max); 2028 return client.getIntegerReply(); 2029 } 2030 alias zcount = BinaryRedis.zcount; 2031 2032 Long zcount(string key, string min, string max) { 2033 checkIsInMultiOrPipeline(); 2034 client.zcount(key, min, max); 2035 return client.getIntegerReply(); 2036 } 2037 2038 /** 2039 * Return the all the elements in the sorted set at key with a score between min and max 2040 * (including elements with score equal to min or max). 2041 * <p> 2042 * The elements having the same score are returned sorted lexicographically as ASCII strings (this 2043 * follows from a property of Redis sorted sets and does not involve further computation). 2044 * <p> 2045 * Using the optional {@link #zrangeByScore(string, double, double, int, int) LIMIT} it's possible 2046 * to get only a range of the matching elements in an SQL-alike way. Note that if offset is large 2047 * the commands needs to traverse the list for offset elements and this adds up to the O(M) 2048 * figure. 2049 * <p> 2050 * The {@link #zcount(string, double, double) ZCOUNT} command is similar to 2051 * {@link #zrangeByScore(string, double, double) ZRANGEBYSCORE} but instead of returning the 2052 * actual elements in the specified interval, it just returns the number of matching elements. 2053 * <p> 2054 * <b>Exclusive intervals and infinity</b> 2055 * <p> 2056 * min and max can be -inf and +inf, so that you are not required to know what's the greatest or 2057 * smallest element in order to take, for instance, elements "up to a given value". 2058 * <p> 2059 * Also while the interval is for default closed (inclusive) it's possible to specify open 2060 * intervals prefixing the score with a "(" character, so for instance: 2061 * <p> 2062 * {@code ZRANGEBYSCORE zset (1.3 5} 2063 * <p> 2064 * Will return all the values with score > 1.3 and <= 5, while for instance: 2065 * <p> 2066 * {@code ZRANGEBYSCORE zset (5 (10} 2067 * <p> 2068 * Will return all the values with score > 5 and < 10 (5 and 10 excluded). 2069 * <p> 2070 * <b>Time complexity:</b> 2071 * <p> 2072 * O(log(N))+O(M) with N being the number of elements in the sorted set and M the number of 2073 * elements returned by the command, so if M is constant (for instance you always ask for the 2074 * first ten elements with LIMIT) you can consider it O(log(N)) 2075 * @see #zrangeByScore(string, double, double) 2076 * @see #zrangeByScore(string, double, double, int, int) 2077 * @see #zrangeByScoreWithScores(string, double, double) 2078 * @see #zrangeByScoreWithScores(string, string, string) 2079 * @see #zrangeByScoreWithScores(string, double, double, int, int) 2080 * @see #zcount(string, double, double) 2081 * @param key 2082 * @param min a double or Double.NEGATIVE_INFINITY for "-inf" 2083 * @param max a double or Double.POSITIVE_INFINITY for "+inf" 2084 * @return Multi bulk reply specifically a list of elements in the specified score range. 2085 */ 2086 Set!(string) zrangeByScore(string key, double min, double max) { 2087 checkIsInMultiOrPipeline(); 2088 client.zrangeByScore(key, min, max); 2089 List!(string) members = client.getMultiBulkReply(); 2090 return new SetFromList!string(members); 2091 } 2092 alias zrangeByScore = BinaryRedis.zrangeByScore; 2093 2094 Set!(string) zrangeByScore(string key, string min, string max) { 2095 checkIsInMultiOrPipeline(); 2096 client.zrangeByScore(key, min, max); 2097 List!(string) members = client.getMultiBulkReply(); 2098 return new SetFromList!string(members); 2099 } 2100 2101 /** 2102 * Return the all the elements in the sorted set at key with a score between min and max 2103 * (including elements with score equal to min or max). 2104 * <p> 2105 * The elements having the same score are returned sorted lexicographically as ASCII strings (this 2106 * follows from a property of Redis sorted sets and does not involve further computation). 2107 * <p> 2108 * Using the optional {@link #zrangeByScore(string, double, double, int, int) LIMIT} it's possible 2109 * to get only a range of the matching elements in an SQL-alike way. Note that if offset is large 2110 * the commands needs to traverse the list for offset elements and this adds up to the O(M) 2111 * figure. 2112 * <p> 2113 * The {@link #zcount(string, double, double) ZCOUNT} command is similar to 2114 * {@link #zrangeByScore(string, double, double) ZRANGEBYSCORE} but instead of returning the 2115 * actual elements in the specified interval, it just returns the number of matching elements. 2116 * <p> 2117 * <b>Exclusive intervals and infinity</b> 2118 * <p> 2119 * min and max can be -inf and +inf, so that you are not required to know what's the greatest or 2120 * smallest element in order to take, for instance, elements "up to a given value". 2121 * <p> 2122 * Also while the interval is for default closed (inclusive) it's possible to specify open 2123 * intervals prefixing the score with a "(" character, so for instance: 2124 * <p> 2125 * {@code ZRANGEBYSCORE zset (1.3 5} 2126 * <p> 2127 * Will return all the values with score > 1.3 and <= 5, while for instance: 2128 * <p> 2129 * {@code ZRANGEBYSCORE zset (5 (10} 2130 * <p> 2131 * Will return all the values with score > 5 and < 10 (5 and 10 excluded). 2132 * <p> 2133 * <b>Time complexity:</b> 2134 * <p> 2135 * O(log(N))+O(M) with N being the number of elements in the sorted set and M the number of 2136 * elements returned by the command, so if M is constant (for instance you always ask for the 2137 * first ten elements with LIMIT) you can consider it O(log(N)) 2138 * @see #zrangeByScore(string, double, double) 2139 * @see #zrangeByScore(string, double, double, int, int) 2140 * @see #zrangeByScoreWithScores(string, double, double) 2141 * @see #zrangeByScoreWithScores(string, double, double, int, int) 2142 * @see #zcount(string, double, double) 2143 * @param key 2144 * @param min 2145 * @param max 2146 * @param offset 2147 * @param count 2148 * @return Multi bulk reply specifically a list of elements in the specified score range. 2149 */ 2150 Set!(string) zrangeByScore(string key, double min, double max, 2151 int offset, int count) { 2152 checkIsInMultiOrPipeline(); 2153 client.zrangeByScore(key, min, max, offset, count); 2154 List!(string) members = client.getMultiBulkReply(); 2155 return new SetFromList!string(members); 2156 } 2157 2158 Set!(string) zrangeByScore(string key, string min, string max, 2159 int offset, int count) { 2160 checkIsInMultiOrPipeline(); 2161 client.zrangeByScore(key, min, max, offset, count); 2162 List!(string) members = client.getMultiBulkReply(); 2163 return new SetFromList!string(members); 2164 } 2165 2166 /** 2167 * Return the all the elements in the sorted set at key with a score between min and max 2168 * (including elements with score equal to min or max). 2169 * <p> 2170 * The elements having the same score are returned sorted lexicographically as ASCII strings (this 2171 * follows from a property of Redis sorted sets and does not involve further computation). 2172 * <p> 2173 * Using the optional {@link #zrangeByScore(string, double, double, int, int) LIMIT} it's possible 2174 * to get only a range of the matching elements in an SQL-alike way. Note that if offset is large 2175 * the commands needs to traverse the list for offset elements and this adds up to the O(M) 2176 * figure. 2177 * <p> 2178 * The {@link #zcount(string, double, double) ZCOUNT} command is similar to 2179 * {@link #zrangeByScore(string, double, double) ZRANGEBYSCORE} but instead of returning the 2180 * actual elements in the specified interval, it just returns the number of matching elements. 2181 * <p> 2182 * <b>Exclusive intervals and infinity</b> 2183 * <p> 2184 * min and max can be -inf and +inf, so that you are not required to know what's the greatest or 2185 * smallest element in order to take, for instance, elements "up to a given value". 2186 * <p> 2187 * Also while the interval is for default closed (inclusive) it's possible to specify open 2188 * intervals prefixing the score with a "(" character, so for instance: 2189 * <p> 2190 * {@code ZRANGEBYSCORE zset (1.3 5} 2191 * <p> 2192 * Will return all the values with score > 1.3 and <= 5, while for instance: 2193 * <p> 2194 * {@code ZRANGEBYSCORE zset (5 (10} 2195 * <p> 2196 * Will return all the values with score > 5 and < 10 (5 and 10 excluded). 2197 * <p> 2198 * <b>Time complexity:</b> 2199 * <p> 2200 * O(log(N))+O(M) with N being the number of elements in the sorted set and M the number of 2201 * elements returned by the command, so if M is constant (for instance you always ask for the 2202 * first ten elements with LIMIT) you can consider it O(log(N)) 2203 * @see #zrangeByScore(string, double, double) 2204 * @see #zrangeByScore(string, double, double, int, int) 2205 * @see #zrangeByScoreWithScores(string, double, double) 2206 * @see #zrangeByScoreWithScores(string, double, double, int, int) 2207 * @see #zcount(string, double, double) 2208 * @param key 2209 * @param min 2210 * @param max 2211 * @return Multi bulk reply specifically a list of elements in the specified score range. 2212 */ 2213 Set!(Tuple) zrangeByScoreWithScores(string key, double min, double max) { 2214 checkIsInMultiOrPipeline(); 2215 client.zrangeByScoreWithScores(key, min, max); 2216 return getTupledSet(); 2217 } 2218 alias zrangeByScoreWithScores = BinaryRedis.zrangeByScoreWithScores; 2219 2220 Set!(Tuple) zrangeByScoreWithScores(string key, string min, string max) { 2221 checkIsInMultiOrPipeline(); 2222 client.zrangeByScoreWithScores(key, min, max); 2223 return getTupledSet(); 2224 } 2225 2226 /** 2227 * Return the all the elements in the sorted set at key with a score between min and max 2228 * (including elements with score equal to min or max). 2229 * <p> 2230 * The elements having the same score are returned sorted lexicographically as ASCII strings (this 2231 * follows from a property of Redis sorted sets and does not involve further computation). 2232 * <p> 2233 * Using the optional {@link #zrangeByScore(string, double, double, int, int) LIMIT} it's possible 2234 * to get only a range of the matching elements in an SQL-alike way. Note that if offset is large 2235 * the commands needs to traverse the list for offset elements and this adds up to the O(M) 2236 * figure. 2237 * <p> 2238 * The {@link #zcount(string, double, double) ZCOUNT} command is similar to 2239 * {@link #zrangeByScore(string, double, double) ZRANGEBYSCORE} but instead of returning the 2240 * actual elements in the specified interval, it just returns the number of matching elements. 2241 * <p> 2242 * <b>Exclusive intervals and infinity</b> 2243 * <p> 2244 * min and max can be -inf and +inf, so that you are not required to know what's the greatest or 2245 * smallest element in order to take, for instance, elements "up to a given value". 2246 * <p> 2247 * Also while the interval is for default closed (inclusive) it's possible to specify open 2248 * intervals prefixing the score with a "(" character, so for instance: 2249 * <p> 2250 * {@code ZRANGEBYSCORE zset (1.3 5} 2251 * <p> 2252 * Will return all the values with score > 1.3 and <= 5, while for instance: 2253 * <p> 2254 * {@code ZRANGEBYSCORE zset (5 (10} 2255 * <p> 2256 * Will return all the values with score > 5 and < 10 (5 and 10 excluded). 2257 * <p> 2258 * <b>Time complexity:</b> 2259 * <p> 2260 * O(log(N))+O(M) with N being the number of elements in the sorted set and M the number of 2261 * elements returned by the command, so if M is constant (for instance you always ask for the 2262 * first ten elements with LIMIT) you can consider it O(log(N)) 2263 * @see #zrangeByScore(string, double, double) 2264 * @see #zrangeByScore(string, double, double, int, int) 2265 * @see #zrangeByScoreWithScores(string, double, double) 2266 * @see #zrangeByScoreWithScores(string, double, double, int, int) 2267 * @see #zcount(string, double, double) 2268 * @param key 2269 * @param min 2270 * @param max 2271 * @param offset 2272 * @param count 2273 * @return Multi bulk reply specifically a list of elements in the specified score range. 2274 */ 2275 Set!(Tuple) zrangeByScoreWithScores(string key, double min, double max, 2276 int offset, int count) { 2277 checkIsInMultiOrPipeline(); 2278 client.zrangeByScoreWithScores(key, min, max, offset, count); 2279 return getTupledSet(); 2280 } 2281 2282 Set!(Tuple) zrangeByScoreWithScores(string key, string min, string max, 2283 int offset, int count) { 2284 checkIsInMultiOrPipeline(); 2285 client.zrangeByScoreWithScores(key, min, max, offset, count); 2286 return getTupledSet(); 2287 } 2288 2289 Set!(string) zrevrangeByScore(string key, double max, double min) { 2290 checkIsInMultiOrPipeline(); 2291 client.zrevrangeByScore(key, max, min); 2292 List!(string) members = client.getMultiBulkReply(); 2293 return new SetFromList!string(members); 2294 } 2295 alias zrevrangeByScore = BinaryRedis.zrevrangeByScore; 2296 2297 Set!(string) zrevrangeByScore(string key, string max, string min) { 2298 checkIsInMultiOrPipeline(); 2299 client.zrevrangeByScore(key, max, min); 2300 List!(string) members = client.getMultiBulkReply(); 2301 return new SetFromList!string(members); 2302 } 2303 2304 Set!(string) zrevrangeByScore(string key, double max, double min, 2305 int offset, int count) { 2306 checkIsInMultiOrPipeline(); 2307 client.zrevrangeByScore(key, max, min, offset, count); 2308 List!(string) members = client.getMultiBulkReply(); 2309 return new SetFromList!string(members); 2310 } 2311 2312 Set!(Tuple) zrevrangeByScoreWithScores(string key, double max, double min) { 2313 checkIsInMultiOrPipeline(); 2314 client.zrevrangeByScoreWithScores(key, max, min); 2315 return getTupledSet(); 2316 } 2317 alias zrevrangeByScoreWithScores = BinaryRedis.zrevrangeByScoreWithScores; 2318 2319 Set!(Tuple) zrevrangeByScoreWithScores(string key, double max, 2320 double min, int offset, int count) { 2321 checkIsInMultiOrPipeline(); 2322 client.zrevrangeByScoreWithScores(key, max, min, offset, count); 2323 return getTupledSet(); 2324 } 2325 2326 Set!(Tuple) zrevrangeByScoreWithScores(string key, string max, 2327 string min, int offset, int count) { 2328 checkIsInMultiOrPipeline(); 2329 client.zrevrangeByScoreWithScores(key, max, min, offset, count); 2330 return getTupledSet(); 2331 } 2332 2333 Set!(string) zrevrangeByScore(string key, string max, string min, 2334 int offset, int count) { 2335 checkIsInMultiOrPipeline(); 2336 client.zrevrangeByScore(key, max, min, offset, count); 2337 List!(string) members = client.getMultiBulkReply(); 2338 return new SetFromList!string(members); 2339 } 2340 2341 Set!(Tuple) zrevrangeByScoreWithScores(string key, string max, string min) { 2342 checkIsInMultiOrPipeline(); 2343 client.zrevrangeByScoreWithScores(key, max, min); 2344 return getTupledSet(); 2345 } 2346 2347 /** 2348 * Remove all elements in the sorted set at key with rank between start and end. Start and end are 2349 * 0-based with rank 0 being the element with the lowest score. Both start and end can be negative 2350 * numbers, where they indicate offsets starting at the element with the highest rank. For 2351 * example: -1 is the element with the highest score, -2 the element with the second highest score 2352 * and so forth. 2353 * <p> 2354 * <b>Time complexity:</b> O(log(N))+O(M) with N being the number of elements in the sorted set 2355 * and M the number of elements removed by the operation 2356 * @param key 2357 * @param start 2358 * @param stop 2359 * @return 2360 */ 2361 Long zremrangeByRank(string key, long start, long stop) { 2362 checkIsInMultiOrPipeline(); 2363 client.zremrangeByRank(key, start, stop); 2364 return client.getIntegerReply(); 2365 } 2366 alias zremrangeByRank = BinaryRedis.zremrangeByRank; 2367 2368 /** 2369 * Remove all the elements in the sorted set at key with a score between min and max (including 2370 * elements with score equal to min or max). 2371 * <p> 2372 * <b>Time complexity:</b> 2373 * <p> 2374 * O(log(N))+O(M) with N being the number of elements in the sorted set and M the number of 2375 * elements removed by the operation 2376 * @param key 2377 * @param min 2378 * @param max 2379 * @return Integer reply, specifically the number of elements removed. 2380 */ 2381 Long zremrangeByScore(string key, double min, double max) { 2382 checkIsInMultiOrPipeline(); 2383 client.zremrangeByScore(key, min, max); 2384 return client.getIntegerReply(); 2385 } 2386 alias zremrangeByScore = BinaryRedis.zremrangeByScore; 2387 2388 Long zremrangeByScore(string key, string min, string max) { 2389 checkIsInMultiOrPipeline(); 2390 client.zremrangeByScore(key, min, max); 2391 return client.getIntegerReply(); 2392 } 2393 2394 /** 2395 * Creates a union or intersection of N sorted sets given by keys k1 through kN, and stores it at 2396 * dstkey. It is mandatory to provide the number of input keys N, before passing the input keys 2397 * and the other (optional) arguments. 2398 * <p> 2399 * As the terms imply, the {@link #zinterstore(string, string...) ZINTERSTORE} command requires an 2400 * element to be present in each of the given inputs to be inserted in the result. The 2401 * {@link #zunionstore(string, string...) ZUNIONSTORE} command inserts all elements across all 2402 * inputs. 2403 * <p> 2404 * Using the WEIGHTS option, it is possible to add weight to each input sorted set. This means 2405 * that the score of each element in the sorted set is first multiplied by this weight before 2406 * being passed to the aggregation. When this option is not given, all weights default to 1. 2407 * <p> 2408 * With the AGGREGATE option, it's possible to specify how the results of the union or 2409 * intersection are aggregated. This option defaults to SUM, where the score of an element is 2410 * summed across the inputs where it exists. When this option is set to be either MIN or MAX, the 2411 * resulting set will contain the minimum or maximum score of an element across the inputs where 2412 * it exists. 2413 * <p> 2414 * <b>Time complexity:</b> O(N) + O(M log(M)) with N being the sum of the sizes of the input 2415 * sorted sets, and M being the number of elements in the resulting sorted set 2416 * @see #zunionstore(string, string...) 2417 * @see #zunionstore(string, ZParams, string...) 2418 * @see #zinterstore(string, string...) 2419 * @see #zinterstore(string, ZParams, string...) 2420 * @param dstkey 2421 * @param sets 2422 * @return Integer reply, specifically the number of elements in the sorted set at dstkey 2423 */ 2424 Long zunionstore(string dstkey, string[] sets...) { 2425 checkIsInMultiOrPipeline(); 2426 client.zunionstore(dstkey, sets); 2427 return client.getIntegerReply(); 2428 } 2429 alias zunionstore = BinaryRedis.zunionstore; 2430 2431 /** 2432 * Creates a union or intersection of N sorted sets given by keys k1 through kN, and stores it at 2433 * dstkey. It is mandatory to provide the number of input keys N, before passing the input keys 2434 * and the other (optional) arguments. 2435 * <p> 2436 * As the terms imply, the {@link #zinterstore(string, string...) ZINTERSTORE} command requires an 2437 * element to be present in each of the given inputs to be inserted in the result. The 2438 * {@link #zunionstore(string, string...) ZUNIONSTORE} command inserts all elements across all 2439 * inputs. 2440 * <p> 2441 * Using the WEIGHTS option, it is possible to add weight to each input sorted set. This means 2442 * that the score of each element in the sorted set is first multiplied by this weight before 2443 * being passed to the aggregation. When this option is not given, all weights default to 1. 2444 * <p> 2445 * With the AGGREGATE option, it's possible to specify how the results of the union or 2446 * intersection are aggregated. This option defaults to SUM, where the score of an element is 2447 * summed across the inputs where it exists. When this option is set to be either MIN or MAX, the 2448 * resulting set will contain the minimum or maximum score of an element across the inputs where 2449 * it exists. 2450 * <p> 2451 * <b>Time complexity:</b> O(N) + O(M log(M)) with N being the sum of the sizes of the input 2452 * sorted sets, and M being the number of elements in the resulting sorted set 2453 * @see #zunionstore(string, string...) 2454 * @see #zunionstore(string, ZParams, string...) 2455 * @see #zinterstore(string, string...) 2456 * @see #zinterstore(string, ZParams, string...) 2457 * @param dstkey 2458 * @param sets 2459 * @param params 2460 * @return Integer reply, specifically the number of elements in the sorted set at dstkey 2461 */ 2462 Long zunionstore(string dstkey, ZParams params, string[] sets...) { 2463 checkIsInMultiOrPipeline(); 2464 client.zunionstore(dstkey, params, sets); 2465 return client.getIntegerReply(); 2466 } 2467 2468 /** 2469 * Creates a union or intersection of N sorted sets given by keys k1 through kN, and stores it at 2470 * dstkey. It is mandatory to provide the number of input keys N, before passing the input keys 2471 * and the other (optional) arguments. 2472 * <p> 2473 * As the terms imply, the {@link #zinterstore(string, string...) ZINTERSTORE} command requires an 2474 * element to be present in each of the given inputs to be inserted in the result. The 2475 * {@link #zunionstore(string, string...) ZUNIONSTORE} command inserts all elements across all 2476 * inputs. 2477 * <p> 2478 * Using the WEIGHTS option, it is possible to add weight to each input sorted set. This means 2479 * that the score of each element in the sorted set is first multiplied by this weight before 2480 * being passed to the aggregation. When this option is not given, all weights default to 1. 2481 * <p> 2482 * With the AGGREGATE option, it's possible to specify how the results of the union or 2483 * intersection are aggregated. This option defaults to SUM, where the score of an element is 2484 * summed across the inputs where it exists. When this option is set to be either MIN or MAX, the 2485 * resulting set will contain the minimum or maximum score of an element across the inputs where 2486 * it exists. 2487 * <p> 2488 * <b>Time complexity:</b> O(N) + O(M log(M)) with N being the sum of the sizes of the input 2489 * sorted sets, and M being the number of elements in the resulting sorted set 2490 * @see #zunionstore(string, string...) 2491 * @see #zunionstore(string, ZParams, string...) 2492 * @see #zinterstore(string, string...) 2493 * @see #zinterstore(string, ZParams, string...) 2494 * @param dstkey 2495 * @param sets 2496 * @return Integer reply, specifically the number of elements in the sorted set at dstkey 2497 */ 2498 Long zinterstore(string dstkey, string[] sets...) { 2499 checkIsInMultiOrPipeline(); 2500 client.zinterstore(dstkey, sets); 2501 return client.getIntegerReply(); 2502 } 2503 alias zinterstore = BinaryRedis.zinterstore; 2504 2505 /** 2506 * Creates a union or intersection of N sorted sets given by keys k1 through kN, and stores it at 2507 * dstkey. It is mandatory to provide the number of input keys N, before passing the input keys 2508 * and the other (optional) arguments. 2509 * <p> 2510 * As the terms imply, the {@link #zinterstore(string, string...) ZINTERSTORE} command requires an 2511 * element to be present in each of the given inputs to be inserted in the result. The 2512 * {@link #zunionstore(string, string...) ZUNIONSTORE} command inserts all elements across all 2513 * inputs. 2514 * <p> 2515 * Using the WEIGHTS option, it is possible to add weight to each input sorted set. This means 2516 * that the score of each element in the sorted set is first multiplied by this weight before 2517 * being passed to the aggregation. When this option is not given, all weights default to 1. 2518 * <p> 2519 * With the AGGREGATE option, it's possible to specify how the results of the union or 2520 * intersection are aggregated. This option defaults to SUM, where the score of an element is 2521 * summed across the inputs where it exists. When this option is set to be either MIN or MAX, the 2522 * resulting set will contain the minimum or maximum score of an element across the inputs where 2523 * it exists. 2524 * <p> 2525 * <b>Time complexity:</b> O(N) + O(M log(M)) with N being the sum of the sizes of the input 2526 * sorted sets, and M being the number of elements in the resulting sorted set 2527 * @see #zunionstore(string, string...) 2528 * @see #zunionstore(string, ZParams, string...) 2529 * @see #zinterstore(string, string...) 2530 * @see #zinterstore(string, ZParams, string...) 2531 * @param dstkey 2532 * @param sets 2533 * @param params 2534 * @return Integer reply, specifically the number of elements in the sorted set at dstkey 2535 */ 2536 Long zinterstore(string dstkey, ZParams params, string[] sets...) { 2537 checkIsInMultiOrPipeline(); 2538 client.zinterstore(dstkey, params, sets); 2539 return client.getIntegerReply(); 2540 } 2541 2542 Long zlexcount(string key, string min, string max) { 2543 checkIsInMultiOrPipeline(); 2544 client.zlexcount(key, min, max); 2545 return client.getIntegerReply(); 2546 } 2547 alias zlexcount = BinaryRedis.zlexcount; 2548 2549 Set!(string) zrangeByLex(string key, string min, string max) { 2550 checkIsInMultiOrPipeline(); 2551 client.zrangeByLex(key, min, max); 2552 List!(string) members = client.getMultiBulkReply(); 2553 return new SetFromList!string(members); 2554 } 2555 alias zrangeByLex = BinaryRedis.zrangeByLex; 2556 2557 Set!(string) zrangeByLex(string key, string min, string max, 2558 int offset, int count) { 2559 checkIsInMultiOrPipeline(); 2560 client.zrangeByLex(key, min, max, offset, count); 2561 List!(string) members = client.getMultiBulkReply(); 2562 return new SetFromList!string(members); 2563 } 2564 2565 Set!(string) zrevrangeByLex(string key, string max, string min) { 2566 checkIsInMultiOrPipeline(); 2567 client.zrevrangeByLex(key, max, min); 2568 List!(string) members = client.getMultiBulkReply(); 2569 return new SetFromList!string(members); 2570 } 2571 alias zrevrangeByLex = BinaryRedis.zrevrangeByLex; 2572 2573 Set!(string) zrevrangeByLex(string key, string max, string min, int offset, int count) { 2574 checkIsInMultiOrPipeline(); 2575 client.zrevrangeByLex(key, max, min, offset, count); 2576 List!(string) members = client.getMultiBulkReply(); 2577 return new SetFromList!string(members); 2578 } 2579 2580 Long zremrangeByLex(string key, string min, string max) { 2581 checkIsInMultiOrPipeline(); 2582 client.zremrangeByLex(key, min, max); 2583 return client.getIntegerReply(); 2584 } 2585 alias zremrangeByLex = BinaryRedis.zremrangeByLex; 2586 2587 Long strlen(string key) { 2588 checkIsInMultiOrPipeline(); 2589 client.strlen(key); 2590 return client.getIntegerReply(); 2591 } 2592 alias strlen = BinaryRedis.strlen; 2593 2594 Long lpushx(string key, string[] string...) { 2595 checkIsInMultiOrPipeline(); 2596 client.lpushx(key, string); 2597 return client.getIntegerReply(); 2598 } 2599 alias lpushx = BinaryRedis.lpushx; 2600 2601 /** 2602 * Undo a {@link #expire(string, int) expire} at turning the expire key into a normal key. 2603 * <p> 2604 * Time complexity: O(1) 2605 * @param key 2606 * @return Integer reply, specifically: 1: the key is now persist. 0: the key is not persist (only 2607 * happens when key not set). 2608 */ 2609 Long persist(string key) { 2610 client.persist(key); 2611 return client.getIntegerReply(); 2612 } 2613 alias persist = BinaryRedis.persist; 2614 2615 Long rpushx(string key, string[] string...) { 2616 checkIsInMultiOrPipeline(); 2617 client.rpushx(key, string); 2618 return client.getIntegerReply(); 2619 } 2620 alias rpushx = BinaryRedis.rpushx; 2621 2622 string echo(string string) { 2623 checkIsInMultiOrPipeline(); 2624 client.echo(string); 2625 return client.getBulkReply(); 2626 } 2627 alias echo = BinaryRedis.echo; 2628 2629 Long linsert(string key, ListPosition where, string pivot, 2630 string value) { 2631 checkIsInMultiOrPipeline(); 2632 client.linsert(key, where, pivot, value); 2633 return client.getIntegerReply(); 2634 } 2635 alias linsert = BinaryRedis.linsert; 2636 2637 /** 2638 * Pop a value from a list, push it to another list and return it; or block until one is available 2639 * @param source 2640 * @param destination 2641 * @param timeout 2642 * @return the element 2643 */ 2644 string brpoplpush(string source, string destination, int timeout) { 2645 client.brpoplpush(source, destination, timeout); 2646 client.setTimeoutInfinite(); 2647 try { 2648 return client.getBulkReply(); 2649 } finally { 2650 client.rollbackTimeout(); 2651 } 2652 } 2653 alias brpoplpush = BinaryRedis.brpoplpush; 2654 2655 /** 2656 * Sets or clears the bit at offset in the string value stored at key 2657 * @param key 2658 * @param offset 2659 * @param value 2660 * @return 2661 */ 2662 bool setbit(string key, long offset, bool value) { 2663 checkIsInMultiOrPipeline(); 2664 client.setbit(key, offset, value); 2665 return client.getIntegerReply() == 1; 2666 } 2667 alias setbit = BinaryRedis.setbit; 2668 2669 2670 bool setbit(string key, long offset, string value) { 2671 checkIsInMultiOrPipeline(); 2672 client.setbit(key, offset, value); 2673 return client.getIntegerReply() == 1; 2674 } 2675 /** 2676 * Returns the bit value at offset in the string value stored at key 2677 * @param key 2678 * @param offset 2679 * @return 2680 */ 2681 bool getbit(string key, long offset) { 2682 checkIsInMultiOrPipeline(); 2683 client.getbit(key, offset); 2684 return client.getIntegerReply() == 1; 2685 } 2686 alias getbit = BinaryRedis.getbit; 2687 2688 Long setrange(string key, long offset, string value) { 2689 checkIsInMultiOrPipeline(); 2690 client.setrange(key, offset, value); 2691 return client.getIntegerReply(); 2692 } 2693 alias setrange = BinaryRedis.setrange; 2694 2695 string getrange(string key, long startOffset, long endOffset) { 2696 checkIsInMultiOrPipeline(); 2697 client.getrange(key, startOffset, endOffset); 2698 return client.getBulkReply(); 2699 } 2700 alias getrange = BinaryRedis.getrange; 2701 2702 Long bitpos(string key, bool value) { 2703 return bitpos(key, value, new BitPosParams()); 2704 } 2705 alias bitpos = BinaryRedis.bitpos; 2706 2707 Long bitpos(string key, bool value, BitPosParams params) { 2708 checkIsInMultiOrPipeline(); 2709 client.bitpos(key, value, params); 2710 return client.getIntegerReply(); 2711 } 2712 2713 /** 2714 * Retrieve the configuration of a running Redis server. Not all the configuration parameters are 2715 * supported. 2716 * <p> 2717 * CONFIG GET returns the current configuration parameters. This sub command only accepts a single 2718 * argument, that is glob style pattern. All the configuration parameters matching this parameter 2719 * are reported as a list of key-value pairs. 2720 * <p> 2721 * <b>Example:</b> 2722 * 2723 * <pre> 2724 * $ redis-cli config get '*' 2725 * 1. "dbfilename" 2726 * 2. "dump.rdb" 2727 * 3. "requirepass" 2728 * 4. (nil) 2729 * 5. "masterauth" 2730 * 6. (nil) 2731 * 7. "maxmemory" 2732 * 8. "0\n" 2733 * 9. "appendfsync" 2734 * 10. "everysec" 2735 * 11. "save" 2736 * 12. "3600 1 300 100 60 10000" 2737 * 2738 * $ redis-cli config get 'm*' 2739 * 1. "masterauth" 2740 * 2. (nil) 2741 * 3. "maxmemory" 2742 * 4. "0\n" 2743 * </pre> 2744 * @param pattern 2745 * @return Bulk reply. 2746 */ 2747 List!(string) configGet(string pattern) { 2748 client.configGet(pattern); 2749 return client.getMultiBulkReply(); 2750 } 2751 2752 /** 2753 * Alter the configuration of a running Redis server. Not all the configuration parameters are 2754 * supported. 2755 * <p> 2756 * The list of configuration parameters supported by CONFIG SET can be obtained issuing a 2757 * {@link #configGet(string) CONFIG GET *} command. 2758 * <p> 2759 * The configuration set using CONFIG SET is immediately loaded by the Redis server that will 2760 * start acting as specified starting from the next command. 2761 * <p> 2762 * <b>Parameters value format</b> 2763 * <p> 2764 * The value of the configuration parameter is the same as the one of the same parameter in the 2765 * Redis configuration file, with the following exceptions: 2766 * <p> 2767 * <ul> 2768 * <li>The save parameter is a list of space-separated integers. Every pair of integers specify the 2769 * time and number of changes limit to trigger a save. For instance the command CONFIG SET save 2770 * "3600 10 60 10000" will configure the server to issue a background saving of the RDB file every 2771 * 3600 seconds if there are at least 10 changes in the dataset, and every 60 seconds if there are 2772 * at least 10000 changes. To completely disable automatic snapshots just set the parameter as an 2773 * empty string. 2774 * <li>All the integer parameters representing memory are returned and accepted only using bytes 2775 * as unit. 2776 * </ul> 2777 * @param parameter 2778 * @param value 2779 * @return Status code reply 2780 */ 2781 string configSet(string parameter, string value) { 2782 client.configSet(parameter, value); 2783 return client.getStatusCodeReply(); 2784 } 2785 2786 Object eval(string script, int keyCount, string[] params...) { 2787 client.setTimeoutInfinite(); 2788 try { 2789 client.eval(script, keyCount, params); 2790 return getEvalResult(); 2791 } finally { 2792 client.rollbackTimeout(); 2793 } 2794 } 2795 2796 void subscribe(RedisPubSub redisPubSub, string[] channels...) { 2797 client.setTimeoutInfinite(); 2798 try { 2799 redisPubSub.proceed(client, channels); 2800 } finally { 2801 client.rollbackTimeout(); 2802 } 2803 } 2804 2805 Long publish(string channel, string message) { 2806 checkIsInMultiOrPipeline(); 2807 connect(); 2808 client.publish(channel, message); 2809 return client.getIntegerReply(); 2810 } 2811 2812 void psubscribe(RedisPubSub redisPubSub, string[] patterns...) { 2813 checkIsInMultiOrPipeline(); 2814 client.setTimeoutInfinite(); 2815 try { 2816 redisPubSub.proceedWithPatterns(client, patterns); 2817 } finally { 2818 client.rollbackTimeout(); 2819 } 2820 } 2821 2822 static string[] getParams(List!(string) keys, List!(string) args) { 2823 int keyCount = keys.size(); 2824 int argCount = args.size(); 2825 2826 string[] params = new string[keyCount + argCount]; 2827 2828 for (int i = 0; i < keyCount; i++) 2829 params[i] = keys.get(i); 2830 2831 for (int i = 0; i < argCount; i++) 2832 params[keyCount + i] = args.get(i); 2833 2834 return params; 2835 } 2836 2837 Object eval(string script, List!(string) keys, List!(string) args) { 2838 return eval(script, keys.size(), getParams(keys, args)); 2839 } 2840 2841 Object eval(string script, string[] keys, string[] args) { 2842 return eval(script, cast(int)keys.length, keys ~ args); 2843 } 2844 2845 Object eval(string script) { 2846 return eval(script, 0); 2847 } 2848 2849 Object evalsha(string sha1) { 2850 return evalsha(sha1, 0); 2851 } 2852 2853 private Object getEvalResult() { 2854 return evalResult(client.getOne()); 2855 } 2856 2857 private Object evalResult(Object result) { 2858 // FIXME: Needing refactor or cleanup -@zxp at 8/5/2019, 1:45:00 PM 2859 // 2860 2861 version(HUNT_REDIS_DEBUG) { 2862 warningf("result's type: %s", typeid(result)); 2863 } 2864 return result; 2865 // if (result instanceof const(ubyte)[]) return SafeEncoder.encode((const(ubyte)[]) result); 2866 2867 // if (result instanceof List<?>) { 2868 // List<?> list = (List<?>) result; 2869 // List!(Object) listResult = new ArrayList!(Object)(list.size()); 2870 // foreach(Object bin ; list) { 2871 // listResult.add(evalResult(bin)); 2872 // } 2873 2874 // return listResult; 2875 // } 2876 2877 // return result; 2878 } 2879 2880 Object evalsha(string sha1, List!(string) keys, List!(string) args) { 2881 return evalsha(sha1, keys.size(), getParams(keys, args)); 2882 } 2883 2884 Object evalsha(string sha1, int keyCount, string[] params...) { 2885 checkIsInMultiOrPipeline(); 2886 client.evalsha(sha1, keyCount, params); 2887 return getEvalResult(); 2888 } 2889 2890 // FIXME: Needing refactor or cleanup -@zxp at 7/15/2019, 11:39:47 AM 2891 // 2892 // override 2893 bool scriptExists(string sha1) { 2894 string[] a = new string[1]; 2895 a[0] = sha1; 2896 return scriptExists(a)[0]; 2897 } 2898 2899 alias scriptExists = BinaryRedis.scriptExists; 2900 2901 // override 2902 bool[] scriptExists(string[] sha1...) { 2903 client.scriptExists(sha1); 2904 // List!(long) result = client.getIntegerMultiBulkReply(); 2905 // List!(bool) exists = new ArrayList!(bool)(); 2906 2907 // foreach(long value ; result) 2908 // exists.add(value == 1); 2909 2910 // return exists; 2911 implementationMissing(false); 2912 return null; 2913 } 2914 2915 string scriptLoad(string script) { 2916 client.scriptLoad(script); 2917 return client.getBulkReply(); 2918 } 2919 alias scriptLoad = BinaryRedis.scriptLoad; 2920 2921 List!(Slowlog) slowlogGet() { 2922 client.slowlogGet(); 2923 return Slowlog.from(client.getObjectMultiBulkReply()); 2924 } 2925 2926 List!(Slowlog) slowlogGet(long entries) { 2927 client.slowlogGet(entries); 2928 return Slowlog.from(client.getObjectMultiBulkReply()); 2929 } 2930 2931 Long objectRefcount(string key) { 2932 client.objectRefcount(key); 2933 return client.getIntegerReply(); 2934 } 2935 alias objectRefcount = BinaryRedis.objectRefcount; 2936 2937 string objectEncoding(string key) { 2938 client.objectEncoding(key); 2939 return client.getBulkReply(); 2940 } 2941 alias objectEncoding = BinaryRedis.objectEncoding; 2942 2943 Long objectIdletime(string key) { 2944 client.objectIdletime(key); 2945 return client.getIntegerReply(); 2946 } 2947 alias objectIdletime = BinaryRedis.objectIdletime; 2948 2949 Long bitcount(string key) { 2950 checkIsInMultiOrPipeline(); 2951 client.bitcount(key); 2952 return client.getIntegerReply(); 2953 } 2954 alias bitcount = BinaryRedis.bitcount; 2955 2956 Long bitcount(string key, long start, long end) { 2957 checkIsInMultiOrPipeline(); 2958 client.bitcount(key, start, end); 2959 return client.getIntegerReply(); 2960 } 2961 2962 Long bitop(BitOP op, string destKey, string[] srcKeys...) { 2963 checkIsInMultiOrPipeline(); 2964 client.bitop(op, destKey, srcKeys); 2965 return client.getIntegerReply(); 2966 } 2967 alias bitop = BinaryRedis.bitop; 2968 2969 /** 2970 * <pre> 2971 * redis 127.0.0.1:26381> sentinel masters 2972 * 1) 1) "name" 2973 * 2) "mymaster" 2974 * 3) "ip" 2975 * 4) "127.0.0.1" 2976 * 5) "port" 2977 * 6) "6379" 2978 * 7) "runid" 2979 * 8) "93d4d4e6e9c06d0eea36e27f31924ac26576081d" 2980 * 9) "flags" 2981 * 10) "master" 2982 * 11) "pending-commands" 2983 * 12) "0" 2984 * 13) "last-ok-ping-reply" 2985 * 14) "423" 2986 * 15) "last-ping-reply" 2987 * 16) "423" 2988 * 17) "info-refresh" 2989 * 18) "6107" 2990 * 19) "num-slaves" 2991 * 20) "1" 2992 * 21) "num-other-sentinels" 2993 * 22) "2" 2994 * 23) "quorum" 2995 * 24) "2" 2996 * 2997 * </pre> 2998 * @return 2999 */ 3000 List!(Map!(string, string)) sentinelMasters() { 3001 client.sentinel(Protocol.SENTINEL_MASTERS); 3002 List!(Object) reply = client.getObjectMultiBulkReply(); 3003 3004 List!(Map!(string, string)) masters = new ArrayList!(Map!(string, string))(); 3005 // foreach(Object obj ; reply) { 3006 // masters.add(BuilderFactory.STRING_MAP.build((List) obj)); 3007 // } 3008 implementationMissing(false); 3009 return masters; 3010 } 3011 3012 /** 3013 * <pre> 3014 * redis 127.0.0.1:26381> sentinel get-master-addr-by-name mymaster 3015 * 1) "127.0.0.1" 3016 * 2) "6379" 3017 * </pre> 3018 * @param masterName 3019 * @return two elements list of strings : host and port. 3020 */ 3021 List!(string) sentinelGetMasterAddrByName(string masterName) { 3022 client.sentinel(Protocol.SENTINEL_GET_MASTER_ADDR_BY_NAME, masterName); 3023 List!(Object) reply = client.getObjectMultiBulkReply(); 3024 return BuilderFactory.STRING_LIST.build(cast(Object)reply); 3025 } 3026 3027 /** 3028 * <pre> 3029 * redis 127.0.0.1:26381> sentinel reset mymaster 3030 * (integer) 1 3031 * </pre> 3032 * @param pattern 3033 * @return 3034 */ 3035 Long sentinelReset(string pattern) { 3036 client.sentinel(Protocol.SENTINEL_RESET, pattern); 3037 return client.getIntegerReply(); 3038 } 3039 3040 /** 3041 * <pre> 3042 * redis 127.0.0.1:26381> sentinel slaves mymaster 3043 * 1) 1) "name" 3044 * 2) "127.0.0.1:6380" 3045 * 3) "ip" 3046 * 4) "127.0.0.1" 3047 * 5) "port" 3048 * 6) "6380" 3049 * 7) "runid" 3050 * 8) "d7f6c0ca7572df9d2f33713df0dbf8c72da7c039" 3051 * 9) "flags" 3052 * 10) "slave" 3053 * 11) "pending-commands" 3054 * 12) "0" 3055 * 13) "last-ok-ping-reply" 3056 * 14) "47" 3057 * 15) "last-ping-reply" 3058 * 16) "47" 3059 * 17) "info-refresh" 3060 * 18) "657" 3061 * 19) "master-link-down-time" 3062 * 20) "0" 3063 * 21) "master-link-status" 3064 * 22) "ok" 3065 * 23) "master-host" 3066 * 24) "localhost" 3067 * 25) "master-port" 3068 * 26) "6379" 3069 * 27) "slave-priority" 3070 * 28) "100" 3071 * </pre> 3072 * @param masterName 3073 * @return 3074 */ 3075 3076 List!(Map!(string, string)) sentinelSlaves(string masterName) { 3077 client.sentinel(Protocol.SENTINEL_SLAVES, masterName); 3078 List!(Object) reply = client.getObjectMultiBulkReply(); 3079 3080 List!(Map!(string, string)) slaves = new ArrayList!(Map!(string, string))(); 3081 // foreach(Object obj ; reply) { 3082 // slaves.add(BuilderFactory.STRING_MAP.build((List) obj)); 3083 // } 3084 implementationMissing(false); 3085 return slaves; 3086 } 3087 3088 string sentinelFailover(string masterName) { 3089 client.sentinel(Protocol.SENTINEL_FAILOVER, masterName); 3090 return client.getStatusCodeReply(); 3091 } 3092 3093 string sentinelMonitor(string masterName, string ip, int port, int quorum) { 3094 client.sentinel(Protocol.SENTINEL_MONITOR, masterName, ip, to!string(port), 3095 to!string(quorum)); 3096 return client.getStatusCodeReply(); 3097 } 3098 3099 string sentinelRemove(string masterName) { 3100 client.sentinel(Protocol.SENTINEL_REMOVE, masterName); 3101 return client.getStatusCodeReply(); 3102 } 3103 3104 string sentinelSet(string masterName, Map!(string, string) parameterMap) { 3105 int index = 0; 3106 int paramsLength = parameterMap.size() * 2 + 2; 3107 string[] params = new string[paramsLength]; 3108 3109 params[index++] = Protocol.SENTINEL_SET; 3110 params[index++] = masterName; 3111 foreach(string key, string value ; parameterMap) { 3112 params[index++] = key; 3113 params[index++] = value; 3114 } 3115 3116 client.sentinel(params); 3117 return client.getStatusCodeReply(); 3118 } 3119 3120 const(ubyte)[] dump(string key) { 3121 checkIsInMultiOrPipeline(); 3122 client.dump(key); 3123 return client.getBinaryBulkReply(); 3124 } 3125 alias dump = BinaryRedis.dump; 3126 3127 string restore(string key, int ttl, const(ubyte)[] serializedValue) { 3128 checkIsInMultiOrPipeline(); 3129 client.restore(key, ttl, serializedValue); 3130 return client.getStatusCodeReply(); 3131 } 3132 alias restore = BinaryRedis.restore; 3133 3134 string restoreReplace(string key, int ttl, const(ubyte)[] serializedValue) { 3135 checkIsInMultiOrPipeline(); 3136 client.restoreReplace(key, ttl, serializedValue); 3137 return client.getStatusCodeReply(); 3138 } 3139 alias restoreReplace = BinaryRedis.restoreReplace; 3140 3141 Long pexpire(string key, long milliseconds) { 3142 checkIsInMultiOrPipeline(); 3143 client.pexpire(key, milliseconds); 3144 return client.getIntegerReply(); 3145 } 3146 alias pexpire = BinaryRedis.pexpire; 3147 3148 Long pexpireAt(string key, long millisecondsTimestamp) { 3149 checkIsInMultiOrPipeline(); 3150 client.pexpireAt(key, millisecondsTimestamp); 3151 return client.getIntegerReply(); 3152 } 3153 alias pexpireAt = BinaryRedis.pexpireAt; 3154 3155 Long pttl(string key) { 3156 checkIsInMultiOrPipeline(); 3157 client.pttl(key); 3158 return client.getIntegerReply(); 3159 } 3160 alias pttl = BinaryRedis.pttl; 3161 3162 /** 3163 * PSETEX works exactly like {@link #setex(string, int, string)} with the sole difference that the 3164 * expire time is specified in milliseconds instead of seconds. Time complexity: O(1) 3165 * @param key 3166 * @param milliseconds 3167 * @param value 3168 * @return Status code reply 3169 */ 3170 string psetex(string key, long milliseconds, string value) { 3171 checkIsInMultiOrPipeline(); 3172 client.psetex(key, milliseconds, value); 3173 return client.getStatusCodeReply(); 3174 } 3175 alias psetex = BinaryRedis.psetex; 3176 3177 string clientKill(string ipPort) { 3178 checkIsInMultiOrPipeline(); 3179 this.client.clientKill(ipPort); 3180 return this.client.getStatusCodeReply(); 3181 } 3182 3183 override string clientKill(string ip, int port) { 3184 return super.clientKill(ip, port); 3185 } 3186 3187 override Long clientKill(ClientKillParams params) { 3188 return super.clientKill(params); 3189 } 3190 3191 string clientGetname() { 3192 checkIsInMultiOrPipeline(); 3193 client.clientGetname(); 3194 return client.getBulkReply(); 3195 } 3196 3197 string clientList() { 3198 checkIsInMultiOrPipeline(); 3199 client.clientList(); 3200 return client.getBulkReply(); 3201 } 3202 3203 string clientSetname(string name) { 3204 checkIsInMultiOrPipeline(); 3205 client.clientSetname(name); 3206 return client.getStatusCodeReply(); 3207 } 3208 3209 string migrate(string host, int port, string key, 3210 int destinationDb, int timeout) { 3211 checkIsInMultiOrPipeline(); 3212 client.migrate(host, port, key, destinationDb, timeout); 3213 return client.getStatusCodeReply(); 3214 } 3215 3216 string migrate(string host, int port, int destinationDB, 3217 int timeout, MigrateParams params, string[] keys...) { 3218 checkIsInMultiOrPipeline(); 3219 client.migrate(host, port, destinationDB, timeout, params, keys); 3220 return client.getStatusCodeReply(); 3221 } 3222 3223 ScanResult!(string) scan(string cursor) { 3224 return scan(cursor, new ScanParams()); 3225 } 3226 alias scan = BinaryRedis.scan; 3227 3228 ScanResult!(string) scan(string cursor, ScanParams params) { 3229 checkIsInMultiOrPipeline(); 3230 client.scan(cursor, params); 3231 List!(Object) result = client.getObjectMultiBulkReply(); 3232 // string newcursor = new string((const(ubyte)[]) result.get(0)); 3233 // List!(string) results = new ArrayList!(string)(); 3234 // List!(const(ubyte)[]) rawResults = (List!(const(ubyte)[])) result.get(1); 3235 // foreach(const(ubyte)[] bs ; rawResults) { 3236 // results.add(SafeEncoder.encode(bs)); 3237 // } 3238 // return new ScanResult!(string)(newcursor, results); 3239 3240 implementationMissing(); 3241 return null; 3242 } 3243 3244 ScanResult!(MapEntry!(string, string)) hscan(string key, string cursor) { 3245 return hscan(key, cursor, new ScanParams()); 3246 } 3247 alias hscan = BinaryRedis.hscan; 3248 3249 ScanResult!(MapEntry!(string, string)) hscan(string key, string cursor, 3250 ScanParams params) { 3251 checkIsInMultiOrPipeline(); 3252 client.hscan(key, cursor, params); 3253 List!(Object) result = client.getObjectMultiBulkReply(); 3254 // string newcursor = new string((const(ubyte)[]) result.get(0)); 3255 // List!(MapEntry!(string, string)) results = new ArrayList!(MapEntry!(string, string))(); 3256 // List!(const(ubyte)[]) rawResults = cast(List!(const(ubyte)[])) result.get(1); 3257 // Iterator!(const(ubyte)[]) iterator = rawResults.iterator(); 3258 // while (iterator.hasNext()) { 3259 // results.add(new AbstractMap.SimpleEntry!(string, string)(SafeEncoder.encode(iterator.next()), 3260 // SafeEncoder.encode(iterator.next()))); 3261 // } 3262 // return new ScanResult!(MapEntry!(string, string))(newcursor, results); 3263 3264 implementationMissing(); 3265 return null; 3266 } 3267 3268 ScanResult!(string) sscan(string key, string cursor) { 3269 return sscan(key, cursor, new ScanParams()); 3270 } 3271 alias sscan = BinaryRedis.sscan; 3272 3273 ScanResult!(string) sscan(string key, string cursor, ScanParams params) { 3274 checkIsInMultiOrPipeline(); 3275 client.sscan(key, cursor, params); 3276 List!(Object) result = client.getObjectMultiBulkReply(); 3277 // string newcursor = new string((const(ubyte)[]) result.get(0)); 3278 // List!(string) results = new ArrayList!(string)(); 3279 // List!(const(ubyte)[]) rawResults = (List!(const(ubyte)[])) result.get(1); 3280 // foreach(const(ubyte)[] bs ; rawResults) { 3281 // results.add(SafeEncoder.encode(bs)); 3282 // } 3283 // return new ScanResult!(string)(newcursor, results); 3284 implementationMissing(); 3285 return null; 3286 3287 } 3288 3289 ScanResult!(Tuple) zscan(string key, string cursor) { 3290 return zscan(key, cursor, new ScanParams()); 3291 } 3292 alias zscan = BinaryRedis.zscan; 3293 3294 ScanResult!(Tuple) zscan(string key, string cursor, ScanParams params) { 3295 checkIsInMultiOrPipeline(); 3296 client.zscan(key, cursor, params); 3297 List!(Object) result = client.getObjectMultiBulkReply(); 3298 // string newcursor = new string((const(ubyte)[]) result.get(0)); 3299 // List!(Tuple) results = new ArrayList!(Tuple)(); 3300 // List!(const(ubyte)[]) rawResults = (List!(const(ubyte)[])) result.get(1); 3301 // Iterator!(const(ubyte)[]) iterator = rawResults.iterator(); 3302 // while (iterator.hasNext()) { 3303 // results.add(new Tuple(iterator.next(), BuilderFactory.DOUBLE.build(iterator.next()))); 3304 // } 3305 // return new ScanResult!(Tuple)(newcursor, results); 3306 implementationMissing(); 3307 return null; 3308 3309 } 3310 3311 string clusterNodes() { 3312 checkIsInMultiOrPipeline(); 3313 client.clusterNodes(); 3314 return client.getBulkReply(); 3315 } 3316 3317 string readonly() { 3318 client.readonly(); 3319 return client.getStatusCodeReply(); 3320 } 3321 3322 string clusterMeet(string ip, int port) { 3323 checkIsInMultiOrPipeline(); 3324 client.clusterMeet(ip, port); 3325 return client.getStatusCodeReply(); 3326 } 3327 3328 string clusterReset(ClusterReset resetType) { 3329 checkIsInMultiOrPipeline(); 3330 client.clusterReset(resetType); 3331 return client.getStatusCodeReply(); 3332 } 3333 3334 string clusterAddSlots(int[] slots...) { 3335 checkIsInMultiOrPipeline(); 3336 client.clusterAddSlots(slots); 3337 return client.getStatusCodeReply(); 3338 } 3339 3340 string clusterDelSlots(int[] slots...) { 3341 checkIsInMultiOrPipeline(); 3342 client.clusterDelSlots(slots); 3343 return client.getStatusCodeReply(); 3344 } 3345 3346 string clusterInfo() { 3347 checkIsInMultiOrPipeline(); 3348 client.clusterInfo(); 3349 return client.getStatusCodeReply(); 3350 } 3351 3352 List!(string) clusterGetKeysInSlot(int slot, int count) { 3353 checkIsInMultiOrPipeline(); 3354 client.clusterGetKeysInSlot(slot, count); 3355 return client.getMultiBulkReply(); 3356 } 3357 3358 string clusterSetSlotNode(int slot, string nodeId) { 3359 checkIsInMultiOrPipeline(); 3360 client.clusterSetSlotNode(slot, nodeId); 3361 return client.getStatusCodeReply(); 3362 } 3363 3364 string clusterSetSlotMigrating(int slot, string nodeId) { 3365 checkIsInMultiOrPipeline(); 3366 client.clusterSetSlotMigrating(slot, nodeId); 3367 return client.getStatusCodeReply(); 3368 } 3369 3370 string clusterSetSlotImporting(int slot, string nodeId) { 3371 checkIsInMultiOrPipeline(); 3372 client.clusterSetSlotImporting(slot, nodeId); 3373 return client.getStatusCodeReply(); 3374 } 3375 3376 string clusterSetSlotStable(int slot) { 3377 checkIsInMultiOrPipeline(); 3378 client.clusterSetSlotStable(slot); 3379 return client.getStatusCodeReply(); 3380 } 3381 3382 string clusterForget(string nodeId) { 3383 checkIsInMultiOrPipeline(); 3384 client.clusterForget(nodeId); 3385 return client.getStatusCodeReply(); 3386 } 3387 3388 string clusterFlushSlots() { 3389 checkIsInMultiOrPipeline(); 3390 client.clusterFlushSlots(); 3391 return client.getStatusCodeReply(); 3392 } 3393 3394 Long clusterKeySlot(string key) { 3395 checkIsInMultiOrPipeline(); 3396 client.clusterKeySlot(key); 3397 return client.getIntegerReply(); 3398 } 3399 3400 Long clusterCountKeysInSlot(int slot) { 3401 checkIsInMultiOrPipeline(); 3402 client.clusterCountKeysInSlot(slot); 3403 return client.getIntegerReply(); 3404 } 3405 3406 string clusterSaveConfig() { 3407 checkIsInMultiOrPipeline(); 3408 client.clusterSaveConfig(); 3409 return client.getStatusCodeReply(); 3410 } 3411 3412 string clusterReplicate(string nodeId) { 3413 checkIsInMultiOrPipeline(); 3414 client.clusterReplicate(nodeId); 3415 return client.getStatusCodeReply(); 3416 } 3417 3418 List!(string) clusterSlaves(string nodeId) { 3419 checkIsInMultiOrPipeline(); 3420 client.clusterSlaves(nodeId); 3421 return client.getMultiBulkReply(); 3422 } 3423 3424 string clusterFailover() { 3425 checkIsInMultiOrPipeline(); 3426 client.clusterFailover(); 3427 return client.getStatusCodeReply(); 3428 } 3429 3430 List!(Object) clusterSlots() { 3431 checkIsInMultiOrPipeline(); 3432 client.clusterSlots(); 3433 return client.getObjectMultiBulkReply(); 3434 } 3435 3436 string asking() { 3437 checkIsInMultiOrPipeline(); 3438 client.asking(); 3439 return client.getStatusCodeReply(); 3440 } 3441 3442 List!(string) pubsubChannels(string pattern) { 3443 checkIsInMultiOrPipeline(); 3444 client.pubsubChannels(pattern); 3445 return client.getMultiBulkReply(); 3446 } 3447 3448 Long pubsubNumPat() { 3449 checkIsInMultiOrPipeline(); 3450 client.pubsubNumPat(); 3451 return client.getIntegerReply(); 3452 } 3453 3454 Map!(string, string) pubsubNumSub(string[] channels...) { 3455 checkIsInMultiOrPipeline(); 3456 client.pubsubNumSub(channels); 3457 return BuilderFactory.PUBSUB_NUMSUB_MAP.build(cast(Object)client.getBinaryMultiBulkReply()); 3458 } 3459 3460 // override void close() { 3461 // // if (dataSource !is null) { 3462 // // RedisPoolAbstract pool = this.dataSource; 3463 // // this.dataSource = null; 3464 // // if (client.isBroken()) { 3465 // // pool.returnBrokenResource(this); 3466 // // } else { 3467 // // pool.returnResource(this); 3468 // // } 3469 // // } else { 3470 // // warning("The connnection has already closed!"); 3471 // // // super.close(); 3472 // // } 3473 3474 // warning("The connnection has already closed!"); 3475 3476 // super.close(); 3477 // } 3478 3479 // void setDataSource(RedisPoolAbstract redisPool) { 3480 // this.dataSource = redisPool; 3481 // } 3482 3483 Long pfadd(string key, string[] elements...) { 3484 checkIsInMultiOrPipeline(); 3485 client.pfadd(key, elements); 3486 return client.getIntegerReply(); 3487 } 3488 alias pfadd = BinaryRedis.pfadd; 3489 3490 Long pfcount(string key) { 3491 checkIsInMultiOrPipeline(); 3492 client.pfcount(key); 3493 return client.getIntegerReply(); 3494 } 3495 alias pfcount = BinaryRedis.pfcount; 3496 3497 Long pfcount(string[] keys...) { 3498 checkIsInMultiOrPipeline(); 3499 client.pfcount(keys); 3500 return client.getIntegerReply(); 3501 } 3502 3503 string pfmerge(string destkey, string[] sourcekeys...) { 3504 checkIsInMultiOrPipeline(); 3505 client.pfmerge(destkey, sourcekeys); 3506 return client.getStatusCodeReply(); 3507 } 3508 alias pfmerge = BinaryRedis.pfmerge; 3509 3510 List!(string) blpop(int timeout, string key) { 3511 return blpop(key, to!string(timeout)); 3512 } 3513 alias blpop = BinaryRedis.blpop; 3514 3515 List!(string) brpop(int timeout, string key) { 3516 return brpop(key, to!string(timeout)); 3517 } 3518 alias brpop = BinaryRedis.brpop; 3519 3520 Long geoadd(string key, double longitude, double latitude, string member) { 3521 checkIsInMultiOrPipeline(); 3522 client.geoadd(key, longitude, latitude, member); 3523 return client.getIntegerReply(); 3524 } 3525 alias geoadd = BinaryRedis.geoadd; 3526 3527 Long geoadd(string key, Map!(string, GeoCoordinate) memberCoordinateMap) { 3528 checkIsInMultiOrPipeline(); 3529 client.geoadd(key, memberCoordinateMap); 3530 return client.getIntegerReply(); 3531 } 3532 3533 Double geodist(string key, string member1, string member2) { 3534 checkIsInMultiOrPipeline(); 3535 client.geodist(key, member1, member2); 3536 string dval = client.getBulkReply(); 3537 return (dval !is null ? new Double(dval) : null); 3538 } 3539 alias geodist = BinaryRedis.geodist; 3540 3541 Double geodist(string key, string member1, string member2, GeoUnit unit) { 3542 checkIsInMultiOrPipeline(); 3543 client.geodist(key, member1, member2, unit); 3544 string dval = client.getBulkReply(); 3545 return (dval !is null ? new Double(dval) : null); 3546 } 3547 3548 List!(string) geohash(string key, string[] members...) { 3549 checkIsInMultiOrPipeline(); 3550 client.geohash(key, members); 3551 return client.getMultiBulkReply(); 3552 } 3553 alias geohash = BinaryRedis.geohash; 3554 3555 List!(GeoCoordinate) geopos(string key, string[] members...) { 3556 checkIsInMultiOrPipeline(); 3557 client.geopos(key, members); 3558 return BuilderFactory.GEO_COORDINATE_LIST.build(cast(Object)client.getObjectMultiBulkReply()); 3559 } 3560 alias geopos = BinaryRedis.geopos; 3561 3562 List!(GeoRadiusResponse) georadius(string key, double longitude, double latitude, 3563 double radius, GeoUnit unit) { 3564 checkIsInMultiOrPipeline(); 3565 client.georadius(key, longitude, latitude, radius, unit); 3566 return BuilderFactory.GEORADIUS_WITH_PARAMS_RESULT.build(cast(Object)client.getObjectMultiBulkReply()); 3567 } 3568 alias georadius = BinaryRedis.georadius; 3569 3570 List!(GeoRadiusResponse) georadiusReadonly(string key, double longitude, double latitude, 3571 double radius, GeoUnit unit) { 3572 checkIsInMultiOrPipeline(); 3573 client.georadiusReadonly(key, longitude, latitude, radius, unit); 3574 return BuilderFactory.GEORADIUS_WITH_PARAMS_RESULT.build(cast(Object)client.getObjectMultiBulkReply()); 3575 } 3576 alias georadiusReadonly = BinaryRedis.georadiusReadonly; 3577 3578 List!(GeoRadiusResponse) georadius(string key, double longitude, double latitude, 3579 double radius, GeoUnit unit, GeoRadiusParam param) { 3580 checkIsInMultiOrPipeline(); 3581 client.georadius(key, longitude, latitude, radius, unit, param); 3582 return BuilderFactory.GEORADIUS_WITH_PARAMS_RESULT.build(cast(Object)client.getObjectMultiBulkReply()); 3583 } 3584 alias georadius = BinaryRedis.georadius; 3585 3586 List!(GeoRadiusResponse) georadiusReadonly(string key, double longitude, double latitude, 3587 double radius, GeoUnit unit, GeoRadiusParam param) { 3588 checkIsInMultiOrPipeline(); 3589 client.georadiusReadonly(key, longitude, latitude, radius, unit, param); 3590 return BuilderFactory.GEORADIUS_WITH_PARAMS_RESULT.build(cast(Object)client.getObjectMultiBulkReply()); 3591 } 3592 3593 List!(GeoRadiusResponse) georadiusByMember(string key, string member, double radius, 3594 GeoUnit unit) { 3595 checkIsInMultiOrPipeline(); 3596 client.georadiusByMember(key, member, radius, unit); 3597 return BuilderFactory.GEORADIUS_WITH_PARAMS_RESULT.build(cast(Object)client.getObjectMultiBulkReply()); 3598 } 3599 alias georadiusByMember = BinaryRedis.georadiusByMember; 3600 3601 List!(GeoRadiusResponse) georadiusByMemberReadonly(string key, string member, double radius, 3602 GeoUnit unit) { 3603 checkIsInMultiOrPipeline(); 3604 client.georadiusByMemberReadonly(key, member, radius, unit); 3605 return BuilderFactory.GEORADIUS_WITH_PARAMS_RESULT.build(cast(Object)client.getObjectMultiBulkReply()); 3606 } 3607 alias georadiusByMemberReadonly = BinaryRedis.georadiusByMemberReadonly; 3608 3609 List!(GeoRadiusResponse) georadiusByMember(string key, string member, double radius, 3610 GeoUnit unit, GeoRadiusParam param) { 3611 checkIsInMultiOrPipeline(); 3612 client.georadiusByMember(key, member, radius, unit, param); 3613 return BuilderFactory.GEORADIUS_WITH_PARAMS_RESULT.build(cast(Object)client.getObjectMultiBulkReply()); 3614 } 3615 3616 List!(GeoRadiusResponse) georadiusByMemberReadonly(string key, string member, double radius, 3617 GeoUnit unit, GeoRadiusParam param) { 3618 checkIsInMultiOrPipeline(); 3619 client.georadiusByMemberReadonly(key, member, radius, unit, param); 3620 return BuilderFactory.GEORADIUS_WITH_PARAMS_RESULT.build(cast(Object)client.getObjectMultiBulkReply()); 3621 } 3622 3623 string moduleLoad(string path) { 3624 client.moduleLoad(path); 3625 return client.getStatusCodeReply(); 3626 } 3627 3628 string moduleUnload(string name) { 3629 client.moduleUnload(name); 3630 return client.getStatusCodeReply(); 3631 } 3632 3633 List!(Module) moduleList() { 3634 client.moduleList(); 3635 return BuilderFactory.MODULE_LIST.build(cast(Object)client.getObjectMultiBulkReply()); 3636 } 3637 3638 List!(long) bitfield(string key, string[] arguments...) { 3639 checkIsInMultiOrPipeline(); 3640 client.bitfield(key, arguments); 3641 return client.getIntegerMultiBulkReply(); 3642 } 3643 alias bitfield = BinaryRedis.bitfield; 3644 3645 Long hstrlen(string key, string field) { 3646 checkIsInMultiOrPipeline(); 3647 client.hstrlen(key, field); 3648 return client.getIntegerReply(); 3649 } 3650 alias hstrlen = BinaryRedis.hstrlen; 3651 3652 string memoryDoctor() { 3653 checkIsInMultiOrPipeline(); 3654 client.memoryDoctor(); 3655 return client.getBulkReply(); 3656 } 3657 3658 StreamEntryID xadd(string key, StreamEntryID id, Map!(string, string) hash) { 3659 return xadd(key, id, hash, long.max, false); 3660 } 3661 alias xadd = BinaryRedis.xadd; 3662 3663 StreamEntryID xadd(string key, StreamEntryID id, Map!(string, string) hash, long maxLen, bool approximateLength) { 3664 checkIsInMultiOrPipeline(); 3665 client.xadd(key, id, hash, maxLen, approximateLength); 3666 string result = client.getBulkReply(); 3667 return new StreamEntryID(result); 3668 } 3669 3670 Long xlen(string key) { 3671 checkIsInMultiOrPipeline(); 3672 client.xlen(key); 3673 return client.getIntegerReply(); 3674 } 3675 alias xlen = BinaryRedis.xlen; 3676 3677 /** 3678 * {@inheritDoc} 3679 */ 3680 List!(StreamEntry) xrange(string key, StreamEntryID start, StreamEntryID end, int count) { 3681 checkIsInMultiOrPipeline(); 3682 client.xrange(key, start, end, count); 3683 return BuilderFactory.STREAM_ENTRY_LIST.build(cast(Object)client.getObjectMultiBulkReply()); 3684 } 3685 alias xrange = BinaryRedis.xrange; 3686 3687 /** 3688 * {@inheritDoc} 3689 */ 3690 List!(StreamEntry) xrevrange(string key, StreamEntryID end, StreamEntryID start, int count) { 3691 checkIsInMultiOrPipeline(); 3692 client.xrevrange(key, end, start, count); 3693 return BuilderFactory.STREAM_ENTRY_LIST.build(cast(Object)client.getObjectMultiBulkReply()); 3694 } 3695 alias xrevrange = BinaryRedis.xrevrange; 3696 3697 3698 /** 3699 * {@inheritDoc} 3700 */ 3701 List!(MapEntry!(string, List!(StreamEntry))) xread(int count, long block, MapEntry!(string, StreamEntryID)[] streams...) { 3702 checkIsInMultiOrPipeline(); 3703 client.xread(count, block, streams); 3704 client.setTimeoutInfinite(); 3705 3706 try { 3707 List!(Object) streamsEntries = client.getObjectMultiBulkReply(); 3708 if(streamsEntries is null) { 3709 return new ArrayList!(MapEntry!(string, List!(StreamEntry)))(); 3710 } 3711 3712 List!(MapEntry!(string, List!(StreamEntry))) result = 3713 new ArrayList!(MapEntry!(string, List!(StreamEntry)))(streamsEntries.size()); 3714 3715 // foreach(Object streamObj ; streamsEntries) { 3716 // List!(Object) stream = cast(List!(Object))streamObj; 3717 // string streamId = SafeEncoder.encode((const(ubyte)[])stream.get(0)); 3718 // List!(StreamEntry) streamEntries = BuilderFactory.STREAM_ENTRY_LIST.build(stream.get(1)); 3719 // result.add(new AbstractMap.SimpleEntry!(string, List!(StreamEntry))(streamId, streamEntries)); 3720 // } 3721 implementationMissing(false); 3722 return result; 3723 } finally { 3724 client.rollbackTimeout(); 3725 } 3726 } 3727 alias xread = BinaryRedis.xread; 3728 3729 /** 3730 * {@inheritDoc} 3731 */ 3732 Long xack(string key, string group, StreamEntryID[] ids...) { 3733 checkIsInMultiOrPipeline(); 3734 client.xack(key, group, ids); 3735 return client.getIntegerReply(); 3736 } 3737 alias xack = BinaryRedis.xack; 3738 3739 string xgroupCreate(string key, string groupname, StreamEntryID id, bool makeStream) { 3740 checkIsInMultiOrPipeline(); 3741 client.xgroupCreate(key, groupname, id, makeStream); 3742 return client.getStatusCodeReply(); 3743 } 3744 alias xgroupCreate = BinaryRedis.xgroupCreate; 3745 3746 string xgroupSetID(string key, string groupname, StreamEntryID id) { 3747 checkIsInMultiOrPipeline(); 3748 client.xgroupSetID(key, groupname, id); 3749 return client.getStatusCodeReply(); 3750 } 3751 alias xgroupSetID = BinaryRedis.xgroupSetID; 3752 3753 Long xgroupDestroy(string key, string groupname) { 3754 checkIsInMultiOrPipeline(); 3755 client.xgroupDestroy(key, groupname); 3756 return client.getIntegerReply(); 3757 } 3758 alias xgroupDestroy = BinaryRedis.xgroupDestroy; 3759 3760 string xgroupDelConsumer(string key, string groupname, string consumerName) { 3761 checkIsInMultiOrPipeline(); 3762 client.xgroupDelConsumer(key, groupname, consumerName); 3763 return client.getStatusCodeReply(); 3764 } 3765 alias xgroupDelConsumer = BinaryRedis.xgroupDelConsumer; 3766 3767 Long xdel(string key, StreamEntryID[] ids...) { 3768 checkIsInMultiOrPipeline(); 3769 client.xdel(key, ids); 3770 return client.getIntegerReply(); 3771 } 3772 alias xdel = BinaryRedis.xdel; 3773 3774 Long xtrim(string key, long maxLen, bool approximateLength) { 3775 checkIsInMultiOrPipeline(); 3776 client.xtrim(key, maxLen, approximateLength); 3777 return client.getIntegerReply(); 3778 } 3779 alias xtrim = BinaryRedis.xtrim; 3780 3781 /** 3782 * {@inheritDoc} 3783 */ 3784 List!(MapEntry!(string, List!(StreamEntry))) xreadGroup(string groupname, string consumer, int count, long block, 3785 bool noAck, MapEntry!(string, StreamEntryID)[] streams...) { 3786 checkIsInMultiOrPipeline(); 3787 client.xreadGroup(groupname, consumer, count, block, noAck, streams); 3788 3789 List!(Object) streamsEntries = client.getObjectMultiBulkReply(); 3790 if(streamsEntries is null) { 3791 return null; 3792 } 3793 3794 List!(MapEntry!(string, List!(StreamEntry))) result = 3795 new ArrayList!(MapEntry!(string, List!(StreamEntry)))(streamsEntries.size()); 3796 3797 // foreach(Object streamObj ; streamsEntries) { 3798 // List!(Object) stream = cast(List!(Object))streamObj; 3799 3800 // // string streamId = SafeEncoder.encode((const(ubyte)[])stream.get(0)); 3801 // // List!(StreamEntry) streamEntries = BuilderFactory.STREAM_ENTRY_LIST.build(stream.get(1)); 3802 // // result.add(new AbstractMap.SimpleEntry!(string, List!(StreamEntry))(streamId, streamEntries)); 3803 // } 3804 3805 foreach(Object streamObj ; streamsEntries) { 3806 List!(Object) stream = cast(List!(Object))streamObj; 3807 Object obj = stream.get(0); 3808 3809 Bytes bytesData = cast(Bytes)obj; 3810 if(bytesData is null) { 3811 warningf("Object: %s", typeid(obj)); 3812 return result; 3813 } 3814 3815 const(ubyte)[] streamData = cast(const(ubyte)[]) bytesData.value; 3816 string streamId = SafeEncoder.encode(streamData); 3817 3818 // 3819 obj = stream.get(1); 3820 List!(StreamEntry) streamEntries = BuilderFactory.STREAM_ENTRY_LIST.build(obj); 3821 3822 result.add(new SimpleEntry!(string, List!(StreamEntry))(streamId, streamEntries)); 3823 } 3824 return result; 3825 } 3826 3827 List!(StreamPendingEntry) xpending(string key, string groupname, StreamEntryID start, StreamEntryID end, 3828 int count, string consumername) { 3829 checkIsInMultiOrPipeline(); 3830 client.xpending(key, groupname, start, end, count, consumername); 3831 3832 // TODO handle consumername == NULL case 3833 3834 return BuilderFactory.STREAM_PENDING_ENTRY_LIST.build(cast(Object)client.getObjectMultiBulkReply()); 3835 } 3836 alias xpending = BinaryRedis.xpending; 3837 3838 List!(StreamEntry) xclaim(string key, string group, string consumername, long minIdleTime, long newIdleTime, 3839 int retries, bool force, StreamEntryID[] ids...) { 3840 3841 checkIsInMultiOrPipeline(); 3842 client.xclaim( key, group, consumername, minIdleTime, newIdleTime, retries, force, ids); 3843 3844 return BuilderFactory.STREAM_ENTRY_LIST.build(cast(Object)client.getObjectMultiBulkReply()); 3845 } 3846 alias xclaim = BinaryRedis.xclaim; 3847 3848 Object sendCommand(ProtocolCommand cmd, string[] args...) { 3849 client.sendCommand(cmd, args); 3850 return client.getOne(); 3851 } 3852 alias sendCommand = BinaryRedis.sendCommand; 3853 3854 override Long slowlogLen() { return super.slowlogLen(); } 3855 override string auth(string password) { 3856 import std.range; 3857 if(password.empty) { 3858 return "empty password"; 3859 } 3860 return super.auth(password); 3861 } 3862 override string ping() { return super.ping(); } 3863 override string quit() { return super.quit(); } 3864 override string shutdown() { return super.shutdown(); } 3865 override Long dbSize() { return super.dbSize(); } 3866 override string flushDB() { return super.flushDB(); } 3867 override string flushAll() { return super.flushAll(); } 3868 3869 override string bgrewriteaof() { return super.bgrewriteaof(); } 3870 override string bgsave() { return super.bgsave(); } 3871 override Long lastsave() { return super.lastsave(); } 3872 override string save() { return super.save(); } 3873 3874 override string unwatch() { return super.unwatch(); } 3875 override string select(int index) { return super.select(index); } 3876 override string swapDB(int index1, int index2) { return super.swapDB(index1, index2); } 3877 override int getDB() { return super.getDB(); } 3878 override string info() { return super.info(); } 3879 override string info(string section) { return super.info(section); } 3880 3881 override string slaveof(string host, int port) { return super.slaveof(host, port); } 3882 override string slaveofNoOne() { return super.slaveofNoOne(); } 3883 override Long waitReplicas(int replicas, long timeout) { return super.waitReplicas(replicas, timeout); } 3884 3885 override string slowlogReset() { return super.slowlogReset(); } 3886 override string configResetStat() { return super.configResetStat(); } 3887 override string configRewrite() { return super.configRewrite(); } 3888 3889 }