mirror of
https://github.com/dragonflydb/dragonfly.git
synced 2025-05-10 18:05:44 +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 JsonExpression = jsoncons::jsonpath::jsonpath_expression<JsonType>;
|
||||
|
||||
namespace details {
|
||||
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 {
|
||||
MutateCallbackResult() {
|
||||
}
|
||||
|
||||
MutateCallbackResult(bool should_be_deleted_, T value_)
|
||||
: should_be_deleted(should_be_deleted_), value(std::move(value_)) {
|
||||
}
|
||||
|
||||
bool should_be_deleted = false;
|
||||
std::optional<T> value;
|
||||
};
|
||||
|
@ -40,6 +40,101 @@ template <typename T>
|
|||
using JsonPathMutateCallback =
|
||||
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 {
|
||||
|
||||
template <typename T>
|
||||
|
@ -57,234 +152,177 @@ template <typename T> void OptionalEmplace(bool keep_defined, T src, T* dest) {
|
|||
|
||||
} // namespace details
|
||||
|
||||
enum class JsonPathType { kV2, kLegacy /*Or V1*/ };
|
||||
constexpr JsonPathType kDefaultJsonPathType = JsonPathType::kV2;
|
||||
inline CallbackResultOptions CallbackResultOptions::DefaultReadOnlyOptions(
|
||||
SavingOrder saving_order) {
|
||||
return CallbackResultOptions{OnEmpty::kSendNil, saving_order};
|
||||
}
|
||||
|
||||
struct CallbackResultOptions {
|
||||
public:
|
||||
enum class SavingOrder { kSaveFirst, kSaveLast };
|
||||
enum class OnEmpty { kSendNil, kSendWrongType };
|
||||
inline CallbackResultOptions CallbackResultOptions::DefaultMutateOptions() {
|
||||
return CallbackResultOptions{OnEmpty::kSendWrongType};
|
||||
}
|
||||
|
||||
// Default options for WrappedJsonPath::Evaluate
|
||||
static CallbackResultOptions DefaultEvaluateOptions() {
|
||||
return CallbackResultOptions{OnEmpty::kSendNil};
|
||||
template <typename T>
|
||||
JsonCallbackResult<T>::JsonCallbackResult(CallbackResultOptions options) : options_(options) {
|
||||
}
|
||||
|
||||
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) {
|
||||
return {saving_order, OnEmpty::kSendNil};
|
||||
details::OptionalEmplace(options_.saving_order == SavingOrder::kSaveFirst, std::move(value),
|
||||
&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
|
||||
static CallbackResultOptions DefaultMutateOptions() {
|
||||
return CallbackResultOptions{OnEmpty::kSendWrongType};
|
||||
}
|
||||
return read_result;
|
||||
}
|
||||
|
||||
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_)
|
||||
: path_type(path_type_), saving_order(saving_order_), on_empty(on_empty_) {
|
||||
}
|
||||
auto mutate_callback = [&cb, &mutate_result](std::optional<std::string_view> path,
|
||||
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;
|
||||
SavingOrder saving_order{SavingOrder::kSaveLast};
|
||||
OnEmpty on_empty;
|
||||
if (HoldsJsonPath()) {
|
||||
const auto& json_path = AsJsonPath();
|
||||
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:
|
||||
CallbackResultOptions(SavingOrder saving_order_, OnEmpty on_empty_)
|
||||
: saving_order(saving_order_), on_empty(on_empty_) {
|
||||
}
|
||||
};
|
||||
custom_functions<JsonType> funcs = custom_functions<JsonType>();
|
||||
|
||||
template <typename T> class JsonCallbackResult {
|
||||
template <typename V> struct is_optional : std::false_type {};
|
||||
std::error_code ec;
|
||||
static_resources<ValueType, Reference> static_resources(funcs);
|
||||
Evaluator e;
|
||||
|
||||
template <typename V> struct is_optional<std::optional<V>> : std::true_type {};
|
||||
|
||||
public:
|
||||
using SavingOrder = CallbackResultOptions::SavingOrder;
|
||||
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;
|
||||
JsonSelector expr = e.compile(static_resources, path_.view(), ec);
|
||||
if (ec) {
|
||||
VLOG(1) << "Failed to mutate json with error: " << ec.message();
|
||||
return OpStatus::SYNTAX_ERR;
|
||||
}
|
||||
|
||||
details::OptionalEmplace(options_.saving_order == SavingOrder::kSaveFirst, std::move(value),
|
||||
&result_.front());
|
||||
}
|
||||
dynamic_resources<ValueType, Reference> resources;
|
||||
|
||||
bool IsV1() const {
|
||||
return options_.path_type == JsonPathType::kLegacy;
|
||||
}
|
||||
|
||||
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));
|
||||
auto f = [&mutate_callback](const basic_path_node<char>& path, JsonType& val) {
|
||||
mutate_callback(to_string(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);
|
||||
}
|
||||
|
||||
return eval_result;
|
||||
expr.evaluate(resources, *json_entry, JsonSelector::path_node_type{}, *json_entry, std::move(f),
|
||||
result_options::nodups | result_options::path);
|
||||
}
|
||||
return mutate_result;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
OpResult<JsonCallbackResult<std::optional<T>>> Mutate(JsonType* json_entry,
|
||||
JsonPathMutateCallback<T> cb,
|
||||
CallbackResultOptions options) const {
|
||||
JsonCallbackResult<std::optional<T>> mutate_result{InitializePathType(options)};
|
||||
inline bool WrappedJsonPath::IsLegacyModePath() const {
|
||||
return path_type_ == JsonPathType::kLegacy;
|
||||
}
|
||||
|
||||
auto mutate_callback = [&cb, &mutate_result](std::optional<std::string_view> path,
|
||||
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;
|
||||
};
|
||||
inline bool WrappedJsonPath::RefersToRootElement() const {
|
||||
auto path = path_.view();
|
||||
return path.empty() || path == kV1PathRootElement || path == kV2PathRootElement;
|
||||
}
|
||||
|
||||
if (HoldsJsonPath()) {
|
||||
const auto& json_path = AsJsonPath();
|
||||
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;
|
||||
inline bool WrappedJsonPath::HoldsJsonPath() const {
|
||||
return std::holds_alternative<json::Path>(parsed_path_);
|
||||
}
|
||||
|
||||
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;
|
||||
static_resources<ValueType, Reference> static_resources(funcs);
|
||||
Evaluator e;
|
||||
inline const JsonExpression& WrappedJsonPath::AsJsonExpression() const {
|
||||
return std::get<JsonExpression>(parsed_path_);
|
||||
}
|
||||
|
||||
JsonSelector expr = e.compile(static_resources, path_.view(), ec);
|
||||
if (ec) {
|
||||
VLOG(1) << "Failed to mutate json with error: " << ec.message();
|
||||
return OpStatus::SYNTAX_ERR;
|
||||
}
|
||||
inline std::string_view WrappedJsonPath::Path() const {
|
||||
return path_.view();
|
||||
}
|
||||
|
||||
dynamic_resources<ValueType, Reference> resources;
|
||||
|
||||
auto f = [&mutate_callback](const basic_path_node<char>& path, JsonType& val) {
|
||||
mutate_callback(to_string(path), &val);
|
||||
};
|
||||
|
||||
expr.evaluate(resources, *json_entry, JsonSelector::path_node_type{}, *json_entry,
|
||||
std::move(f), result_options::nodups | result_options::path);
|
||||
}
|
||||
return mutate_result;
|
||||
inline CallbackResultOptions WrappedJsonPath::InitializePathType(
|
||||
CallbackResultOptions options) const {
|
||||
if (!options.path_type) {
|
||||
options.path_type = path_type_;
|
||||
}
|
||||
|
||||
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;
|
||||
};
|
||||
return options;
|
||||
}
|
||||
|
||||
} // namespace dfly
|
||||
|
|
|
@ -404,17 +404,6 @@ string JsonTypeToName(const JsonType& val) {
|
|||
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
|
||||
OptSize GetNextIndex(string_view str) {
|
||||
size_t current_idx = 0;
|
||||
|
@ -593,25 +582,31 @@ size_t CountJsonFields(const JsonType& j) {
|
|||
return res;
|
||||
}
|
||||
|
||||
struct EvaluateOperationOptions {
|
||||
struct ReadOnlyOperationOptions {
|
||||
bool return_nil_if_key_not_found = false;
|
||||
CallbackResultOptions cb_result_options = CallbackResultOptions::DefaultEvaluateOptions();
|
||||
CallbackResultOptions cb_result_options = CallbackResultOptions::DefaultReadOnlyOptions();
|
||||
};
|
||||
|
||||
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,
|
||||
JsonPathEvaluateCallback<T> cb,
|
||||
EvaluateOperationOptions options = {}) {
|
||||
OpResult<JsonType*> result = GetJson(op_args, key);
|
||||
if (options.return_nil_if_key_not_found && result == OpStatus::KEY_NOTFOUND) {
|
||||
return JsonCallbackResult<T>{
|
||||
{JsonPathType::kLegacy, options.cb_result_options.saving_order,
|
||||
CallbackResultOptions::OnEmpty::kSendNil}}; // set legacy mode to return nil
|
||||
JsonPathReadOnlyCallback<T> cb,
|
||||
ReadOnlyOperationOptions options = {}) {
|
||||
auto it_res = op_args.GetDbSlice().FindReadOnly(op_args.db_cntx, key, OBJ_JSON);
|
||||
|
||||
if (!it_res) {
|
||||
if (options.return_nil_if_key_not_found && it_res == OpStatus::KEY_NOTFOUND) {
|
||||
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);
|
||||
return json_path.Evaluate<T>(*result, cb, options.cb_result_options);
|
||||
JsonType* json_val = it_res.value()->second.GetJson();
|
||||
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 {
|
||||
|
@ -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);
|
||||
|
||||
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
|
||||
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; };
|
||||
|
||||
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;
|
||||
|
||||
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());
|
||||
|
||||
|
@ -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 {
|
||||
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,
|
||||
|
@ -776,9 +771,9 @@ OpResult<JsonCallbackResult<OptSize>> OpStrLen(const OpArgs& op_args, string_vie
|
|||
return nullopt;
|
||||
}
|
||||
};
|
||||
return JsonEvaluateOperation<OptSize>(
|
||||
return JsonReadOnlyOperation<OptSize>(
|
||||
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,
|
||||
|
@ -790,10 +785,10 @@ OpResult<JsonCallbackResult<OptSize>> OpObjLen(const OpArgs& op_args, string_vie
|
|||
return nullopt;
|
||||
}
|
||||
};
|
||||
return JsonEvaluateOperation<OptSize>(
|
||||
return JsonReadOnlyOperation<OptSize>(
|
||||
op_args, key, json_path, std::move(cb),
|
||||
{json_path.IsLegacyModePath(),
|
||||
CallbackResultOptions::DefaultEvaluateOptions(SavingOrder::kSaveFirst)});
|
||||
CallbackResultOptions::DefaultReadOnlyOptions(SavingOrder::kSaveFirst)});
|
||||
}
|
||||
|
||||
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 JsonEvaluateOperation<OptSize>(
|
||||
return JsonReadOnlyOperation<OptSize>(
|
||||
op_args, key, json_path, std::move(cb),
|
||||
{true, CallbackResultOptions::DefaultEvaluateOptions(SavingOrder::kSaveFirst)});
|
||||
{true, CallbackResultOptions::DefaultReadOnlyOptions(SavingOrder::kSaveFirst)});
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
|
@ -973,8 +968,8 @@ OpResult<long> OpDel(const OpArgs& op_args, string_view key, string_view path,
|
|||
return {};
|
||||
};
|
||||
|
||||
auto res = json_path.Mutate<Nothing>(json_val, std::move(cb),
|
||||
CallbackResultOptions::DefaultMutateOptions());
|
||||
auto res = json_path.ExecuteMutateCallback<Nothing>(
|
||||
json_val, std::move(cb), CallbackResultOptions::DefaultMutateOptions());
|
||||
RETURN_ON_BAD_STATUS(res);
|
||||
|
||||
if (deletion_items.empty()) {
|
||||
|
@ -1017,10 +1012,10 @@ auto OpObjKeys(const OpArgs& op_args, string_view key, const WrappedJsonPath& js
|
|||
}
|
||||
return vec;
|
||||
};
|
||||
return JsonEvaluateOperation<StringVec>(
|
||||
return JsonReadOnlyOperation<StringVec>(
|
||||
op_args, key, json_path, std::move(cb),
|
||||
{json_path.IsLegacyModePath(),
|
||||
CallbackResultOptions::DefaultEvaluateOptions(SavingOrder::kSaveFirst)});
|
||||
CallbackResultOptions::DefaultReadOnlyOptions(SavingOrder::kSaveFirst)});
|
||||
}
|
||||
|
||||
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 JsonEvaluateOperation<std::optional<long>>(
|
||||
return JsonReadOnlyOperation<std::optional<long>>(
|
||||
op_args, key, json_path, std::move(cb),
|
||||
{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,
|
||||
&cb](const WrappedJsonPath& json_path) -> std::optional<JsonType> {
|
||||
auto eval_result = json_path.Evaluate<JsonType>(
|
||||
json_val, std::move(cb), CallbackResultOptions::DefaultEvaluateOptions());
|
||||
auto eval_result = json_path.ExecuteReadOnlyCallback<JsonType>(
|
||||
json_val, std::move(cb), CallbackResultOptions::DefaultReadOnlyOptions());
|
||||
|
||||
if (eval_result.IsV1()) {
|
||||
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> {
|
||||
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.
|
||||
auto OpResp(const OpArgs& op_args, string_view key, const WrappedJsonPath& json_path) {
|
||||
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.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue