diff --git a/backends/tests/QueryTest.cpp b/backends/tests/QueryTest.cpp index d5d3674..26cc82a 100644 --- a/backends/tests/QueryTest.cpp +++ b/backends/tests/QueryTest.cpp @@ -10,6 +10,9 @@ #include "models/airplane.hpp" #include "models/flight.hpp" #include "models/person.hpp" +#include "models/recipe.hpp" + +#include using namespace matador::sql; using namespace matador::test; @@ -29,6 +32,9 @@ public: drop_table_if_exists("flight"); drop_table_if_exists("airplane"); drop_table_if_exists("person"); + drop_table_if_exists("recipe_ingredients"); + drop_table_if_exists("recipes"); + drop_table_if_exists("ingredients"); } protected: @@ -79,16 +85,17 @@ TEST_CASE_METHOD(QueryFixture, "Execute select statement with where clause", "[s auto res = db.query(schema) .insert() - .into("person") + .into("person", column_generator::generate(schema, true)) .values(george) .execute(); REQUIRE(res == 1); // fetch person as record - auto result_record = db.query(schema).select() - .from("person") - .where("id"_col == 7) - .fetch_all(); + auto result_record = db.query(schema) + .select(column_generator::generate(schema, true)) + .from("person") + .where("id"_col == 7) + .fetch_all(); for (const auto &i: result_record) { REQUIRE(i.size() == 4); @@ -104,10 +111,11 @@ TEST_CASE_METHOD(QueryFixture, "Execute select statement with where clause", "[s } // fetch person as person - auto result_person = db.query(schema).select() - .from("person") - .where("id"_col == 7) - .fetch_all(); + auto result_person = db.query(schema) + .select(column_generator::generate(schema, true)) + .from("person") + .where("id"_col == 7) + .fetch_all(); for (const auto &i: result_person) { REQUIRE(i.id == 7); @@ -176,20 +184,31 @@ TEST_CASE_METHOD(QueryFixture, "Select statement with foreign key", "[session]") }; for (const auto &plane: planes) { - auto res = db.query(schema).insert().into("airplane").values(*plane).execute(); + auto res = db.query(schema) + .insert() + .into("airplane", column_generator::generate(schema, true)) + .values(*plane) + .execute(); REQUIRE(res == 1); } - auto count = db.query(schema).select({count_all()}).from("airplane").fetch_value(); + auto count = db.query(schema) + .select({count_all()}) + .from("airplane") + .fetch_value().value(); REQUIRE(count == 3); flight f4711{4, planes.at(1), "hans"}; - auto res = db.query(schema).insert().into("flight").values(f4711).execute(); + auto res = db.query(schema) + .insert() + .into("flight", column_generator::generate(schema, true)) + .values(f4711) + .execute(); REQUIRE(res == 1); auto f = *db.query(schema) - .select() + .select(column_generator::generate(schema, true)) .from("flight") .fetch_all().begin(); REQUIRE(f.at(0).as() == 4); @@ -219,11 +238,18 @@ TEST_CASE_METHOD(QueryFixture, "Select statement with foreign key and join_left" }; for (const auto &plane: planes) { - auto res = db.query(schema).insert().into("airplane").values(*plane).execute(); + auto res = db.query(schema) + .insert() + .into("airplane", column_generator::generate(schema, true)) + .values(*plane) + .execute(); REQUIRE(res == 1); } - auto count = db.query(schema).select({count_all()}).from("airplane").fetch_value(); + auto count = db.query(schema) + .select({count_all()}) + .from("airplane") + .fetch_value().value(); REQUIRE(count == 3); std::vector> flights{ @@ -234,12 +260,16 @@ TEST_CASE_METHOD(QueryFixture, "Select statement with foreign key and join_left" }; for (const auto &f: flights) { - auto res = db.query(schema).insert().into("flight").values(*f).execute(); + auto res = db.query(schema) + .insert() + .into("flight", {"id", "airplane_id", "pilot_name"}) + .values(*f) + .execute(); REQUIRE(res == 1); } auto f = *db.query(schema) - .select() + .select(column_generator::generate(schema, true)) .from("flight") .fetch_all().begin(); REQUIRE(f.at(0).as() == 4); @@ -291,7 +321,7 @@ TEST_CASE_METHOD(QueryFixture, "Select statement with foreign key and for single auto res = db .query(schema) .insert() - .into("airplane") + .into("airplane", column_generator::generate(schema, true)) .values(*plane) .execute(); REQUIRE(res == 1); @@ -301,7 +331,7 @@ TEST_CASE_METHOD(QueryFixture, "Select statement with foreign key and for single .query(schema) .select({count_all()}) .from("airplane") - .fetch_value(); + .fetch_value().value(); REQUIRE(count == 3); std::vector> flights{ @@ -312,17 +342,22 @@ TEST_CASE_METHOD(QueryFixture, "Select statement with foreign key and for single }; for (const auto &f: flights) { - auto res = db.query(schema).insert().into("flight").values(*f).execute(); + auto res = db.query(schema) + .insert() + .into("flight", column_generator::generate(schema, true)) + .values(*f) + .execute(); REQUIRE(res == 1); } - auto f = *db.query(schema) - .select() + auto f = db.query(schema) + .select(column_generator::generate(schema, true)) .from("flight") - .fetch_all().begin(); - REQUIRE(f.at(0).as() == 4); - REQUIRE(f.at(1).as() == 1); - REQUIRE(f.at(2).as() == "hans"); + .fetch_one(); + REQUIRE(f.has_value()); + REQUIRE(f->at(0).as() == 4); + REQUIRE(f->at(1).as() == 1); + REQUIRE(f->at(2).as() == "hans"); auto result = db .query(schema) @@ -345,4 +380,122 @@ TEST_CASE_METHOD(QueryFixture, "Select statement with foreign key and for single db.query(schema).drop().table("flight").execute(); db.query(schema).drop().table("airplane").execute(); +} + +TEST_CASE_METHOD(QueryFixture, "Select statement with many to many relationship", "[session][join][many_to_many]") { + schema.attach("recipes"); + schema.attach("ingredients"); + schema.attach("recipe_ingredients"); + db.query(schema).create() + .table("recipes") + .execute(); + + db.query(schema).create() + .table("ingredients") + .execute(); + + db.query(schema).create() + .table("recipe_ingredients") + .execute(); + + std::vector ingredients { + {1, "Apple"}, + {2, "Strawberry"}, + {3, "Pineapple"}, + {4, "Sugar"}, + {5, "Flour"}, + {6, "Butter"}, + {7, "Beans"} + }; + + for (const auto &i: ingredients) { + auto res = db + .query(schema) + .insert() + .into("ingredients", column_generator::generate(schema, true)) + .values(i) + .execute(); + REQUIRE(res == 1); + } + + std::vector recipes{ + {7, "Apple Crumble"}, + {8, "Beans Chili"}, + {9, "Fruit Salad"} + }; + + for (const auto &r: recipes) { + auto res = db + .query(schema) + .insert() + .into("recipes", column_generator::generate(schema, true)) + .values(r) + .execute(); + REQUIRE(res == 1); + } + + std::vector> recipe_ingredients { + { 7, 1 }, + { 7, 4 }, + { 7, 5 }, + { 8, 6 }, + { 8, 7 }, + { 9, 1 }, + { 9, 2 }, + { 9, 3 } + }; + + for (const auto &ri: recipe_ingredients) { + auto res = db + .query(schema) + .insert() + .into("recipe_ingredients", column_generator::generate(schema, true)) + .values({ri.first, ri.second}) + .execute(); + REQUIRE(res == 1); + } + + auto result = db + .query(schema) + .select({"r.id", "r.name", "ri.recipe_id"}) + .from({"recipes", "r"}) + .join_left({"recipe_ingredients", "ri"}) + .on("r.id"_col == "ri.recipe_id"_col) + .fetch_all(); + + for (const auto &r: result) { + REQUIRE(r.size() == 3); + std::cout << "record r.id " << r.at(0).as().value() << " r.name " << r.at(1).as().value() << " ri.id " << r.at(2).as().value() << "\n"; + } + + result = db + .query(schema) + .select({"r.id", "r.name", "ri.recipe_id", "i.name"}) + .from({"recipes", "r"}) + .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) + .fetch_all(); + + for (const auto &r: result) { + REQUIRE(r.size() == 4); + std::cout << "record r.id " << r.at(0).as().value() << " r.name " << r.at(1).as().value() << " ri.id " << r.at(2).as().value() << " i.name " << r.at(3).as().value() << "\n"; + } + + result = db + .query(schema) + .select({"r.id", "r.name", "ri.recipe_id", "i.name"}) + .from({"recipes", "r"}) + .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) + .where("r.id"_col == 8) + .fetch_all(); + + for (const auto &r: result) { + REQUIRE(r.size() == 4); + std::cout << "record r.id " << r.at(0).as().value() << " r.name " << r.at(1).as().value() << " ri.id " << r.at(2).as().value() << " i.name " << r.at(3).as().value() << "\n"; + } + + db.query(schema).drop().table("recipe_ingredients").execute(); + db.query(schema).drop().table("recipes").execute(); + db.query(schema).drop().table("ingredients").execute(); } \ No newline at end of file diff --git a/backends/tests/StatementTest.cpp b/backends/tests/StatementTest.cpp index 6a69708..029894a 100644 --- a/backends/tests/StatementTest.cpp +++ b/backends/tests/StatementTest.cpp @@ -52,7 +52,7 @@ TEST_CASE_METHOD(StatementTestFixture, "Create prepared statement", "[statement] table ap{"airplane"}; SECTION("Insert with prepared statement and placeholder") { auto stmt = db.query(schema).insert() - .into("airplane") + .into("airplane", column_generator::generate(schema, true)) .values() .prepare(); @@ -62,7 +62,10 @@ TEST_CASE_METHOD(StatementTestFixture, "Create prepared statement", "[statement] stmt.reset(); } - auto result = db.query(schema).select().from(ap).fetch_all(); + auto result = db.query(schema) + .select(column_generator::generate(schema, true)) + .from(ap) + .fetch_all(); size_t index{0}; for (const auto &i: result) { @@ -74,11 +77,19 @@ TEST_CASE_METHOD(StatementTestFixture, "Create prepared statement", "[statement] SECTION("Select with prepared statement") { for (const auto &plane: planes) { - auto res = db.query(schema).insert().into("airplane").values(*plane).execute(); + auto res = db.query(schema) + .insert() + .into("airplane", column_generator::generate(schema, true)) + .values(*plane) + .execute(); REQUIRE(res == 1); } - auto stmt = db.query(schema).select().from(ap).where("brand"_col == _).prepare(); + auto stmt = db.query(schema) + .select(column_generator::generate(schema, true)) + .from(ap) + .where("brand"_col == _) + .prepare(); stmt.bind(0, "Airbus"); diff --git a/backends/tests/TypeTraitsTest.cpp b/backends/tests/TypeTraitsTest.cpp index 94ff02f..bc99de8 100644 --- a/backends/tests/TypeTraitsTest.cpp +++ b/backends/tests/TypeTraitsTest.cpp @@ -1,6 +1,7 @@ #include #include "matador/sql/connection.hpp" +#include "matador/sql/column_generator.hpp" #include "matador/utils/enum_mapper.hpp" @@ -8,6 +9,7 @@ #include "models/location.hpp" +using namespace matador::sql; using namespace matador::test; class TypeTraitsTestFixture @@ -91,14 +93,14 @@ TEST_CASE_METHOD(TypeTraitsTestFixture, "Special handling of attributes with typ auto res = db .query(schema) .insert() - .into("location") + .into("location", column_generator::generate(schema, true)) .values(loc) .execute(); REQUIRE(res == 1); auto result = db .query(schema) - .select() + .select(column_generator::generate(schema, true)) .from("location") .fetch_all(); @@ -113,7 +115,7 @@ TEST_CASE_METHOD(TypeTraitsTestFixture, "Special handling of attributes with typ auto stmt = db .query(schema) .insert() - .into("location") + .into("location", column_generator::generate(schema, true)) .values() .prepare(); @@ -124,7 +126,7 @@ TEST_CASE_METHOD(TypeTraitsTestFixture, "Special handling of attributes with typ auto result = db .query(schema) - .select() + .select(column_generator::generate(schema, true)) .from("location") .fetch_all(); diff --git a/demo/main.cpp b/demo/main.cpp index f3455ae..0987a54 100644 --- a/demo/main.cpp +++ b/demo/main.cpp @@ -90,14 +90,14 @@ int main() mc.distinguished = true; auto insert_authors_sql = c.query(s) .insert() - .into(qh::authors) + .into(qh::authors) .values(mc) .execute(); std::cout << "SQL: " << insert_authors_sql << "\n"; auto result = c.query(s) - .select() + .select(qh::authors.columns) .from(qh::authors) .fetch_all(); @@ -115,7 +115,7 @@ int main() std::cout << "SQL: " << update_authors_sql << "\n"; auto authors = c.query(s) - .select() + .select(qh::authors.columns) .from(qh::authors) .fetch_all(); @@ -125,18 +125,18 @@ int main() c.query(s) .insert() - .into(qh::books) + .into(qh::books) .values({2, "It", mc.id, 1980}) .execute(); c.query(s) .insert() - .into(qh::books) + .into(qh::books) .values({3, "Misery", mc.id, 1984}) .execute(); auto select_books_sql = c.query(s) - .select({qh::authors.last_name}) + .select(qh::books.columns, {qh::authors.last_name}) .from(qh::books) .join_left(qh::authors) .on(qh::books.author_id == qh::authors.id) diff --git a/include/matador/sql/column.hpp b/include/matador/sql/column.hpp index 06d5e66..a14b332 100644 --- a/include/matador/sql/column.hpp +++ b/include/matador/sql/column.hpp @@ -5,6 +5,8 @@ namespace matador::sql { +struct table; + enum class sql_function_t { NONE, COUNT, @@ -21,6 +23,7 @@ struct column 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, const char* name, std::string as); + column(table &t, const char* name, std::string as); bool equals(const column &x) const; diff --git a/include/matador/sql/column_generator.hpp b/include/matador/sql/column_generator.hpp index 6a629f2..827b44a 100644 --- a/include/matador/sql/column_generator.hpp +++ b/include/matador/sql/column_generator.hpp @@ -17,20 +17,23 @@ namespace matador::sql { class column_generator { private: - column_generator(std::vector &column_infos, const sql::schema &ts, const std::string &table_name); + column_generator(std::vector &column_infos, + const sql::schema &ts, + const std::string &table_name, + bool force_lazy); public: ~column_generator() = default; template < class Type > - static std::vector generate(const sql::schema &ts) + static std::vector generate(const sql::schema &ts, bool force_lazy = false) { const auto info = ts.info(); if (!info) { return {}; } std::vector columns; - column_generator gen(columns, ts, info.value().name); + column_generator gen(columns, ts, info.value().name, force_lazy); Type obj; matador::utils::access::process(gen, obj); return std::move(columns); @@ -53,7 +56,7 @@ public: template void on_belongs_to(const char *id, Pointer &, const utils::foreign_attributes &attr) { - if (attr.fetch() == utils::fetch_type::LAZY) { + if (attr.fetch() == utils::fetch_type::LAZY || force_lazy_) { push(id); } else { const auto info = table_schema_.info(); @@ -69,7 +72,7 @@ public: template void on_has_one(const char *id, Pointer &, const utils::foreign_attributes &attr) { - if (attr.fetch() == utils::fetch_type::LAZY) { + if (attr.fetch() == utils::fetch_type::LAZY || force_lazy_) { push(id); } else { const auto info = table_schema_.info(); @@ -85,7 +88,7 @@ public: template void on_has_many(const char *, ContainerType &, const char *, const char *, const utils::foreign_attributes &attr) { - if (attr.fetch() == utils::fetch_type::LAZY) { + if (attr.fetch() == utils::fetch_type::LAZY || force_lazy_) { return; } const auto info = table_schema_.info(); @@ -112,6 +115,7 @@ private: std::vector &column_infos_; const sql::schema &table_schema_; int column_index{0}; + bool force_lazy_{false}; }; } diff --git a/include/matador/sql/entity_query_builder.hpp b/include/matador/sql/entity_query_builder.hpp index 9628ce7..ea3e825 100644 --- a/include/matador/sql/entity_query_builder.hpp +++ b/include/matador/sql/entity_query_builder.hpp @@ -32,7 +32,7 @@ public: columns_.clear(); table_name_ = info.value().name; query q(db, schema_); - return q.select().from({table_name_}).build(); + return q.select(column_generator::generate(schema_)).from({table_name_}).build(); // auto from_intermediate = q.select().from({"t"}); // return {}; } diff --git a/include/matador/sql/query.hpp b/include/matador/sql/query.hpp index 68cc437..9c7058b 100644 --- a/include/matador/sql/query.hpp +++ b/include/matador/sql/query.hpp @@ -16,12 +16,9 @@ public: query_create_intermediate create(); query_drop_intermediate drop(); - template < class Type > - query_select_intermediate select(); - template < class Type > - query_select_intermediate select(std::initializer_list columns); query_select_intermediate select(std::initializer_list columns); query_select_intermediate select(const std::vector& columns); + query_select_intermediate select(std::vector columns, std::initializer_list additional_columns); query_insert_intermediate insert(); query_update_intermediate update(const sql::table &table); query_delete_intermediate remove(); @@ -31,19 +28,5 @@ private: const sql::schema &schema_; }; -template -query_select_intermediate query::select() -{ - return select(column_generator::generate(schema_)); -} - -template -query_select_intermediate query::select(std::initializer_list columns) -{ - auto cols = column_generator::generate(schema_); - cols.insert(cols.end(), columns); - return select(cols); -} - } #endif //QUERY_QUERY_HPP diff --git a/include/matador/sql/query_helper.hpp b/include/matador/sql/query_helper.hpp index 6739564..0aaf0f9 100644 --- a/include/matador/sql/query_helper.hpp +++ b/include/matador/sql/query_helper.hpp @@ -9,7 +9,7 @@ #include #include -#define FIELD(x) const sql::column x{this->name, #x, ""}; +#define FIELD(x) const sql::column x{*this, #x, ""}; #define QUERY_HELPER(C, ...) \ namespace matador::qh { \ diff --git a/include/matador/sql/query_intermediates.hpp b/include/matador/sql/query_intermediates.hpp index 2dc1c49..8e66461 100644 --- a/include/matador/sql/query_intermediates.hpp +++ b/include/matador/sql/query_intermediates.hpp @@ -257,9 +257,6 @@ public: template query_execute_finish table(const sql::table &table) { -// if (!schema_.exists()) { -// schema_.attach(table.name); -// } return this->table(table, column_definition_generator::generate(schema_)); } }; @@ -279,11 +276,7 @@ public: query_into_intermediate into(const sql::table &table, std::initializer_list column_names); query_into_intermediate into(const sql::table &table, std::vector &&column_names); - template - query_into_intermediate into(const sql::table &table) - { - return into(table, column_generator::generate(schema_)); - } + query_into_intermediate into(const sql::table &table); }; class query_execute_where_intermediate : public query_execute_finish diff --git a/include/matador/sql/session.hpp b/include/matador/sql/session.hpp index 0927311..a3d5c72 100644 --- a/include/matador/sql/session.hpp +++ b/include/matador/sql/session.hpp @@ -101,7 +101,11 @@ entity session::insert(Type *obj) if (!info) { return {}; } - c->query(*schema_).insert().into(info->name).values(*obj).execute(); + c->query(*schema_) + .insert() + .into(info->name, column_generator::generate(*schema_)) + .values(*obj) + .execute(); return entity{obj}; } diff --git a/include/matador/sql/table.hpp b/include/matador/sql/table.hpp index 1f7e0d7..0ab7bfc 100644 --- a/include/matador/sql/table.hpp +++ b/include/matador/sql/table.hpp @@ -1,16 +1,16 @@ #ifndef QUERY_TABLE_HPP #define QUERY_TABLE_HPP +#include "matador/sql/column.hpp" + #include #include +#include namespace matador::sql { struct table { - std::string name; - std::string alias; - table(const char *name, std::string as = "") // NOLINT(*-explicit-constructor) : name(name), alias(std::move(as)) {} table(std::string name, std::string as = "") // NOLINT(*-explicit-constructor) @@ -21,6 +21,10 @@ struct table return *this; } + std::string name; + std::string alias; + + std::vector columns; }; } diff --git a/src/sql/column.cpp b/src/sql/column.cpp index 9aa6701..3c2c0c9 100644 --- a/src/sql/column.cpp +++ b/src/sql/column.cpp @@ -1,4 +1,5 @@ #include "matador/sql/column.hpp" +#include "matador/sql/table.hpp" namespace matador::sql { @@ -23,6 +24,14 @@ column::column(std::string table_name, const char *name, std::string as) , name(name) , alias(std::move(as)) {} +column::column(struct table &t, const char *name, std::string as) +: table(t.name) +, name(name) +, alias(std::move(as)) +{ + t.columns.push_back(*this); +} + bool column::equals(const column &x) const { return table == x.table && diff --git a/src/sql/column_generator.cpp b/src/sql/column_generator.cpp index 176b733..d321896 100644 --- a/src/sql/column_generator.cpp +++ b/src/sql/column_generator.cpp @@ -4,9 +4,11 @@ namespace matador::sql { column_generator::column_generator(std::vector &column_infos, const sql::schema &ts, - const std::string &table_name) + const std::string &table_name, + bool force_lazy) : column_infos_(column_infos) , table_schema_(ts) +, force_lazy_(force_lazy) { table_name_stack_.push(table_name); } diff --git a/src/sql/query.cpp b/src/sql/query.cpp index 33292bb..6a8380b 100644 --- a/src/sql/query.cpp +++ b/src/sql/query.cpp @@ -28,6 +28,14 @@ query_select_intermediate query::select(const std::vector& columns) return {connection_, schema_, columns}; } +query_select_intermediate query::select(std::vector columns, std::initializer_list additional_columns) +{ + for (const auto &col : additional_columns) { + columns.push_back(col); + } + return {connection_, schema_, columns}; +} + query_insert_intermediate query::insert() { return query_insert_intermediate{connection_, schema_}; diff --git a/src/sql/query_compiler.cpp b/src/sql/query_compiler.cpp index dec6601..59e8a5b 100644 --- a/src/sql/query_compiler.cpp +++ b/src/sql/query_compiler.cpp @@ -70,9 +70,17 @@ void query_compiler::visit(query_from_part &from_part) void query_compiler::visit(query_join_part &join_part) { - query_.sql += " " + dialect_.token_at(dialect::token_t::JOIN) + - " " + dialect_.prepare_identifier(join_part.table().name) + - (join_part.table().alias.empty() ? "" : " AS " + dialect_.prepare_identifier(join_part.table().alias)); + if (dialect_.default_schema_name().empty()) { + query_.sql += " " + dialect_.token_at(dialect::token_t::JOIN) + + " " + dialect_.prepare_identifier(join_part.table().name) + + (join_part.table().alias.empty() ? "" : " AS " + dialect_.prepare_identifier(join_part.table().alias)); + } else { + query_.sql += " " + dialect_.token_at(dialect::token_t::JOIN) + + " " + dialect_.prepare_identifier(dialect_.default_schema_name()) + + "." + dialect_.prepare_identifier(join_part.table().name) + + (join_part.table().alias.empty() ? "" : " AS " + dialect_.prepare_identifier(join_part.table().alias)); + + } } void query_compiler::visit(query_on_part &on_part) diff --git a/src/sql/query_intermediates.cpp b/src/sql/query_intermediates.cpp index f73a7a2..27b569b 100644 --- a/src/sql/query_intermediates.cpp +++ b/src/sql/query_intermediates.cpp @@ -178,6 +178,12 @@ query_into_intermediate query_insert_intermediate::into(const table &table, std: return {connection_, schema_, data_}; } +query_into_intermediate query_insert_intermediate::into(const table &table) +{ + data_.parts.push_back(std::make_unique(table, table.columns)); + return {connection_, schema_, data_}; +} + size_t query_execute_finish::execute() { query_compiler compiler(connection_.dialect()); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 6ba60d7..4f9cec2 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -39,7 +39,8 @@ add_executable(tests EntityQueryBuilderTest.cpp models/author.hpp models/book.hpp - FieldTest.cpp) + FieldTest.cpp + models/recipe.hpp) target_link_libraries(tests PRIVATE Catch2::Catch2WithMain diff --git a/test/models/recipe.hpp b/test/models/recipe.hpp new file mode 100644 index 0000000..b4087e2 --- /dev/null +++ b/test/models/recipe.hpp @@ -0,0 +1,55 @@ +#ifndef QUERY_RECIPE_HPP +#define QUERY_RECIPE_HPP + +#include "matador/utils/access.hpp" +#include "matador/utils/field_attributes.hpp" +#include "matador/utils/foreign_attributes.hpp" + +#include "matador/sql/entity.hpp" + +#include + +namespace matador::test { + +struct ingredient +{ + unsigned long id{}; + std::string name; + + template + void process(Operator &op) { + namespace field = matador::utils::access; + field::primary_key(op, "id", id); + field::attribute(op, "name", name, 255); + } +}; + +struct recipe +{ + unsigned long id{}; + std::string name; + + template + void process(Operator &op) { + namespace field = matador::utils::access; + field::primary_key(op, "id", id); + field::attribute(op, "name", name, 255); + } +}; + +struct recipe_ingredient +{ + sql::entity recipe_; + sql::entity ingredient_; + + template + void process(Operator &op) { + namespace field = matador::utils::access; + field::belongs_to(op, "recipe_id", recipe_, utils::default_foreign_attributes); + field::belongs_to(op, "ingredient_id", ingredient_, utils::default_foreign_attributes); + } +}; + +} + +#endif //QUERY_RECIPE_HPP