insert_query_builder optimizations
This commit is contained in:
parent
627af1d1a8
commit
aa8da1f76f
|
|
@ -69,11 +69,13 @@ public:
|
||||||
return utils::failure(utils::error{error_code::UnknownType, "Unknown type for insert query"});
|
return utils::failure(utils::error{error_code::UnknownType, "Unknown type for insert query"});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
relation_steps_.clear();
|
||||||
|
processing_many_to_many_relations_.clear();
|
||||||
steps_.clear();
|
steps_.clear();
|
||||||
visited_.clear();
|
visited_.clear();
|
||||||
|
|
||||||
ptr_ = ptr;
|
ptr_ = ptr;
|
||||||
const auto result = build_for(ptr, steps_);
|
const auto result = build_insert_steps(ptr, steps_);
|
||||||
ptr_.reset();
|
ptr_.reset();
|
||||||
if (!result) {
|
if (!result) {
|
||||||
return utils::failure(result.err());
|
return utils::failure(result.err());
|
||||||
|
|
@ -108,6 +110,9 @@ public:
|
||||||
object::collection<object::object_ptr<CollectionType>> &objects,
|
object::collection<object::object_ptr<CollectionType>> &objects,
|
||||||
const char *join_column,
|
const char *join_column,
|
||||||
const utils::foreign_attributes &attr) {
|
const utils::foreign_attributes &attr) {
|
||||||
|
if (join_column == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (!utils::is_cascade_type_set(attr.cascade(), utils::cascade_type::Insert)) {
|
if (!utils::is_cascade_type_set(attr.cascade(), utils::cascade_type::Insert)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -115,18 +120,24 @@ public:
|
||||||
has_many_linker<ObjectType> linker(ptr_, join_column);
|
has_many_linker<ObjectType> linker(ptr_, join_column);
|
||||||
for (auto &obj : objects) {
|
for (auto &obj : objects) {
|
||||||
if (obj.is_transient()) {
|
if (obj.is_transient()) {
|
||||||
build_for(obj, relation_steps_);
|
const auto result = build_insert_steps(obj, relation_steps_);
|
||||||
|
if (!result) {
|
||||||
|
throw query_builder_exception(error_code::InvalidObject, "Invalid object");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
access::process(linker, *obj);
|
access::process(linker, *obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class CollectionType>
|
template<class CollectionType>
|
||||||
void on_has_many(const char *id,
|
void on_has_many(const char *id,
|
||||||
object::collection<CollectionType> &objects,
|
object::collection<CollectionType> &objects,
|
||||||
const char *join_column,
|
const char *join_column,
|
||||||
const utils::foreign_attributes &attr) {
|
const utils::foreign_attributes &attr) {
|
||||||
|
if (id == nullptr || join_column == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (!utils::is_cascade_type_set(attr.cascade(), utils::cascade_type::Insert)) {
|
if (!utils::is_cascade_type_set(attr.cascade(), utils::cascade_type::Insert)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -159,106 +170,42 @@ public:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto it = schema_.find(std::string{id});
|
|
||||||
if (it == schema_.end()) {
|
|
||||||
throw query_builder_exception(error_code::UnknownType, "Unknown type");
|
|
||||||
}
|
|
||||||
|
|
||||||
using relation_value_type = object::many_to_many_relation<ObjectType, ForeignType>;
|
using relation_value_type = object::many_to_many_relation<ObjectType, ForeignType>;
|
||||||
if (std::type_index(typeid(relation_value_type)) != it->second.node().info().type_index()) {
|
insert_many_to_many_relations<relation_value_type>(
|
||||||
throw query_builder_exception(error_code::InvalidRelationType, "Invalid relation type");
|
id,
|
||||||
}
|
objects,
|
||||||
|
attr,
|
||||||
const auto cit = contexts_by_type_.find(it->second.node().info().type_index());
|
[this, join_column, inverse_join_column](const auto &obj) {
|
||||||
if (cit == contexts_by_type_.end()) {
|
return object::make_object<relation_value_type>(join_column, inverse_join_column, ptr_, obj);
|
||||||
throw query_builder_exception(error_code::UnknownType, "Unknown type");
|
});
|
||||||
}
|
|
||||||
|
|
||||||
std::ignore = processing_many_to_many_relations_.insert(id);
|
|
||||||
std::vector<std::unique_ptr<insert_step>> insert_relation_steps;
|
|
||||||
for (auto &obj : objects) {
|
|
||||||
if (!obj) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure target exists as dependency (deps first)
|
|
||||||
if (obj.is_transient()) {
|
|
||||||
build_for(obj, relation_steps_);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto rel = object::make_object<relation_value_type>(join_column, inverse_join_column, ptr_, obj);
|
|
||||||
|
|
||||||
access::process(*this, *rel);
|
|
||||||
|
|
||||||
insert_relation_steps.push_back(std::make_unique<insert_step_relation<relation_value_type>>(cit->second.insert, rel));
|
|
||||||
}
|
|
||||||
relation_steps_.insert(relation_steps_.end(), std::make_move_iterator(insert_relation_steps.begin()), std::make_move_iterator(insert_relation_steps.end()));
|
|
||||||
processing_many_to_many_relations_.erase(id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class ForeignType>
|
template<class ForeignType>
|
||||||
void on_has_many_to_many(const char *id, object::collection<object::object_ptr<ForeignType>> &objects, const utils::foreign_attributes &attr) {
|
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)) {
|
if (id == nullptr) {
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (processing_many_to_many_relations_.find(id) != processing_many_to_many_relations_.end()) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
object::join_columns_collector collector;
|
object::join_columns_collector collector;
|
||||||
auto join_columns = collector.collect<ForeignType>();
|
auto join_columns = collector.collect<ForeignType>();
|
||||||
|
if (join_columns.join_column.empty() || join_columns.inverse_join_column.empty()) {
|
||||||
const auto it = schema_.find(std::string{id});
|
return;
|
||||||
if (it == schema_.end()) {
|
|
||||||
throw query_builder_exception(error_code::UnknownType, "Unknown type");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
using relation_value_type = object::many_to_many_relation<ForeignType, ObjectType>;
|
using relation_value_type = object::many_to_many_relation<ForeignType, ObjectType>;
|
||||||
|
insert_many_to_many_relations<relation_value_type>(
|
||||||
if (std::type_index(typeid(relation_value_type)) != it->second.node().info().type_index()) {
|
id,
|
||||||
throw query_builder_exception(error_code::InvalidRelationType, "Invalid relation type");
|
objects,
|
||||||
}
|
attr,
|
||||||
|
[this, join_columns = std::move(join_columns)](const auto &obj) {
|
||||||
const auto cit = contexts_by_type_.find(it->second.node().info().type_index());
|
return object::make_object<relation_value_type>(join_columns.inverse_join_column, join_columns.join_column, obj, ptr_);
|
||||||
if (cit == contexts_by_type_.end()) {
|
});
|
||||||
throw query_builder_exception(error_code::UnknownType, "Unknown type");
|
|
||||||
}
|
|
||||||
|
|
||||||
std::ignore = processing_many_to_many_relations_.insert(id);
|
|
||||||
std::vector<std::unique_ptr<insert_step>> insert_relation_steps;
|
|
||||||
for (auto &obj : objects) {
|
|
||||||
if (!obj) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure target exists as dependency (deps first)
|
|
||||||
if (obj.is_transient()) {
|
|
||||||
build_for(obj, relation_steps_);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto rel = object::make_object<relation_value_type>(join_columns.inverse_join_column, join_columns.join_column, obj, ptr_);
|
|
||||||
|
|
||||||
access::process(*this, *rel);
|
|
||||||
|
|
||||||
insert_relation_steps.push_back(std::make_unique<insert_step_relation<relation_value_type>>(cit->second.insert, rel));
|
|
||||||
}
|
|
||||||
relation_steps_.insert(relation_steps_.end(), std::make_move_iterator(insert_relation_steps.begin()), std::make_move_iterator(insert_relation_steps.end()));
|
|
||||||
processing_many_to_many_relations_.erase(id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template<class EntityType>
|
template<class EntityType>
|
||||||
static std::pair<std::type_index, const void *> make_visit_key(const object::object_ptr<EntityType> &ptr) {
|
static std::pair<std::type_index, const void *> make_visit_key(const EntityType &ptr) {
|
||||||
return {std::type_index(typeid(EntityType)), static_cast<const void *>(&(*ptr))};
|
return {std::type_index(typeid(EntityType)), static_cast<const void *>(&ptr)};
|
||||||
}
|
}
|
||||||
|
|
||||||
struct visit_key_hash {
|
struct visit_key_hash {
|
||||||
|
|
@ -271,12 +218,12 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
template<class EntityType>
|
template<class EntityType>
|
||||||
utils::result<void, utils::error> build_for(const object::object_ptr<EntityType> &ptr, std::vector<std::unique_ptr<insert_step>> &steps) {
|
utils::result<void, utils::error> build_insert_steps(const object::object_ptr<EntityType> &ptr, std::vector<std::unique_ptr<insert_step>> &steps) {
|
||||||
if (!ptr) {
|
if (!ptr) {
|
||||||
return utils::failure(utils::error{error_code::InvalidObject, "Object is null"});
|
return utils::failure(utils::error{error_code::InvalidObject, "Object is null"});
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto key = make_visit_key<EntityType>(ptr);
|
const auto key = make_visit_key<EntityType>(*ptr);
|
||||||
if (visited_.find(key) != visited_.end()) {
|
if (visited_.find(key) != visited_.end()) {
|
||||||
return utils::ok<void>();
|
return utils::ok<void>();
|
||||||
}
|
}
|
||||||
|
|
@ -315,20 +262,81 @@ private:
|
||||||
return utils::ok<void>();
|
return utils::ok<void>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<class LocalType, class ForeignType, class RelationFactory>
|
||||||
|
void insert_many_to_many_relations(const char *id,
|
||||||
|
object::collection<object::object_ptr<ForeignType>> &objects,
|
||||||
|
const utils::foreign_attributes &attr,
|
||||||
|
RelationFactory make_relation) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto it = schema_.find(std::string{id});
|
||||||
|
if (it == schema_.end()) {
|
||||||
|
throw query_builder_exception(error_code::UnknownType, "Unknown type");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (std::type_index(typeid(LocalType)) != it->second.node().info().type_index()) {
|
||||||
|
throw query_builder_exception(error_code::InvalidRelationType, "Invalid relation type");
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto cit = contexts_by_type_.find(it->second.node().info().type_index());
|
||||||
|
if (cit == contexts_by_type_.end()) {
|
||||||
|
throw query_builder_exception(error_code::UnknownType, "Unknown type");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ignore = processing_many_to_many_relations_.insert(id);
|
||||||
|
std::vector<std::unique_ptr<insert_step>> insert_relation_steps;
|
||||||
|
for (auto &obj : objects) {
|
||||||
|
if (!obj) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure target exists as dependency (deps first)
|
||||||
|
if (obj.is_transient()) {
|
||||||
|
const auto result = build_insert_steps(obj, relation_steps_);
|
||||||
|
if (!result) {
|
||||||
|
throw query_builder_exception(error_code::InvalidObject, "Invalid object");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto rel = make_relation(obj);
|
||||||
|
|
||||||
|
access::process(*this, *rel);
|
||||||
|
|
||||||
|
insert_relation_steps.push_back(std::make_unique<insert_step_relation<LocalType>>(cit->second.insert, rel));
|
||||||
|
}
|
||||||
|
relation_steps_.insert(
|
||||||
|
relation_steps_.end(),
|
||||||
|
std::make_move_iterator(insert_relation_steps.begin()),
|
||||||
|
std::make_move_iterator(insert_relation_steps.end()));
|
||||||
|
processing_many_to_many_relations_.erase(id);
|
||||||
|
}
|
||||||
template<class Pointer>
|
template<class Pointer>
|
||||||
void on_foreign_object(Pointer &obj, const utils::foreign_attributes & /*attr*/) {
|
void on_foreign_object(Pointer &obj, const utils::foreign_attributes &attr) {
|
||||||
|
if (!utils::is_cascade_type_set(attr.cascade(), utils::cascade_type::Insert)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!obj) {
|
if (!obj) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dependency only matters if the referenced object must be inserted
|
|
||||||
if (obj.is_persistent()) {
|
if (obj.is_persistent()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
using dep_t = std::remove_reference_t<decltype(*obj)>;
|
using dep_t = std::remove_reference_t<decltype(*obj)>;
|
||||||
build_for<dep_t>(obj, steps_);
|
const auto result = build_insert_steps<dep_t>(obj, steps_);
|
||||||
|
if (!result) {
|
||||||
|
throw query_builder_exception(error_code::InvalidObject, "Invalid object");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const basic_schema &schema_;
|
const basic_schema &schema_;
|
||||||
const std::unordered_map<std::type_index, query_contexts> &contexts_by_type_;
|
const std::unordered_map<std::type_index, query_contexts> &contexts_by_type_;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue