feat(json_family): Add support of the JSON legacy mode (#3284)

This commit is contained in:
Stepan Bagritsevich 2024-08-06 18:04:45 +02:00 committed by GitHub
parent 7df72fd6d0
commit 75452a7108
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 1733 additions and 1012 deletions

View file

@ -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);

View file

@ -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[];

View file

@ -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";

View file

@ -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:

View file

@ -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,

View file

@ -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_);
}

View file

@ -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