Compare commits
No commits in common. "31e9c7e9ac18789ec8a65369976a782fb4a5af90" and "4cda0f26649c3e58cacdfecf7c41f1e3801a2a55" have entirely different histories.
31e9c7e9ac
...
4cda0f2664
|
|
@ -457,76 +457,42 @@ TEST_CASE_METHOD(QueryFixture, "Select statement with many to many relationship"
|
||||||
|
|
||||||
auto result = db
|
auto result = db
|
||||||
.query(schema)
|
.query(schema)
|
||||||
.select({"r.id", "r.name", "ri.ingredient_id"})
|
.select({"r.id", "r.name", "ri.recipe_id"})
|
||||||
.from({"recipes", "r"})
|
.from({"recipes", "r"})
|
||||||
.join_left({"recipe_ingredients", "ri"})
|
.join_left({"recipe_ingredients", "ri"})
|
||||||
.on("r.id"_col == "ri.recipe_id"_col)
|
.on("r.id"_col == "ri.recipe_id"_col)
|
||||||
.fetch_all();
|
.fetch_all();
|
||||||
|
|
||||||
std::vector<std::tuple<unsigned long, std::string, unsigned long>> expected_result_one_join {
|
|
||||||
{7, "Apple Crumble", 1},
|
|
||||||
{7, "Apple Crumble", 4},
|
|
||||||
{7, "Apple Crumble", 5},
|
|
||||||
{8, "Beans Chili", 6},
|
|
||||||
{8, "Beans Chili", 7},
|
|
||||||
{9, "Fruit Salad", 1},
|
|
||||||
{9, "Fruit Salad", 2},
|
|
||||||
{9, "Fruit Salad", 3}
|
|
||||||
};
|
|
||||||
size_t index{0};
|
|
||||||
for (const auto &r: result) {
|
for (const auto &r: result) {
|
||||||
REQUIRE(r.size() == 3);
|
REQUIRE(r.size() == 3);
|
||||||
REQUIRE(r.at(0).as<unsigned long>().value() == std::get<0>(expected_result_one_join[index]));
|
std::cout << "record r.id " << r.at(0).as<unsigned long>().value() << " r.name " << r.at(1).as<std::string>().value() << " ri.id " << r.at(2).as<unsigned long>().value() << "\n";
|
||||||
REQUIRE(r.at(1).as<std::string>().value() == std::get<1>(expected_result_one_join[index]));
|
|
||||||
REQUIRE(r.at(2).as<unsigned long>().value() == std::get<2>(expected_result_one_join[index]));
|
|
||||||
++index;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
result = db
|
result = db
|
||||||
.query(schema)
|
.query(schema)
|
||||||
.select({"r.id", "r.name", "ri.ingredient_id", "i.name"})
|
.select({"r.id", "r.name", "ri.recipe_id", "i.name"})
|
||||||
.from({"recipes", "r"})
|
.from({"recipes", "r"})
|
||||||
.join_left({"recipe_ingredients", "ri"}).on("r.id"_col == "ri.recipe_id"_col)
|
.join_left({"recipe_ingredients", "ri"}).on("r.id"_col == "ri.recipe_id"_col)
|
||||||
.join_left({"ingredients", "i"}).on("ri.ingredient_id"_col == "i.id"_col)
|
.join_left({"ingredients", "i"}).on("ri.ingredient_id"_col == "i.id"_col)
|
||||||
.fetch_all();
|
.fetch_all();
|
||||||
|
|
||||||
std::vector<std::tuple<unsigned long, std::string, unsigned long, std::string>> expected_result_two_joins {
|
|
||||||
{7, "Apple Crumble", 1, "Apple"},
|
|
||||||
{7, "Apple Crumble", 4, "Sugar"},
|
|
||||||
{7, "Apple Crumble", 5, "Flour"},
|
|
||||||
{8, "Beans Chili", 6, "Butter"},
|
|
||||||
{8, "Beans Chili", 7, "Beans"},
|
|
||||||
{9, "Fruit Salad", 1, "Apple"},
|
|
||||||
{9, "Fruit Salad", 2, "Strawberry"},
|
|
||||||
{9, "Fruit Salad", 3, "Pineapple"}
|
|
||||||
};
|
|
||||||
index = 0;
|
|
||||||
for (const auto &r: result) {
|
for (const auto &r: result) {
|
||||||
REQUIRE(r.size() == 4);
|
REQUIRE(r.size() == 4);
|
||||||
REQUIRE(r.at(0).as<unsigned long>().value() == std::get<0>(expected_result_two_joins[index]));
|
std::cout << "record r.id " << r.at(0).as<unsigned long>().value() << " r.name " << r.at(1).as<std::string>().value() << " ri.id " << r.at(2).as<unsigned long>().value() << " i.name " << r.at(3).as<std::string>().value() << "\n";
|
||||||
REQUIRE(r.at(1).as<std::string>().value() == std::get<1>(expected_result_two_joins[index]));
|
|
||||||
REQUIRE(r.at(2).as<unsigned long>().value() == std::get<2>(expected_result_two_joins[index]));
|
|
||||||
REQUIRE(r.at(3).as<std::string>().value() == std::get<3>(expected_result_two_joins[index]));
|
|
||||||
++index;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
result = db
|
result = db
|
||||||
.query(schema)
|
.query(schema)
|
||||||
.select({"r.id", "r.name", "ri.ingredient_id", "i.name"})
|
.select({"r.id", "r.name", "ri.recipe_id", "i.name"})
|
||||||
.from({"recipes", "r"})
|
.from({"recipes", "r"})
|
||||||
.join_left({"recipe_ingredients", "ri"}).on("r.id"_col == "ri.recipe_id"_col)
|
.join_left({"recipe_ingredients", "ri"}).on("r.id"_col == "ri.recipe_id"_col)
|
||||||
.join_left({"ingredients", "i"}).on("ri.ingredient_id"_col == "i.id"_col)
|
.join_left({"ingredients", "i"}).on("ri.ingredient_id"_col == "i.id"_col)
|
||||||
.where("r.id"_col == 8)
|
.where("r.id"_col == 8)
|
||||||
.fetch_all();
|
.fetch_all();
|
||||||
|
|
||||||
index = 3;
|
|
||||||
for (const auto &r: result) {
|
for (const auto &r: result) {
|
||||||
REQUIRE(r.size() == 4);
|
REQUIRE(r.size() == 4);
|
||||||
REQUIRE(r.at(0).as<unsigned long>().value() == std::get<0>(expected_result_two_joins[index]));
|
std::cout << "record r.id " << r.at(0).as<unsigned long>().value() << " r.name " << r.at(1).as<std::string>().value() << " ri.id " << r.at(2).as<unsigned long>().value() << " i.name " << r.at(3).as<std::string>().value() << "\n";
|
||||||
REQUIRE(r.at(1).as<std::string>().value() == std::get<1>(expected_result_two_joins[index]));
|
|
||||||
REQUIRE(r.at(2).as<unsigned long>().value() == std::get<2>(expected_result_two_joins[index]));
|
|
||||||
REQUIRE(r.at(3).as<std::string>().value() == std::get<3>(expected_result_two_joins[index]));
|
|
||||||
++index;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
db.query(schema).drop().table("recipe_ingredients").execute();
|
db.query(schema).drop().table("recipe_ingredients").execute();
|
||||||
|
|
|
||||||
|
|
@ -23,9 +23,9 @@ struct column
|
||||||
column(sql_function_t func, std::string name); // NOLINT(*-explicit-constructor)
|
column(sql_function_t func, std::string name); // NOLINT(*-explicit-constructor)
|
||||||
column(std::string table_name, std::string name, std::string as);
|
column(std::string table_name, std::string name, std::string as);
|
||||||
column(std::string table_name, const char* name, std::string as);
|
column(std::string table_name, const char* name, std::string as);
|
||||||
column(struct table &t, const char* name, std::string as);
|
column(table &t, const char* name, std::string as);
|
||||||
|
|
||||||
[[nodiscard]] bool equals(const column &x) const;
|
bool equals(const column &x) const;
|
||||||
|
|
||||||
column& as(std::string a);
|
column& as(std::string a);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -53,15 +53,6 @@ public:
|
||||||
[[nodiscard]] const std::string& ref_table() const;
|
[[nodiscard]] const std::string& ref_table() const;
|
||||||
[[nodiscard]] const std::string& ref_column() const;
|
[[nodiscard]] const std::string& ref_column() const;
|
||||||
|
|
||||||
[[nodiscard]] bool is_integer() const;
|
|
||||||
[[nodiscard]] bool is_floating_point() const;
|
|
||||||
[[nodiscard]] bool is_bool() const;
|
|
||||||
[[nodiscard]] bool is_string() const;
|
|
||||||
[[nodiscard]] bool is_varchar() const;
|
|
||||||
[[nodiscard]] bool is_blob() const;
|
|
||||||
[[nodiscard]] bool is_null() const;
|
|
||||||
[[nodiscard]] bool is_unknown() const;
|
|
||||||
|
|
||||||
void type(data_type_t type);
|
void type(data_type_t type);
|
||||||
|
|
||||||
template< typename Type >
|
template< typename Type >
|
||||||
|
|
|
||||||
|
|
@ -63,46 +63,6 @@ const std::string &column_definition::ref_column() const
|
||||||
return ref_column_;
|
return ref_column_;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool column_definition::is_integer() const
|
|
||||||
{
|
|
||||||
return type_ >= data_type_t::type_char && type_ <= data_type_t::type_unsigned_long_long;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool column_definition::is_floating_point() const
|
|
||||||
{
|
|
||||||
return type_ == data_type_t::type_float || type_ == data_type_t::type_double;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool column_definition::is_bool() const
|
|
||||||
{
|
|
||||||
return type_ == data_type_t::type_bool;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool column_definition::is_string() const
|
|
||||||
{
|
|
||||||
return type_ == data_type_t::type_text;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool column_definition::is_varchar() const
|
|
||||||
{
|
|
||||||
return type_ == data_type_t::type_varchar;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool column_definition::is_blob() const
|
|
||||||
{
|
|
||||||
return type_ == data_type_t::type_blob;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool column_definition::is_null() const
|
|
||||||
{
|
|
||||||
return type_ == data_type_t::type_null;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool column_definition::is_unknown() const
|
|
||||||
{
|
|
||||||
return type_ == data_type_t::type_unknown;
|
|
||||||
}
|
|
||||||
|
|
||||||
void column_definition::type(data_type_t type)
|
void column_definition::type(data_type_t type)
|
||||||
{
|
{
|
||||||
type_ = type;
|
type_ = type;
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,6 @@ struct author
|
||||||
std::string date_of_birth;
|
std::string date_of_birth;
|
||||||
unsigned short year_of_birth{};
|
unsigned short year_of_birth{};
|
||||||
bool distinguished{false};
|
bool distinguished{false};
|
||||||
std::vector<matador::sql::entity<book>> books;
|
|
||||||
|
|
||||||
template<typename Operator>
|
template<typename Operator>
|
||||||
void process(Operator &op)
|
void process(Operator &op)
|
||||||
|
|
@ -27,7 +26,6 @@ struct author
|
||||||
field::attribute(op, "date_of_birth", date_of_birth, 31);
|
field::attribute(op, "date_of_birth", date_of_birth, 31);
|
||||||
field::attribute(op, "year_of_birth", year_of_birth);
|
field::attribute(op, "year_of_birth", year_of_birth);
|
||||||
field::attribute(op, "distinguished", distinguished);
|
field::attribute(op, "distinguished", distinguished);
|
||||||
field::has_many(op, "books", books, "author_id", "id", utils::fetch_type::LAZY);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ struct book
|
||||||
namespace field = matador::utils::access;
|
namespace field = matador::utils::access;
|
||||||
field::primary_key(op, "id", id);
|
field::primary_key(op, "id", id);
|
||||||
field::attribute(op, "title", title, 511);
|
field::attribute(op, "title", title, 511);
|
||||||
field::belongs_to(op, "author_id", book_author, utils::fetch_type::EAGER);
|
field::has_one(op, "author_id", book_author, utils::fetch_type::EAGER);
|
||||||
field::attribute(op, "published_in", published_in);
|
field::attribute(op, "published_in", published_in);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -11,19 +11,16 @@
|
||||||
|
|
||||||
namespace matador::test {
|
namespace matador::test {
|
||||||
|
|
||||||
struct recipe;
|
|
||||||
struct ingredient
|
struct ingredient
|
||||||
{
|
{
|
||||||
unsigned long id{};
|
unsigned long id{};
|
||||||
std::string name;
|
std::string name;
|
||||||
std::vector<matador::sql::entity<recipe>> recipes;
|
|
||||||
|
|
||||||
template<class Operator>
|
template<class Operator>
|
||||||
void process(Operator &op) {
|
void process(Operator &op) {
|
||||||
namespace field = matador::utils::access;
|
namespace field = matador::utils::access;
|
||||||
field::primary_key(op, "id", id);
|
field::primary_key(op, "id", id);
|
||||||
field::attribute(op, "name", name, 255);
|
field::attribute(op, "name", name, 255);
|
||||||
field::has_many(op, "recipes", recipes, "ingredient_id", "recipe_id", utils::fetch_type::EAGER);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -31,14 +28,12 @@ struct recipe
|
||||||
{
|
{
|
||||||
unsigned long id{};
|
unsigned long id{};
|
||||||
std::string name;
|
std::string name;
|
||||||
std::vector<matador::sql::entity<ingredient>> ingredients;
|
|
||||||
|
|
||||||
template<class Operator>
|
template<class Operator>
|
||||||
void process(Operator &op) {
|
void process(Operator &op) {
|
||||||
namespace field = matador::utils::access;
|
namespace field = matador::utils::access;
|
||||||
field::primary_key(op, "id", id);
|
field::primary_key(op, "id", id);
|
||||||
field::attribute(op, "name", name, 255);
|
field::attribute(op, "name", name, 255);
|
||||||
field::has_many(op, "ingredients", ingredients, "recipe_id", "ingredient_id", utils::fetch_type::EAGER);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue