Skip to content

Commit

Permalink
Add redisxGetStringValue() and site update
Browse files Browse the repository at this point in the history
  • Loading branch information
attipaci committed Sep 5, 2024
1 parent a677f4c commit b19601b
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 13 deletions.
17 changes: 6 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -437,33 +437,28 @@ Retrieving individual keyed values is simple:
```c
Redis *redis = ...;
int status; // Variable in which we'll report error status.
int len; // Variable in which we return the length of the value or an error code
// Get the "property" field from the "system:subsystem" hash table
RESP *resp = redisxGetValue(redis, "system:subsystem", "property", &status);
if (status != X_SUCCESS) {
char *value = redisxGetStringValue(redis, "system:subsystem", "property", &len);
if (len < 0) {
// Oops something went wrong.
...
}
// Check and process resp
...
// Destroy resp
redisxDestroyRESP(resp);
// Discard the value once it's no longer needed.
if(value) free(value);
```

The same goes for top-level keyed values, using `NULL` for the hash table name:

```c
// Get value for top-level key (not stored in hash table!)
RESP *resp = redisxGetValue(redis, NULL, "my-key", &status);
char *value = redisxGetStringValue(redis, NULL, "my-key", &len);
```

The reason the return value is a `RESP` pointer, rather than a string is twofold: (1) because it lets you process possible
error responses from Redis also, and (2) because it lets you deal with unterminated string values, such as binary sequences
of known length.

In turn, setting values is also straightforward:

```c
Expand Down
1 change: 1 addition & 0 deletions include/redisx.h
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,7 @@ RESP *redisxRequest(Redis *redis, const char *command, const char *arg1, const c
RESP *redisxArrayRequest(Redis *redis, char *args[], int length[], int n, int *status);
int redisxSetValue(Redis *redis, const char *table, const char *key, const char *value, boolean isPipelined);
RESP *redisxGetValue(Redis*redis, const char *table, const char *key, int *status);
char *redisxGetStringValue(Redis *redis, const char *table, const char *key, int *len);
RedisEntry *redisxGetTable(Redis *redis, const char *table, int *n);
RedisEntry *redisxScanTable(Redis *redis, const char *table, const char *pattern, int *n, int *status);
int redisxMultiSet(Redis *redis, const char *table, const RedisEntry *entries, int n, boolean isPipelined);
Expand Down
55 changes: 53 additions & 2 deletions src/redisx-tab.c
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ int redisxSetValueAsync(RedisClient *cl, const char *table, const char *key, con
* Retrieve a variable from Redis, through the interactive connection. This is not the highest throughput mode
* (that would be sending asynchronous pipeline request, and then asynchronously collecting the results such as
* with redisxSendRequestAsync() / redisxReadReplyAsync()), because it requires separate network roundtrips for each
* and every request. But, it is simple and perfectly good method when one needs to retrieve only a few (<1000)
* and every request. But, it is simple and perfectly good method when one needs to retrieve only a few (&lt;1000)
* variables per second...
*
* The call is effectively implements a Redis GET (if the tale argument is NULL) or HGET call.
Expand All @@ -210,13 +210,18 @@ int redisxSetValueAsync(RedisClient *cl, const char *table, const char *key, con
*
* \return A freshly allocated RESP array containing the Redis response, or NULL if no valid
* response could be obtained.
*
* \sa redisxGetStringValue()
*/
RESP *redisxGetValue(Redis *redis, const char *table, const char *key, int *status) {
static const char *funcName = "redisxGetValue()";

RESP *reply;

if(redis == NULL) return NULL;
if(redis == NULL) {
if(status) *status = X_NULL;
return NULL;
}

if(key == NULL) {
*status = redisxError(funcName, X_NAME_INVALID);
Expand All @@ -231,6 +236,52 @@ RESP *redisxGetValue(Redis *redis, const char *table, const char *key, int *stat
return reply;
}

/**
* Retrieve a variable from Redis as a string (or byte array), through the interactive connection. This is not the
* highest throughput mode (that would be sending asynchronous pipeline request, and then asynchronously collecting
* the results such as with redisxSendRequestAsync() / redisxReadReplyAsync()), because it requires separate network
* roundtrips for each and every request. But, it is simple and perfectly good method when one needs to retrieve only
* a few (&lt;1000) variables per second...
*
* The call is effectively implements a Redis GET (if the tale argument is NULL) or HGET call.
*
* \param[in] redis Pointer to a Redis instance.
* \param[in] table Hashtable from which to retrieve a value or NULL if to use the global table.
* \param[in] key Field name (i.e. variable name).
* \param[out] len (optional) pointer in which to return the length (&gt;=0) of the value or else
* an error code (&lt;0) defined in xchange.h / redisx.h
*
* \return A freshly allocated RESP array containing the Redis response, or NULL if no valid
* response could be obtained.
*
* \sa redisxGetValue()
*/
char *redisxGetStringValue(Redis *redis, const char *table, const char *key, int *len) {
RESP *reply;
char *str = NULL;
int status;

if(redis == NULL) {
if(len) *len = X_NULL;
return NULL;
}

reply = redisxGetValue(redis, table, key, len);

status = redisxCheckRESP(reply, RESP_BULK_STRING, 0);

if(status == X_SUCCESS) {
str = (char *) reply->value;
reply->value = NULL;
if(len) *len = reply->n;
}
else if(len) *len = status;

redisxDestroyRESP(reply);

return str;
}

/**
* Sets multiple key/value pairs in a given hash table.
*
Expand Down

0 comments on commit b19601b

Please sign in to comment.