JMESPath is a query language for JSON.
Glaze currently has limited support for partial reading with JMESPath. Broader support will be added in the future.
- Compile time evaluated JMESPath expressions offer excellent performance.
Example:
struct Person
{
std::string first_name{};
std::string last_name{};
uint16_t age{};
};
struct Family
{
Person father{};
Person mother{};
std::vector<Person> children{};
};
struct Home
{
Family family{};
std::string address{};
};
suite jmespath_read_at_tests = [] {
"compile-time read_jmespath"_test = [] {
Home home{.family = {.father = {"Gilbert", "Fox", 28},
.mother = {"Anne", "Fox", 30},
.children = {{"Lilly"}, {"Vincent"}}}};
std::string buffer{};
expect(not glz::write_json(home, buffer));
std::string first_name{};
auto ec = glz::read_jmespath<"family.father.first_name">(first_name, buffer);
expect(not ec) << glz::format_error(ec, buffer);
expect(first_name == "Gilbert");
Person child{};
expect(not glz::read_jmespath<"family.children[0]">(child, buffer));
expect(child.first_name == "Lilly");
expect(not glz::read_jmespath<"family.children[1]">(child, buffer));
expect(child.first_name == "Vincent");
};
"run-time read_jmespath"_test = [] {
Home home{.family = {.father = {"Gilbert", "Fox", 28},
.mother = {"Anne", "Fox", 30},
.children = {{"Lilly"}, {"Vincent"}}}};
std::string buffer{};
expect(not glz::write_json(home, buffer));
std::string first_name{};
auto ec = glz::read_jmespath("family.father.first_name", first_name, buffer);
expect(not ec) << glz::format_error(ec, buffer);
expect(first_name == "Gilbert");
Person child{};
expect(not glz::read_jmespath("family.children[0]", child, buffer));
expect(child.first_name == "Lilly");
expect(not glz::read_jmespath("family.children[1]", child, buffer));
expect(child.first_name == "Vincent");
};
};
It can be expensive to tokenize at runtime. The runtime version of glz::read_jmespath
takes in a const glz::jmespath_expression&
. This allows expressions to be pre-computed, reused, and cached for better runtime performance.
Person child{};
// A runtime expression can be pre-computed and saved for more efficient lookups
glz::jmespath_expression expression{"family.children[0]"};
expect(not glz::read_jmespath(expression, child, buffer));
expect(child.first_name == "Lilly");
Note that this still works:
expect(not glz::read_jmespath("family.children[0]", child, buffer));
suite jmespath_slice_tests = [] {
"slice compile-time"_test = [] {
std::vector<int> data{0,1,2,3,4,5,6,7,8,9};
std::string buffer{};
expect(not glz::write_json(data, buffer));
std::vector<int> slice{};
expect(not glz::read_jmespath<"[0:5]">(slice, buffer));
expect(slice.size() == 5);
expect(slice[0] == 0);
expect(slice[1] == 1);
expect(slice[2] == 2);
expect(slice[3] == 3);
expect(slice[4] == 4);
};
"slice run-time"_test = [] {
std::vector<int> data{0,1,2,3,4,5,6,7,8,9};
std::string buffer{};
expect(not glz::write_json(data, buffer));
std::vector<int> slice{};
expect(not glz::read_jmespath("[0:5]", slice, buffer));
expect(slice.size() == 5);
expect(slice[0] == 0);
expect(slice[1] == 1);
expect(slice[2] == 2);
expect(slice[3] == 3);
expect(slice[4] == 4);
};
"slice compile-time multi-bracket"_test = [] {
std::vector<std::vector<int>> data{{1,2},{3,4,5},{6,7}};
std::string buffer{};
expect(not glz::write_json(data, buffer));
int v{};
expect(not glz::read_jmespath<"[1][2]">(v, buffer));
expect(v == 5);
};
"slice run-time multi-bracket"_test = [] {
std::vector<std::vector<int>> data{{1,2},{3,4,5},{6,7}};
std::string buffer{};
expect(not glz::write_json(data, buffer));
int v{};
expect(not glz::read_jmespath("[1][2]", v, buffer));
expect(v == 5);
};
};