observer progress, added to schema and added schema_observer class

This commit is contained in:
Sascha Kühl
2025-12-19 15:56:36 +01:00
parent 5e2d2ddde5
commit d104222fdd
16 changed files with 205 additions and 116 deletions
@@ -12,24 +12,32 @@
#include "matador/logger/log_manager.hpp"
#include <stack>
#include "repository.hpp"
#include <vector>
namespace matador::object {
template<typename NodeType, template<typename> typename... Observers>
class completer {
public:
template<typename Type>
void foo(Observers<NodeType>&&... observers) {
(std::unique_ptr<Observers<Type>>(new Observers(std::forward<Observers>(observers))), ...);
}
};
/**
* Processes the given node and ensures
* that all foreign nodes needed by the given node
* relations are attached in schema.
*/
template<typename NodeType>
template<typename NodeType, template<typename> typename ...Observers>
class foreign_node_completer final {
private:
using node_ptr = std::shared_ptr<repository_node>;
public:
static void complete(const std::shared_ptr<repository_node> &node) {
static void complete(const std::shared_ptr<repository_node> &node, Observers<NodeType>... observers) {
internal::shadow_repository shadow(node->repo_);
foreign_node_completer completer(shadow);
foreign_node_completer completer(shadow, observers...);
completer.complete_node(node);
}
@@ -60,18 +68,20 @@ public:
}
template<class CollectionType>
void on_has_many_to_many(const char *id,
CollectionType &collection,
const char *join_column,
const char *inverse_join_column,
const utils::foreign_attributes &attr);
static void on_has_many_to_many(const char * /*id*/,
CollectionType &/*collection*/,
const char * /*join_column*/,
const char * /*inverse_join_column*/,
const utils::foreign_attributes &/*attr*/) {}
template<class CollectionType>
void on_has_many_to_many(const char *id, CollectionType &collection, const utils::foreign_attributes &attr);
static void on_has_many_to_many(const char * /*id*/, CollectionType &/*collection*/, const utils::foreign_attributes &/*attr*/) {}
private:
explicit foreign_node_completer(internal::shadow_repository &shadow)
explicit foreign_node_completer(internal::shadow_repository &shadow, Observers<NodeType>... observers)
: repo_(shadow)
, log_(logger::create_logger("node_completer")) {}
, log_(logger::create_logger("node_completer")) {
// observers_.emplace_back(observers...);
}
void complete_node(const std::shared_ptr<repository_node> &node) {
nodes_.push(node);
@@ -160,7 +170,7 @@ private:
const endpoint_ptr &other_endpoint);
private:
template<typename Type>
template<typename Type, template<typename> typename ...OtherObservers>
friend class foreign_node_completer;
private:
@@ -168,69 +178,41 @@ private:
internal::shadow_repository &repo_;
logger::logger log_;
join_columns_collector join_columns_collector_{};
// const std::vector<Observers<NodeType>...> observers_;
};
template<typename NodeType>
template<typename NodeType, template<typename> typename ...Observers>
template<class ForeignPointerType>
void foreign_node_completer<NodeType>::on_belongs_to(const char * /*id*/, ForeignPointerType &, const utils::foreign_attributes &) {
void foreign_node_completer<NodeType, Observers...>::on_belongs_to(const char * /*id*/, ForeignPointerType &, const utils::foreign_attributes &) {
attach_node<typename ForeignPointerType::value_type>();
}
template<typename NodeType>
template<typename NodeType, template<typename> typename ...Observers>
template<class ForeignPointerType>
void foreign_node_completer<NodeType>::on_has_one(const char *, ForeignPointerType &, const utils::foreign_attributes &) {
void foreign_node_completer<NodeType, Observers...>::on_has_one(const char *, ForeignPointerType &, const utils::foreign_attributes &) {
attach_node<typename ForeignPointerType::value_type>();
}
template<typename NodeType>
template<typename NodeType, template<typename> typename ...Observers>
template<class CollectionType>
void foreign_node_completer<NodeType>::on_has_many(const char * /*id*/,
void foreign_node_completer<NodeType, Observers...>::on_has_many(const char * /*id*/,
CollectionType &, const char * /*join_column*/,
const utils::foreign_attributes & /*attr*/,
std::enable_if_t<is_object_ptr<typename CollectionType::value_type>::value> *) {
attach_node<typename CollectionType::value_type::value_type>();
}
template<typename NodeType>
template<class CollectionType>
void foreign_node_completer<NodeType>::on_has_many_to_many(const char * /*id*/,
CollectionType & /*collection*/,
const char * /*join_column*/,
const char * /*inverse_join_column*/,
const utils::foreign_attributes & /*attr*/) {
// if (!repo_.expecting_relation_node(id)) {
// repo_.expect_relation_node(id, typeid(typename CollectionType::value_type::value_type));
// } else {
// attach_relation_node<typename CollectionType::value_type::value_type>(id, join_column, inverse_join_column);
// repo_.remove_expected_relation_node(id);
// }
}
template<typename NodeType>
template<class CollectionType>
void foreign_node_completer<NodeType>::on_has_many_to_many(const char * /*id*/,
CollectionType & /*collection*/,
const utils::foreign_attributes & /*attr*/) {
// if (!repo_.expecting_relation_node(id)) {
// repo_.expect_relation_node(id, typeid(typename CollectionType::value_type::value_type));
// } else {
// const auto join_columns = join_columns_collector_.collect<typename CollectionType::value_type::value_type>();
// attach_relation_node<typename CollectionType::value_type::value_type>(id, join_columns.join_column, join_columns.inverse_join_column);
// repo_.remove_expected_relation_node(id);
// }
}
template<typename NodeType>
void foreign_node_completer<NodeType>::register_relation_endpoints(const endpoint_ptr &endpoint,
template<typename NodeType, template<typename> typename ...Observers>
void foreign_node_completer<NodeType, Observers...>::register_relation_endpoints(const endpoint_ptr &endpoint,
const endpoint_ptr &other_endpoint) {
endpoint->node_->info_->register_relation_endpoint(other_endpoint->node_->type_index(), endpoint);
other_endpoint->node_->info_->register_relation_endpoint(endpoint->node_->type_index(), other_endpoint);
link_relation_endpoints(endpoint, other_endpoint);
}
template<typename NodeType>
void foreign_node_completer<NodeType>::link_relation_endpoints(const endpoint_ptr &endpoint, const endpoint_ptr &other_endpoint) {
template<typename NodeType, template<typename> typename ...Observers>
void foreign_node_completer<NodeType, Observers...>::link_relation_endpoints(const endpoint_ptr &endpoint, const endpoint_ptr &other_endpoint) {
endpoint->link_foreign_endpoint(other_endpoint);
other_endpoint->link_foreign_endpoint(endpoint);
}
+1 -1
View File
@@ -43,7 +43,7 @@ public:
private:
template<typename Type>
friend class relation_completer;
template<typename Type>
template<typename Type, template<typename> typename ...Observers>
friend class foreign_node_completer;
std::string field_name_;
+1 -3
View File
@@ -67,8 +67,6 @@ public:
return utils::failure(result.err());
}
node->on_attach();
foreign_node_completer<Type>::complete(node);
relation_completer<Type>::complete(node);
} else if (!has_node(name)) {
@@ -200,7 +198,7 @@ private:
private:
friend class internal::shadow_repository;
friend class repository_node;
template < typename NodeType >
template < typename NodeType, template<typename> typename ...Observers >
friend class foreign_node_completer;
friend class object_generator;
+1 -1
View File
@@ -80,7 +80,7 @@ private:
friend class repository;
template<typename Type>
friend class relation_completer;
template < typename NodeType >
template < typename NodeType, template<typename> typename ...Observers >
friend class foreign_node_completer;
friend class const_repository_node_iterator;
+10 -9
View File
@@ -5,6 +5,7 @@
#include "matador/query/criteria.hpp"
#include "matador/query/query.hpp"
#include "matador/query/schema.hpp"
#include "matador/sql/executor.hpp"
#include "matador/sql/statement.hpp"
@@ -33,7 +34,7 @@ struct entity_query_data {
class criteria_transformer final : public query::criteria_visitor {
public:
criteria_transformer(const object::repository &repo, const std::unordered_map<std::string, std::shared_ptr<query::table>>& tables_by_name);
criteria_transformer(const query::schema &repo, const std::unordered_map<std::string, std::shared_ptr<query::table>>& tables_by_name);
void visit( const query::between_criteria& node ) override;
void visit( const query::binary_criteria& node ) override;
void visit( const query::binary_column_criteria& node ) override;
@@ -47,19 +48,19 @@ private:
void update_criteria_column(const query::abstract_column_criteria& node) const;
private:
const object::repository &repo_;
const query::schema &repo_;
const std::unordered_map<std::string, std::shared_ptr<query::table>>& tables_by_name_;
};
class session_query_builder final {
public:
session_query_builder(const object::repository &scm, sql::executor &exec)
session_query_builder(const query::schema &scm, sql::executor &exec)
: schema_(scm)
, executor_(exec){}
template<class EntityType>
utils::result<entity_query_data, query_build_error> build(query::criteria_ptr clause = {}) {
const auto info = schema_.info<EntityType>();
const auto info = schema_.repo().info<EntityType>();
if (!info) {
return utils::failure(query_build_error::UnknownType);
}
@@ -114,7 +115,7 @@ public:
template<class ContainerType>
void on_has_many(const char * /*id*/, ContainerType &, const char *join_column, const utils::foreign_attributes &attr) {
if (attr.fetch() == utils::fetch_type::Eager) {
const auto result = schema_.basic_info(typeid(typename ContainerType::value_type::value_type));
const auto result = schema_.repo().basic_info(typeid(typename ContainerType::value_type::value_type));
if (!result) {
throw query_builder_exception{query_build_error::UnknownType};
}
@@ -146,7 +147,7 @@ public:
if (attr.fetch() != utils::fetch_type::Eager) {
return;
}
const auto result = schema_.basic_info(typeid(typename ContainerType::value_type::value_type));
const auto result = schema_.repo().basic_info(typeid(typename ContainerType::value_type::value_type));
if (!result) {
throw query_builder_exception{query_build_error::UnknownType};
}
@@ -186,7 +187,7 @@ public:
if (attr.fetch() != utils::fetch_type::Eager) {
return;
}
const auto result = schema_.basic_info(typeid(typename ContainerType::value_type::value_type));
const auto result = schema_.repo().basic_info(typeid(typename ContainerType::value_type::value_type));
if (!result) {
throw query_builder_exception{query_build_error::UnknownType};
}
@@ -239,7 +240,7 @@ private:
std::stack<table_info> table_info_stack_{};
std::unordered_map<std::string, std::shared_ptr<query::table>> processed_tables_{};
const object::repository &schema_;
const query::schema &schema_;
entity_query_data entity_query_data_{};
unsigned int column_index{0};
unsigned int table_index{0};
@@ -249,7 +250,7 @@ private:
template<class Pointer>
void session_query_builder::on_foreign_object(const char *id, Pointer &, const utils::foreign_attributes &attr) {
const auto info = schema_.info<typename Pointer::value_type>();
const auto info = schema_.repo().info<typename Pointer::value_type>();
if (!info) {
throw query_builder_exception{query_build_error::UnknownType};
}
+8 -3
View File
@@ -16,10 +16,13 @@ class table;
// ReSharper disable CppNonExplicitConvertingConstructor
class column {
public:
column(const char *name, const std::string& as = ""); // NOLINT(*-explicit-constructor)
column(std::string name, std::string as = ""); // NOLINT(*-explicit-constructor)
column(const char *name); // NOLINT(*-explicit-constructor)
column(std::string name); // NOLINT(*-explicit-constructor)
column(std::string name, std::string alias);
column(sql::sql_function_t func, std::string name);
column(const class table* tab, std::string name, std::string as = "");
column(const class table* tab, std::string name);
column(const class table* tab, std::string name, std::string alias);
column(const class table* tab, std::string name, utils::basic_type type, const utils::field_attributes& attributes);
[[nodiscard]] bool equals(const column &x) const;
@@ -45,6 +48,8 @@ private:
static query::table* default_table();
private:
friend class table;
const query::table* table_{nullptr};
std::string name_;
std::string alias_;
+9 -10
View File
@@ -6,12 +6,11 @@
#include <matador/utils/field_attributes.hpp>
#include <matador/utils/foreign_attributes.hpp>
#include "matador/object/repository.hpp"
#include "matador/query/fk_value_extractor.hpp"
#include "matador/query/internal/column_value_pair.hpp"
#include "matador/query/table.hpp"
#include "matador/query/schema.hpp"
#include <vector>
@@ -48,7 +47,7 @@ class column_generator {
public:
explicit column_generator(const std::string &table_name = "",
column_generator_options options = default_column_generator_options);
explicit column_generator(const object::repository &repo,
explicit column_generator(const schema &repo,
const std::string &table_name = "",
column_generator_options options = default_column_generator_options);
@@ -94,7 +93,7 @@ public:
if (!repo_) {
return;
}
const auto info = repo_->get().info<typename ContainerType::value_type::value_type>();
const auto info = repo_->get().repo().info<typename ContainerType::value_type::value_type>();
if (!info) {
return;
}
@@ -130,7 +129,7 @@ private:
if (!repo_) {
return;
}
const auto info = repo_->get().info<typename Pointer::value_type>();
const auto info = repo_->get().repo().info<typename Pointer::value_type>();
if (!info) {
return;
}
@@ -148,7 +147,7 @@ private:
void push(const std::string &column_name);
private:
std::optional<std::reference_wrapper<const object::repository>> repo_;
std::optional<std::reference_wrapper<const schema>> repo_;
std::vector<column> result_;
std::stack<std::shared_ptr<table>> table_stack_;
std::unordered_set<std::string> seen_tables;
@@ -296,7 +295,7 @@ std::vector<internal::column_value_pair> column_value_pairs() {
}
template<typename Type>
std::vector<column> columns(const object::repository &repo,
std::vector<column> columns(const schema &repo,
const std::string &table_name = "",
const column_generator_options options = default_column_generator_options) {
column_generator generator(repo, table_name, options);
@@ -304,10 +303,10 @@ std::vector<column> columns(const object::repository &repo,
}
template<typename Type>
std::vector<column> columns(const object::repository &repo,
std::vector<column> columns(const schema &repo,
const column_generator_options options) {
std::string table_name;
if (const auto result = repo.info<Type>()) {
if (const auto result = repo.repo().info<Type>()) {
table_name = result.value().get().name();
}
column_generator generator(repo, table_name, options);
@@ -316,7 +315,7 @@ std::vector<column> columns(const object::repository &repo,
template<typename Type>
std::vector<column> columns(const Type &obj,
const object::repository &repo,
const schema &repo,
const std::string &table_name = "",
const column_generator_options options = default_column_generator_options) {
column_generator generator(repo, table_name, options);
+51 -11
View File
@@ -1,6 +1,7 @@
#ifndef MATADOR_SCHEMA_HPP
#define MATADOR_SCHEMA_HPP
#include "matador/object/observer.hpp"
#include "matador/object/repository.hpp"
#include "matador/sql/query_context.hpp"
@@ -28,19 +29,39 @@ private:
std::unordered_map<std::string, schema> schema_map_;
};
template<typename Type>
class schema_observer final : public object::observer<Type> {
public:
explicit schema_observer(schema& s)
: schema_(s) {}
void on_attach(object::repository_node &node, const Type &prototype) override;
void on_detach(object::repository_node &node, const Type &prototype) override;
void on_insert(Type &obj) override;
void on_update(Type &obj) override;
void on_delete(Type &obj) override;
private:
schema& schema_;
};
class schema final {
public:
explicit schema(sql::connection_pool &pool);
schema(sql::connection_pool &pool, const std::string &name);
template<typename Type, template <typename> class ObserverType>
[[nodiscard]] utils::result<void, utils::error> attach(const std::string &name, const std::string &parent = "", std::initializer_list<ObserverType<Type>*> observer = {}) {
return repo_.attach<Type>(name, parent, observer);
template<typename Type, typename... Observers>
[[nodiscard]] utils::result<void, utils::error> attach(const std::string &name, Observers&&... observers) {
return repo_.attach<Type>(name, schema_observer<Type>{*this}, std::forward<Observers>(observers)...);
}
template<typename Type, typename SuperType, template <typename> class ObserverType>
[[nodiscard]] utils::result<void, utils::error> attach(const std::string &name, std::initializer_list<ObserverType<Type>*> observer = {}) {
return repo_.attach<Type, SuperType>(name, observer);
template<typename Type, typename... Observers>
[[nodiscard]] utils::result<void, utils::error> attach(const std::string &name, const std::string &parent, Observers&&... observers) {
return repo_.attach<Type>(name, parent, schema_observer<Type>{*this}, std::forward<Observers>(observers)...);
}
template<typename Type, typename SuperType, typename... Observers>
[[nodiscard]] utils::result<void, utils::error> attach(const std::string &name, Observers&&... observers) {
return repo_.attach<Type, SuperType>(name, schema_observer<Type>{*this}, std::forward<Observers>(observers)...);
}
[[nodiscard]] utils::result<void, utils::error> create() const;
@@ -53,13 +74,20 @@ public:
[[nodiscard]] utils::result<std::vector<object::attribute>, utils::error> describe_table(const std::string &table_name) const;
[[nodiscard]] utils::result<bool, utils::error> table_exists(const std::string &table_name) const;
private:
[[nodiscard]] sql::query_context build_add_constraint_context( const object::repository_node& node, const object::restriction& cons ) const;
[[nodiscard]] sql::query_context build_drop_constraint_context( const object::repository_node& node, const object::restriction& cons ) const;
const object::repository &repo() const { return repo_; }
private:
[[nodiscard]] sql::query_context build_add_constraint_context( const object::repository_node& node, const object::restriction& cons ) const;
[[nodiscard]] sql::query_context build_drop_constraint_context( const object::repository_node& node, const object::restriction& cons ) const;
void insert_table(const std::type_index& ti, const object::repository_node &node);
private:
template<typename Type>
friend class schema_observer;
object::repository repo_;
std::unordered_map<std::type_index, table> table_map_;
std::unordered_map<std::type_index, table> tables_;
sql::connection_pool &pool_;
};
@@ -72,6 +100,18 @@ utils::result<void, utils::error> schema::drop_table() {
return utils::failure(info.err());
}
template <typename Type>
void schema_observer<Type>::on_attach(object::repository_node &node, const Type &prototype) {
schema_.insert_table(typeid(Type), node);
}
template <typename Type>
void schema_observer<Type>::on_detach(object::repository_node &node, const Type &prototype) {}
template <typename Type>
void schema_observer<Type>::on_insert(Type &obj) {}
template <typename Type>
void schema_observer<Type>::on_update(Type &obj) {}
template <typename Type>
void schema_observer<Type>::on_delete(Type &obj) {}
} // namespace matador::query
#endif //MATADOR_SCHEMA_HPP