From e5b5947d517b2b6ef9f08edbcfa0e5f16ce42f19 Mon Sep 17 00:00:00 2001 From: Ryan Joseph Date: Wed, 21 Aug 2019 18:11:18 -0700 Subject: [PATCH] List commands (phase one) v0.4.0 * add Redis_LPUSH as a macro (for now) * add LPUSHX & LPOP * add LINDEX & LINSERT --- src/commands.c | 24 +++++++++++++++++++++++- src/commands.h | 17 +++++++++++++++++ src/types.h | 8 ++++++++ src/yarl.h | 2 +- test/test.c | 37 +++++++++++++++++++++++-------------- 5 files changed, 72 insertions(+), 16 deletions(-) diff --git a/src/commands.c b/src/commands.c index 265c7b1..1d77135 100644 --- a/src/commands.c +++ b/src/commands.c @@ -4,7 +4,6 @@ #include "resp.h" #include "log.h" -#include #include #include #include @@ -157,3 +156,26 @@ void Redis_PSUBSCRIBE(RedisConnection_t conn, const char *pattern) { _RedisCommand_issue(conn, "PSUBSCRIBE", 1, 0, pattern); } + +int Redis_LPUSHX(RedisConnection_t conn, const char *key, const char* value) +{ + return _RedisCommandReturn_extractInt(_RedisCommand_issue(conn, "LPUSHX", 2, 0, key, value)); +} + +char* Redis_LPOP(RedisConnection_t conn, const char* key) +{ + REDIS_CMD__GENERIC(RedisObjectType_BulkString, conn, "LPOP", 1, 0, (char *)cmdRet.obj, NULL, false, key); +} + +char *Redis_LINDEX(RedisConnection_t conn, const char* key, int index) +{ + REDIS_CMD__GENERIC(RedisObjectType_BulkString, conn, "LINDEX", 2, 0x2, + (char *)cmdRet.obj, NULL, false, key, _RedisObject_RESP__intAsStringWithLength(index, NULL)); +} + +int Redis_LINSERT(RedisConnection_t conn, const char* key, RedisLINSERTPivot_t pivotPoint, const char* pivot, const char* value) +{ + assert(pivotPoint > PivotInvalid && pivotPoint < PivotLastSentinel); + const char* pivotStr = pivotPoint == PivotBefore ? "BEFORE" : "AFTER"; + return _RedisCommandReturn_extractInt(_RedisCommand_issue(conn, "LINSERT", 4, 0, key, pivotStr, pivot, value)); +} \ No newline at end of file diff --git a/src/commands.h b/src/commands.h index b9902bf..0ef7bb9 100644 --- a/src/commands.h +++ b/src/commands.h @@ -5,6 +5,7 @@ #include "constants.h" #include +#include // any non-scalar return values are OWNED BY THE CALLER and must be free()ed @@ -28,8 +29,24 @@ bool Redis_EXPIRE(RedisConnection_t conn, const char *key, int seconds); bool Redis_EXPIREAT(RedisConnection_t conn, const char *key, int timestamp); +// int Redis_LPUSH(RedisConnection_t conn, const char *key, uint32_t argCount, ...) +#define Redis_LPUSH(conn, key, argCount, ...) \ + _RedisCommandReturn_extractInt(_RedisCommand_issue((conn), "LPUSH", (argCount) + 1, 0x0, (key), __VA_ARGS__)) + +int Redis_LPUSHX(RedisConnection_t conn, const char *key, const char* value); + +char* Redis_LPOP(RedisConnection_t conn, const char* key); + +char* Redis_LINDEX(RedisConnection_t conn, const char* key, int index); + +int Redis_LINSERT(RedisConnection_t conn, const char* key, RedisLINSERTPivot_t pivotPoint, const char* pivot, const char* value); + // use RedisConnection_getNextObject() to get messages void Redis_SUBSCRIBE(RedisConnection_t conn, const char *channel); void Redis_PSUBSCRIBE(RedisConnection_t conn, const char *pattern); +// for Redis_LPUSH as currently (macro) defined +extern RedisObject_t _RedisCommand_issue(RedisConnection_t, const char *, uint32_t, uint32_t, ...); +extern int _RedisCommandReturn_extractInt(RedisObject_t); + #endif // __YARL_COMMANDS__H__ diff --git a/src/types.h b/src/types.h index 5fd1209..ae7f1ad 100644 --- a/src/types.h +++ b/src/types.h @@ -20,4 +20,12 @@ typedef struct RedisArray_t RedisObject_t *objects; } RedisArray_t; +typedef enum +{ + PivotInvalid = -1, + PivotBefore, + PivotAfter, + PivotLastSentinel +} RedisLINSERTPivot_t; + #endif // __YARL_TYPES__H__ \ No newline at end of file diff --git a/src/yarl.h b/src/yarl.h index 99eea53..ed346f4 100644 --- a/src/yarl.h +++ b/src/yarl.h @@ -5,7 +5,7 @@ extern "C" { #endif -#define YARL_VERSION "0.3.1" +#define YARL_VERSION "0.4.0" #include "commands.h" #include "constants.h" diff --git a/test/test.c b/test/test.c index 5c22d2e..f24580c 100644 --- a/test/test.c +++ b/test/test.c @@ -127,11 +127,7 @@ int main(int argc, char **argv) printf("Appended %d bytes, now have '%s'\n", appended, getVal); free(getVal); - if (!Redis_DEL(rConn, TEST_KEY_NAME)) - { - fprintf(stderr, "DEL failed\n"); - exit(-2); - } + assert(Redis_DEL(rConn, TEST_KEY_NAME)); printf("Publish result: %d\n", Redis_PUBLISH(rConn, TEST_KEY_NAME, "Pub/sub is the bee's knees!")); @@ -139,9 +135,7 @@ int main(int argc, char **argv) if (allKeys) { - printf("Found %lu keys:\n", allKeys->count); - for (int i = 0; i < allKeys->count; i++) - printf("\t%s\n", (char *)allKeys->objects[i].obj); + printf("Found %lu keys\n", allKeys->count); RedisArray_dealloc(allKeys); } else @@ -150,10 +144,25 @@ int main(int argc, char **argv) exit(-1); } - if (!Redis_SET(rConn, TEST_KEY_NAME "ButWillExpireInSixty", "60...") || - !Redis_EXPIRE(rConn, TEST_KEY_NAME "ButWillExpireInSixty", 60)) - { - fprintf(stderr, "EXPIRE failed\n"); - exit(-2); - } + assert(Redis_SET(rConn, TEST_KEY_NAME "ButWillExpireInSixty", "60...") && + Redis_EXPIRE(rConn, TEST_KEY_NAME "ButWillExpireInSixty", 60)); + + char* lName = TEST_KEY_NAME "Listicle"; + assert(Redis_LPUSH(rConn, lName, 3, "foo", "bar", "baz") == 3); + assert(Redis_LPUSHX(rConn, lName, "LPUSHX") == 4); + + char* popped = Redis_LPOP(rConn, lName); + assert(!strncmp(popped, "LPUSHX", strlen("LPUSHX"))); + free(popped); + + assert(!Redis_LPUSHX(rConn, TEST_KEY_NAME "DNE", "LPUSHX")); + + char* lidx = Redis_LINDEX(rConn, lName, 2); + assert(!strncmp(lidx, "foo", strlen("foo"))); + + assert(Redis_LINSERT(rConn, lName, PivotBefore, "bar", "before_bar") == 4 && + Redis_LINSERT(rConn, lName, PivotAfter, "bar", "after_bar") == 5); + + Redis_DEL(rConn, lName); + printf("List tests successful.\n"); }