Skip to content

Commit

Permalink
jsonpath use evaluate for update
Browse files Browse the repository at this point in the history
  • Loading branch information
danielaparker committed Nov 24, 2023
1 parent 587dde5 commit 5945f83
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 49 deletions.
52 changes: 15 additions & 37 deletions include/jsoncons_ext/jsonpath/expression.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3102,19 +3102,28 @@ namespace detail {

if (receiver.nodes.size() > 1)
{
if ((options & result_options::sort) == result_options::sort)
{
std::sort(receiver.nodes.begin(), receiver.nodes.end(), path_value_pair_less_type());
}
else if ((options & result_options::sort_descending) == result_options::sort_descending)
if ((options & result_options::sort_descending) == result_options::sort_descending)
{
std::sort(receiver.nodes.begin(), receiver.nodes.end(), path_value_pair_greater_type());
}
else if ((options & result_options::sort) == result_options::sort)
{
std::sort(receiver.nodes.begin(), receiver.nodes.end(), path_value_pair_less_type());
}
}

if (receiver.nodes.size() > 1 && (options & result_options::nodups) == result_options::nodups)
{
if ((options & result_options::sort) == result_options::sort)
if ((options & result_options::sort_descending) == result_options::sort_descending)
{
auto last = std::unique(receiver.nodes.rbegin(),receiver.nodes.rend(),path_value_pair_equal_type());
receiver.nodes.erase(receiver.nodes.begin(), last.base());
for (auto& node : receiver.nodes)
{
callback(node.path(), node.value());
}
}
else if ((options & result_options::sort) == result_options::sort)
{
auto last = std::unique(receiver.nodes.begin(),receiver.nodes.end(),path_value_pair_equal_type());
receiver.nodes.erase(last,receiver.nodes.end());
Expand Down Expand Up @@ -3162,37 +3171,6 @@ namespace detail {
}
}

template <class Callback>
typename std::enable_if<extension_traits::is_binary_function_object<Callback,const path_node_type&,reference>::value,void>::type
evaluate_with_replacement(dynamic_resources<Json,JsonReference>& resources,
reference root,
const path_node_type& path,
reference current,
Callback callback) const
{
std::error_code ec;

result_options options = result_options::path | result_options::nodups | result_options::sort;

path_value_receiver<Json,JsonReference> receiver{alloc_};
selector_->select(resources, root, path, current, receiver, options);

if (!receiver.nodes.empty())
{
if (receiver.nodes.size() > 1)
{
std::sort(receiver.nodes.begin(), receiver.nodes.end(), path_value_pair_less_type());
auto last = std::unique(receiver.nodes.begin(),receiver.nodes.end(),path_value_pair_equal_type());
receiver.nodes.erase(last,receiver.nodes.end());
}
for (std::size_t i = receiver.nodes.size(); i-- > 0;)
{
auto& node = receiver.nodes[i];
callback(node.path(), node.value());
}
}
}

std::string to_string(int level) const
{
std::string s;
Expand Down
9 changes: 4 additions & 5 deletions include/jsoncons_ext/jsonpath/json_location.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -548,13 +548,12 @@ namespace jsonpath {
using allocator_type = Allocator;
using string_view_type = jsoncons::basic_string_view<char_type, std::char_traits<char_type>>;
using value_type = basic_path_element<CharT,Allocator>;
using path_node_type = basic_path_node<CharT>;
using path_element_allocator_type = typename std::allocator_traits<allocator_type>:: template rebind_alloc<value_type>;
using const_iterator = typename std::vector<value_type>::const_iterator;
using iterator = const_iterator;
private:
using path_element_allocator_type = typename std::allocator_traits<allocator_type>:: template rebind_alloc<value_type>;
std::vector<value_type,path_element_allocator_type> elements_;
public:
using const_iterator = typename std::vector<value_type>::const_iterator;
using iterator = const_iterator;

basic_json_location(const allocator_type& alloc=Allocator())
: elements_(alloc)
Expand All @@ -564,7 +563,7 @@ namespace jsonpath {
explicit basic_json_location(const basic_path_node<char_type>& path, const allocator_type& alloc=Allocator())
: elements_(alloc)
{
const path_node_type* p_node = std::addressof(path);
auto p_node = std::addressof(path);
while (p_node != nullptr)
{
switch (p_node->node_kind())
Expand Down
16 changes: 11 additions & 5 deletions include/jsoncons_ext/jsonpath/json_query.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,9 @@ namespace jsonpath {
{
v = std::forward<T>(new_value);
};
expr.evaluate_with_replacement(resources, root_value, path_node_type{}, root_value, callback);

result_options options = result_options::nodups | result_options::path | result_options::sort_descending;
expr.evaluate(resources, root_value, path_node_type{}, root_value, callback, options);
}

template<class Json, class T, class TempAllocator>
Expand All @@ -124,7 +126,8 @@ namespace jsonpath {
{
v = Json(std::forward<T>(new_value), semantic_tag::none);
};
expr.evaluate_with_replacement(resources, root_value, path_node_type{}, root_value, callback);
result_options options = result_options::nodups | result_options::path | result_options::sort_descending;
expr.evaluate(resources, root_value, path_node_type{}, root_value, callback, options);
}

template<class Json, class BinaryCallback>
Expand All @@ -150,7 +153,8 @@ namespace jsonpath {
{
callback(to_basic_string(path), val);
};
expr.evaluate_with_replacement(resources, root_value, path_node_type{}, root_value, f);
result_options options = result_options::nodups | result_options::path | result_options::sort_descending;
expr.evaluate(resources, root_value, path_node_type{}, root_value, f, options);
}

template<class Json, class BinaryCallback, class TempAllocator>
Expand All @@ -177,7 +181,8 @@ namespace jsonpath {
{
callback(to_basic_string(path), val);
};
expr.evaluate_with_replacement(resources, root_value, path_node_type{}, root_value, f);
result_options options = result_options::nodups | result_options::path | result_options::sort_descending;
expr.evaluate(resources, root_value, path_node_type{}, root_value, f, options);
}

// Legacy replace function
Expand All @@ -202,7 +207,8 @@ namespace jsonpath {
{
v = callback(v);
};
expr.evaluate_with_replacement(resources, root_value, path_node_type{}, root_value, f);
result_options options = result_options::nodups | result_options::path | result_options::sort_descending;
expr.evaluate(resources, root_value, path_node_type{}, root_value, f, options);
}

} // namespace jsonpath
Expand Down
4 changes: 3 additions & 1 deletion include/jsoncons_ext/jsonpath/jsonpath_expression.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,9 @@ namespace jsonpath {
update(reference root_value, BinaryCallback callback) const
{
jsoncons::jsonpath::detail::dynamic_resources<value_type,reference> resources{alloc_};
expr_.evaluate_with_replacement(resources, root_value, path_node_type{}, root_value, callback);

result_options options = result_options::nodups | result_options::path | result_options::sort_descending;
expr_.evaluate(resources, root_value, path_node_type{}, root_value, callback, options);
}

std::vector<basic_json_location<char_type>> select_paths(const_reference root_value,
Expand Down
2 changes: 1 addition & 1 deletion test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ add_executable(unit_tests
jsonpath/src/json_location_parser_tests.cpp
jsonpath/src/jsonpath_custom_function_tests.cpp
jsonpath/src/jsonpath_json_query_tests.cpp
jsonpath/src/jsonpath_make_expression_tests.cpp
jsonpath/src/jsonpath_expression_tests.cpp
jsonpath/src/jsonpath_json_replace_tests.cpp
jsonpath/src/jsonpath_select_paths_tests.cpp
jsonpath/src/jsonpath_test_suite.cpp
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,62 @@ TEST_CASE("jsonpath_expression::select_path tests")
// std::cout << jsonpath::to_string(path) << "\n";
//}
}

SECTION("Return locations, nodups, sort_descending")
{
json root_value = json::parse(input);

auto expr = jsoncons::jsonpath::make_expression<json>("$.books[*]['category','category','title','title']");

std::vector<jsonpath::json_location> paths = expr.select_paths(root_value,jsonpath::result_options::nodups | jsonpath::result_options::sort_descending);

REQUIRE(paths.size() == 8);
CHECK(jsonpath::to_string(paths[0]) == "$['books'][3]['title']");
CHECK(jsonpath::to_string(paths[1]) == "$['books'][3]['category']");
CHECK(jsonpath::to_string(paths[2]) == "$['books'][2]['title']");
CHECK(jsonpath::to_string(paths[3]) == "$['books'][2]['category']");
CHECK(jsonpath::to_string(paths[4]) == "$['books'][1]['title']");
CHECK(jsonpath::to_string(paths[5]) == "$['books'][1]['category']");
CHECK(jsonpath::to_string(paths[6]) == "$['books'][0]['title']");
CHECK(jsonpath::to_string(paths[7]) == "$['books'][0]['category']");

//for (const auto& path : paths)
//{
// std::cout << jsonpath::to_string(path) << "\n";
//}
}

SECTION("Return locations, sort_descending")
{
json root_value = json::parse(input);

auto expr = jsoncons::jsonpath::make_expression<json>("$.books[*]['category','category','title','title']");

std::vector<jsonpath::json_location> paths = expr.select_paths(root_value, jsonpath::result_options::sort_descending);

REQUIRE(paths.size() == 16);
CHECK(jsonpath::to_string(paths[0]) == "$['books'][3]['title']");
CHECK(jsonpath::to_string(paths[1]) == "$['books'][3]['title']");
CHECK(jsonpath::to_string(paths[2]) == "$['books'][3]['category']");
CHECK(jsonpath::to_string(paths[3]) == "$['books'][3]['category']");
CHECK(jsonpath::to_string(paths[4]) == "$['books'][2]['title']");
CHECK(jsonpath::to_string(paths[5]) == "$['books'][2]['title']");
CHECK(jsonpath::to_string(paths[6]) == "$['books'][2]['category']");
CHECK(jsonpath::to_string(paths[7]) == "$['books'][2]['category']");
CHECK(jsonpath::to_string(paths[8]) == "$['books'][1]['title']");
CHECK(jsonpath::to_string(paths[9]) == "$['books'][1]['title']");
CHECK(jsonpath::to_string(paths[10]) == "$['books'][1]['category']");
CHECK(jsonpath::to_string(paths[11]) == "$['books'][1]['category']");
CHECK(jsonpath::to_string(paths[12]) == "$['books'][0]['title']");
CHECK(jsonpath::to_string(paths[13]) == "$['books'][0]['title']");
CHECK(jsonpath::to_string(paths[14]) == "$['books'][0]['category']");
CHECK(jsonpath::to_string(paths[15]) == "$['books'][0]['category']");

//for (const auto& path : paths)
//{
// std::cout << jsonpath::to_string(path) << "\n";
//}
}
}

TEST_CASE("jsonpath_expression::update tests")
Expand Down

0 comments on commit 5945f83

Please sign in to comment.