From 258f8562d244642dcd3fe7265414df8aaf4324af Mon Sep 17 00:00:00 2001 From: Daniel Parker Date: Tue, 21 Nov 2023 15:30:00 -0500 Subject: [PATCH] make_expression doc --- doc/ref/jsonpath/make_expression.md | 100 +++++++++++++++++- .../src/jsonpath_make_expression_tests.cpp | 42 ++++---- 2 files changed, 120 insertions(+), 22 deletions(-) diff --git a/doc/ref/jsonpath/make_expression.md b/doc/ref/jsonpath/make_expression.md index 2bcee95590..a1e7e57d91 100644 --- a/doc/ref/jsonpath/make_expression.md +++ b/doc/ref/jsonpath/make_expression.md @@ -21,7 +21,7 @@ jsonpath_expression make_expression(const Json::string_view_type& expr, ```cpp template jsonpath_expression make_expression(const Json::string_view_type& expr, - const custom_functions& funcs, std::error_code& ec); (3) (since 0.164.0) + const custom_functions& funcs, std::error_code& ec); (3) (since 0.164.0) ``` ```cpp template (4) (since 0.170.0) @@ -108,6 +108,12 @@ The examples below uses the sample data file `books.json`, #### Return copies ```cpp +#include +#include + +using json = jsoncons::json; +namespace jsonpath = jsoncons::jsonpath; + int main() { auto expr = jsonpath::make_expression("$.books[?(@.price > avg($.books[*].price))].title"); @@ -126,9 +132,85 @@ Output: ] ``` +#### Return locations of selected values (since 0.172.0) + +```cpp +#include +#include + +using json = jsoncons::json; +namespace jsonpath = jsoncons::jsonpath; + +int main() +{ + auto expr = jsoncons::jsonpath::make_expression("$.books[*]"); + + std::ifstream is("./input/books.json"); + json doc = json::parse(is); + + std::vector paths = expr.select_paths(doc); + for (const auto& path : paths) + { + std::cout << jsonpath::to_string(path) << "\n"; + } +} +``` +Output: +``` +[ + $['books'][0] + $['books'][1] + $['books'][2] + $['books'][3] +] +``` + +#### Update in place (since 0.172.0) + +```cpp +#include +#include + +using json = jsoncons::json; +namespace jsonpath = jsoncons::jsonpath; + +int main() +{ + auto expr = jsoncons::jsonpath::make_expression("$.books[*]"); + + std::ifstream is("./input/books.json"); + json doc = json::parse(is); + + auto callback = [](const jsonpath::path_node& /*location*/, json& book) + { + if (book.at("category") == "memoir" && !book.contains("price")) + { + book.try_emplace("price", 140.0); + } + }; + + expr.update(doc, callback); +} +``` +Output: +``` +{ + "author": "Phillips, David Atlee", + "category": "memoir", + "price": 140.0, + "title": "The Night Watch" +} +``` + #### Access path and reference to original value ```cpp +#include +#include + +using json = jsoncons::json; +namespace jsonpath = jsoncons::jsonpath; + int main() { auto expr = jsonpath::make_expression("$.books[?(@.price >= 22.0)]"); @@ -136,10 +218,18 @@ int main() std::ifstream is("./input/books.json"); json data = json::parse(is); - auto callback = [](const std::string& path, const json& val) + // legacy (deprecated in 0.172.0) + // auto callback = [](const std::string& path, const json& val) + // { + // std::cout << path << ": " << val << "\n"; + // }; + + // since 0.172.0 + auto callback = [](const jsonpath::path_node& path, const json& val) { - std::cout << path << ": " << val << "\n"; + std::cout << jsonpath::to_string(path) << ": " << val << "\n"; }; + expr.evaluate(data, callback, jsonpath::result_options::path); } ``` @@ -210,6 +300,8 @@ Output: using my_alloc = FreeListAllocator; // an allocator with a single-argument constructor using my_json = jsoncons::basic_json; +namespace jsonpath = jsoncons::jsonpath; + int main() { auto alloc = my_alloc(1); @@ -229,7 +321,7 @@ int main() my_json doc = decoder.get_result(); std::string_view p{"$.books[?(@.category == 'fiction')].title"}; - auto expr = jsoncons::jsonpath::make_expression(combine_allocators(alloc), p); + auto expr = jsonpath::make_expression(combine_allocators(alloc), p); auto result = expr.evaluate(doc); std::cout << pretty_print(result) << "\n\n"; diff --git a/test/jsonpath/src/jsonpath_make_expression_tests.cpp b/test/jsonpath/src/jsonpath_make_expression_tests.cpp index 825255a640..57e8da4e5f 100644 --- a/test/jsonpath/src/jsonpath_make_expression_tests.cpp +++ b/test/jsonpath/src/jsonpath_make_expression_tests.cpp @@ -74,23 +74,13 @@ TEST_CASE("jsonpath make_expression tests") CHECK_FALSE(doc["books"][3].contains("price")); } - SECTION("test 2") + SECTION("Update in place") { - int count = 0; - json doc = json::parse(input); auto expr = jsoncons::jsonpath::make_expression("$.books[*]"); - auto callback1 = [&](const jsonpath::path_node& /*location*/, const json& book) - { - if (book.at("category") == "memoir" && !book.contains("price")) - { - ++count; - } - }; - - auto callback2 = [](const jsonpath::path_node& /*location*/, json& book) + auto callback = [](const jsonpath::path_node& /*location*/, json& book) { if (book.at("category") == "memoir" && !book.contains("price")) { @@ -98,16 +88,31 @@ TEST_CASE("jsonpath make_expression tests") } }; - expr.select(doc, callback1); - - CHECK(count == 1); + expr.update(doc, callback); - CHECK_FALSE(doc["books"][3].contains("price")); - expr.update(doc, callback2); CHECK(doc["books"][3].contains("price")); CHECK(doc["books"][3].at("price") == 140); } + SECTION("Return locations of selected values") + { + json doc = json::parse(input); + + auto expr = jsoncons::jsonpath::make_expression("$.books[*]"); + + std::vector paths = expr.select_paths(doc); + + REQUIRE(paths.size() == 4); + CHECK(jsonpath::to_string(paths[0]) == "$['books'][0]"); + CHECK(jsonpath::to_string(paths[1]) == "$['books'][1]"); + CHECK(jsonpath::to_string(paths[2]) == "$['books'][2]"); + CHECK(jsonpath::to_string(paths[3]) == "$['books'][3]"); + //for (const auto& path : paths) + //{ + // std::cout << jsonpath::to_string(path) << "\n"; + //} + } + SECTION("update default sort order") { json doc = json::parse(input); @@ -168,6 +173,7 @@ TEST_CASE("jsonpath legacy make_expression test") int count = 0; const json doc = json::parse(input); + const json original = doc; auto expr = jsoncons::jsonpath::make_expression("$.books[*]"); @@ -182,7 +188,7 @@ TEST_CASE("jsonpath legacy make_expression test") expr.evaluate(doc, callback); CHECK(count == 1); - CHECK_FALSE(doc["books"][3].contains("price")); + CHECK(doc == original); } }