Merge remote-tracking branch 'origin/feature/matador-ng' into feature/matador-ng
This commit is contained in:
@@ -0,0 +1,173 @@
|
||||
#ifndef MATADOR_DEPENDENCY_COLLECTOR_HPP
|
||||
#define MATADOR_DEPENDENCY_COLLECTOR_HPP
|
||||
|
||||
#include "matador/utils/field_attributes.hpp"
|
||||
#include "matador/utils/foreign_attributes.hpp"
|
||||
#include "matador/utils/primary_key_attribute.hpp"
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <typeindex>
|
||||
#include <cstdint>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace matador::query {
|
||||
enum class pk_strategy_kind {
|
||||
manual,
|
||||
sequence,
|
||||
table,
|
||||
identity
|
||||
};
|
||||
|
||||
enum class pk_state {
|
||||
unknown, // z.B. identity vor insert, oder manual aber nicht gesetzt
|
||||
known // id ist gesetzt/verfügbar
|
||||
};
|
||||
|
||||
struct fk_ref {
|
||||
std::string fk_column; // z.B. "author_id" (optional, für Debug/SQL)
|
||||
void* parent_object_ptr; // Adresse des referenzierten Objekts (type-erased)
|
||||
std::type_index parent_type;
|
||||
};
|
||||
|
||||
struct pk_accessor {
|
||||
// obj zeigt auf konkrete Entity-Instanz
|
||||
bool (*is_known)(void* obj) = nullptr;
|
||||
void (*set_u64)(void* obj, std::uint64_t id) = nullptr;
|
||||
std::uint64_t (*get_u64)(void* obj) = nullptr;
|
||||
};
|
||||
|
||||
struct entity_meta {
|
||||
pk_strategy_kind strategy{};
|
||||
pk_accessor pk;
|
||||
// optional: table name, pk column name, etc.
|
||||
};
|
||||
|
||||
struct meta_registry {
|
||||
std::unordered_map<std::type_index, entity_meta> by_type;
|
||||
|
||||
const entity_meta& get(const std::type_index t) const {
|
||||
return by_type.at(t);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void register_type(entity_meta m) {
|
||||
by_type.emplace(std::type_index(typeid(T)), m);
|
||||
}
|
||||
};
|
||||
|
||||
struct dependency_collector {
|
||||
std::vector<fk_ref> refs;
|
||||
|
||||
template<class V>
|
||||
static void on_primary_key(const char*, V&, const utils::primary_key_attribute& /*attr*/ = utils::default_pk_attributes) {}
|
||||
|
||||
static void on_revision(const char*, std::uint64_t&) {}
|
||||
|
||||
template<class V>
|
||||
static void on_attribute(const char*, V&, const utils::field_attributes &/*attr*/ = utils::null_attributes) {}
|
||||
|
||||
template<class Pointer>
|
||||
void on_belongs_to(const char* id, Pointer& p, utils::foreign_attributes &attr) {
|
||||
// Erwartung: Pointer verhält sich wie matador::object::object_ptr<T>
|
||||
// also: p.get() liefert raw ptr, und Pointer::value_type / element_type ist T.
|
||||
auto* raw = p.get();
|
||||
if (!raw) {
|
||||
return;
|
||||
}
|
||||
|
||||
using parent_type = typename Pointer::value_type; // falls object_ptr<T> so definiert ist
|
||||
// Falls dein object_ptr anders heißt (z.B. element_type), hier anpassen.
|
||||
|
||||
refs.push_back(fk_ref{
|
||||
id ? std::string{id} : std::string{},
|
||||
static_cast<void*>(raw),
|
||||
typeid(parent_type)
|
||||
});
|
||||
}
|
||||
|
||||
template<class Pointer>
|
||||
static void on_has_one(const char*, Pointer&, const auto&) {}
|
||||
|
||||
template<class Container>
|
||||
static void on_has_many(const char*, Container&, const char*, const auto&) {}
|
||||
|
||||
template<class Container>
|
||||
static void on_has_many_to_many(const char*, Container&, const char*, const char*, const auto&) {}
|
||||
|
||||
template<class Container>
|
||||
static void on_has_many_to_many(const char*, Container&, const auto&) {}
|
||||
};
|
||||
|
||||
struct flush_node {
|
||||
void* object_ptr = nullptr; // raw pointer (nicht owning)
|
||||
std::type_index type = typeid(void);
|
||||
|
||||
pk_strategy_kind pk_strategy = pk_strategy_kind::manual;
|
||||
pk_accessor pk{};
|
||||
|
||||
pk_state state = pk_state::unknown;
|
||||
|
||||
// eingehende Dependencies: child hängt von parents ab
|
||||
std::vector<std::size_t> depends_on; // Indizes in nodes[]
|
||||
bool inserted = false;
|
||||
};
|
||||
|
||||
struct flush_plan {
|
||||
std::vector<flush_node> nodes;
|
||||
|
||||
// map raw ptr -> node index
|
||||
std::unordered_map<void*, std::size_t> index_by_ptr;
|
||||
};
|
||||
|
||||
flush_plan build_nodes(const std::vector<std::pair<void*, std::type_index>>& new_objects, const meta_registry& reg) {
|
||||
flush_plan plan;
|
||||
plan.nodes.reserve(new_objects.size());
|
||||
|
||||
for (const auto& [ptr, ti] : new_objects) {
|
||||
const auto& meta = reg.get(ti);
|
||||
|
||||
flush_node n;
|
||||
n.object_ptr = ptr;
|
||||
n.type = ti;
|
||||
n.pk_strategy = meta.strategy;
|
||||
n.pk = meta.pk;
|
||||
n.state = n.pk.is_known(n.object_ptr) ? pk_state::known : pk_state::unknown;
|
||||
|
||||
plan.index_by_ptr.emplace(ptr, plan.nodes.size());
|
||||
plan.nodes.push_back(n);
|
||||
}
|
||||
return plan;
|
||||
}
|
||||
|
||||
void add_edges_from_process(flush_plan& plan, const matador::query::process_registry& preg) {
|
||||
using namespace matador::query;
|
||||
for (std::size_t i = 0; i < plan.nodes.size(); ++i) { auto& node = plan.nodes[i];
|
||||
dependency_collector dc;
|
||||
preg.get(node.type).collect_deps(node.object_ptr, dc);
|
||||
|
||||
// 1) belongs_to: node (child) depends on parent
|
||||
for (const auto& ref : dc.refs) {
|
||||
auto it = plan.index_by_ptr.find(ref.parent_object_ptr);
|
||||
if (it == plan.index_by_ptr.end()) {
|
||||
// Parent ist nicht Teil des Plans (externe persistent entity?)
|
||||
// Policy: wenn parent PK known -> ok; sonst Fehler oder cascade-add
|
||||
continue;
|
||||
}
|
||||
node.depends_on.push_back(it->second);
|
||||
}
|
||||
|
||||
// 2) has_many: inverse; daraus macht man Kanten child -> this(parent)
|
||||
for (const auto& child : dc.has_many_children) {
|
||||
auto it_child = plan.index_by_ptr.find(child.child_object_ptr);
|
||||
if (it_child == plan.index_by_ptr.end()) continue;
|
||||
|
||||
auto& child_node = plan.nodes[it_child->second];
|
||||
child_node.depends_on.push_back(i);
|
||||
}
|
||||
|
||||
// 3) many-to-many: als separate work items (nicht in depends_on quetschen)
|
||||
// dc.many_to_many_links -> später join-table tasks planen
|
||||
} }
|
||||
}
|
||||
#endif //MATADOR_DEPENDENCY_COLLECTOR_HPP
|
||||
Reference in New Issue
Block a user