diff options
author | Pavlo Yatsukhnenko <yatsukhnenko@gmail.com> | 2022-04-11 22:59:01 +0300 |
---|---|---|
committer | Pavlo Yatsukhnenko <yatsukhnenko@gmail.com> | 2022-04-12 22:00:04 +0300 |
commit | fe397371ef1504b90c484df93c30a596aa201ce1 (patch) | |
tree | 94d345d0677e6b82ca8398163ecc1952ebac74db | |
parent | c65772fb4d954933a503494b5d5413c3948ece6a (diff) |
Issue #1894
Add Redis::hRandField command
-rw-r--r-- | library.c | 11 | ||||
-rw-r--r-- | library.h | 1 | ||||
-rw-r--r-- | redis.c | 8 | ||||
-rw-r--r-- | redis.stub.php | 2 | ||||
-rw-r--r-- | redis_arginfo.h | 14 | ||||
-rw-r--r-- | redis_commands.c | 50 | ||||
-rw-r--r-- | redis_commands.h | 3 | ||||
-rw-r--r-- | redis_legacy_arginfo.h | 16 | ||||
-rw-r--r-- | tests/RedisClusterTest.php | 1 | ||||
-rw-r--r-- | tests/RedisTest.php | 19 |
10 files changed, 112 insertions, 13 deletions
@@ -1301,6 +1301,17 @@ redis_set_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_ } PHP_REDIS_API int +redis_hrandfield_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx) +{ + if (ctx == NULL) { + return redis_string_response(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, z_tab, NULL); + } else if (ctx == PHPREDIS_CTX_PTR) { + return redis_mbulk_reply_raw(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, z_tab, NULL); + } + return redis_mbulk_reply_zipped_raw(INTERNAL_FUNCTION_PARAM_PASSTHRU, redis_sock, z_tab, NULL); +} + +PHP_REDIS_API int redis_boolean_response_impl(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx, SuccessCallback success_callback) @@ -165,6 +165,7 @@ PHP_REDIS_API int redis_zrandmember_response(INTERNAL_FUNCTION_PARAMETERS, Redis PHP_REDIS_API int redis_zdiff_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx); PHP_REDIS_API int redis_set_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx); PHP_REDIS_API int redis_geosearch_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx); +PHP_REDIS_API int redis_hrandfield_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx); /* Helper methods to get configuration values from a HashTable. */ @@ -2219,6 +2219,14 @@ PHP_METHOD(Redis, hMset) } /* }}} */ +/* {{{ proto bool Redis::hRandField(string key, [array $options]) */ +PHP_METHOD(Redis, hRandField) +{ + REDIS_PROCESS_CMD(hrandfield, redis_hrandfield_response); +} +/* }}} */ + + /* {{{ proto long Redis::hstrlen(string key, string field) */ PHP_METHOD(Redis, hStrLen) { REDIS_PROCESS_CMD(hstrlen, redis_long_response); diff --git a/redis.stub.php b/redis.stub.php index 03183817..e5b72dd1 100644 --- a/redis.stub.php +++ b/redis.stub.php @@ -193,6 +193,8 @@ class Redis { public function hMset(string $key, array $keyvals): bool; + public function hRandField(string $key, array $options = null): string|array; + public function hSet(string $key, string $member, string $value): int; public function hSetNx(string $key, string $member, string $value): int; diff --git a/redis_arginfo.h b/redis_arginfo.h index 786c2547..3525e26c 100644 --- a/redis_arginfo.h +++ b/redis_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 4b894d8f0c04d6c25398e5dc399598d0ede4ed05 */ + * Stub hash: 452d7bafe0b4a9d6d67353613d9cde2d407aa2a2 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis___construct, 0, 0, 0) ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_ARRAY, 0, "null") @@ -334,6 +334,11 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Redis_hMset, 0, 2, _IS_BOO ZEND_ARG_TYPE_INFO(0, keyvals, IS_ARRAY, 0) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_class_Redis_hRandField, 0, 1, MAY_BE_STRING|MAY_BE_ARRAY) + ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0) + ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_ARRAY, 0, "null") +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Redis_hSet, 0, 3, IS_LONG, 0) ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0) ZEND_ARG_TYPE_INFO(0, member, IS_STRING, 0) @@ -888,10 +893,7 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Redis_zRangeByScore, 0, 3, ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_ARRAY, 0, "[]") ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_WITH_RETURN_TYPE_MASK_EX(arginfo_class_Redis_zRandMember, 0, 1, MAY_BE_STRING|MAY_BE_ARRAY) - ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0) - ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_ARRAY, 0, "null") -ZEND_END_ARG_INFO() +#define arginfo_class_Redis_zRandMember arginfo_class_Redis_hRandField #define arginfo_class_Redis_zRank arginfo_class_Redis_hStrLen @@ -1030,6 +1032,7 @@ ZEND_METHOD(Redis, hKeys); ZEND_METHOD(Redis, hLen); ZEND_METHOD(Redis, hMget); ZEND_METHOD(Redis, hMset); +ZEND_METHOD(Redis, hRandField); ZEND_METHOD(Redis, hSet); ZEND_METHOD(Redis, hSetNx); ZEND_METHOD(Redis, hStrLen); @@ -1257,6 +1260,7 @@ static const zend_function_entry class_Redis_methods[] = { ZEND_ME(Redis, hLen, arginfo_class_Redis_hLen, ZEND_ACC_PUBLIC) ZEND_ME(Redis, hMget, arginfo_class_Redis_hMget, ZEND_ACC_PUBLIC) ZEND_ME(Redis, hMset, arginfo_class_Redis_hMset, ZEND_ACC_PUBLIC) + ZEND_ME(Redis, hRandField, arginfo_class_Redis_hRandField, ZEND_ACC_PUBLIC) ZEND_ME(Redis, hSet, arginfo_class_Redis_hSet, ZEND_ACC_PUBLIC) ZEND_ME(Redis, hSetNx, arginfo_class_Redis_hSetNx, ZEND_ACC_PUBLIC) ZEND_ME(Redis, hStrLen, arginfo_class_Redis_hStrLen, ZEND_ACC_PUBLIC) diff --git a/redis_commands.c b/redis_commands.c index 7d9fd88a..c4809e32 100644 --- a/redis_commands.c +++ b/redis_commands.c @@ -2548,6 +2548,54 @@ int redis_hsetnx_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, cmd, cmd_len, slot); } +int +redis_hrandfield_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, + char **cmd, int *cmd_len, short *slot, void **ctx) +{ + char *key; + int count = 0; + size_t key_len; + smart_string cmdstr = {0}; + zend_bool withvalues = 0; + zval *z_opts = NULL, *z_ele; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|a", + &key, &key_len, &z_opts) == FAILURE) + { + return FAILURE; + } + + if (z_opts && Z_TYPE_P(z_opts) == IS_ARRAY) { + zend_string *zkey; + ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(z_opts), zkey, z_ele) { + ZVAL_DEREF(z_ele); + if (zend_string_equals_literal_ci(zkey, "count")) { + count = zval_get_long(z_ele); + } else if (zend_string_equals_literal_ci(zkey, "withvalues")) { + withvalues = zval_is_true(z_ele); + } + } ZEND_HASH_FOREACH_END(); + } + + REDIS_CMD_INIT_SSTR_STATIC(&cmdstr, 1 + (count != 0) + withvalues, "HRANDFIELD"); + redis_cmd_append_sstr_key(&cmdstr, key, key_len, redis_sock, slot); + + if (count != 0) { + redis_cmd_append_sstr_long(&cmdstr, count); + *ctx = PHPREDIS_CTX_PTR; + } + + if (withvalues) { + REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "WITHVALUES"); + *ctx = PHPREDIS_CTX_PTR + 1; + } + + + *cmd = cmdstr.c; + *cmd_len = cmdstr.len; + return SUCCESS; +} + /* SRANDMEMBER */ int redis_srandmember_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, char **cmd, int *cmd_len, short *slot, void **ctx, @@ -3299,7 +3347,6 @@ redis_geosearch_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, { char *key, *unit; int argc = 2; - short store_slot = 0; size_t keylen, unitlen; geoOptions gopts = {0}; smart_string cmdstr = {0}; @@ -3423,7 +3470,6 @@ redis_geosearchstore_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, { int argc = 3; char *dest, *src, *unit; - short store_slot = 0; size_t destlen, srclen, unitlen; geoOptions gopts = {0}; smart_string cmdstr = {0}; diff --git a/redis_commands.h b/redis_commands.h index eed3d7dc..ab9646e7 100644 --- a/redis_commands.h +++ b/redis_commands.h @@ -219,6 +219,9 @@ int redis_lrem_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, int redis_smove_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, char **cmd, int *cmd_len, short *slot, void **ctx); +int redis_hrandfield_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, + char **cmd, int *cmd_len, short *slot, void **ctx); + int redis_hset_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, char **cmd, int *cmd_len, short *slot, void **ctx); diff --git a/redis_legacy_arginfo.h b/redis_legacy_arginfo.h index 39890355..1788713c 100644 --- a/redis_legacy_arginfo.h +++ b/redis_legacy_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 4b894d8f0c04d6c25398e5dc399598d0ede4ed05 */ + * Stub hash: 452d7bafe0b4a9d6d67353613d9cde2d407aa2a2 */ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis___construct, 0, 0, 0) ZEND_ARG_INFO(0, options) @@ -304,6 +304,11 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_hMset, 0, 0, 2) ZEND_ARG_INFO(0, keyvals) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_hRandField, 0, 0, 1) + ZEND_ARG_INFO(0, key) + ZEND_ARG_INFO(0, options) +ZEND_END_ARG_INFO() + #define arginfo_class_Redis_hSet arginfo_class_Redis_hIncrBy #define arginfo_class_Redis_hSetNx arginfo_class_Redis_hIncrBy @@ -602,10 +607,7 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_slowlog, 0, 0, 1) ZEND_ARG_INFO(0, option) ZEND_END_ARG_INFO() -ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_sort, 0, 0, 1) - ZEND_ARG_INFO(0, key) - ZEND_ARG_INFO(0, options) -ZEND_END_ARG_INFO() +#define arginfo_class_Redis_sort arginfo_class_Redis_hRandField ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_sortAsc, 0, 0, 1) ZEND_ARG_INFO(0, key) @@ -800,7 +802,7 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_zRangeByScore, 0, 0, 3) ZEND_ARG_INFO(0, options) ZEND_END_ARG_INFO() -#define arginfo_class_Redis_zRandMember arginfo_class_Redis_sort +#define arginfo_class_Redis_zRandMember arginfo_class_Redis_hRandField #define arginfo_class_Redis_zRank arginfo_class_Redis_hExists @@ -932,6 +934,7 @@ ZEND_METHOD(Redis, hKeys); ZEND_METHOD(Redis, hLen); ZEND_METHOD(Redis, hMget); ZEND_METHOD(Redis, hMset); +ZEND_METHOD(Redis, hRandField); ZEND_METHOD(Redis, hSet); ZEND_METHOD(Redis, hSetNx); ZEND_METHOD(Redis, hStrLen); @@ -1159,6 +1162,7 @@ static const zend_function_entry class_Redis_methods[] = { ZEND_ME(Redis, hLen, arginfo_class_Redis_hLen, ZEND_ACC_PUBLIC) ZEND_ME(Redis, hMget, arginfo_class_Redis_hMget, ZEND_ACC_PUBLIC) ZEND_ME(Redis, hMset, arginfo_class_Redis_hMset, ZEND_ACC_PUBLIC) + ZEND_ME(Redis, hRandField, arginfo_class_Redis_hRandField, ZEND_ACC_PUBLIC) ZEND_ME(Redis, hSet, arginfo_class_Redis_hSet, ZEND_ACC_PUBLIC) ZEND_ME(Redis, hSetNx, arginfo_class_Redis_hSetNx, ZEND_ACC_PUBLIC) ZEND_ME(Redis, hStrLen, arginfo_class_Redis_hStrLen, ZEND_ACC_PUBLIC) diff --git a/tests/RedisClusterTest.php b/tests/RedisClusterTest.php index 6ca5153d..18e4ac21 100644 --- a/tests/RedisClusterTest.php +++ b/tests/RedisClusterTest.php @@ -61,6 +61,7 @@ class Redis_Cluster_Test extends Redis_Test { public function testCopy() { return $this->marktestSkipped(); } public function testGeoSearch() { return $this->marktestSkipped(); } public function testGeoSearchStore() { return $this->marktestSkipped(); } + public function testHRandField() { return $this->marktestSkipped(); } /* Session locking feature is currently not supported in in context of Redis Cluster. The biggest issue for this is the distribution nature of Redis cluster */ diff --git a/tests/RedisTest.php b/tests/RedisTest.php index 8c79d6be..d480e7ec 100644 --- a/tests/RedisTest.php +++ b/tests/RedisTest.php @@ -2846,6 +2846,25 @@ class Redis_Test extends TestSuite } } + public function testHRandField() + { + if (version_compare($this->version, "6.2.0") < 0) { + $this->MarkTestSkipped(); + return; + } + $this->redis->del('key'); + $this->redis->hMSet('key', ['a' => 0, 'b' => 1, 'c' => 'foo', 'd' => 'bar', 'e' => null]); + $this->assertInArray($this->redis->hRandField('key'), ['a', 'b', 'c', 'd', 'e']); + + $result = $this->redis->hRandField('key', ['count' => 3]); + $this->assertEquals(3, count($result)); + $this->assertEquals(array_intersect($result, ['a', 'b', 'c', 'd', 'e']), $result); + + $result = $this->redis->hRandField('key', ['count' => 2, 'withvalues' => true]); + $this->assertEquals(2, count($result)); + $this->assertEquals(array_intersect_key($result, ['a' => 0, 'b' => 1, 'c' => 'foo', 'd' => 'bar', 'e' => null]), $result); + } + public function testSetRange() { $this->redis->del('key'); |