mirror of https://mirror.osredm.com/root/redis.git
Expr: handle JSON arrays as expr tuples.
This commit is contained in:
parent
764fb8cc74
commit
44c064c0b4
78
expr.c
78
expr.c
|
@ -699,6 +699,63 @@ int exprTokensEqual(exprtoken *a, exprtoken *b) {
|
||||||
return exprTokenToNum(a) == exprTokenToNum(b);
|
return exprTokenToNum(a) == exprTokenToNum(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Convert a json object to an expression token. There is only
|
||||||
|
* limited support for JSON arrays: they must be composed of
|
||||||
|
* just numbers and strings. Returns NULL if the JSON object
|
||||||
|
* cannot be converted. */
|
||||||
|
exprtoken *exprJsonToToken(cJSON *js) {
|
||||||
|
if (cJSON_IsNumber(js)) {
|
||||||
|
exprtoken *obj = exprNewToken(EXPR_TOKEN_NUM);
|
||||||
|
obj->num = cJSON_GetNumberValue(js);
|
||||||
|
return obj;
|
||||||
|
} else if (cJSON_IsString(js)) {
|
||||||
|
exprtoken *obj = exprNewToken(EXPR_TOKEN_STR);
|
||||||
|
char *strval = cJSON_GetStringValue(js);
|
||||||
|
obj->str.heapstr = RedisModule_Strdup(strval);
|
||||||
|
obj->str.start = obj->str.heapstr;
|
||||||
|
obj->str.len = strlen(obj->str.heapstr);
|
||||||
|
return obj;
|
||||||
|
} else if (cJSON_IsArray(js)) {
|
||||||
|
// First, scan the array to ensure it only
|
||||||
|
// contains strings and numbers. Otherwise the
|
||||||
|
// expression will evaluate to false.
|
||||||
|
int array_size = cJSON_GetArraySize(js);
|
||||||
|
|
||||||
|
for (int j = 0; j < array_size; j++) {
|
||||||
|
cJSON *item = cJSON_GetArrayItem(js, j);
|
||||||
|
if (!cJSON_IsNumber(item) && !cJSON_IsString(item)) return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a tuple token for the array.
|
||||||
|
exprtoken *obj = exprNewToken(EXPR_TOKEN_TUPLE);
|
||||||
|
obj->tuple.len = array_size;
|
||||||
|
obj->tuple.ele = NULL;
|
||||||
|
if (obj->tuple.len == 0) return obj; // No elements, already ok.
|
||||||
|
|
||||||
|
obj->tuple.ele =
|
||||||
|
RedisModule_Alloc(sizeof(exprtoken*) * obj->tuple.len);
|
||||||
|
|
||||||
|
// Convert each array element to a token.
|
||||||
|
for (size_t j = 0; j < obj->tuple.len; j++) {
|
||||||
|
cJSON *item = cJSON_GetArrayItem(js, j);
|
||||||
|
if (cJSON_IsNumber(item)) {
|
||||||
|
exprtoken *eleToken = exprNewToken(EXPR_TOKEN_NUM);
|
||||||
|
eleToken->num = cJSON_GetNumberValue(item);
|
||||||
|
obj->tuple.ele[j] = eleToken;
|
||||||
|
} else if (cJSON_IsString(item)) {
|
||||||
|
exprtoken *eleToken = exprNewToken(EXPR_TOKEN_STR);
|
||||||
|
char *strval = cJSON_GetStringValue(item);
|
||||||
|
eleToken->str.heapstr = RedisModule_Strdup(strval);
|
||||||
|
eleToken->str.start = eleToken->str.heapstr;
|
||||||
|
eleToken->str.len = strlen(eleToken->str.heapstr);
|
||||||
|
obj->tuple.ele[j] = eleToken;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
return NULL; // No conversion possible for this type.
|
||||||
|
}
|
||||||
|
|
||||||
/* Execute the compiled expression program. Returns 1 if the final stack value
|
/* Execute the compiled expression program. Returns 1 if the final stack value
|
||||||
* evaluates to true, 0 otherwise. Also returns 0 if any selector callback
|
* evaluates to true, 0 otherwise. Also returns 0 if any selector callback
|
||||||
* fails. */
|
* fails. */
|
||||||
|
@ -728,28 +785,19 @@ int exprRun(exprstate *es, char *json, size_t json_len) {
|
||||||
/* Fill the token according to the JSON type stored
|
/* Fill the token according to the JSON type stored
|
||||||
* at the attribute. */
|
* at the attribute. */
|
||||||
if (attrib) {
|
if (attrib) {
|
||||||
if (cJSON_IsNumber(attrib)) {
|
exprtoken *obj = exprJsonToToken(attrib);
|
||||||
exprtoken *obj = exprNewToken(EXPR_TOKEN_NUM);
|
if (obj) {
|
||||||
obj->num = cJSON_GetNumberValue(attrib);
|
|
||||||
exprStackPush(&es->values_stack, obj);
|
exprStackPush(&es->values_stack, obj);
|
||||||
} else if (cJSON_IsString(attrib)) {
|
continue;
|
||||||
exprtoken *obj = exprNewToken(EXPR_TOKEN_STR);
|
|
||||||
char *strval = cJSON_GetStringValue(attrib);
|
|
||||||
obj->str.heapstr = RedisModule_Strdup(strval);
|
|
||||||
obj->str.start = obj->str.heapstr;
|
|
||||||
obj->str.len = strlen(obj->str.heapstr);
|
|
||||||
exprStackPush(&es->values_stack, obj);
|
|
||||||
} else {
|
|
||||||
/* XXX: fixme: turn JS arrays into tuples. */
|
|
||||||
attrib = NULL; // Unsupported type.
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (attrib) continue; // Selector found and pushed on stack.
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Selector not found or JSON object not convertible to
|
||||||
|
// expression tokens. Evaluate the expression to false.
|
||||||
if (parsed_json) cJSON_Delete(parsed_json);
|
if (parsed_json) cJSON_Delete(parsed_json);
|
||||||
return 0; // Selector not found: expression evaluates to false.
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Push non-operator values directly onto the stack.
|
// Push non-operator values directly onto the stack.
|
||||||
|
|
Loading…
Reference in New Issue