use table metas where possible

This commit is contained in:
2026-01-09 18:10:23 +01:00
parent ac53526a27
commit b9f5819be5
9 changed files with 173 additions and 404 deletions
+66 -203
View File
@@ -13,6 +13,7 @@
#include "models/person.hpp"
#include "models/recipe.hpp"
#include "models/shipment.hpp"
#include "models/model_metas.hpp"
#include "../test/utils/record_printer.hpp"
@@ -20,93 +21,59 @@ using namespace matador::object;
using namespace matador::query;
using namespace matador::sql;
using namespace matador::test;
META_TABLE(recipes, RECIPE, id, name);
META_TABLE(ingredients, INGREDIENT, id, name);
META_TABLE(recipe_ingredients, RECIPE_INGREDIENT, recipe_id, ingredient_id);
META_TABLE(airplanes, AIRPLANE, id, brand, model);
META_TABLE(flights, FLIGHT, id, airplane_id, pilot_name);
META_TABLE(shipments, SHIPMENT, id, tracking_number)
META_TABLE(packages, PACKAGE, id, weight, shipment_id)
using namespace matador::query::meta;
TEST_CASE_METHOD(QueryFixture, "Create table with foreign key relation", "[query][foreign][relation]") {
auto result = repo.attach<airplane>("airplane")
.and_then( [this] { return repo.attach<flight>("flight");} );
.and_then([this] { return repo.attach<flight>("flight");})
.and_then([this] {return repo.create(db); });
REQUIRE(result.is_ok());
auto obj = object_generator::generate<airplane>(repo.repo(), "airplane");
auto res = query::create()
.table(obj->name())
.columns(obj->attributes())
.constraints(obj->constraints())
.execute(db);
REQUIRE(res.is_ok());
REQUIRE(*res == 0);
check_table_exists("airplane");
tables_to_drop.emplace("airplane");
obj = object_generator::generate<flight>(repo.repo(), "flight");
res = query::create()
.table(obj->name())
.columns(obj->attributes())
.constraints(obj->constraints())
.execute(db);
REQUIRE(res.is_ok());
REQUIRE(*res == 0);
check_table_exists("flight");
tables_to_drop.emplace("flight");
}
TEST_CASE_METHOD(QueryFixture, "Execute select statement with where clause", "[query][where]") {
REQUIRE(repo.attach<person>("person"));
const auto obj = object_generator::generate<person>(repo.repo(), "person");
auto res = query::create()
.table(obj->name())
.columns(obj->attributes())
.constraints(obj->constraints())
.execute(db);
REQUIRE(res.is_ok());
REQUIRE(*res == 0);
REQUIRE(repo.attach<person>("persons"));
auto result = repo.create(db);
REQUIRE(result.is_ok());
check_table_exists("person");
tables_to_drop.emplace("person");
check_table_exists(PERSON.table_name());
person george{7, "george", 45};
george.image.emplace_back(37);
res = query::insert()
.into("person", generator::columns<person>(repo))
auto res = query::insert()
.into(PERSON, {PERSON.id, PERSON.name, PERSON.age, PERSON.image})
.values(george)
.execute(db);
REQUIRE(res.is_ok());
REQUIRE(*res == 1);
// fetch person as record
auto result_record = query::select(generator::columns<person>(repo))
.from("person")
.where("id"_col == 7)
auto result_record = query::select({PERSON.id, PERSON.name, PERSON.age, PERSON.image})
.from(PERSON)
.where(PERSON.id == 7)
.fetch_all(db);
REQUIRE(result_record.is_ok());
for (const auto &i: *result_record) {
REQUIRE(i.size() == 4);
REQUIRE(i.at(0).name() == "person.id");
REQUIRE(i.at(0).name() == "persons.id");
REQUIRE(i.at(0).is_integer());
REQUIRE(i.at(0).as<uint32_t>() == george.id);
REQUIRE(i.at(1).name() == "person.name");
REQUIRE(i.at(1).name() == "persons.name");
REQUIRE(i.at(1).is_varchar());
REQUIRE(i.at(1).as<std::string>() == george.name);
REQUIRE(i.at(2).name() == "person.age");
REQUIRE(i.at(2).name() == "persons.age");
REQUIRE(i.at(2).is_integer());
REQUIRE(i.at(2).as<uint32_t>() == george.age);
}
// fetch person as person
auto result_person = query::select(generator::columns<person>(repo))
.from("person")
.where("id"_col == 7)
auto result_person = query::select({PERSON.id, PERSON.name, PERSON.age, PERSON.image})
.from(PERSON)
.where(PERSON.id == 7)
.fetch_all<person>(db);
REQUIRE(result_person.is_ok());
@@ -164,33 +131,13 @@ TEST_CASE_METHOD(QueryFixture, "Execute insert statement", "[query][insert]") {
}
TEST_CASE_METHOD(QueryFixture, "Select statement with foreign key", "[query][foreign]") {
auto result = repo.attach<airplane>("airplane")
.and_then( [this] { return repo.attach<flight>("flight");} );
auto result = repo.attach<airplane>("airplanes")
.and_then( [this] { return repo.attach<flight>("flights");} )
.and_then([this] {return repo.create(db); });
REQUIRE(result.is_ok());
auto obj = object_generator::generate<airplane>(repo.repo(), "airplane");
auto res = query::create()
.table(obj->name())
.columns(obj->attributes())
.constraints(obj->constraints())
.execute(db);
REQUIRE(res.is_ok());
REQUIRE(*res == 0);
REQUIRE(db.exists("airplane"));
tables_to_drop.emplace("airplane");
obj = object_generator::generate<flight>(repo.repo(), "flight");
res = query::create()
.table(obj->name())
.columns(obj->attributes())
.constraints(obj->constraints())
.execute(db);
REQUIRE(res.is_ok());
REQUIRE(*res == 0);
REQUIRE(db.exists("flight"));
tables_to_drop.emplace("flight");
REQUIRE(db.exists(AIRPLANE.table_name()));
REQUIRE(db.exists(FLIGHT.table_name()));
std::vector planes{
object_ptr(new airplane{1, "Airbus", "A380"}),
@@ -199,8 +146,8 @@ TEST_CASE_METHOD(QueryFixture, "Select statement with foreign key", "[query][for
};
for (const auto &plane: planes) {
res = query::insert()
.into("airplane", generator::columns<airplane>(repo))
auto res = query::insert()
.into(AIRPLANE, {AIRPLANE.id, AIRPLANE.brand, AIRPLANE.model})
.values(*plane)
.execute(db);
REQUIRE(res.is_ok());
@@ -208,22 +155,22 @@ TEST_CASE_METHOD(QueryFixture, "Select statement with foreign key", "[query][for
}
auto count = query::select({count_all()})
.from("airplane")
.from(AIRPLANE)
.fetch_value<int>(db);
REQUIRE(count.is_ok());
REQUIRE(*count == 3);
flight f4711{4, planes.at(1), "hans"};
res = query::insert()
.into("flight", generator::columns<flight>(repo))
auto res = query::insert()
.into(FLIGHT, {FLIGHT.id, FLIGHT.airplane_id, FLIGHT.pilot_name})
.values(f4711)
.execute(db);
REQUIRE(res.is_ok());
REQUIRE(*res == 1);
auto f = query::select(generator::columns<flight>(repo))
.from("flight")
auto f = query::select({FLIGHT.id, FLIGHT.airplane_id, FLIGHT.pilot_name})
.from(FLIGHT)
.fetch_one(db);
REQUIRE(f.is_ok());
@@ -234,32 +181,12 @@ TEST_CASE_METHOD(QueryFixture, "Select statement with foreign key", "[query][for
TEST_CASE_METHOD(QueryFixture, "Select statement with foreign key and join_left", "[query][foreign][join_left]") {
auto result = repo.attach<airplane>("airplanes")
.and_then( [this] { return repo.attach<flight>("flights");} );
.and_then( [this] { return repo.attach<flight>("flights");} )
.and_then([this] {return repo.create(db); });
REQUIRE(result.is_ok());
auto obj = object_generator::generate<airplane>(repo.repo(), "airplanes");
auto res = query::create()
.table(obj->name())
.columns(obj->attributes())
.constraints(obj->constraints())
.execute(db);
REQUIRE(res.is_ok());
REQUIRE(*res == 0);
REQUIRE(db.exists("airplanes"));
tables_to_drop.emplace("airplanes");
obj = object_generator::generate<flight>(repo.repo(), "flights");
res = query::create()
.table(obj->name())
.columns(obj->attributes())
.constraints(obj->constraints())
.execute(db);
REQUIRE(res.is_ok());
REQUIRE(*res == 0);
REQUIRE(db.exists("flights"));
tables_to_drop.emplace("flights");
REQUIRE(db.exists(AIRPLANE.table_name()));
REQUIRE(db.exists(FLIGHT.table_name()));
std::vector planes{
object_ptr(new airplane{1, "Airbus", "A380"}),
@@ -268,8 +195,8 @@ TEST_CASE_METHOD(QueryFixture, "Select statement with foreign key and join_left"
};
for (const auto &plane: planes) {
res = query::insert()
.into("airplanes", generator::columns<airplane>(repo))
auto res = query::insert()
.into(AIRPLANE, {AIRPLANE.id, AIRPLANE.brand, AIRPLANE.model})
.values(*plane)
.execute(db);
REQUIRE(res.is_ok());
@@ -277,7 +204,7 @@ TEST_CASE_METHOD(QueryFixture, "Select statement with foreign key and join_left"
}
auto count = query::select({count_all()})
.from("airplanes")
.from(AIRPLANE)
.fetch_value<int>(db).value();
REQUIRE(count == 3);
@@ -289,16 +216,16 @@ TEST_CASE_METHOD(QueryFixture, "Select statement with foreign key and join_left"
};
for (const auto &f: flights) {
res = query::insert()
.into("flights", {"id", "airplane_id", "pilot_name"})
auto res = query::insert()
.into(FLIGHT, {FLIGHT.id, FLIGHT.airplane_id, FLIGHT.pilot_name})
.values(*f)
.execute(db);
REQUIRE(res.is_ok());
REQUIRE(*res == 1);
}
auto flight_result = query::select(generator::columns<flight>(repo))
.from("flights")
auto flight_result = query::select({FLIGHT.id, FLIGHT.airplane_id, FLIGHT.pilot_name})
.from(FLIGHT)
.fetch_one(db);
REQUIRE(flight_result.is_ok());
REQUIRE(flight_result->has_value());
@@ -306,7 +233,6 @@ TEST_CASE_METHOD(QueryFixture, "Select statement with foreign key and join_left"
REQUIRE(flight_result.value()->at(1).as<uint32_t>() == 1);
REQUIRE(flight_result.value()->at(2).as<std::string>() == "hans");
using namespace matador::query::meta;
const auto f = FLIGHT.as("f");
const auto ap = AIRPLANE.as("ap");
@@ -334,32 +260,12 @@ TEST_CASE_METHOD(QueryFixture, "Select statement with foreign key and join_left"
TEST_CASE_METHOD(QueryFixture, "Select statement with foreign key and for single entity", "[query][join_left][find]") {
auto result = repo.attach<airplane>("airplanes")
.and_then( [this] { return repo.attach<flight>("flights");} );
.and_then([this] { return repo.attach<flight>("flights");})
.and_then([this] {return repo.create(db); });
REQUIRE(result.is_ok());
auto obj = object_generator::generate<airplane>(repo.repo(), "airplanes");
auto res = query::create()
.table(obj->name())
.columns(obj->attributes())
.constraints(obj->constraints())
.execute(db);
REQUIRE(res.is_ok());
REQUIRE(*res == 0);
REQUIRE(db.exists("airplanes"));
tables_to_drop.emplace("airplanes");
obj = object_generator::generate<flight>(repo.repo(), "flights");
res = query::create()
.table(obj->name())
.columns(obj->attributes())
.constraints(obj->constraints())
.execute(db);
REQUIRE(res.is_ok());
REQUIRE(*res == 0);
REQUIRE(db.exists("flights"));
tables_to_drop.emplace("flights");
REQUIRE(db.exists(AIRPLANE.table_name()));
REQUIRE(db.exists(FLIGHT.table_name()));
std::vector planes{
object_ptr(new airplane{1, "Airbus", "A380"}),
@@ -368,8 +274,8 @@ TEST_CASE_METHOD(QueryFixture, "Select statement with foreign key and for single
};
for (const auto &plane: planes) {
res = query::insert()
.into("airplanes", generator::columns<airplane>(repo))
auto res = query::insert()
.into(AIRPLANE, {AIRPLANE.id, AIRPLANE.brand, AIRPLANE.model})
.values(*plane)
.execute(db);
REQUIRE(res.is_ok());
@@ -377,7 +283,7 @@ TEST_CASE_METHOD(QueryFixture, "Select statement with foreign key and for single
}
auto count = query::select({count_all()})
.from("airplanes")
.from(AIRPLANE)
.fetch_value<int>(db);
REQUIRE(count.is_ok());
REQUIRE(count->has_value());
@@ -391,16 +297,16 @@ TEST_CASE_METHOD(QueryFixture, "Select statement with foreign key and for single
};
for (const auto &f: flights) {
res = query::insert()
.into("flights", generator::columns<flight>(repo))
auto res = query::insert()
.into(FLIGHT, {FLIGHT.id, FLIGHT.airplane_id, FLIGHT.pilot_name})
.values(*f)
.execute(db);
REQUIRE(res.is_ok());
REQUIRE(*res == 1);
}
auto flight_result = query::select(generator::columns<flight>(repo))
.from("flights")
auto flight_result = query::select({FLIGHT.id, FLIGHT.airplane_id, FLIGHT.pilot_name})
.from(FLIGHT)
.fetch_one(db);
REQUIRE(flight_result.is_ok());
REQUIRE(flight_result->has_value());
@@ -408,7 +314,6 @@ TEST_CASE_METHOD(QueryFixture, "Select statement with foreign key and for single
REQUIRE(flight_result.value()->at(1).as<uint32_t>() == 1);
REQUIRE(flight_result.value()->at(2).as<std::string>() == "hans");
using namespace matador::query::meta;
const auto f = FLIGHT.as("f");
const auto ap = AIRPLANE.as("ap");
@@ -434,46 +339,12 @@ TEST_CASE_METHOD(QueryFixture, "Select statement with foreign key and for single
TEST_CASE_METHOD(QueryFixture, "Select statement with many to many relationship", "[query][join][many_to_many]") {
auto result = repo.attach<ingredient>("ingredients")
.and_then( [this] { return repo.attach<recipe>("recipes"); } );
.and_then( [this] { return repo.attach<recipe>("recipes"); } )
.and_then([this] {return repo.create(db); });
auto obj = object_generator::generate<recipe>(repo.repo(), "recipes");
auto res = query::create()
.table(obj->name())
.columns(obj->attributes())
.constraints(obj->constraints())
.execute(db);
REQUIRE(res.is_ok());
REQUIRE(*res == 0);
REQUIRE(db.exists("recipes"));
tables_to_drop.emplace("recipes");
obj = object_generator::generate<ingredient>(repo.repo(), "ingredients");
res = query::create()
.table(obj->name())
.columns(obj->attributes())
.constraints(obj->constraints())
.execute(db);
REQUIRE(res.is_ok());
REQUIRE(*res == 0);
REQUIRE(db.exists("ingredients"));
tables_to_drop.emplace("ingredients");
const auto it = repo.find("recipe_ingredients");
REQUIRE(it != repo.end());
obj = it->second.node().info().object();
// obj = object_generator::generate<recipe_ingredient>(repo.repo(), "recipe_ingredients");
res = query::create()
.table(obj->name())
.columns(obj->attributes())
.constraints(obj->constraints())
.execute(db);
REQUIRE(res.is_ok());
REQUIRE(*res == 0);
REQUIRE(db.exists("recipe_ingredients"));
tables_to_drop.emplace("recipe_ingredients");
REQUIRE(db.exists(RECIPE.table_name()));
REQUIRE(db.exists(INGREDIENT.table_name()));
REQUIRE(db.exists(RECIPE_INGREDIENT.table_name()));
std::vector<ingredient> ingredients {
{1, "Apple"},
@@ -486,8 +357,8 @@ TEST_CASE_METHOD(QueryFixture, "Select statement with many to many relationship"
};
for (const auto &i: ingredients) {
res = query::insert()
.into("ingredients", generator::columns<ingredient>(repo))
auto res = query::insert()
.into(INGREDIENT, {INGREDIENT.id, INGREDIENT.name})
.values(i)
.execute(db);
REQUIRE(res.is_ok());
@@ -501,8 +372,8 @@ TEST_CASE_METHOD(QueryFixture, "Select statement with many to many relationship"
};
for (const auto &r: recipes) {
res = query::insert()
.into("recipes", generator::columns<recipe>(repo))
auto res = query::insert()
.into(RECIPE, {RECIPE.id, RECIPE.name})
.values(r)
.execute(db);
REQUIRE(res.is_ok());
@@ -520,11 +391,9 @@ TEST_CASE_METHOD(QueryFixture, "Select statement with many to many relationship"
{ 9, 3 }
};
using namespace matador::query::meta;
for (const auto & [recipe_id, ingredient_id]: recipe_ingredients) {
res = query::insert()
.into("recipe_ingredients", RECIPE_INGREDIENT)
auto res = query::insert()
.into(RECIPE_INGREDIENT, {RECIPE_INGREDIENT.recipe_id, RECIPE_INGREDIENT.ingredient_id})
.values({recipe_id, ingredient_id})
.execute(db);
REQUIRE(res.is_ok());
@@ -618,12 +487,8 @@ void print(std::ostream& out, const record& row) {
TEST_CASE_METHOD(QueryFixture, "Test load entity with eager has many relation", "[query][has_many][eager]") {
auto result = repo.attach<package>("packages")
.and_then( [this] { return repo.attach<shipment>("shipments"); } );
REQUIRE(result.is_ok());
tables_to_drop.emplace("shipments");
tables_to_drop.emplace("packages");
result = repo.create(db);
.and_then([this] { return repo.attach<shipment>("shipments"); })
.and_then([this] {return repo.create(db); });
REQUIRE(result.is_ok());
const std::vector shipments {
@@ -631,8 +496,6 @@ TEST_CASE_METHOD(QueryFixture, "Test load entity with eager has many relation",
object_ptr{new shipment{2, "0815"}}
};
using namespace matador::query::meta;
for (const auto &sh: shipments) {
auto res = query::insert()
.into(SHIPMENT, SHIPMENT)