session and insert query builder has many to many progress
This commit is contained in:
parent
59e1533cca
commit
78eb5d04cd
|
|
@ -53,7 +53,7 @@ public:
|
|||
[[nodiscard]] bool is_detached() const { return proxy_->is_detached(); }
|
||||
[[nodiscard]] bool is_removed() const { return proxy_->is_removed(); }
|
||||
|
||||
void change_state(object_state s) {
|
||||
void change_state(object_state s) const {
|
||||
if (proxy_) {
|
||||
proxy_->change_state(s);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -145,6 +145,7 @@ utils::result<object::object_ptr<Type>, utils::error> session::insert(object::ob
|
|||
} else if (const auto exec_result = result->execute(); !exec_result.is_ok()) {
|
||||
return utils::failure(exec_result.err());
|
||||
}
|
||||
step.make_object_persistent();
|
||||
}
|
||||
|
||||
obj.change_state(object::object_state::Persistent);
|
||||
|
|
|
|||
|
|
@ -64,6 +64,7 @@ struct insert_step {
|
|||
std::function<void(const sql::record &)> apply_returning{};
|
||||
std::function<void(const utils::identifier &)> apply_primary_key{};
|
||||
std::function<void(sql::statement &)> bind_object{};
|
||||
std::function<void()> make_object_persistent{};
|
||||
};
|
||||
|
||||
template<class ObjectType>
|
||||
|
|
@ -139,17 +140,28 @@ public:
|
|||
return;
|
||||
}
|
||||
|
||||
if (processing_many_to_many_relations_.find(id) != processing_many_to_many_relations_.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto it = schema_.find(std::string{id});
|
||||
if (it == schema_.end()) {
|
||||
throw query_builder_exception(query_build_error::UnknownType);
|
||||
}
|
||||
|
||||
using relation_value_type = object::many_to_many_relation<ObjectType, ForeignType>;
|
||||
using relation_value_type = object::many_to_many_relation<ForeignType, ObjectType>;
|
||||
|
||||
if (std::type_index(typeid(relation_value_type)) != it->second.node().info().type_index()) {
|
||||
throw query_builder_exception(query_build_error::InvalidRelationType);
|
||||
}
|
||||
|
||||
const auto cit = contexts_by_type_.find(it->second.node().info().type_index());
|
||||
if (cit == contexts_by_type_.end()) {
|
||||
throw query_builder_exception(query_build_error::UnknownType);
|
||||
}
|
||||
|
||||
const auto rel_it = processing_many_to_many_relations_.insert(id);
|
||||
std::vector<insert_step> rel_steps;
|
||||
for (auto &obj : objects) {
|
||||
if (!obj) {
|
||||
continue;
|
||||
|
|
@ -164,24 +176,32 @@ public:
|
|||
build_for(obj, relation_steps_);
|
||||
}
|
||||
|
||||
auto rel = object::make_object<relation_value_type>(join_column, inverse_join_column, ptr_, obj);
|
||||
auto rel = object::make_object<relation_value_type>(join_column, inverse_join_column, obj, ptr_);
|
||||
|
||||
// Extract FK value from the foreign object
|
||||
insert_step rel_step{};
|
||||
// const auto pk = rel_step.pk_accessor.get(*obj);
|
||||
// if (pk.is_valid()) {
|
||||
// continue;
|
||||
// }
|
||||
access::process(*this, *rel);
|
||||
|
||||
relation_steps_.push_back(std::move(rel_step));
|
||||
insert_step step{};
|
||||
step.pk_generator = utils::generator_type::None;
|
||||
step.ctx = cit->second.insert;
|
||||
step.bind_object = [rel](sql::statement &stmt) { stmt.bind(*rel); };
|
||||
step.make_object_persistent = [] {};
|
||||
|
||||
rel_steps.push_back(std::move(step));
|
||||
}
|
||||
relation_steps_.insert(relation_steps_.end(), rel_steps.begin(), rel_steps.end());
|
||||
processing_many_to_many_relations_.erase(id);
|
||||
}
|
||||
|
||||
template<class ForeignType>
|
||||
void on_has_many_to_many(const char *id, object::collection<object::object_ptr<ForeignType>> &objects, const utils::foreign_attributes &attr) {
|
||||
if (!utils::is_cascade_type_set(attr.cascade(), utils::cascade_type::Insert)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (processing_many_to_many_relations_.find(id) != processing_many_to_many_relations_.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
object::join_columns_collector collector;
|
||||
auto join_columns = collector.collect<ForeignType>();
|
||||
|
||||
|
|
@ -196,6 +216,13 @@ public:
|
|||
throw query_builder_exception(query_build_error::InvalidRelationType);
|
||||
}
|
||||
|
||||
const auto cit = contexts_by_type_.find(it->second.node().info().type_index());
|
||||
if (cit == contexts_by_type_.end()) {
|
||||
throw query_builder_exception(query_build_error::UnknownType);
|
||||
}
|
||||
|
||||
const auto rel_it = processing_many_to_many_relations_.insert(id);
|
||||
std::vector<insert_step> rel_steps;
|
||||
for (auto &obj : objects) {
|
||||
if (!obj) {
|
||||
continue;
|
||||
|
|
@ -212,23 +239,20 @@ public:
|
|||
|
||||
auto rel = object::make_object<relation_value_type>(join_columns.inverse_join_column, join_columns.join_column, obj, ptr_);
|
||||
|
||||
// Extract FK value from the foreign object
|
||||
insert_step rel_step{};
|
||||
// const auto pk = rel_step.pk_accessor.get(*obj);
|
||||
// if (pk.is_valid()) {
|
||||
// continue;
|
||||
// }
|
||||
access::process(*this, *rel);
|
||||
|
||||
relation_steps_.push_back(std::move(rel_step));
|
||||
insert_step step{};
|
||||
step.pk_generator = utils::generator_type::None;
|
||||
step.ctx = cit->second.insert;
|
||||
step.bind_object = [rel](sql::statement &stmt) { stmt.bind(*rel); };
|
||||
step.make_object_persistent = [] {};
|
||||
|
||||
rel_steps.push_back(std::move(step));
|
||||
}
|
||||
relation_steps_.insert(relation_steps_.end(), rel_steps.begin(), rel_steps.end());
|
||||
processing_many_to_many_relations_.erase(id);
|
||||
}
|
||||
|
||||
template<class CollectionType>
|
||||
void process_has_many_to_many(const char *id, CollectionType &objects, const char *join_column, const char *inverse_join_column) {
|
||||
if (id == nullptr || join_column == nullptr || inverse_join_column == nullptr) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
private:
|
||||
template<class EntityType>
|
||||
static std::pair<std::type_index, const void *> make_visit_key(const object::object_ptr<EntityType> &ptr) {
|
||||
|
|
@ -292,6 +316,7 @@ private:
|
|||
step.pk_accessor.set(*ptr, id);
|
||||
};
|
||||
}
|
||||
step.make_object_persistent = [ptr] { ptr.change_state(object::object_state::Persistent); };
|
||||
steps.push_back(std::move(step));
|
||||
}
|
||||
|
||||
|
|
@ -318,6 +343,7 @@ private:
|
|||
std::vector<insert_step> steps_;
|
||||
std::vector<insert_step> relation_steps_;
|
||||
std::unordered_set<std::pair<std::type_index, const void *>, visit_key_hash> visited_;
|
||||
std::unordered_set<std::string> processing_many_to_many_relations_;
|
||||
};
|
||||
}
|
||||
#endif //MATADOR_INSERT_QUERY_BUILDER_HPP
|
||||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
namespace matador::utils {
|
||||
enum class generator_type {
|
||||
None = 0, /**< No generator type set. */
|
||||
Manual, /**< User sets the primary key value manually. */
|
||||
Auto, /**< Matador chooses the best generator type depending on the underlying dbms. */
|
||||
Identity, /**< DBMS automatically generates the primary key value. */
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
#include "../../models/book.hpp"
|
||||
#include "../../models/airplane.hpp"
|
||||
#include "../../models/flight.hpp"
|
||||
#include "../../models/recipe.hpp"
|
||||
|
||||
using namespace matador::object;
|
||||
using namespace matador::sql;
|
||||
|
|
@ -113,3 +114,40 @@ TEST_CASE("Test insert builder has many", "[query][insert_query_builder][has_man
|
|||
REQUIRE_FALSE(stmts.empty());
|
||||
REQUIRE(stmts.size() == 6);
|
||||
}
|
||||
|
||||
TEST_CASE("Test insert builder has many to many", "[query][insert_query_builder][many_to_many]") {
|
||||
using namespace matador::test;
|
||||
backend_provider::instance().register_backend("noop", std::make_unique<orm::test_backend_service>());
|
||||
connection db("noop://noop.db");
|
||||
|
||||
schema scm;
|
||||
const auto result = scm.attach<recipe>("recipes")
|
||||
.and_then( [&scm] { return scm.attach<ingredient>("ingredients"); } );
|
||||
REQUIRE(result.is_ok());
|
||||
|
||||
const std::vector ingredients {
|
||||
make_object<ingredient>(1, "Apple"),
|
||||
make_object<ingredient>(2, "Strawberry"),
|
||||
make_object<ingredient>(3, "Pineapple"),
|
||||
make_object<ingredient>(4, "Sugar"),
|
||||
make_object<ingredient>(5, "Flour"),
|
||||
make_object<ingredient>(6, "Butter"),
|
||||
make_object<ingredient>(7, "Beans")
|
||||
};
|
||||
|
||||
std::vector recipes {
|
||||
make_object<recipe>(1, "Apple Pie", std::vector{ingredients[0], ingredients[3], ingredients[4]}),
|
||||
make_object<recipe>(2, "Strawberry Cake", std::vector{ingredients[5], ingredients[6]}),
|
||||
make_object<recipe>(3, "Pineapple Pie", std::vector{ingredients[0], ingredients[1], ingredients[2]})
|
||||
};
|
||||
|
||||
const auto contexts_by_type = to_contexts_by_name(scm, db.dialect());
|
||||
insert_query_builder<recipe> iqb(scm, contexts_by_type);
|
||||
|
||||
auto build_result = iqb.build(recipes[0]);
|
||||
REQUIRE(build_result.is_ok());
|
||||
|
||||
const auto& stmts = *build_result;
|
||||
REQUIRE_FALSE(stmts.empty());
|
||||
REQUIRE(stmts.size() == 7);
|
||||
}
|
||||
Loading…
Reference in New Issue