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