From 422df82b7c110575abaca1d448946e4f38274bd4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sascha=20K=C3=BChl?= Date: Mon, 1 Dec 2025 16:14:13 +0100 Subject: [PATCH] object generating progress --- include/matador/object/attribute.hpp | 1 + .../matador/object/attribute_generator.hpp | 5 +- include/matador/object/constraint.hpp | 1 + .../matador/object/constraints_generator.hpp | 7 +- include/matador/object/object.hpp | 41 ++--- include/matador/object/object_generator.hpp | 142 ++++++++++++++++++ include/matador/object/repository_node.hpp | 13 +- source/core/CMakeLists.txt | 2 + source/core/object/object_generator.cpp | 60 ++++++++ test/core/object/ObjectTest.cpp | 3 +- 10 files changed, 242 insertions(+), 33 deletions(-) create mode 100644 include/matador/object/object_generator.hpp create mode 100644 source/core/object/object_generator.cpp diff --git a/include/matador/object/attribute.hpp b/include/matador/object/attribute.hpp index cbc9e2d..5353bf6 100644 --- a/include/matador/object/attribute.hpp +++ b/include/matador/object/attribute.hpp @@ -71,6 +71,7 @@ public: private: friend class object; friend class attribute_generator; + friend class object_generator; std::string name_; object *owner_{nullptr}; diff --git a/include/matador/object/attribute_generator.hpp b/include/matador/object/attribute_generator.hpp index 3378059..c269d18 100644 --- a/include/matador/object/attribute_generator.hpp +++ b/include/matador/object/attribute_generator.hpp @@ -62,11 +62,8 @@ public: template < class Type > static std::vector generate(const repository &repo, object &obj) { - std::vector columns; - attribute_generator gen(columns, repo, obj); Type t; - access::process(gen, t); - return columns; + return generate(t, repo, obj); } template < class Type > diff --git a/include/matador/object/constraint.hpp b/include/matador/object/constraint.hpp index 9f1055f..bf66968 100644 --- a/include/matador/object/constraint.hpp +++ b/include/matador/object/constraint.hpp @@ -22,6 +22,7 @@ public: private: friend class constraint_builder; friend class constraints_generator; + friend class object_generator; friend class object; std::string name_; diff --git a/include/matador/object/constraints_generator.hpp b/include/matador/object/constraints_generator.hpp index f2b79ac..17b1564 100644 --- a/include/matador/object/constraints_generator.hpp +++ b/include/matador/object/constraints_generator.hpp @@ -24,9 +24,14 @@ public: template < typename Type > static std::vector generate(const repository &repo, object &obj) { + Type t; + return generate(t, repo, obj); + } + + template < typename Type > + static std::vector generate(const Type& t, const repository &repo, object &obj) { std::vector constraints; constraints_generator gen(constraints, repo, obj); - Type t; access::process(gen, t); return constraints; } diff --git a/include/matador/object/object.hpp b/include/matador/object/object.hpp index 1b7911f..a22c93f 100644 --- a/include/matador/object/object.hpp +++ b/include/matador/object/object.hpp @@ -1,10 +1,10 @@ -#ifndef MATADOR_OBJECT_GENERATOR_HPP -#define MATADOR_OBJECT_GENERATOR_HPP +#ifndef MATADOR_OBJECT_HPP +#define MATADOR_OBJECT_HPP #include "matador/object/attribute.hpp" -#include "matador/object/attribute_generator.hpp" +// #include "matador/object/attribute_generator.hpp" #include "matador/object/constraint.hpp" -#include "matador/object/constraints_generator.hpp" +// #include "matador/object/constraints_generator.hpp" #include "matador/utils/identifier.hpp" @@ -16,21 +16,21 @@ class object { public: explicit object(std::string name, std::string alias = ""); - template - static std::unique_ptr generate(const repository& repo, std::string name, std::string alias = "") { - auto obj = std::make_unique(std::move(name), std::move(alias)); - obj->attributes_ = std::move(attribute_generator::generate(repo, *obj)); - obj->constraints_ = std::move(constraints_generator::generate(repo, *obj)); - return obj; - } - - template - static std::unique_ptr generate(const repository& repo, std::string name, std::string alias = "") { - auto obj = std::make_unique(std::move(name), std::move(alias)); - obj->attributes_ = std::move(attribute_generator::generate(repo, *obj)); - obj->constraints_ = std::move(constraints_generator::generate(repo, *obj)); - return obj; - } + // template + // static std::unique_ptr generate(const repository& repo, std::string name, std::string alias = "") { + // auto obj = std::make_unique(std::move(name), std::move(alias)); + // obj->attributes_ = std::move(attribute_generator::generate(repo, *obj)); + // obj->constraints_ = std::move(constraints_generator::generate(repo, *obj)); + // return obj; + // } + // + // template + // static std::unique_ptr generate(const std::unique_ptr& ptr, const repository& repo, std::string name, std::string alias = "") { + // auto obj = std::make_unique(std::move(name), std::move(alias)); + // obj->attributes_ = std::move(attribute_generator::generate(*ptr, repo, *obj)); + // obj->constraints_ = std::move(constraints_generator::generate(*ptr, repo, *obj)); + // return obj; + // } static const attribute& create_attribute(std::string name, object& obj); @@ -57,6 +57,7 @@ public: private: friend class constraints_generator; friend class attribute_generator; + friend class object_generator; std::string name_; std::string alias_; @@ -67,4 +68,4 @@ private: std::vector constraints_; }; } -#endif //MATADOR_OBJECT_GENERATOR_HPP \ No newline at end of file +#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 new file mode 100644 index 0000000..f084593 --- /dev/null +++ b/include/matador/object/object_generator.hpp @@ -0,0 +1,142 @@ +#ifndef MATADOR_OBJECT_GENERATOR_HPP +#define MATADOR_OBJECT_GENERATOR_HPP + +#include "matador/object/object.hpp" + +#include "matador/utils/access.hpp" +#include "matador/utils/primary_key_attribute.hpp" + +#include + +namespace matador::object { +class repository; + +class pk_type_determinator { +private: + pk_type_determinator() = default; + +public: + template + static utils::basic_type determine() { + pk_type_determinator determinator; + Type t; + + access::process(determinator, t); + return determinator.type_; + } + + template + void on_primary_key(const char *, ValueType &/*pk*/, const utils::primary_key_attribute& attr = utils::default_pk_attributes) { + type_ = utils::data_type_traits::type(attr.size()); + } + static void on_revision(const char * /*id*/, uint64_t &/*rev*/) {} + template < class Type > + static void on_attribute(const char * /*id*/, Type &/*x*/, const utils::field_attributes &/*attr*/ = utils::null_attributes) {} + static void on_attribute(const char * /*id*/, char * /*x*/, const utils::field_attributes &/*attr*/ = utils::null_attributes) {} + template + static void on_belongs_to(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/) {} + template + static void on_has_one(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/) {} + template + static void on_has_many(const char * /*id*/, ContainerType &, const char *, const utils::foreign_attributes &/*attr*/) {} + template + static void on_has_many_to_many(const char * /*id*/, ContainerType & /*cont*/, const char * /*join_column*/, const char * /*inverse_join_column*/, const utils::foreign_attributes &/*attr*/) {} + template + static void on_has_many_to_many(const char * /*id*/, ContainerType & /*cont*/, const utils::foreign_attributes &/*attr*/) {} + +private: + utils::basic_type type_{}; +}; + +class object_generator { +private: + explicit object_generator(const repository& repo, std::unique_ptr &&object); + +public: + template < class Type > + static std::unique_ptr generate(const repository &repo, const std::string &name, const std::string &alias = "") { + return generate(std::make_unique(), repo, name, alias); + } + + template < class Type > + static std::unique_ptr generate(std::unique_ptr&& t, const repository &repo, const std::string &name, const std::string &alias = "") { + object_generator gen(repo, std::make_unique(name, alias)); + access::process(gen, *t); + return gen.move(); + } + + [[nodiscard]] std::unique_ptr move() { return std::move(object_); } + + template < class Type > + void on_primary_key(const char *, Type &x, const utils::primary_key_attribute& attr = utils::default_pk_attributes); + void on_revision(const char *id, uint64_t &rev); + + template + void on_attribute(const char *id, Type &x, const utils::field_attributes &attr = utils::null_attributes); + + template + void on_attribute(const char *id, std::optional &x, const utils::field_attributes &attr = utils::null_attributes); + + template + void on_belongs_to(const char *id, Pointer &x, const utils::foreign_attributes &/*attr*/) { + on_foreign_key(id, x); + create_fk_constraint( typeid(typename Pointer::value_type), id); + } + template + static void on_has_one(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/) {} + + template + void on_foreign_key(const char *id, Pointer &x) { + const auto type = pk_type_determinator::determine(); + auto &ref = object_->attributes_.emplace_back(id, type, utils::constraints::ForeignKey, null_option_type::NOT_NULL); + ref.owner_ = object_.get(); + + create_fk_constraint(typeid(typename Pointer::value_type), id); + } + template + static void on_has_many(const char * /*id*/, ContainerType &, const char *, const utils::foreign_attributes &/*attr*/) {} + template + static void on_has_many_to_many(const char * /*id*/, ContainerType & /*cont*/, const char * /*join_column*/, const char * /*inverse_join_column*/, const utils::foreign_attributes &/*attr*/) {} + template + static void on_has_many_to_many(const char * /*id*/, ContainerType & /*cont*/, const utils::foreign_attributes &/*attr*/) {} + +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.owner_ = object_.get(); + return ref; + } + + void create_pk_constraint(const std::string& name) const; + void create_fk_constraint(const std::type_index& ti, const std::string& name) const; + void create_unique_constraint(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; + +private: + const repository &repo_; + std::unique_ptr object_; +}; + +template +void object_generator::on_primary_key(const char *id, ValueType &x, const utils::primary_key_attribute& attr) { + auto &ref = emplace_attribute(id, { attr.size(), utils::constraints::PrimaryKey }, null_option_type::NOT_NULL); + prepare_primary_key(ref, utils::identifier(x)); + create_pk_constraint(id); +} + +template +void object_generator::on_attribute(const char *id, Type &/*x*/, const utils::field_attributes &attr) { + std::ignore = emplace_attribute(id, attr, null_option_type::NOT_NULL); +} + +template +void object_generator::on_attribute(const char *id, std::optional & /*x*/, const utils::field_attributes &attr) { + std::ignore = emplace_attribute(id, attr, null_option_type::NULLABLE); +} + +} +#endif //MATADOR_OBJECT_GENERATOR_HPP \ No newline at end of file diff --git a/include/matador/object/repository_node.hpp b/include/matador/object/repository_node.hpp index f9d5a61..2df49dd 100644 --- a/include/matador/object/repository_node.hpp +++ b/include/matador/object/repository_node.hpp @@ -2,7 +2,7 @@ #define SCHEMA_NODE_HPP #include "matador/object/attribute_generator.hpp" -#include "matador/object/object.hpp" +#include "matador/object/object_generator.hpp" #include "matador/object/object_info.hpp" #include "matador/object/primary_key_resolver.hpp" @@ -23,7 +23,7 @@ public: primary_key_resolver resolver; auto pk_info = resolver.resolve(); - auto obj = object::generate(repo, name); + auto obj = object_generator::generate(repo, name); auto info = std::make_unique>( node, std::move(obj), @@ -41,12 +41,11 @@ public: return result; } - auto obj = creator(); - object o(name); + auto obj = object_generator::generate(creator(), repo, name); auto info = std::make_unique>( - result.value(), - attribute_generator::generate(*obj, repo, o), - std::forward(creator) + result.value(), + std::move(obj), + std::forward(creator) ); result.value()->info_ = std::move(info); diff --git a/source/core/CMakeLists.txt b/source/core/CMakeLists.txt index fd464b4..291557c 100644 --- a/source/core/CMakeLists.txt +++ b/source/core/CMakeLists.txt @@ -108,6 +108,8 @@ add_library(matador-core STATIC utils/value.cpp utils/version.cpp object/object.cpp + ../../include/matador/object/object_generator.hpp + object/object_generator.cpp ) target_link_libraries(matador-core ${CMAKE_DL_LIBS}) diff --git a/source/core/object/object_generator.cpp b/source/core/object/object_generator.cpp new file mode 100644 index 0000000..eb03170 --- /dev/null +++ b/source/core/object/object_generator.cpp @@ -0,0 +1,60 @@ +#include "matador/object/object_generator.hpp" + +#include "matador/object/repository.hpp" + +namespace matador::object { +object_generator::object_generator( const repository& repo, std::unique_ptr&& object ) +: repo_(repo) +, object_(std::move(object)) {} + +void object_generator::on_revision(const char* id, uint64_t& rev) { + on_attribute(id, rev); +} + +void object_generator::create_pk_constraint(const std::string& name) const { + class constraint pk_constraint("PK_" + object_->name()); + pk_constraint.options_ |= utils::constraints::PrimaryKey; + if (const auto pk_attr = find_attribute_by_name(name); pk_attr != std::end(object_->attributes_)) { + pk_constraint.attr_ = &*pk_attr; + } + pk_constraint.owner_ = object_.get(); + 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 result = repo_.basic_info(ti); + if (!result) { + return; + } + const auto *pk_attribute = result.value().get().primary_key_attribute(); + class constraint pk_constraint("FK_" + object_->name() + "_" + name); + pk_constraint.options_ |= utils::constraints::ForeignKey; + if (const auto pk_attr = find_attribute_by_name(name); pk_attr != std::end(object_->attributes_)) { + pk_constraint.attr_ = &*pk_attr; + } + pk_constraint.owner_ = object_.get(); + pk_constraint.ref_column_name_ = pk_attribute->name(); + pk_constraint.ref_table_name_ = pk_attribute->owner() ? pk_attribute->owner()->name() : ""; + object_->constraints_.emplace_back(std::move(pk_constraint)); +} + +void object_generator::create_unique_constraint(const std::string& name) const { + class constraint pk_constraint("UK_" + object_->name() + "_" + name); + pk_constraint.options_ |= utils::constraints::Unique; + if (const auto pk_attr = find_attribute_by_name(name); pk_attr != std::end(object_->attributes_)) { + pk_constraint.attr_ = &*pk_attr; + } + pk_constraint.owner_ = object_.get(); +} + +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(attribute& ref, utils::identifier &&pk) const { + object_->pk_attribute_ = &ref; + object_->pk_identifier_ = std::move(pk); +} +} diff --git a/test/core/object/ObjectTest.cpp b/test/core/object/ObjectTest.cpp index ae69bc3..652bd9f 100644 --- a/test/core/object/ObjectTest.cpp +++ b/test/core/object/ObjectTest.cpp @@ -1,6 +1,7 @@ #include #include "matador/object/object.hpp" +#include "matador/object/object_generator.hpp" #include "matador/object/repository.hpp" #include "../test/models/author.hpp" @@ -12,7 +13,7 @@ TEST_CASE("Generate object from type", "[object][generate]") { auto result = repo.attach("authors"); REQUIRE(result); - const auto obj = object::object::generate(repo, "books"); + const auto obj = object::object_generator::generate(repo, "books"); REQUIRE(obj->name() == "books"); REQUIRE(obj->alias().empty()); REQUIRE(obj->attributes().size() == 4);