has many to many relation inserts
This commit is contained in:
parent
cfd2a9c423
commit
a2c5bca709
|
|
@ -59,6 +59,28 @@ struct pk_unset_checker {
|
|||
static void on_has_many_to_many(const char * /*id*/, C &, const utils::foreign_attributes & ) {}
|
||||
};
|
||||
|
||||
struct pk_value_extractor {
|
||||
std::uint64_t value{0};
|
||||
|
||||
template<class V>
|
||||
void on_primary_key(const char * /*id*/, V &pk, const utils::primary_key_attribute & = utils::default_pk_attributes) {
|
||||
value = static_cast<std::uint64_t>(pk);
|
||||
}
|
||||
static void on_revision(const char * /*id*/, uint64_t & /*rev*/) {}
|
||||
template<typename T>
|
||||
static void on_attribute(const char * /*id*/, T &, const utils::field_attributes & = utils::null_attributes) {}
|
||||
template<class P>
|
||||
static void on_belongs_to(const char * /*id*/, P &, const utils::foreign_attributes & ) {}
|
||||
template<class P>
|
||||
static void on_has_one(const char * /*id*/, P &, const utils::foreign_attributes & ) {}
|
||||
template<class C>
|
||||
static void on_has_many(const char * /*id*/, C &, const char * /*join_column*/, const utils::foreign_attributes & ) {}
|
||||
template<class C>
|
||||
static void on_has_many_to_many(const char * /*id*/, C &, const char * /*join_column*/, const char * /*inverse_join_column*/, const utils::foreign_attributes & ) {}
|
||||
template<class C>
|
||||
static void on_has_many_to_many(const char * /*id*/, C &, const utils::foreign_attributes & ) {}
|
||||
};
|
||||
|
||||
class insert_query_builder {
|
||||
public:
|
||||
using step_query_t = std::variant<executable_query, fetchable_query>;
|
||||
|
|
@ -91,6 +113,12 @@ public:
|
|||
|
||||
build_for(ptr);
|
||||
|
||||
// relation inserts must run after all entity inserts were collected
|
||||
for (auto &s : relation_steps_) {
|
||||
steps_.push_back(std::move(s));
|
||||
}
|
||||
relation_steps_.clear();
|
||||
|
||||
return utils::ok(steps_);
|
||||
}
|
||||
|
||||
|
|
@ -110,10 +138,53 @@ public:
|
|||
void on_has_one(const char * /*id*/, Pointer &obj, const utils::foreign_attributes &attr) {
|
||||
on_foreign_object(obj, attr);
|
||||
}
|
||||
template<class C>
|
||||
static void on_has_many(const char * /*id*/, C &, const char * /*join_column*/, const utils::foreign_attributes & ) {}
|
||||
template<class C>
|
||||
static void on_has_many_to_many(const char * /*id*/, C &, const char * /*join_column*/, const char * /*inverse_join_column*/, const utils::foreign_attributes & ) {}
|
||||
template<class Collection>
|
||||
static void on_has_many(const char * /*id*/, Collection &con, const char * /*join_column*/, const utils::foreign_attributes & ) {}
|
||||
template<class Collection>
|
||||
void on_has_many_to_many(const char *id, Collection &con, const char *join_column, const char *inverse_join_column, const utils::foreign_attributes & ) {
|
||||
if (id == nullptr || join_column == nullptr || inverse_join_column == nullptr) {
|
||||
return;
|
||||
}
|
||||
if (current_entity_pk_ == 0ULL) {
|
||||
// Without a local PK we cannot create relation rows
|
||||
// (PK may be assigned later by Identity; that case needs a different mechanism than requested here)
|
||||
return;
|
||||
}
|
||||
|
||||
const auto rel_it = schema_.find(std::string{id});
|
||||
if (rel_it == schema_.end()) {
|
||||
throw query_builder_exception(query_build_error::UnknownType);
|
||||
}
|
||||
const table &rel_table = rel_it->second.table();
|
||||
|
||||
for (auto &obj : con) {
|
||||
if (!obj) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Ensure target exists as dependency (deps first)
|
||||
if (!obj.is_persistent()) {
|
||||
using dep_t = std::remove_reference_t<decltype(*obj)>;
|
||||
build_for<dep_t>(obj);
|
||||
}
|
||||
|
||||
// Extract FK value from the foreign object
|
||||
pk_value_extractor fk{};
|
||||
access::process(fk, *obj);
|
||||
if (fk.value == 0ULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Build INSERT into relation table with the 2 FK columns
|
||||
insert_step rel_step{};
|
||||
rel_step.query = executable_query{
|
||||
query::query::insert()
|
||||
.into(rel_table, {table_column{&rel_table, join_column}, table_column{&rel_table, inverse_join_column}})
|
||||
.values({utils::database_type{current_entity_pk_}, utils::database_type{fk.value}})
|
||||
};
|
||||
relation_steps_.push_back(std::move(rel_step));
|
||||
}
|
||||
}
|
||||
template<class C>
|
||||
static void on_has_many_to_many(const char * /*id*/, C &, const utils::foreign_attributes & ) {}
|
||||
|
||||
|
|
@ -204,7 +275,10 @@ private:
|
|||
const basic_schema &schema_;
|
||||
|
||||
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::uint64_t current_entity_pk_{0};
|
||||
};
|
||||
}
|
||||
#endif //MATADOR_INSERT_QUERY_BUILDER_HPP
|
||||
Loading…
Reference in New Issue