From 85c56584beeca30af835910cf8b454342e16aa75 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sascha=20K=C3=BChl?= Date: Sun, 1 Mar 2026 20:23:59 +0100 Subject: [PATCH] added column_expression and table_column_expression --- demo/CMakeLists.txt | 3 +- .../query/abstract_column_expression.hpp | 18 ++++ include/matador/query/column_expression.hpp | 102 ++++++++++++++++++ .../query_execute_where_intermediate.hpp | 4 +- .../query_update_intermediate.hpp | 14 ++- .../query/internal/column_value_pair.hpp | 6 +- .../matador/query/internal/query_parts.hpp | 6 +- include/matador/query/query_column.hpp | 14 +++ include/matador/query/table_column.hpp | 5 + source/orm/CMakeLists.txt | 4 + source/orm/query/column_expression.cpp | 49 +++++++++ .../query_update_intermediate.cpp | 25 +++-- .../orm/query/internal/column_value_pair.cpp | 9 +- source/orm/query/internal/query_parts.cpp | 4 +- source/orm/query/table_pk_generator.cpp | 10 +- test/orm/query/QueryBuilderTest.cpp | 26 ++--- 16 files changed, 262 insertions(+), 37 deletions(-) create mode 100644 include/matador/query/abstract_column_expression.hpp create mode 100644 include/matador/query/column_expression.hpp create mode 100644 include/matador/query/query_column.hpp create mode 100644 source/orm/query/column_expression.cpp diff --git a/demo/CMakeLists.txt b/demo/CMakeLists.txt index 1ed962e..50b350b 100644 --- a/demo/CMakeLists.txt +++ b/demo/CMakeLists.txt @@ -1,4 +1,5 @@ -add_executable(demo main.cpp) +add_executable(demo main.cpp + ../include/matador/query/query_column.hpp) target_link_libraries(demo PRIVATE matador-core diff --git a/include/matador/query/abstract_column_expression.hpp b/include/matador/query/abstract_column_expression.hpp new file mode 100644 index 0000000..95cc581 --- /dev/null +++ b/include/matador/query/abstract_column_expression.hpp @@ -0,0 +1,18 @@ +#ifndef MATADOR_ABSTRACT_COLUMN_EXPRESSION_HPP +#define MATADOR_ABSTRACT_COLUMN_EXPRESSION_HPP + +#include + +namespace matador::query { +class expression_visitor; +class table_column; +class abstract_column_expression { +public: + virtual ~abstract_column_expression() = default; + + virtual void accept(expression_visitor& visitor) const = 0; +}; + +using column_expression_ptr = std::unique_ptr; +} +#endif //MATADOR_ABSTRACT_COLUMN_EXPRESSION_HPP \ No newline at end of file diff --git a/include/matador/query/column_expression.hpp b/include/matador/query/column_expression.hpp new file mode 100644 index 0000000..33566ef --- /dev/null +++ b/include/matador/query/column_expression.hpp @@ -0,0 +1,102 @@ +#ifndef MATADOR_COLUMN_EXPRESSION_HPP +#define MATADOR_COLUMN_EXPRESSION_HPP + +#include "matador/query/table_column.hpp" +#include "matador/query/abstract_column_expression.hpp" + +#include "matador/utils/placeholder.hpp" +#include "matador/utils/types.hpp" + +namespace matador::query { +class binary_column_expression; +class table_column_expression; +class value_expression; +class placeholder_expression; + +class expression_visitor { +public: + virtual ~expression_visitor() = default; + + virtual void visit(const binary_column_expression& node) = 0; + virtual void visit(const table_column_expression& node) = 0; + virtual void visit(const value_expression& node) = 0; + virtual void visit(const placeholder_expression& node) = 0; +}; + +enum class binary_expression_operator { + Plus, + Minus, + Multiply, + Divide, + Modulo +}; + +class binary_column_expression : public abstract_column_expression { +public: + binary_column_expression() = delete; + binary_column_expression(column_expression_ptr left_column, binary_expression_operator operand, column_expression_ptr right_column); + + void accept(expression_visitor& visitor) const override; + +private: + column_expression_ptr left_column_; + binary_expression_operator operand_; + column_expression_ptr right_column_; +}; + +class table_column_expression : public abstract_column_expression { +public: + table_column_expression() = delete; + table_column_expression(table_column col); + + void accept(expression_visitor& visitor) const override; + +private: + table_column column_; +}; + +class value_expression : public abstract_column_expression { +public: + value_expression() = delete; + value_expression(utils::database_type value); + + void accept(expression_visitor& visitor) const override; + +private: + utils::database_type value_; +}; + +class placeholder_expression : public abstract_column_expression { +public: + placeholder_expression() = default; + + void accept(expression_visitor& visitor) const override; +}; + +template +column_expression_ptr operator+(const table_column& col, Type val) { + return std::make_unique(std::make_unique(col), binary_expression_operator::Plus, std::make_unique(val)); +} + +template +column_expression_ptr operator+(Type val, const table_column& col) { + return std::make_unique(std::make_unique(val), binary_expression_operator::Plus, std::make_unique(col)); +} + +column_expression_ptr operator+(const table_column& col, utils::placeholder /*val*/); +column_expression_ptr operator+(utils::placeholder /*val*/, const table_column& col); + +template +column_expression_ptr operator-(const table_column& col, Type val) { + return std::make_unique(std::make_unique(col), binary_expression_operator::Minus, std::make_unique(val)); +} + +template +column_expression_ptr operator-(Type val, const table_column& col) { + return std::make_unique(std::make_unique(val), binary_expression_operator::Minus, std::make_unique(col)); +} + +column_expression_ptr operator-(const table_column& col, utils::placeholder /*val*/); +column_expression_ptr operator-(utils::placeholder /*val*/, const table_column& col); +} +#endif //MATADOR_COLUMN_EXPRESSION_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 139193c..6651d3a 100644 --- a/include/matador/query/intermediates/query_execute_where_intermediate.hpp +++ b/include/matador/query/intermediates/query_execute_where_intermediate.hpp @@ -16,8 +16,8 @@ public: using executable_query::executable_query; template - fetchable_query returning(const TableColumns&... table_columns) { - const std::vector tcv { table_columns... }; + fetchable_query returning(TableColumns... table_columns) { + const std::vector tcv { std::forward(table_columns)... }; return returning(tcv); } diff --git a/include/matador/query/intermediates/query_update_intermediate.hpp b/include/matador/query/intermediates/query_update_intermediate.hpp index a1c65b9..671a453 100644 --- a/include/matador/query/intermediates/query_update_intermediate.hpp +++ b/include/matador/query/intermediates/query_update_intermediate.hpp @@ -2,9 +2,9 @@ #define QUERY_UPDATE_INTERMEDIATE_HPP #include "matador/query/intermediates/query_intermediate.hpp" - #include "matador/query/intermediates/query_set_intermediate.hpp" +#include "matador/query/column_expression.hpp" #include "matador/query/key_value_generator.hpp" #include "matador/query/internal/column_value_pair.hpp" @@ -15,12 +15,20 @@ class query_update_intermediate : public query_intermediate { public: explicit query_update_intermediate(const table& tab); - query_set_intermediate set(std::initializer_list columns); - query_set_intermediate set(std::vector &&columns); + // query_set_intermediate set(std::initializer_list columns); + // query_set_intermediate set(std::vector &&columns); + query_update_intermediate& set(const table_column& col, column_expression_ptr expression); template query_set_intermediate set(const Type &obj) { return set(key_value_generator::generate(obj)); } + query_execute_where_intermediate where(std::unique_ptr cond); + +private: + query_execute_where_intermediate where_clause(std::unique_ptr &&cond); + +private: + std::vector key_value_pairs_; }; } diff --git a/include/matador/query/internal/column_value_pair.hpp b/include/matador/query/internal/column_value_pair.hpp index af48421..f3a51f4 100644 --- a/include/matador/query/internal/column_value_pair.hpp +++ b/include/matador/query/internal/column_value_pair.hpp @@ -2,6 +2,7 @@ #define QUERY_KEY_VALUE_PAIR_HPP #include "matador/query/table_column.hpp" +#include "matador/query/column_expression.hpp" #include "matador/utils/placeholder.hpp" #include "matador/utils/types.hpp" @@ -11,9 +12,10 @@ namespace matador::query::internal { class column_value_pair { public: column_value_pair(table_column col, utils::database_type value); - column_value_pair(std::string name, utils::database_type value); + column_value_pair(const std::string& name, utils::database_type value); column_value_pair(const char *name, utils::database_type value); column_value_pair(const char *name, utils::placeholder p); + column_value_pair(table_column col, column_expression_ptr expression); friend bool operator==(const column_value_pair &lhs, const column_value_pair &rhs); friend bool operator!=(const column_value_pair &lhs, const column_value_pair &rhs); @@ -24,6 +26,8 @@ public: private: table_column column_; std::variant value_; + column_expression_ptr expression_; + }; } diff --git a/include/matador/query/internal/query_parts.hpp b/include/matador/query/internal/query_parts.hpp index 0d007ae..b105c87 100644 --- a/include/matador/query/internal/query_parts.hpp +++ b/include/matador/query/internal/query_parts.hpp @@ -374,15 +374,15 @@ private: class query_set_part final : public query_part { public: - explicit query_set_part(const std::vector& key_value_pairs); + explicit query_set_part(std::vector&& key_value_pairs); - [[nodiscard]] const std::vector& column_values() const; + [[nodiscard]] const std::vector& column_values() const; private: void accept(query_part_visitor &visitor) override; private: - std::vector key_value_pairs_; + std::vector key_value_pairs_; }; class query_delete_part final : public query_part diff --git a/include/matador/query/query_column.hpp b/include/matador/query/query_column.hpp new file mode 100644 index 0000000..e03b49c --- /dev/null +++ b/include/matador/query/query_column.hpp @@ -0,0 +1,14 @@ +#ifndef MATADOR_QUERY_COLUMN_HPP +#define MATADOR_QUERY_COLUMN_HPP +#include + +namespace matador::query { +class query_column { +public: + query_column() = default; + +private: + std::string name_; +} +} +#endif //MATADOR_QUERY_COLUMN_HPP \ No newline at end of file diff --git a/include/matador/query/table_column.hpp b/include/matador/query/table_column.hpp index 4ea6c29..3291f9f 100644 --- a/include/matador/query/table_column.hpp +++ b/include/matador/query/table_column.hpp @@ -1,6 +1,8 @@ #ifndef QUERY_COLUMN_HPP #define QUERY_COLUMN_HPP +#include "matador/query/abstract_column_expression.hpp" + #include "matador/sql/sql_functions.hpp" #include "matador/utils/basic_types.hpp" @@ -29,6 +31,9 @@ public: utils::basic_type type, const utils::field_attributes& attributes, sql::sql_function_t func = sql::sql_function_t::None); + + + table_column(column_expression_ptr expression) noexcept; table_column& operator=(const table_column& other); table_column(const table_column& other) = default; table_column(table_column&& other) noexcept = default; diff --git a/source/orm/CMakeLists.txt b/source/orm/CMakeLists.txt index d785042..54a7d27 100644 --- a/source/orm/CMakeLists.txt +++ b/source/orm/CMakeLists.txt @@ -202,6 +202,10 @@ add_library(matador-orm STATIC query/intermediates/query_values_intermediate.cpp ../../include/matador/query/error_code.hpp query/error_code.cpp + ../../include/matador/query/column_expression.hpp + query/column_expression.cpp + ../../include/matador/query/abstract_column_expression.hpp + ../../include/matador/query/query_column.hpp ) target_include_directories(matador-orm diff --git a/source/orm/query/column_expression.cpp b/source/orm/query/column_expression.cpp new file mode 100644 index 0000000..c07789b --- /dev/null +++ b/source/orm/query/column_expression.cpp @@ -0,0 +1,49 @@ +#include "matador/query/column_expression.hpp" + +namespace matador::query { +binary_column_expression::binary_column_expression(column_expression_ptr left_column, binary_expression_operator operand, column_expression_ptr right_column) +: left_column_(std::move(left_column)) +, operand_(operand) +, right_column_(std::move(right_column)) { +} + +void binary_column_expression::accept(expression_visitor &visitor) const { + visitor.visit(*this); +} + +table_column_expression::table_column_expression(table_column col) +: column_(std::move(col)){ +} + +void table_column_expression::accept(expression_visitor &visitor) const { + visitor.visit(*this); +} + +value_expression::value_expression(utils::database_type value) +: value_(std::move(value)) { +} + +void value_expression::accept(expression_visitor &visitor) const { + visitor.visit(*this); +} + +void placeholder_expression::accept(expression_visitor &visitor) const { + visitor.visit(*this); +} + +column_expression_ptr operator+(const table_column &col, utils::placeholder /*placeholder*/) { + return std::make_unique(std::make_unique(col), binary_expression_operator::Plus, std::make_unique()); +} + +column_expression_ptr operator+(utils::placeholder /*placeholder*/, const table_column &col) { + return std::make_unique(std::make_unique(), binary_expression_operator::Plus, std::make_unique(col)); +} + +column_expression_ptr operator-(const table_column &col, utils::placeholder /*placeholder*/) { + return std::make_unique(std::make_unique(col), binary_expression_operator::Minus, std::make_unique()); +} + +column_expression_ptr operator-(utils::placeholder /*placeholder*/, const table_column &col) { + return std::make_unique(std::make_unique(), binary_expression_operator::Minus, std::make_unique(col)); +} +} diff --git a/source/orm/query/intermediates/query_update_intermediate.cpp b/source/orm/query/intermediates/query_update_intermediate.cpp index dcfceb4..f9ebeb9 100644 --- a/source/orm/query/intermediates/query_update_intermediate.cpp +++ b/source/orm/query/intermediates/query_update_intermediate.cpp @@ -9,13 +9,26 @@ query_update_intermediate::query_update_intermediate(const table& tab) { context_->parts.push_back(std::make_unique(tab)); } -query_set_intermediate query_update_intermediate::set(const std::initializer_list columns) { - return set(std::vector{columns}); +// query_set_intermediate query_update_intermediate::set(const std::initializer_list columns) { + // return set(std::vector{columns}); +// } + +// query_set_intermediate query_update_intermediate::set(std::vector &&columns) { + // context_->parts.push_back(std::make_unique(std::move(columns))); + // return {context_}; +// } +query_update_intermediate& query_update_intermediate::set(const table_column &col, column_expression_ptr expression) { + key_value_pairs_.emplace_back(col, std::move(expression)); + return *this; } -query_set_intermediate query_update_intermediate::set(std::vector &&columns) { - context_->parts.push_back(std::make_unique(std::move(columns))); +query_execute_where_intermediate query_update_intermediate::where(std::unique_ptr cond) { + context_->parts.push_back(std::make_unique(std::move(key_value_pairs_))); + return where_clause(std::move(cond)); +} + +query_execute_where_intermediate query_update_intermediate::where_clause(std::unique_ptr &&cond) { + context_->parts.push_back(std::make_unique(std::move(cond))); return {context_}; } - -} \ No newline at end of file +} diff --git a/source/orm/query/internal/column_value_pair.cpp b/source/orm/query/internal/column_value_pair.cpp index 5e00d6f..3c78105 100644 --- a/source/orm/query/internal/column_value_pair.cpp +++ b/source/orm/query/internal/column_value_pair.cpp @@ -4,8 +4,8 @@ namespace matador::query::internal { -column_value_pair::column_value_pair(std::string name, utils::database_type value) -: column_(std::move(name)) +column_value_pair::column_value_pair(const std::string& name, utils::database_type value) +: column_(name) , value_(std::move(value)) { } @@ -23,6 +23,11 @@ column_value_pair::column_value_pair( const char* name, utils::placeholder p ) : column_(name) , value_(p) {} +column_value_pair::column_value_pair(table_column col, column_expression_ptr expression) +: column_(std::move(col)) +, expression_(std::move(expression)){ +} + const table_column &column_value_pair::col() const { return column_; } diff --git a/source/orm/query/internal/query_parts.cpp b/source/orm/query/internal/query_parts.cpp index fcd42f2..cc11c8f 100644 --- a/source/orm/query/internal/query_parts.cpp +++ b/source/orm/query/internal/query_parts.cpp @@ -350,9 +350,9 @@ void query_update_part::accept(query_part_visitor &visitor) { visitor.visit(*this); } -query_set_part::query_set_part(const std::vector &key_value_pairs) +query_set_part::query_set_part(std::vector &&key_value_pairs) : query_part(sql::dialect_token::Set) -, key_value_pairs_(key_value_pairs) { +, key_value_pairs_(std::move(key_value_pairs)) { } const std::vector &query_set_part::column_values() const { diff --git a/source/orm/query/table_pk_generator.cpp b/source/orm/query/table_pk_generator.cpp index f673e1b..a856386 100644 --- a/source/orm/query/table_pk_generator.cpp +++ b/source/orm/query/table_pk_generator.cpp @@ -1,15 +1,17 @@ #include "matador/query/table_pk_generator.hpp" #include "matador/query/query.hpp" +#include "matador/query/criteria.hpp" #include "matador/query/error_code.hpp" +#include "matador/query/internal/column_value_pair.hpp" namespace matador::query { table_pk_generator::table_pk_generator(const std::string& table_name, const std::string &sequence_name) : abstract_pk_generator(utils::generator_type::Table) { - // query::update(table_name) - // .set("next_id", "next_id + 1") - // .where("name", "=", table_name) - // .returning("next_id - 1 AS id"); + query::update(table_name) + .set("next_id"_col, "next_id"_col + 1) + .where("name"_col == sequence_name) + .returning(("next_id"_col - 1)); /* *UPDATE id_table SET next_id = next_id + 1 diff --git a/test/orm/query/QueryBuilderTest.cpp b/test/orm/query/QueryBuilderTest.cpp index bc6a21c..bbab180 100644 --- a/test/orm/query/QueryBuilderTest.cpp +++ b/test/orm/query/QueryBuilderTest.cpp @@ -115,21 +115,17 @@ TEST_CASE_METHOD(QueryFixture, "Test insert sql statement string", "[query]") { TEST_CASE_METHOD(QueryFixture, "Test update sql statement string", "[query]") { auto result = query::update("person") - .set({ - {"id", 7U}, - {"name", "george"}, - {"age", 65U} - }) + .set("id", 7U) + .set("name", "george") + .set("age", 65U) .str(*db); REQUIRE(result == R"(UPDATE "person" SET "id"=7, "name"='george', "age"=65)"); result = query::update("person") - .set({ - {"id", 7U}, - {"name", "george"}, - {"age", 65U} - }) + .set("id", 7U) + .set("name", "george") + .set("age", 65U) .where("id"_col > 9) .order_by("id").asc() .limit(3) @@ -141,8 +137,10 @@ TEST_CASE_METHOD(QueryFixture, "Test update sql statement string", "[query]") { 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") + .set("id", 7U) + .set("name", "george") + .set("age", 65U) + .where("name"_col == "george") .returning("id"_col, "name"_col, "age"_col) .str(*db); @@ -151,7 +149,9 @@ TEST_CASE_METHOD(QueryFixture, "Test update returning statement", "[query][updat 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}}) + .set("id", 7U) + .set("name", "george") + .set("age", 65U) .where("name"_col == "george") .order_by("id"_col).asc() .limit(2)