10000 SRANDMEMBER optional COUNT argument · jrtkcoder/phpredis@51b9693 · GitHub
[go: up one dir, main page]

Skip to content

Commit 51b9693

Browse files
SRANDMEMBER optional COUNT argument
Adds support for the new COUNT argument to SRANDMEMBER. If called without a count, we will still return a string response (with one randome member from the set, or false on a failure/type error). If the count argument is passed, we return instead an array up to the number asked for, given how Redis will process this value. http://redis.io/commands/srandmember
1 parent 70430fb commit 51b9693

File tree

3 files changed

+124
-6
lines changed

3 files changed

+124
-6
lines changed

README.markdown

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -906,19 +906,31 @@ $redis->sPop('key1'); /* 'member3', 'key1' => {'member2'} */
906906

907907
## sRandMember
908908
##### *Description*
909-
Returns a random element from the set value at Key, without removing it.
909+
Returns a random element or random elements from the set value at Key, wit 10000 hout removing it/them.
910910
##### *Parameters*
911911
*key*
912-
##### *Return value*
912+
*count*: int, How many elements to return - optional. If the count is negative it will always return the # requested even if this requires duplicates to be returned
913+
##### *Return value (No count passed)*
913914
*String* value from the set
914915
*Bool* `FALSE` if set identified by key is empty or doesn't exist.
916+
##### *Return value (with count passed)*
917+
*Array* Random value(s) from the set, or an empty array if the set is empty or doesn't exist
915918
##### *Example*
916919
<pre>
917920
$redis->sAdd('key1' , 'member1');
918921
$redis->sAdd('key1' , 'member2');
919922
$redis->sAdd('key1' , 'member3'); /* 'key1' => {'member3', 'member1', 'member2'}*/
923+
924+
// No count
920925
$redis->sRandMember('key1'); /* 'member1', 'key1' => {'member3', 'member1', 'member2'} */
921926
$redis->sRandMember('key1'); /* 'member3', 'key1' => {'member3', 'member1', 'member2'} */
927+
928+
// With a count
929+
$redis->sRandMember('key1', 3); // Will return an array with all members from the set
930+
$redis->sRandMember('key1', 2); // Will an array with 2 members of the set
931+
$redis->sRandMember('key1', -100); // Will return an array of 100 elements, picked from our set (with dups)
932+
$redis->sRandMember('empty_set', 100); // Will return an empty array
933+
$redis->sRandMember('not_a_set', 100); // Will return FALSE
922934
</pre>
923935

924936
## sInter

redis.c

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2195,19 +2195,65 @@ PHP_METHOD(Redis, sPop)
21952195
/* }}} */
21962196

21972197
/* }}} */
2198-
/* {{{ proto string Redis::sRandMember(string key)
2198+
/* {{{ proto string Redis::sRandMember(string key [int count])
21992199
*/
22002200
PHP_METHOD(Redis, sRandMember)
22012201
{
2202-
generic_pop_function(INTERNAL_FUNCTION_PARAM_PASSTHRU, "SRANDMEMBER", 11);
2202+
zval *object;
2203+
RedisSock *redis_sock;
2204+
char *key = NULL, *cmd;
2205+
int key_len, cmd_len, key_free = 0, have_count = 0;
2206+
long count;
2207+
2208+
// Parse our params
2209+
if(zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os|l",
2210+
&object, redis_ce, &key, &key_len, &count) == FAILURE) {
2211+
RETURN_FALSE;
2212+
}
2213+
2214+
// Get our redis socket
2215+
if(redis_sock_get(object, &redis_sock TSRMLS_CC, 0) < 0) {
2216+
RETURN_FALSE;
2217+
}
2218+
2219+
// Prefix our key if necissary
2220+
key_free = redis_key_prefix(redis_sock, &key, &key_len TSRMLS_CC);
2221+
2222+
// Do we have a count
2223+
have_count = ZEND_NUM_ARGS() == 2;
2224+
2225+
// If we have two arguments, we're running with an optional COUNT, which will return
2226+
// a multibulk reply. Without the argument we'll return a string response
2227+
if(have_count) {
2228+
// Construct our command with count
2229+
cmd_len = redis_cmd_format_static(&cmd, "SRANDMEMBER", "sl", key, key_len, count);
2230+
} else {
2231+
// Construct our command
2232+
cmd_len = redis_cmd_format_static(&cmd, "SRANDMEMBER", "s", key, key_len);
2233+
}
2234+
2235+
// Free our key if we prefixed it
2236+
if(key_free) efree(key);
2237+
2238+
// Process our command
2239+
REDIS_PROCESS_REQUEST(redis_sock, cmd, cmd_len);
2240+
2241+
// Process our reply
2242+
IF_ATOMIC() {
2243+
// This will be bulk or multi-bulk depending if we passed the optional [COUNT] argument
2244+
if(redis_read_variant_reply(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, NULL) < 0) {
2245+
RETURN_FALSE;
2246+
}
2247+
}
2248+
REDIS_PROCESS_RESPONSE(redis_read_variant_reply);
22032249
}
22042250
/* }}} */
22052251

22062252
/* {{{ proto boolean Redis::sContains(string set, string value)
22072253
*/
22082254
PHP_METHOD(Redis, sContains)
22092255
{
2210-
zval *object;
2256+
zval *object;
22112257
RedisSock *redis_sock;
22122258
char *key = NULL, *val = NULL, *cmd;
22132259
int key_len, val_len, cmd_len;

tests/TestRedis.php

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1083,6 +1083,61 @@ public function testsRandMember() {
10831083
}
10841084
}
10851085

1086+
public function testSRandMemberWithCount() {
1087+
// Make sure the set is nuked
1088+
$this->redis->delete('set0');
1089+
1090+
// Run with a count (positive and negative) on an empty set
1091+
$ret_pos = $this->redis->sRandMember('set0', 10);
1092+
$ret_neg = $this->redis->sRandMember('set0', -10);
1093+
1094+
// Should both be empty arrays
1095+
$this->assertTrue(is_array($ret_pos) && empty($ret_pos));
1096+
$this->assertTrue(is_array($ret_neg) && empty($ret_neg));
1097+
1098+
// Add a few items to the set
1099+
for($i=0;$i<100;$i++) {
1100+
$this->redis->sadd('set0', "member$i");
1101+
}
1102+
1103+
// Get less than the size of the list
1104+
$ret_slice = $this->redis->srandmember('set0', 20);
1105+
1106+
// Should be an array with 20 items
1107+
$this->assertTrue(is_array($ret_slice) && count($ret_slice) == 20);
1108+
1109+
// Ask for more items than are in the list (but with a positive count)
1110+
$ret_slice = $this->redis->srandmember('set0', 200);
1111+
1112+
// Should be an array, should be however big the set is, exactly
1113+
$this->assertTrue(is_array($ret_slice) && count($ret_slice) == $i);
1114+
1115+
// Now ask for too many items but negative
1116+
$ret_slice = $this->redis->srandmember('set0', -200);
1117+
1118+
// Should be an array, should have exactly the # of items we asked for (will be dups)
1119+
$this->assertTrue(is_array($ret_slice) && count($ret_slice) == 200);
1120+
1121+
//
1122+
// Test in a pipeline
1123+
//
1124+
1125+
$pipe = $this->redis->pipeline();
1126+
1127+
$pipe->srandmember('set0', 20);
1128+
$pipe->srandmember('set0', 200);
1129+
$pipe->srandmember('set0', -200);
1130+
1131+
$ret = $this->redis->exec();
1132+
1133+
$this->assertTrue(is_array($ret[0]) && count($ret[0]) == 20);
1134+
$this->assertTrue(is_array($ret[1]) && count($ret[1]) == $i);
1135+
$this->assertTrue(is_array($ret[2]) && count($ret[2]) == 200);
1136+
1137+
// Kill the set
1138+
$this->redis->del('set0');
1139+
}
1140+
10861141
public function testsContains()
10871142
{
10881143
$this->redis->delete('set');
@@ -3241,7 +3296,12 @@ public function testUnserialize() {
32413296
1,1.5,'one',Array('this','is','an','array')
32423297
);
32433298

3244-
foreach(Array(Redis::SERIALIZER_PHP, Redis::SERIALIZER_IGBINARY) as $mode) {
3299+
$serializers = Array(Redis::SERIALIZER_PHP);
3300+
if(defined('Redis::SERIALIZER_IGBINARY')) {
3301+
$serializers[] = Redis::SERIALIZER_IGBINARY;
3302+
}
3303+
3304+
foreach($serializers as $mode) {
32453305
$vals_enc = Array();
32463306

32473307
// Pass them through redis so they're serialized

0 commit comments

Comments
 (0)
0