mirror of
https://github.com/dragonflydb/dragonfly.git
synced 2025-05-11 10:25:47 +02:00
chore(json_family): Clean up code. FIRST PR (#5049)
* chore(json_family): Clean up code Signed-off-by: Stepan Bagritsevich <stefan@dragonflydb.io> * refactor: address comments Signed-off-by: Stepan Bagritsevich <stefan@dragonflydb.io> * chore(json_family): Remove const ref for mutate operations Signed-off-by: Stepan Bagritsevich <stefan@dragonflydb.io> * refactor: address comments 2 Signed-off-by: Stepan Bagritsevich <stefan@dragonflydb.io> * chore(json_family): Remove GetJson method Signed-off-by: Stepan Bagritsevich <stefan@dragonflydb.io> * refactor: revert const modifiers removing Signed-off-by: Stepan Bagritsevich <stefan@dragonflydb.io> --------- Signed-off-by: Stepan Bagritsevich <stefan@dragonflydb.io>
This commit is contained in:
parent
9f7b11628a
commit
0a33f28bd4
2 changed files with 286 additions and 253 deletions
|
@ -21,17 +21,17 @@ using facade::OpStatus;
|
||||||
using Nothing = std::monostate;
|
using Nothing = std::monostate;
|
||||||
using JsonExpression = jsoncons::jsonpath::jsonpath_expression<JsonType>;
|
using JsonExpression = jsoncons::jsonpath::jsonpath_expression<JsonType>;
|
||||||
|
|
||||||
|
namespace details {
|
||||||
template <typename T>
|
template <typename T>
|
||||||
using JsonPathEvaluateCallback = absl::FunctionRef<T(std::string_view, const JsonType&)>;
|
void OptionalEmplace(bool keep_defined, std::optional<T> src, std::optional<T>* dest);
|
||||||
|
|
||||||
|
template <typename T> void OptionalEmplace(bool keep_defined, T src, T* dest);
|
||||||
|
} // namespace details
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
using JsonPathReadOnlyCallback = absl::FunctionRef<T(std::string_view, const JsonType&)>;
|
||||||
|
|
||||||
template <typename T = Nothing> struct MutateCallbackResult {
|
template <typename T = Nothing> struct MutateCallbackResult {
|
||||||
MutateCallbackResult() {
|
|
||||||
}
|
|
||||||
|
|
||||||
MutateCallbackResult(bool should_be_deleted_, T value_)
|
|
||||||
: should_be_deleted(should_be_deleted_), value(std::move(value_)) {
|
|
||||||
}
|
|
||||||
|
|
||||||
bool should_be_deleted = false;
|
bool should_be_deleted = false;
|
||||||
std::optional<T> value;
|
std::optional<T> value;
|
||||||
};
|
};
|
||||||
|
@ -40,6 +40,101 @@ template <typename T>
|
||||||
using JsonPathMutateCallback =
|
using JsonPathMutateCallback =
|
||||||
absl::FunctionRef<MutateCallbackResult<T>(std::optional<std::string_view>, JsonType*)>;
|
absl::FunctionRef<MutateCallbackResult<T>(std::optional<std::string_view>, JsonType*)>;
|
||||||
|
|
||||||
|
enum class JsonPathType { kV2, kLegacy /*Or V1*/ };
|
||||||
|
constexpr JsonPathType kDefaultJsonPathType = JsonPathType::kV2;
|
||||||
|
|
||||||
|
struct CallbackResultOptions {
|
||||||
|
public:
|
||||||
|
enum class SavingOrder { kSaveFirst, kSaveLast };
|
||||||
|
enum class OnEmpty { kSendNil, kSendWrongType };
|
||||||
|
|
||||||
|
// Default options for WrappedJsonPath::ExecuteReadOnlyCallback
|
||||||
|
static CallbackResultOptions DefaultReadOnlyOptions(
|
||||||
|
SavingOrder saving_order = SavingOrder::kSaveLast);
|
||||||
|
// Default options for WrappedJsonPath::ExecuteMutateCallback
|
||||||
|
static CallbackResultOptions DefaultMutateOptions();
|
||||||
|
|
||||||
|
OnEmpty on_empty;
|
||||||
|
SavingOrder saving_order{SavingOrder::kSaveLast};
|
||||||
|
std::optional<JsonPathType> path_type{std::nullopt};
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T> class JsonCallbackResult {
|
||||||
|
private:
|
||||||
|
template <typename V> struct is_optional : std::false_type {};
|
||||||
|
|
||||||
|
template <typename V> struct is_optional<std::optional<V>> : std::true_type {};
|
||||||
|
|
||||||
|
public:
|
||||||
|
using SavingOrder = CallbackResultOptions::SavingOrder;
|
||||||
|
using OnEmpty = CallbackResultOptions::OnEmpty;
|
||||||
|
|
||||||
|
JsonCallbackResult() = default;
|
||||||
|
|
||||||
|
explicit JsonCallbackResult(CallbackResultOptions options);
|
||||||
|
|
||||||
|
void AddValue(T value);
|
||||||
|
|
||||||
|
bool Empty() const;
|
||||||
|
|
||||||
|
bool IsV1() const;
|
||||||
|
const T& AsV1() const;
|
||||||
|
const auto& AsV2() const;
|
||||||
|
|
||||||
|
bool ShouldSendNil() const;
|
||||||
|
bool ShouldSendWrongType() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<T> result_;
|
||||||
|
CallbackResultOptions options_{OnEmpty::kSendWrongType, SavingOrder::kSaveLast,
|
||||||
|
kDefaultJsonPathType};
|
||||||
|
};
|
||||||
|
|
||||||
|
class WrappedJsonPath {
|
||||||
|
public:
|
||||||
|
static constexpr std::string_view kV1PathRootElement = ".";
|
||||||
|
static constexpr std::string_view kV2PathRootElement = "$";
|
||||||
|
|
||||||
|
WrappedJsonPath(json::Path json_path, StringOrView path, JsonPathType path_type);
|
||||||
|
|
||||||
|
WrappedJsonPath(JsonExpression expression, StringOrView path, JsonPathType path_type);
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
JsonCallbackResult<T> ExecuteReadOnlyCallback(const JsonType* json_entry,
|
||||||
|
JsonPathReadOnlyCallback<T> cb,
|
||||||
|
CallbackResultOptions options) const;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
OpResult<JsonCallbackResult<std::optional<T>>> ExecuteMutateCallback(
|
||||||
|
JsonType* json_entry, JsonPathMutateCallback<T> cb, CallbackResultOptions options) const;
|
||||||
|
|
||||||
|
bool IsLegacyModePath() const;
|
||||||
|
|
||||||
|
bool RefersToRootElement() const;
|
||||||
|
|
||||||
|
// Returns true if this is internal implementation of json path
|
||||||
|
// Check AsJsonPath
|
||||||
|
bool HoldsJsonPath() const;
|
||||||
|
|
||||||
|
// Internal implementation of json path
|
||||||
|
const json::Path& AsJsonPath() const;
|
||||||
|
// Jsoncons implementation of json path
|
||||||
|
const JsonExpression& AsJsonExpression() const;
|
||||||
|
|
||||||
|
// Returns the path as a string_view.
|
||||||
|
std::string_view Path() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
CallbackResultOptions InitializePathType(CallbackResultOptions options) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::variant<json::Path, JsonExpression> parsed_path_;
|
||||||
|
StringOrView path_;
|
||||||
|
JsonPathType path_type_ = kDefaultJsonPathType;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Implementation
|
||||||
|
/******************************************************************/
|
||||||
namespace details {
|
namespace details {
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
@ -57,234 +152,177 @@ template <typename T> void OptionalEmplace(bool keep_defined, T src, T* dest) {
|
||||||
|
|
||||||
} // namespace details
|
} // namespace details
|
||||||
|
|
||||||
enum class JsonPathType { kV2, kLegacy /*Or V1*/ };
|
inline CallbackResultOptions CallbackResultOptions::DefaultReadOnlyOptions(
|
||||||
constexpr JsonPathType kDefaultJsonPathType = JsonPathType::kV2;
|
SavingOrder saving_order) {
|
||||||
|
return CallbackResultOptions{OnEmpty::kSendNil, saving_order};
|
||||||
|
}
|
||||||
|
|
||||||
struct CallbackResultOptions {
|
inline CallbackResultOptions CallbackResultOptions::DefaultMutateOptions() {
|
||||||
public:
|
return CallbackResultOptions{OnEmpty::kSendWrongType};
|
||||||
enum class SavingOrder { kSaveFirst, kSaveLast };
|
}
|
||||||
enum class OnEmpty { kSendNil, kSendWrongType };
|
|
||||||
|
|
||||||
// Default options for WrappedJsonPath::Evaluate
|
template <typename T>
|
||||||
static CallbackResultOptions DefaultEvaluateOptions() {
|
JsonCallbackResult<T>::JsonCallbackResult(CallbackResultOptions options) : options_(options) {
|
||||||
return CallbackResultOptions{OnEmpty::kSendNil};
|
}
|
||||||
|
|
||||||
|
template <typename T> void JsonCallbackResult<T>::AddValue(T value) {
|
||||||
|
if (result_.empty() || !IsV1()) {
|
||||||
|
result_.push_back(std::move(value));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static CallbackResultOptions DefaultEvaluateOptions(SavingOrder saving_order) {
|
details::OptionalEmplace(options_.saving_order == SavingOrder::kSaveFirst, std::move(value),
|
||||||
return {saving_order, OnEmpty::kSendNil};
|
&result_.front());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> bool JsonCallbackResult<T>::Empty() const {
|
||||||
|
return result_.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> bool JsonCallbackResult<T>::IsV1() const {
|
||||||
|
return options_.path_type == JsonPathType::kLegacy;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> const T& JsonCallbackResult<T>::AsV1() const {
|
||||||
|
return result_.front();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> const auto& JsonCallbackResult<T>::AsV2() const {
|
||||||
|
return result_;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> bool JsonCallbackResult<T>::ShouldSendNil() const {
|
||||||
|
return IsV1() && options_.on_empty == OnEmpty::kSendNil && result_.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T> bool JsonCallbackResult<T>::ShouldSendWrongType() const {
|
||||||
|
if (IsV1()) {
|
||||||
|
if (result_.empty() && options_.on_empty == OnEmpty::kSendWrongType)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if constexpr (is_optional<T>::value) {
|
||||||
|
return !result_.front().has_value();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline WrappedJsonPath::WrappedJsonPath(json::Path json_path, StringOrView path,
|
||||||
|
JsonPathType path_type)
|
||||||
|
: parsed_path_(std::move(json_path)), path_(std::move(path)), path_type_(path_type) {
|
||||||
|
}
|
||||||
|
|
||||||
|
inline WrappedJsonPath::WrappedJsonPath(JsonExpression expression, StringOrView path,
|
||||||
|
JsonPathType path_type)
|
||||||
|
: parsed_path_(std::move(expression)), path_(std::move(path)), path_type_(path_type) {
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
JsonCallbackResult<T> WrappedJsonPath::ExecuteReadOnlyCallback(
|
||||||
|
const JsonType* json_entry, JsonPathReadOnlyCallback<T> cb,
|
||||||
|
CallbackResultOptions options) const {
|
||||||
|
JsonCallbackResult<T> read_result{InitializePathType(options)};
|
||||||
|
|
||||||
|
auto eval_callback = [&cb, &read_result](std::string_view path, const JsonType& val) {
|
||||||
|
read_result.AddValue(cb(path, val));
|
||||||
|
};
|
||||||
|
|
||||||
|
if (HoldsJsonPath()) {
|
||||||
|
const auto& json_path = AsJsonPath();
|
||||||
|
json::EvaluatePath(json_path, *json_entry,
|
||||||
|
[&eval_callback](std::optional<std::string_view> key, const JsonType& val) {
|
||||||
|
eval_callback(key ? *key : std::string_view{}, val);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
const auto& json_expression = AsJsonExpression();
|
||||||
|
json_expression.evaluate(*json_entry, eval_callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default options for WrappedJsonPath::Mutate
|
return read_result;
|
||||||
static CallbackResultOptions DefaultMutateOptions() {
|
}
|
||||||
return CallbackResultOptions{OnEmpty::kSendWrongType};
|
|
||||||
}
|
|
||||||
|
|
||||||
explicit CallbackResultOptions(OnEmpty on_empty_) : on_empty(on_empty_) {
|
template <typename T>
|
||||||
}
|
OpResult<JsonCallbackResult<std::optional<T>>> WrappedJsonPath::ExecuteMutateCallback(
|
||||||
|
JsonType* json_entry, JsonPathMutateCallback<T> cb, CallbackResultOptions options) const {
|
||||||
|
JsonCallbackResult<std::optional<T>> mutate_result{InitializePathType(options)};
|
||||||
|
|
||||||
CallbackResultOptions(JsonPathType path_type_, SavingOrder saving_order_, OnEmpty on_empty_)
|
auto mutate_callback = [&cb, &mutate_result](std::optional<std::string_view> path,
|
||||||
: path_type(path_type_), saving_order(saving_order_), on_empty(on_empty_) {
|
JsonType* val) -> bool {
|
||||||
}
|
auto res = cb(path, val);
|
||||||
|
if (res.value.has_value()) {
|
||||||
|
mutate_result.AddValue(std::move(res.value).value());
|
||||||
|
} else if (!mutate_result.IsV1()) {
|
||||||
|
mutate_result.AddValue(std::nullopt);
|
||||||
|
}
|
||||||
|
return res.should_be_deleted;
|
||||||
|
};
|
||||||
|
|
||||||
std::optional<JsonPathType> path_type;
|
if (HoldsJsonPath()) {
|
||||||
SavingOrder saving_order{SavingOrder::kSaveLast};
|
const auto& json_path = AsJsonPath();
|
||||||
OnEmpty on_empty;
|
json::MutatePath(json_path, mutate_callback, json_entry);
|
||||||
|
} else {
|
||||||
|
using namespace jsoncons::jsonpath;
|
||||||
|
using namespace jsoncons::jsonpath::detail;
|
||||||
|
using Evaluator = jsonpath_evaluator<JsonType, JsonType&>;
|
||||||
|
using ValueType = Evaluator::value_type;
|
||||||
|
using Reference = Evaluator::reference;
|
||||||
|
using JsonSelector = Evaluator::path_expression_type;
|
||||||
|
|
||||||
private:
|
custom_functions<JsonType> funcs = custom_functions<JsonType>();
|
||||||
CallbackResultOptions(SavingOrder saving_order_, OnEmpty on_empty_)
|
|
||||||
: saving_order(saving_order_), on_empty(on_empty_) {
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T> class JsonCallbackResult {
|
std::error_code ec;
|
||||||
template <typename V> struct is_optional : std::false_type {};
|
static_resources<ValueType, Reference> static_resources(funcs);
|
||||||
|
Evaluator e;
|
||||||
|
|
||||||
template <typename V> struct is_optional<std::optional<V>> : std::true_type {};
|
JsonSelector expr = e.compile(static_resources, path_.view(), ec);
|
||||||
|
if (ec) {
|
||||||
public:
|
VLOG(1) << "Failed to mutate json with error: " << ec.message();
|
||||||
using SavingOrder = CallbackResultOptions::SavingOrder;
|
return OpStatus::SYNTAX_ERR;
|
||||||
using OnEmpty = CallbackResultOptions::OnEmpty;
|
|
||||||
|
|
||||||
JsonCallbackResult()
|
|
||||||
: options_(kDefaultJsonPathType, SavingOrder::kSaveLast, OnEmpty::kSendWrongType) {
|
|
||||||
}
|
|
||||||
|
|
||||||
explicit JsonCallbackResult(CallbackResultOptions options) : options_(options) {
|
|
||||||
}
|
|
||||||
|
|
||||||
void AddValue(T value) {
|
|
||||||
if (result_.empty() || !IsV1()) {
|
|
||||||
result_.push_back(std::move(value));
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
details::OptionalEmplace(options_.saving_order == SavingOrder::kSaveFirst, std::move(value),
|
dynamic_resources<ValueType, Reference> resources;
|
||||||
&result_.front());
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsV1() const {
|
auto f = [&mutate_callback](const basic_path_node<char>& path, JsonType& val) {
|
||||||
return options_.path_type == JsonPathType::kLegacy;
|
mutate_callback(to_string(path), &val);
|
||||||
}
|
|
||||||
|
|
||||||
const T& AsV1() const {
|
|
||||||
return result_.front();
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto& AsV2() const {
|
|
||||||
return result_;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Empty() const {
|
|
||||||
return result_.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ShouldSendNil() const {
|
|
||||||
return IsV1() && options_.on_empty == OnEmpty::kSendNil && result_.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ShouldSendWrongType() const {
|
|
||||||
if (IsV1()) {
|
|
||||||
if (result_.empty() && options_.on_empty == OnEmpty::kSendWrongType)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
if constexpr (is_optional<T>::value) {
|
|
||||||
return !result_.front().has_value();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::vector<T> result_;
|
|
||||||
CallbackResultOptions options_;
|
|
||||||
};
|
|
||||||
|
|
||||||
class WrappedJsonPath {
|
|
||||||
public:
|
|
||||||
static constexpr std::string_view kV1PathRootElement = ".";
|
|
||||||
static constexpr std::string_view kV2PathRootElement = "$";
|
|
||||||
|
|
||||||
WrappedJsonPath(json::Path json_path, StringOrView path, JsonPathType path_type)
|
|
||||||
: parsed_path_(std::move(json_path)), path_(std::move(path)), path_type_(path_type) {
|
|
||||||
}
|
|
||||||
|
|
||||||
WrappedJsonPath(JsonExpression expression, StringOrView path, JsonPathType path_type)
|
|
||||||
: parsed_path_(std::move(expression)), path_(std::move(path)), path_type_(path_type) {
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
JsonCallbackResult<T> Evaluate(const JsonType* json_entry, JsonPathEvaluateCallback<T> cb,
|
|
||||||
CallbackResultOptions options) const {
|
|
||||||
JsonCallbackResult<T> eval_result{InitializePathType(options)};
|
|
||||||
|
|
||||||
auto eval_callback = [&cb, &eval_result](std::string_view path, const JsonType& val) {
|
|
||||||
eval_result.AddValue(cb(path, val));
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (HoldsJsonPath()) {
|
expr.evaluate(resources, *json_entry, JsonSelector::path_node_type{}, *json_entry, std::move(f),
|
||||||
const auto& json_path = AsJsonPath();
|
result_options::nodups | result_options::path);
|
||||||
json::EvaluatePath(
|
|
||||||
json_path, *json_entry,
|
|
||||||
[&eval_callback](std::optional<std::string_view> key, const JsonType& val) {
|
|
||||||
eval_callback(key ? *key : std::string_view{}, val);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
const auto& json_expression = AsJsonExpression();
|
|
||||||
json_expression.evaluate(*json_entry, eval_callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
return eval_result;
|
|
||||||
}
|
}
|
||||||
|
return mutate_result;
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T>
|
inline bool WrappedJsonPath::IsLegacyModePath() const {
|
||||||
OpResult<JsonCallbackResult<std::optional<T>>> Mutate(JsonType* json_entry,
|
return path_type_ == JsonPathType::kLegacy;
|
||||||
JsonPathMutateCallback<T> cb,
|
}
|
||||||
CallbackResultOptions options) const {
|
|
||||||
JsonCallbackResult<std::optional<T>> mutate_result{InitializePathType(options)};
|
|
||||||
|
|
||||||
auto mutate_callback = [&cb, &mutate_result](std::optional<std::string_view> path,
|
inline bool WrappedJsonPath::RefersToRootElement() const {
|
||||||
JsonType* val) -> bool {
|
auto path = path_.view();
|
||||||
auto res = cb(path, val);
|
return path.empty() || path == kV1PathRootElement || path == kV2PathRootElement;
|
||||||
if (res.value.has_value()) {
|
}
|
||||||
mutate_result.AddValue(std::move(res.value).value());
|
|
||||||
} else if (!mutate_result.IsV1()) {
|
|
||||||
mutate_result.AddValue(std::nullopt);
|
|
||||||
}
|
|
||||||
return res.should_be_deleted;
|
|
||||||
};
|
|
||||||
|
|
||||||
if (HoldsJsonPath()) {
|
inline bool WrappedJsonPath::HoldsJsonPath() const {
|
||||||
const auto& json_path = AsJsonPath();
|
return std::holds_alternative<json::Path>(parsed_path_);
|
||||||
json::MutatePath(json_path, mutate_callback, json_entry);
|
}
|
||||||
} else {
|
|
||||||
using namespace jsoncons::jsonpath;
|
|
||||||
using namespace jsoncons::jsonpath::detail;
|
|
||||||
using Evaluator = jsonpath_evaluator<JsonType, JsonType&>;
|
|
||||||
using ValueType = Evaluator::value_type;
|
|
||||||
using Reference = Evaluator::reference;
|
|
||||||
using JsonSelector = Evaluator::path_expression_type;
|
|
||||||
|
|
||||||
custom_functions<JsonType> funcs = custom_functions<JsonType>();
|
inline const json::Path& WrappedJsonPath::AsJsonPath() const {
|
||||||
|
return std::get<json::Path>(parsed_path_);
|
||||||
|
}
|
||||||
|
|
||||||
std::error_code ec;
|
inline const JsonExpression& WrappedJsonPath::AsJsonExpression() const {
|
||||||
static_resources<ValueType, Reference> static_resources(funcs);
|
return std::get<JsonExpression>(parsed_path_);
|
||||||
Evaluator e;
|
}
|
||||||
|
|
||||||
JsonSelector expr = e.compile(static_resources, path_.view(), ec);
|
inline std::string_view WrappedJsonPath::Path() const {
|
||||||
if (ec) {
|
return path_.view();
|
||||||
VLOG(1) << "Failed to mutate json with error: " << ec.message();
|
}
|
||||||
return OpStatus::SYNTAX_ERR;
|
|
||||||
}
|
|
||||||
|
|
||||||
dynamic_resources<ValueType, Reference> resources;
|
inline CallbackResultOptions WrappedJsonPath::InitializePathType(
|
||||||
|
CallbackResultOptions options) const {
|
||||||
auto f = [&mutate_callback](const basic_path_node<char>& path, JsonType& val) {
|
if (!options.path_type) {
|
||||||
mutate_callback(to_string(path), &val);
|
options.path_type = path_type_;
|
||||||
};
|
|
||||||
|
|
||||||
expr.evaluate(resources, *json_entry, JsonSelector::path_node_type{}, *json_entry,
|
|
||||||
std::move(f), result_options::nodups | result_options::path);
|
|
||||||
}
|
|
||||||
return mutate_result;
|
|
||||||
}
|
}
|
||||||
|
return options;
|
||||||
bool IsLegacyModePath() const {
|
}
|
||||||
return path_type_ == JsonPathType::kLegacy;
|
|
||||||
}
|
|
||||||
|
|
||||||
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_);
|
|
||||||
}
|
|
||||||
|
|
||||||
const json::Path& AsJsonPath() const {
|
|
||||||
return std::get<json::Path>(parsed_path_);
|
|
||||||
}
|
|
||||||
|
|
||||||
const JsonExpression& AsJsonExpression() const {
|
|
||||||
return std::get<JsonExpression>(parsed_path_);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string_view Path() const {
|
|
||||||
return path_.view();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
CallbackResultOptions InitializePathType(CallbackResultOptions options) const {
|
|
||||||
if (!options.path_type) {
|
|
||||||
options.path_type = path_type_;
|
|
||||||
}
|
|
||||||
return options;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::variant<json::Path, JsonExpression> parsed_path_;
|
|
||||||
StringOrView path_;
|
|
||||||
JsonPathType path_type_ = kDefaultJsonPathType;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace dfly
|
} // namespace dfly
|
||||||
|
|
|
@ -404,17 +404,6 @@ string JsonTypeToName(const JsonType& val) {
|
||||||
return std::string{};
|
return std::string{};
|
||||||
}
|
}
|
||||||
|
|
||||||
OpResult<JsonType*> GetJson(const OpArgs& op_args, string_view key) {
|
|
||||||
auto it_res = op_args.GetDbSlice().FindReadOnly(op_args.db_cntx, key, OBJ_JSON);
|
|
||||||
if (!it_res.ok())
|
|
||||||
return it_res.status();
|
|
||||||
|
|
||||||
JsonType* json_val = it_res.value()->second.GetJson();
|
|
||||||
DCHECK(json_val) << "should have a valid JSON object for key " << key;
|
|
||||||
|
|
||||||
return json_val;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns the index of the next right bracket
|
// Returns the index of the next right bracket
|
||||||
OptSize GetNextIndex(string_view str) {
|
OptSize GetNextIndex(string_view str) {
|
||||||
size_t current_idx = 0;
|
size_t current_idx = 0;
|
||||||
|
@ -593,25 +582,31 @@ size_t CountJsonFields(const JsonType& j) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct EvaluateOperationOptions {
|
struct ReadOnlyOperationOptions {
|
||||||
bool return_nil_if_key_not_found = false;
|
bool return_nil_if_key_not_found = false;
|
||||||
CallbackResultOptions cb_result_options = CallbackResultOptions::DefaultEvaluateOptions();
|
CallbackResultOptions cb_result_options = CallbackResultOptions::DefaultReadOnlyOptions();
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
OpResult<JsonCallbackResult<T>> JsonEvaluateOperation(const OpArgs& op_args, std::string_view key,
|
OpResult<JsonCallbackResult<T>> JsonReadOnlyOperation(const OpArgs& op_args, std::string_view key,
|
||||||
const WrappedJsonPath& json_path,
|
const WrappedJsonPath& json_path,
|
||||||
JsonPathEvaluateCallback<T> cb,
|
JsonPathReadOnlyCallback<T> cb,
|
||||||
EvaluateOperationOptions options = {}) {
|
ReadOnlyOperationOptions options = {}) {
|
||||||
OpResult<JsonType*> result = GetJson(op_args, key);
|
auto it_res = op_args.GetDbSlice().FindReadOnly(op_args.db_cntx, key, OBJ_JSON);
|
||||||
if (options.return_nil_if_key_not_found && result == OpStatus::KEY_NOTFOUND) {
|
|
||||||
return JsonCallbackResult<T>{
|
if (!it_res) {
|
||||||
{JsonPathType::kLegacy, options.cb_result_options.saving_order,
|
if (options.return_nil_if_key_not_found && it_res == OpStatus::KEY_NOTFOUND) {
|
||||||
CallbackResultOptions::OnEmpty::kSendNil}}; // set legacy mode to return nil
|
return JsonCallbackResult<T>{{CallbackResultOptions::OnEmpty::kSendNil,
|
||||||
|
options.cb_result_options.saving_order,
|
||||||
|
JsonPathType::kLegacy}}; // set legacy mode to return nil
|
||||||
|
}
|
||||||
|
return it_res.status();
|
||||||
}
|
}
|
||||||
|
|
||||||
RETURN_ON_BAD_STATUS(result);
|
JsonType* json_val = it_res.value()->second.GetJson();
|
||||||
return json_path.Evaluate<T>(*result, cb, options.cb_result_options);
|
DCHECK(json_val) << "should have a valid JSON object for key " << key;
|
||||||
|
|
||||||
|
return json_path.ExecuteReadOnlyCallback<T>(json_val, cb, options.cb_result_options);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct MutateOperationOptions {
|
struct MutateOperationOptions {
|
||||||
|
@ -640,7 +635,7 @@ OpResult<JsonCallbackResult<optional<T>>> JsonMutateOperation(const OpArgs& op_a
|
||||||
|
|
||||||
op_args.shard->search_indices()->RemoveDoc(key, op_args.db_cntx, pv);
|
op_args.shard->search_indices()->RemoveDoc(key, op_args.db_cntx, pv);
|
||||||
|
|
||||||
auto mutate_res = json_path.Mutate(json_val, cb, options.cb_result_options);
|
auto mutate_res = json_path.ExecuteMutateCallback(json_val, cb, options.cb_result_options);
|
||||||
|
|
||||||
// Call post mutate callback
|
// Call post mutate callback
|
||||||
if (mutate_res && options.post_mutate_cb) {
|
if (mutate_res && options.post_mutate_cb) {
|
||||||
|
@ -719,11 +714,11 @@ OpResult<std::string> OpJsonGet(const OpArgs& op_args, string_view key,
|
||||||
auto cb = [](std::string_view, const JsonType& val) { return val; };
|
auto cb = [](std::string_view, const JsonType& val) { return val; };
|
||||||
|
|
||||||
const bool legacy_mode_is_enabled = LegacyModeIsEnabled(paths);
|
const bool legacy_mode_is_enabled = LegacyModeIsEnabled(paths);
|
||||||
CallbackResultOptions cb_options = CallbackResultOptions::DefaultEvaluateOptions();
|
CallbackResultOptions cb_options = CallbackResultOptions::DefaultReadOnlyOptions();
|
||||||
cb_options.path_type = legacy_mode_is_enabled ? JsonPathType::kLegacy : JsonPathType::kV2;
|
cb_options.path_type = legacy_mode_is_enabled ? JsonPathType::kLegacy : JsonPathType::kV2;
|
||||||
|
|
||||||
auto eval_wrapped = [&](const WrappedJsonPath& json_path) -> std::optional<JsonType> {
|
auto eval_wrapped = [&](const WrappedJsonPath& json_path) -> std::optional<JsonType> {
|
||||||
auto eval_result = json_path.Evaluate<JsonType>(&json_entry, cb, cb_options);
|
auto eval_result = json_path.ExecuteReadOnlyCallback<JsonType>(&json_entry, cb, cb_options);
|
||||||
|
|
||||||
DCHECK(legacy_mode_is_enabled == eval_result.IsV1());
|
DCHECK(legacy_mode_is_enabled == eval_result.IsV1());
|
||||||
|
|
||||||
|
@ -764,7 +759,7 @@ auto OpType(const OpArgs& op_args, string_view key, const WrappedJsonPath& json_
|
||||||
auto cb = [](const string_view&, const JsonType& val) -> std::string {
|
auto cb = [](const string_view&, const JsonType& val) -> std::string {
|
||||||
return JsonTypeToName(val);
|
return JsonTypeToName(val);
|
||||||
};
|
};
|
||||||
return JsonEvaluateOperation<std::string>(op_args, key, json_path, std::move(cb), {true});
|
return JsonReadOnlyOperation<std::string>(op_args, key, json_path, std::move(cb), {true});
|
||||||
}
|
}
|
||||||
|
|
||||||
OpResult<JsonCallbackResult<OptSize>> OpStrLen(const OpArgs& op_args, string_view key,
|
OpResult<JsonCallbackResult<OptSize>> OpStrLen(const OpArgs& op_args, string_view key,
|
||||||
|
@ -776,9 +771,9 @@ OpResult<JsonCallbackResult<OptSize>> OpStrLen(const OpArgs& op_args, string_vie
|
||||||
return nullopt;
|
return nullopt;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return JsonEvaluateOperation<OptSize>(
|
return JsonReadOnlyOperation<OptSize>(
|
||||||
op_args, key, json_path, std::move(cb),
|
op_args, key, json_path, std::move(cb),
|
||||||
{true, CallbackResultOptions::DefaultEvaluateOptions(SavingOrder::kSaveFirst)});
|
{true, CallbackResultOptions::DefaultReadOnlyOptions(SavingOrder::kSaveFirst)});
|
||||||
}
|
}
|
||||||
|
|
||||||
OpResult<JsonCallbackResult<OptSize>> OpObjLen(const OpArgs& op_args, string_view key,
|
OpResult<JsonCallbackResult<OptSize>> OpObjLen(const OpArgs& op_args, string_view key,
|
||||||
|
@ -790,10 +785,10 @@ OpResult<JsonCallbackResult<OptSize>> OpObjLen(const OpArgs& op_args, string_vie
|
||||||
return nullopt;
|
return nullopt;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return JsonEvaluateOperation<OptSize>(
|
return JsonReadOnlyOperation<OptSize>(
|
||||||
op_args, key, json_path, std::move(cb),
|
op_args, key, json_path, std::move(cb),
|
||||||
{json_path.IsLegacyModePath(),
|
{json_path.IsLegacyModePath(),
|
||||||
CallbackResultOptions::DefaultEvaluateOptions(SavingOrder::kSaveFirst)});
|
CallbackResultOptions::DefaultReadOnlyOptions(SavingOrder::kSaveFirst)});
|
||||||
}
|
}
|
||||||
|
|
||||||
OpResult<JsonCallbackResult<OptSize>> OpArrLen(const OpArgs& op_args, string_view key,
|
OpResult<JsonCallbackResult<OptSize>> OpArrLen(const OpArgs& op_args, string_view key,
|
||||||
|
@ -805,9 +800,9 @@ OpResult<JsonCallbackResult<OptSize>> OpArrLen(const OpArgs& op_args, string_vie
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return JsonEvaluateOperation<OptSize>(
|
return JsonReadOnlyOperation<OptSize>(
|
||||||
op_args, key, json_path, std::move(cb),
|
op_args, key, json_path, std::move(cb),
|
||||||
{true, CallbackResultOptions::DefaultEvaluateOptions(SavingOrder::kSaveFirst)});
|
{true, CallbackResultOptions::DefaultReadOnlyOptions(SavingOrder::kSaveFirst)});
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
|
@ -973,8 +968,8 @@ OpResult<long> OpDel(const OpArgs& op_args, string_view key, string_view path,
|
||||||
return {};
|
return {};
|
||||||
};
|
};
|
||||||
|
|
||||||
auto res = json_path.Mutate<Nothing>(json_val, std::move(cb),
|
auto res = json_path.ExecuteMutateCallback<Nothing>(
|
||||||
CallbackResultOptions::DefaultMutateOptions());
|
json_val, std::move(cb), CallbackResultOptions::DefaultMutateOptions());
|
||||||
RETURN_ON_BAD_STATUS(res);
|
RETURN_ON_BAD_STATUS(res);
|
||||||
|
|
||||||
if (deletion_items.empty()) {
|
if (deletion_items.empty()) {
|
||||||
|
@ -1017,10 +1012,10 @@ auto OpObjKeys(const OpArgs& op_args, string_view key, const WrappedJsonPath& js
|
||||||
}
|
}
|
||||||
return vec;
|
return vec;
|
||||||
};
|
};
|
||||||
return JsonEvaluateOperation<StringVec>(
|
return JsonReadOnlyOperation<StringVec>(
|
||||||
op_args, key, json_path, std::move(cb),
|
op_args, key, json_path, std::move(cb),
|
||||||
{json_path.IsLegacyModePath(),
|
{json_path.IsLegacyModePath(),
|
||||||
CallbackResultOptions::DefaultEvaluateOptions(SavingOrder::kSaveFirst)});
|
CallbackResultOptions::DefaultReadOnlyOptions(SavingOrder::kSaveFirst)});
|
||||||
}
|
}
|
||||||
|
|
||||||
OpResult<JsonCallbackResult<OptSize>> OpStrAppend(const OpArgs& op_args, string_view key,
|
OpResult<JsonCallbackResult<OptSize>> OpStrAppend(const OpArgs& op_args, string_view key,
|
||||||
|
@ -1243,7 +1238,7 @@ auto OpArrIndex(const OpArgs& op_args, string_view key, const WrappedJsonPath& j
|
||||||
return pos;
|
return pos;
|
||||||
};
|
};
|
||||||
|
|
||||||
return JsonEvaluateOperation<std::optional<long>>(
|
return JsonReadOnlyOperation<std::optional<long>>(
|
||||||
op_args, key, json_path, std::move(cb),
|
op_args, key, json_path, std::move(cb),
|
||||||
{false, CallbackResultOptions{CallbackResultOptions::OnEmpty::kSendWrongType}});
|
{false, CallbackResultOptions{CallbackResultOptions::OnEmpty::kSendWrongType}});
|
||||||
}
|
}
|
||||||
|
@ -1270,8 +1265,8 @@ std::vector<std::optional<std::string>> OpJsonMGet(const WrappedJsonPath& json_p
|
||||||
|
|
||||||
auto eval_wrapped = [&json_val,
|
auto eval_wrapped = [&json_val,
|
||||||
&cb](const WrappedJsonPath& json_path) -> std::optional<JsonType> {
|
&cb](const WrappedJsonPath& json_path) -> std::optional<JsonType> {
|
||||||
auto eval_result = json_path.Evaluate<JsonType>(
|
auto eval_result = json_path.ExecuteReadOnlyCallback<JsonType>(
|
||||||
json_val, std::move(cb), CallbackResultOptions::DefaultEvaluateOptions());
|
json_val, std::move(cb), CallbackResultOptions::DefaultReadOnlyOptions());
|
||||||
|
|
||||||
if (eval_result.IsV1()) {
|
if (eval_result.IsV1()) {
|
||||||
if (eval_result.Empty())
|
if (eval_result.Empty())
|
||||||
|
@ -1306,13 +1301,13 @@ auto OpFields(const OpArgs& op_args, string_view key, const WrappedJsonPath& jso
|
||||||
auto cb = [](const string_view&, const JsonType& val) -> std::optional<std::size_t> {
|
auto cb = [](const string_view&, const JsonType& val) -> std::optional<std::size_t> {
|
||||||
return CountJsonFields(val);
|
return CountJsonFields(val);
|
||||||
};
|
};
|
||||||
return JsonEvaluateOperation<std::optional<std::size_t>>(op_args, key, json_path, std::move(cb));
|
return JsonReadOnlyOperation<std::optional<std::size_t>>(op_args, key, json_path, std::move(cb));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns json vector that represents the result of the json query.
|
// Returns json vector that represents the result of the json query.
|
||||||
auto OpResp(const OpArgs& op_args, string_view key, const WrappedJsonPath& json_path) {
|
auto OpResp(const OpArgs& op_args, string_view key, const WrappedJsonPath& json_path) {
|
||||||
auto cb = [](const string_view&, const JsonType& val) { return val; };
|
auto cb = [](const string_view&, const JsonType& val) { return val; };
|
||||||
return JsonEvaluateOperation<JsonType>(op_args, key, json_path, std::move(cb));
|
return JsonReadOnlyOperation<JsonType>(op_args, key, json_path, std::move(cb));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns boolean that represents the result of the operation.
|
// Returns boolean that represents the result of the operation.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue