removed make_relation_node method from repository_node

This commit is contained in:
Sascha Kühl 2025-12-08 19:45:35 +01:00
parent 263c202c69
commit d4ef97ef5a
15 changed files with 90 additions and 133 deletions

View File

@ -2,8 +2,8 @@ CPMAddPackage("gh:catchorg/Catch2@3.7.1")
list(APPEND CMAKE_MODULE_PATH ${catch2_SOURCE_DIR}/extras)
set(POSTGRES_CONNECTION_STRING "postgres://test:test123!@127.0.0.1:15442/matador")
#set(POSTGRES_CONNECTION_STRING "postgres://test:test123!@127.0.0.1:5432/matador")
#set(POSTGRES_CONNECTION_STRING "postgres://test:test123!@127.0.0.1:15442/matador")
set(POSTGRES_CONNECTION_STRING "postgres://test:test123!@127.0.0.1:5432/matador")
configure_file(Connection.hpp.in ${PROJECT_BINARY_DIR}/backends/postgres/test/connection.hpp @ONLY IMMEDIATE)

View File

@ -6,6 +6,7 @@
#include "matador/utils/field_attributes.hpp"
#include <memory>
#include <ostream>
namespace matador::object {
@ -60,6 +61,8 @@ public:
return type() == utils::data_type_traits<Type>::type(attributes().size());
}
friend std::ostream& operator<<(std::ostream& os, const attribute& attr);
private:
friend class object;
friend class attribute_generator;

View File

@ -26,6 +26,7 @@ public:
[[nodiscard]] std::type_index type_index() const;
[[nodiscard]] std::string name() const;
[[nodiscard]] const class object& object() const;
[[nodiscard]] const std::list<attribute>& attributes() const;
[[nodiscard]] const std::list<class constraint>& constraints() const;
@ -54,10 +55,10 @@ public:
[[nodiscard]] bool endpoints_empty() const;
protected:
basic_object_info(std::shared_ptr<repository_node> node, std::unique_ptr<object> &&obj);
basic_object_info(std::shared_ptr<repository_node> node, std::unique_ptr<class object> &&obj);
protected:
std::unique_ptr<object> object_;
std::unique_ptr<class object> object_;
std::shared_ptr<repository_node> node_; /**< prototype node of the represented object type */
t_endpoint_map relation_endpoints_;
};

View File

@ -3,6 +3,7 @@
#include "matador/utils/constraints.hpp"
#include <ostream>
#include <string>
#include <variant>
@ -28,6 +29,8 @@ public:
[[nodiscard]] const std::string& ref_table_name() const;
[[nodiscard]] const std::string& ref_column_name() const;
friend std::ostream& operator<<(std::ostream& os, const constraint& c);
private:
friend class constraint_builder;
friend class constraints_generator;

View File

@ -115,13 +115,13 @@ private:
return std::make_unique<relation_value_type>(join_column, inverse_join_column);
};
result = repository_node::make_relation_node<relation_value_type>(repo_.repo(), name, std::move(creator));
auto node = repository_node::make_node<relation_value_type>(repo_.repo(), name, std::move(creator));
result = repo_.attach_node(node);
if (!result) {
// Todo: throw internal error
return;
}
auto& node = result.value();
complete<relation_value_type>(result.value());
// auto& node = result.value();

View File

@ -7,6 +7,7 @@
#include "matador/utils/identifier.hpp"
#include <list>
#include <ostream>
namespace matador::object {
@ -38,6 +39,8 @@ public:
[[nodiscard]] size_t constraint_count() const;
[[nodiscard]] const std::list<class constraint>& constraints() const;
friend std::ostream& operator<<(std::ostream& os, const object& obj);
private:
friend class constraints_generator;
friend class attribute_generator;

View File

@ -14,7 +14,7 @@ public:
using create_func = std::function<std::unique_ptr<Type>()>;
object_info(const std::shared_ptr<repository_node>& node,
std::unique_ptr<object> &&obj,
std::unique_ptr<class object> &&obj,
create_func&& creator)
: basic_object_info(node, std::move(obj))
, creator_(std::move(creator)){

View File

@ -186,28 +186,28 @@ void relation_completer<Type>::on_has_many(const char *id, CollectionType &,
const auto local_endpoint = std::make_shared<relation_endpoint>(id, relation_type::HasMany, foreign_node);
nodes_.top()->info_->register_relation_endpoint(typeid(value_type), local_endpoint);
} else {
// A relation table is necessary
// Endpoint was not found.
// Always attach a many-to-many relation type. If later a
// belongs-to relation handles this relation, the many-to-many
// relation is maybe detached.
log_.debug("node '%s' has has many foreign keys '%s' mapped by '%s'", nodes_.top()->name().c_str(), id, join_column);
result = repository_node::make_relation_node<relation_value_type>(
schema_.repo(), id, [join_column] {
return std::make_unique<relation_value_type>("id", join_column);
});
if (!result) {
// Todo: throw internal error
return;
}
const auto local_endpoint = std::make_shared<relation_endpoint>(id, relation_type::HasMany, result.value());
const auto foreign_endpoint = std::make_shared<relation_endpoint>("id", relation_type::BelongsTo, nodes_.top());
nodes_.top()->info_->register_relation_endpoint(typeid(value_type), local_endpoint);
result.value()->info_->register_relation_endpoint(nodes_.top()->type_index(), foreign_endpoint);
link_relation_endpoints(local_endpoint, foreign_endpoint);
// A relation table is necessary
// Endpoint was not found.
// Always attach a many-to-many relation type. If later a
// belongs-to relation handles this relation, the many-to-many
// relation is maybe detached.
log_.debug("node '%s' has has many foreign keys '%s' mapped by '%s'", nodes_.top()->name().c_str(), id, join_column);
auto node = repository_node::make_node<relation_value_type>(schema_.repo(), id, [join_column] {
return std::make_unique<relation_value_type>("id", join_column);
});
result = schema_.attach_node(node);
if (!result) {
// Todo: throw internal error
return;
}
const auto local_endpoint = std::make_shared<relation_endpoint>(id, relation_type::HasMany, node);
const auto foreign_endpoint = std::make_shared<relation_endpoint>("id", relation_type::BelongsTo, nodes_.top());
nodes_.top()->info_->register_relation_endpoint(typeid(value_type), local_endpoint);
node->info_->register_relation_endpoint(nodes_.top()->type_index(), foreign_endpoint);
link_relation_endpoints(local_endpoint, foreign_endpoint);
const auto foreign_value_endpoint = std::make_shared<relation_endpoint>(join_column, relation_type::BelongsTo, foreign_node);
result.value()->info_->register_relation_endpoint(typeid(value_type), foreign_value_endpoint);
const auto foreign_value_endpoint = std::make_shared<relation_endpoint>(join_column, relation_type::BelongsTo, foreign_node);
node->info_->register_relation_endpoint(typeid(value_type), foreign_value_endpoint);
}
}
@ -220,21 +220,20 @@ void relation_completer<Type>::on_has_many(const char *id, CollectionType &, con
using value_type = typename CollectionType::value_type;
using relation_value_type = many_to_relation<Type, value_type>;
const auto result = repository_node::make_relation_node<relation_value_type>(
schema_.repo(), id, [join_column] {
return std::make_unique<relation_value_type>(join_column, "value");
});
auto node = repository_node::make_node<relation_value_type>(schema_.repo(), id, [join_column] {
return std::make_unique<relation_value_type>(join_column, "value");
});
const auto result = schema_.attach_node(node);
if (!result) {
// Todo: throw internal exception
return;
}
const auto local_endpoint = std::make_shared<relation_endpoint>(id, relation_type::HasMany, result.value());
const auto local_endpoint = std::make_shared<relation_endpoint>(id, relation_type::HasMany, node);
const auto foreign_endpoint = std::make_shared<relation_endpoint>(join_column, relation_type::BelongsTo, nodes_.top());
nodes_.top()->info_->register_relation_endpoint(typeid(value_type), local_endpoint);
result.value()->info_->register_relation_endpoint(nodes_.top()->type_index(), foreign_endpoint);
node->info_->register_relation_endpoint(nodes_.top()->type_index(), foreign_endpoint);
link_relation_endpoints(local_endpoint, foreign_endpoint);
}
@ -265,13 +264,13 @@ void relation_completer<Type>::on_has_many_to_many(const char *id,
return std::make_unique<relation_value_type>(join_column, inverse_join_column);
};
result = repository_node::make_relation_node<relation_value_type>(schema_.repo(), id, std::move(creator));
auto node = repository_node::make_node<relation_value_type>(schema_.repo(), id, std::move(creator));
result = schema_.attach_node(node);
if (!result) {
// Todo: throw internal error
return;
}
auto& node = result.value();
const auto local_endpoint = std::make_shared<relation_endpoint>(id, relation_type::HasMany, node);
const auto join_endpoint = std::make_shared<relation_endpoint>(join_column, relation_type::BelongsTo, nodes_.top());
const auto inverse_join_endpoint = std::make_shared<relation_endpoint>(inverse_join_column, relation_type::BelongsTo, foreign_node);

View File

@ -4,7 +4,6 @@
#include "matador/object/attribute_generator.hpp"
#include "matador/object/object_generator.hpp"
#include "matador/object/object_info.hpp"
#include "matador/object/primary_key_resolver.hpp"
#include <memory>
@ -16,42 +15,24 @@ class repository;
class repository_node final {
public:
using node_ptr = std::shared_ptr<repository_node>;
template< typename Type>
using creator_func = std::function<std::unique_ptr<Type>()>;
template < typename Type >
static std::shared_ptr<repository_node> make_node(repository& repo, const std::string& name) {
static std::shared_ptr<repository_node> make_node(repository& repo, const std::string& name, creator_func<Type> creator = []{ return std::make_unique<Type>(); }) {
auto node = std::shared_ptr<repository_node>(new repository_node(repo, name, typeid(Type)));
primary_key_resolver resolver;
auto pk_info = resolver.resolve<Type>();
auto obj = object_generator::generate<Type>(repo, name);
auto obj = object_generator::generate<Type>(creator(), repo, name);
auto info = std::make_unique<object_info<Type>>(
node,
std::move(obj),
[]{ return std::make_unique<Type>(); }
std::forward<creator_func<Type>>(creator)
);
node->info_ = std::move(info);
return node;
}
template < typename Type, typename CreatorFunc >
static utils::result<node_ptr, utils::error> make_relation_node(repository& repo, const std::string& name, CreatorFunc &&creator) {
const auto result = make_and_attach_node(repo, name, typeid(Type));
if (!result) {
return result;
}
auto obj = object_generator::generate(creator(), repo, name);
auto info = std::make_unique<object_info<Type>>(
result.value(),
std::move(obj),
std::forward<CreatorFunc>(creator)
);
result.value()->info_ = std::move(info);
return result;
}
static std::shared_ptr<repository_node> make_null_node(repository& repo);
repository_node(const repository_node& other) = delete;
@ -87,10 +68,6 @@ private:
void unlink();
static utils::result<node_ptr, utils::error> make_and_attach_node(repository& repo, const std::string& name, const std::type_index& ti);
static attribute* determine_reference_column(const std::type_index& ti,
const std::string& table_name,
const primary_key_info& pk_info,
repository& repo);
private:
friend class repository;

View File

@ -92,45 +92,9 @@ bool attribute::is_null() const {
return type_ == utils::basic_type::type_null;
}
// attribute make_column(const std::string &name, utils::basic_type type, utils::field_attributes attr,
// null_option_type null_opt) {
// return {name, type, attr, null_opt};
// }
//
// template<>
// attribute make_column<std::string>(const std::string &name, utils::field_attributes attr,
// null_option_type null_opt) {
// return make_column(name, utils::data_type_traits<std::string>::type(attr.size()), attr, null_opt);
// }
//
// template<>
// attribute make_pk_column<std::string>(const std::string &name, size_t size) {
// return make_column<std::string>(name, {size, utils::constraints::PrimaryKey});
// }
//
// template<>
// attribute make_fk_column<std::string>(const std::string &name, size_t size, const std::shared_ptr<attribute> &ref_column) {
// return {
// name, utils::data_type_traits<std::string>::type(size), 0, ref_column,
// {size, utils::constraints::ForeignKey}, null_option_type::NOT_NULL
// };
// }
//
// template<>
// attribute make_fk_column<std::string>( const std::string& name, const std::string& ref_table_name, const std::string& ref_column_name ) {
// return {
// name, utils::basic_type::type_varchar, 0,
// std::make_shared<attribute>(ref_column_name, utils::basic_type::type_varchar, ref_table_name, attribute_options{utils::constraints::ForeignKey}),
// { 0, utils::constraints::ForeignKey }, null_option_type::NOT_NULL
// };
// }
//
// template<>
// attribute make_fk_column<std::string>(const std::string &name, size_t size, const std::string &ref_table_name, const std::string &ref_column_name) {
// const auto ref_column = std::make_shared<attribute>(ref_column_name, utils::basic_type::type_varchar, ref_table_name, attribute_options{utils::constraints::ForeignKey});
// return {
// name, utils::data_type_traits<std::string>::type(size), 0, ref_column,
// {size, utils::constraints::ForeignKey}, null_option_type::NOT_NULL
// };
// }
std::ostream & operator<<(std::ostream &os, const attribute &attr) {
os << attr.name_;
return os;
}
}

View File

@ -20,7 +20,7 @@ namespace matador::object {
// : node_(std::move(node))
// , attributes_(attributes) {}
basic_object_info::basic_object_info(std::shared_ptr<repository_node> node, std::unique_ptr<object>&& obj)
basic_object_info::basic_object_info(std::shared_ptr<repository_node> node, std::unique_ptr<class object>&& obj)
: object_(std::move(obj))
, node_(std::move(node)) {}
@ -32,6 +32,10 @@ std::string basic_object_info::name() const {
return node_->name();
}
const class object & basic_object_info::object() const {
return *object_;
}
const std::list<attribute>& basic_object_info::attributes() const {
return object_->attributes();
}

View File

@ -52,6 +52,11 @@ const std::string& constraint::ref_column_name() const {
return ref_column_name_;
}
std::ostream & operator<<(std::ostream &os, const class constraint &c) {
os << "constraint " << c.name_ << " for column " << c.column_name();
return os;
}
constraint_builder & constraint_builder::constraint(std::string name) {
constraint_name = std::move(name);
return *this;

View File

@ -75,4 +75,17 @@ size_t object::constraint_count() const {
const std::list<class constraint>& object::constraints() const {
return constraints_;
}
}
std::ostream & operator<<(std::ostream &os, const object &obj) {
os << "Object " << obj.name_ << "\nAttributes:\n";
for (const auto &attr : obj.attributes_) {
os << " " << attr << "\n";
}
os << "Constraints:\n";
for (const auto &con : obj.constraints_) {
os << " " << con << "\n";
}
os << "\n";
return os;
}
}

View File

@ -26,7 +26,7 @@ repository_node::repository_node(repository &repo, std::string name, const std::
std::shared_ptr<repository_node> repository_node::make_null_node(repository &repo) {
auto node = std::shared_ptr<repository_node>(new repository_node(repo));
node->info_ = std::make_unique<null_info>(node/*, std::shared_ptr<attribute_definition>{}*/);
node->info_ = std::make_unique<null_info>(node);
return node;
}
@ -101,27 +101,4 @@ utils::result<repository_node::node_ptr, utils::error> repository_node::make_and
return repo.attach_node(node, "");
}
attribute* repository_node::determine_reference_column(const std::type_index& ti,
const std::string& table_name,
const primary_key_info& pk_info,
repository& repo) {
const auto it = repo.missing_references_.find(ti);
if (it == repo.missing_references_.end()) {
return new attribute(pk_info.pk_column_name, pk_info.type, {utils::constraints::ForeignKey}, null_option_type::NotNull);
}
auto ref_column = it->second;
repo.missing_references_.erase(it);
ref_column->name(pk_info.pk_column_name);
ref_column->owner()->update_name(table_name);
ref_column->change_type(pk_info.type);
ref_column->attributes() = utils::constraints::ForeignKey;
if (table_name.empty()) {
repo.missing_references_.insert({ti, ref_column});
}
return ref_column;
}
}

View File

@ -104,6 +104,9 @@ TEST_CASE("Test one to many", "[relation][one-to-many]") {
REQUIRE(repo.size() == 2);
REQUIRE(repo.contains("departments"));
REQUIRE(repo.contains("employees"));
std::cout << repo.basic_info("departments")->get().object();
std::cout << repo.basic_info("employees")->get().object();
}
TEST_CASE("Test one to many reverse", "[relation][one-to-many][reverse]") {
@ -117,6 +120,9 @@ TEST_CASE("Test one to many reverse", "[relation][one-to-many][reverse]") {
REQUIRE(repo.size() == 2);
REQUIRE(repo.contains("departments"));
REQUIRE(repo.contains("employees"));
std::cout << repo.basic_info("departments")->get().object();
std::cout << repo.basic_info("employees")->get().object();
}
TEST_CASE("Test many to many relation", "[relation][many-to-many]") {
@ -133,5 +139,7 @@ TEST_CASE("Test many to many relation", "[relation][many-to-many]") {
REQUIRE(repo.contains("recipes"));
REQUIRE(repo.contains("recipe_ingredients"));
auto info = repo.basic_info("ingredients");
std::cout << repo.basic_info("ingredients")->get().object();
std::cout << repo.basic_info("recipes")->get().object();
std::cout << repo.basic_info("recipe_ingredients")->get().object();
}