From 54e6786ceb4b166178a32e00c5c6c27dff983260 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sascha=20K=C3=BChl?= Date: Sun, 8 Feb 2026 22:38:11 +0100 Subject: [PATCH] some improvements to select_query_builder and started insert_query_builder --- include/matador/orm/session.hpp | 6 +- .../matador/query/insert_query_builder.hpp | 47 ++++ include/matador/query/schema.hpp | 11 +- .../matador/query/select_query_builder.hpp | 33 ++- source/orm/CMakeLists.txt | 1 + source/orm/orm/session.cpp | 9 - source/orm/query/select_query_builder.cpp | 4 + test/backends/SessionTest.cpp | 35 +-- test/models/recipe.hpp | 7 +- test/orm/orm/SessionQueryBuilderTest.cpp | 208 ++++++++++-------- 10 files changed, 217 insertions(+), 144 deletions(-) create mode 100644 include/matador/query/insert_query_builder.hpp diff --git a/include/matador/orm/session.hpp b/include/matador/orm/session.hpp index b29d4bf..8c7991a 100644 --- a/include/matador/orm/session.hpp +++ b/include/matador/orm/session.hpp @@ -147,8 +147,6 @@ public: private: friend class query_select; - static query::fetchable_query build_select_query(query::select_query_data &&data); - private: sql::connection_pool pool_; mutable sql::statement_cache cache_; @@ -321,7 +319,7 @@ utils::result, utils::error> session::find(const Primar return utils::failure(make_error(error_code::NoPrimaryKey, "Type hasn't primary key.")); } - query::select_query_builder eqb(schema_, *this); + query::select_query_builder eqb(schema_); const query::table_column c(&it->second.table(), info.primary_key_attribute()->name()); using namespace matador::query; auto data = eqb.build(c == utils::_); @@ -352,7 +350,7 @@ utils::result, utils::error> session::find(query::criter return utils::failure(make_error(error_code::UnknownType, "Failed to determine requested type.")); } - query::select_query_builder eqb(schema_, *this); + query::select_query_builder eqb(schema_); auto data = eqb.build(std::move(clause)); if (!data.is_ok()) { return utils::failure(make_error(error_code::FailedToBuildQuery, diff --git a/include/matador/query/insert_query_builder.hpp b/include/matador/query/insert_query_builder.hpp new file mode 100644 index 0000000..d070c9e --- /dev/null +++ b/include/matador/query/insert_query_builder.hpp @@ -0,0 +1,47 @@ +#ifndef MATADOR_INSERT_QUERY_BUILDER_HPP +#define MATADOR_INSERT_QUERY_BUILDER_HPP + +#include "matador/query/basic_schema.hpp" +#include "matador/query/intermediates/executable_query.hpp" + +namespace matador::query { +class insert_query_builder { +public: + explicit insert_query_builder(const basic_schema &schema); + + template + utils::result build(const object::object_ptr &ptr) { + } + + template < class V > + void on_primary_key(const char *id, V &, const utils::primary_key_attribute& /*attr*/ = utils::default_pk_attributes) { + push(id); + if (!is_root_entity()) { + return; + } + entity_query_data_.pk_column_name = id; + } + + void on_revision(const char *id, uint64_t &/*rev*/); + + template + void on_attribute(const char *id, Type &, const utils::field_attributes &/*attr*/ = utils::null_attributes) + { + push(id); + } + + template + void on_belongs_to(const char *id, Pointer &obj, const utils::foreign_attributes &attr) { + on_foreign_object(id, obj, attr); + } + + template + void on_has_one(const char *id, Pointer &obj, const utils::foreign_attributes &attr) { + on_foreign_object(id, obj, attr); + } + +private: + const basic_schema &schema_; +}; +} +#endif //MATADOR_INSERT_QUERY_BUILDER_HPP \ No newline at end of file diff --git a/include/matador/query/schema.hpp b/include/matador/query/schema.hpp index 54287cf..d6a7651 100644 --- a/include/matador/query/schema.hpp +++ b/include/matador/query/schema.hpp @@ -154,7 +154,7 @@ public: Type obj; access::process(pc, obj); - select_query_builder qb(repo_, exec); + select_query_builder qb(repo_); const auto *pk_column = table_[pk_name_]; auto builder_result = qb.build(*pk_column == utils::_); @@ -162,13 +162,8 @@ public: return nullptr; } - auto data = builder_result.release(); - auto stmt = query::query::select(data.columns) - .from(*data.root_table) - .join_left(data.joins) - .where(std::move(data.where_clause)) - .order_by({data.root_table, data.pk_column_name}) - .asc() + auto stmt = builder_result + .release() .prepare(exec); if (!stmt) { diff --git a/include/matador/query/select_query_builder.hpp b/include/matador/query/select_query_builder.hpp index 9817e37..31fdc7b 100644 --- a/include/matador/query/select_query_builder.hpp +++ b/include/matador/query/select_query_builder.hpp @@ -25,7 +25,6 @@ struct select_query_data { const table* root_table{nullptr}; std::string pk_column_name{}; std::vector columns{}; - std::unordered_map lazy_loading_statements{}; std::vector joins{}; criteria_ptr where_clause{}; }; @@ -53,12 +52,11 @@ private: class select_query_builder final { public: - select_query_builder(const basic_schema &scm, sql::executor &exec) - : schema_(scm) - , executor_(exec){} + explicit select_query_builder(const basic_schema &scm) + : schema_(scm){} template - utils::result build(criteria_ptr clause = {}) { + utils::result build(criteria_ptr clause = {}) { const auto it = schema_.find(typeid(EntityType)); if (it == schema_.end()) { return utils::failure(query_build_error::UnknownType); @@ -75,7 +73,15 @@ public: clause->accept(transformer); entity_query_data_.where_clause = std::move(clause); } - return {utils::ok(std::move(entity_query_data_))}; + + fetchable_query q = query::query::select(entity_query_data_.columns) + .from(*entity_query_data_.root_table) + .join_left(entity_query_data_.joins) + .where(std::move(entity_query_data_.where_clause)) + .order_by({entity_query_data_.root_table, entity_query_data_.pk_column_name}) + .asc(); + + return {utils::ok(std::move(q))}; } catch (const query_builder_exception &ex) { return {utils::failure(ex.error_type())}; } catch (...) { @@ -243,6 +249,8 @@ public: ); } + const select_query_data &query_data() const; + private: template void on_foreign_object(const char *id, Pointer &, const utils::foreign_attributes &attr); @@ -264,7 +272,6 @@ private: unsigned int column_index{0}; unsigned int table_index{0}; object::join_columns_collector join_columns_collector_{}; - sql::executor &executor_; }; template @@ -297,18 +304,6 @@ void select_query_builder::on_foreign_object(const char *id, Pointer &, const ut ); } else { push(id); - using namespace matador::utils; - using namespace matador::query; - // create select query - auto result = query::query::select(generator::columns(schema_, foreign_table, generator::column_generator_options::ForceLazy)) - .from(foreign_table) - .where(table_column(&foreign_table, info.primary_key_attribute()->name(), "") == _) - .prepare(executor_); - if (!result) { - throw query_builder_exception(query_build_error::QueryError, result.release_error()); - } - - entity_query_data_.lazy_loading_statements.emplace(id, std::move(result.release())); } } diff --git a/source/orm/CMakeLists.txt b/source/orm/CMakeLists.txt index ad7767b..930ea20 100644 --- a/source/orm/CMakeLists.txt +++ b/source/orm/CMakeLists.txt @@ -185,6 +185,7 @@ add_library(matador-orm STATIC sql/resolver_service.cpp sql/statement.cpp sql/statement_cache.cpp + ../../include/matador/query/insert_query_builder.hpp ) target_include_directories(matador-orm diff --git a/source/orm/orm/session.cpp b/source/orm/orm/session.cpp index e759334..50de345 100644 --- a/source/orm/orm/session.cpp +++ b/source/orm/orm/session.cpp @@ -119,13 +119,4 @@ utils::result session::prepare(const sql::query_co std::string session::str(const sql::query_context& ctx) const { return ctx.sql; } - -query::fetchable_query session::build_select_query(query::select_query_data &&data) { - return query::query::select(data.columns) - .from(*data.root_table) - .join_left(data.joins) - .where(std::move(data.where_clause)) - .order_by({data.root_table, data.pk_column_name}) - .asc(); -} } diff --git a/source/orm/query/select_query_builder.cpp b/source/orm/query/select_query_builder.cpp index b4b2b90..dc54a50 100644 --- a/source/orm/query/select_query_builder.cpp +++ b/source/orm/query/select_query_builder.cpp @@ -64,6 +64,10 @@ void select_query_builder::push(const std::string &column_name) { entity_query_data_.columns.emplace_back(&it->second, column_name, build_alias('c', ++column_index)); } +const select_query_data & select_query_builder::query_data() const { + return entity_query_data_; +} + std::string select_query_builder::build_alias(const char prefix, const unsigned int count) { char str[4]; snprintf(str, 4, "%c%02d", prefix, count); diff --git a/test/backends/SessionTest.cpp b/test/backends/SessionTest.cpp index f5873e6..c75dfbf 100644 --- a/test/backends/SessionTest.cpp +++ b/test/backends/SessionTest.cpp @@ -284,22 +284,31 @@ TEST_CASE_METHOD(SessionFixture, "Use session to find all objects with many-to-m return schema.create(db); } ); - std::vector> ingredients; - ingredients.push_back(std::make_unique(1, "Apple")); - ingredients.push_back(std::make_unique(2, "Strawberry")); - ingredients.push_back(std::make_unique(3, "Pineapple")); - ingredients.push_back(std::make_unique(4, "Sugar")); - ingredients.push_back(std::make_unique(5, "Flour")); - ingredients.push_back(std::make_unique(6, "Butter")); - ingredients.push_back(std::make_unique(7, "Beans")); + std::vector ingredients { + object_ptr(std::make_shared(1, "Apple")), + object_ptr(std::make_shared(2, "Strawberry")), + object_ptr(std::make_shared(3, "Pineapple")), + object_ptr(std::make_shared(4, "Sugar")), + object_ptr(std::make_shared(5, "Flour")), + object_ptr(std::make_shared(6, "Butter")), + object_ptr(std::make_shared(7, "Beans")) + }; for (auto &i: ingredients) { - auto res = ses.insert(i.release()); + auto res = ses.insert(i); REQUIRE(res.is_ok()); } - std::vector> recipes; - recipes.push_back(std::make_unique(7, "Apple Crumble")); - recipes.push_back(std::make_unique(8, "Beans Chili")); - recipes.push_back(std::make_unique(9, "Fruit Salad")); + std::vector recipes { + object_ptr(std::make_shared(1, "Apple Pie", std::vector{ingredients[0], ingredients[3], ingredients[4]})), + object_ptr(std::make_shared(2, "Strawberry Cake", std::vector{ingredients[5], ingredients[6]})), + object_ptr(std::make_shared(3, "Pineapple Pie", std::vector{ingredients[0], ingredients[1], ingredients[2]})) + }; + + for (auto &r: recipes) { + auto res = ses.insert(r); + REQUIRE(res.is_ok()); + } + + } \ No newline at end of file diff --git a/test/models/recipe.hpp b/test/models/recipe.hpp index efc4f10..1678529 100644 --- a/test/models/recipe.hpp +++ b/test/models/recipe.hpp @@ -9,6 +9,7 @@ #include "matador/object/many_to_many_relation.hpp" #include +#include namespace matador::test { struct recipe; @@ -39,10 +40,14 @@ struct recipe { object::collection > ingredients{}; recipe() = default; - recipe(const unsigned int id, std::string name) : id(id), name(std::move(name)) { } + recipe(const unsigned int id, std::string name, std::vector> ings) + : id(id) + , name(std::move(name)) + , ingredients(std::move(ings)){ + } template void process(Operator &op) { diff --git a/test/orm/orm/SessionQueryBuilderTest.cpp b/test/orm/orm/SessionQueryBuilderTest.cpp index 164fc33..09a2fc8 100644 --- a/test/orm/orm/SessionQueryBuilderTest.cpp +++ b/test/orm/orm/SessionQueryBuilderTest.cpp @@ -3,7 +3,6 @@ #include "matador/sql/backend_provider.hpp" #include "matador/sql/connection.hpp" -#include "matador/sql/connection_pool.hpp" #include "matador/sql/interface/connection_impl.hpp" #include "matador/query/criteria_evaluator.hpp" @@ -37,53 +36,57 @@ TEST_CASE("Create sql query data for entity with eager has one", "[query][entity using namespace matador::test; backend_provider::instance().register_backend("noop", std::make_unique()); connection db("noop://noop.db"); - connection_pool pool("noop://noop.db", 4); schema scm; auto result = scm.attach("airplanes") .and_then( [&scm] { return scm.attach("flights"); } ); REQUIRE(result); - select_query_builder eqb(scm, db); + select_query_builder eqb(scm); const auto it = scm.find(typeid(flight)); REQUIRE(it != scm.end()); const auto* col = it->second.table()["id"]; REQUIRE(col); - auto data = eqb.build(*col == _); + auto q = eqb.build(*col == _); + REQUIRE(q.is_ok()); - REQUIRE(data.is_ok()); - REQUIRE(data->root_table->table_name() == "flights"); - REQUIRE(data->joins.size() == 1); + const auto sql = q->str(db); + const std::string expected_sql = R"(SELECT "t01"."id", "t02"."id", "t02"."brand", "t02"."model", "t01"."pilot_name" FROM "flights" "t01" LEFT JOIN "airplanes" "t02" ON "t01"."airplane_id" = "t02"."id" WHERE "t01"."id" = ? ORDER BY "t01"."id" ASC)"; + REQUIRE(expected_sql == sql); + + const auto& data = eqb.query_data(); + REQUIRE(data.root_table->table_name() == "flights"); + REQUIRE(data.joins.size() == 1); const auto flights = table("flights").as("t01"); const auto airplanes = table("airplanes").as("t02"); const std::vector expected_columns { - { &flights, "id", "c01" }, - { &airplanes, "id", "c02" }, - { &airplanes, "brand", "c03" }, - { &airplanes, "model", "c04" }, - { &flights, "pilot_name", "c05" }, - }; - REQUIRE(data->columns.size() == expected_columns.size()); + { &flights, "id", "c01" }, + { &airplanes, "id", "c02" }, + { &airplanes, "brand", "c03" }, + { &airplanes, "model", "c04" }, + { &flights, "pilot_name", "c05" }, + }; + REQUIRE(data.columns.size() == expected_columns.size()); for (size_t i = 0; i != expected_columns.size(); ++i) { - REQUIRE(expected_columns[i].equals(data->columns[i])); + REQUIRE(expected_columns[i].equals(data.columns[i])); } std::vector> expected_join_data { - { "airplanes", R"("t01"."airplane_id" = "t02"."id")"} + { "airplanes", R"("t01"."airplane_id" = "t02"."id")"} }; query_context qc; size_t index{0}; criteria_evaluator evaluator(db.dialect(), qc); - for (const auto &[join_table, condition] : data->joins) { + for (const auto &[join_table, condition] : data.joins) { REQUIRE(join_table->table_name() == expected_join_data[index].first); REQUIRE(evaluator.evaluate(*condition) == expected_join_data[index].second); ++index; } - REQUIRE(data->where_clause.get()); - auto cond = evaluator.evaluate(*data->where_clause); + REQUIRE(data.where_clause.get()); + auto cond = evaluator.evaluate(*data.where_clause); REQUIRE(cond == R"("t01"."id" = ?)"); } @@ -91,24 +94,29 @@ TEST_CASE("Create sql query data for entity with eager belongs to", "[query][ent using namespace matador::test; backend_provider::instance().register_backend("noop", std::make_unique()); connection db("noop://noop.db"); - connection_pool pool("noop://noop.db", 4); schema scm; auto result = scm.attach("authors") .and_then( [&scm] { return scm.attach("books"); } ); REQUIRE(result); - select_query_builder eqb(scm, db); + select_query_builder eqb(scm); const auto it = scm.find(typeid(book)); REQUIRE(it != scm.end()); const auto* col = it->second.table()["id"]; REQUIRE(col); - auto data = eqb.build(*col == _); + auto q = eqb.build(*col == _); - REQUIRE(data.is_ok()); - REQUIRE(data->root_table->table_name() == "books"); - REQUIRE(data->joins.size() == 1); + REQUIRE(q.is_ok()); + const auto sql = q->str(db); + const std::string expected_sql = R"(SELECT "t01"."id", "t01"."title", "t02"."id", "t02"."first_name", "t02"."last_name", "t02"."date_of_birth", "t02"."year_of_birth", "t02"."distinguished", "t01"."published_in" FROM "books" "t01" LEFT JOIN "authors" "t02" ON "t01"."author_id" = "t02"."id" WHERE "t01"."id" = ? ORDER BY "t01"."id" ASC)"; + REQUIRE(expected_sql == sql); + + const auto& data = eqb.query_data(); + + REQUIRE(data.root_table->table_name() == "books"); + REQUIRE(data.joins.size() == 1); const auto books = table("books").as("t01"); const auto authors = table("authors").as("t02"); const std::vector expected_columns { @@ -122,9 +130,9 @@ TEST_CASE("Create sql query data for entity with eager belongs to", "[query][ent { &authors, "distinguished", "c08" }, { &books, "published_in", "c09" } }; - REQUIRE(data->columns.size() == expected_columns.size()); + REQUIRE(data.columns.size() == expected_columns.size()); for (size_t i = 0; i != expected_columns.size(); ++i) { - REQUIRE(expected_columns[i].equals(data->columns[i])); + REQUIRE(expected_columns[i].equals(data.columns[i])); } std::vector> expected_join_data { @@ -134,33 +142,32 @@ TEST_CASE("Create sql query data for entity with eager belongs to", "[query][ent query_context qc; size_t index{0}; criteria_evaluator evaluator(db.dialect(), qc); - for (const auto & [join_table, clause] : data->joins) { + for (const auto & [join_table, clause] : data.joins) { REQUIRE(join_table->table_name() == expected_join_data[index].first); REQUIRE(evaluator.evaluate(*clause) == expected_join_data[index].second); ++index; } - REQUIRE(data->where_clause.get()); - auto cond = evaluator.evaluate(*data->where_clause); + REQUIRE(data.where_clause.get()); + auto cond = evaluator.evaluate(*data.where_clause); REQUIRE(cond == R"("t01"."id" = ?)"); - auto q = matador::query::query::select(data->columns) - .from(data->root_table->name()); + auto qs = matador::query::query::select(data.columns) + .from(data.root_table->name()); - for (auto &jd : data->joins) { - q.join_left(*jd.join_table) - .on(std::move(jd.condition)); - } - auto context = q - .where(std::move(data->where_clause)) - .str(db); + // for (auto &jd : data.joins) { + // qs.join_left(*jd.join_table) + // .on(std::move(jd.condition)); + // } + // auto context = qs + // .where(std::move(data.where_clause)) + // .str(db); } 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"); - connection_pool pool("noop://noop.db", 4); schema scm; auto result = scm.attach("products") @@ -170,17 +177,23 @@ TEST_CASE("Create sql query data for entity with eager has many belongs to", "[q .and_then( [&scm] { return scm.attach("orders"); } ); REQUIRE(result); - select_query_builder eqb(scm, db); + select_query_builder eqb(scm); const auto it = scm.find(typeid(order)); REQUIRE(it != scm.end()); const auto* col = it->second.table()["order_id"]; REQUIRE(col); - auto data = eqb.build(*col == _); + auto q = eqb.build(*col == _); - REQUIRE(data.is_ok()); - REQUIRE(data->root_table->table_name() == "orders"); - REQUIRE(data->joins.size() == 1); + REQUIRE(q.is_ok()); + const auto sql = q->str(db); + const std::string expected_sql = R"(SELECT "t01"."order_id", "t01"."order_date", "t01"."required_date", "t01"."shipped_date", "t01"."ship_via", "t01"."freight", "t01"."ship_name", "t01"."ship_address", "t01"."ship_city", "t01"."ship_region", "t01"."ship_postal_code", "t01"."ship_country", "t02"."order_details_id", "t02"."order_id", "t02"."product_id" FROM "orders" "t01" LEFT JOIN "order_details" "t02" ON "t01"."order_id" = "t02"."order_id" WHERE "t01"."order_id" = ? ORDER BY "t01"."order_id" ASC)"; + REQUIRE(expected_sql == sql); + + const auto& data = eqb.query_data(); + + REQUIRE(data.root_table->table_name() == "orders"); + REQUIRE(data.joins.size() == 1); const auto orders = table("orders").as("t01"); const auto order_details = table("order_details").as("t02"); const std::vector expected_columns = { @@ -200,9 +213,9 @@ TEST_CASE("Create sql query data for entity with eager has many belongs to", "[q { &order_details, "order_id", "c14" }, { &order_details, "product_id", "c15" } }; - REQUIRE(data->columns.size() == expected_columns.size()); + REQUIRE(data.columns.size() == expected_columns.size()); for (size_t i = 0; i != expected_columns.size(); ++i) { - REQUIRE(expected_columns[i].equals(data->columns[i])); + REQUIRE(expected_columns[i].equals(data.columns[i])); } std::vector> expected_join_data { @@ -212,39 +225,44 @@ TEST_CASE("Create sql query data for entity with eager has many belongs to", "[q query_context qc; size_t index{0}; criteria_evaluator evaluator(db.dialect(), qc); - for (const auto &jd : data->joins) { + for (const auto &jd : data.joins) { REQUIRE(jd.join_table->table_name() == expected_join_data[index].first); - REQUIRE(evaluator.evaluate(*jd.condition) == expected_join_data[index].second); + // REQUIRE(evaluator.evaluate(*jd.condition) == expected_join_data[index].second); ++index; } - REQUIRE(data->where_clause.get()); - auto cond = evaluator.evaluate(*data->where_clause); - REQUIRE(cond == R"("t01"."order_id" = ?)"); + // REQUIRE(data.where_clause.get()); + // auto cond = evaluator.evaluate(*data.where_clause); + // REQUIRE(cond == R"("t01"."order_id" = ?)"); } 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"); - connection_pool pool("noop://noop.db", 4); schema scm; auto result = scm.attach("recipes") .and_then( [&scm] { return scm.attach("ingredients"); } ); REQUIRE(result); - select_query_builder eqb(scm, db); + select_query_builder eqb(scm); const auto it = scm.find(typeid(ingredient)); REQUIRE(it != scm.end()); const auto* col = it->second.table()["id"]; REQUIRE(col); - auto data = eqb.build(*col == _); + auto q = eqb.build(*col == _); - REQUIRE(data.is_ok()); - REQUIRE(data->root_table->table_name() == "ingredients"); - REQUIRE(data->joins.size() == 2); + REQUIRE(q.is_ok()); + const auto sql = q->str(db); + const std::string expected_sql = R"(SELECT "t01"."id", "t01"."name", "t03"."id", "t03"."name" FROM "ingredients" "t01" LEFT JOIN "recipe_ingredients" "t02" ON "t01"."id" = "t02"."ingredient_id" LEFT JOIN "recipes" "t03" ON "t02"."recipe_id" = "t03"."id" WHERE "t01"."id" = ? ORDER BY "t01"."id" ASC)"; + REQUIRE(expected_sql == sql); + + const auto& data = eqb.query_data(); + + REQUIRE(data.root_table->table_name() == "ingredients"); + REQUIRE(data.joins.size() == 2); const auto ingredients = table("ingredients").as("t01"); const auto recipes = table("recipes").as("t03"); const std::vector expected_columns { @@ -253,9 +271,9 @@ TEST_CASE("Create sql query data for entity with eager many to many", "[query][e { &recipes, "id", "c03" }, { &recipes, "name", "c04" } }; - REQUIRE(data->columns.size() == expected_columns.size()); + REQUIRE(data.columns.size() == expected_columns.size()); for (size_t i = 0; i != expected_columns.size(); ++i) { - REQUIRE(expected_columns[i].equals(data->columns[i])); + REQUIRE(expected_columns[i].equals(data.columns[i])); } std::vector> expected_join_data { @@ -266,39 +284,44 @@ TEST_CASE("Create sql query data for entity with eager many to many", "[query][e query_context qc; size_t index{0}; criteria_evaluator evaluator(db.dialect(), qc); - for (const auto &jd : data->joins) { + for (const auto &jd : data.joins) { REQUIRE(jd.join_table->table_name() == expected_join_data[index].first); - REQUIRE(evaluator.evaluate(*jd.condition) == expected_join_data[index].second); + // REQUIRE(evaluator.evaluate(*jd.condition) == expected_join_data[index].second); ++index; } - REQUIRE(data->where_clause.get()); - auto cond = evaluator.evaluate(*data->where_clause); - REQUIRE(cond == R"("t01"."id" = ?)"); + // REQUIRE(data.where_clause.get()); + // auto cond = evaluator.evaluate(*data.where_clause); + // REQUIRE(cond == R"("t01"."id" = ?)"); } 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"); - connection_pool pool("noop://noop.db", 4); schema scm; auto result = scm.attach("students") .and_then( [&scm] { return scm.attach("courses"); } ); REQUIRE(result); - select_query_builder eqb(scm, db); + select_query_builder eqb(scm); const auto it = scm.find(typeid(course)); REQUIRE(it != scm.end()); const auto* col = it->second.table()["id"]; REQUIRE(col); - auto data = eqb.build(*col == _); + auto q = eqb.build(*col == _); - REQUIRE(data.is_ok()); - REQUIRE(data->root_table->table_name() == "courses"); - REQUIRE(data->joins.size() == 2); + REQUIRE(q.is_ok()); + const auto sql = q->str(db); + const std::string expected_sql = R"(SELECT "t01"."id", "t01"."title", "t03"."id", "t03"."name" FROM "courses" "t01" LEFT JOIN "student_courses" "t02" ON "t01"."id" = "t02"."course_id" LEFT JOIN "students" "t03" ON "t02"."student_id" = "t03"."id" WHERE "t01"."id" = ? ORDER BY "t01"."id" ASC)"; + REQUIRE(expected_sql == sql); + + const auto& data = eqb.query_data(); + + REQUIRE(data.root_table->table_name() == "courses"); + REQUIRE(data.joins.size() == 2); const auto courses = table("courses").as("t01"); const auto students = table("students").as("t03"); const std::vector expected_columns { @@ -307,9 +330,9 @@ TEST_CASE("Create sql query data for entity with eager many to many (inverse par { &students, "id", "c03" }, { &students, "name", "c04" } }; - REQUIRE(data->columns.size() == expected_columns.size()); + REQUIRE(data.columns.size() == expected_columns.size()); for (size_t i = 0; i != expected_columns.size(); ++i) { - REQUIRE(expected_columns[i].equals(data->columns[i])); + REQUIRE(expected_columns[i].equals(data.columns[i])); } std::vector> expected_join_data { @@ -320,40 +343,45 @@ TEST_CASE("Create sql query data for entity with eager many to many (inverse par query_context qc; size_t index{0}; criteria_evaluator evaluator(db.dialect(), qc); - for (const auto &jd : data->joins) { + for (const auto &jd : data.joins) { REQUIRE(jd.join_table->table_name() == expected_join_data[index].first); - REQUIRE(evaluator.evaluate(*jd.condition) == expected_join_data[index].second); + // REQUIRE(evaluator.evaluate(*jd.condition) == expected_join_data[index].second); ++index; } - REQUIRE(data->where_clause.get()); - auto cond = evaluator.evaluate(*data->where_clause); - REQUIRE(cond == R"("t01"."id" = ?)"); + // REQUIRE(data.where_clause.get()); + // auto cond = evaluator.evaluate(*data.where_clause); + // REQUIRE(cond == R"("t01"."id" = ?)"); } TEST_CASE("Test eager relationship", "[query][entity][builder]") { using namespace matador::test; backend_provider::instance().register_backend("noop", std::make_unique()); connection db("noop://noop.db"); - connection_pool pool("noop://noop.db", 4); schema scm; auto result = scm.attach("departments") .and_then( [&scm] { return scm.attach("employees"); } ); REQUIRE(result); - select_query_builder eqb(scm, db); + select_query_builder eqb(scm); - auto data = eqb.build(); - REQUIRE(data.is_ok()); + auto q = eqb.build(); + REQUIRE(q.is_ok()); + const auto sql = q->str(db); + const std::string expected_sql = R"(SELECT "t01"."id", "t01"."name", "t02"."id", "t02"."first_name", "t02"."last_name", "t02"."dep_id" FROM "departments" "t01" LEFT JOIN "employees" "t02" ON "t01"."id" = "t02"."dep_id" ORDER BY "t01"."id" ASC)"; + REQUIRE(expected_sql == sql); - auto ctx = query::select(data->columns) - .from(*data->root_table) - .join_left(data->joins) - .where(std::move(data->where_clause)) - .order_by(table_column{data->root_table, data->pk_column_name}) - .asc() - .str(db); + const auto& data = eqb.query_data(); - std::cout << ctx << std::endl; + + // auto ctx = query::select(data.columns) + // .from(*data.root_table) + // .join_left(data.joins) + // .where(std::move(data.where_clause)) + // .order_by(table_column{data.root_table, data.pk_column_name}) + // .asc() + // .str(db); + // + // std::cout << ctx << std::endl; } \ No newline at end of file