replaced pk_is_unset, pk_setter and pk_value_extractor with pk_accessor

This commit is contained in:
Sascha Kühl 2026-04-05 12:49:18 +02:00
parent 1806e2670c
commit 57246d8742
1 changed files with 19 additions and 105 deletions

View File

@ -6,81 +6,9 @@
#include "matador/query/query.hpp"
#include "matador/query/query_builder_exception.hpp"
#include "matador/utils/primary_key_accessor.hpp"
namespace matador::query {
struct pk_setter {
const std::string &name;
std::uint64_t value;
template<class V>
void on_primary_key(const char *id, V &pk, const utils::primary_key_attribute &/*attr*/) {
if (id != nullptr && name == id) {
pk = static_cast<V>(value);
}
}
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 &/*attr*/) {}
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 & ) {}
};
struct pk_unset_checker {
const std::string &name;
bool unset{true};
template<class V>
void on_primary_key(const char *id, V &pk, const utils::primary_key_attribute &/*attr*/) {
if (id != nullptr && name == id) {
// Your convention: 0 means unset for integer PKs
unset = (static_cast<std::uint64_t>(pk) == 0ULL);
}
}
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 &/*attr*/) {}
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 & ) {}
};
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 &/*attr*/) {
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 &/*attr*/) {}
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>;
@ -90,10 +18,7 @@ public:
// Session uses these to handle manual/sequence/table pre-insert PKs
utils::generator_type pk_generator{utils::generator_type::Manual};
std::string pk_name;
std::function<bool()> pk_is_unset{};
std::function<void(std::uint64_t)> set_pk{};
utils::primary_key_accessor pk_accessor;
// Identity post-insert
std::function<void(const sql::record &)> apply_returning{};
@ -180,19 +105,18 @@ public:
}
// Extract FK value from the foreign object
pk_value_extractor fk{};
access::process(fk, *obj);
if (fk.value == 0ULL) {
insert_step rel_step{};
const auto pk = rel_step.pk_accessor.get(obj);
if (pk.is_valid()) {
continue;
}
// Build INSERT into relation table with the 2 FK columns
insert_step rel_step{};
rel_step.query = executable_query{
insert()
.into(relation_table, {table_column{&relation_table, join_column}, table_column{&relation_table, inverse_join_column}})
.values({utils::database_type{current_entity_pk_}, utils::database_type{fk.value}})
};
// rel_step.query = executable_query{
// insert()
// .into(relation_table, {table_column{&relation_table, join_column}, table_column{&relation_table, inverse_join_column}})
// .values({utils::database_type{current_entity_pk_}, utils::database_type{fk.value}})
// };
relation_steps_.push_back(std::move(rel_step));
}
}
@ -238,29 +162,18 @@ private:
const auto &info = it->second.node().info();
insert_step step{};
if (info.has_primary_key()) {
step.pk_name = info.primary_key_attribute()->name();
step.pk_generator = it->second.pk_generator().type();
step.pk_is_unset = [ptr, name = step.pk_name]() {
pk_unset_checker chk{name};
access::process(chk, *ptr);
return chk.unset;
};
step.set_pk = [ptr, name = step.pk_name](std::uint64_t v) {
pk_setter setter{name, v};
access::process(setter, *ptr);
};
}
if (info.has_primary_key() && step.pk_generator == utils::generator_type::Identity) {
const table_column pk_col(&it->second.table(), step.pk_name);
const auto pk_name = info.primary_key_attribute()->name();
const table_column pk_col(&it->second.table(), pk_name);
step.query = fetchable_query{insert().into(it->second.table()).values(*ptr).returning(pk_col)};
step.apply_returning = [ptr, pk_name = step.pk_name](const sql::record &rec) {
if (auto v = rec.at<std::uint64_t>(pk_name); v.has_value()) {
pk_setter setter{pk_name, *v};
access::process(setter, *ptr);
}
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);
};
} else {
step.query = executable_query{insert().into(it->second.table()).values(*ptr)};
@ -289,6 +202,7 @@ private:
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};
};
}