Skip to content
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

chore(fakeredis): Enable JSON tests in the Fakeredis tests #3773

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .github/workflows/test-fakeredis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ jobs:
run: |
poetry run pytest test/ \
--ignore test/test_hypothesis.py \
--ignore test/test_json/ \
--ignore test/test_mixins/test_bitmap_commands.py \
--junit-xml=results-tests.xml --html=report-tests.html -v
continue-on-error: true # For now to mark the flow as successful
Expand Down
36 changes: 24 additions & 12 deletions src/server/detail/wrapped_json_path.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,15 +61,22 @@ 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 };

CallbackResultOptions() = default;
// Default options for WrappedJsonPath::Evaluate
static CallbackResultOptions DefaultEvaluateOptions() {
return CallbackResultOptions{OnEmpty::kSendNil};
}

explicit CallbackResultOptions(JsonPathType path_type_) : path_type(path_type_) {
static CallbackResultOptions DefaultEvaluateOptions(SavingOrder saving_order) {
return {saving_order, OnEmpty::kSendNil};
}

explicit CallbackResultOptions(SavingOrder saving_order_) : saving_order(saving_order_) {
// Default options for WrappedJsonPath::Mutate
static CallbackResultOptions DefaultMutateOptions() {
return CallbackResultOptions{OnEmpty::kSendWrongType};
}

explicit CallbackResultOptions(OnEmpty on_empty_) : on_empty(on_empty_) {
Expand All @@ -79,9 +86,14 @@ struct CallbackResultOptions {
: path_type(path_type_), saving_order(saving_order_), on_empty(on_empty_) {
}

std::optional<JsonPathType> path_type = std::nullopt;
std::optional<JsonPathType> path_type;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see that all this values has const default values
kDefaultOnEmpty
and kDefaultJsonPathType
so why do we need to use std::optional?

SavingOrder saving_order{SavingOrder::kSaveLast};
OnEmpty on_empty{OnEmpty::kSendWrongType};
OnEmpty on_empty;

private:
CallbackResultOptions(SavingOrder saving_order_, OnEmpty on_empty_)
: saving_order(saving_order_), on_empty(on_empty_) {
}
};

template <typename T> class JsonCallbackResult {
Expand All @@ -93,10 +105,11 @@ template <typename T> class JsonCallbackResult {
using SavingOrder = CallbackResultOptions::SavingOrder;
using OnEmpty = CallbackResultOptions::OnEmpty;

JsonCallbackResult() {
JsonCallbackResult()
: options_(kDefaultJsonPathType, SavingOrder::kSaveLast, OnEmpty::kSendWrongType) {
}

explicit JsonCallbackResult(CallbackResultOptions options) : options_(std::move(options)) {
explicit JsonCallbackResult(CallbackResultOptions options) : options_(options) {
}

void AddValue(T value) {
Expand Down Expand Up @@ -143,7 +156,7 @@ template <typename T> class JsonCallbackResult {

private:
std::vector<T> result_;
CallbackResultOptions options_{kDefaultJsonPathType};
CallbackResultOptions options_;
};

class WrappedJsonPath {
Expand All @@ -161,9 +174,8 @@ class WrappedJsonPath {

template <typename T>
JsonCallbackResult<T> Evaluate(const JsonType* json_entry, JsonPathEvaluateCallback<T> cb,
CallbackResultOptions options = {}) const {
JsonCallbackResult<T> eval_result{{options.path_type.value_or(path_type_), options.saving_order,
CallbackResultOptions::OnEmpty::kSendNil}};
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));
Expand All @@ -187,7 +199,7 @@ class WrappedJsonPath {
template <typename T>
OpResult<JsonCallbackResult<std::optional<T>>> Mutate(JsonType* json_entry,
JsonPathMutateCallback<T> cb,
CallbackResultOptions options = {}) const {
CallbackResultOptions options) const {
JsonCallbackResult<std::optional<T>> mutate_result{InitializePathType(options)};

auto mutate_callback = [&cb, &mutate_result](std::optional<std::string_view> path,
Expand Down
47 changes: 25 additions & 22 deletions src/server/json_family.cc
Original file line number Diff line number Diff line change
Expand Up @@ -583,7 +583,7 @@ size_t CountJsonFields(const JsonType& j) {

struct EvaluateOperationOptions {
bool return_nil_if_key_not_found = false;
CallbackResultOptions cb_result_options;
CallbackResultOptions cb_result_options = CallbackResultOptions::DefaultEvaluateOptions();
};

template <typename T>
Expand All @@ -604,7 +604,7 @@ OpResult<JsonCallbackResult<T>> JsonEvaluateOperation(const OpArgs& op_args, std

struct MutateOperationOptions {
JsonReplaceVerify verify_op;
CallbackResultOptions cb_result_options;
CallbackResultOptions cb_result_options = CallbackResultOptions::DefaultMutateOptions();
};

template <typename T>
Expand Down Expand Up @@ -684,8 +684,8 @@ 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{legacy_mode_is_enabled ? JsonPathType::kLegacy
: JsonPathType::kV2};
CallbackResultOptions cb_options = CallbackResultOptions::DefaultEvaluateOptions();
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);
Expand Down Expand Up @@ -729,7 +729,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 JsonEvaluateOperation<std::string>(op_args, key, json_path, std::move(cb), {true});
}

OpResult<JsonCallbackResult<OptSize>> OpStrLen(const OpArgs& op_args, string_view key,
Expand All @@ -741,9 +741,9 @@ OpResult<JsonCallbackResult<OptSize>> OpStrLen(const OpArgs& op_args, string_vie
return nullopt;
}
};

return JsonEvaluateOperation<OptSize>(op_args, key, json_path, std::move(cb),
{true, CallbackResultOptions{SavingOrder::kSaveFirst}});
return JsonEvaluateOperation<OptSize>(
op_args, key, json_path, std::move(cb),
{true, CallbackResultOptions::DefaultEvaluateOptions(SavingOrder::kSaveFirst)});
}

OpResult<JsonCallbackResult<OptSize>> OpObjLen(const OpArgs& op_args, string_view key,
Expand All @@ -757,7 +757,8 @@ OpResult<JsonCallbackResult<OptSize>> OpObjLen(const OpArgs& op_args, string_vie
};
return JsonEvaluateOperation<OptSize>(
op_args, key, json_path, std::move(cb),
{json_path.IsLegacyModePath(), CallbackResultOptions{SavingOrder::kSaveFirst}});
{json_path.IsLegacyModePath(),
CallbackResultOptions::DefaultEvaluateOptions(SavingOrder::kSaveFirst)});
}

OpResult<JsonCallbackResult<OptSize>> OpArrLen(const OpArgs& op_args, string_view key,
Expand All @@ -769,8 +770,9 @@ OpResult<JsonCallbackResult<OptSize>> OpArrLen(const OpArgs& op_args, string_vie
return std::nullopt;
}
};
return JsonEvaluateOperation<OptSize>(op_args, key, json_path, std::move(cb),
{true, CallbackResultOptions{SavingOrder::kSaveFirst}});
return JsonEvaluateOperation<OptSize>(
op_args, key, json_path, std::move(cb),
{true, CallbackResultOptions::DefaultEvaluateOptions(SavingOrder::kSaveFirst)});
}

template <typename T>
Expand Down Expand Up @@ -930,7 +932,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));
auto res = json_path.Mutate<Nothing>(json_val, std::move(cb),
CallbackResultOptions::DefaultMutateOptions());
RETURN_ON_BAD_STATUS(res);

if (deletion_items.empty()) {
Expand Down Expand Up @@ -973,10 +976,10 @@ auto OpObjKeys(const OpArgs& op_args, string_view key, const WrappedJsonPath& js
}
return vec;
};

return JsonEvaluateOperation<StringVec>(
op_args, key, json_path, std::move(cb),
{json_path.IsLegacyModePath(), CallbackResultOptions{SavingOrder::kSaveFirst}});
{json_path.IsLegacyModePath(),
CallbackResultOptions::DefaultEvaluateOptions(SavingOrder::kSaveFirst)});
}

OpResult<JsonCallbackResult<OptSize>> OpStrAppend(const OpArgs& op_args, string_view key,
Expand All @@ -990,7 +993,6 @@ OpResult<JsonCallbackResult<OptSize>> OpStrAppend(const OpArgs& op_args, string_
*val = std::move(new_val);
return {false, len}; // do not delete, new value len
};

return JsonMutateOperation<size_t>(op_args, key, path, std::move(cb));
}

Expand Down Expand Up @@ -1045,9 +1047,8 @@ auto OpArrPop(const OpArgs& op_args, string_view key, WrappedJsonPath& path, int
val->erase(it);
return {false, std::move(str)};
};
return JsonMutateOperation<std::string>(
op_args, key, path, std::move(cb),
MutateOperationOptions{{}, CallbackResultOptions{OnEmpty::kSendNil}});
return JsonMutateOperation<std::string>(op_args, key, path, std::move(cb),
{{}, CallbackResultOptions{OnEmpty::kSendNil}});
}

// Returns numeric vector that represents the new length of the array at each path.
Expand Down Expand Up @@ -1201,7 +1202,9 @@ auto OpArrIndex(const OpArgs& op_args, string_view key, const WrappedJsonPath& j
return pos;
};

return JsonEvaluateOperation<std::optional<long>>(op_args, key, json_path, std::move(cb));
return JsonEvaluateOperation<std::optional<long>>(
op_args, key, json_path, std::move(cb),
{false, CallbackResultOptions{CallbackResultOptions::OnEmpty::kSendWrongType}});
}

// Returns string vector that represents the query result of each supplied key.
Expand All @@ -1226,7 +1229,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));
auto eval_result = json_path.Evaluate<JsonType>(
json_val, std::move(cb), CallbackResultOptions::DefaultEvaluateOptions());

if (eval_result.IsV1()) {
return eval_result.AsV1();
Expand Down Expand Up @@ -1259,7 +1263,6 @@ 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));
}

Expand Down Expand Up @@ -1359,7 +1362,7 @@ OpResult<bool> OpSet(const OpArgs& op_args, string_view key, string_view path,
// existing json keys use copy assign, so we don't really need to account for the memory
// allocated by ShardJsonFromString above since it's not being moved here at all.
auto res = JsonMutateOperation<Nothing>(op_args, key, json_path, std::move(cb),
MutateOperationOptions{std::move(inserter), {}});
MutateOperationOptions{std::move(inserter)});
RETURN_ON_BAD_STATUS(res);

return operation_result;
Expand Down
3 changes: 3 additions & 0 deletions src/server/json_family_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2342,6 +2342,9 @@ TEST_F(JsonFamilyTest, ArrIndexLegacy) {
resp = Run({"JSON.ARRINDEX", "json", ".children", R"("DoesNotExist")"});
EXPECT_THAT(resp, IntArg(-1));

resp = Run({"JSON.ARRINDEX", "json", ".children.[0].notexist", "3"});
EXPECT_THAT(resp.type, RespExpr::ERROR);

json = R"(
{"a":"b"}
)";
Expand Down
18 changes: 10 additions & 8 deletions tests/fakeredis/test/test_json/test_json_arr_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -210,14 +210,16 @@ def test_arrindex(r: redis.Redis):
},
)

assert r.json().get("store", "$.store.book[?(@.price<10)].size") == [
[10, 20, 30, 40],
[5, 10, 20, 30],
]
assert r.json().arrindex("store", "$.store.book[?(@.price<10)].size", "20") == [
-1,
-1,
]
# Temporary disable filter expressions tests
#
# assert r.json().get("store", "$.store.book[?(@.price<10)].size") == [
# [10, 20, 30, 40],
# [5, 10, 20, 30],
# ]
# assert r.json().arrindex("store", "$.store.book[?(@.price<10)].size", "20") == [
# -1,
# -1,
# ]

# Test index of int scalar in multi values
r.json().set(
Expand Down
Loading