diff --git a/include/matador/orm/session.hpp b/include/matador/orm/session.hpp index 9a8d782..4eaa295 100644 --- a/include/matador/orm/session.hpp +++ b/include/matador/orm/session.hpp @@ -228,7 +228,7 @@ utils::result, utils::error> session::update(const obje const auto col = table_column(it->second.node().info().primary_key_attribute()->name()); auto res = matador::query::query::update(it->second.name()) - .set(generator::column_value_pairs()) + .set() .where(col == _) .prepare(*this); if (!res) { diff --git a/include/matador/query/criteria/abstract_column_criteria.hpp b/include/matador/query/criteria/abstract_column_criteria.hpp index bf14770..1947f5c 100644 --- a/include/matador/query/criteria/abstract_column_criteria.hpp +++ b/include/matador/query/criteria/abstract_column_criteria.hpp @@ -15,7 +15,7 @@ public: [[nodiscard]] const table_column& col() const; protected: - const table_column& column_; + table_column column_; }; } diff --git a/include/matador/query/criteria/binary_criteria.hpp b/include/matador/query/criteria/binary_criteria.hpp index 61c4482..4fe28ea 100644 --- a/include/matador/query/criteria/binary_criteria.hpp +++ b/include/matador/query/criteria/binary_criteria.hpp @@ -34,7 +34,7 @@ private: class binary_column_criteria final : public abstract_criteria { public: binary_column_criteria() = delete; - binary_column_criteria(const table_column& left_column, binary_operator operand, const table_column& right_column); + binary_column_criteria(table_column left_column, binary_operator operand, table_column right_column); void accept(criteria_visitor& visitor) const override; @@ -43,9 +43,9 @@ public: [[nodiscard]] const table_column& right_column() const; private: - const table_column& left_column_; + table_column left_column_; binary_operator operator_{}; - const table_column& right_column_; + table_column right_column_; }; } #endif //CRITERIA_BINARY_CRITERIA_NODE_HPP \ No newline at end of file diff --git a/include/matador/query/expression/column_expression.hpp b/include/matador/query/expression/column_expression.hpp index 1f6bcb5..eecf901 100644 --- a/include/matador/query/expression/column_expression.hpp +++ b/include/matador/query/expression/column_expression.hpp @@ -17,8 +17,8 @@ public: template>> column_expression(Type&& value) : column_expression(std::make_unique(std::forward(value))){ - } + column_expression(utils::placeholder p); column_expression(const column_expression&) = delete; column_expression& operator=(const column_expression&) = delete; column_expression(column_expression&&) noexcept = default; diff --git a/include/matador/query/expression/table_column_expression.hpp b/include/matador/query/expression/table_column_expression.hpp index 26bdf60..2155965 100644 --- a/include/matador/query/expression/table_column_expression.hpp +++ b/include/matador/query/expression/table_column_expression.hpp @@ -8,14 +8,14 @@ namespace matador::query { class table_column_expression : public abstract_column_expression { public: table_column_expression() = delete; - explicit table_column_expression(const table_column& col); + explicit table_column_expression(table_column col); void accept(expression_visitor& visitor) const override; [[nodiscard]] const table_column& col() const; private: - const table_column& column_; + table_column column_; }; } #endif //MATADOR_TABLE_COLUMN_EXPRESSION_HPP \ No newline at end of file diff --git a/include/matador/query/expression_evaluator.hpp b/include/matador/query/expression_evaluator.hpp index 60b32f6..61b318f 100644 --- a/include/matador/query/expression_evaluator.hpp +++ b/include/matador/query/expression_evaluator.hpp @@ -19,6 +19,8 @@ public: void visit(const value_expression& node) override; void visit(const placeholder_expression& node) override; + const std::string& result() const; + private: const sql::dialect &dialect_; sql::query_context &query_; diff --git a/include/matador/query/generator.hpp b/include/matador/query/generator.hpp index 9e437b1..ec26449 100644 --- a/include/matador/query/generator.hpp +++ b/include/matador/query/generator.hpp @@ -224,7 +224,7 @@ public: result_.clear(); access::process(*this, obj); - return result_; + return std::move(result_); } template < class V > diff --git a/include/matador/query/intermediates/query_update_intermediate.hpp b/include/matador/query/intermediates/query_update_intermediate.hpp index 417bb8f..ce59abf 100644 --- a/include/matador/query/intermediates/query_update_intermediate.hpp +++ b/include/matador/query/intermediates/query_update_intermediate.hpp @@ -5,30 +5,35 @@ #include "matador/query/intermediates/query_set_intermediate.hpp" #include "matador/query/expression/column_expression.hpp" -#include "matador/query/key_value_generator.hpp" +#include "matador/query/generator.hpp" #include "matador/query/internal/column_value_pair.hpp" namespace matador::query { - +namespace internal { +class query_set_part; +} class query_update_intermediate : public executable_query { public: explicit query_update_intermediate(const table& tab); - // 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&& expression); template query_set_intermediate set(const Type &obj) { - return set(key_value_generator::generate(obj)); + return set(generator::column_value_pairs(obj)); + } + template + query_set_intermediate set() { + return set(generator::column_value_pairs()); } query_execute_where_intermediate where(std::unique_ptr cond); private: query_execute_where_intermediate where_clause(std::unique_ptr &&cond); + query_set_intermediate set(std::vector &&key_value_pairs); private: - std::vector key_value_pairs_; + internal::query_set_part* query_set_part_{nullptr}; }; } diff --git a/include/matador/query/internal/column_value_pair.hpp b/include/matador/query/internal/column_value_pair.hpp index 858f7ad..41219e3 100644 --- a/include/matador/query/internal/column_value_pair.hpp +++ b/include/matador/query/internal/column_value_pair.hpp @@ -11,10 +11,13 @@ namespace matador::query::internal { class column_value_pair { public: + column_value_pair() = default; // column_value_pair(table_column col, 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(column_value_pair&& x) = default; + column_value_pair& operator=(column_value_pair&& x) = default; column_value_pair(table_column col, column_expression_ptr expression); friend bool operator==(const column_value_pair &lhs, const column_value_pair &rhs); diff --git a/include/matador/query/query_builder.hpp b/include/matador/query/query_builder.hpp index 20b2058..6e63d0a 100644 --- a/include/matador/query/query_builder.hpp +++ b/include/matador/query/query_builder.hpp @@ -83,8 +83,10 @@ protected: static std::string build_table_name(sql::dialect_token token, const sql::dialect &d, const table& t); static std::string build_table_name(const sql::dialect &d, const table& t); + static std::string determine_value(const sql::dialect &d, sql::query_context& ctx, const abstract_column_expression &exp); static std::string determine_value(value_visitor &visitor, const std::variant &val); + [[nodiscard]] std::string build_add_constraint_string(const table_constraint& c) const; [[nodiscard]] std::string build_drop_constraint_string(const table_constraint& c) const; static std::string build_constraint_name(const table_constraint& c); diff --git a/include/matador/query/table_column.hpp b/include/matador/query/table_column.hpp index b082616..fe9bafd 100644 --- a/include/matador/query/table_column.hpp +++ b/include/matador/query/table_column.hpp @@ -17,6 +17,7 @@ class table; // ReSharper disable CppNonExplicitConvertingConstructor class table_column { public: + table_column() = default; table_column(const char *name); // NOLINT(*-explicit-constructor) table_column(const std::string& name); // NOLINT(*-explicit-constructor) table_column(const std::string& name, const std::string& alias); diff --git a/source/orm/query/criteria/binary_criteria.cpp b/source/orm/query/criteria/binary_criteria.cpp index d8bcc18..4014d7e 100644 --- a/source/orm/query/criteria/binary_criteria.cpp +++ b/source/orm/query/criteria/binary_criteria.cpp @@ -25,7 +25,7 @@ const criteria_value& binary_criteria::value() const { return value_; } -binary_column_criteria::binary_column_criteria(const table_column& left_column, const binary_operator operand, const table_column& right_column) +binary_column_criteria::binary_column_criteria(table_column left_column, const binary_operator operand, table_column right_column) : left_column_(std::move(left_column)) , operator_(operand) , right_column_(std::move(right_column)){} diff --git a/source/orm/query/expression/column_expression.cpp b/source/orm/query/expression/column_expression.cpp index 36caa77..a0fbfed 100644 --- a/source/orm/query/expression/column_expression.cpp +++ b/source/orm/query/expression/column_expression.cpp @@ -4,6 +4,10 @@ namespace matador::query { column_expression::column_expression(column_expression_ptr expr) noexcept : expression_(std::move(expr)) {} +column_expression::column_expression(utils::placeholder /*p*/) +: expression_(std::make_unique()){ +} + bool column_expression::empty() const noexcept { return !expression_; } diff --git a/source/orm/query/expression/table_column_expression.cpp b/source/orm/query/expression/table_column_expression.cpp index efb8fcc..6f8a29c 100644 --- a/source/orm/query/expression/table_column_expression.cpp +++ b/source/orm/query/expression/table_column_expression.cpp @@ -2,8 +2,8 @@ #include "matador/query/expression/expression_visitor.hpp" namespace matador::query { -table_column_expression::table_column_expression(const table_column& col) -: column_(col){ +table_column_expression::table_column_expression(table_column col) +: column_(std::move(col)){ } void table_column_expression::accept(expression_visitor &visitor) const { diff --git a/source/orm/query/expression_evaluator.cpp b/source/orm/query/expression_evaluator.cpp index 646f0ea..be33c00 100644 --- a/source/orm/query/expression_evaluator.cpp +++ b/source/orm/query/expression_evaluator.cpp @@ -54,4 +54,8 @@ void expression_evaluator::visit(const placeholder_expression& /*node*/) { query_.bind_vars.emplace_back(std::string("value_") + std::to_string(query_.bind_vars.size() + 1)); expression_.append(dialect_.next_placeholder(query_.bind_vars)); } + +const std::string& expression_evaluator::result() const { + return expression_; +} } diff --git a/source/orm/query/intermediates/query_update_intermediate.cpp b/source/orm/query/intermediates/query_update_intermediate.cpp index 955f472..1fd4f65 100644 --- a/source/orm/query/intermediates/query_update_intermediate.cpp +++ b/source/orm/query/intermediates/query_update_intermediate.cpp @@ -9,21 +9,20 @@ 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(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&& expression) { - key_value_pairs_.emplace_back(col, std::move(expression)); + if (query_set_part_ == nullptr) { + std::vector key_value_pairs; + key_value_pairs.emplace_back(col, std::move(expression)); + auto ptr = std::make_unique(std::move(key_value_pairs)); + query_set_part_ = ptr.get(); + context_->parts.push_back(std::move(ptr)); + } else { + const_cast&>(query_set_part_->column_values()).emplace_back(col, std::move(expression)); + } return *this; } 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)); } @@ -31,4 +30,9 @@ query_execute_where_intermediate query_update_intermediate::where_clause(std::un context_->parts.push_back(std::make_unique(std::move(cond))); return {context_}; } + +query_set_intermediate query_update_intermediate::set(std::vector&& key_value_pairs) { + context_->parts.push_back(std::make_unique(std::move(key_value_pairs))); + return {context_}; +} } diff --git a/source/orm/query/query_builder.cpp b/source/orm/query/query_builder.cpp index df2a036..d7b83d6 100644 --- a/source/orm/query/query_builder.cpp +++ b/source/orm/query/query_builder.cpp @@ -1,6 +1,7 @@ #include "matador/query/query_builder.hpp" #include "matador/query/attribute_string_writer.hpp" +#include "matador/query/expression_evaluator.hpp" #include "matador/query/query_data.hpp" #include "matador/query/criteria_evaluator.hpp" #include "matador/query/query_utils.hpp" @@ -218,6 +219,14 @@ struct value_visitor { internal::basic_type_to_string_visitor value_to_string_visitor; }; +std::string query_builder::determine_value(const sql::dialect &d, sql::query_context& ctx, const abstract_column_expression &exp) { + attribute_string_writer writer(d, {}); + expression_evaluator v(d, ctx); + exp.accept(v); + + return v.result(); +} + std::string query_builder::determine_value(value_visitor &visitor, const std::variant &val) { std::visit(visitor, val); return visitor.value_to_string_visitor.result; @@ -334,25 +343,36 @@ void query_builder::visit(internal::query_set_part &part) { query_.sql += " " + dialect_->set() + " "; attribute_string_writer writer(*dialect_, connection_); - std::string result; + // std::string result; - value_visitor visitor(writer, query_); if (part.column_values().size() < 2) { - for (const auto &column_value: part.column_values()) { - result.append(dialect_->prepare_identifier_string(column_value.col().name()) + "="); - result.append(determine_value(visitor, column_value.value())); - } - } else { - auto it = part.column_values().begin(); - result.append(dialect_->prepare_identifier_string(it->col().name()) + "="); - result.append(determine_value(visitor, (it++)->value())); - for (; it != part.column_values().end(); ++it) { - result.append(", "); - result.append(dialect_->prepare_identifier_string(it->col().name()) + "="); - result.append(determine_value(visitor, it->value())); + value_visitor visitor(writer, query_); + bool first = true; + for (const auto& column_value : part.column_values()) { + if (!first) { + query_.sql.append(", "); } + query_.sql.append(dialect_->prepare_identifier_string(column_value.col().name()) + "="); + query_.sql.append(determine_value(*dialect_,query_, column_value.expression())); + first = false; } - query_.sql += result; + // if (part.column_values().size() < 2) { + // for (const auto &column_value: part.column_values()) { + // result.append(dialect_->prepare_identifier_string(column_value.col().name()) + "="); + // result.append(determine_value(visitor, column_value.value())); + // } + // } else { + // auto it = part.column_values().begin(); + // result.append(dialect_->prepare_identifier_string(it->col().name()) + "="); + // result.append(determine_value(visitor, (it++)->value())); + // for (; it != part.column_values().end(); ++it) { + // result.append(", "); + // result.append(dialect_->prepare_identifier_string(it->col().name()) + "="); + // result.append(determine_value(visitor, it->value())); + // } + // } + // + // query_.sql += result; } void query_builder::visit(internal::query_drop_sequence_part& part) { diff --git a/test/backends/QueryBasicTest.cpp b/test/backends/QueryBasicTest.cpp index e9444db..d96c854 100644 --- a/test/backends/QueryBasicTest.cpp +++ b/test/backends/QueryBasicTest.cpp @@ -143,7 +143,8 @@ TEST_CASE_METHOD( QueryFixture, "Test quoted identifier", "[query][quotes][ident REQUIRE(row.value()->at("to").as() == "London"); res = query::update("quotes") - .set({{"from", "Hamburg"}, {"to", "New York"}}) + .set("from", "Hamburg") + .set("to", "New York") .where("from"_col == "Berlin") .execute(db); REQUIRE(res.is_ok()); @@ -227,7 +228,7 @@ TEST_CASE_METHOD(QueryFixture, "Test quoted literals", "[query][quotes][literals REQUIRE(row.value()->at("name").as() == "text"); res = query::update("escapes") - .set({{"name", "text'd"}}) + .set("name", "text'd") .execute(db); REQUIRE(res.is_ok()); REQUIRE(res->affected_rows == 1); @@ -241,7 +242,7 @@ TEST_CASE_METHOD(QueryFixture, "Test quoted literals", "[query][quotes][literals REQUIRE(row.value()->at("name").as() == "text'd"); res = query::update("escapes") - .set({{"name", "text\nhello\tworld"}}) + .set("name", "text\nhello\tworld") .execute(db); REQUIRE(res.is_ok()); REQUIRE(res->affected_rows == 1); @@ -255,7 +256,7 @@ TEST_CASE_METHOD(QueryFixture, "Test quoted literals", "[query][quotes][literals REQUIRE(row.value()->at("name").as() == "text\nhello\tworld"); res = query::update("escapes") - .set({{"name", "text \"text\""}}) + .set("name", "text \"text\"") .execute(db); REQUIRE(res.is_ok()); REQUIRE(res->affected_rows == 1); diff --git a/test/backends/QueryRecordTest.cpp b/test/backends/QueryRecordTest.cpp index 57d1f97..cd79969 100644 --- a/test/backends/QueryRecordTest.cpp +++ b/test/backends/QueryRecordTest.cpp @@ -363,9 +363,9 @@ TEST_CASE_METHOD(QueryFixture, "Execute update record statement", "[query][recor REQUIRE(res->affected_rows == 1); res = query::update("person") - .set({{"id", 7}, - {"name", "jane"}, - {"age", 35}}) + .set("id", 7) + .set("name", "jane") + .set("age", 35) .where("id"_col == 7) .execute(db); REQUIRE(res.is_ok()); @@ -645,7 +645,8 @@ TEST_CASE_METHOD(QueryFixture, "Test quoted identifier record", "[query][record] REQUIRE("London" == (*result)->at("to").str()); res = query::update("quotes") - .set({{"from", "Hamburg"}, {"to", "New York"}}) + .set("from", "Hamburg") + .set("to", "New York") .where("from"_col == "Berlin") .execute(db); REQUIRE(res.is_ok()); @@ -761,7 +762,8 @@ TEST_CASE_METHOD(QueryFixture, "Test update record", "[query][record][update]") REQUIRE((*row)->at("age").as() == 45); res = query::update("person") - .set({{"name", "jane"}, {"age", 47}}) + .set("name", "jane") + .set("age", 47) .where("name"_col == "hans") .execute(db); REQUIRE(res.is_ok()); diff --git a/test/backends/QueryStatementTests.cpp b/test/backends/QueryStatementTests.cpp index 81951a2..b5b6069 100644 --- a/test/backends/QueryStatementTests.cpp +++ b/test/backends/QueryStatementTests.cpp @@ -110,7 +110,10 @@ TEST_CASE_METHOD(QueryFixture, "Test update statement", "[query][statement][upda george.age = 36; george.image = {5,6,7,8}; stmt = query::update(PERSON) - .set(generator::column_value_pairs()) + .set(PERSON.id, _) + .set(PERSON.name, _) + .set(PERSON.age, _) + .set(PERSON.image, _) .where(PERSON.id == _) .prepare(db); REQUIRE(stmt);