fixed object generation on nested objects

This commit is contained in:
Sascha Kühl 2025-12-11 15:41:45 +01:00
parent 571cfd52ae
commit 79c46bbd38
8 changed files with 97 additions and 34 deletions

View File

@ -29,8 +29,7 @@ private:
public: public:
template<class Type> template<class Type>
static void complete(const std::shared_ptr<repository_node> &node) { static void complete(const std::shared_ptr<repository_node> &node) {
internal::shadow_repository shadow(node->repo_); foreign_node_completer<Type> completer(internal::shadow_repository(node->repo_));
foreign_node_completer<Type> completer(shadow);
completer.complete_node(node); completer.complete_node(node);
} }
@ -83,7 +82,7 @@ private:
} }
template<typename Type> template<typename Type>
void attach_node(const std::string &name = "") { void attach_node(const std::string &name) {
if (repo_.contains(typeid(Type))) { if (repo_.contains(typeid(Type))) {
return; return;
} }
@ -93,6 +92,18 @@ private:
} }
} }
template<typename Type>
void attach_node() {
if (repo_.contains(typeid(Type))) {
return;
}
const auto node = repository_node::make_node<Type>(repo_.repo(), "");
if (auto result = repo_.attach_node(node)) {
complete<Type>(result.value());
}
}
template<typename Type> template<typename Type>
void attach_relation_node(const std::string &name, const std::string &join_column, const std::string &inverse_join_column) { void attach_relation_node(const std::string &name, const std::string &join_column, const std::string &inverse_join_column) {
using relation_value_type = many_to_many_relation<Type, NodeType>; using relation_value_type = many_to_many_relation<Type, NodeType>;

View File

@ -1,6 +1,8 @@
#ifndef SHADOW_SCHEMA_HPP #ifndef SHADOW_SCHEMA_HPP
#define SHADOW_SCHEMA_HPP #define SHADOW_SCHEMA_HPP
#include "matador/object/basic_object_info.hpp"
#include "matador/utils/result.hpp" #include "matador/utils/result.hpp"
#include "matador/utils/error.hpp" #include "matador/utils/error.hpp"
@ -10,6 +12,7 @@
namespace matador::object { namespace matador::object {
class repository; class repository;
class repository_node; class repository_node;
class object;
} }
namespace matador::object::internal { namespace matador::object::internal {
@ -22,6 +25,7 @@ public:
[[nodiscard]] repository& repo() const; [[nodiscard]] repository& repo() const;
[[nodiscard]] bool contains(const std::type_index& ti) const; [[nodiscard]] bool contains(const std::type_index& ti) const;
[[nodiscard]] utils::result<basic_object_info_ref, utils::error> basic_info(const std::type_index& ti) const;
[[nodiscard]] utils::result<node_ptr, utils::error> find_node(const std::type_index &type_index) const; [[nodiscard]] utils::result<node_ptr, utils::error> find_node(const std::type_index &type_index) const;
[[nodiscard]] utils::result<node_ptr, utils::error> find_node(const std::string &name) const; [[nodiscard]] utils::result<node_ptr, utils::error> find_node(const std::string &name) const;
[[nodiscard]] utils::result<node_ptr, utils::error> attach_node(const std::shared_ptr<repository_node> &node) const; [[nodiscard]] utils::result<node_ptr, utils::error> attach_node(const std::shared_ptr<repository_node> &node) const;
@ -31,6 +35,11 @@ public:
void expect_relation_node(const std::string &name, const std::type_index &ti) const; void expect_relation_node(const std::string &name, const std::type_index &ti) const;
void remove_expected_relation_node(const std::string &name) const; void remove_expected_relation_node(const std::string &name) const;
[[nodiscard]] std::shared_ptr<object> provide_object_in_advance(const std::type_index &ti, const std::shared_ptr<object>& obj) const;
[[nodiscard]] bool has_object_for_type(const std::type_index &ti) const;
[[nodiscard]] std::shared_ptr<object> object_for_type(const std::type_index &ti) const;
void remove_object_for_type(const std::type_index &ti) const;
private: private:
repository& repo_; repository& repo_;
}; };

View File

@ -23,6 +23,7 @@ public:
[[nodiscard]] const utils::identifier& primary_key() const; [[nodiscard]] const utils::identifier& primary_key() const;
[[nodiscard]] bool has_primary_key() const; [[nodiscard]] bool has_primary_key() const;
[[nodiscard]] bool empty() const;
[[nodiscard]] const std::string& name() const; [[nodiscard]] const std::string& name() const;
void update_name(const std::string& name); void update_name(const std::string& name);
@ -33,7 +34,7 @@ public:
[[nodiscard]] bool has_constraints() const; [[nodiscard]] bool has_constraints() const;
[[nodiscard]] size_t constraint_count() const; [[nodiscard]] size_t constraint_count() const;
[[nodiscard]] const std::list<class restriction>& constraints() const; [[nodiscard]] const std::list<restriction>& constraints() const;
friend std::ostream& operator<<(std::ostream& os, const object& obj); friend std::ostream& operator<<(std::ostream& os, const object& obj);

View File

@ -1,6 +1,7 @@
#ifndef MATADOR_OBJECT_GENERATOR_HPP #ifndef MATADOR_OBJECT_GENERATOR_HPP
#define MATADOR_OBJECT_GENERATOR_HPP #define MATADOR_OBJECT_GENERATOR_HPP
#include "matador/object/internal/shadow_repository.hpp"
#include "matador/object/object.hpp" #include "matador/object/object.hpp"
#include "matador/utils/access.hpp" #include "matador/utils/access.hpp"
@ -60,7 +61,16 @@ public:
template < class Type > template < class Type >
static std::shared_ptr<object> generate(std::unique_ptr<Type>&& t, repository &repo, const std::string &name) { static std::shared_ptr<object> generate(std::unique_ptr<Type>&& t, repository &repo, const std::string &name) {
auto obj = acquire_object(repo, typeid(Type), name); const internal::shadow_repository shadow_repo(repo);
const std::type_index ti(typeid(Type));
if (shadow_repo.has_object_for_type(ti)) {
auto obj = shadow_repo.object_for_type(ti);
shadow_repo.remove_object_for_type(ti);
obj->update_name(name);
return obj;
}
auto obj = shadow_repo.provide_object_in_advance(ti, std::make_shared<object>(name));
object_generator gen(repo, obj); object_generator gen(repo, obj);
access::process(gen, *t); access::process(gen, *t);
return obj; return obj;
@ -79,7 +89,7 @@ public:
template<class Pointer> template<class Pointer>
void on_belongs_to(const char *id, Pointer &x, const utils::foreign_attributes &/*attr*/) { void on_belongs_to(const char *id, Pointer &x, const utils::foreign_attributes &/*attr*/) {
on_foreign_key(id, x); on_foreign_key(id, x);
create_fk_constraint( typeid(typename Pointer::value_type), id); create_fk_constraint<typename Pointer::value_type>(id);
} }
template<class Pointer> template<class Pointer>
static void on_has_one(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/) {} static void on_has_one(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/) {}
@ -106,14 +116,16 @@ private:
} }
void create_pk_constraint(const std::string& name) const; void create_pk_constraint(const std::string& name) const;
void create_fk_constraint(const std::type_index& ti, const std::string& name) const; template<typename Type>
void create_fk_constraint(const std::string& name) const;
void create_unique_constraint(const std::string& name) const; void create_unique_constraint(const std::string& name) const;
[[nodiscard]] std::list<attribute>::iterator find_attribute_by_name(const std::string &name) const; [[nodiscard]] std::list<attribute>::iterator find_attribute_by_name(const std::string &name) const;
void prepare_primary_key(attribute &ref, utils::identifier &&pk) const; void prepare_primary_key(attribute &ref, utils::identifier &&pk) const;
[[nodiscard]] std::shared_ptr<class object> fk_object(const std::type_index& ti) const; template<typename Type>
[[nodiscard]] std::shared_ptr<object> fk_object() const;
static std::shared_ptr<object> acquire_object(repository &repo, const std::type_index &ti, const std::string& name); static std::shared_ptr<object> acquire_object(repository &repo, const std::type_index &ti, const std::string& name);
private: private:
@ -138,5 +150,37 @@ void object_generator::on_attribute(const char *id, std::optional<Type> & /*x*/,
std::ignore = emplace_attribute<Type>(id, attr, null_option_type::Nullable); std::ignore = emplace_attribute<Type>(id, attr, null_option_type::Nullable);
} }
template<typename Type>
void object_generator::create_fk_constraint(const std::string& name) const {
const auto pk_attr = find_attribute_by_name(name);
if (pk_attr == std::end(object_->attributes_)) {
return;
}
const auto obj = fk_object<Type>();
restriction pk_constraint(*pk_attr);
pk_constraint.options_ |= utils::constraints::ForeignKey;
pk_constraint.owner_ = object_;
pk_constraint.reference_ = obj;
object_->constraints_.emplace_back(std::move(pk_constraint));
}
template<typename Type>
std::shared_ptr<object> object_generator::fk_object() const {
const auto ti = std::type_index(typeid(Type));
const internal::shadow_repository shadow_repo(repo_);
if (const auto result = shadow_repo.basic_info(ti)) {
return result->get().object();
}
if (shadow_repo.has_object_for_type(ti)) {
return shadow_repo.object_for_type(ti);
}
const auto obj = shadow_repo.provide_object_in_advance(ti, std::make_shared<object>(""));
object_generator gen(repo_, obj);
Type t;
access::process(gen, t);
return obj;
}
} }
#endif //MATADOR_OBJECT_GENERATOR_HPP #endif //MATADOR_OBJECT_GENERATOR_HPP

View File

@ -15,6 +15,10 @@ bool shadow_repository::contains( const std::type_index& ti ) const {
return repo_.contains(ti); return repo_.contains(ti);
} }
utils::result<basic_object_info_ref, utils::error> shadow_repository::basic_info(const std::type_index& ti) const {
return repo_.basic_info(ti);
}
utils::result<shadow_repository::node_ptr, utils::error> shadow_repository::find_node( const std::type_index& type_index ) const { utils::result<shadow_repository::node_ptr, utils::error> shadow_repository::find_node( const std::type_index& type_index ) const {
return repo_.find_node(type_index); return repo_.find_node(type_index);
} }
@ -42,4 +46,20 @@ void shadow_repository::expect_relation_node(const std::string &name, const std:
void shadow_repository::remove_expected_relation_node(const std::string &name) const { void shadow_repository::remove_expected_relation_node(const std::string &name) const {
repo_.remove_expected_relation_node(name); repo_.remove_expected_relation_node(name);
} }
std::shared_ptr<object> shadow_repository::provide_object_in_advance(const std::type_index& ti, const std::shared_ptr<object>& obj) const {
return repo_.provide_object_in_advance(ti, obj);
}
bool shadow_repository::has_object_for_type(const std::type_index& ti) const {
return repo_.has_object_for_type(ti);
}
std::shared_ptr<object> shadow_repository::object_for_type(const std::type_index& ti) const {
return repo_.object_for_type(ti);
}
void shadow_repository::remove_object_for_type(const std::type_index& ti) const {
repo_.remove_object_for_type(ti);
}
} }

View File

@ -50,7 +50,7 @@ size_t object::constraint_count() const {
return constraints_.size(); return constraints_.size();
} }
const std::list<class restriction>& object::constraints() const { const std::list<restriction>& object::constraints() const {
return constraints_; return constraints_;
} }

View File

@ -35,19 +35,6 @@ void object_generator::create_pk_constraint(const std::string& name) const {
object_->constraints_.emplace_back(std::move(pk_constraint)); object_->constraints_.emplace_back(std::move(pk_constraint));
} }
void object_generator::create_fk_constraint(const std::type_index& ti, const std::string& name) const {
const auto pk_attr = find_attribute_by_name(name);
if (pk_attr == std::end(object_->attributes_)) {
return;
}
const auto obj = fk_object(ti);
restriction pk_constraint(*pk_attr);
pk_constraint.options_ |= utils::constraints::ForeignKey;
pk_constraint.owner_ = object_;
pk_constraint.reference_ = obj;
object_->constraints_.emplace_back(std::move(pk_constraint));
}
void object_generator::create_unique_constraint(const std::string& name) const { void object_generator::create_unique_constraint(const std::string& name) const {
const auto pk_attr = find_attribute_by_name(name); const auto pk_attr = find_attribute_by_name(name);
if (pk_attr == std::end(object_->attributes_)) { if (pk_attr == std::end(object_->attributes_)) {
@ -68,16 +55,4 @@ void object_generator::prepare_primary_key(attribute& ref, utils::identifier &&p
object_->pk_attribute_ = &ref; object_->pk_attribute_ = &ref;
object_->pk_identifier_ = std::move(pk); object_->pk_identifier_ = std::move(pk);
} }
std::shared_ptr<object> object_generator::fk_object(const std::type_index& ti) const {
const auto result = repo_.basic_info(ti);
if (result) {
return result->get().object();
}
if (repo_.has_object_for_type(ti)) {
return repo_.object_for_type(ti);
}
return repo_.provide_object_in_advance(ti, std::make_shared<object>(""));
}
} }

View File

@ -40,6 +40,9 @@ const std::string& restriction::ref_column_name() const {
std::ostream & operator<<(std::ostream &os, const class restriction &c) { std::ostream & operator<<(std::ostream &os, const class restriction &c) {
os << "constraint " << c.type_string() << " for column " << c.column_name(); os << "constraint " << c.type_string() << " for column " << c.column_name();
if (c.is_foreign_key_constraint()) {
os << " references " << c.ref_table_name() << "." << c.ref_column_name();
}
return os; return os;
} }