Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/phpredis/phpredis.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--library.c69
-rw-r--r--library.h1
-rw-r--r--php_redis.h2
-rw-r--r--redis.c8
-rw-r--r--redis.stub.php4
-rw-r--r--redis_arginfo.h23
-rw-r--r--redis_commands.c242
-rw-r--r--redis_commands.h6
-rw-r--r--redis_legacy_arginfo.h23
-rw-r--r--tests/RedisClusterTest.php2
-rw-r--r--tests/RedisTest.php28
11 files changed, 405 insertions, 3 deletions
diff --git a/library.c b/library.c
index 119af6f7..a675551d 100644
--- a/library.c
+++ b/library.c
@@ -1543,6 +1543,75 @@ redis_sock_read_single_line(RedisSock *redis_sock, char *buffer, size_t buflen,
return type == TYPE_LINE ? 0 : -1;
}
+static int
+geosearch_cast(zval *zv)
+{
+ if (Z_TYPE_P(zv) == IS_ARRAY) {
+ zend_hash_apply(Z_ARRVAL_P(zv), geosearch_cast);
+ } else if (Z_TYPE_P(zv) == IS_STRING) {
+ convert_to_double(zv);
+ }
+ return SUCCESS;
+}
+
+PHP_REDIS_API int
+redis_geosearch_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
+ zval *z_tab, void *ctx)
+{
+ int numElems;
+ zval z_ret, z_multi_result, z_sub, z_tmp, *z_ele, *zv;
+ zend_string *zkey;
+
+ if (read_mbulk_header(redis_sock, &numElems) < 0) {
+ return FAILURE;
+ }
+
+ if (numElems < 0 && redis_sock->null_mbulk_as_null) {
+ ZVAL_NULL(&z_ret);
+ } else {
+ array_init(&z_ret);
+ if (ctx == NULL) {
+ redis_mbulk_reply_loop(redis_sock, &z_ret, numElems, UNSERIALIZE_NONE);
+ } else {
+ array_init(&z_multi_result);
+ redis_read_multibulk_recursive(redis_sock, numElems, 0, &z_multi_result);
+
+ ZEND_HASH_FOREACH_VAL(Z_ARRVAL(z_multi_result), z_ele) {
+ // The first item in the sub-array is always the name of the returned item
+ zv = zend_hash_index_find(Z_ARRVAL_P(z_ele), 0);
+ zkey = zval_get_string(zv);
+
+ zend_hash_index_del(Z_ARRVAL_P(z_ele), 0);
+
+ // The other information is returned in the following order as successive
+ // elements of the sub-array: distance, geohash, coordinates
+ zend_hash_apply(Z_ARRVAL_P(z_ele), geosearch_cast);
+
+ // Copy values to re-order from zero
+ array_init(&z_sub);
+ ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(z_ele), zv) {
+ ZVAL_ZVAL(&z_tmp, zv, 1, 0);
+ add_next_index_zval(&z_sub, &z_tmp);
+ } ZEND_HASH_FOREACH_END();
+
+ add_assoc_zval_ex(&z_ret, ZSTR_VAL(zkey), ZSTR_LEN(zkey), &z_sub);
+ zend_string_release(zkey);
+ } ZEND_HASH_FOREACH_END();
+
+ // Cleanup
+ zval_dtor(&z_multi_result);
+ }
+ }
+
+ if (IS_ATOMIC(redis_sock)) {
+ RETVAL_ZVAL(&z_ret, 0, 1);
+ } else {
+ add_next_index_zval(z_tab, &z_ret);
+ }
+
+ return SUCCESS;
+}
+
/* Helper function to consume Redis stream message data. This is useful for
* multiple stream callers (e.g. XREAD[GROUP], and X[REV]RANGE handlers). */
PHP_REDIS_API int
diff --git a/library.h b/library.h
index 0b3b713c..4fa32eae 100644
--- a/library.h
+++ b/library.h
@@ -165,6 +165,7 @@ PHP_REDIS_API int redis_client_list_reply(INTERNAL_FUNCTION_PARAMETERS, RedisSoc
PHP_REDIS_API int redis_zrandmember_response(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock, zval *z_tab, void *ctx);
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);
/* Helper methods to get configuration values from a HashTable. */
diff --git a/php_redis.h b/php_redis.h
index 2c9ec50f..97ef3b55 100644
--- a/php_redis.h
+++ b/php_redis.h
@@ -23,7 +23,7 @@
#define PHP_REDIS_H
/* phpredis version */
-#define PHP_REDIS_VERSION "5.3.2"
+#define PHP_REDIS_VERSION "6.0.0-dev"
/* For convenience we store the salt as a printable hex string which requires 2
* characters per byte + 1 for the NULL terminator */
diff --git a/redis.c b/redis.c
index 991d940e..5a5d787b 100644
--- a/redis.c
+++ b/redis.c
@@ -3598,6 +3598,14 @@ PHP_METHOD(Redis, georadiusbymember_ro) {
REDIS_PROCESS_KW_CMD("GEORADIUSBYMEMBER_RO", redis_georadiusbymember_cmd, redis_read_variant_reply);
}
+PHP_METHOD(Redis, geosearch) {
+ REDIS_PROCESS_CMD(geosearch, redis_geosearch_response);
+}
+
+PHP_METHOD(Redis, geosearchstore) {
+ REDIS_PROCESS_CMD(geosearchstore, redis_long_response);
+}
+
/*
* Streams
*/
diff --git a/redis.stub.php b/redis.stub.php
index 1cef27c7..1ab3b318 100644
--- a/redis.stub.php
+++ b/redis.stub.php
@@ -137,6 +137,10 @@ class Redis {
public function georadiusbymember_ro(string $key, string $member, float $radius, string $unit, array $options = []): array;
+ public function geosearch(string $key, array|string $position, array|int|float $shape, string $unit, array $options = []): array;
+
+ public function geosearchstore(string $dst, string $src, array|string $position, array|int|float $shape, string $unit, array $options = []): array;
+
/** @return string|Redis */
public function get(string $key);
diff --git a/redis_arginfo.h b/redis_arginfo.h
index 2efa4481..09b2fda4 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: 1c4a88252c8b66263f1b1d72af974ba5ce992d40 */
+ * Stub hash: c2cbe49e22cba6f23e98c1676b7769c55a6fd043 */
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")
@@ -229,6 +229,23 @@ ZEND_END_ARG_INFO()
#define arginfo_class_Redis_georadiusbymember_ro arginfo_class_Redis_georadiusbymember
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Redis_geosearch, 0, 4, IS_ARRAY, 0)
+ ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
+ ZEND_ARG_TYPE_MASK(0, position, MAY_BE_ARRAY|MAY_BE_STRING, NULL)
+ ZEND_ARG_TYPE_MASK(0, shape, MAY_BE_ARRAY|MAY_BE_LONG|MAY_BE_DOUBLE, NULL)
+ ZEND_ARG_TYPE_INFO(0, unit, IS_STRING, 0)
+ ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_ARRAY, 0, "[]")
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Redis_geosearchstore, 0, 5, IS_ARRAY, 0)
+ ZEND_ARG_TYPE_INFO(0, dst, IS_STRING, 0)
+ ZEND_ARG_TYPE_INFO(0, src, IS_STRING, 0)
+ ZEND_ARG_TYPE_MASK(0, position, MAY_BE_ARRAY|MAY_BE_STRING, NULL)
+ ZEND_ARG_TYPE_MASK(0, shape, MAY_BE_ARRAY|MAY_BE_LONG|MAY_BE_DOUBLE, NULL)
+ ZEND_ARG_TYPE_INFO(0, unit, IS_STRING, 0)
+ ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_ARRAY, 0, "[]")
+ZEND_END_ARG_INFO()
+
#define arginfo_class_Redis_get arginfo_class_Redis_decr
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_Redis_getAuth, 0, 0, IS_MIXED, 0)
@@ -974,6 +991,8 @@ ZEND_METHOD(Redis, georadius);
ZEND_METHOD(Redis, georadius_ro);
ZEND_METHOD(Redis, georadiusbymember);
ZEND_METHOD(Redis, georadiusbymember_ro);
+ZEND_METHOD(Redis, geosearch);
+ZEND_METHOD(Redis, geosearchstore);
ZEND_METHOD(Redis, get);
ZEND_METHOD(Redis, getAuth);
ZEND_METHOD(Redis, getBit);
@@ -1197,6 +1216,8 @@ static const zend_function_entry class_Redis_methods[] = {
ZEND_ME(Redis, georadius_ro, arginfo_class_Redis_georadius_ro, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, georadiusbymember, arginfo_class_Redis_georadiusbymember, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, georadiusbymember_ro, arginfo_class_Redis_georadiusbymember_ro, ZEND_ACC_PUBLIC)
+ ZEND_ME(Redis, geosearch, arginfo_class_Redis_geosearch, ZEND_ACC_PUBLIC)
+ ZEND_ME(Redis, geosearchstore, arginfo_class_Redis_geosearchstore, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, get, arginfo_class_Redis_get, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, getAuth, arginfo_class_Redis_getAuth, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, getBit, arginfo_class_Redis_getBit, ZEND_ACC_PUBLIC)
diff --git a/redis_commands.c b/redis_commands.c
index 3a274ebe..895078da 100644
--- a/redis_commands.c
+++ b/redis_commands.c
@@ -3316,6 +3316,248 @@ int redis_georadiusbymember_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_s
return SUCCESS;
}
+int
+redis_geosearch_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
+ char **cmd, int *cmd_len, short *slot, void **ctx)
+{
+ char *key, *unit;
+ int argc = 2;
+ short store_slot = 0;
+ size_t keylen, unitlen;
+ geoOptions gopts = {0};
+ smart_string cmdstr = {0};
+ zval *position, *shape, *opts = NULL, *z_ele;
+ zend_string *zkey;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "szzs|a",
+ &key, &keylen, &position, &shape,
+ &unit, &unitlen, &opts) == FAILURE)
+ {
+ return FAILURE;
+ }
+
+ if (Z_TYPE_P(position) == IS_STRING && Z_STRLEN_P(position) > 0) {
+ argc += 2;
+ } else if (Z_TYPE_P(position) == IS_ARRAY && zend_hash_num_elements(Z_ARRVAL_P(position)) == 2) {
+ argc += 3;
+ } else {
+ php_error_docref(NULL, E_WARNING, "Invalid position");
+ return FAILURE;
+ }
+
+ if (Z_TYPE_P(shape) == IS_LONG || Z_TYPE_P(shape) == IS_DOUBLE) {
+ argc += 2;
+ } else if (Z_TYPE_P(shape) == IS_ARRAY) {
+ argc += 3;
+ } else {
+ php_error_docref(NULL, E_WARNING, "Invalid shape dimensions");
+ return FAILURE;
+ }
+
+ /* Attempt to parse our options array */
+ if (opts != NULL && Z_TYPE_P(opts) == IS_ARRAY) {
+ ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(opts), zkey, z_ele) {
+ ZVAL_DEREF(z_ele);
+ if (zkey != NULL) {
+ if (zend_string_equals_literal_ci(zkey, "COUNT")) {
+ if (Z_TYPE_P(z_ele) != IS_LONG || Z_LVAL_P(z_ele) <= 0) {
+ php_error_docref(NULL, E_WARNING, "COUNT must be an integer > 0!");
+ return FAILURE;
+ }
+ gopts.count = Z_LVAL_P(z_ele);
+ }
+ } else if (Z_TYPE_P(z_ele) == IS_STRING) {
+ if (!strcasecmp(Z_STRVAL_P(z_ele), "WITHCOORD")) {
+ gopts.withcoord = 1;
+ } else if (!strcasecmp(Z_STRVAL_P(z_ele), "WITHDIST")) {
+ gopts.withdist = 1;
+ } else if (!strcasecmp(Z_STRVAL_P(z_ele), "WITHHASH")) {
+ gopts.withhash = 1;
+ } else if (!strcasecmp(Z_STRVAL_P(z_ele), "ASC")) {
+ gopts.sort = SORT_ASC;
+ } else if (!strcasecmp(Z_STRVAL_P(z_ele), "DESC")) {
+ gopts.sort = SORT_DESC;
+ }
+ }
+ } ZEND_HASH_FOREACH_END();
+ }
+
+ /* Increment argc based on options */
+ argc += gopts.withcoord + gopts.withdist + gopts.withhash
+ + (gopts.sort != SORT_NONE) + (gopts.count ? 2 : 0);
+
+ REDIS_CMD_INIT_SSTR_STATIC(&cmdstr, argc, "GEOSEARCH");
+ redis_cmd_append_sstr_key(&cmdstr, key, keylen, redis_sock, slot);
+
+ if (Z_TYPE_P(position) == IS_ARRAY) {
+ REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "FROMLONLAT");
+ ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(position), z_ele) {
+ ZVAL_DEREF(z_ele);
+ redis_cmd_append_sstr_dbl(&cmdstr, zval_get_double(z_ele));
+ } ZEND_HASH_FOREACH_END();
+ } else {
+ REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "FROMMEMBER");
+ redis_cmd_append_sstr(&cmdstr, Z_STRVAL_P(position), Z_STRLEN_P(position));
+ }
+
+ if (Z_TYPE_P(shape) == IS_ARRAY) {
+ REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "BYBOX");
+ ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(shape), z_ele) {
+ ZVAL_DEREF(z_ele);
+ redis_cmd_append_sstr_dbl(&cmdstr, zval_get_double(z_ele));
+ } ZEND_HASH_FOREACH_END();
+ } else {
+ REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "BYRADIUS");
+ redis_cmd_append_sstr_dbl(&cmdstr, zval_get_double(shape));
+ }
+ redis_cmd_append_sstr(&cmdstr, unit, unitlen);
+
+ /* Append optional arguments */
+ if (gopts.withcoord) REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "WITHCOORD");
+ if (gopts.withdist) REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "WITHDIST");
+ if (gopts.withhash) REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "WITHHASH");
+
+ /* Append sort if it's not GEO_NONE */
+ if (gopts.sort == SORT_ASC) {
+ REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "ASC");
+ } else if (gopts.sort == SORT_DESC) {
+ REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "DESC");
+ }
+
+ /* Append our count if we've got one */
+ if (gopts.count) {
+ REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "COUNT");
+ redis_cmd_append_sstr_long(&cmdstr, gopts.count);
+ }
+
+ if ((argc = gopts.withcoord + gopts.withdist + gopts.withhash) > 0) {
+ *ctx = PHPREDIS_CTX_PTR;
+ }
+
+ *cmd = cmdstr.c;
+ *cmd_len = cmdstr.len;
+
+ return SUCCESS;
+}
+
+int
+redis_geosearchstore_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
+ char **cmd, int *cmd_len, short *slot, void **ctx)
+{
+ int argc = 3;
+ char *dest, *src, *unit;
+ short store_slot = 0;
+ size_t destlen, srclen, unitlen;
+ geoOptions gopts = {0};
+ smart_string cmdstr = {0};
+ zval *position, *shape, *opts = NULL, *z_ele;
+ zend_string *zkey;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS(), "sszzs|a",
+ &dest, &destlen, &src, &srclen, &position, &shape,
+ &unit, &unitlen, &opts) == FAILURE)
+ {
+ return FAILURE;
+ }
+
+ if (Z_TYPE_P(position) == IS_STRING && Z_STRLEN_P(position) > 0) {
+ argc += 2;
+ } else if (Z_TYPE_P(position) == IS_ARRAY && zend_hash_num_elements(Z_ARRVAL_P(position)) == 2) {
+ argc += 3;
+ } else {
+ php_error_docref(NULL, E_WARNING, "Invalid position");
+ return FAILURE;
+ }
+
+ if (Z_TYPE_P(shape) == IS_LONG || Z_TYPE_P(shape) == IS_DOUBLE) {
+ argc += 2;
+ } else if (Z_TYPE_P(shape) == IS_ARRAY) {
+ argc += 3;
+ } else {
+ php_error_docref(NULL, E_WARNING, "Invalid shape dimensions");
+ return FAILURE;
+ }
+
+ /* Attempt to parse our options array */
+ if (opts != NULL && Z_TYPE_P(opts) == IS_ARRAY) {
+ ZEND_HASH_FOREACH_STR_KEY_VAL(Z_ARRVAL_P(opts), zkey, z_ele) {
+ ZVAL_DEREF(z_ele);
+ if (zkey != NULL) {
+ if (zend_string_equals_literal_ci(zkey, "COUNT")) {
+ if (Z_TYPE_P(z_ele) != IS_LONG || Z_LVAL_P(z_ele) <= 0) {
+ php_error_docref(NULL, E_WARNING, "COUNT must be an integer > 0!");
+ return FAILURE;
+ }
+ gopts.count = Z_LVAL_P(z_ele);
+ }
+ } else if (Z_TYPE_P(z_ele) == IS_STRING) {
+ if (!strcasecmp(Z_STRVAL_P(z_ele), "ASC")) {
+ gopts.sort = SORT_ASC;
+ } else if (!strcasecmp(Z_STRVAL_P(z_ele), "DESC")) {
+ gopts.sort = SORT_DESC;
+ } else if (!strcasecmp(Z_STRVAL_P(z_ele), "STOREDIST")) {
+ gopts.store = STORE_DIST;
+ }
+ }
+ } ZEND_HASH_FOREACH_END();
+
+ }
+
+ /* Increment argc based on options */
+ argc += gopts.withcoord + gopts.withdist + gopts.withhash
+ + (gopts.sort != SORT_NONE) + (gopts.count ? 2 : 0)
+ + (gopts.store != STORE_NONE);
+
+ REDIS_CMD_INIT_SSTR_STATIC(&cmdstr, argc, "GEOSEARCHSTORE");
+ redis_cmd_append_sstr_key(&cmdstr, dest, destlen, redis_sock, slot);
+ redis_cmd_append_sstr_key(&cmdstr, src, srclen, redis_sock, slot);
+
+ if (Z_TYPE_P(position) == IS_ARRAY) {
+ REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "FROMLONLAT");
+ ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(position), z_ele) {
+ ZVAL_DEREF(z_ele);
+ redis_cmd_append_sstr_dbl(&cmdstr, zval_get_double(z_ele));
+ } ZEND_HASH_FOREACH_END();
+ } else {
+ REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "FROMMEMBER");
+ redis_cmd_append_sstr(&cmdstr, Z_STRVAL_P(position), Z_STRLEN_P(position));
+ }
+
+ if (Z_TYPE_P(shape) == IS_ARRAY) {
+ REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "BYBOX");
+ ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(shape), z_ele) {
+ ZVAL_DEREF(z_ele);
+ redis_cmd_append_sstr_dbl(&cmdstr, zval_get_double(z_ele));
+ } ZEND_HASH_FOREACH_END();
+ } else {
+ REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "BYRADIUS");
+ redis_cmd_append_sstr_dbl(&cmdstr, zval_get_double(shape));
+ }
+ redis_cmd_append_sstr(&cmdstr, unit, unitlen);
+
+ /* Append sort if it's not GEO_NONE */
+ if (gopts.sort == SORT_ASC) {
+ REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "ASC");
+ } else if (gopts.sort == SORT_DESC) {
+ REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "DESC");
+ }
+
+ /* Append our count if we've got one */
+ if (gopts.count) {
+ REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "COUNT");
+ redis_cmd_append_sstr_long(&cmdstr, gopts.count);
+ }
+
+ if (gopts.store == STORE_DIST) {
+ REDIS_CMD_APPEND_SSTR_STATIC(&cmdstr, "STOREDIST");
+ }
+
+ *cmd = cmdstr.c;
+ *cmd_len = cmdstr.len;
+
+ return SUCCESS;
+}
+
/* MIGRATE */
int redis_migrate_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx)
diff --git a/redis_commands.h b/redis_commands.h
index 88c66bcf..851e28b2 100644
--- a/redis_commands.h
+++ b/redis_commands.h
@@ -145,6 +145,12 @@ int redis_georadius_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
int redis_georadiusbymember_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char *kw, char **cmd, int *cmd_len, short *slot, void **ctx);
+int redis_geosearch_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
+ char **cmd, int *cmd_len, short *slot, void **ctx);
+
+int redis_geosearchstore_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
+ char **cmd, int *cmd_len, short *slot, void **ctx);
+
/* Commands which need a unique construction mechanism. This is either because
* they don't share a signature with any other command, or because there is
* specific processing we do (e.g. verifying subarguments) that make them
diff --git a/redis_legacy_arginfo.h b/redis_legacy_arginfo.h
index f1022664..9021f63c 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: 1c4a88252c8b66263f1b1d72af974ba5ce992d40 */
+ * Stub hash: c2cbe49e22cba6f23e98c1676b7769c55a6fd043 */
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis___construct, 0, 0, 0)
ZEND_ARG_INFO(0, options)
@@ -217,6 +217,23 @@ ZEND_END_ARG_INFO()
#define arginfo_class_Redis_georadiusbymember_ro arginfo_class_Redis_georadiusbymember
+ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_geosearch, 0, 0, 4)
+ ZEND_ARG_INFO(0, key)
+ ZEND_ARG_INFO(0, position)
+ ZEND_ARG_INFO(0, shape)
+ ZEND_ARG_INFO(0, unit)
+ ZEND_ARG_INFO(0, options)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_geosearchstore, 0, 0, 5)
+ ZEND_ARG_INFO(0, dst)
+ ZEND_ARG_INFO(0, src)
+ ZEND_ARG_INFO(0, position)
+ ZEND_ARG_INFO(0, shape)
+ ZEND_ARG_INFO(0, unit)
+ ZEND_ARG_INFO(0, options)
+ZEND_END_ARG_INFO()
+
#define arginfo_class_Redis_get arginfo_class_Redis__prefix
#define arginfo_class_Redis_getAuth arginfo_class_Redis___destruct
@@ -876,6 +893,8 @@ ZEND_METHOD(Redis, georadius);
ZEND_METHOD(Redis, georadius_ro);
ZEND_METHOD(Redis, georadiusbymember);
ZEND_METHOD(Redis, georadiusbymember_ro);
+ZEND_METHOD(Redis, geosearch);
+ZEND_METHOD(Redis, geosearchstore);
ZEND_METHOD(Redis, get);
ZEND_METHOD(Redis, getAuth);
ZEND_METHOD(Redis, getBit);
@@ -1099,6 +1118,8 @@ static const zend_function_entry class_Redis_methods[] = {
ZEND_ME(Redis, georadius_ro, arginfo_class_Redis_georadius_ro, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, georadiusbymember, arginfo_class_Redis_georadiusbymember, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, georadiusbymember_ro, arginfo_class_Redis_georadiusbymember_ro, ZEND_ACC_PUBLIC)
+ ZEND_ME(Redis, geosearch, arginfo_class_Redis_geosearch, ZEND_ACC_PUBLIC)
+ ZEND_ME(Redis, geosearchstore, arginfo_class_Redis_geosearchstore, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, get, arginfo_class_Redis_get, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, getAuth, arginfo_class_Redis_getAuth, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, getBit, arginfo_class_Redis_getBit, ZEND_ACC_PUBLIC)
diff --git a/tests/RedisClusterTest.php b/tests/RedisClusterTest.php
index 394d13f2..f491e92a 100644
--- a/tests/RedisClusterTest.php
+++ b/tests/RedisClusterTest.php
@@ -58,6 +58,8 @@ class Redis_Cluster_Test extends Redis_Test {
public function testzMscore() { return $this->marktestSkipped(); }
public function testZRandMember() { return $this->marktestSkipped(); }
public function testCopy() { return $this->marktestSkipped(); }
+ public function testGeoSearch() { return $this->marktestSkipped(); }
+ public function testGeoSearchStore() { 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 fa26d18e..66b51f7f 100644
--- a/tests/RedisTest.php
+++ b/tests/RedisTest.php
@@ -5875,6 +5875,34 @@ class Redis_Test extends TestSuite
$this->assertEquals(round($r1, 8), round($r2, 8));
}
+ public function testGeoSearch() {
+ if (!$this->minVersionCheck("6.2.0")) {
+ return $this->markTestSkipped();
+ }
+
+ $this->addCities('gk');
+
+ $this->assertEquals($this->redis->geosearch('gk', 'Chico', 1, 'm'), ['Chico']);
+ $this->assertValidate($this->redis->geosearch('gk', 'Chico', 1, 'm', ['withcoord', 'withdist', 'withhash']), function ($v) {
+ $this->assertArrayKey($v, 'Chico', 'is_array');
+ $this->assertEquals(count($v['Chico']), 3);
+ $this->assertArrayKey($v['Chico'], 0, 'is_float');
+ $this->assertArrayKey($v['Chico'], 1, 'is_int');
+ $this->assertArrayKey($v['Chico'], 2, 'is_array');
+ return true;
+ });
+ }
+
+ public function testGeoSearchStore() {
+ if (!$this->minVersionCheck("6.2.0")) {
+ return $this->markTestSkipped();
+ }
+
+ $this->addCities('gk');
+ $this->assertEquals($this->redis->geosearchstore('{gk}', 'gk', 'Chico', 100, 'km'), 3);
+ $this->assertEquals($this->redis->geosearch('{gk}', 'Chico', 1, 'm'), ['Chico']);
+ }
+
/* Test a 'raw' command */
public function testRawCommand() {
$this->redis->set('mykey','some-value');