insert_query_builder progress
This commit is contained in:
@@ -33,11 +33,47 @@ struct pk_setter {
|
||||
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 & = utils::default_pk_attributes) {
|
||||
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 & = 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>;
|
||||
|
||||
struct insert_step {
|
||||
executable_query query;
|
||||
bool has_returning{false};
|
||||
step_query_t query;
|
||||
|
||||
// Session uses these to handle manual/sequence/table pre-insert PKs
|
||||
utils::generator_type pk_generator{utils::generator_type::Manually};
|
||||
std::string pk_name;
|
||||
|
||||
std::function<bool()> pk_is_unset{};
|
||||
std::function<void(std::uint64_t)> set_pk{};
|
||||
|
||||
// Identity post-insert
|
||||
std::function<void(const sql::record &)> apply_returning{};
|
||||
};
|
||||
|
||||
@@ -68,13 +104,19 @@ public:
|
||||
|
||||
template<class Pointer>
|
||||
void on_belongs_to(const char *id, Pointer &obj, const utils::foreign_attributes &attr) {
|
||||
on_foreign_object(id, obj, attr);
|
||||
on_foreign_object(obj, attr);
|
||||
}
|
||||
|
||||
template<class Pointer>
|
||||
void on_has_one(const char *id, Pointer &obj, const utils::foreign_attributes &attr) {
|
||||
on_foreign_object(id, obj, 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 C>
|
||||
static void on_has_many_to_many(const char * /*id*/, C &, const utils::foreign_attributes & ) {}
|
||||
|
||||
private:
|
||||
template<class EntityType>
|
||||
@@ -112,35 +154,36 @@ private:
|
||||
access::process(*this, *ptr);
|
||||
|
||||
// 2) Build INSERT for this object
|
||||
// For Identity PK strategy: append RETURNING(pk_column)
|
||||
const auto &info = it->second.node().info();
|
||||
if (info.has_primary_key() && it->second.generator_type() == utils::generator_type::Identity) {
|
||||
const std::string pk_name = info.primary_key_attribute()->name();
|
||||
const table_column pk_col(&it->second.table(), pk_name);
|
||||
insert_step step {
|
||||
query::query::insert()
|
||||
.into(it->second.table())
|
||||
.values(*ptr)
|
||||
.returning(pk_col),
|
||||
true,
|
||||
[ptr, pk_name](const sql::record &rec) {
|
||||
// record.at<T>(name) returns optional<T>
|
||||
// We assume integer-like PKs for now (as in your examples).
|
||||
if (auto v = rec.at<std::uint64_t>(pk_name); v.has_value()) {
|
||||
pk_setter setter{pk_name, *v};
|
||||
access::process(setter, *ptr);
|
||||
}
|
||||
}
|
||||
insert_step step{};
|
||||
if (info.has_primary_key()) {
|
||||
step.pk_name = info.primary_key_attribute()->name();
|
||||
step.pk_generator = it->second.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);
|
||||
};
|
||||
steps_.push_back(std::move(step));
|
||||
return;
|
||||
}
|
||||
|
||||
insert_step step{
|
||||
query::query::insert().into(it->second.table()).values(*ptr),
|
||||
false,
|
||||
{}
|
||||
};
|
||||
if (info.has_primary_key() && step.pk_generator == utils::generator_type::Identity) {
|
||||
const table_column pk_col(&it->second.table(), step.pk_name);
|
||||
step.query = fetchable_query{query::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);
|
||||
}
|
||||
};
|
||||
} else {
|
||||
step.query = executable_query{query::query::insert().into(it->second.table()).values(*ptr)};
|
||||
}
|
||||
steps_.push_back(std::move(step));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user