New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
JSON: support basic legacy path #1829
base: unstable
Are you sure you want to change the base?
Conversation
src/commands/cmd_json.cc
Outdated
@@ -52,7 +55,7 @@ class CommandJsonGet : public Commander { | |||
} | |||
}; | |||
|
|||
REDIS_REGISTER_COMMANDS(MakeCmdAttr<CommandJsonSet>("json.set", -3, "write", 1, 1, 1), | |||
REDIS_REGISTER_COMMANDS(MakeCmdAttr<CommandJsonSet>("json.set", 3, "write", 1, 1, 1), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should use -3
after set with NX
support.
Now I think we only support 3 arguments.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oops, seems this should be 4 (or -4 if implement NX and other options)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems there are several issues that need to be addressed in this PR:
- All special logic related to legacy path goes to
redis_json.h/cc
instead ofjson.h
, which is not aligned with the original intention.redis_json.h/cc
should only contain i/o specific code and method call tojson.h
. You can try to implement them inJsonValue
or add a class namedJsonPath
. - Actually there are some difference in the query result between path
$.x
and.x
(orx
). It can be observe that query of path prefixed without$
will just get response with the first matched value instead of an array. - I think we can consider a more complete path resolution mechanism rather than just handling one case.
This patch is only a basic json legacy path support, the detail rule will be handled later. |
@PragmaTwice I've add a JsonPath type, however, currently I find the |
592d348
to
9d76a51
Compare
9d76a51
to
50fa211
Compare
src/types/json.h
Outdated
jsoncons::jsonpath::json_replace(value, path, [&new_value](const std::string & /*path*/, jsoncons::json &origin) { | ||
origin = new_value.value; | ||
}); | ||
path.EvalReplaceExpression( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually I do not think this function name is clear enough. Maybe we can figure out another name.
src/types/json_path.h
Outdated
public: | ||
using JsonType = jsoncons::basic_json<char>; | ||
using JsonPathExpression = jsoncons::jsonpath::jsonpath_expression<JsonType, const JsonType&>; | ||
using JsonQueryCallback = std::function<void(const std::string_view&, const JsonType&)>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cannot find where it is used 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove it
src/types/json_path.h
Outdated
JsonType EvalQueryExpression(const JsonType& json_value) const { | ||
return expression_.evaluate(const_cast<JsonType&>(json_value)); | ||
} | ||
|
||
void EvalReplaceExpression(JsonType& json_value, const JsonReplaceCallback& callback) const { | ||
auto wrapped_cb = [&callback](const std::string_view& path, const JsonType& json) { | ||
// Though JsonPath supports mutable reference, `jsoncons::make_expression` | ||
// only supports const reference, so const_cast is used as a workaround. | ||
callback(path, const_cast<JsonType&>(json)); | ||
}; | ||
expression_.evaluate(json_value, wrapped_cb); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it necessary to provide two function?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🤔the first one is used to get a JsonValue, the second value is used to replace
. Any better idea for this?
src/types/json_path.h
Outdated
JsonPath(std::string path, std::string fixed_path, JsonPathExpression path_expression) | ||
: origin_(std::move(path)), fixed_path_(std::move(fixed_path)), expression_(std::move(path_expression)) {} | ||
|
||
std::string origin_; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it necessary to store the original path string? Or just store the original one rather than the modified one?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it necessary to store the original path string
We need the OriginPath
in someplace like MSET. It's also ok to only has the origin_path
and expression. But I think it would not heavy to having one more string?
Note: this patch doesn't means fully compatible with Json legacy path, it just try it best to convert to I found that:
|
|
||
static constexpr std::string_view ROOT_PATH = "$"; | ||
|
||
static StatusOr<JsonPath> BuildJsonPath(std::string_view path); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
static StatusOr<JsonPath> BuildJsonPath(std::string_view path); | |
static StatusOr<JsonPath> FromString(std::string_view path); |
void EvalJsonReplace(JsonType &json_value, const BinaryJsonFunction &callback) const { | ||
auto wrapped_cb = [&callback](const std::string_view &path, const JsonType &json) { | ||
// Though JsonPath supports mutable reference, `jsoncons::make_expression` | ||
// only supports const reference, so const_cast is used as a workaround. | ||
callback(path, const_cast<JsonType &>(json)); | ||
}; | ||
expression_.evaluate(json_value, wrapped_cb); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as #1829 (comment), maybe json_replace
has no const_cast
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
json_replace has use a different expression 😅 I don't know how jsoncons consider it. I'll dive into it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@PragmaTwice The author says he will implement a mutable in next release. Let me make this patch small and waiting for next release
if (json_parse_error) { | ||
return {Status::NotOK, json_parse_error.message()}; | ||
} | ||
return JsonPath(std::string(json_string), !fixed_path.empty(), std::move(path_expression)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think maybe we can avoid re-construct json_string while it is fixed_path.
JsonType EvalJsonQuery(const JsonType &json_value) const { | ||
return expression_.evaluate(const_cast<JsonType &>(json_value)); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could it return multiple query result? e.g. query $..a
from {"a":{"a":1}}
, we'll get {"a":1}
and 1
.
RedisJson supports a JsonPath for legacy client [1]. This patch only support the basic JsonPath "."
Note: this patch doesn't means fully compatible with Json legacy path, it just try it best to convert to
JsonPath. There're still some behaviors we cannot compatible with.
[1] https://redis.io/docs/data-types/json/path/#legacy-path-syntax