diff options
-rw-r--r-- | README.redis | 38 | ||||
-rw-r--r-- | examples/redis.tcl | 11 | ||||
-rw-r--r-- | jim-redis.c | 65 |
3 files changed, 95 insertions, 19 deletions
diff --git a/README.redis b/README.redis index adae3b5..59fc860 100644 --- a/README.redis +++ b/README.redis @@ -11,7 +11,7 @@ Usage ~~~~~ The redis extension exports an Object Based interface. In order -to open a connection, a stream sock must be open to the redis server. +to open a connection, a stream socket must be open to the redis server. e.g. set r [redis [socket stream localhost:6379]] @@ -21,7 +21,7 @@ Or to connect via the unix domain socket: set r [redis [socket unix /tmp/redis.sock]] The [redis] command returns a handle, that is a command name that -can be used to perform operations on the redis instance. A real example: +can be used to perform operations on the redis instance. For example: . package require redis 1.0 @@ -51,15 +51,45 @@ format will be stored and returned exactly. Return values ~~~~~~~~~~~~~ -The response from redis contains a type, and these types are handled as follows: +Responses from redis contain type information. These types are handled as follows: * integer - returns the integer result * string - returns the string result * array - returns a list of elements (where each element is a redis type) -* null - returns the empty string +* nil - returns the empty string * status - returns the status as a string * error - returns an error with the message as the value +Accessing type information +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Normally the type of the return value doesn't matter as Jim treats everything as a string, +however it can be useful to differentiate between the empty string and nil, or between a status +return and an error return. In order to support this, the '-type' option is allowed as the +first word of the subcommand. In this case, whenever a value is returned, a list of {value type} +is returned instead. This is true recursively, so an array will return both the type for the array +and each element will include a type. The types are identified as follows: + +* integer - "int" +* string - "str" +* array - "array" +* nil - "nil" +* status - "status" +* error - "error" + +The following example illustrates the use of types: + + . $r -type KEYS a* + {{abc str}} array + . $r -type SET def 3 + OK status + . $r INCR def + 4 int + . $r -type GET missing + {} nil + . $r -type KEYS + {ERR wrong number of arguments for 'keys' command} error + The read subcommand ~~~~~~~~~~~~~~~~~~~ diff --git a/examples/redis.tcl b/examples/redis.tcl index 3044ab8..aa3d246 100644 --- a/examples/redis.tcl +++ b/examples/redis.tcl @@ -27,6 +27,17 @@ $r HMSET env {*}$env set result [$r HGET env testing] puts "HGET: testing=$result" +# Now the same with -type +set result [$r -type HGET env testing] +puts "HGET (-type): testing=$result" + +# Now a missing value with -type +set result [$r -type HGET env doesnotexist] +puts "HGET (-type): doesnotexist=$result" + +set result [$r -type HGETALL env] +puts "HGETALL (-type): $result" + set size [$r HLEN env] puts "Size of env is $size" diff --git a/jim-redis.c b/jim-redis.c index 72f55eb..2534347 100644 --- a/jim-redis.c +++ b/jim-redis.c @@ -13,30 +13,63 @@ /** * Recursively decode a redis reply as Tcl data structure. */ -static Jim_Obj *jim_redis_get_result(Jim_Interp *interp, redisReply *reply) +static Jim_Obj *jim_redis_get_result(Jim_Interp *interp, redisReply *reply, int addtype) { int i; + Jim_Obj *obj; + switch (reply->type) { case REDIS_REPLY_INTEGER: - return Jim_NewIntObj(interp, reply->integer); + obj = Jim_NewIntObj(interp, reply->integer); + break; case REDIS_REPLY_STATUS: case REDIS_REPLY_ERROR: case REDIS_REPLY_STRING: - return Jim_NewStringObj(interp, reply->str, reply->len); + obj = Jim_NewStringObj(interp, reply->str, reply->len); break; case REDIS_REPLY_ARRAY: - { - Jim_Obj *obj = Jim_NewListObj(interp, NULL, 0); - for (i = 0; i < reply->elements; i++) { - Jim_ListAppendElement(interp, obj, jim_redis_get_result(interp, reply->element[i])); - } - return obj; + obj = Jim_NewListObj(interp, NULL, 0); + for (i = 0; i < reply->elements; i++) { + Jim_ListAppendElement(interp, obj, jim_redis_get_result(interp, reply->element[i], addtype)); } + break; case REDIS_REPLY_NIL: - return Jim_NewStringObj(interp, NULL, 0); + obj = Jim_NewStringObj(interp, NULL, 0); + break; default: - return Jim_NewStringObj(interp, "badtype", -1); + obj = Jim_NewStringObj(interp, "badtype", -1); + break; } + if (addtype) { + const char *type; + + switch (reply->type) { + case REDIS_REPLY_INTEGER: + type = "int"; + break; + case REDIS_REPLY_STATUS: + type = "status"; + break; + case REDIS_REPLY_ERROR: + type = "error"; + break; + case REDIS_REPLY_STRING: + type = "str"; + break; + case REDIS_REPLY_ARRAY: + type = "array"; + break; + case REDIS_REPLY_NIL: + type = "nil"; + break; + default: + type = "invalid"; + break; + } + obj = Jim_NewListObj(interp, &obj, 1); + Jim_ListAppendElement(interp, obj, Jim_NewStringObj(interp, type, -1)); + } + return obj; } /** @@ -56,12 +89,14 @@ static int jim_redis_subcmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv) const char **args; size_t *arglens; int ret = JIM_OK; + int addtype = 0; redisReply *reply; - if (argc < 2) { - Jim_WrongNumArgs(interp, 1, argv, "cmd ?args ...?"); - return JIM_ERR; + if (argc >= 3 && Jim_CompareStringImmediate(interp, argv[1], "-type")) { + addtype = 1; + argc--; + argv++; } if (Jim_CompareStringImmediate(interp, argv[1], "readable")) { @@ -94,7 +129,7 @@ static int jim_redis_subcmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv) } /* sometimes commands return NULL */ if (reply) { - Jim_SetResult(interp, jim_redis_get_result(interp, reply)); + Jim_SetResult(interp, jim_redis_get_result(interp, reply, addtype)); if (reply->type == REDIS_REPLY_ERROR) { ret = JIM_ERR; } |