#include <sqlite_orm/sqlite_orm.h>

#include <string>
#include <iostream>

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

struct Contract {
    std::string firstName;
    std::string lastName;
    std::string email;
};

using namespace sqlite_orm;

//  beware - put `make_index` before `make_table` cause `sync_schema` is called in reverse order
//  otherwise you'll receive an exception
auto storage = make_storage(
    "index.sqlite",
    make_index("idx_contacts_name", &Contract::firstName, &Contract::lastName, where(length(&Contract::firstName) > 2)),
    make_unique_index("idx_contacts_email", indexed_column(&Contract::email).collate("BINARY").desc()),
    make_table("contacts",
               make_column("first_name", &Contract::firstName),
               make_column("last_name", &Contract::lastName),
               make_column("email", &Contract::email)));

int main(int, char**) {

    storage.sync_schema();
    storage.remove_all<Contract>();

    storage.insert(Contract{
        "John",
        "Doe",
        "john.doe@sqlitetutorial.net",
    });
    try {
        storage.insert(Contract{
            "Johny",
            "Doe",
            "john.doe@sqlitetutorial.net",
        });
    } catch(const std::system_error& e) {
        cout << e.what() << endl;
    }
    std::vector<Contract> moreContracts = {
        Contract{
            "David",
            "Brown",
            "david.brown@sqlitetutorial.net",
        },
        Contract{
            "Lisa",
            "Smith",
            "lisa.smith@sqlitetutorial.net",
        },
    };
    storage.insert_range(moreContracts.begin(), moreContracts.end());

    auto lisas = storage.get_all<Contract>(where(c(&Contract::email) == "lisa.smith@sqlitetutorial.net"));

    storage.drop_index("idx_contacts_name");
    storage.drop_index("idx_contacts_email");

    return 0;
}
