Implement DELEX command

This commit is contained in:
michael-grunder
2025-11-05 16:43:30 -08:00
committed by Michael Grunder
parent e2dd13ce7b
commit 00c62de277
11 changed files with 170 additions and 21 deletions
+4
View File
@@ -989,6 +989,10 @@ PHP_METHOD(Redis, del) {
}
/* }}} */
PHP_METHOD(Redis, delex) {
REDIS_PROCESS_CMD(delex, redis_long_response);
}
PHP_METHOD(Redis, delifeq) {
REDIS_PROCESS_KW_CMD("DELIFEQ", redis_kv_cmd, redis_long_response);
}
+10
View File
@@ -1009,6 +1009,16 @@ class Redis {
*/
public function del(array|string $key, string ...$other_keys): Redis|int|false;
/**
* Delete a key conditionally based on its value or hash digest
*
* @param string $key The key to delete
* @param array|null $options An array with options to modify how DELX works.
*
* @return Redis|int|false Returns 1 if the key was deleted, 0 if it was not.
*/
public function delex(string $key, ?array $options = null): Redis|int|false;
/**
* Delete a key if it's equal to the specified value. This command is
* specific to Valkey >= 9.0
+8 -1
View File
@@ -1,5 +1,5 @@
/* This is a generated file, edit the .stub.php file instead.
* Stub hash: 6d3e032dd0579e635f9479bf2b5ccde5e990ba97 */
* Stub hash: 971f78fe271baaeb6a5835b2bd645c18df9be7e2 */
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis___construct, 0, 0, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_ARRAY, 1, "null")
@@ -177,6 +177,11 @@ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_del, 0, 1, Redis
ZEND_ARG_VARIADIC_TYPE_INFO(0, other_keys, IS_STRING, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_Redis_delex, 0, 1, Redis, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_ARRAY, 1, "null")
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_delifeq arginfo_class_Redis_append
#define arginfo_class_Redis_delete arginfo_class_Redis_del
@@ -1343,6 +1348,7 @@ ZEND_METHOD(Redis, debug);
ZEND_METHOD(Redis, decr);
ZEND_METHOD(Redis, decrBy);
ZEND_METHOD(Redis, del);
ZEND_METHOD(Redis, delex);
ZEND_METHOD(Redis, delifeq);
ZEND_METHOD(Redis, discard);
ZEND_METHOD(Redis, dump);
@@ -1631,6 +1637,7 @@ static const zend_function_entry class_Redis_methods[] = {
ZEND_ME(Redis, decr, arginfo_class_Redis_decr, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, decrBy, arginfo_class_Redis_decrBy, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, del, arginfo_class_Redis_del, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, delex, arginfo_class_Redis_delex, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, delifeq, arginfo_class_Redis_delifeq, ZEND_ACC_PUBLIC)
#if (PHP_VERSION_ID >= 80400)
ZEND_RAW_FENTRY("delete", zim_Redis_del, arginfo_class_Redis_delete, ZEND_ACC_PUBLIC|ZEND_ACC_DEPRECATED, NULL, NULL)
+5 -1
View File
@@ -798,7 +798,11 @@ static void cluster_generic_delete(INTERNAL_FUNCTION_PARAMETERS,
/* {{{ proto array RedisCluster::del(string key1, string key2, ... keyN) */
PHP_METHOD(RedisCluster, del) {
cluster_generic_delete(INTERNAL_FUNCTION_PARAM_PASSTHRU, "DEL", sizeof("DEL") - 1);
cluster_generic_delete(INTERNAL_FUNCTION_PARAM_PASSTHRU, ZEND_STRL("DEL"));
}
PHP_METHOD(RedisCluster, delex) {
CLUSTER_PROCESS_CMD(delex, cluster_long_resp, 0);
}
PHP_METHOD(RedisCluster, delifeq) {
+10
View File
@@ -268,6 +268,16 @@ class RedisCluster {
*/
public function del(array|string $key, string ...$other_keys): RedisCluster|int|false;
/**
* Delete a key conditionally based on its value or hash digest
*
* @param string $key The key to delete
* @param array|null $options An array with options to modify how DELX works.
*
* @return RedisCluster|int|false Returns 1 if the key was deleted, 0 if it was not.
*/
public function delex(string $key, ?array $options = null): RedisCluster|int|false;
/**
* Delete a key if it's equal to the specified value. This command is
* specific to Valkey >= 9.0
+8 -1
View File
@@ -1,5 +1,5 @@
/* This is a generated file, edit the .stub.php file instead.
* Stub hash: 22ead9142161a92426bf27f80bb6334fd95f8680 */
* Stub hash: 76e57d541155478d414e8cfe84d56f6d07ec6e3d */
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster___construct, 0, 0, 1)
ZEND_ARG_TYPE_INFO(0, name, IS_STRING, 1)
@@ -206,6 +206,11 @@ ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_del, 0, 1
ZEND_ARG_VARIADIC_TYPE_INFO(0, other_keys, IS_STRING, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_delex, 0, 1, RedisCluster, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, options, IS_ARRAY, 1, "null")
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_TYPE_MASK_EX(arginfo_class_RedisCluster_delifeq, 0, 2, RedisCluster, MAY_BE_LONG|MAY_BE_FALSE)
ZEND_ARG_TYPE_INFO(0, key, IS_STRING, 0)
ZEND_ARG_TYPE_INFO(0, value, IS_MIXED, 0)
@@ -1234,6 +1239,7 @@ ZEND_METHOD(RedisCluster, decr);
ZEND_METHOD(RedisCluster, decrby);
ZEND_METHOD(RedisCluster, decrbyfloat);
ZEND_METHOD(RedisCluster, del);
ZEND_METHOD(RedisCluster, delex);
ZEND_METHOD(RedisCluster, delifeq);
ZEND_METHOD(RedisCluster, discard);
ZEND_METHOD(RedisCluster, dump);
@@ -1494,6 +1500,7 @@ static const zend_function_entry class_RedisCluster_methods[] = {
ZEND_ME(RedisCluster, decrby, arginfo_class_RedisCluster_decrby, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, decrbyfloat, arginfo_class_RedisCluster_decrbyfloat, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, del, arginfo_class_RedisCluster_del, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, delex, arginfo_class_RedisCluster_delex, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, delifeq, arginfo_class_RedisCluster_delifeq, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, discard, arginfo_class_RedisCluster_discard, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, dump, arginfo_class_RedisCluster_dump, ZEND_ACC_PUBLIC)
+13 -9
View File
@@ -1,5 +1,5 @@
/* This is a generated file, edit the .stub.php file instead.
* Stub hash: 22ead9142161a92426bf27f80bb6334fd95f8680 */
* Stub hash: 76e57d541155478d414e8cfe84d56f6d07ec6e3d */
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster___construct, 0, 0, 1)
ZEND_ARG_INFO(0, name)
@@ -186,6 +186,11 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_del, 0, 0, 1)
ZEND_ARG_VARIADIC_INFO(0, other_keys)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_delex, 0, 0, 1)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, options)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_delifeq arginfo_class_RedisCluster_append
#define arginfo_class_RedisCluster_discard arginfo_class_RedisCluster__masters
@@ -309,10 +314,7 @@ ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_getWithMeta arginfo_class_RedisCluster__prefix
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_getex, 0, 0, 1)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, options)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_getex arginfo_class_RedisCluster_delex
#define arginfo_class_RedisCluster_getbit arginfo_class_RedisCluster_append
@@ -410,7 +412,7 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_expirememberat, 0, 0, 3)
ZEND_ARG_INFO(0, timestamp)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_hrandfield arginfo_class_RedisCluster_getex
#define arginfo_class_RedisCluster_hrandfield arginfo_class_RedisCluster_delex
#define arginfo_class_RedisCluster_hset arginfo_class_RedisCluster_hincrby
@@ -713,9 +715,9 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_smove, 0, 0, 3)
ZEND_ARG_INFO(0, member)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_sort arginfo_class_RedisCluster_getex
#define arginfo_class_RedisCluster_sort arginfo_class_RedisCluster_delex
#define arginfo_class_RedisCluster_sort_ro arginfo_class_RedisCluster_getex
#define arginfo_class_RedisCluster_sort_ro arginfo_class_RedisCluster_delex
#define arginfo_class_RedisCluster_spop arginfo_class_RedisCluster_lpop
@@ -957,7 +959,7 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_zrangestore, 0, 0, 4)
ZEND_ARG_INFO(0, options)
ZEND_END_ARG_INFO()
#define arginfo_class_RedisCluster_zrandmember arginfo_class_RedisCluster_getex
#define arginfo_class_RedisCluster_zrandmember arginfo_class_RedisCluster_delex
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_RedisCluster_zrangebylex, 0, 0, 3)
ZEND_ARG_INFO(0, key)
@@ -1063,6 +1065,7 @@ ZEND_METHOD(RedisCluster, decr);
ZEND_METHOD(RedisCluster, decrby);
ZEND_METHOD(RedisCluster, decrbyfloat);
ZEND_METHOD(RedisCluster, del);
ZEND_METHOD(RedisCluster, delex);
ZEND_METHOD(RedisCluster, delifeq);
ZEND_METHOD(RedisCluster, discard);
ZEND_METHOD(RedisCluster, dump);
@@ -1323,6 +1326,7 @@ static const zend_function_entry class_RedisCluster_methods[] = {
ZEND_ME(RedisCluster, decrby, arginfo_class_RedisCluster_decrby, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, decrbyfloat, arginfo_class_RedisCluster_decrbyfloat, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, del, arginfo_class_RedisCluster_del, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, delex, arginfo_class_RedisCluster_delex, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, delifeq, arginfo_class_RedisCluster_delifeq, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, discard, arginfo_class_RedisCluster_discard, ZEND_ACC_PUBLIC)
ZEND_ME(RedisCluster, dump, arginfo_class_RedisCluster_dump, ZEND_ACC_PUBLIC)
+71
View File
@@ -2642,6 +2642,77 @@ int redis_decr_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
TYPE_DECR, redis_sock, cmd, cmd_len, slot, ctx);
}
typedef enum delExType {
REDIS_DELEX_NONE,
REDIS_DELEX_IFEQ,
REDIS_DELEX_IFNE,
REDIS_DELEX_IFDEQ,
REDIS_DELEX_IFDNE
} delExType;
static zend_bool stringToDelExType(delExType *dst, zend_string *src) {
*dst = REDIS_DELEX_NONE;
if (zend_string_equals_literal_ci(src, "IFEQ")) {
*dst = REDIS_DELEX_IFEQ;
} else if (zend_string_equals_literal_ci(src, "IFNE")) {
*dst = REDIS_DELEX_IFNE;
} else if (zend_string_equals_literal_ci(src, "IFDEQ")) {
*dst = REDIS_DELEX_IFDEQ;
} else if (zend_string_equals_literal_ci(src, "IFDNE")) {
*dst = REDIS_DELEX_IFDNE;
} else {
return 0;
}
return 1;
}
int redis_delex_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx)
{
delExType type = REDIS_DELEX_NONE;
smart_string cmdstr = {0};
zend_string *key, *ztype;;
HashTable *ht = NULL;
zval *zv = NULL;
zend_bool pack;
ZEND_PARSE_PARAMETERS_START(1, 2)
Z_PARAM_STR(key)
Z_PARAM_OPTIONAL
Z_PARAM_ARRAY_HT_OR_NULL(ht)
ZEND_PARSE_PARAMETERS_END_EX(return FAILURE);
if (ht != NULL) {
ZEND_HASH_FOREACH_STR_KEY_VAL(ht, ztype, zv) {
if (ztype == NULL)
continue;
ZVAL_DEREF(zv);
if (stringToDelExType(&type, ztype))
break;
php_error_docref(NULL, E_WARNING, "Unknown option '%s'", ZSTR_VAL(ztype));
} ZEND_HASH_FOREACH_END();
}
REDIS_CMD_INIT_SSTR_STATIC(&cmdstr, type != REDIS_DELEX_NONE ? 3 : 1, "DELEX");
redis_cmd_append_sstr_key_zstr(&cmdstr, key, redis_sock, slot);
if (type != REDIS_DELEX_NONE) {
redis_cmd_append_sstr_zstr(&cmdstr, ztype);
pack = type == REDIS_DELEX_IFEQ || type == REDIS_DELEX_IFNE;
redis_cmd_append_sstr_zval(&cmdstr, zv, pack ? redis_sock : NULL);
}
*cmd = cmdstr.c;
*cmd_len = cmdstr.len;
return SUCCESS;
}
/* HINCRBY */
int redis_hincrby_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx)
+3
View File
@@ -238,6 +238,9 @@ int redis_incr_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
int redis_decr_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_delex_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx);
int redis_hincrby_cmd(INTERNAL_FUNCTION_PARAMETERS, RedisSock *redis_sock,
char **cmd, int *cmd_len, short *slot, void **ctx);
+13 -9
View File
@@ -1,5 +1,5 @@
/* This is a generated file, edit the .stub.php file instead.
* Stub hash: 6d3e032dd0579e635f9479bf2b5ccde5e990ba97 */
* Stub hash: 971f78fe271baaeb6a5835b2bd645c18df9be7e2 */
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis___construct, 0, 0, 0)
ZEND_ARG_INFO(0, options)
@@ -165,6 +165,11 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_del, 0, 0, 1)
ZEND_ARG_VARIADIC_INFO(0, other_keys)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_delex, 0, 0, 1)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, options)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_delifeq arginfo_class_Redis_append
#define arginfo_class_Redis_delete arginfo_class_Redis_del
@@ -314,10 +319,7 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_getBit, 0, 0, 2)
ZEND_ARG_INFO(0, idx)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_getEx, 0, 0, 1)
ZEND_ARG_INFO(0, key)
ZEND_ARG_INFO(0, options)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_getEx arginfo_class_Redis_delex
#define arginfo_class_Redis_getDBNum arginfo_class_Redis___destruct
@@ -415,7 +417,7 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_hMset, 0, 0, 2)
ZEND_ARG_INFO(0, fieldvals)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_hRandField arginfo_class_Redis_getEx
#define arginfo_class_Redis_hRandField arginfo_class_Redis_delex
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_hSet, 0, 0, 1)
ZEND_ARG_INFO(0, key)
@@ -793,9 +795,9 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_slowlog, 0, 0, 1)
ZEND_ARG_INFO(0, length)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_sort arginfo_class_Redis_getEx
#define arginfo_class_Redis_sort arginfo_class_Redis_delex
#define arginfo_class_Redis_sort_ro arginfo_class_Redis_getEx
#define arginfo_class_Redis_sort_ro arginfo_class_Redis_delex
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_sortAsc, 0, 0, 1)
ZEND_ARG_INFO(0, key)
@@ -1064,7 +1066,7 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_class_Redis_zrangestore, 0, 0, 4)
ZEND_ARG_INFO(0, options)
ZEND_END_ARG_INFO()
#define arginfo_class_Redis_zRandMember arginfo_class_Redis_getEx
#define arginfo_class_Redis_zRandMember arginfo_class_Redis_delex
#define arginfo_class_Redis_zRank arginfo_class_Redis_hGet
@@ -1175,6 +1177,7 @@ ZEND_METHOD(Redis, debug);
ZEND_METHOD(Redis, decr);
ZEND_METHOD(Redis, decrBy);
ZEND_METHOD(Redis, del);
ZEND_METHOD(Redis, delex);
ZEND_METHOD(Redis, delifeq);
ZEND_METHOD(Redis, discard);
ZEND_METHOD(Redis, dump);
@@ -1463,6 +1466,7 @@ static const zend_function_entry class_Redis_methods[] = {
ZEND_ME(Redis, decr, arginfo_class_Redis_decr, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, decrBy, arginfo_class_Redis_decrBy, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, del, arginfo_class_Redis_del, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, delex, arginfo_class_Redis_delex, ZEND_ACC_PUBLIC)
ZEND_ME(Redis, delifeq, arginfo_class_Redis_delifeq, ZEND_ACC_PUBLIC)
#if (PHP_VERSION_ID >= 80400)
ZEND_RAW_FENTRY("delete", zim_Redis_del, arginfo_class_Redis_delete, ZEND_ACC_PUBLIC|ZEND_ACC_DEPRECATED, NULL, NULL)
+25
View File
@@ -8706,5 +8706,30 @@ class Redis_Test extends TestSuite {
$this->redis->setOption(Redis::OPT_SERIALIZER, Redis::SERIALIZER_NONE);
}
}
public function testDelEx() {
if ( ! $this->haveCommand('DELEX'))
$this->markTestSkipped();
$this->assertIsInt($this->redis->del('captain'));
$this->assertTrue($this->redis->set('captain', 'picard'));
$this->assertEquals(0, $this->redis->delex('captain', ['ifeq' => 'not-picard']));
$this->assertEquals(0, $this->redis->delex('captain', ['ifne' => 'picard']));
$this->assertEquals(1, $this->redis->delex('captain', ['ifeq' => 'picard']));
$this->assertTrue($this->redis->set('captain', 'Sisko'));
$digest = $this->redis->digest('captain');
$this->assertEquals(0, $this->redis->delex('captain', ['ifdne' => $digest]));
$this->assertEquals(1, $this->redis->delex('captain', ['ifdeq' => $digest]));
$this->assertTrue($this->redis->set('captain', 'Janeway'));
$this->assertEquals(1, $this->redis->delex('captain'));
foreach ([[], null] as $arg) {
$this->assertTrue($this->redis->set('captain', 'Archer'));
$this->assertEquals(1, $this->redis->delex('captain', $arg));
}
}
}
?>