diff --git a/include/matador/query/insert_query_builder.hpp b/include/matador/query/insert_query_builder.hpp index bac26cb..0587217 100644 --- a/include/matador/query/insert_query_builder.hpp +++ b/include/matador/query/insert_query_builder.hpp @@ -11,6 +11,7 @@ #include "matador/query/query_contexts.hpp" #include "matador/query/query_builder_exception.hpp" +#include "matador/sql/execute_result.hpp" #include "matador/sql/statement.hpp" #include "matador/utils/primary_key_accessor.hpp" @@ -86,9 +87,9 @@ protected: }; template -class insert_step_sequence : public insert_step2 { +class insert_step_pk_generated : public insert_step2 { public: - insert_step_sequence(sql::query_context ctx, const object::object_ptr& ptr, abstract_pk_generator& pk_generator) + insert_step_pk_generated(sql::query_context ctx, const object::object_ptr& ptr, abstract_pk_generator& pk_generator) : insert_step2(std::move(ctx)) , ptr_(ptr) , pk_generator_(pk_generator){} @@ -120,40 +121,88 @@ private: }; template -class insert_step_identity : public insert_step2 { +class insert_step_pk_identity : public insert_step2 { public: - insert_step_identity(sql::query_context ctx, const object::object_ptr& ptr) + insert_step_pk_identity(sql::query_context ctx, const object::object_ptr& ptr, const std::string &pk_column_name) : insert_step2(std::move(ctx)) - , ptr_(ptr) {} + , ptr_(ptr) + , pk_column_name_(pk_column_name){} - utils::result prepare(sql::executor& conn) const override { + utils::result prepare(sql::executor&) const override { return utils::ok(); } utils::result insert(sql::statement& stmt) const override { stmt.bind(*ptr_); - auto record = stmt.fetch_one(); - if (!record.is_ok()) { - return utils::failure(record.err()); + auto result = stmt.fetch_one(); + if (!result.is_ok()) { + return utils::failure(result.err()); } - if (!record.value().has_value()) { + if (!result.value().has_value()) { return utils::failure(utils::error(error_code::FailedToFindObject, "Failed to insert object and retrieve identity.")); } - const auto pk_name = info.primary_key_attribute()->name(); - const table_column pk_col(&it->second.table(), pk_name); - step.apply_returning = [ptr, &step, pk_name = pk_name](const sql::record &rec) { - const auto& f = rec.at(pk_name); - utils::identifier id; - id.assign(f.value()); - step.pk_accessor.set(*ptr, id); - }; + auto rec = result->value(); + const auto& f = rec.at(pk_column_name_); + utils::identifier id; + if (auto res = id.assign(f.value()); !res.is_ok()) { + return utils::failure(res.err()); + } + pk_accessor_.set(*ptr_, id); ptr_.change_state(object::object_state::Persistent); return utils::ok(); } +private: + object::object_ptr ptr_; + std::string pk_column_name_; +}; + +template +class insert_step_pk_manual : public insert_step2 { +public: + insert_step_pk_manual(sql::query_context ctx, const object::object_ptr& ptr) + : insert_step2(std::move(ctx)) + , ptr_(ptr) {} + + utils::result prepare(sql::executor &) const override { + return utils::ok(); + } + utils::result insert(sql::statement &stmt) const override { + stmt.bind(*ptr_); + if (const auto exec_result = stmt.execute(); !exec_result.is_ok()) { + return utils::failure(exec_result.err()); + } + + ptr_.change_state(object::object_state::Persistent); + return utils::ok(); + } + +private: + object::object_ptr ptr_; +}; + +template +class insert_step_relation : public insert_step2 { +public: + insert_step_relation(sql::query_context ctx, const object::object_ptr& ptr) + : insert_step2(std::move(ctx)) + , ptr_(ptr) {} + + utils::result prepare(sql::executor &) const override { + return utils::ok(); + } + utils::result insert(sql::statement &stmt) const override { + stmt.bind(*ptr_); + if (const auto exec_result = stmt.execute(); !exec_result.is_ok()) { + return utils::failure(exec_result.err()); + } + + return utils::ok(); + } + private: object::object_ptr ptr_; }; @@ -380,14 +429,23 @@ private: // 2) Build INSERT for this object const auto &info = it->second.node().info(); insert_step step{}; - if (info.has_primary_key()) { - step.pk_generator = it->second.pk_generator().type(); + if (!info.has_primary_key() || it->second.pk_generator().type() == utils::generator_type::None) { + return utils::failure(utils::error{error_code::MissingPrimaryKey, "Type " + info.name() + " has no primary key"}); } - const auto cit = contexts_by_type_.find(it->second.node().info().type_index()); if (cit == contexts_by_type_.end()) { return utils::failure(utils::error{error_code::UnknownType, "Unknown type"}); } + + if (it->second.pk_generator().type() == utils::generator_type::Manual) { + steps2_.push_back(std::make_unique>(cit->second.insert, ptr)); + } else if (it->second.pk_generator().type() == utils::generator_type::Identity) { + steps2_.push_back(std::make_unique>(cit->second.insert, ptr, info.primary_key_attribute()->name())); + } else { + steps2_.push_back(std::make_unique>(cit->second.insert, ptr)); + } + step.pk_generator = it->second.pk_generator().type(); + step.ctx = cit->second.insert; step.bind_object = [ptr](sql::statement &stmt) { stmt.bind(*ptr); @@ -432,6 +490,7 @@ private: object::object_ptr ptr_; + std::vector> steps2_; std::vector steps_; std::vector relation_steps_; std::unordered_set, visit_key_hash> visited_;