mirror of
https://github.com/dragonflydb/dragonfly.git
synced 2025-05-11 18:35:46 +02:00
feat(json_family): Add support of the JSON legacy mode (#3284)
This commit is contained in:
parent
7df72fd6d0
commit
75452a7108
9 changed files with 1733 additions and 1012 deletions
|
@ -90,6 +90,11 @@ struct CmdArgParser {
|
|||
}
|
||||
}
|
||||
|
||||
// returns next value if exists or default value
|
||||
template <class T = std::string_view> auto NextOrDefault(T default_value = {}) {
|
||||
return HasNext() ? Next<T>() : default_value;
|
||||
}
|
||||
|
||||
// check next value ignoring case and consume it
|
||||
void ExpectTag(std::string_view tag);
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@ std::string UnknownSubCmd(std::string_view subcmd, std::string_view cmd);
|
|||
|
||||
extern const char kSyntaxErr[];
|
||||
extern const char kWrongTypeErr[];
|
||||
extern const char kWrongJsonTypeErr[];
|
||||
extern const char kKeyNotFoundErr[];
|
||||
extern const char kInvalidIntErr[];
|
||||
extern const char kInvalidFloatErr[];
|
||||
|
|
|
@ -79,6 +79,7 @@ string ConfigSetFailed(string_view config_name) {
|
|||
|
||||
const char kSyntaxErr[] = "syntax error";
|
||||
const char kWrongTypeErr[] = "-WRONGTYPE Operation against a key holding the wrong kind of value";
|
||||
const char kWrongJsonTypeErr[] = "-WRONGTYPE wrong JSON type of path value";
|
||||
const char kKeyNotFoundErr[] = "no such key";
|
||||
const char kInvalidIntErr[] = "value is not an integer or out of range";
|
||||
const char kInvalidFloatErr[] = "value is not a valid float";
|
||||
|
|
|
@ -14,6 +14,8 @@ std::string_view StatusToMsg(OpStatus status) {
|
|||
return kKeyNotFoundErr;
|
||||
case OpStatus::WRONG_TYPE:
|
||||
return kWrongTypeErr;
|
||||
case OpStatus::WRONG_JSON_TYPE:
|
||||
return kWrongJsonTypeErr;
|
||||
case OpStatus::OUT_OF_RANGE:
|
||||
return kIndexOutOfRange;
|
||||
case OpStatus::INVALID_FLOAT:
|
||||
|
|
|
@ -18,6 +18,7 @@ enum class OpStatus : uint16_t {
|
|||
INVALID_VALUE,
|
||||
OUT_OF_RANGE,
|
||||
WRONG_TYPE,
|
||||
WRONG_JSON_TYPE,
|
||||
TIMED_OUT,
|
||||
OUT_OF_MEMORY,
|
||||
INVALID_FLOAT,
|
||||
|
|
|
@ -24,32 +24,15 @@ using JsonExpression = jsoncons::jsonpath::jsonpath_expression<JsonType>;
|
|||
template <typename T>
|
||||
using JsonPathEvaluateCallback = absl::FunctionRef<T(std::string_view, const JsonType&)>;
|
||||
|
||||
template <typename T = Nothing> class MutateCallbackResult {
|
||||
public:
|
||||
template <typename T = Nothing> struct MutateCallbackResult {
|
||||
MutateCallbackResult() = default;
|
||||
|
||||
explicit MutateCallbackResult(bool should_be_deleted) : should_be_deleted_(should_be_deleted_) {
|
||||
MutateCallbackResult(bool should_be_deleted_, T value_)
|
||||
: should_be_deleted(should_be_deleted_), value(std::move(value_)) {
|
||||
}
|
||||
|
||||
MutateCallbackResult(bool should_be_deleted, T&& value)
|
||||
: should_be_deleted_(should_be_deleted), value_(std::forward<T>(value)) {
|
||||
}
|
||||
|
||||
bool HasValue() const {
|
||||
return value_.has_value();
|
||||
}
|
||||
|
||||
T&& GetValue() && {
|
||||
return std::move(value_).value();
|
||||
}
|
||||
|
||||
bool ShouldBeDeleted() const {
|
||||
return should_be_deleted_;
|
||||
}
|
||||
|
||||
private:
|
||||
bool should_be_deleted_;
|
||||
std::optional<T> value_;
|
||||
bool should_be_deleted = false;
|
||||
std::optional<T> value;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
|
@ -81,7 +64,8 @@ template <typename T> class JsonCallbackResult {
|
|||
|
||||
JsonCallbackResult() = default;
|
||||
|
||||
explicit JsonCallbackResult(bool legacy_mode_is_enabled) {
|
||||
explicit JsonCallbackResult(bool legacy_mode_is_enabled, bool save_first_result = false)
|
||||
: save_first_result_(save_first_result) {
|
||||
if (!legacy_mode_is_enabled) {
|
||||
result_ = JsonV2Result{};
|
||||
}
|
||||
|
@ -89,7 +73,14 @@ template <typename T> class JsonCallbackResult {
|
|||
|
||||
void AddValue(T value) {
|
||||
if (IsV1()) {
|
||||
details::OptionalEmplace(std::move(value), &AsV1());
|
||||
if (!save_first_result_) {
|
||||
details::OptionalEmplace(std::move(value), &AsV1());
|
||||
} else {
|
||||
auto& as_v1 = AsV1();
|
||||
if (!as_v1.has_value()) {
|
||||
details::OptionalEmplace(std::move(value), &as_v1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
AsV2().emplace_back(std::move(value));
|
||||
}
|
||||
|
@ -117,6 +108,7 @@ template <typename T> class JsonCallbackResult {
|
|||
|
||||
private:
|
||||
std::variant<JsonV1Result, JsonV2Result> result_;
|
||||
bool save_first_result_ = false;
|
||||
};
|
||||
|
||||
class WrappedJsonPath {
|
||||
|
@ -137,14 +129,15 @@ class WrappedJsonPath {
|
|||
}
|
||||
|
||||
template <typename T>
|
||||
JsonCallbackResult<T> Evaluate(const JsonType* json_entry, JsonPathEvaluateCallback<T> cb) const {
|
||||
return Evaluate(json_entry, cb, IsLegacyModePath());
|
||||
JsonCallbackResult<T> Evaluate(const JsonType* json_entry, JsonPathEvaluateCallback<T> cb,
|
||||
bool save_first_result) const {
|
||||
return Evaluate(json_entry, cb, save_first_result, IsLegacyModePath());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
JsonCallbackResult<T> Evaluate(const JsonType* json_entry, JsonPathEvaluateCallback<T> cb,
|
||||
bool legacy_mode_is_enabled) const {
|
||||
JsonCallbackResult<T> eval_result{legacy_mode_is_enabled};
|
||||
bool save_first_result, bool legacy_mode_is_enabled) const {
|
||||
JsonCallbackResult<T> eval_result{legacy_mode_is_enabled, save_first_result};
|
||||
|
||||
auto eval_callback = [&cb, &eval_result](std::string_view path, const JsonType& val) {
|
||||
eval_result.AddValue(cb(path, val));
|
||||
|
@ -172,10 +165,10 @@ class WrappedJsonPath {
|
|||
auto mutate_callback = [&cb, &mutate_result](std::optional<std::string_view> path,
|
||||
JsonType* val) -> bool {
|
||||
auto res = cb(path, val);
|
||||
if (res.HasValue()) {
|
||||
mutate_result.AddValue(std::move(res).GetValue());
|
||||
if (res.value.has_value()) {
|
||||
mutate_result.AddValue(std::move(res.value).value());
|
||||
}
|
||||
return res.ShouldBeDeleted();
|
||||
return res.should_be_deleted;
|
||||
};
|
||||
|
||||
if (HoldsJsonPath()) {
|
||||
|
@ -217,7 +210,11 @@ class WrappedJsonPath {
|
|||
return is_legacy_mode_path_;
|
||||
}
|
||||
|
||||
private:
|
||||
bool RefersToRootElement() const {
|
||||
auto path = path_.view();
|
||||
return path.empty() || path == kV1PathRootElement || path == kV2PathRootElement;
|
||||
}
|
||||
|
||||
bool HoldsJsonPath() const {
|
||||
return std::holds_alternative<json::Path>(parsed_path_);
|
||||
}
|
||||
|
|
|
@ -44,17 +44,6 @@ using facade::kWrongTypeErr;
|
|||
|
||||
#endif // RETURN_ON_BAD_STATUS
|
||||
|
||||
#ifndef RETURN_UNEXPECTED
|
||||
|
||||
#define RETURN_UNEXPECTED(x) \
|
||||
do { \
|
||||
if (!(x)) { \
|
||||
return (x).get_unexpected(); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#endif // RETURN_UNEXPECTED
|
||||
|
||||
#ifndef GET_OR_SEND_UNEXPECTED
|
||||
|
||||
#define GET_OR_SEND_UNEXPECTED(expr) \
|
||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue