
#include <sqlite_orm/sqlite_orm.h>
#include <iostream>
#include <algorithm>

using std::cout;
using std::endl;

struct MarvelHero {
    int id;
    std::string name;
    std::string abilities;
};

int main(int, char**) {
    using namespace sqlite_orm;
    auto storage = make_storage("iteration.sqlite",
                                make_table("marvel",
                                           make_column("id", &MarvelHero::id, primary_key()),
                                           make_column("name", &MarvelHero::name),
                                           make_column("abilities", &MarvelHero::abilities)));
    storage.sync_schema();

    storage.remove_all<MarvelHero>();

    //  insert values..
    storage.insert(MarvelHero{-1, "Tony Stark", "Iron man, playboy, billionaire, philanthropist"});
    storage.insert(MarvelHero{-1, "Thor", "Storm god"});
    storage.insert(MarvelHero{-1, "Vision", "Min Stone"});
    storage.insert(MarvelHero{-1, "Captain America", "Vibranium shield"});
    storage.insert(MarvelHero{-1, "Hulk", "Strength"});
    storage.insert(MarvelHero{-1, "Star Lord", "Humor"});
    storage.insert(MarvelHero{-1, "Peter Parker", "Spiderman"});
    storage.insert(MarvelHero{-1, "Clint Barton", "Hawkeye"});
    storage.insert(MarvelHero{-1, "Natasha Romanoff", "Black widow"});
    storage.insert(MarvelHero{-1, "Groot", "I am Groot!"});

    cout << "Heros count = " << storage.count<MarvelHero>() << endl;

    //  iterate through heros - iteration takes less memory than `get_all` because
    //  iteration fetches row by row once it is needed. If you break at any iteration
    //  statement will be cleared without fetching remaining rows.
    for(auto& hero: storage.iterate<MarvelHero>()) {
        cout << "hero = " << storage.dump(hero) << endl;
    }

    cout << "====" << endl;

    //  one can iterate with custom WHERE conditions..
    for(auto& hero: storage.iterate<MarvelHero>(where(c(&MarvelHero::name) == "Thor"))) {
        cout << "hero = " << storage.dump(hero) << endl;
    }

    cout << "Heros with LENGTH(name) < 6 :" << endl;
    for(auto& hero: storage.iterate<MarvelHero>(where(length(&MarvelHero::name) < 6))) {
        cout << "hero = " << storage.dump(hero) << endl;
    }

    std::vector<MarvelHero> heroesByAlgorithm;
    heroesByAlgorithm.reserve(static_cast<size_t>(storage.count<MarvelHero>()));
    {
        auto view = storage.iterate<MarvelHero>();
        std::copy(view.begin(), view.end(), std::back_inserter(heroesByAlgorithm));
    }
    cout << "heroesByAlgorithm.size = " << heroesByAlgorithm.size() << endl;

    return 0;
}
