264 lines
9.8 KiB
C++
264 lines
9.8 KiB
C++
#include "catch2/catch_test_macros.hpp"
|
|
|
|
#include "SessionFixture.hpp"
|
|
|
|
#include "connection.hpp"
|
|
|
|
#include "matador/query/session.hpp"
|
|
|
|
#include "models/recipe.hpp"
|
|
#include "models/model_metas.hpp"
|
|
|
|
using namespace matador;
|
|
using namespace matador::object;
|
|
using namespace matador::test;
|
|
using namespace matador::query::meta;
|
|
|
|
namespace matador::test {
|
|
template<const utils::primary_key_attribute &PkAttribute>
|
|
struct recipe_pk_generator;
|
|
|
|
template<const utils::primary_key_attribute &PkAttribute>
|
|
struct ingredient_pk_generator {
|
|
unsigned int id{};
|
|
std::string name;
|
|
collection<object_ptr<recipe_pk_generator<PkAttribute>>> recipes{};
|
|
|
|
ingredient_pk_generator() = default;
|
|
|
|
explicit ingredient_pk_generator(std::string name)
|
|
: name(std::move(name)) {
|
|
}
|
|
|
|
ingredient_pk_generator(std::string name, std::vector<object_ptr<recipe_pk_generator<PkAttribute>>> recps)
|
|
: name(std::move(name))
|
|
, recipes(std::move(recps)){}
|
|
|
|
template<class Operator>
|
|
void process(Operator &op) {
|
|
namespace field = matador::access;
|
|
field::primary_key(op, "id", id, PkAttribute);
|
|
field::attribute(op, "name", name, UniqueVarChar255);
|
|
field::has_many_to_many(op, "recipe_ingredients", recipes, "ingredient_id", "recipe_id", utils::CascadeAllFetchEager);
|
|
}
|
|
};
|
|
|
|
template<const utils::primary_key_attribute &PkAttribute>
|
|
struct recipe_pk_generator {
|
|
unsigned int id{};
|
|
std::string name;
|
|
collection<object_ptr<ingredient_pk_generator<PkAttribute>>> ingredients{};
|
|
|
|
recipe_pk_generator() = default;
|
|
explicit recipe_pk_generator(std::string name)
|
|
: name(std::move(name)) {
|
|
}
|
|
recipe_pk_generator(std::string name, std::vector<object_ptr<ingredient_pk_generator<PkAttribute>>> ings)
|
|
: name(std::move(name))
|
|
, ingredients(std::move(ings)){}
|
|
|
|
template<class Operator>
|
|
void process(Operator &op) {
|
|
namespace field = matador::access;
|
|
field::primary_key(op, "id", id, PkAttribute);
|
|
field::attribute(op, "name", name, UniqueVarChar255);
|
|
field::has_many_to_many(op, "recipe_ingredients", ingredients, utils::CascadeAllFetchLazy);
|
|
}
|
|
};
|
|
|
|
using ingredient_identity = ingredient_pk_generator<utils::Identity>;
|
|
using ingredient_table = ingredient_pk_generator<utils::Table>;
|
|
using ingredient_sequence = ingredient_pk_generator<utils::Sequence>;
|
|
using recipe_identity = recipe_pk_generator<utils::Identity>;
|
|
using recipe_table = recipe_pk_generator<utils::Table>;
|
|
using recipe_sequence = recipe_pk_generator<utils::Sequence>;
|
|
}
|
|
|
|
TEST_CASE_METHOD(SessionFixture, "Test insert object with has many to many relation", "[session][insert][has_many_to_many]") {
|
|
auto result = schema.attach<recipe>("recipes")
|
|
.and_then( [this] { return schema.attach<ingredient>("ingredients"); } )
|
|
.and_then([this] { return schema.create(db); } );
|
|
|
|
query::session ses({bus, connection::dns, 4}, schema);
|
|
|
|
std::vector ingredients {
|
|
make_object<ingredient>(1, "Apple"),
|
|
make_object<ingredient>(2, "Strawberry"),
|
|
make_object<ingredient>(3, "Pineapple"),
|
|
make_object<ingredient>(4, "Sugar"),
|
|
make_object<ingredient>(5, "Flour"),
|
|
make_object<ingredient>(6, "Butter"),
|
|
make_object<ingredient>(7, "Beans")
|
|
};
|
|
|
|
std::vector recipes {
|
|
make_object<recipe>(1, "Apple Pie", std::vector{ingredients[0], ingredients[3], ingredients[4]}),
|
|
make_object<recipe>(2, "Strawberry Cake", std::vector{ingredients[5], ingredients[6]}),
|
|
make_object<recipe>(3, "Pineapple Pie", std::vector{ingredients[0], ingredients[1], ingredients[2]})
|
|
};
|
|
|
|
for (auto &r: recipes) {
|
|
REQUIRE(r.is_transient());
|
|
auto res = ses.insert(r);
|
|
REQUIRE(res.is_ok());
|
|
REQUIRE(res->is_persistent());
|
|
}
|
|
|
|
auto recipe_result = ses.find<recipe>(1);
|
|
REQUIRE(recipe_result.is_ok());
|
|
REQUIRE(recipe_result->is_persistent());
|
|
REQUIRE(recipe_result.value()->ingredients.size() == 3);
|
|
}
|
|
|
|
TEST_CASE_METHOD(SessionFixture, "Test insert object with has many to many relation identity", "[session][insert][identity][has_many_to_many]") {
|
|
auto result = schema.attach<recipe_identity>("recipes")
|
|
.and_then( [this] { return schema.attach<ingredient_identity>("ingredients"); } )
|
|
.and_then([this] { return schema.create(db); } );
|
|
|
|
query::session ses({bus, connection::dns, 4}, schema);
|
|
|
|
std::vector ingredients {
|
|
make_object<ingredient_identity>("Apple"),
|
|
make_object<ingredient_identity>("Strawberry"),
|
|
make_object<ingredient_identity>("Pineapple"),
|
|
make_object<ingredient_identity>("Sugar"),
|
|
make_object<ingredient_identity>("Flour"),
|
|
make_object<ingredient_identity>("Butter"),
|
|
make_object<ingredient_identity>("Beans")
|
|
};
|
|
|
|
std::vector recipes {
|
|
make_object<recipe_identity>("Apple Pie", std::vector{ingredients[0], ingredients[3], ingredients[4]}),
|
|
make_object<recipe_identity>("Strawberry Cake", std::vector{ingredients[5], ingredients[6]}),
|
|
make_object<recipe_identity>("Pineapple Pie", std::vector{ingredients[0], ingredients[1], ingredients[2]})
|
|
};
|
|
|
|
for (auto &r: recipes) {
|
|
REQUIRE(r.is_transient());
|
|
auto res = ses.insert(r);
|
|
REQUIRE(res.is_ok());
|
|
REQUIRE(res->is_persistent());
|
|
}
|
|
|
|
auto recipe_result = ses.find<recipe_identity>(1);
|
|
REQUIRE(recipe_result.is_ok());
|
|
REQUIRE(recipe_result->is_persistent());
|
|
REQUIRE(recipe_result.value()->ingredients.size() == 3);
|
|
}
|
|
|
|
TEST_CASE_METHOD(SessionFixture, "Test insert object with has many to many relation table sequence", "[session][insert][table_sequence][has_many_to_many]") {
|
|
auto result = schema.attach<recipe_table>("recipes")
|
|
.and_then( [this] { return schema.attach<ingredient_table>("ingredients"); } )
|
|
.and_then([this] { return schema.create(db); } );
|
|
|
|
query::session ses({bus, connection::dns, 4}, schema);
|
|
|
|
std::vector ingredients {
|
|
make_object<ingredient_table>("Apple"),
|
|
make_object<ingredient_table>("Strawberry"),
|
|
make_object<ingredient_table>("Pineapple"),
|
|
make_object<ingredient_table>("Sugar"),
|
|
make_object<ingredient_table>("Flour"),
|
|
make_object<ingredient_table>("Butter"),
|
|
make_object<ingredient_table>("Beans")
|
|
};
|
|
|
|
std::vector recipes {
|
|
make_object<recipe_table>("Apple Pie", std::vector{ingredients[0], ingredients[3], ingredients[4]}),
|
|
make_object<recipe_table>("Strawberry Cake", std::vector{ingredients[5], ingredients[6]}),
|
|
make_object<recipe_table>("Pineapple Pie", std::vector{ingredients[0], ingredients[1], ingredients[2]})
|
|
};
|
|
|
|
for (auto &r: recipes) {
|
|
REQUIRE(r.is_transient());
|
|
auto res = ses.insert(r);
|
|
REQUIRE(res.is_ok());
|
|
REQUIRE(res->is_persistent());
|
|
}
|
|
|
|
auto recipe_result = ses.find<recipe_table>(1);
|
|
REQUIRE(recipe_result.is_ok());
|
|
REQUIRE(recipe_result->is_persistent());
|
|
REQUIRE(recipe_result.value()->ingredients.size() == 3);
|
|
}
|
|
|
|
TEST_CASE_METHOD(SessionFixture, "Test insert object with has many to many relation sequence", "[session][insert][sequence][has_many_to_many]") {
|
|
auto result = schema.attach<recipe_sequence>("recipes")
|
|
.and_then( [this] { return schema.attach<ingredient_sequence>("ingredients"); } )
|
|
.and_then([this] { return schema.create(db); } );
|
|
|
|
query::session ses({bus, connection::dns, 4}, schema);
|
|
|
|
std::vector ingredients {
|
|
make_object<ingredient_sequence>("Apple"),
|
|
make_object<ingredient_sequence>("Strawberry"),
|
|
make_object<ingredient_sequence>("Pineapple"),
|
|
make_object<ingredient_sequence>("Sugar"),
|
|
make_object<ingredient_sequence>("Flour"),
|
|
make_object<ingredient_sequence>("Butter"),
|
|
make_object<ingredient_sequence>("Beans")
|
|
};
|
|
|
|
std::vector recipes {
|
|
make_object<recipe_sequence>("Apple Pie", std::vector{ingredients[0], ingredients[3], ingredients[4]}),
|
|
make_object<recipe_sequence>("Strawberry Cake", std::vector{ingredients[5], ingredients[6]}),
|
|
make_object<recipe_sequence>("Pineapple Pie", std::vector{ingredients[0], ingredients[1], ingredients[2]})
|
|
};
|
|
|
|
for (auto &r: recipes) {
|
|
REQUIRE(r.is_transient());
|
|
auto res = ses.insert(r);
|
|
REQUIRE(res.is_ok());
|
|
REQUIRE(res->is_persistent());
|
|
}
|
|
|
|
auto recipe_result = ses.find<recipe_sequence>(1);
|
|
REQUIRE(recipe_result.is_ok());
|
|
REQUIRE(recipe_result->is_persistent());
|
|
REQUIRE(recipe_result.value()->ingredients.size() == 3);
|
|
|
|
const auto ing_result = ses.find<ingredient_sequence>(ingredients[0]->id);
|
|
REQUIRE(ing_result.is_ok());
|
|
REQUIRE(ing_result.value()->recipes.size() == 2);
|
|
}
|
|
|
|
TEST_CASE_METHOD(SessionFixture, "Test insert object with has many to many relation sequence reverse", "[session][insert][sequence][has_many_to_many][reverse]") {
|
|
auto result = schema.attach<recipe_sequence>("recipes")
|
|
.and_then( [this] { return schema.attach<ingredient_sequence>("ingredients"); } )
|
|
.and_then([this] { return schema.create(db); } );
|
|
|
|
query::session ses({bus, connection::dns, 4}, schema);
|
|
|
|
std::vector recipes {
|
|
make_object<recipe_sequence>("Apple Pie"),
|
|
make_object<recipe_sequence>("Strawberry Cake"),
|
|
make_object<recipe_sequence>("Pineapple Pie")
|
|
};
|
|
|
|
std::vector ingredients {
|
|
make_object<ingredient_sequence>("Apple", std::vector{recipes[0], recipes[2]}),
|
|
make_object<ingredient_sequence>("Strawberry", std::vector{recipes[2]}),
|
|
make_object<ingredient_sequence>("Pineapple", std::vector{recipes[2]}),
|
|
make_object<ingredient_sequence>("Sugar", std::vector{recipes[0]}),
|
|
make_object<ingredient_sequence>("Flour", std::vector{recipes[0]}),
|
|
make_object<ingredient_sequence>("Butter", std::vector{recipes[1]}),
|
|
make_object<ingredient_sequence>("Beans", std::vector{recipes[1]})
|
|
};
|
|
|
|
for (auto &i: ingredients) {
|
|
REQUIRE(i.is_transient());
|
|
auto res = ses.insert(i);
|
|
REQUIRE(res.is_ok());
|
|
REQUIRE(res->is_persistent());
|
|
}
|
|
|
|
auto recipe_result = ses.find<ingredient_sequence>(1);
|
|
REQUIRE(recipe_result.is_ok());
|
|
REQUIRE(recipe_result->is_persistent());
|
|
REQUIRE(recipe_result.value()->recipes.size() == 2);
|
|
|
|
const auto ing_result = ses.find<recipe_sequence>(recipes[0]->id);
|
|
REQUIRE(ing_result.is_ok());
|
|
REQUIRE(ing_result.value()->ingredients.size() == 3);
|
|
}
|