diff --git a/include/matador/orm/session_query_builder.hpp b/include/matador/orm/session_query_builder.hpp index 6f57f0b..bb9070b 100644 --- a/include/matador/orm/session_query_builder.hpp +++ b/include/matador/orm/session_query_builder.hpp @@ -203,8 +203,7 @@ public: } template - void on_has_many_to_many(const char *id, ContainerType &/*cont*/, const char *join_column, const char *inverse_join_column, const utils::foreign_attributes &attr) - { + void on_has_many_to_many(const char *id, ContainerType &/*cont*/, const char *join_column, const char *inverse_join_column, const utils::foreign_attributes &attr) { if (attr.fetch() != utils::fetch_type::EAGER) { return; } @@ -217,6 +216,11 @@ public: if (next != processed_tables_.end()) { return; } + auto relation = processed_tables_.find(id); + if (relation == processed_tables_.end()) { + relation = processed_tables_.insert({id, std::make_shared(id, build_alias('t', ++table_index))}).first; + } + table_info_stack_.push({info.value(), std::make_shared(info->get().name(), build_alias('t', ++table_index))}); next = processed_tables_.insert({info->get().name(), table_info_stack_.top().table}).first; typename ContainerType::value_type::value_type obj; @@ -230,17 +234,16 @@ public: append_join( sql::column{table_info_stack_.top().table, table_info_stack_.top().info.get().definition().primary_key()->name()}, - sql::column{std::make_shared(id), join_column} + sql::column{relation->second, join_column} ); append_join( - sql::column{next->second, inverse_join_column}, - sql::column{std::make_shared(info->get().name()), pk->name()} + sql::column{relation->second, inverse_join_column}, + sql::column{next->second, pk->name()} ); } template - void on_has_many_to_many(const char *id, ContainerType &/*cont*/, const utils::foreign_attributes &attr) - { + void on_has_many_to_many(const char *id, ContainerType &/*cont*/, const utils::foreign_attributes &attr) { if (attr.fetch() != utils::fetch_type::EAGER) { return; } @@ -253,7 +256,13 @@ public: if (next != processed_tables_.end()) { return; } + + auto relation = processed_tables_.find(id); + if (relation == processed_tables_.end()) { + relation = processed_tables_.insert({id, std::make_shared(id, build_alias('t', ++table_index))}).first; + } table_info_stack_.push({info.value(), std::make_shared(info->get().name(), build_alias('t', ++table_index))}); + next = processed_tables_.insert({info->get().name(), table_info_stack_.top().table}).first; typename ContainerType::value_type::value_type obj; access::process(*this , obj); table_info_stack_.pop(); @@ -267,11 +276,12 @@ public: append_join( sql::column{table_info_stack_.top().table, table_info_stack_.top().info.get().definition().primary_key()->name()}, - sql::column{std::make_shared(id), join_columns.inverse_join_column} + sql::column{relation->second, join_columns.inverse_join_column} ); append_join( - sql::column{std::make_shared(id), join_columns.join_column}, - sql::column{std::make_shared(info->get().name()), pk->name()} + sql::column{relation->second, join_columns.join_column}, + sql::column{next->second, pk->name()} + // sql::column{std::make_shared(info->get().name()), pk->name()} ); } diff --git a/test/models/department.hpp b/test/models/department.hpp new file mode 100644 index 0000000..7c988c5 --- /dev/null +++ b/test/models/department.hpp @@ -0,0 +1,45 @@ +#ifndef DEPARTMENT_EMPLOYEE_HPP +#define DEPARTMENT_EMPLOYEE_HPP + +#include "matador/object/object_ptr.hpp" + +#include +#include + +namespace matador::test { + +struct employee; + +struct department { + unsigned int id{}; + std::string name; + std::vector> employees; + + template + void process(Operator &op) { + namespace field = matador::access; + field::primary_key(op, "id", id); + field::attribute(op, "name", name, 63); + field::has_many(op, "employees", employees, "dep_id", utils::fetch_type::EAGER); + } +}; + +struct employee { + unsigned int id{}; + std::string first_name; + std::string last_name; + object::object_ptr dep; + + template + void process(Operator &op) { + namespace field = matador::access; + field::primary_key(op, "id", id); + field::attribute(op, "first_name", first_name, 63); + field::attribute(op, "last_name", last_name, 63); + field::belongs_to(op, "dep_id", dep, utils::fetch_type::EAGER); + } +}; + +} + +#endif //DEPARTMENT_EMPLOYEE_HPP diff --git a/test/orm/orm/SessionQueryBuilderTest.cpp b/test/orm/orm/SessionQueryBuilderTest.cpp index d7c89d4..68e5abc 100644 --- a/test/orm/orm/SessionQueryBuilderTest.cpp +++ b/test/orm/orm/SessionQueryBuilderTest.cpp @@ -15,6 +15,7 @@ #include "../../models/airplane.hpp" #include "../../models/author.hpp" +#include "../../models/department.hpp" #include "../../models/book.hpp" #include "../../models/flight.hpp" #include "../../models/recipe.hpp" @@ -29,6 +30,7 @@ using namespace matador::test; TEST_CASE("Create sql query data for entity with eager has one", "[query][entity][builder]") { using namespace matador::test; + backend_provider::instance().register_backend("noop", std::make_unique()); connection db("noop://noop.db"); schema scm("noop"); auto result = scm.attach("airplanes") @@ -133,6 +135,7 @@ TEST_CASE("Create sql query data for entity with eager belongs to", "[query][ent TEST_CASE("Create sql query data for entity with eager has many belongs to", "[query][entity][builder]") { using namespace matador::test; + backend_provider::instance().register_backend("noop", std::make_unique()); connection db("noop://noop.db"); schema scm("noop"); auto result = scm.attach("products") @@ -190,6 +193,7 @@ TEST_CASE("Create sql query data for entity with eager has many belongs to", "[q TEST_CASE("Create sql query data for entity with eager many to many", "[query][entity][builder]") { using namespace matador::test; + backend_provider::instance().register_backend("noop", std::make_unique()); connection db("noop://noop.db"); schema scm("noop"); auto result = scm.attach("recipes") @@ -215,8 +219,8 @@ TEST_CASE("Create sql query data for entity with eager many to many", "[query][e } std::vector> expected_join_data { - { "recipe_ingredients", R"("t01"."id" = "recipe_ingredients"."ingredient_id")"}, - { "recipes", R"("t02"."recipe_id" = "recipes"."id")"} + { "recipe_ingredients", R"("t01"."id" = "t02"."ingredient_id")"}, + { "recipes", R"("t02"."recipe_id" = "t03"."id")"} }; query_context qc; @@ -234,6 +238,7 @@ TEST_CASE("Create sql query data for entity with eager many to many", "[query][e TEST_CASE("Create sql query data for entity with eager many to many (inverse part)", "[query][entity][builder]") { using namespace matador::test; + backend_provider::instance().register_backend("noop", std::make_unique()); connection db("noop://noop.db"); schema scm("noop"); auto result = scm.attach("students") @@ -259,8 +264,8 @@ TEST_CASE("Create sql query data for entity with eager many to many (inverse par } std::vector> expected_join_data { - { "student_courses", R"("courses"."id" = "student_courses"."course_id")"}, - { "students", R"("student_courses"."student_id" = "students"."id")"} + { "student_courses", R"("t01"."id" = "t02"."course_id")"}, + { "students", R"("t02"."student_id" = "t03"."id")"} }; query_context qc; @@ -276,53 +281,17 @@ TEST_CASE("Create sql query data for entity with eager many to many (inverse par REQUIRE(cond == R"("courses"."id" = 17)"); } -namespace matador::test::orm { - -struct employee; - -struct department { - unsigned int id{}; - std::string name; - std::vector> employees; - - template - void process(Operator &op) { - namespace field = matador::access; - field::primary_key(op, "id", id); - field::attribute(op, "name", name, 63); - field::has_many(op, "employees", employees, "dep_id", utils::fetch_type::EAGER); - } -}; - -struct employee { - unsigned int id{}; - std::string first_name; - std::string last_name; - object_ptr dep; - - template - void process(Operator &op) { - namespace field = matador::access; - field::primary_key(op, "id", id); - field::attribute(op, "first_name", first_name, 63); - field::attribute(op, "last_name", last_name, 63); - field::belongs_to(op, "dep_id", dep, utils::fetch_type::EAGER); - } -}; - -} - TEST_CASE("Test eager relationship", "[session][eager]") { using namespace matador::test; backend_provider::instance().register_backend("noop", std::make_unique()); connection db("noop://noop.db"); schema scm("noop"); - auto result = scm.attach("departments") - .and_then( [&scm] { return scm.attach("employees"); } ); + auto result = scm.attach("departments") + .and_then( [&scm] { return scm.attach("employees"); } ); session_query_builder eqb(scm); - auto data = eqb.build(); + auto data = eqb.build(); REQUIRE(data.is_ok()); auto ctx = query::select(data->columns)