From cea7b97f2b478cc5bbf67513caaa59be57019222 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sascha=20K=C3=BChl?= Date: Mon, 1 Jun 2026 06:57:38 +0200 Subject: [PATCH] added join_column_index and inverse_join_column_index to object and table classes --- include/matador/object/attribute.hpp | 2 + include/matador/object/basic_object_info.hpp | 6 +- include/matador/object/basic_repository.hpp | 2 +- include/matador/object/object.hpp | 19 ++-- include/matador/object/object_generator.hpp | 17 +++- include/matador/object/relation_completer.hpp | 7 +- include/matador/object/repository_node.hpp | 30 ++++++ .../query_create_intermediate.hpp | 4 +- include/matador/query/schema.hpp | 20 ++-- source/core/object/attribute.cpp | 4 + source/core/object/basic_object_info.cpp | 6 +- source/core/object/basic_repository.cpp | 2 +- source/core/object/object.cpp | 22 ++++- source/core/object/object_generator.cpp | 91 +++++++++++-------- .../query_create_intermediate.cpp | 4 +- source/orm/query/schema.cpp | 3 + 16 files changed, 164 insertions(+), 75 deletions(-) diff --git a/include/matador/object/attribute.hpp b/include/matador/object/attribute.hpp index 83d917f..d19c256 100644 --- a/include/matador/object/attribute.hpp +++ b/include/matador/object/attribute.hpp @@ -34,6 +34,7 @@ public: [[nodiscard]] const std::string& name() const; void name(const std::string& n); [[nodiscard]] std::string full_name() const; + [[nodiscard]] size_t index() const; [[nodiscard]] const utils::field_attributes& attributes() const; [[nodiscard]] utils::field_attributes& attributes(); [[nodiscard]] bool is_nullable() const; @@ -68,6 +69,7 @@ private: friend class object_generator; std::string name_; + size_t index_{0}; std::weak_ptr owner_; utils::basic_type type_{utils::basic_type::Null}; utils::field_attributes options_{}; diff --git a/include/matador/object/basic_object_info.hpp b/include/matador/object/basic_object_info.hpp index 111d922..9f7deae 100644 --- a/include/matador/object/basic_object_info.hpp +++ b/include/matador/object/basic_object_info.hpp @@ -27,12 +27,12 @@ public: [[nodiscard]] std::type_index type_index() const; [[nodiscard]] std::string name() const; [[nodiscard]] std::shared_ptr object() const; - [[nodiscard]] const std::list& attributes() const; - [[nodiscard]] const std::list& constraints() const; + [[nodiscard]] const std::vector& attributes() const; + [[nodiscard]] const std::vector& constraints() const; [[nodiscard]] bool has_primary_key() const; [[nodiscard]] const utils::identifier& primary_key() const; - [[nodiscard]] attribute* primary_key_attribute() const; + [[nodiscard]] const attribute* primary_key_attribute() const; void update_name(const std::string& name) const; diff --git a/include/matador/object/basic_repository.hpp b/include/matador/object/basic_repository.hpp index 8a743f4..b51caf2 100644 --- a/include/matador/object/basic_repository.hpp +++ b/include/matador/object/basic_repository.hpp @@ -95,7 +95,7 @@ public: return basic_info(std::type_index(typeid(Type))); } - [[nodiscard]] utils::result primary_key_attribute(const std::type_index &ti) const; + [[nodiscard]] utils::result primary_key_attribute(const std::type_index &ti) const; void dump(std::ostream &os) const; static void dump(std::ostream &os, const repository_node& node); diff --git a/include/matador/object/object.hpp b/include/matador/object/object.hpp index 688e9b3..3575b7a 100644 --- a/include/matador/object/object.hpp +++ b/include/matador/object/object.hpp @@ -17,21 +17,25 @@ public: static const attribute& create_attribute(std::string name, const std::shared_ptr& obj); - [[nodiscard]] attribute* primary_key_attribute() const; + [[nodiscard]] const attribute* primary_key_attribute() const; [[nodiscard]] const utils::identifier& primary_key() const; [[nodiscard]] bool has_primary_key() const; + [[nodiscard]] bool is_relation_object() const; + [[nodiscard]] const attribute* join_attribute() const; + [[nodiscard]] const attribute* inverse_join_attribute() const; + [[nodiscard]] const std::string& name() const; void update_name(const std::string& name); [[nodiscard]] bool has_attributes() const; [[nodiscard]] size_t attribute_count() const; - [[nodiscard]] const std::list& attributes() const; + [[nodiscard]] const std::vector& attributes() const; [[nodiscard]] bool has_constraints() const; [[nodiscard]] size_t constraint_count() const; - [[nodiscard]] const std::list& constraints() const; + [[nodiscard]] const std::vector& constraints() const; friend std::ostream& operator<<(std::ostream& os, const object& obj); @@ -40,10 +44,13 @@ private: friend class object_generator; std::string name_; - attribute* pk_attribute_{nullptr}; + int pk_column_index_{-1}; + int join_column_index_{-1}; + int inverse_join_column_index_{-1}; + utils::identifier pk_identifier_; - std::list attributes_; - std::list constraints_; + std::vector attributes_; + std::vector constraints_; }; } #endif //MATADOR_OBJECT_HPP \ No newline at end of file diff --git a/include/matador/object/object_generator.hpp b/include/matador/object/object_generator.hpp index c45062c..c69eaaa 100644 --- a/include/matador/object/object_generator.hpp +++ b/include/matador/object/object_generator.hpp @@ -58,7 +58,11 @@ public: } template < class Type > - static std::shared_ptr generate(std::unique_ptr&& t, basic_repository &repo, const std::string &name) { + static std::shared_ptr generate(std::unique_ptr&& t, + basic_repository &repo, + const std::string &name, + const std::string &join_column = "", + const std::string &inverse_join_column = "") { const std::type_index ti(typeid(Type)); if (repo.has_object_for_type(ti)) { auto obj = repo.object_for_type(ti); @@ -71,6 +75,9 @@ public: std::ignore = repo.provide_object_in_advance(ti, obj); object_generator gen(repo, obj); access::process(gen, *t); + if (!join_column.empty() && !inverse_join_column.empty()) { + gen.prepare_relation_table(join_column, inverse_join_column); + } return obj; } @@ -111,6 +118,7 @@ private: template attribute &emplace_attribute(const char *id, const utils::field_attributes& attr, null_option_type null_option) { auto &ref = object_->attributes_.emplace_back(id, utils::data_type_traits::type(attr.size()), attr, null_option); + ref.index_ = object_->attributes_.size() - 1; ref.owner_ = object_; return ref; } @@ -120,9 +128,10 @@ private: void create_fk_constraint(const std::string& name) const; void create_unique_constraint(const std::string& name) const; - [[nodiscard]] std::list::iterator find_attribute_by_name(const std::string &name) const; + [[nodiscard]] std::vector::iterator find_attribute_by_name(const std::string &name) const; - void prepare_primary_key(attribute &ref, utils::identifier &&pk) const; + void prepare_primary_key(const attribute &ref, utils::identifier &&pk) const; + void prepare_relation_table(const std::string &join_column, const std::string &inverse_join_column) const; template [[nodiscard]] std::shared_ptr fk_object() const; @@ -135,7 +144,7 @@ private: template void object_generator::on_primary_key(const char *id, ValueType &x, const utils::primary_key_attribute& attr) { - utils::constraints cs = utils::constraints::PrimaryKey; + auto cs = utils::constraints::PrimaryKey; if (attr.generator() == utils::generator_type::Identity) { cs |= utils::constraints::Identity; } diff --git a/include/matador/object/relation_completer.hpp b/include/matador/object/relation_completer.hpp index 97cb91d..077ac75 100644 --- a/include/matador/object/relation_completer.hpp +++ b/include/matador/object/relation_completer.hpp @@ -367,7 +367,12 @@ void relation_completer::attach_relation_node(const std::str auto observers = internal::observer_list_copy_creator::copy_create(observers_); - auto node = repository_node::make_node(repo_, name, std::move(creator), std::move(observers)); + auto node = repository_node::make_relation_node(repo_, + name, + join_column, + inverse_join_column, + std::move(creator), + std::move(observers)); auto result = repo_.attach_node(node.release(), ""); if (!result) { // Todo: throw internal error diff --git a/include/matador/object/repository_node.hpp b/include/matador/object/repository_node.hpp index 91c12e7..69b6ad0 100644 --- a/include/matador/object/repository_node.hpp +++ b/include/matador/object/repository_node.hpp @@ -23,6 +23,13 @@ public: const std::string& name, creator_func creator, std::vector>>&& observers); + template < typename Type, template typename... Observers > + static std::unique_ptr make_relation_node(basic_repository& repo, + const std::string& name, + const std::string& join_column, + const std::string& inverse_join_column, + creator_func creator, + std::vector>>&& observers); explicit repository_node(basic_repository& repo); repository_node(const repository_node& other) = delete; @@ -101,5 +108,28 @@ std::unique_ptr repository_node::make_node(basic_repository &re return node; } + +template class ... Observers> +std::unique_ptr repository_node::make_relation_node(basic_repository &repo, + const std::string &name, + const std::string &join_column, + const std::string &inverse_join_column, + creator_func creator, + std::vector>> &&observers) { + const std::type_index ti(typeid(Type)); + auto node = std::unique_ptr(new repository_node(repo, name, ti)); + + internal::observer_list_creator::create_missing(observers); + + auto obj = object_generator::generate(creator(), repo, name, join_column, inverse_join_column); + node->info_.reset(std::make_unique>( + *node, + obj, + std::move(observers), + std::forward>(creator) + ).release()); + + return node; +} } #endif //REPOSITORY_NODE_HPP diff --git a/include/matador/query/intermediates/query_create_intermediate.hpp b/include/matador/query/intermediates/query_create_intermediate.hpp index fb70291..aaf7592 100644 --- a/include/matador/query/intermediates/query_create_intermediate.hpp +++ b/include/matador/query/intermediates/query_create_intermediate.hpp @@ -11,6 +11,8 @@ #include "matador/object/attribute.hpp" #include "matador/object/restriction.hpp" +#include + namespace matador::query { class table; class query_create_table_columns_intermediate : public executable_query { @@ -28,7 +30,7 @@ public: using query_intermediate::query_intermediate; query_create_table_columns_intermediate columns(std::initializer_list attributes); - query_create_table_columns_intermediate columns(const std::list &attributes); + query_create_table_columns_intermediate columns(const std::vector &attributes); query_create_table_columns_intermediate columns(std::initializer_list columns); query_create_table_columns_intermediate columns(const std::list &columns); query_create_table_columns_intermediate columns(const std::vector &columns); diff --git a/include/matador/query/schema.hpp b/include/matador/query/schema.hpp index c767453..dfd866c 100644 --- a/include/matador/query/schema.hpp +++ b/include/matador/query/schema.hpp @@ -318,6 +318,7 @@ public: private: iterator insert_table(const std::type_index& ti, const object::repository_node &node, utils::generator_type generator_type); + iterator insert_relation_table(const std::type_index& ti, const object::repository_node &node); private: template @@ -364,17 +365,16 @@ utils::result query_joined_object_resolver_pro template void schema_observer::on_attach(const object::repository_node &node, const Type &/*prototype*/) const { - primary_key_generator_finder finder; - const auto generator_type = finder.find(node.info().get()); - - const auto it = schema_.insert_table(typeid(Type), node, generator_type); - - if (!it->second.node().info().has_primary_key()) { - return; + const object::object_info& info = node.info().get(); + if (info.has_primary_key()) { + primary_key_generator_finder finder; + const auto generator_type = finder.find(info); + const auto it = schema_.insert_table(typeid(Type), node, generator_type); + auto producer = std::make_unique>(schema_, it->second.table(), it->second.node().info().primary_key_attribute()->name()); + schema_.resolver_producers_[typeid(Type)] = std::move(producer); + } else { + object::join_columns_collector collector; } - - auto producer = std::make_unique>(schema_, it->second.table(), it->second.node().info().primary_key_attribute()->name()); - schema_.resolver_producers_[typeid(Type)] = std::move(producer); } template diff --git a/source/core/object/attribute.cpp b/source/core/object/attribute.cpp index 99d54de..f0c9f8e 100644 --- a/source/core/object/attribute.cpp +++ b/source/core/object/attribute.cpp @@ -32,6 +32,10 @@ std::string attribute::full_name() const { return owner ? owner->name() + "." + name_ : name_; } +size_t attribute::index() const { + return index_; +} + const utils::field_attributes &attribute::attributes() const { return options_; } diff --git a/source/core/object/basic_object_info.cpp b/source/core/object/basic_object_info.cpp index d2ac699..54601f8 100644 --- a/source/core/object/basic_object_info.cpp +++ b/source/core/object/basic_object_info.cpp @@ -21,11 +21,11 @@ std::shared_ptr basic_object_info::object() const { return object_; } -const std::list& basic_object_info::attributes() const { +const std::vector& basic_object_info::attributes() const { return object_->attributes(); } -const std::list& basic_object_info::constraints() const { +const std::vector& basic_object_info::constraints() const { return object_->constraints(); } @@ -37,7 +37,7 @@ const utils::identifier& basic_object_info::primary_key() const { return object_->primary_key(); } -attribute* basic_object_info::primary_key_attribute() const { +const attribute* basic_object_info::primary_key_attribute() const { return object_->primary_key_attribute(); } diff --git a/source/core/object/basic_repository.cpp b/source/core/object/basic_repository.cpp index 1fa78ef..1e1ba4b 100644 --- a/source/core/object/basic_repository.cpp +++ b/source/core/object/basic_repository.cpp @@ -88,7 +88,7 @@ utils::result basic_repository::basic_info( return utils::ok(basic_object_info_ref{it->info()}); } -utils::result basic_repository::primary_key_attribute(const std::type_index &ti) const { +utils::result basic_repository::primary_key_attribute(const std::type_index &ti) const { const auto it = find_node(ti); if (it == end()) { return utils::failure(make_error(error_code::NodeNotFound, "Node '" + std::string(ti.name()) + "' not found.")); diff --git a/source/core/object/object.cpp b/source/core/object/object.cpp index e546787..e31ba17 100644 --- a/source/core/object/object.cpp +++ b/source/core/object/object.cpp @@ -10,8 +10,8 @@ const attribute& object::create_attribute(std::string name, const std::shared_pt return obj->attributes_.emplace_back(std::move(attr)); } -attribute* object::primary_key_attribute() const { - return pk_attribute_; +const attribute* object::primary_key_attribute() const { + return pk_column_index_ != -1 ? &attributes_.at(pk_column_index_) : nullptr; } const utils::identifier& object::primary_key() const { @@ -19,7 +19,19 @@ const utils::identifier& object::primary_key() const { } bool object::has_primary_key() const { - return pk_attribute_ != nullptr; + return pk_column_index_ != -1; +} + +bool object::is_relation_object() const { + return join_column_index_ != -1 && inverse_join_column_index_ != -1; +} + +const attribute * object::join_attribute() const { + return join_column_index_ != -1 ? &attributes_.at(join_column_index_) : nullptr; +} + +const attribute * object::inverse_join_attribute() const { + return inverse_join_column_index_ != -1 ? &attributes_.at(inverse_join_column_index_) : nullptr; } const std::string& object::name() const { @@ -38,7 +50,7 @@ size_t object::attribute_count() const { return attributes_.size(); } -const std::list& object::attributes() const { +const std::vector& object::attributes() const { return attributes_; } @@ -50,7 +62,7 @@ size_t object::constraint_count() const { return constraints_.size(); } -const std::list& object::constraints() const { +const std::vector& object::constraints() const { return constraints_; } diff --git a/source/core/object/object_generator.cpp b/source/core/object/object_generator.cpp index 531b083..737c10f 100644 --- a/source/core/object/object_generator.cpp +++ b/source/core/object/object_generator.cpp @@ -5,54 +5,69 @@ #include namespace matador::object { -object_generator::object_generator(basic_repository& repo, const std::shared_ptr& object) +object_generator::object_generator(basic_repository &repo, const std::shared_ptr &object) : repo_(repo) -, object_(object) {} - -std::shared_ptr object_generator::acquire_object(basic_repository &repo, const std::type_index &ti, const std::string& name) { - if (repo.has_object_for_type(ti)) { - auto obj = repo.object_for_type(ti); - repo.remove_object_for_type(ti); - obj->update_name(name); - return obj; - } - - return repo.provide_object_in_advance(ti, std::make_shared(name)); +, object_(object) { } -void object_generator::on_revision(const char* id, uint64_t& rev) { - access::attribute(*this, id, rev); +std::shared_ptr object_generator::acquire_object(basic_repository &repo, const std::type_index &ti, const std::string &name) { + if (repo.has_object_for_type(ti)) { + auto obj = repo.object_for_type(ti); + repo.remove_object_for_type(ti); + obj->update_name(name); + return obj; + } + + return repo.provide_object_in_advance(ti, std::make_shared(name)); } -void object_generator::create_pk_constraint(const std::string& name) const { - const auto pk_attr = find_attribute_by_name(name); - if (pk_attr == std::end(object_->attributes_)) { - return; - } - restriction pk_constraint(*pk_attr); - pk_constraint.options_ |= utils::constraints::PrimaryKey; - pk_constraint.owner_ = object_; - object_->constraints_.emplace_back(std::move(pk_constraint)); +void object_generator::on_revision(const char *id, uint64_t &rev) { + access::attribute(*this, id, rev); } -void object_generator::create_unique_constraint(const std::string& name) const { - const auto pk_attr = find_attribute_by_name(name); - if (pk_attr == std::end(object_->attributes_)) { - return; - } - restriction pk_constraint(*pk_attr); - pk_constraint.options_ |= utils::constraints::Unique; - pk_constraint.owner_ = object_; +void object_generator::create_pk_constraint(const std::string &name) const { + const auto pk_attr = find_attribute_by_name(name); + if (pk_attr == std::end(object_->attributes_)) { + return; + } + restriction pk_constraint(*pk_attr); + pk_constraint.options_ |= utils::constraints::PrimaryKey; + pk_constraint.owner_ = object_; + object_->constraints_.emplace_back(std::move(pk_constraint)); } -std::list::iterator object_generator::find_attribute_by_name(const std::string& name) const { - return std::find_if(std::begin(object_->attributes_), std::end(object_->attributes_), [&name](const attribute& elem) { - return elem.name() == name; - }); +void object_generator::create_unique_constraint(const std::string &name) const { + const auto pk_attr = find_attribute_by_name(name); + if (pk_attr == std::end(object_->attributes_)) { + return; + } + restriction pk_constraint(*pk_attr); + pk_constraint.options_ |= utils::constraints::Unique; + pk_constraint.owner_ = object_; } -void object_generator::prepare_primary_key(attribute& ref, utils::identifier &&pk) const { - object_->pk_attribute_ = &ref; - object_->pk_identifier_ = std::move(pk); +std::vector::iterator object_generator::find_attribute_by_name(const std::string &name) const { + return std::find_if(std::begin(object_->attributes_), std::end(object_->attributes_), [&name](const attribute &elem) { + return elem.name() == name; + }); +} + +void object_generator::prepare_primary_key(const attribute &ref, utils::identifier &&pk) const { + object_->pk_column_index_ = static_cast(ref.index_); + object_->pk_identifier_ = std::move(pk); +} + +void object_generator::prepare_relation_table(const std::string &join_column, const std::string &inverse_join_column) const { + auto it = find_attribute_by_name(join_column); + if (it == std::end(object_->attributes_)) { + return; + } + object_->join_column_index_ = static_cast(it->index_); + + it = find_attribute_by_name(inverse_join_column); + if (it == std::end(object_->attributes_)) { + return; + } + object_->inverse_join_column_index_ = static_cast(it->index_); } } diff --git a/source/orm/query/intermediates/query_create_intermediate.cpp b/source/orm/query/intermediates/query_create_intermediate.cpp index 3aa64a1..c0a6f5a 100644 --- a/source/orm/query/intermediates/query_create_intermediate.cpp +++ b/source/orm/query/intermediates/query_create_intermediate.cpp @@ -58,10 +58,10 @@ executable_query query_create_table_columns_intermediate::constraints(const std: } query_create_table_columns_intermediate query_create_table_intermediate::columns(const std::initializer_list attributes) { - return columns(std::list(attributes)); + return columns(std::vector(attributes)); } -query_create_table_columns_intermediate query_create_table_intermediate::columns(const std::list& attributes) { +query_create_table_columns_intermediate query_create_table_intermediate::columns(const std::vector& attributes) { std::list columns; for (const auto& attr : attributes) { auto options = attr.attributes().options(); diff --git a/source/orm/query/schema.cpp b/source/orm/query/schema.cpp index f8f9451..3db0c6f 100644 --- a/source/orm/query/schema.cpp +++ b/source/orm/query/schema.cpp @@ -59,4 +59,7 @@ schema::iterator schema::insert_table(const std::type_index &ti, const object::r } return schema_nodes_.insert({ti, schema_node{table(node.name(), columns), std::move(pk_generator), node}}).first; } + +basic_schema::iterator schema::insert_relation_table(const std::type_index &ti, const object::repository_node &node) { +} } // namespace matador::query