|
|
|
@@ -64,7 +64,6 @@ static std::pair<std::type_index, const void *> make_visit_key(const EntityType
|
|
|
|
|
|
|
|
|
|
struct visit_key_hash {
|
|
|
|
|
size_t operator()(const std::pair<std::type_index, const void *> &p) const noexcept {
|
|
|
|
|
// combine hashes (simple + sufficient here)
|
|
|
|
|
const size_t h1 = p.first.hash_code();
|
|
|
|
|
const size_t h2 = std::hash<const void *>{}(p.second);
|
|
|
|
|
return h1 ^ (h2 + 0x9e3779b97f4a7c15ULL + (h1 << 6) + (h1 >> 2));
|
|
|
|
@@ -117,7 +116,7 @@ public:
|
|
|
|
|
: ctx_{ctx}
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
utils::result<void, utils::error> build(object::object_ptr<ObjectType> ptr) {
|
|
|
|
|
utils::result<void, utils::error> build(object::object_ptr<ObjectType> ptr, const bool as_relation_step = false) {
|
|
|
|
|
if (!ptr) {
|
|
|
|
|
return utils::failure(utils::error{error_code::InvalidObject, "Object is null"});
|
|
|
|
|
}
|
|
|
|
@@ -137,12 +136,6 @@ public:
|
|
|
|
|
// 1) Traverse relations first => dependencies will be inserted before this object
|
|
|
|
|
try {
|
|
|
|
|
access::process(*this, *ptr_);
|
|
|
|
|
|
|
|
|
|
// relation inserts must run after all entity inserts were collected
|
|
|
|
|
for (auto &s : ctx_.relation_steps_) {
|
|
|
|
|
ctx_.steps_.push_back(std::move(s));
|
|
|
|
|
}
|
|
|
|
|
ctx_.relation_steps_.clear();
|
|
|
|
|
} catch (const query_builder_exception &ex) {
|
|
|
|
|
return utils::failure(ex.error());
|
|
|
|
|
}
|
|
|
|
@@ -157,12 +150,11 @@ public:
|
|
|
|
|
return utils::failure(utils::error{error_code::UnknownType, "Unknown type"});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (it->second.pk_generator().type() == utils::generator_type::Manual) {
|
|
|
|
|
ctx_.steps_.push_back(std::make_unique<insert_step_pk_manual<ObjectType>>(cit->second.insert, ptr_));
|
|
|
|
|
} else if (it->second.pk_generator().type() == utils::generator_type::Identity) {
|
|
|
|
|
ctx_.steps_.push_back(std::make_unique<insert_step_pk_identity<ObjectType>>(cit->second.insert, ptr_, info.primary_key_attribute()->name()));
|
|
|
|
|
auto step = create_insert_step(cit->second.insert, it->second);
|
|
|
|
|
if (as_relation_step) {
|
|
|
|
|
ctx_.relation_steps_.push_back(std::move(step));
|
|
|
|
|
} else {
|
|
|
|
|
ctx_.steps_.push_back(std::make_unique<insert_step_pk_generated<ObjectType>>(cit->second.insert, ptr_, it->second.pk_generator()));
|
|
|
|
|
ctx_.steps_.push_back(std::move(step));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ptr_.reset();
|
|
|
|
@@ -199,18 +191,19 @@ public:
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
has_many_linker<ObjectType> linker(ptr_, join_column);
|
|
|
|
|
insert_context ctx{ctx_.schema_, ctx_.contexts_by_type_};
|
|
|
|
|
insert_step_processor<CollectionType> processor{ctx};
|
|
|
|
|
insert_step_processor<CollectionType> processor{ctx_};
|
|
|
|
|
for (auto &obj : objects) {
|
|
|
|
|
if (!obj.is_transient()) {
|
|
|
|
|
if (!obj) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const auto result = processor.build(obj);
|
|
|
|
|
if (obj.is_transient()) {
|
|
|
|
|
const auto result = processor.build(obj, true);
|
|
|
|
|
if (!result) {
|
|
|
|
|
throw query_builder_exception(error_code::InvalidObject, "Invalid object");
|
|
|
|
|
// return utils::failure(result.err());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
access::process(linker, *obj);
|
|
|
|
|
}
|
|
|
|
@@ -268,7 +261,6 @@ public:
|
|
|
|
|
objects,
|
|
|
|
|
attr,
|
|
|
|
|
[foreign_type, local_type](const char* relation_name) -> processing_many_to_many_key {
|
|
|
|
|
std::cout << "Processing many-to-many relation: " << local_type.name() << ":" << foreign_type.name() << ":" << relation_name << std::endl;
|
|
|
|
|
return {std::string{relation_name}, local_type, foreign_type};
|
|
|
|
|
// return make_processing_many_to_many_key<ObjectType, ForeignType>(relation_name);
|
|
|
|
|
},
|
|
|
|
@@ -297,7 +289,6 @@ public:
|
|
|
|
|
objects,
|
|
|
|
|
attr,
|
|
|
|
|
[foreign_type, local_type](const char* relation_name) -> processing_many_to_many_key {
|
|
|
|
|
std::cout << "Processing many-to-many relation: " << foreign_type.name() << ":" << local_type.name() << ":" << relation_name << std::endl;
|
|
|
|
|
return {std::string{relation_name}, foreign_type, local_type};
|
|
|
|
|
return make_processing_many_to_many_key<ForeignType, ObjectType>(relation_name);
|
|
|
|
|
},
|
|
|
|
@@ -309,12 +300,11 @@ public:
|
|
|
|
|
private:
|
|
|
|
|
template<class PointerType>
|
|
|
|
|
void on_foreign_object(object::object_ptr<PointerType> &obj, const utils::foreign_attributes &attr) {
|
|
|
|
|
if (!utils::is_cascade_type_set(attr.cascade(), utils::cascade_type::Insert) || !obj || obj.is_transient()) {
|
|
|
|
|
if (!utils::is_cascade_type_set(attr.cascade(), utils::cascade_type::Insert) || !obj || !obj.is_transient()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
insert_context ctx{ctx_.schema_, ctx_.contexts_by_type_};
|
|
|
|
|
insert_step_processor<PointerType> processor{ctx};
|
|
|
|
|
insert_step_processor<PointerType> processor{ctx_};
|
|
|
|
|
|
|
|
|
|
const auto result = processor.build(obj);
|
|
|
|
|
if (!result) {
|
|
|
|
@@ -356,15 +346,17 @@ private:
|
|
|
|
|
std::vector<std::unique_ptr<insert_step>> insert_relation_steps;
|
|
|
|
|
insert_step_processor<ForeignType> processor(ctx_);
|
|
|
|
|
for (auto &obj : objects) {
|
|
|
|
|
if (!obj || !obj.is_transient()) {
|
|
|
|
|
if (!obj) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const auto result = processor.build(obj);
|
|
|
|
|
if (obj.is_transient()) {
|
|
|
|
|
const auto result = processor.build(obj, true);
|
|
|
|
|
if (!result) {
|
|
|
|
|
throw query_builder_exception(error_code::InvalidObject, "Invalid object");
|
|
|
|
|
// return utils::failure(result.err());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto rel = make_relation(obj);
|
|
|
|
|
|
|
|
|
@@ -379,6 +371,16 @@ private:
|
|
|
|
|
ctx_.processing_many_to_many_relations_.erase(key);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::unique_ptr<insert_step> create_insert_step(const sql::query_context& query_ctx, const schema_node& node) {
|
|
|
|
|
if (node.pk_generator().type() == utils::generator_type::Manual) {
|
|
|
|
|
return std::make_unique<insert_step_pk_manual<ObjectType>>(query_ctx, ptr_);
|
|
|
|
|
}
|
|
|
|
|
if (node.pk_generator().type() == utils::generator_type::Identity) {
|
|
|
|
|
return std::make_unique<insert_step_pk_identity<ObjectType>>(query_ctx, ptr_, node.node().info().primary_key_attribute()->name());
|
|
|
|
|
}
|
|
|
|
|
return std::make_unique<insert_step_pk_generated<ObjectType>>(query_ctx, ptr_, node.pk_generator());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
insert_context& ctx_;
|
|
|
|
|
object::object_ptr<ObjectType> ptr_;
|
|
|
|
@@ -388,15 +390,16 @@ template<class ObjectType>
|
|
|
|
|
class insert_query_builder {
|
|
|
|
|
public:
|
|
|
|
|
explicit insert_query_builder(const basic_schema &schema, const std::unordered_map<std::type_index, query_contexts> &contexts_by_type)
|
|
|
|
|
: context_{schema, contexts_by_type}
|
|
|
|
|
: schema_(schema)
|
|
|
|
|
, contexts_by_type_(contexts_by_type)
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
utils::result<std::vector<std::unique_ptr<insert_step>>, utils::error> build(const object::object_ptr<ObjectType> &ptr) {
|
|
|
|
|
if (const auto it = context_.schema_.find(typeid(ObjectType)); it == context_.schema_.end()) {
|
|
|
|
|
if (const auto it = schema_.find(typeid(ObjectType)); it == schema_.end()) {
|
|
|
|
|
return utils::failure(utils::error{error_code::UnknownType, "Unknown type for insert query"});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
insert_context ctx{context_.schema_, context_.contexts_by_type_};
|
|
|
|
|
insert_context ctx{schema_, contexts_by_type_};
|
|
|
|
|
insert_step_processor<ObjectType> processor{ctx};
|
|
|
|
|
|
|
|
|
|
const auto result = processor.build(ptr);
|
|
|
|
@@ -404,11 +407,18 @@ public:
|
|
|
|
|
return utils::failure(result.err());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// relation inserts must run after all entity inserts were collected
|
|
|
|
|
for (auto &s : ctx.relation_steps_) {
|
|
|
|
|
ctx.steps_.push_back(std::move(s));
|
|
|
|
|
}
|
|
|
|
|
ctx.relation_steps_.clear();
|
|
|
|
|
|
|
|
|
|
return utils::ok(std::move(ctx.steps_));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
insert_context context_;
|
|
|
|
|
const basic_schema &schema_;
|
|
|
|
|
const std::unordered_map<std::type_index, query_contexts> &contexts_by_type_;
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
#endif //MATADOR_INSERT_QUERY_BUILDER_HPP
|