From 1e784308558b5c51b7732e2c7095e0813da54fb1 Mon Sep 17 00:00:00 2001 From: sascha Date: Fri, 27 Feb 2026 16:29:49 +0100 Subject: [PATCH] added returning to update statement and added error code implementation for query --- demo/work.cpp | 3 +- include/matador/query/error_code.hpp | 35 +++++++++++++++ .../query_execute_where_intermediate.hpp | 10 +++++ .../intermediates/query_into_intermediate.hpp | 11 +---- .../intermediates/query_set_intermediate.hpp | 7 +-- .../query_values_intermediate.hpp | 24 ++++++++++ source/orm/CMakeLists.txt | 4 ++ source/orm/query/error_code.cpp | 45 +++++++++++++++++++ .../query_execute_where_intermediate.cpp | 4 ++ .../intermediates/query_into_intermediate.cpp | 5 --- .../intermediates/query_set_intermediate.cpp | 3 ++ .../query_values_intermediate.cpp | 11 +++++ source/orm/query/schema.cpp | 3 +- source/orm/query/table_pk_generator.cpp | 2 + test/orm/orm/SessionQueryBuilderTest.cpp | 6 +-- test/orm/query/InsertQueryBuilderTest.cpp | 5 ++- test/orm/query/QueryBuilderTest.cpp | 20 +++++++++ 17 files changed, 172 insertions(+), 26 deletions(-) create mode 100644 include/matador/query/error_code.hpp create mode 100644 include/matador/query/intermediates/query_values_intermediate.hpp create mode 100644 source/orm/query/error_code.cpp create mode 100644 source/orm/query/intermediates/query_values_intermediate.cpp diff --git a/demo/work.cpp b/demo/work.cpp index eef528f..3d9b7fd 100644 --- a/demo/work.cpp +++ b/demo/work.cpp @@ -88,6 +88,7 @@ int main() { .and_then([&admin_schema] { return admin_schema.attach("id_list_payloads"); }) .and_then([&admin_schema] { return admin_schema.attach("id_payloads"); }) .and_then([&admin_schema] { return admin_schema.attach("tasks"); }) + .and_then([&admin_schema, &pool] { return admin_schema.create( *pool.acquire() ); }) ; admin_schema.dump(std::cout); @@ -109,7 +110,7 @@ int main() { // } /* - * const auto statement = QString( "SELECT %5.%6, %1.%2 FROM %3 %1, %4 %5 WHERE %1.%2=%5.%6 AND %7" ) +const auto statement = QString( "SELECT %5.%6, %1.%2 FROM %3 %1, %4 %5 WHERE %1.%2=%5.%6 AND %7" ) .arg( payloadTableAliasName, payloadSqlMetaInfo.columnName( Payload::Attributes::idAttributeId() ), Payload::staticSqlMetaInfo().tableName(), diff --git a/include/matador/query/error_code.hpp b/include/matador/query/error_code.hpp new file mode 100644 index 0000000..308081d --- /dev/null +++ b/include/matador/query/error_code.hpp @@ -0,0 +1,35 @@ +#ifndef MATADOR_ERROR_CODE_HPP +#define MATADOR_ERROR_CODE_HPP + +#include +#include + +namespace matador::query { +enum class error_code { + Success, + Failure, + InvalidQuery, + InvalidSchema, + InvalidTable, + InvalidColumn, + InvalidConstraint, + InvalidDataType, + InvalidValue +}; + +class query_category_impl final : public std::error_category +{ +public: + [[nodiscard]] const char* name() const noexcept override; + [[nodiscard]] std::string message(int ev) const override; +}; + +const std::error_category& query_category(); +std::error_code make_error_code(error_code e); +std::error_condition make_error_condition(error_code e); + +} + +template <> +struct std::is_error_code_enum : true_type {}; +#endif //MATADOR_ERROR_CODE_HPP \ No newline at end of file diff --git a/include/matador/query/intermediates/query_execute_where_intermediate.hpp b/include/matador/query/intermediates/query_execute_where_intermediate.hpp index 6168f7b..139193c 100644 --- a/include/matador/query/intermediates/query_execute_where_intermediate.hpp +++ b/include/matador/query/intermediates/query_execute_where_intermediate.hpp @@ -2,6 +2,7 @@ #define QUERY_EXECUTE_WHERE_INTERMEDIATE_HPP #include "matador/query/intermediates/executable_query.hpp" +#include "matador/query/intermediates/fetchable_query.hpp" namespace matador::query { @@ -14,9 +15,18 @@ class query_execute_where_intermediate : public executable_query public: using executable_query::executable_query; + template + fetchable_query returning(const TableColumns&... table_columns) { + const std::vector tcv { table_columns... }; + return returning(tcv); + } + query_execute_limit_intermediate limit(size_t limit); query_execute_order_by_intermediate order_by(const table_column &col); query_execute_order_by_intermediate order_by(std::initializer_list columns); + +private: + fetchable_query returning(const std::vector& tables); }; } diff --git a/include/matador/query/intermediates/query_into_intermediate.hpp b/include/matador/query/intermediates/query_into_intermediate.hpp index 79230a8..dc9c6bc 100644 --- a/include/matador/query/intermediates/query_into_intermediate.hpp +++ b/include/matador/query/intermediates/query_into_intermediate.hpp @@ -2,22 +2,13 @@ #define QUERY_INTO_INTERMEDIATE_HPP #include "matador/query/intermediates/executable_query.hpp" -#include "matador/query/intermediates/fetchable_query.hpp" +#include "matador/query/intermediates/query_values_intermediate.hpp" #include "matador/query/value_extractor.hpp" #include "matador/utils/placeholder.hpp" namespace matador::query { -class table_column; - -class query_values_intermediate : public executable_query { -public: - using executable_query::executable_query; - - fetchable_query returning(const table_column &col); -}; - class query_into_intermediate : public query_intermediate { public: using query_intermediate::query_intermediate; diff --git a/include/matador/query/intermediates/query_set_intermediate.hpp b/include/matador/query/intermediates/query_set_intermediate.hpp index cc07927..fe5bdd0 100644 --- a/include/matador/query/intermediates/query_set_intermediate.hpp +++ b/include/matador/query/intermediates/query_set_intermediate.hpp @@ -9,14 +9,11 @@ namespace matador::query { -class query_set_intermediate : public executable_query -{ +class query_set_intermediate : public executable_query { public: using executable_query::executable_query; - query_execute_where_intermediate where(std::unique_ptr cond) { - return where_clause(std::move(cond)); - } + query_execute_where_intermediate where(std::unique_ptr cond); private: query_execute_where_intermediate where_clause(std::unique_ptr &&cond); diff --git a/include/matador/query/intermediates/query_values_intermediate.hpp b/include/matador/query/intermediates/query_values_intermediate.hpp new file mode 100644 index 0000000..1bda74f --- /dev/null +++ b/include/matador/query/intermediates/query_values_intermediate.hpp @@ -0,0 +1,24 @@ +#ifndef MATADOR_QUERY_VALUES_INTERMEDIATE_H +#define MATADOR_QUERY_VALUES_INTERMEDIATE_H + +#include "matador/query/intermediates/executable_query.hpp" +#include "matador/query/intermediates/fetchable_query.hpp" + +namespace matador::query { +class table_column; +class query_values_intermediate : public executable_query { +public: + using executable_query::executable_query; + + template + fetchable_query returning(const TableColumns&... table_columns) { + const std::vector tcv { table_columns... }; + return returning(tcv); + } + +private: + fetchable_query returning(const std::vector& tables); +}; +} + +#endif //MATADOR_QUERY_VALUES_INTERMEDIATE_H \ No newline at end of file diff --git a/source/orm/CMakeLists.txt b/source/orm/CMakeLists.txt index 8a886a8..d785042 100644 --- a/source/orm/CMakeLists.txt +++ b/source/orm/CMakeLists.txt @@ -198,6 +198,10 @@ add_library(matador-orm STATIC query/manual_pk_generator.cpp ../../include/matador/query/table_pk_generator.hpp query/table_pk_generator.cpp + ../../include/matador/query/intermediates/query_values_intermediate.hpp + query/intermediates/query_values_intermediate.cpp + ../../include/matador/query/error_code.hpp + query/error_code.cpp ) target_include_directories(matador-orm diff --git a/source/orm/query/error_code.cpp b/source/orm/query/error_code.cpp new file mode 100644 index 0000000..dd6b37c --- /dev/null +++ b/source/orm/query/error_code.cpp @@ -0,0 +1,45 @@ +#include "matador/query/error_code.hpp" + +namespace matador::query { +const char* query_category_impl::name() const noexcept { + return "query"; +} + +std::string query_category_impl::message(int ev) const { + switch (static_cast(ev)) { + case error_code::Success: + return "Success"; + case error_code::Failure: + return "Failure"; + case error_code::InvalidQuery: + return "Invalid query"; + case error_code::InvalidSchema: + return "Invalid schema"; + case error_code::InvalidTable: + return "Invalid table"; + case error_code::InvalidColumn: + return "Invalid column"; + case error_code::InvalidConstraint: + return "Invalid constraint"; + case error_code::InvalidDataType: + return "Invalid data type"; + case error_code::InvalidValue: + return "Invalid value"; + default: + return "Unknown error"; + } +} + +const std::error_category& query_category() { + static query_category_impl instance; + return instance; +} + +std::error_code make_error_code(error_code e) { + return {static_cast(e), query_category()}; +} + +std::error_condition make_error_condition(error_code e) { + return {static_cast(e), query_category()}; +} +} diff --git a/source/orm/query/intermediates/query_execute_where_intermediate.cpp b/source/orm/query/intermediates/query_execute_where_intermediate.cpp index 3827587..8262b41 100644 --- a/source/orm/query/intermediates/query_execute_where_intermediate.cpp +++ b/source/orm/query/intermediates/query_execute_where_intermediate.cpp @@ -8,6 +8,10 @@ #include "matador/query/query_data.hpp" namespace matador::query { +fetchable_query query_execute_where_intermediate::returning(const std::vector& table_columns) { + context_->parts.push_back(std::make_unique(table_columns)); + return {context_}; +} query_execute_limit_intermediate query_execute_where_intermediate::limit(size_t limit) { context_->parts.push_back(std::make_unique(limit)); diff --git a/source/orm/query/intermediates/query_into_intermediate.cpp b/source/orm/query/intermediates/query_into_intermediate.cpp index 3a21c71..d20dd23 100644 --- a/source/orm/query/intermediates/query_into_intermediate.cpp +++ b/source/orm/query/intermediates/query_into_intermediate.cpp @@ -4,11 +4,6 @@ #include "matador/query/query_data.hpp" namespace matador::query { -fetchable_query query_values_intermediate::returning(const table_column &col) { - context_->parts.push_back(std::make_unique(std::vector{col})); - return {context_}; -} - query_values_intermediate query_into_intermediate::values(const std::initializer_list> values) { return this->values(std::vector(values)); } diff --git a/source/orm/query/intermediates/query_set_intermediate.cpp b/source/orm/query/intermediates/query_set_intermediate.cpp index b8dd516..ad156c6 100644 --- a/source/orm/query/intermediates/query_set_intermediate.cpp +++ b/source/orm/query/intermediates/query_set_intermediate.cpp @@ -4,6 +4,9 @@ #include "matador/query/query_data.hpp" namespace matador::query { +query_execute_where_intermediate query_set_intermediate::where(std::unique_ptr cond) { + return where_clause(std::move(cond)); +} query_execute_where_intermediate query_set_intermediate::where_clause(std::unique_ptr &&cond) { diff --git a/source/orm/query/intermediates/query_values_intermediate.cpp b/source/orm/query/intermediates/query_values_intermediate.cpp new file mode 100644 index 0000000..1b8515e --- /dev/null +++ b/source/orm/query/intermediates/query_values_intermediate.cpp @@ -0,0 +1,11 @@ +#include "matador/query/intermediates/query_values_intermediate.hpp" + +#include "matador/query/internal/query_parts.hpp" +#include "matador/query/query_data.hpp" + +namespace matador::query { +fetchable_query query_values_intermediate::returning(const std::vector& table_columns) { + context_->parts.push_back(std::make_unique(table_columns)); + return {context_}; +} +} \ No newline at end of file diff --git a/source/orm/query/schema.cpp b/source/orm/query/schema.cpp index b650527..55a4f4a 100644 --- a/source/orm/query/schema.cpp +++ b/source/orm/query/schema.cpp @@ -3,6 +3,7 @@ #include "matador/query/schema.hpp" #include "matador/query/query.hpp" +#include "matador/query/manual_pk_generator.hpp" #include "matador/object/repository_node.hpp" @@ -164,6 +165,6 @@ schema::iterator schema::insert_table(const std::type_index &ti, const object::r for (const auto &attr: node.info().attributes()) { columns.emplace_back(nullptr, attr.name(), attr.type(), attr.attributes()); } - return schema_nodes_.insert({ti, schema_node{table(node.name(), columns), generator_type, node}}).first; + return schema_nodes_.insert({ti, schema_node{table(node.name(), columns), std::make_unique(), node}}).first; } } // namespace matador::query diff --git a/source/orm/query/table_pk_generator.cpp b/source/orm/query/table_pk_generator.cpp index 1ad1578..f673e1b 100644 --- a/source/orm/query/table_pk_generator.cpp +++ b/source/orm/query/table_pk_generator.cpp @@ -1,5 +1,6 @@ #include "matador/query/table_pk_generator.hpp" #include "matador/query/query.hpp" +#include "matador/query/error_code.hpp" namespace matador::query { table_pk_generator::table_pk_generator(const std::string& table_name, const std::string &sequence_name) @@ -18,5 +19,6 @@ table_pk_generator::table_pk_generator(const std::string& table_name, const std: } utils::result table_pk_generator::next_id(const sql::executor &exec) { + return utils::failure(utils::error{error_code::Failure}); } } diff --git a/test/orm/orm/SessionQueryBuilderTest.cpp b/test/orm/orm/SessionQueryBuilderTest.cpp index 09a2fc8..be3bf6e 100644 --- a/test/orm/orm/SessionQueryBuilderTest.cpp +++ b/test/orm/orm/SessionQueryBuilderTest.cpp @@ -142,9 +142,9 @@ 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) { - REQUIRE(join_table->table_name() == expected_join_data[index].first); - REQUIRE(evaluator.evaluate(*clause) == expected_join_data[index].second); + for (const auto &join : data.joins) { + REQUIRE(join.join_table->table_name() == expected_join_data[index].first); + REQUIRE(evaluator.evaluate(*join.condition) == expected_join_data[index].second); ++index; } diff --git a/test/orm/query/InsertQueryBuilderTest.cpp b/test/orm/query/InsertQueryBuilderTest.cpp index 7661b65..a749e7b 100644 --- a/test/orm/query/InsertQueryBuilderTest.cpp +++ b/test/orm/query/InsertQueryBuilderTest.cpp @@ -39,6 +39,9 @@ TEST_CASE("insert query builder test", "[query][insert_query_builder]") { const auto& stmts = *build_result; REQUIRE(stmts.size() == 1); - const auto sql = stmts.front().str(db); + const auto step = stmts.front(); + + REQUIRE(std::holds_alternative(step.query)); + const auto sql = std::get(step.query).str(db); REQUIRE(sql == R"(INSERT INTO "airplanes" ("id", "brand", "model") VALUES (1, 'Boeing', 'A380'))"); } diff --git a/test/orm/query/QueryBuilderTest.cpp b/test/orm/query/QueryBuilderTest.cpp index d238137..bc6a21c 100644 --- a/test/orm/query/QueryBuilderTest.cpp +++ b/test/orm/query/QueryBuilderTest.cpp @@ -139,6 +139,16 @@ TEST_CASE_METHOD(QueryFixture, "Test update sql statement string", "[query]") { REQUIRE(result == R"(UPDATE "person" SET "id"=7, "name"='george', "age"=65 WHERE "id" > 9 ORDER BY "id" ASC LIMIT 3 OFFSET 2)"); } +TEST_CASE_METHOD(QueryFixture, "Test update returning statement", "[query][update][returning]") { + const auto result = query::update("person") + .set({{"id", 7U}, {"name", "george"}, {"age", 65U}}) + .where("name"_col == "george") + .returning("id"_col, "name"_col, "age"_col) + .str(*db); + + REQUIRE(result == R"(UPDATE "person" SET "id"=7, "name"='george', "age"=65 WHERE "name" = 'george' RETURNING "id", "name", "age")"); +} + TEST_CASE_METHOD(QueryFixture, "Test update limit sql statement", "[query][update][limit]") { const auto result = query::update("person") .set({{"id", 7U}, {"name", "george"}, {"age", 65U}}) @@ -199,6 +209,16 @@ TEST_CASE_METHOD(QueryFixture, "Test insert sql statement with placeholder", "[q REQUIRE(result == R"(INSERT INTO "person" ("id", "name", "age") VALUES (9, 'george', ?))"); } +TEST_CASE_METHOD(QueryFixture, "Test insert sql statement with returning", "[query][insert][returning]") { + const auto result = query::insert() + .into("person", {"id", "name", "age"}) + .values({9, "george", _}) + .returning("id"_col, "name"_col, "age"_col) + .str(*db); + + REQUIRE(result == R"(INSERT INTO "person" ("id", "name", "age") VALUES (9, 'george', ?) RETURNING "id", "name", "age")"); +} + TEST_CASE_METHOD(QueryFixture, "Test select sql statement string with order by", "[query]") { const auto result = query::select({"id", "name", "age"}) .from("person")