Unverified Commit 12ce2c39 authored by Shaya Potter's avatar Shaya Potter Committed by GitHub
Browse files

Add RM_ReplyWithBigNumber module API (#9639)



Let modules use additional type of RESP3 response (unused by redis so far)
Also fix tests that where introduced in #8521 but didn't actually run.
Co-authored-by: default avatarOran Agra <oran@redislabs.com>
parent c1718f9d
...@@ -43,4 +43,5 @@ $TCLSH tests/test_helper.tcl \ ...@@ -43,4 +43,5 @@ $TCLSH tests/test_helper.tcl \
--single unit/moduleapi/cluster \ --single unit/moduleapi/cluster \
--single unit/moduleapi/aclcheck \ --single unit/moduleapi/aclcheck \
--single unit/moduleapi/subcommands \ --single unit/moduleapi/subcommands \
--single unit/moduleapi/reply \
"${@}" "${@}"
...@@ -2227,7 +2227,11 @@ int RM_ReplyWithNull(RedisModuleCtx *ctx) { ...@@ -2227,7 +2227,11 @@ int RM_ReplyWithNull(RedisModuleCtx *ctx) {
return REDISMODULE_OK; return REDISMODULE_OK;
} }
/* Reply to the client with a boolean value. /* Reply with a RESP3 Boolean type.
* Visit https://github.com/antirez/RESP3/blob/master/spec.md for more info about RESP3.
*
* In RESP3, this is boolean type
* In RESP2, it's a string response of "1" and "0" for true and false respectively.
* *
* The function always returns REDISMODULE_OK. */ * The function always returns REDISMODULE_OK. */
int RM_ReplyWithBool(RedisModuleCtx *ctx, int b) { int RM_ReplyWithBool(RedisModuleCtx *ctx, int b) {
...@@ -2264,11 +2268,17 @@ int RM_ReplyWithCallReply(RedisModuleCtx *ctx, RedisModuleCallReply *reply) { ...@@ -2264,11 +2268,17 @@ int RM_ReplyWithCallReply(RedisModuleCtx *ctx, RedisModuleCallReply *reply) {
return REDISMODULE_OK; return REDISMODULE_OK;
} }
/* Send a string reply obtained converting the double 'd' into a bulk string. /* Reply with a RESP3 Double type.
* Visit https://github.com/antirez/RESP3/blob/master/spec.md for more info about RESP3.
*
* Send a string reply obtained converting the double 'd' into a bulk string.
* This function is basically equivalent to converting a double into * This function is basically equivalent to converting a double into
* a string into a C buffer, and then calling the function * a string into a C buffer, and then calling the function
* RedisModule_ReplyWithStringBuffer() with the buffer and length. * RedisModule_ReplyWithStringBuffer() with the buffer and length.
* *
* In RESP3 the string is tagged as a double, while in RESP2 it's just a plain string
* that the user will have to parse.
*
* The function always returns REDISMODULE_OK. */ * The function always returns REDISMODULE_OK. */
int RM_ReplyWithDouble(RedisModuleCtx *ctx, double d) { int RM_ReplyWithDouble(RedisModuleCtx *ctx, double d) {
client *c = moduleGetReplyClient(ctx); client *c = moduleGetReplyClient(ctx);
...@@ -2277,6 +2287,21 @@ int RM_ReplyWithDouble(RedisModuleCtx *ctx, double d) { ...@@ -2277,6 +2287,21 @@ int RM_ReplyWithDouble(RedisModuleCtx *ctx, double d) {
return REDISMODULE_OK; return REDISMODULE_OK;
} }
/* Reply with a RESP3 BigNumber type.
* Visit https://github.com/antirez/RESP3/blob/master/spec.md for more info about RESP3.
*
* In RESP3, this is a string of length `len` that is tagged as a BigNumber,
* however, it's up to the caller to ensure that it's a valid BigNumber.
* In RESP2, this is just a plain bulk string response.
*
* The function always returns REDISMODULE_OK. */
int RM_ReplyWithBigNumber(RedisModuleCtx *ctx, const char *bignum, size_t len) {
client *c = moduleGetReplyClient(ctx);
if (c == NULL) return REDISMODULE_OK;
addReplyBigNum(c, bignum, len);
return REDISMODULE_OK;
}
/* Send a string reply obtained converting the long double 'ld' into a bulk /* Send a string reply obtained converting the long double 'ld' into a bulk
* string. This function is basically equivalent to converting a long double * string. This function is basically equivalent to converting a long double
* into a string into a C buffer, and then calling the function * into a string into a C buffer, and then calling the function
...@@ -10346,6 +10371,7 @@ void moduleRegisterCoreAPI(void) { ...@@ -10346,6 +10371,7 @@ void moduleRegisterCoreAPI(void) {
REGISTER_API(ReplyWithBool); REGISTER_API(ReplyWithBool);
REGISTER_API(ReplyWithCallReply); REGISTER_API(ReplyWithCallReply);
REGISTER_API(ReplyWithDouble); REGISTER_API(ReplyWithDouble);
REGISTER_API(ReplyWithBigNumber);
REGISTER_API(ReplyWithLongDouble); REGISTER_API(ReplyWithLongDouble);
REGISTER_API(GetSelectedDb); REGISTER_API(GetSelectedDb);
REGISTER_API(SelectDb); REGISTER_API(SelectDb);
......
...@@ -667,8 +667,9 @@ REDISMODULE_API int (*RedisModule_ReplyWithVerbatimString)(RedisModuleCtx *ctx, ...@@ -667,8 +667,9 @@ REDISMODULE_API int (*RedisModule_ReplyWithVerbatimString)(RedisModuleCtx *ctx,
REDISMODULE_API int (*RedisModule_ReplyWithVerbatimStringType)(RedisModuleCtx *ctx, const char *buf, size_t len, const char *ext) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_ReplyWithVerbatimStringType)(RedisModuleCtx *ctx, const char *buf, size_t len, const char *ext) REDISMODULE_ATTR;
REDISMODULE_API int (*RedisModule_ReplyWithNull)(RedisModuleCtx *ctx) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_ReplyWithNull)(RedisModuleCtx *ctx) REDISMODULE_ATTR;
REDISMODULE_API int (*RedisModule_ReplyWithBool)(RedisModuleCtx *ctx, int b) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_ReplyWithBool)(RedisModuleCtx *ctx, int b) REDISMODULE_ATTR;
REDISMODULE_API int (*RedisModule_ReplyWithDouble)(RedisModuleCtx *ctx, double d) REDISMODULE_ATTR;
REDISMODULE_API int (*RedisModule_ReplyWithLongDouble)(RedisModuleCtx *ctx, long double d) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_ReplyWithLongDouble)(RedisModuleCtx *ctx, long double d) REDISMODULE_ATTR;
REDISMODULE_API int (*RedisModule_ReplyWithDouble)(RedisModuleCtx *ctx, double d) REDISMODULE_ATTR;
REDISMODULE_API int (*RedisModule_ReplyWithBigNumber)(RedisModuleCtx *ctx, const char *bignum, size_t len) REDISMODULE_ATTR;
REDISMODULE_API int (*RedisModule_ReplyWithCallReply)(RedisModuleCtx *ctx, RedisModuleCallReply *reply) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_ReplyWithCallReply)(RedisModuleCtx *ctx, RedisModuleCallReply *reply) REDISMODULE_ATTR;
REDISMODULE_API int (*RedisModule_StringToLongLong)(const RedisModuleString *str, long long *ll) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_StringToLongLong)(const RedisModuleString *str, long long *ll) REDISMODULE_ATTR;
REDISMODULE_API int (*RedisModule_StringToDouble)(const RedisModuleString *str, double *d) REDISMODULE_ATTR; REDISMODULE_API int (*RedisModule_StringToDouble)(const RedisModuleString *str, double *d) REDISMODULE_ATTR;
...@@ -953,6 +954,7 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int ...@@ -953,6 +954,7 @@ static int RedisModule_Init(RedisModuleCtx *ctx, const char *name, int ver, int
REDISMODULE_GET_API(ReplyWithBool); REDISMODULE_GET_API(ReplyWithBool);
REDISMODULE_GET_API(ReplyWithCallReply); REDISMODULE_GET_API(ReplyWithCallReply);
REDISMODULE_GET_API(ReplyWithDouble); REDISMODULE_GET_API(ReplyWithDouble);
REDISMODULE_GET_API(ReplyWithBigNumber);
REDISMODULE_GET_API(ReplyWithLongDouble); REDISMODULE_GET_API(ReplyWithLongDouble);
REDISMODULE_GET_API(GetSelectedDb); REDISMODULE_GET_API(GetSelectedDb);
REDISMODULE_GET_API(SelectDb); REDISMODULE_GET_API(SelectDb);
......
...@@ -51,7 +51,8 @@ TEST_MODULES = \ ...@@ -51,7 +51,8 @@ TEST_MODULES = \
stream.so \ stream.so \
aclcheck.so \ aclcheck.so \
list.so \ list.so \
subcommands.so subcommands.so \
reply.so
.PHONY: all .PHONY: all
......
...@@ -47,6 +47,15 @@ int rw_longdouble(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { ...@@ -47,6 +47,15 @@ int rw_longdouble(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
return RedisModule_ReplyWithLongDouble(ctx, longdbl); return RedisModule_ReplyWithLongDouble(ctx, longdbl);
} }
int rw_bignumber(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
if (argc != 2) return RedisModule_WrongArity(ctx);
size_t bignum_len;
const char *bignum_str = RedisModule_StringPtrLen(argv[1], &bignum_len);
return RedisModule_ReplyWithBigNumber(ctx, bignum_str, bignum_len);
}
int rw_array(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int rw_array(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
if (argc != 2) return RedisModule_WrongArity(ctx); if (argc != 2) return RedisModule_WrongArity(ctx);
...@@ -106,6 +115,7 @@ int rw_attribute(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { ...@@ -106,6 +115,7 @@ int rw_attribute(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
for (int i = 0; i < integer; ++i) { for (int i = 0; i < integer; ++i) {
RedisModule_ReplyWithLongLong(ctx, i); RedisModule_ReplyWithLongLong(ctx, i);
RedisModule_ReplyWithDouble(ctx, i * 1.5);
} }
RedisModule_ReplyWithSimpleString(ctx, "OK"); RedisModule_ReplyWithSimpleString(ctx, "OK");
...@@ -136,9 +146,12 @@ int rw_error(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { ...@@ -136,9 +146,12 @@ int rw_error(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
} }
int rw_verbatim(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int rw_verbatim(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
if (argc != 1) return RedisModule_WrongArity(ctx); if (argc != 2) return RedisModule_WrongArity(ctx);
return RedisModule_ReplyWithVerbatimString(ctx, argv[1]); size_t verbatim_len;
const char *verbatim_str = RedisModule_StringPtrLen(argv[1], &verbatim_len);
return RedisModule_ReplyWithVerbatimString(ctx, verbatim_str, verbatim_len);
} }
int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
...@@ -151,6 +164,8 @@ int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) ...@@ -151,6 +164,8 @@ int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc)
return REDISMODULE_ERR; return REDISMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"rw.cstring",rw_cstring,"",0,0,0) != REDISMODULE_OK) if (RedisModule_CreateCommand(ctx,"rw.cstring",rw_cstring,"",0,0,0) != REDISMODULE_OK)
return REDISMODULE_ERR; return REDISMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"rw.bignumber",rw_bignumber,"",0,0,0) != REDISMODULE_OK)
return REDISMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"rw.int",rw_int,"",0,0,0) != REDISMODULE_OK) if (RedisModule_CreateCommand(ctx,"rw.int",rw_int,"",0,0,0) != REDISMODULE_OK)
return REDISMODULE_ERR; return REDISMODULE_ERR;
if (RedisModule_CreateCommand(ctx,"rw.double",rw_double,"",0,0,0) != REDISMODULE_OK) if (RedisModule_CreateCommand(ctx,"rw.double",rw_double,"",0,0,0) != REDISMODULE_OK)
......
set testmodule [file normalize tests/modules/reply.so] set testmodule [file normalize tests/modules/reply.so]
# test all with hello 2/3
start_server {tags {"modules"}} { start_server {tags {"modules"}} {
r module load $testmodule r module load $testmodule
for {proto=2; proto<=3; incr proto} { # test all with hello 2/3
for {set proto 2} {$proto <= 3} {incr proto} {
r hello $proto r hello $proto
test {RM_ReplyWithString: an string reply} { test {RM_ReplyWithString: an string reply} {
...@@ -17,6 +16,10 @@ start_server {tags {"modules"}} { ...@@ -17,6 +16,10 @@ start_server {tags {"modules"}} {
assert_equal "A simple string" $string assert_equal "A simple string" $string
} }
test {RM_ReplyWithBigNumber: an string reply} {
assert_equal "123456778901234567890" [r rw.bignumber "123456778901234567890"]
}
test {RM_ReplyWithInt: an integer reply} { test {RM_ReplyWithInt: an integer reply} {
assert_equal 42 [r rw.int 42] assert_equal 42 [r rw.int 42]
} }
...@@ -40,7 +43,7 @@ start_server {tags {"modules"}} { ...@@ -40,7 +43,7 @@ start_server {tags {"modules"}} {
test {RM_ReplyWithMap: an map reply} { test {RM_ReplyWithMap: an map reply} {
set res [r rw.map 3] set res [r rw.map 3]
if {$proto == 2} { if {$proto == 2} {
assert_equal {0 0.0 1 1.5 2 3.0} $res assert_equal {0 0 1 1.5 2 3} $res
} else { } else {
assert_equal [dict create 0 0.0 1 1.5 2 3.0] $res assert_equal [dict create 0 0.0 1 1.5 2 3.0] $res
} }
...@@ -51,14 +54,21 @@ start_server {tags {"modules"}} { ...@@ -51,14 +54,21 @@ start_server {tags {"modules"}} {
} }
test {RM_ReplyWithAttribute: an set reply} { test {RM_ReplyWithAttribute: an set reply} {
set res [r rw.attribute 3]
if {$proto == 2} { if {$proto == 2} {
catch {r rw.error} e catch {[r rw.attribute 3]} e
assert_match "Attributes aren't supported by RESP 2" $e assert_match "Attributes aren't supported by RESP 2" $e
} else { } else {
assert_equal [dict create 0 0.0 1 1.5 2 3.0] $res r readraw 1
set res [r rw.attribute 3]
assert_equal [r read] {:0}
assert_equal [r read] {,0}
assert_equal [r read] {:1}
assert_equal [r read] {,1.5}
assert_equal [r read] {:2}
assert_equal [r read] {,3}
assert_equal [r read] {+OK}
r readraw 0
} }
assert_equal "OK" $res
} }
test {RM_ReplyWithBool: a boolean reply} { test {RM_ReplyWithBool: a boolean reply} {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment