column_expression progress

This commit is contained in:
sascha 2026-03-06 15:39:53 +01:00
parent 9b4738a5ff
commit 2aff0cabbb
20 changed files with 104 additions and 53 deletions

View File

@ -228,7 +228,7 @@ utils::result<object::object_ptr<Type>, utils::error> session::update(const obje
const auto col = table_column(it->second.node().info().primary_key_attribute()->name()); const auto col = table_column(it->second.node().info().primary_key_attribute()->name());
auto res = matador::query::query::update(it->second.name()) auto res = matador::query::query::update(it->second.name())
.set(generator::column_value_pairs<Type>()) .set<Type>()
.where(col == _) .where(col == _)
.prepare(*this); .prepare(*this);
if (!res) { if (!res) {

View File

@ -15,7 +15,7 @@ public:
[[nodiscard]] const table_column& col() const; [[nodiscard]] const table_column& col() const;
protected: protected:
const table_column& column_; table_column column_;
}; };
} }

View File

@ -34,7 +34,7 @@ private:
class binary_column_criteria final : public abstract_criteria { class binary_column_criteria final : public abstract_criteria {
public: public:
binary_column_criteria() = delete; 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; void accept(criteria_visitor& visitor) const override;
@ -43,9 +43,9 @@ public:
[[nodiscard]] const table_column& right_column() const; [[nodiscard]] const table_column& right_column() const;
private: private:
const table_column& left_column_; table_column left_column_;
binary_operator operator_{}; binary_operator operator_{};
const table_column& right_column_; table_column right_column_;
}; };
} }
#endif //CRITERIA_BINARY_CRITERIA_NODE_HPP #endif //CRITERIA_BINARY_CRITERIA_NODE_HPP

View File

@ -17,8 +17,8 @@ public:
template<typename Type, typename = std::enable_if_t<std::is_convertible_v<Type, utils::database_type>>> template<typename Type, typename = std::enable_if_t<std::is_convertible_v<Type, utils::database_type>>>
column_expression(Type&& value) column_expression(Type&& value)
: column_expression(std::make_unique<value_expression>(std::forward<Type>(value))){ : column_expression(std::make_unique<value_expression>(std::forward<Type>(value))){
} }
column_expression(utils::placeholder p);
column_expression(const column_expression&) = delete; column_expression(const column_expression&) = delete;
column_expression& operator=(const column_expression&) = delete; column_expression& operator=(const column_expression&) = delete;
column_expression(column_expression&&) noexcept = default; column_expression(column_expression&&) noexcept = default;

View File

@ -8,14 +8,14 @@ namespace matador::query {
class table_column_expression : public abstract_column_expression { class table_column_expression : public abstract_column_expression {
public: public:
table_column_expression() = delete; 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; void accept(expression_visitor& visitor) const override;
[[nodiscard]] const table_column& col() const; [[nodiscard]] const table_column& col() const;
private: private:
const table_column& column_; table_column column_;
}; };
} }
#endif //MATADOR_TABLE_COLUMN_EXPRESSION_HPP #endif //MATADOR_TABLE_COLUMN_EXPRESSION_HPP

View File

@ -19,6 +19,8 @@ public:
void visit(const value_expression& node) override; void visit(const value_expression& node) override;
void visit(const placeholder_expression& node) override; void visit(const placeholder_expression& node) override;
const std::string& result() const;
private: private:
const sql::dialect &dialect_; const sql::dialect &dialect_;
sql::query_context &query_; sql::query_context &query_;

View File

@ -224,7 +224,7 @@ public:
result_.clear(); result_.clear();
access::process(*this, obj); access::process(*this, obj);
return result_; return std::move(result_);
} }
template < class V > template < class V >

View File

@ -5,30 +5,35 @@
#include "matador/query/intermediates/query_set_intermediate.hpp" #include "matador/query/intermediates/query_set_intermediate.hpp"
#include "matador/query/expression/column_expression.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" #include "matador/query/internal/column_value_pair.hpp"
namespace matador::query { namespace matador::query {
namespace internal {
class query_set_part;
}
class query_update_intermediate : public executable_query { class query_update_intermediate : public executable_query {
public: public:
explicit query_update_intermediate(const table& tab); explicit query_update_intermediate(const table& tab);
// query_set_intermediate set(std::initializer_list<internal::column_value_pair> columns);
// query_set_intermediate set(std::vector<internal::column_value_pair> &&columns);
query_update_intermediate& set(const table_column& col, column_expression&& expression); query_update_intermediate& set(const table_column& col, column_expression&& expression);
template<class Type> template<class Type>
query_set_intermediate set(const Type &obj) { query_set_intermediate set(const Type &obj) {
return set(key_value_generator::generate(obj)); return set(generator::column_value_pairs(obj));
}
template<class Type>
query_set_intermediate set() {
return set(generator::column_value_pairs<Type>());
} }
query_execute_where_intermediate where(std::unique_ptr<abstract_criteria> cond); query_execute_where_intermediate where(std::unique_ptr<abstract_criteria> cond);
private: private:
query_execute_where_intermediate where_clause(std::unique_ptr<abstract_criteria> &&cond); query_execute_where_intermediate where_clause(std::unique_ptr<abstract_criteria> &&cond);
query_set_intermediate set(std::vector<internal::column_value_pair> &&key_value_pairs);
private: private:
std::vector<internal::column_value_pair> key_value_pairs_; internal::query_set_part* query_set_part_{nullptr};
}; };
} }

View File

@ -11,10 +11,13 @@ namespace matador::query::internal {
class column_value_pair { class column_value_pair {
public: public:
column_value_pair() = default;
// column_value_pair(table_column col, utils::database_type value); // 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 std::string& name, utils::database_type value);
// column_value_pair(const char *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(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); 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);

View File

@ -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(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 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<utils::placeholder, utils::database_type> &val); static std::string determine_value(value_visitor &visitor, const std::variant<utils::placeholder, utils::database_type> &val);
[[nodiscard]] std::string build_add_constraint_string(const table_constraint& c) const; [[nodiscard]] std::string build_add_constraint_string(const table_constraint& c) const;
[[nodiscard]] std::string build_drop_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); static std::string build_constraint_name(const table_constraint& c);

View File

@ -17,6 +17,7 @@ class table;
// ReSharper disable CppNonExplicitConvertingConstructor // ReSharper disable CppNonExplicitConvertingConstructor
class table_column { class table_column {
public: public:
table_column() = default;
table_column(const char *name); // NOLINT(*-explicit-constructor) table_column(const char *name); // NOLINT(*-explicit-constructor)
table_column(const std::string& name); // NOLINT(*-explicit-constructor) table_column(const std::string& name); // NOLINT(*-explicit-constructor)
table_column(const std::string& name, const std::string& alias); table_column(const std::string& name, const std::string& alias);

View File

@ -25,7 +25,7 @@ const criteria_value& binary_criteria::value() const {
return value_; 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)) : left_column_(std::move(left_column))
, operator_(operand) , operator_(operand)
, right_column_(std::move(right_column)){} , right_column_(std::move(right_column)){}

View File

@ -4,6 +4,10 @@ namespace matador::query {
column_expression::column_expression(column_expression_ptr expr) noexcept column_expression::column_expression(column_expression_ptr expr) noexcept
: expression_(std::move(expr)) {} : expression_(std::move(expr)) {}
column_expression::column_expression(utils::placeholder /*p*/)
: expression_(std::make_unique<placeholder_expression>()){
}
bool column_expression::empty() const noexcept { bool column_expression::empty() const noexcept {
return !expression_; return !expression_;
} }

View File

@ -2,8 +2,8 @@
#include "matador/query/expression/expression_visitor.hpp" #include "matador/query/expression/expression_visitor.hpp"
namespace matador::query { namespace matador::query {
table_column_expression::table_column_expression(const table_column& col) table_column_expression::table_column_expression(table_column col)
: column_(col){ : column_(std::move(col)){
} }
void table_column_expression::accept(expression_visitor &visitor) const { void table_column_expression::accept(expression_visitor &visitor) const {

View File

@ -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)); query_.bind_vars.emplace_back(std::string("value_") + std::to_string(query_.bind_vars.size() + 1));
expression_.append(dialect_.next_placeholder(query_.bind_vars)); expression_.append(dialect_.next_placeholder(query_.bind_vars));
} }
const std::string& expression_evaluator::result() const {
return expression_;
}
} }

View File

@ -9,21 +9,20 @@ query_update_intermediate::query_update_intermediate(const table& tab) {
context_->parts.push_back(std::make_unique<internal::query_update_part>(tab)); context_->parts.push_back(std::make_unique<internal::query_update_part>(tab));
} }
// query_set_intermediate query_update_intermediate::set(const std::initializer_list<internal::column_value_pair> columns) {
// return set(std::vector<internal::column_value_pair>{columns});
// }
// query_set_intermediate query_update_intermediate::set(std::vector<internal::column_value_pair> &&columns) {
// context_->parts.push_back(std::make_unique<internal::query_set_part>(std::move(columns)));
// return {context_};
// }
query_update_intermediate& query_update_intermediate::set(const table_column &col, column_expression&& expression) { 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<internal::column_value_pair> key_value_pairs;
key_value_pairs.emplace_back(col, std::move(expression));
auto ptr = std::make_unique<internal::query_set_part>(std::move(key_value_pairs));
query_set_part_ = ptr.get();
context_->parts.push_back(std::move(ptr));
} else {
const_cast<std::vector<internal::column_value_pair>&>(query_set_part_->column_values()).emplace_back(col, std::move(expression));
}
return *this; return *this;
} }
query_execute_where_intermediate query_update_intermediate::where(std::unique_ptr<abstract_criteria> cond) { query_execute_where_intermediate query_update_intermediate::where(std::unique_ptr<abstract_criteria> cond) {
context_->parts.push_back(std::make_unique<internal::query_set_part>(std::move(key_value_pairs_)));
return where_clause(std::move(cond)); 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<internal::query_where_part>(std::move(cond))); context_->parts.push_back(std::make_unique<internal::query_where_part>(std::move(cond)));
return {context_}; return {context_};
} }
query_set_intermediate query_update_intermediate::set(std::vector<internal::column_value_pair>&& key_value_pairs) {
context_->parts.push_back(std::make_unique<internal::query_set_part>(std::move(key_value_pairs)));
return {context_};
}
} }

View File

@ -1,6 +1,7 @@
#include "matador/query/query_builder.hpp" #include "matador/query/query_builder.hpp"
#include "matador/query/attribute_string_writer.hpp" #include "matador/query/attribute_string_writer.hpp"
#include "matador/query/expression_evaluator.hpp"
#include "matador/query/query_data.hpp" #include "matador/query/query_data.hpp"
#include "matador/query/criteria_evaluator.hpp" #include "matador/query/criteria_evaluator.hpp"
#include "matador/query/query_utils.hpp" #include "matador/query/query_utils.hpp"
@ -218,6 +219,14 @@ struct value_visitor {
internal::basic_type_to_string_visitor value_to_string_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<utils::placeholder, utils::database_type> &val) { std::string query_builder::determine_value(value_visitor &visitor, const std::variant<utils::placeholder, utils::database_type> &val) {
std::visit(visitor, val); std::visit(visitor, val);
return visitor.value_to_string_visitor.result; return visitor.value_to_string_visitor.result;
@ -334,25 +343,36 @@ void query_builder::visit(internal::query_set_part &part) {
query_.sql += " " + dialect_->set() + " "; query_.sql += " " + dialect_->set() + " ";
attribute_string_writer writer(*dialect_, connection_); attribute_string_writer writer(*dialect_, connection_);
std::string result; // std::string result;
value_visitor visitor(writer, query_); if (part.column_values().size() < 2) { value_visitor visitor(writer, query_);
for (const auto &column_value: part.column_values()) { bool first = true;
result.append(dialect_->prepare_identifier_string(column_value.col().name()) + "="); for (const auto& column_value : part.column_values()) {
result.append(determine_value(visitor, column_value.value())); if (!first) {
} query_.sql.append(", ");
} 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.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) { void query_builder::visit(internal::query_drop_sequence_part& part) {

View File

@ -143,7 +143,8 @@ TEST_CASE_METHOD( QueryFixture, "Test quoted identifier", "[query][quotes][ident
REQUIRE(row.value()->at("to").as<std::string>() == "London"); REQUIRE(row.value()->at("to").as<std::string>() == "London");
res = query::update("quotes") res = query::update("quotes")
.set({{"from", "Hamburg"}, {"to", "New York"}}) .set("from", "Hamburg")
.set("to", "New York")
.where("from"_col == "Berlin") .where("from"_col == "Berlin")
.execute(db); .execute(db);
REQUIRE(res.is_ok()); REQUIRE(res.is_ok());
@ -227,7 +228,7 @@ TEST_CASE_METHOD(QueryFixture, "Test quoted literals", "[query][quotes][literals
REQUIRE(row.value()->at("name").as<std::string>() == "text"); REQUIRE(row.value()->at("name").as<std::string>() == "text");
res = query::update("escapes") res = query::update("escapes")
.set({{"name", "text'd"}}) .set("name", "text'd")
.execute(db); .execute(db);
REQUIRE(res.is_ok()); REQUIRE(res.is_ok());
REQUIRE(res->affected_rows == 1); 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<std::string>() == "text'd"); REQUIRE(row.value()->at("name").as<std::string>() == "text'd");
res = query::update("escapes") res = query::update("escapes")
.set({{"name", "text\nhello\tworld"}}) .set("name", "text\nhello\tworld")
.execute(db); .execute(db);
REQUIRE(res.is_ok()); REQUIRE(res.is_ok());
REQUIRE(res->affected_rows == 1); 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<std::string>() == "text\nhello\tworld"); REQUIRE(row.value()->at("name").as<std::string>() == "text\nhello\tworld");
res = query::update("escapes") res = query::update("escapes")
.set({{"name", "text \"text\""}}) .set("name", "text \"text\"")
.execute(db); .execute(db);
REQUIRE(res.is_ok()); REQUIRE(res.is_ok());
REQUIRE(res->affected_rows == 1); REQUIRE(res->affected_rows == 1);

View File

@ -363,9 +363,9 @@ TEST_CASE_METHOD(QueryFixture, "Execute update record statement", "[query][recor
REQUIRE(res->affected_rows == 1); REQUIRE(res->affected_rows == 1);
res = query::update("person") res = query::update("person")
.set({{"id", 7}, .set("id", 7)
{"name", "jane"}, .set("name", "jane")
{"age", 35}}) .set("age", 35)
.where("id"_col == 7) .where("id"_col == 7)
.execute(db); .execute(db);
REQUIRE(res.is_ok()); REQUIRE(res.is_ok());
@ -645,7 +645,8 @@ TEST_CASE_METHOD(QueryFixture, "Test quoted identifier record", "[query][record]
REQUIRE("London" == (*result)->at("to").str()); REQUIRE("London" == (*result)->at("to").str());
res = query::update("quotes") res = query::update("quotes")
.set({{"from", "Hamburg"}, {"to", "New York"}}) .set("from", "Hamburg")
.set("to", "New York")
.where("from"_col == "Berlin") .where("from"_col == "Berlin")
.execute(db); .execute(db);
REQUIRE(res.is_ok()); REQUIRE(res.is_ok());
@ -761,7 +762,8 @@ TEST_CASE_METHOD(QueryFixture, "Test update record", "[query][record][update]")
REQUIRE((*row)->at("age").as<unsigned short>() == 45); REQUIRE((*row)->at("age").as<unsigned short>() == 45);
res = query::update("person") res = query::update("person")
.set({{"name", "jane"}, {"age", 47}}) .set("name", "jane")
.set("age", 47)
.where("name"_col == "hans") .where("name"_col == "hans")
.execute(db); .execute(db);
REQUIRE(res.is_ok()); REQUIRE(res.is_ok());

View File

@ -110,7 +110,10 @@ TEST_CASE_METHOD(QueryFixture, "Test update statement", "[query][statement][upda
george.age = 36; george.age = 36;
george.image = {5,6,7,8}; george.image = {5,6,7,8};
stmt = query::update(PERSON) stmt = query::update(PERSON)
.set(generator::column_value_pairs<person>()) .set(PERSON.id, _)
.set(PERSON.name, _)
.set(PERSON.age, _)
.set(PERSON.image, _)
.where(PERSON.id == _) .where(PERSON.id == _)
.prepare(db); .prepare(db);
REQUIRE(stmt); REQUIRE(stmt);