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

Create a [key:member_pointer] map to ease parsing custom types #471

Closed
fnc12 opened this issue Feb 25, 2017 · 4 comments
Closed

Create a [key:member_pointer] map to ease parsing custom types #471

fnc12 opened this issue Feb 25, 2017 · 4 comments

Comments

@fnc12
Copy link

fnc12 commented Feb 25, 2017

Once from_json and to_json functions overloading appeared in the lib it became easy to build and serialize custom classes from and to json. But it can be more easy if lib provide ability to create a map for each type with json keys strings and member pointers as values.

For example right now one have to write a code like this

Regions.h

#include <string>
#include <vector>
#include <json/json.hpp>

#include "City.hpp"

namespace DataModel {
    
    struct Region {
        std::string name;
        std::vector<City> cities;
    };
    
    using nlohmann::json;
    
    void to_json(json &j, const Region &o);
    
    void from_json(const json &j, Region &o);
}

Region.cpp

#include "Region.hpp"

namespace Keys {
    const std::string name = "name";
    const std::string cities = "cities";
}

void DataModel::to_json(json &j, const Region &o) {
    using namespace Keys;
    j = {
        { name, o.name },
        { cities, o.cities },
    };
}

void DataModel::from_json(const json &j, Region &o) {
    using namespace Keys;
    o.name = j[name];
    o.cities = j[cities].get<decltype(o.cities)>();
}

Now keys are stored in datamodel class implementation file. It's ok but it can be implemented even shorter and more comfortable if lib could store an std::map<std::string, F T::*> for T class (Region in the example above). Of course one cannot create such a map in C++ cause value may have different types. But this kind of mapping can be implemented with variadic templates just like sqlite_orm works (look at make_column function). To implement this functionality developer can create template specialization like this:

Region.hpp

#include <string>
#include <vector>
#include <json/json.hpp>

#include "City.hpp"

namespace DataModel {
    
    struct Region {
        std::string name;
        std::vector<City> cities;
    };
    
    using nlohmann::json;
    
    template<>
    struct key_value_mapper<Region> {
        auto operator()() const {
            return make_mapper(make_mapping("name", &Region::name), make_mapping("cities", &Region::cities));
        }
    };
}

City is omitted in the example but it also has from_json and to_json overriden and has the only field std::string name.

@fnc12
Copy link
Author

fnc12 commented Feb 25, 2017

Also if value needs extra transformation (enum for example) make_mapping function can take transformation lambda as third and fourth arguments like this (example uses BETTER_ENUM lib but it can be implemented without it or with any other lib):

return make_mapper(make_mapping("type", &Region::type, [](const json &j){
    return Region::Type::_from_string(j.get<std::string>());
}, [](const Region::Type &o){
    return o._to_string();
});

@nlohmann
Copy link
Owner

I am not sure where the benefit is. @theodelrieu, can you comment on this?

@fnc12
Copy link
Author

fnc12 commented Mar 28, 2017

The benefit is to combine from_json and to_json at one place. I mean replace two functions with one specialization (and no need to use same keys in two places)

@nlohmann
Copy link
Owner

I close this issue: the current approach works, and changing it to the proposed mapping would require a lot of work that I currently cannot provide.

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