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

JSON comparison, contains and operator& #1778

Closed
rafadesu opened this issue Oct 7, 2019 · 2 comments
Closed

JSON comparison, contains and operator& #1778

rafadesu opened this issue Oct 7, 2019 · 2 comments

Comments

@rafadesu
Copy link

rafadesu commented Oct 7, 2019

It would be nice to include as part of the library a way to compare JSON object in a way that the order is not important.

I though maybe defining operator&& to do it.

auto example1 = R("{
 "name": "Rafa",
 "age": 38,
 "hobbies": [ "windsurfing", "cards", { "name": "sailing", "difficulty": 4 } ]
}")_json;

if (R("{ "name": "Rafa", "hobbies": [ { "name": "sailing" }, "cards" ] }")_json && example1)
  std::cout << "example1 contains name: Rafa with hobbies sailing object and cards string\n";

//Or maybe nicer syntax:
if (example1.contains(R("{ "name": "Rafa", "hobbies": [ { "name": "sailing" }, "cards" ] }")_json))
  std::cout << "Yes, example1 contains the json object passed by parameter\n";

Obviously, this example is very simple but it could work with more complex objects.

This could be a very simplistic implementation:

operator&&(const json & lhs, const json & rhs)
{
  bool equal = false;

  if (lhs.type() == rhs.type())
  {
    if (lhs.is_array())
    {
      equal = true;
      for (const auto &lhs_item : lhs.items())
      {
        equal = false;
        for (const auto rhs_item : rhs.items())
        {
          if (lhs_item.value() && rhs_item.value())
          {
            equal = true;
            break;
          }
        }
        if (!equal) break;
      }
    }
    else if (lhs.is_object())
    {
      equal = true;
      for (const auto &item : lhs.items())
      {
        auto res = rhs.find(item.key());
        if ((res == rhs.end()) || (res->type() != item.value().type()) || !(item.value() && *res))
        {
          equal = false;
          break;
        }
      }
    }
    else
    {
      equal = (lhs == rhs);
    }
  }

  return equal;
}

Sorry, if I'm not using the library the best way. I have just started to use it today.

Instead of using the operators, it maybe nicer to extend the json object to have a .contains method (or several depending on parameters).

Also, it would be nice to consider providing options like "arrays might be in the same order" or take some considerations on duplicated keys, ...

I'd like to use this function for testing. For example, I want to know if the JSON returned by a function contains at least the keys I expect it to have even if it has more or in a different order and with the values and types I expect.

@nlohmann
Copy link
Owner

Some thoughts:

  • I do not like overloading operator&& as this would be really surprising behavior.
  • I think the usecase is really specific; as you demonstrated that it is possible to realize in client code, I do not see the need to add this to the library.

@rafadesu
Copy link
Author

I guess defining equality with JSON objets is very tricky. It would be useful if there was an RFC or something that defines first what is a useful way of comparing.

I first attempted to use the diff function to generate a patch and check only adds operations are generated but it is unfortunately not the minimum patch so that didn’t work.

I ended up creating a function instead of the operator and having a parameter to take the array order into account or not. That is sufficient for our needs at the moment.

I initially thought about the operator& but I really didn’t like the idea that much but
it makes me think though on what operations make sense with JSON objects like merging JSON objects by using operator+ etc.

Anyways, thank you for your feedback and consideration of the feature and, by the way, your library is really outstanding. Thank you for sharing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants