mirror of
https://github.com/redis/redis.git
synced 2026-02-03 20:39:54 -05:00
Merge 65db598134 into b5a37c0e42
This commit is contained in:
commit
fb09662794
6 changed files with 239 additions and 0 deletions
|
|
@ -41,6 +41,7 @@ $TCLSH tests/test_helper.tcl \
|
|||
--single unit/moduleapi/zset \
|
||||
--single unit/moduleapi/list \
|
||||
--single unit/moduleapi/stream \
|
||||
--single unit/moduleapi/set \
|
||||
--single unit/moduleapi/mallocsize \
|
||||
--single unit/moduleapi/datatype2 \
|
||||
--single unit/moduleapi/cluster \
|
||||
|
|
|
|||
111
src/module.c
111
src/module.c
|
|
@ -715,6 +715,9 @@ int moduleCreateEmptyKey(RedisModuleKey *key, int type) {
|
|||
case REDISMODULE_KEYTYPE_STREAM:
|
||||
obj = createStreamObject();
|
||||
break;
|
||||
case REDISMODULE_KEYTYPE_SET:
|
||||
obj = createSetObject();
|
||||
break;
|
||||
default: return REDISMODULE_ERR;
|
||||
}
|
||||
|
||||
|
|
@ -15152,6 +15155,111 @@ int RM_GetDbIdFromDefragCtx(RedisModuleDefragCtx *ctx) {
|
|||
return ctx->dbid;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
* ## Key API for Set type
|
||||
*
|
||||
* See also RM_ValueLength(), which returns the cardinality of a set.
|
||||
* -------------------------------------------------------------------------- */
|
||||
|
||||
/* Add new elements into a set.
|
||||
*
|
||||
* Returns REDISMODULE_OK if elements have been added successfully.
|
||||
* On failure, REDISMODULE_ERR is returned and `errno` is set as follows:
|
||||
*
|
||||
* - EBADF if the key was not opened for writing
|
||||
* - ENOTSUP if the key is of another type than set.
|
||||
*
|
||||
* In order to know the number of elements were added, the additional argument
|
||||
* 'added' must be passed, that populates the integer by reference
|
||||
* setting it to the number of elements added depending on the outcome of the operation.
|
||||
* The 'added' argument can be NULL if the caller is not interested
|
||||
* to know if the number of elements were really added.
|
||||
*
|
||||
* Empty keys will be created with set key type and continue. */
|
||||
int RM_SetAdd(RedisModuleKey *key, RedisModuleString **elements, size_t numeles, size_t *added) {
|
||||
if (!(key->mode & REDISMODULE_WRITE)) {
|
||||
errno = EBADF;
|
||||
return REDISMODULE_ERR;
|
||||
}
|
||||
if (key->value && key->value->type != OBJ_SET) {
|
||||
errno = ENOTSUP;
|
||||
return REDISMODULE_ERR;
|
||||
}
|
||||
if (key->value == NULL) moduleCreateEmptyKey(key,REDISMODULE_KEYTYPE_SET);
|
||||
size_t i, numadded = 0;
|
||||
for (i = 0; i < numeles; i++) {
|
||||
numadded += setTypeAdd(key->value,elements[i]->ptr);
|
||||
}
|
||||
if (added) *added = numadded;
|
||||
|
||||
return REDISMODULE_OK;
|
||||
}
|
||||
|
||||
/* Remove the specified element from the set and the key will be
|
||||
* removed if has no any element in after remove elements operation.
|
||||
*
|
||||
* Returns REDISMODULE_OK on success. On failure, REDISMODULE_ERR is returned
|
||||
* and `errno` is set as follows:
|
||||
*
|
||||
* - EINVAL if called with invalid arguments
|
||||
* - ENOTSUP if the key refers to a value of a type other than set
|
||||
* - EBADF if the key was not opened for writing
|
||||
*
|
||||
* Key will be removed if has no any element in after remove elements operation
|
||||
*
|
||||
* The return value does NOT indicate the fact the element was really
|
||||
* removed (since it existed) or not, just if the function was executed
|
||||
* with success.
|
||||
*
|
||||
* In order to know the number of elements were removed, the additional argument
|
||||
* 'deleted' must be passed, that populates the integer by reference
|
||||
* setting it to the number of elements removed depending on the outcome of the operation.
|
||||
* The 'deleted' argument can be NULL if the caller is not interested
|
||||
* to know if the number of elements were really removed.
|
||||
*
|
||||
* Empty keys will be handled correctly by doing nothing. */
|
||||
int RM_SetRem(RedisModuleKey *key, RedisModuleString **elements, size_t numeles, size_t *deleted) {
|
||||
size_t numdeleted = 0;
|
||||
if (!key) {
|
||||
errno = EINVAL;
|
||||
return REDISMODULE_ERR;
|
||||
} else if (!key->value) {
|
||||
/*return 0 for empty key*/
|
||||
if (deleted) *deleted = numdeleted;
|
||||
return REDISMODULE_OK;
|
||||
} else if (key->value->type != OBJ_SET) {
|
||||
errno = ENOTSUP; /* wrong type */
|
||||
return REDISMODULE_ERR;
|
||||
} else if (!(key->mode & REDISMODULE_WRITE)) {
|
||||
errno = EBADF; /* key not opened for writing */
|
||||
return REDISMODULE_ERR;
|
||||
}
|
||||
for (size_t i = 0; i < numeles; i++) {
|
||||
numdeleted += setTypeRemove(key->value,elements[i]->ptr);
|
||||
if (moduleDelKeyIfEmpty(key)) break;
|
||||
}
|
||||
if (deleted) *deleted = numdeleted;
|
||||
return REDISMODULE_OK;
|
||||
}
|
||||
|
||||
/* Query if member is a member of the set stored at key
|
||||
*
|
||||
* Returns 0 if member is not a member of the set stored at key.
|
||||
* Returns 1 if member is a member of the set stored at key.
|
||||
* On failure, -1 is returned and `errno` is set as follows:
|
||||
*
|
||||
* - ENOTSUP if the key refers to a value of a type other than set */
|
||||
int RM_SetIsMember(RedisModuleKey *key, RedisModuleString *ele) {
|
||||
if (!key || !key->value) {
|
||||
/* return 0 for empty key */
|
||||
return 0;
|
||||
} else if (key->value->type != OBJ_SET) {
|
||||
errno = ENOTSUP; /* wrong type */
|
||||
return -1;
|
||||
}
|
||||
return setTypeIsMember(key->value,ele->ptr);
|
||||
}
|
||||
|
||||
/* Register all the APIs we export. Keep this function at the end of the
|
||||
* file so that's easy to seek it to add new entries. */
|
||||
void moduleRegisterCoreAPI(void) {
|
||||
|
|
@ -15292,6 +15400,9 @@ void moduleRegisterCoreAPI(void) {
|
|||
REGISTER_API(StreamIteratorDelete);
|
||||
REGISTER_API(StreamTrimByLength);
|
||||
REGISTER_API(StreamTrimByID);
|
||||
REGISTER_API(SetAdd);
|
||||
REGISTER_API(SetRem);
|
||||
REGISTER_API(SetIsMember);
|
||||
REGISTER_API(IsKeysPositionRequest);
|
||||
REGISTER_API(KeyAtPos);
|
||||
REGISTER_API(KeyAtPosWithFlags);
|
||||
|
|
|
|||
|
|
@ -1212,6 +1212,9 @@ REDISMODULE_API int (*RedisModule_StreamIteratorNextField)(RedisModuleKey *key,
|
|||
REDISMODULE_API int (*RedisModule_StreamIteratorDelete)(RedisModuleKey *key) REDISMODULE_ATTR;
|
||||
REDISMODULE_API long long (*RedisModule_StreamTrimByLength)(RedisModuleKey *key, int flags, long long length) REDISMODULE_ATTR;
|
||||
REDISMODULE_API long long (*RedisModule_StreamTrimByID)(RedisModuleKey *key, int flags, RedisModuleStreamID *id) REDISMODULE_ATTR;
|
||||
REDISMODULE_API int (*RedisModule_SetAdd)(RedisModuleKey *key, RedisModuleString **elements, int numeles, size_t *added) REDISMODULE_ATTR;
|
||||
REDISMODULE_API int (*RedisModule_SetRem)(RedisModuleKey *key, RedisModuleString **elements, int numeles, size_t *deleted) REDISMODULE_ATTR;
|
||||
REDISMODULE_API int (*RedisModule_SetIsMember)(RedisModuleKey *key, RedisModuleString *ele) REDISMODULE_ATTR;
|
||||
REDISMODULE_API int (*RedisModule_IsKeysPositionRequest)(RedisModuleCtx *ctx) REDISMODULE_ATTR;
|
||||
REDISMODULE_API void (*RedisModule_KeyAtPos)(RedisModuleCtx *ctx, int pos) REDISMODULE_ATTR;
|
||||
REDISMODULE_API void (*RedisModule_KeyAtPosWithFlags)(RedisModuleCtx *ctx, int pos, int flags) REDISMODULE_ATTR;
|
||||
|
|
@ -1611,6 +1614,9 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int
|
|||
REDISMODULE_GET_API(StreamIteratorDelete);
|
||||
REDISMODULE_GET_API(StreamTrimByLength);
|
||||
REDISMODULE_GET_API(StreamTrimByID);
|
||||
REDISMODULE_GET_API(SetAdd);
|
||||
REDISMODULE_GET_API(SetRem);
|
||||
REDISMODULE_GET_API(SetIsMember);
|
||||
REDISMODULE_GET_API(IsKeysPositionRequest);
|
||||
REDISMODULE_GET_API(KeyAtPos);
|
||||
REDISMODULE_GET_API(KeyAtPosWithFlags);
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@ TEST_MODULES = \
|
|||
hash.so \
|
||||
zset.so \
|
||||
stream.so \
|
||||
set.so \
|
||||
mallocsize.so \
|
||||
aclcheck.so \
|
||||
list.so \
|
||||
|
|
|
|||
79
tests/modules/set.c
Normal file
79
tests/modules/set.c
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
#include "redismodule.h"
|
||||
#include <math.h>
|
||||
#include <errno.h>
|
||||
|
||||
/* SET.REM key element [element ...]
|
||||
*
|
||||
* Removes elements from a set. Replies with the
|
||||
* number of removed elements.
|
||||
*/
|
||||
int set_rem(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
|
||||
if (argc < 3) return RedisModule_WrongArity(ctx);
|
||||
RedisModule_AutoMemory(ctx);
|
||||
int keymode = REDISMODULE_READ | REDISMODULE_WRITE;
|
||||
RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1], keymode);
|
||||
size_t deleted;
|
||||
if (RedisModule_SetRem(key, &argv[2], argc-2, &deleted) == REDISMODULE_OK) {
|
||||
RedisModule_ReplyWithLongLong(ctx, deleted);
|
||||
} else {
|
||||
RedisModule_ReplyWithError(ctx, "ERR SetRem failed");
|
||||
}
|
||||
RedisModule_CloseKey(key);
|
||||
return REDISMODULE_OK;
|
||||
}
|
||||
|
||||
/* SET.ADD key member [member ...]
|
||||
*
|
||||
* Adds members to the set stored at key. Replies with the
|
||||
* number of added elements.
|
||||
*/
|
||||
int set_add(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
|
||||
if (argc < 3) return RedisModule_WrongArity(ctx);
|
||||
RedisModule_AutoMemory(ctx);
|
||||
int keymode = REDISMODULE_READ | REDISMODULE_WRITE;
|
||||
RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1], keymode);
|
||||
size_t added;
|
||||
if (RedisModule_SetAdd(key, &argv[2], argc-2, &added) == REDISMODULE_OK) {
|
||||
RedisModule_ReplyWithLongLong(ctx, added);
|
||||
} else {
|
||||
RedisModule_ReplyWithError(ctx, "ERR SetAdd failed");
|
||||
}
|
||||
RedisModule_CloseKey(key);
|
||||
return REDISMODULE_OK;
|
||||
}
|
||||
|
||||
/* SET.ISMEMBER key member
|
||||
*
|
||||
* Is member of the set stored at key. Replies with 1 as member of the key
|
||||
* or 0 as not member of the key
|
||||
*/
|
||||
int set_ismember(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
|
||||
if (argc != 3) return RedisModule_WrongArity(ctx);
|
||||
RedisModule_AutoMemory(ctx);
|
||||
int keymode = REDISMODULE_READ;
|
||||
RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1], keymode);
|
||||
RedisModule_ReplyWithLongLong(ctx, RedisModule_SetIsMember(key, argv[2]));
|
||||
RedisModule_CloseKey(key);
|
||||
return REDISMODULE_OK;
|
||||
}
|
||||
|
||||
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
|
||||
REDISMODULE_NOT_USED(argv);
|
||||
REDISMODULE_NOT_USED(argc);
|
||||
if (RedisModule_Init(ctx, "set", 1, REDISMODULE_APIVER_1) == REDISMODULE_ERR)
|
||||
return REDISMODULE_ERR;
|
||||
|
||||
if (RedisModule_CreateCommand(ctx, "set.rem", set_rem, "write",
|
||||
1, 1, 1) == REDISMODULE_ERR)
|
||||
return REDISMODULE_ERR;
|
||||
|
||||
if (RedisModule_CreateCommand(ctx, "set.add", set_add, "write",
|
||||
1, 1, 1) == REDISMODULE_ERR)
|
||||
return REDISMODULE_ERR;
|
||||
|
||||
if (RedisModule_CreateCommand(ctx, "set.ismember", set_ismember, "readonly",
|
||||
1, 1, 1) == REDISMODULE_ERR)
|
||||
return REDISMODULE_ERR;
|
||||
|
||||
return REDISMODULE_OK;
|
||||
}
|
||||
41
tests/unit/moduleapi/set.tcl
Normal file
41
tests/unit/moduleapi/set.tcl
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
set testmodule [file normalize tests/modules/set.so]
|
||||
|
||||
start_server {tags {"modules"}} {
|
||||
r module load $testmodule
|
||||
|
||||
test {Module set add} {
|
||||
r del k
|
||||
# Check that failure does not create empty key
|
||||
assert_error "ERR wrong number of arguments for 'set.add' command" {r set.add k}
|
||||
assert_equal 0 [r exists k]
|
||||
|
||||
assert_equal 1 [r set.add k hello]
|
||||
assert_equal 1 [r set.ismember k hello]
|
||||
assert_equal 0 [r set.ismember k world]
|
||||
}
|
||||
|
||||
test {Module set rem} {
|
||||
r del k
|
||||
r sadd k hello world
|
||||
assert_equal 1 [r set.rem k hello]
|
||||
assert_equal 1 [r exists k]
|
||||
# Check that removing the last element deletes the key
|
||||
assert_equal 1 [r set.rem k world]
|
||||
assert_equal 0 [r exists k]
|
||||
# Removing element from empty key shall work.
|
||||
assert_equal 0 [r set.rem k world]
|
||||
assert_equal 0 [r exists k]
|
||||
}
|
||||
|
||||
test {Module set ismember} {
|
||||
r del k
|
||||
assert_equal 0 [r set.ismember k hello]
|
||||
assert_equal 1 [r set.add k hello]
|
||||
assert_equal 1 [r set.ismember k hello]
|
||||
assert_equal 0 [r set.ismember k world]
|
||||
|
||||
r del k
|
||||
assert_equal OK [r set k hello]
|
||||
assert_equal -1 [r set.ismember k hello]
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue