schema progress (does not compile)

This commit is contained in:
2025-12-31 11:56:12 +01:00
parent d104222fdd
commit ab2d39407c
65 changed files with 1355 additions and 922 deletions
@@ -2,6 +2,7 @@
#define FOREIGN_NODE_COMPLETER_HPP
#include "matador/object/internal/shadow_repository.hpp"
#include "matador/object/internal/observer_list_copy_creator.hpp"
#include "matador/object/many_to_many_relation.hpp"
#include "matador/object/repository_node.hpp"
#include "matador/object/join_columns_collector.hpp"
@@ -35,9 +36,9 @@ private:
using node_ptr = std::shared_ptr<repository_node>;
public:
static void complete(const std::shared_ptr<repository_node> &node, Observers<NodeType>... observers) {
static void complete(const std::shared_ptr<repository_node> &node, const std::vector<std::unique_ptr<observer<NodeType>>> &observers) {
internal::shadow_repository shadow(node->repo_);
foreign_node_completer completer(shadow, observers...);
foreign_node_completer completer(shadow, observers);
completer.complete_node(node);
}
@@ -77,11 +78,10 @@ public:
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, Observers<NodeType>... observers)
explicit foreign_node_completer(internal::shadow_repository &shadow, const std::vector<std::unique_ptr<observer<NodeType>>> &observers)
: repo_(shadow)
, log_(logger::create_logger("node_completer")) {
// observers_.emplace_back(observers...);
}
, log_(logger::create_logger("node_completer"))
, observers_(observers) {}
void complete_node(const std::shared_ptr<repository_node> &node) {
nodes_.push(node);
@@ -91,75 +91,22 @@ private:
nodes_.pop();
}
template<typename Type>
void attach_node(const std::string &name) {
if (repo_.contains(typeid(Type))) {
return;
}
const auto node = repository_node::make_node<Type>(repo_.repo(), name);
if (auto result = repo_.attach_node(node)) {
foreign_node_completer<Type>::complete(result.value());
}
}
template<typename Type>
void attach_node() {
if (repo_.contains(typeid(Type))) {
return;
}
const auto node = repository_node::make_node<Type>(repo_.repo(), "", []{ return std::make_unique<Type>(); });
if (auto result = repo_.attach_node(node)) {
foreign_node_completer<Type>::complete(result.value());
}
}
auto observers = internal::observer_list_copy_creator<NodeType, Type, Observers...>::copy_create(observers_);
template<typename Type>
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 value_type = Type;
// Check if the object_ptr type is already inserted in the schema (by id)
auto result = repo_.find_node(typeid(value_type));
if (!result) {
// Todo: throw internal error or attach node
if (repo_.is_node_announced(typeid(Type))) {
return;
}
const auto foreign_node = result.value();
result = repo_.find_node(name);
if (result) {
return;
}
// Relation does not exist. Create it.
auto creator = [join_column, inverse_join_column] {
return std::make_unique<relation_value_type>(join_column, inverse_join_column);
};
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;
}
foreign_node_completer<relation_value_type>::complete(result.value());
// auto& node = result.value();
const auto local_endpoint = std::make_shared<relation_endpoint>(name, 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);
const auto foreign_endpoint = std::make_shared<relation_endpoint>(name, relation_type::HasMany, node);
// register relation endpoint in local node
nodes_.top()->info_->register_relation_endpoint(typeid(value_type), local_endpoint);
// register relation endpoint in foreign node
foreign_node->info_->register_relation_endpoint(nodes_.top()->type_index(), foreign_endpoint);
// register endpoints in relation node
node->info_->register_relation_endpoint(nodes_.top()->type_index(), join_endpoint);
node->info_->register_relation_endpoint(typeid(value_type), inverse_join_endpoint);
// link endpoints
link_relation_endpoints(local_endpoint, join_endpoint);
link_relation_endpoints(foreign_endpoint, inverse_join_endpoint);
const auto node = repository_node::make_node<Type>(repo_.repo(), "", []{ return std::make_unique<Type>(); }, std::move(observers));
repo_.push_announce_node(typeid(Type), node);
// if (auto result = repo_.attach_node(node)) {
// foreign_node_completer<Type>::complete(result.value(), {});
// }
}
private:
@@ -178,7 +125,7 @@ private:
internal::shadow_repository &repo_;
logger::logger log_;
join_columns_collector join_columns_collector_{};
// const std::vector<Observers<NodeType>...> observers_;
const std::vector<std::unique_ptr<observer<NodeType>>>& observers_;
};
@@ -190,7 +137,7 @@ void foreign_node_completer<NodeType, Observers...>::on_belongs_to(const char *
template<typename NodeType, template<typename> typename ...Observers>
template<class ForeignPointerType>
void foreign_node_completer<NodeType, Observers...>::on_has_one(const char *, ForeignPointerType &, const utils::foreign_attributes &) {
void foreign_node_completer<NodeType, Observers...>::on_has_one(const char * /*id*/, ForeignPointerType &, const utils::foreign_attributes &) {
attach_node<typename ForeignPointerType::value_type>();
}
@@ -0,0 +1,57 @@
#ifndef MATADOR_OBSERVER_LIST_COPY_CREATOR_HPP
#define MATADOR_OBSERVER_LIST_COPY_CREATOR_HPP
#include "matador/object/observer.hpp"
#include <memory>
#include <vector>
namespace matador::object::internal {
template <typename SourceType, typename DestType, template <typename> class... ObserverType>
class observer_list_copy_creator
{
public:
using source_observer_vector = std::vector<std::unique_ptr<observer<SourceType>>>;
using observer_vector = std::vector<std::unique_ptr<observer<DestType>>>;
using iterator = typename observer_vector::iterator;
static observer_vector copy_create(const source_observer_vector &source_observers) {
observer_list_copy_creator creator(source_observers);
return std::move(creator.observers_);
}
private:
explicit observer_list_copy_creator(const source_observer_vector &source_observers)
: source_observers_(source_observers) {
if constexpr (sizeof...(ObserverType) != 0) {
copy_observer<ObserverType...>();
}
}
template <template <typename> class FirstObserverType>
void copy_observer() {
try_copy_observer<FirstObserverType>();
}
template <template <typename> class FirstObserverType, template <typename> class NextObserverType, template <typename> class... RestObserverType>
void copy_observer() {
try_copy_observer<FirstObserverType>();
copy_observer<NextObserverType, RestObserverType...>();
}
template <template <typename> class CurrentObserverType>
void try_copy_observer() {
for ( const auto &obs : source_observers_ ) {;
if (const auto *casted_observer = dynamic_cast<const CurrentObserverType<SourceType>*>(obs.get()); casted_observer != nullptr) {
observers_.emplace_back(std::make_unique<CurrentObserverType<DestType>>(*casted_observer));
break;
}
}
}
private:
const source_observer_vector &source_observers_;
observer_vector observers_;
};
}
#endif //MATADOR_OBSERVER_LIST_COPY_CREATOR_HPP
@@ -0,0 +1,69 @@
#ifndef MATADOR_OBSERVER_LIST_CREATOR_HPP
#define MATADOR_OBSERVER_LIST_CREATOR_HPP
#include "matador/object/observer.hpp"
#include <memory>
#include <vector>
namespace matador::object::internal {
template <typename Type, template <typename> class... ObserverType>
class observer_list_creator
{
public:
using observer_vector = std::vector<std::unique_ptr<observer<Type>>>;
static void create_missing(observer_vector &observers) {
observer_list_creator creator(observers);
}
private:
explicit observer_list_creator(observer_vector &observers)
: observers_(observers) {
if constexpr (sizeof...(ObserverType) != 0) {
build_observer<ObserverType...>();
}
}
template <template <typename> class FirstObserverType>
void build_observer() {
try_copy_on_missing<FirstObserverType>();
}
template <template <typename> class FirstObserverType, template <typename> class NextObserverType, template <typename> class... RestObserverType>
void build_observer() {
try_copy_on_missing<FirstObserverType>();
build_observer<NextObserverType, RestObserverType...>();
}
template <template <typename> class CurrentObserverType>
void try_copy_on_missing() {
bool is_missing{true};
for ( const auto &obs : observers_ ) {;
if (dynamic_cast<const CurrentObserverType<Type>*>(obs.get())) {
is_missing = false;
break;
}
}
if (is_missing) {
append<CurrentObserverType<Type>>();
}
}
template <class CurrentObserverType>
void append(std::enable_if_t<std::is_default_constructible_v<CurrentObserverType> || std::is_trivially_default_constructible_v<CurrentObserverType>>* = nullptr) {
observers_.emplace_back(std::make_unique<CurrentObserverType>());
}
template <class CurrentObserverType>
void append(std::enable_if_t<!std::is_default_constructible_v<CurrentObserverType> && !std::is_trivially_default_constructible_v<CurrentObserverType>>* = nullptr) {
static_assert("no default constructor");
}
private:
observer_vector &observers_;
};
}
#endif //MATADOR_OBSERVER_LIST_CREATOR_HPP
@@ -40,6 +40,11 @@ public:
[[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;
[[nodiscard]] bool is_node_announced(const std::type_index &ti) const;
void push_announce_node(const std::type_index &ti, const node_ptr &node) const;
[[nodiscard]] node_ptr announce_node(const std::type_index &ti) const;
[[nodiscard]] node_ptr pop_announce_node(const std::type_index &ti) const;
private:
repository& repo_;
};
+6 -6
View File
@@ -51,17 +51,17 @@ private:
class object_generator {
private:
explicit object_generator(repository& repo, const std::shared_ptr<object> &object);
explicit object_generator(const repository& repo, const std::shared_ptr<object> &object);
public:
template < class Type >
static std::shared_ptr<object> generate(repository &repo, const std::string &name) {
static std::shared_ptr<object> generate(const repository &repo, const std::string &name) {
return generate(std::make_unique<Type>(), repo, name);
}
template < class Type >
static std::shared_ptr<object> generate(std::unique_ptr<Type>&& t, repository &repo, const std::string &name) {
const internal::shadow_repository shadow_repo(repo);
static std::shared_ptr<object> generate(std::unique_ptr<Type>&& t, const repository &repo, const std::string &name) {
const internal::shadow_repository shadow_repo(const_cast<repository&>(repo));
const std::type_index ti(typeid(Type));
if (shadow_repo.has_object_for_type(ti)) {
auto obj = shadow_repo.object_for_type(ti);
@@ -129,7 +129,7 @@ private:
static std::shared_ptr<object> acquire_object(repository &repo, const std::type_index &ti, const std::string& name);
private:
repository &repo_;
const repository &repo_;
std::shared_ptr<object> object_;
};
@@ -167,7 +167,7 @@ void object_generator::create_fk_constraint(const std::string& name) const {
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_);
const internal::shadow_repository shadow_repo(const_cast<repository &>(repo_));
if (const auto result = shadow_repo.basic_info(ti)) {
return result->get().object();
}
+25 -19
View File
@@ -9,21 +9,21 @@
namespace matador::object {
class repository_node;
template<typename Type>
class observer_ptr {
public:
explicit observer_ptr(std::unique_ptr<observer<Type>> &&observer)
: observer(std::move(observer)) {}
operator bool() const { return observer != nullptr; }
observer<Type> *get() const { return observer.get(); }
observer<Type> &operator*() const { return *observer; }
observer<Type> *operator->() const { return observer.get(); }
private:
std::unique_ptr<observer<Type>> observer;
};
// template<typename Type>
// class observer_ptr {
// public:
// explicit observer_ptr(std::unique_ptr<observer<Type>> &&o)
// : observer_(std::move(o)) {}
//
// operator bool() const { return observer_ != nullptr; }
//
// observer<Type> *get() const { return observer_.get(); }
// observer<Type> &operator*() const { return *observer_; }
// observer<Type> *operator->() const { return observer_.get(); }
//
// private:
// std::unique_ptr<observer<Type>> observer_;
// };
template<typename Type>
class object_info final : public basic_object_info {
public:
@@ -31,10 +31,11 @@ public:
object_info(const std::shared_ptr<repository_node>& node,
std::shared_ptr<class object> &&obj,
std::vector<std::unique_ptr<observer<Type>>>&& observers,
create_func&& creator)
: basic_object_info(node, std::move(obj))
, creator_(std::move(creator)){
}
, creator_(std::move(creator))
, observers_(std::move(observers)){}
explicit object_info(const std::shared_ptr<repository_node>& node)
: basic_object_info(node, {}) {
@@ -55,13 +56,18 @@ public:
}
}
void register_observer(observer_ptr<Type> observer) {
void register_observer(std::unique_ptr<observer<Type>>&& observer) {
observers_.push_back(std::move(observer));
}
const std::vector<std::unique_ptr<observer<Type>>>& observers() const {
return observers_;
}
private:
Type prototype_;
create_func creator_{[]{ return std::make_unique<Type>(); }};
std::vector<observer_ptr<Type>> observers_;
std::vector<std::unique_ptr<observer<Type>>> observers_;
};
template<typename Type>
+5 -5
View File
@@ -63,7 +63,7 @@ public:
* @param node The attached repository_node
* @param prototype The prototype object of the attached node
*/
virtual void on_attach(repository_node &node, const Type &prototype) = 0;
virtual void on_attach(const repository_node &node, const Type &prototype) const = 0;
/**
* @brief Called on repository_node detached
@@ -74,7 +74,7 @@ public:
* @param node The to be detached repository_node
* @param prototype The prototype object of the detached node
*/
virtual void on_detach(repository_node &node, const Type &prototype) = 0;
virtual void on_detach(const repository_node &node, const Type &prototype) const = 0;
/**
* @brief Called on object insertion.
@@ -84,7 +84,7 @@ public:
*
* @param obj The proxy of the inserted object.
*/
virtual void on_insert(Type &obj) = 0;
virtual void on_insert(const Type &obj) = 0;
/**
* @brief Called on object update.
@@ -94,7 +94,7 @@ public:
*
* @param obj The proxy of the updated object.
*/
virtual void on_update(Type &obj) = 0;
virtual void on_update(const Type &obj) = 0;
/**
* @brief Called on object deletion.
@@ -104,7 +104,7 @@ public:
*
* @param obj The proxy of the deleted object.
*/
virtual void on_delete(Type &obj) = 0;
virtual void on_delete(const Type &obj) = 0;
};
namespace internal {
+62 -49
View File
@@ -92,7 +92,7 @@ private:
* no has_many or belongs_to
* invalid relation -> error
*/
template<typename Type>
template<typename Type, template<typename> typename... Observers>
class relation_completer final {
private:
using node_ptr = std::shared_ptr<repository_node>;
@@ -100,9 +100,9 @@ private:
public:
using endpoint_ptr = std::shared_ptr<relation_endpoint>;
static void complete(const std::shared_ptr<repository_node> &node) {
static void complete(const std::shared_ptr<repository_node> &node, const std::vector<std::unique_ptr<observer<Type>>> &observers) {
internal::shadow_repository shadow(node->repo_);
relation_completer completer(shadow);
relation_completer completer(shadow, observers);
completer.complete_node_relations(node);
}
@@ -131,10 +131,10 @@ public:
void on_has_many_to_many(const char *id, CollectionType &collection, const utils::foreign_attributes &attr);
private:
explicit relation_completer(internal::shadow_repository &shadow)
: schema_(shadow)
, log_(logger::create_logger("relation_completer")) {
}
explicit relation_completer(internal::shadow_repository &shadow, const std::vector<std::unique_ptr<observer<Type>>>& observers)
: schema_(shadow)
, log_(logger::create_logger("relation_completer"))
, observers_(observers) {}
void complete_node_relations(const std::shared_ptr<repository_node> &node) {
nodes_.push(node);
@@ -152,16 +152,19 @@ private:
static void link_relation_endpoints(const endpoint_ptr &endpoint,
const endpoint_ptr &other_endpoint);
node_ptr find_node(const std::type_index &ti) const;
private:
std::stack<node_ptr> nodes_;
internal::shadow_repository &schema_;
logger::logger log_;
join_columns_collector join_columns_collector_{};
const std::vector<std::unique_ptr<observer<Type>>>& observers_;
};
template<typename Type>
template<typename Type, template<typename> typename... Observers>
template<class CollectionType>
void relation_completer<Type>::on_has_many(const char *id, CollectionType &,
void relation_completer<Type, Observers...>::on_has_many(const char *id, CollectionType &,
const char *join_column,
const utils::foreign_attributes &,
std::enable_if_t<is_object_ptr<typename CollectionType::value_type>::value> * /*unused*/) {
@@ -170,12 +173,11 @@ void relation_completer<Type>::on_has_many(const char *id, CollectionType &,
using relation_value_type = many_to_many_relation<Type, value_type>;
// Check if the object_ptr type is already inserted in the schema (by id)
auto result = schema_.find_node(typeid(value_type));
if (!result) {
auto foreign_node = find_node(typeid(value_type));
if (!foreign_node) {
// Todo: throw internal error or attach node
return;
}
const auto foreign_node = result.value();
// has foreign node corresponding join column (join_column)
if (const auto it = foreign_node->info_->find_relation_endpoint(typeid(Type)); it != foreign_node->info().endpoint_end()) {
@@ -198,8 +200,8 @@ void relation_completer<Type>::on_has_many(const char *id, CollectionType &,
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);
}, {});
const auto result = schema_.attach_node(node);
if (!result) {
// Todo: throw internal error
return;
@@ -215,9 +217,9 @@ void relation_completer<Type>::on_has_many(const char *id, CollectionType &,
}
}
template<typename Type>
template<typename Type, template<typename> typename... Observers>
template<class CollectionType>
void relation_completer<Type>::on_has_many(const char *id, CollectionType &, const char *join_column,
void relation_completer<Type, Observers...>::on_has_many(const char *id, CollectionType &, const char *join_column,
const utils::foreign_attributes &,
std::enable_if_t<!is_object_ptr<typename CollectionType::value_type>::value>
* /*unused*/) {
@@ -226,7 +228,7 @@ void relation_completer<Type>::on_has_many(const char *id, CollectionType &, con
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
@@ -241,9 +243,9 @@ void relation_completer<Type>::on_has_many(const char *id, CollectionType &, con
link_relation_endpoints(local_endpoint, foreign_endpoint);
}
template<typename Type>
template<typename Type, template<typename> typename... Observers>
template<class CollectionType>
void relation_completer<Type>::on_has_many_to_many(const char *id,
void relation_completer<Type, Observers...>::on_has_many_to_many(const char *id,
CollectionType &/*collection*/,
const char *join_column,
const char *inverse_join_column,
@@ -256,9 +258,9 @@ void relation_completer<Type>::on_has_many_to_many(const char *id,
}
}
template<typename Type>
template<typename Type, template<typename> typename... Observers>
template<class CollectionType>
void relation_completer<Type>::on_has_many_to_many(const char *id,
void relation_completer<Type, Observers...>::on_has_many_to_many(const char *id,
CollectionType &collection,
const utils::foreign_attributes &attr) {
const auto join_columns = join_columns_collector_.collect<typename CollectionType::value_type::value_type>();
@@ -270,46 +272,43 @@ void relation_completer<Type>::on_has_many_to_many(const char *id,
attr);
}
template<typename Type>
template<typename Type, template<typename> typename... Observers>
template<class ForeignPointerType>
void relation_completer<Type>::on_has_one(const char *id,
void relation_completer<Type, Observers...>::on_has_one(const char *id,
ForeignPointerType &/*obj*/,
const utils::foreign_attributes &/*attr*/) {
using value_type = typename ForeignPointerType::value_type;
const auto ti = std::type_index(typeid(value_type));
const auto result = schema_.find_node(ti);
if (!result) {
// Node was not found
// Todo: Throw internal error
auto foreign_node = find_node(typeid(value_type));
if (!foreign_node) {
// Todo: throw internal error or attach node
return;
}
auto local_it = nodes_.top()->info().find_relation_endpoint(typeid(value_type));
if (local_it == nodes_.top()->info().endpoint_end()) {
const auto local_endpoint = std::make_shared<relation_endpoint>(id, relation_type::HasOne, result.value());
const auto local_endpoint = std::make_shared<relation_endpoint>(id, relation_type::HasOne, foreign_node);
local_it = nodes_.top()->info_->register_relation_endpoint(typeid(value_type), local_endpoint);
}
if (const auto foreign_it = result.value()->info().find_relation_endpoint(typeid(Type)); foreign_it != result.value()->info().endpoint_end()) {
if (const auto foreign_it = foreign_node->info().find_relation_endpoint(typeid(Type)); foreign_it != foreign_node->info().endpoint_end()) {
link_relation_endpoints(local_it->second, foreign_it->second);
}
}
template<typename Type>
template<typename Type, template<typename> typename... Observers>
template<class ForeignPointerType>
void relation_completer<Type>::on_belongs_to(const char *id,
void relation_completer<Type, Observers...>::on_belongs_to(const char *id,
ForeignPointerType & /*obj*/,
const utils::foreign_attributes & /*attr*/) {
using value_type = typename ForeignPointerType::value_type;
const auto ti = std::type_index(typeid(value_type));
auto result = schema_.find_node(ti);
if (!result) {
// Type was not found
// Todo: Throw internal error
auto foreign_node = find_node(typeid(value_type));
if (!foreign_node) {
// Todo: throw internal error or attach node
return;
}
// Type was found
const auto &foreign_node = result.value();
// Check foreign node and relation endpoint
if (const auto it = foreign_node->info_->find_relation_endpoint(nodes_.top()->type_index()); it != foreign_node->info().endpoint_end()) {
// Found corresponding relation endpoint in the foreign node
@@ -341,21 +340,20 @@ void relation_completer<Type>::on_belongs_to(const char *id,
}
}
template<typename Type>
template<typename Type, template<typename> typename... Observers>
template<typename NodeType>
void relation_completer<Type>::attach_relation_node(const std::string &name, const std::string &join_column, const std::string &inverse_join_column) {
void relation_completer<Type, Observers...>::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<NodeType, Type>;
using value_type = NodeType;
// Check if the object_ptr type is already inserted in the schema (by id)
auto result = schema_.find_node(typeid(value_type));
if (!result) {
auto foreign_node = find_node(typeid(value_type));
if (!foreign_node) {
// Todo: throw internal error or attach node
return;
}
const auto foreign_node = result.value();
result = schema_.find_node(name);
auto result = schema_.find_node(name);
if (result) {
return;
}
@@ -364,14 +362,16 @@ void relation_completer<Type>::attach_relation_node(const std::string &name, con
return std::make_unique<relation_value_type>(join_column, inverse_join_column);
};
auto node = repository_node::make_node<relation_value_type>(schema_.repo(), name, std::move(creator));
auto observers = internal::observer_list_copy_creator<Type, relation_value_type, Observers...>::copy_create(observers_);
auto node = repository_node::make_node<relation_value_type>(schema_.repo(), name, std::move(creator), std::move(observers));
result = schema_.attach_node(node);
if (!result) {
// Todo: throw internal error
return;
}
foreign_node_completer<relation_value_type>::complete(result.value());
foreign_node_completer<relation_value_type>::complete(result.value(), {});
const auto local_endpoint = std::make_shared<relation_endpoint>(name, relation_type::HasMany, node);
const auto join_endpoint = std::make_shared<relation_endpoint>(join_column, relation_type::BelongsTo, nodes_.top());
@@ -389,18 +389,31 @@ void relation_completer<Type>::attach_relation_node(const std::string &name, con
link_relation_endpoints(foreign_endpoint, inverse_join_endpoint);
}
template<typename Type>
void relation_completer<Type>::register_relation_endpoints(const endpoint_ptr &endpoint,
template<typename Type, template<typename> typename... Observers>
void relation_completer<Type, 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 Type>
void relation_completer<Type>::link_relation_endpoints(const endpoint_ptr &endpoint, const endpoint_ptr &other_endpoint) {
template<typename Type, template<typename> typename... Observers>
void relation_completer<Type, 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);
}
template<typename Type, template <typename> class ... Observers>
typename relation_completer<Type, Observers...>::node_ptr relation_completer<Type, Observers...>::find_node(const std::type_index &ti) const {
node_ptr foreign_node;
if (auto result = schema_.find_node(ti); result) {
return result.value();
}
if (!schema_.is_node_announced(ti)) {
return {};
}
return schema_.announce_node(ti);
}
}
#endif //RELATION_COMPLETER_HPP
+1 -1
View File
@@ -41,7 +41,7 @@ public:
void link_foreign_endpoint(const std::shared_ptr<relation_endpoint>& endpoint);
private:
template<typename Type>
template<typename Type, template<typename> typename... Observers>
friend class relation_completer;
template<typename Type, template<typename> typename ...Observers>
friend class foreign_node_completer;
+33 -15
View File
@@ -38,44 +38,55 @@ public:
*/
explicit repository(std::string name = "");
template<typename Type, typename... Observers>
[[nodiscard]] utils::result<void, utils::error> attach(const std::string &name, Observers&&... observers) {
return attach_type<Type, Observers...>(name, std::string{}, std::forward<Observers>(observers)...);
template<typename Type, template<typename> typename... Observers>
[[nodiscard]] utils::result<void, utils::error> attach(const std::string &name, Observers<Type>&&... observers) {
return attach_type<Type, Observers...>(name, std::string{}, std::forward<Observers<Type>>(observers)...);
}
template<typename Type, typename SuperType, typename... Observers>
[[nodiscard]] utils::result<void, utils::error> attach(const std::string &name, Observers&&... observers) {
template<typename Type, typename SuperType, template<typename> typename... Observers>
[[nodiscard]] utils::result<void, utils::error> attach(const std::string &name, Observers<Type>&&... observers) {
const auto ti = std::type_index(typeid(SuperType));
auto result = find_node(ti);
if (!result) {
return utils::failure(make_error(error_code::NodeNotFound, "Parent node '" + std::string(ti.name()) + "' not found"));
}
return attach_type<Type, Observers...>(name, (*result)->name(), std::forward<Observers>(observers)...);
return attach_type<Type, Observers...>(name, (*result)->name(), std::forward<Observers<Type>>(observers)...);
}
template<typename Type, typename... Observers>
[[nodiscard]] utils::result<void, utils::error> attach(const std::string &name, const std::string &parent, Observers&&... observers) {
return attach_type<Type, Observers...>(name, parent, std::forward<Observers>(observers)...);
template<typename Type, template<typename> typename... Observers>
[[nodiscard]] utils::result<void, utils::error> attach(const std::string &name, const std::string &parent, Observers<Type>&&... observers) {
return attach_type<Type, Observers...>(name, parent, std::forward<Observers<Type>>(observers)...);
}
template<typename Type, typename... Observers>
[[nodiscard]] utils::result<void, utils::error> attach_type(const std::string &name, const std::string &parent, Observers&&... observers) {
template<typename Type, template<typename> typename... Observers>
[[nodiscard]] utils::result<void, utils::error> attach_type(const std::string &name, const std::string &parent, Observers<Type>&&... observers) {
if (const auto it = nodes_by_type_.find(typeid(Type)); it == nodes_by_type_.end() ) {
std::vector<std::unique_ptr<observer<Type>>> obs;
obs.reserve(sizeof...(Observers));
(obs.push_back(std::unique_ptr<observer<Type>>(new Observers<Type>(std::forward<Observers<Type>>(observers)))), ...);
// if the type was not found
auto node = repository_node::make_node<Type>(*this, name, []{ return std::make_unique<Type>(); }, std::forward<Observers>(observers)...);
std::shared_ptr<repository_node> node;
if (is_node_announced(typeid(Type))) {
node = pop_announce_node(typeid(Type));
node->update_name(name);
} else {
node = repository_node::make_node<Type>(*this, name, []{ return std::make_unique<Type>(); }, std::move(obs));
}
if (auto result = attach_node(node, parent); !result) {
return utils::failure(result.err());
}
foreign_node_completer<Type>::complete(node);
relation_completer<Type>::complete(node);
const auto info = node->template info<Type>();
foreign_node_completer<Type, Observers...>::complete(node, info.get().observers());
relation_completer<Type, Observers...>::complete(node, info.get().observers());
} else if (!has_node(name)) {
it->second->update_name(name);
nodes_by_name_[name] = it->second;
if (const auto i = nodes_by_name_.find(""); i != nodes_by_name_.end()) {
nodes_by_name_.erase(i);
}
relation_completer<Type>::complete(it->second);
const auto info = it->second->info<Type>();
relation_completer<Type, Observers...>::complete(it->second, info.get().observers());
log_.info("attach: update node name to '%s' (type: %s)", it->second->name().c_str(), it->second->type_index().name());
} else {
return utils::failure(make_error(error_code::NodeAlreadyExists, "Node '" + name + "' already exists"));
@@ -195,6 +206,11 @@ private:
[[nodiscard]] std::shared_ptr<object> object_for_type(const std::type_index &ti) const;
void remove_object_for_type(const std::type_index &ti);
[[nodiscard]] bool is_node_announced(const std::type_index &ti) const;
void push_announce_node(const std::type_index &ti, const node_ptr &node);
[[nodiscard]] node_ptr announce_node(const std::type_index &ti);
[[nodiscard]] node_ptr pop_announce_node(const std::type_index &ti);
private:
friend class internal::shadow_repository;
friend class repository_node;
@@ -209,9 +225,11 @@ private:
t_type_index_node_map nodes_by_type_;
logger::logger log_;
std::unordered_map<std::type_index, std::shared_ptr<repository_node>> announced_node_;
std::unordered_map<std::type_index, attribute*> missing_references_;
std::unordered_map<std::string, std::type_index> expected_relation_nodes_;
std::unordered_map<std::type_index, std::shared_ptr<object>> object_by_type_;
};
}
+26 -19
View File
@@ -3,6 +3,7 @@
#include "matador/object/object_generator.hpp"
#include "matador/object/object_info.hpp"
#include "matador/object/internal/observer_list_creator.hpp"
#include "matador/utils/error.hpp"
#include "matador/utils/result.hpp"
@@ -20,22 +21,11 @@ public:
template< typename Type>
using creator_func = std::function<std::unique_ptr<Type>()>;
template < typename Type, typename... Observers >
static std::shared_ptr<repository_node> make_node(repository& repo, const std::string& name, creator_func<Type> creator, Observers&&... observers) {
const std::type_index ti(typeid(Type));
auto node = std::shared_ptr<repository_node>(new repository_node(repo, name, ti));
auto obj = object_generator::generate<Type>(creator(), repo, name);
auto info = std::make_unique<object_info<Type>>(
node,
std::move(obj),
std::forward<creator_func<Type>>(creator)
);
(info->register_observer(observer_ptr<Type>(std::unique_ptr<Observers>(new Observers(std::forward<Observers>(observers))))), ...);
node->info_ = std::move(info);
return node;
}
template < typename Type, template<typename> typename... Observers >
static std::shared_ptr<repository_node> make_node(repository& repo,
const std::string& name,
creator_func<Type> creator,
std::vector<std::unique_ptr<observer<Type>>>&& observers);
static std::shared_ptr<repository_node> make_null_node(repository& repo);
@@ -74,11 +64,9 @@ 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);
private:
friend class repository;
template<typename Type>
template<typename Type, template<typename> typename... Observers>
friend class relation_completer;
template < typename NodeType, template<typename> typename ...Observers >
friend class foreign_node_completer;
@@ -98,5 +86,24 @@ private:
size_t depth_{0};
};
template<typename Type, template <typename> class ... Observers>
std::shared_ptr<repository_node> repository_node::make_node(repository &repo, const std::string &name,
creator_func<Type> creator, std::vector<std::unique_ptr<observer<Type>>> &&observers) {
const std::type_index ti(typeid(Type));
auto node = std::shared_ptr<repository_node>(new repository_node(repo, name, ti));
internal::observer_list_creator<Type, Observers...>::create_missing(observers);
auto obj = object_generator::generate<Type>(creator(), repo, name);
auto info = std::make_unique<object_info<Type>>(
node,
std::move(obj),
std::move(observers),
std::forward<creator_func<Type>>(creator)
);
node->info_ = std::move(info);
return node;
}
}
#endif //SCHEMA_NODE_HPP
+122 -77
View File
@@ -24,7 +24,7 @@
namespace matador::orm {
struct entity_query_data {
std::shared_ptr<query::table> root_table;
const query::table* root_table{nullptr};
std::string pk_column_name{};
std::vector<query::column> columns{};
std::unordered_map<std::string, sql::statement> lazy_loading_statements{};
@@ -34,7 +34,7 @@ struct entity_query_data {
class criteria_transformer final : public query::criteria_visitor {
public:
criteria_transformer(const query::schema &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, 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;
@@ -49,7 +49,7 @@ private:
private:
const query::schema &repo_;
const std::unordered_map<std::string, std::shared_ptr<query::table>>& tables_by_name_;
const std::unordered_map<std::string, query::table>& tables_by_name_;
};
class session_query_builder final {
@@ -60,15 +60,16 @@ public:
template<class EntityType>
utils::result<entity_query_data, query_build_error> build(query::criteria_ptr clause = {}) {
const auto info = schema_.repo().info<EntityType>();
if (!info) {
const auto it = schema_.find(typeid(EntityType));
if (it == schema_.end()) {
return utils::failure(query_build_error::UnknownType);
}
table_info_stack_.push({info.value(), std::make_shared<query::table>(info.value().get().name(), build_alias('t', ++table_index))});
entity_query_data_ = { table_info_stack_.top().table };
processed_tables_.insert({info->get().name(), entity_query_data_.root_table});
table_info_stack_.push({it->second.node().info(), it->second.table().as(build_alias('t', ++table_index))});
entity_query_data_ = { &table_info_stack_.top().table };
processed_tables_.insert({it->second.name(), *entity_query_data_.root_table});
try {
access::process(*this, info->get().prototype());
EntityType obj;
access::process(*this, obj);
if (clause) {
criteria_transformer transformer{schema_, processed_tables_};
@@ -101,45 +102,77 @@ public:
}
template<class Pointer>
void on_belongs_to(const char *id, Pointer &obj, const utils::foreign_attributes &attr)
{
void on_belongs_to(const char *id, Pointer &obj, const utils::foreign_attributes &attr) {
on_foreign_object(id, obj, attr);
}
template<class Pointer>
void on_has_one(const char *id, Pointer &obj, const utils::foreign_attributes &attr)
{
void on_has_one(const char *id, Pointer &obj, const utils::foreign_attributes &attr) {
on_foreign_object(id, obj, attr);
}
template<typename T>
struct NoopDeleter {
void operator()(const T*) const {}
};
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_.repo().basic_info(typeid(typename ContainerType::value_type::value_type));
if (!result) {
throw query_builder_exception{query_build_error::UnknownType};
}
const auto &info = result.value().get();
auto next = processed_tables_.find(info.name());
if (next != processed_tables_.end()) {
return;
}
table_info_stack_.push({*result, std::make_shared<query::table>(info.name(), build_alias('t', ++table_index))});
next = processed_tables_.insert({info.name(), table_info_stack_.top().table}).first;
typename ContainerType::value_type::value_type obj;
access::process(*this , obj);
table_info_stack_.pop();
if (!info.has_primary_key()) {
throw query_builder_exception{query_build_error::MissingPrimaryKey};
}
append_join(
query::column{table_info_stack_.top().table.get(), table_info_stack_.top().info.get().primary_key_attribute()->name()},
query::column{next->second.get(), join_column}
);
if (attr.fetch() != utils::fetch_type::Eager) {
return;
}
const auto it = schema_.find(typeid(typename ContainerType::value_type::value_type));
if (it == schema_.end()) {
throw query_builder_exception{query_build_error::UnknownType};
}
auto next = processed_tables_.find(it->second.name());
if (next != processed_tables_.end()) {
// node already processed
return;
}
table_info_stack_.push({it->second.node().info(), it->second.table().as(build_alias('t', ++table_index))});
next = processed_tables_.insert({it->second.name(), table_info_stack_.top().table}).first;
typename ContainerType::value_type::value_type obj;
access::process(*this , obj);
table_info_stack_.pop();
if (!it->second.node().info().has_primary_key()) {
throw query_builder_exception{query_build_error::MissingPrimaryKey};
}
append_join(
query::column{&table_info_stack_.top().table, table_info_stack_.top().info.primary_key_attribute()->name()},
query::column{&next->second, join_column}
);
// const auto result = schema_.repo().basic_info(typeid(typename ContainerType::value_type::value_type));
// if (!result) {
// throw query_builder_exception{query_build_error::UnknownType};
// }
//
// const auto &info = result.value().get();
// auto next = processed_tables_.find(info.name());
// if (next != processed_tables_.end()) {
// return;
// }
// table_info_stack_.push({*result, std::make_shared<query::table>(info.name(), build_alias('t', ++table_index))});
// next = processed_tables_.insert({info.name(), table_info_stack_.top().table}).first;
// typename ContainerType::value_type::value_type obj;
// access::process(*this , obj);
// table_info_stack_.pop();
//
// if (!info.has_primary_key()) {
// throw query_builder_exception{query_build_error::MissingPrimaryKey};
// }
//
// append_join(
// query::column{table_info_stack_.top().table.get(), table_info_stack_.top().info.get().primary_key_attribute()->name()},
// query::column{next->second.get(), join_column}
// );
}
template<class ContainerType>
@@ -147,38 +180,42 @@ public:
if (attr.fetch() != utils::fetch_type::Eager) {
return;
}
const auto result = schema_.repo().basic_info(typeid(typename ContainerType::value_type::value_type));
if (!result) {
const auto result = schema_.find(typeid(typename ContainerType::value_type::value_type));
if (result == schema_.end()) {
throw query_builder_exception{query_build_error::UnknownType};
}
const auto &info = result.value().get();
auto next = processed_tables_.find(info.name());
auto next = processed_tables_.find(result->second.name());
if (next != processed_tables_.end()) {
// attribute was already processed
return;
}
auto relation = processed_tables_.find(id);
if (relation == processed_tables_.end()) {
relation = processed_tables_.insert({id, std::make_shared<query::table>(id, build_alias('t', ++table_index))}).first;
const auto it = schema_.find(id);
if (it == schema_.end()) {
throw query_builder_exception{query_build_error::UnknownType};
}
relation = processed_tables_.emplace(id, it->second.table().as(build_alias('t', ++table_index))).first;
}
table_info_stack_.push({*result, std::make_shared<query::table>(info.name(), build_alias('t', ++table_index))});
next = processed_tables_.insert({info.name(), table_info_stack_.top().table}).first;
table_info_stack_.push({result->second.node().info(), result->second.table().as(build_alias('t', ++table_index))});
next = processed_tables_.insert({result->second.name(), table_info_stack_.top().table}).first;
typename ContainerType::value_type::value_type obj;
access::process(*this , obj);
table_info_stack_.pop();
if (!info.has_primary_key()) {
if (!result->second.node().info().has_primary_key()) {
throw query_builder_exception{query_build_error::MissingPrimaryKey};
}
append_join(
query::column{table_info_stack_.top().table.get(), table_info_stack_.top().info.get().primary_key_attribute()->name()},
query::column{relation->second.get(), join_column}
query::column{&table_info_stack_.top().table, table_info_stack_.top().info.primary_key_attribute()->name()},
query::column{&relation->second, join_column}
);
append_join(
query::column{relation->second.get(), inverse_join_column},
query::column{next->second.get(), info.primary_key_attribute()->name()}
query::column{&relation->second, inverse_join_column},
query::column{&next->second, result->second.node().info().primary_key_attribute()->name()}
);
}
@@ -187,40 +224,45 @@ public:
if (attr.fetch() != utils::fetch_type::Eager) {
return;
}
const auto result = schema_.repo().basic_info(typeid(typename ContainerType::value_type::value_type));
if (!result) {
const auto result = schema_.find(typeid(typename ContainerType::value_type::value_type));
if (result == schema_.end()) {
throw query_builder_exception{query_build_error::UnknownType};
}
const auto &info = result.value().get();
auto next = processed_tables_.find(info.name());
auto next = processed_tables_.find(result->second.name());
if (next != processed_tables_.end()) {
// attribute was already processed
return;
}
auto relation = processed_tables_.find(id);
if (relation == processed_tables_.end()) {
relation = processed_tables_.insert({id, std::make_shared<query::table>(id, build_alias('t', ++table_index))}).first;
const auto it = schema_.find(id);
if (it == schema_.end()) {
throw query_builder_exception{query_build_error::UnknownType};
}
const auto t = it->second.table().as(build_alias('t', ++table_index));
relation = processed_tables_.insert({id, t}).first;
}
table_info_stack_.push({*result, std::make_shared<query::table>(info.name(), build_alias('t', ++table_index))});
next = processed_tables_.insert({info.name(), table_info_stack_.top().table}).first;
table_info_stack_.push({result->second.node().info(), result->second.table().as(build_alias('t', ++table_index))});
next = processed_tables_.insert({result->second.name(), table_info_stack_.top().table}).first;
typename ContainerType::value_type::value_type obj;
access::process(*this , obj);
table_info_stack_.pop();
if (!info.has_primary_key()) {
if (!result->second.node().info().has_primary_key()) {
throw query_builder_exception{query_build_error::MissingPrimaryKey};
}
const auto join_columns = join_columns_collector_.collect<typename ContainerType::value_type::value_type>();
append_join(
query::column{table_info_stack_.top().table.get(), table_info_stack_.top().info.get().primary_key_attribute()->name()},
query::column{relation->second.get(), join_columns.inverse_join_column}
query::column{&table_info_stack_.top().table, table_info_stack_.top().info.primary_key_attribute()->name()},
query::column{&relation->second, join_columns.inverse_join_column}
);
append_join(
query::column{relation->second.get(), join_columns.join_column},
query::column{next->second.get(), info.primary_key_attribute()->name()}
query::column{&relation->second, join_columns.join_column},
query::column{&next->second, result->second.node().info().primary_key_attribute()->name()}
);
}
@@ -234,12 +276,14 @@ private:
private:
struct table_info {
std::reference_wrapper<const object::basic_object_info> info;
std::shared_ptr<query::table> table;
const object::basic_object_info &info;
query::table table;
// std::reference_wrapper<const object::basic_object_info> info;
// std::shared_ptr<query::table> table;
};
std::stack<table_info> table_info_stack_{};
std::unordered_map<std::string, std::shared_ptr<query::table>> processed_tables_{};
std::unordered_map<std::string, query::table> processed_tables_{};
const query::schema &schema_;
entity_query_data entity_query_data_{};
unsigned int column_index{0};
@@ -250,30 +294,31 @@ private:
template<class Pointer>
void session_query_builder::on_foreign_object(const char *id, Pointer &, const utils::foreign_attributes &attr) {
const auto info = schema_.repo().info<typename Pointer::value_type>();
if (!info) {
const auto it = schema_.find(typeid(typename Pointer::value_type));
if (it == schema_.end()) {
throw query_builder_exception{query_build_error::UnknownType};
}
if (!info->get().has_primary_key()) {
if (!it->second.node().info().has_primary_key()) {
throw query_builder_exception{query_build_error::MissingPrimaryKey};
}
const auto foreign_table = std::make_shared<query::table>(info->get().name(), build_alias('t', ++table_index));
const auto& info = it->second.node().info();
auto foreign_table = it->second.table().as(build_alias('t', ++table_index));
if (attr.fetch() == utils::fetch_type::Eager) {
auto next = processed_tables_.find(info->get().name());
auto next = processed_tables_.find(info.name());
if (next != processed_tables_.end()) {
return;
}
table_info_stack_.push({info.value(), foreign_table});
next = processed_tables_.insert({info->get().name(), table_info_stack_.top().table}).first;
table_info_stack_.push({info, std::move(foreign_table)});
next = processed_tables_.insert({info.name(), table_info_stack_.top().table}).first;
typename Pointer::value_type obj;
access::process(*this, obj);
table_info_stack_.pop();
append_join(
query::column{table_info_stack_.top().table.get(), id},
query::column{next->second.get(), info->get().primary_key_attribute()->name()}
query::column{&table_info_stack_.top().table, id},
query::column{&next->second, info.primary_key_attribute()->name()}
);
} else {
push(id);
@@ -281,8 +326,8 @@ void session_query_builder::on_foreign_object(const char *id, Pointer &, const u
using namespace matador::query;
// create select query
auto result = matador::query::query::select(generator::columns<typename Pointer::value_type>(schema_, generator::column_generator_options::ForceLazy))
.from(*foreign_table)
.where(column(foreign_table.get(), info->get().primary_key_attribute()->name(), "") == _)
.from(foreign_table)
.where(column(&foreign_table, info.primary_key_attribute()->name(), "") == _)
.prepare(executor_);
if (!result) {
throw query_builder_exception(query_build_error::QueryError, result.release_error());
+10 -10
View File
@@ -68,25 +68,25 @@ public:
operator column() const; // NOLINT(*-explicit-constructor)
column_builder& not_null();
column_builder& primary_key();
column_builder& unique();
private:
std::string column_name_;
utils::basic_type type_{};
utils::constraints constraints_{};
utils::constraints constraints_{utils::constraints::NotNull};
size_t size_{0};
};
class table_builder {
public:
explicit table_builder(std::string name);
table_builder& as(std::string table_alias);
// ReSharper disable once CppNonExplicitConversionOperator
operator table() const; // NOLINT(*-explicit-constructor)
private:
std::string table_name;
std::string alias;
};
class constraint_builder {
@@ -100,16 +100,16 @@ public:
operator class constraint() const; // NOLINT(*-explicit-constructor)
private:
std::string constraint_name;
std::string pk_column_name;
std::string fk_column_name;
std::string table_name;
std::string column_name;
std::string constraint_name_;
std::string column_name_;
std::string ref_table_name_;
std::string ref_column_name_;
utils::constraints type_{};
};
constraint_builder constraint(std::string name);
// table_builder table(std::string name);
// column_builder column(std::string name, utils::basic_type type, size_t size = 0);
column_builder column(std::string name, utils::basic_type type, size_t size = 0);
}
#endif //MATADOR_BUILDER_HPP
+6 -5
View File
@@ -8,6 +8,7 @@
#include <memory>
#include <string>
#include <variant>
namespace matador::query {
@@ -23,6 +24,9 @@ public:
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);
column(const class table*, std::string name, std::string alias, utils::basic_type type, const utils::field_attributes& attributes);
column& operator=(const column& other);
column(const column& other);
[[nodiscard]] bool equals(const column &x) const;
@@ -39,18 +43,15 @@ public:
[[nodiscard]] bool has_alias() const;
[[nodiscard]] const class table* table() const;
void table(const query::table* t);
void table(const query::table* tab);
// ReSharper disable once CppNonExplicitConversionOperator
operator const std::string&() const; // NOLINT(*-explicit-constructor)
private:
static query::table* default_table();
private:
friend class table;
const query::table* table_{nullptr};
const class table* table_{nullptr};
std::string name_;
std::string alias_;
utils::basic_type type_{utils::basic_type::Unknown};
+3
View File
@@ -13,7 +13,9 @@ public:
constraint() = default;
constraint(std::string column_name, std::string table_name, utils::constraints type);
constraint(std::string column_name, std::string table_name, utils::constraints type, std::string referenced_table, std::string referenced_column);
constraint(std::string name, std::string column_name, std::string table_name, utils::constraints type, std::string referenced_table, std::string referenced_column);
[[nodiscard]] std::string name() const;
[[nodiscard]] std::string column_name() const;
[[nodiscard]] std::string table_name() const;
[[nodiscard]] const utils::constraints& type() const;
@@ -24,6 +26,7 @@ public:
[[nodiscard]] const std::string& referenced_column() const;
private:
std::string name_;
std::string column_name_;
std::string table_name_;
utils::constraints type_{};
@@ -10,12 +10,12 @@ namespace matador::query {
class abstract_column_criteria : public abstract_criteria {
public:
abstract_column_criteria() = delete;
explicit abstract_column_criteria(column col);
explicit abstract_column_criteria(const class column& col);
[[nodiscard]] const column& col() const;
[[nodiscard]] const class column& col() const;
protected:
column column_;
class column column_;
};
}
@@ -4,15 +4,13 @@
#include "matador/query/criteria/abstract_column_criteria.hpp"
#include "matador/query/criteria/criteria_utils.hpp"
#include "matador/utils/value.hpp"
namespace matador::query {
class between_criteria final : public abstract_column_criteria {
public:
between_criteria() = delete;
between_criteria(column col, int64_t min, int64_t max);
between_criteria(column col, utils::placeholder min, utils::placeholder max);
between_criteria(const class column& col, int64_t min, int64_t max);
between_criteria(const class column& col, utils::placeholder min, utils::placeholder max);
void accept(criteria_visitor& visitor) const override;
@@ -19,7 +19,7 @@ enum class binary_operator {
class binary_criteria final : public abstract_column_criteria {
public:
binary_criteria() = delete;
binary_criteria(column col, binary_operator operand, criteria_value value);
binary_criteria(const class column& col, binary_operator operand, criteria_value value);
void accept( criteria_visitor& visitor ) const override;
@@ -34,18 +34,18 @@ private:
class binary_column_criteria final : public abstract_criteria {
public:
binary_column_criteria() = delete;
binary_column_criteria(column left_column, binary_operator operand, column right_column);
binary_column_criteria(const class column& left_column, binary_operator operand, const class column& right_column);
void accept(criteria_visitor& visitor) const override;
[[nodiscard]] const column& left_column() const;
[[nodiscard]] const class column& left_column() const;
[[nodiscard]] binary_operator operand() const;
[[nodiscard]] const column& right_column() const;
[[nodiscard]] const class column& right_column() const;
private:
column left_column_;
class column left_column_;
binary_operator operator_{};
column right_column_;
class column right_column_;
};
}
#endif //CRITERIA_BINARY_CRITERIA_NODE_HPP
@@ -4,10 +4,12 @@
#include "matador/query/criteria/abstract_column_criteria.hpp"
#include "matador/query/criteria/criteria_utils.hpp"
#include "matador/query/column.hpp"
#include "matador/query/table.hpp"
#include "matador/sql/query_context.hpp"
namespace matador::query {
class column;
enum class collection_operator {
In,
Out
@@ -36,8 +38,8 @@ public:
* @param operand_ Operator to use
* @param values List of values
*/
collection_criteria(column col, collection_operator operand_, std::vector<criteria_value> values);
collection_criteria(column col, collection_operator operand_, std::initializer_list<criteria_value> values);
collection_criteria(const class column& col, collection_operator operand_, std::vector<criteria_value> values);
collection_criteria(const class column& col, collection_operator operand_, std::initializer_list<criteria_value> values);
void accept(criteria_visitor& visitor) const override;
@@ -52,7 +54,7 @@ private:
class collection_query_criteria final : public abstract_column_criteria {
public:
collection_query_criteria() = delete;
collection_query_criteria(column col, collection_operator operand_, sql::query_context ctx);
collection_query_criteria(const class column& col, collection_operator operand_, sql::query_context ctx);
void accept(criteria_visitor& visitor) const override;
@@ -14,48 +14,48 @@ namespace matador::query {
class column;
template<class Type>
criteria_ptr operator==(const column &col, Type val) {
criteria_ptr operator==(const class column &col, Type val) {
return std::make_unique<binary_criteria>(col, binary_operator::EQUALS, utils::value(val));
}
template<class Type>
criteria_ptr operator!=(const column &col, Type val) {
criteria_ptr operator!=(const class column &col, Type val) {
return std::make_unique<binary_criteria>(col, binary_operator::NOT_EQUALS, utils::value(val));
}
template<class Type>
criteria_ptr operator>(const column &col, Type val) {
criteria_ptr operator>(const class column &col, Type val) {
return std::make_unique<binary_criteria>(col, binary_operator::GREATER_THAN, utils::value(val));
}
template<class Type>
criteria_ptr operator>=(const column &col, Type val) {
criteria_ptr operator>=(const class column &col, Type val) {
return std::make_unique<binary_criteria>(col, binary_operator::GREATER_THAN_OR_EQUAL, utils::value(val));
}
template<class Type>
criteria_ptr operator<(const column &col, Type val) {
criteria_ptr operator<(const class column &col, Type val) {
return std::make_unique<binary_criteria>(col, binary_operator::LESS_THAN, utils::value(val));
}
template<class Type>
criteria_ptr operator<=(const column &col, Type val) {
criteria_ptr operator<=(const class column &col, Type val) {
return std::make_unique<binary_criteria>(col, binary_operator::LESS_THAN_OR_EQUAL, utils::value(val));
}
criteria_ptr operator==(const column &col_left, const column &col_right);
criteria_ptr operator!=(const column &col_left, const column &col_right);
criteria_ptr operator>(const column &col_left, const column &col_right);
criteria_ptr operator>=(const column &col_left, const column &col_right);
criteria_ptr operator<(const column &col_left, const column &col_right);
criteria_ptr operator<=(const column &col_left, const column &col_right);
criteria_ptr operator==(const class column &col_left, const class column &col_right);
criteria_ptr operator!=(const class column &col_left, const class column &col_right);
criteria_ptr operator>(const class column &col_left, const class column &col_right);
criteria_ptr operator>=(const class column &col_left, const class column &col_right);
criteria_ptr operator<(const class column &col_left, const class column &col_right);
criteria_ptr operator<=(const class column &col_left, const class column &col_right);
criteria_ptr operator==(const column &col, utils::placeholder p);
criteria_ptr operator!=(const column &col, utils::placeholder p);
criteria_ptr operator>(const column &col, utils::placeholder p);
criteria_ptr operator>=(const column &col, utils::placeholder p);
criteria_ptr operator<(const column &col, utils::placeholder p);
criteria_ptr operator<=(const column &col, utils::placeholder p);
criteria_ptr operator==(const class column &col, utils::placeholder p);
criteria_ptr operator!=(const class column &col, utils::placeholder p);
criteria_ptr operator>(const class column &col, utils::placeholder p);
criteria_ptr operator>=(const class column &col, utils::placeholder p);
criteria_ptr operator<(const class column &col, utils::placeholder p);
criteria_ptr operator<=(const class column &col, utils::placeholder p);
criteria_ptr operator&&(criteria_ptr left, criteria_ptr right);
@@ -64,7 +64,7 @@ criteria_ptr operator||(criteria_ptr left, criteria_ptr right);
criteria_ptr operator!(criteria_ptr clause);
template < class Type >
criteria_ptr in(const column &col, std::initializer_list<Type> args) {
criteria_ptr in(const class column &col, std::initializer_list<Type> args) {
std::vector<criteria_value> values;
for ( auto &&arg : args ) {
values.emplace_back(utils::value{std::move(arg)});
@@ -73,12 +73,12 @@ criteria_ptr in(const column &col, std::initializer_list<Type> args) {
}
template <>
criteria_ptr in(const column &col, std::initializer_list<utils::placeholder> args);
criteria_ptr in(const class column &col, std::initializer_list<utils::placeholder> args);
criteria_ptr in(const column &col, sql::query_context &&ctx);
criteria_ptr in(const class column &col, sql::query_context &&ctx);
template < class Type >
criteria_ptr out(const column &col, std::initializer_list<Type> args) {
criteria_ptr out(const class column &col, std::initializer_list<Type> args) {
std::vector<criteria_value> values;
for ( auto &&arg : args ) {
values.emplace_back(utils::value{std::move(arg)});
@@ -87,14 +87,14 @@ criteria_ptr out(const column &col, std::initializer_list<Type> args) {
}
template <>
criteria_ptr out(const column &col, std::initializer_list<utils::placeholder> args);
criteria_ptr out(const class column &col, std::initializer_list<utils::placeholder> args);
criteria_ptr out(const column &col, sql::query_context &&ctx);
criteria_ptr out(const class column &col, sql::query_context &&ctx);
criteria_ptr between(const column &col, int64_t min, int64_t max);
criteria_ptr between(const column &col, utils::placeholder min, utils::placeholder max);
criteria_ptr between(const class column &col, int64_t min, int64_t max);
criteria_ptr between(const class column &col, utils::placeholder min, utils::placeholder max);
criteria_ptr like(const column &col, const std::string &pattern);
criteria_ptr like(const class column &col, const std::string &pattern);
}
#endif //CRITERIA_CRITERIA_OPERATORS_HPP
@@ -3,13 +3,13 @@
#include "matador/query/criteria/abstract_column_criteria.hpp"
#include "matador/query/column.hpp"
namespace matador::query {
class column;
class like_criteria final : public abstract_column_criteria {
public:
like_criteria() = delete;
like_criteria(column col, std::string pattern);
like_criteria(const class column& col, std::string pattern);
void accept(criteria_visitor &visitor) const override;
-17
View File
@@ -45,8 +45,6 @@ constexpr auto default_column_generator_options = column_generator_options::Forc
class column_generator {
public:
explicit column_generator(const std::string &table_name = "",
column_generator_options options = default_column_generator_options);
explicit column_generator(const schema &repo,
const std::string &table_name = "",
column_generator_options options = default_column_generator_options);
@@ -322,20 +320,5 @@ std::vector<column> columns(const Type &obj,
return generator.generate(obj);
}
template<typename Type>
std::vector<column> columns(const std::string &table_name = "",
const column_generator_options options = default_column_generator_options) {
column_generator generator(table_name, options);
return generator.generate<Type>();
}
template<typename Type>
std::vector<column> columns(const Type &obj,
const std::string &table_name = "",
const column_generator_options options = default_column_generator_options) {
column_generator generator(table_name, options);
return generator.generate(obj);
}
}
#endif //MATADOR_GENERATOR_HPP
@@ -3,19 +3,18 @@
#include "matador/query/intermediates/query_intermediate.hpp"
#include "matador/query/intermediates/query_into_intermediate.hpp"
#include "matador/query/schema.hpp"
#include "matador/query/generator.hpp"
namespace matador::query {
class query_insert_intermediate : public query_intermediate
{
class query_insert_intermediate : public query_intermediate {
public:
query_insert_intermediate();
template<class Type>
query_into_intermediate into(const table &tab, const object::repository &schema) {
return into(tab, generator::columns<Type>(schema));
query_into_intermediate into(const table &tab, const schema &scm) {
return into(tab, generator::columns<Type>(scm));
}
query_into_intermediate into(const table &tab, std::initializer_list<column> columns);
query_into_intermediate into(const table &tab, std::vector<column> &&columns);
+3 -2
View File
@@ -4,6 +4,7 @@
#include "matador/query/query_intermediates.hpp"
#include "matador/query/generator.hpp"
#include "matador/query/schema.hpp"
namespace matador::sql {
class connection;
@@ -26,8 +27,8 @@ public:
[[nodiscard]] static query_select_intermediate select(const std::vector<std::string> &column_names);
[[nodiscard]] static query_select_intermediate select(std::vector<column> columns, std::initializer_list<column> additional_columns);
template<class Type>
[[nodiscard]] static query_select_intermediate select(const object::repository &schema) {
return select(generator::columns<Type>(schema));
[[nodiscard]] static query_select_intermediate select(const schema &scm) {
return select(generator::columns<Type>(scm));
}
[[nodiscard]] static query_insert_intermediate insert();
[[nodiscard]] static query_update_intermediate update(const table &table);
+3 -3
View File
@@ -77,9 +77,9 @@ protected:
static std::string build_table_name(sql::dialect_token token, const sql::dialect &d, const table& t);
static std::string determine_value(value_visitor &visitor, const std::variant<utils::placeholder, utils::database_type> &val);
std::string build_add_constraint_string(const class constraint& c);
std::string build_drop_constraint_string(const class constraint& c);
std::string build_constraint_name(const class constraint& c);
std::string build_add_constraint_string(const class constraint& c) const;
std::string build_drop_constraint_string(const class constraint& c) const;
static std::string build_constraint_name(const class constraint& c);
protected:
const query_data *data_{};
-1
View File
@@ -13,7 +13,6 @@ namespace matador::query {
class column;
[[nodiscard]] std::string prepare_identifier(const sql::dialect& d, const column &col);
[[nodiscard]] std::string prepare_identifier(const sql::dialect& d, const table &tab, const column &col);
[[nodiscard]] std::string prepare_criteria(const sql::dialect& d, const column &col);
}
#endif //MATADOR_QUERY_UTILS_HPP
+58 -24
View File
@@ -10,6 +10,7 @@
namespace matador::sql {
class connection_pool;
class connection;
}
namespace matador::query {
@@ -34,20 +35,42 @@ 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;
template<typename OtherType>
explicit schema_observer(const schema_observer<OtherType> &x)
: schema_(x.schema_)
{}
void on_attach(const object::repository_node &node, const Type &prototype) const override;
void on_detach(const object::repository_node &node, const Type &prototype) const override;
void on_insert(const Type &obj) override;
void on_update(const Type &obj) override;
void on_delete(const Type &obj) override;
private:
template < class OtherType >
friend class schema_observer;
schema& schema_;
};
class schema_node final {
public:
schema_node(class table tab, const object::repository_node& node);
[[nodiscard]] const std::string& name() const;
[[nodiscard]] const class table& table() const;
[[nodiscard]] const object::repository_node& node() const;
private:
class table table_;
const object::repository_node& node_;
};
class schema final {
public:
explicit schema(sql::connection_pool &pool);
schema(sql::connection_pool &pool, const std::string &name);
using iterator = std::unordered_map<std::type_index, schema_node>::iterator;
using const_iterator = std::unordered_map<std::type_index, schema_node>::const_iterator;
schema() = default;
explicit schema(const std::string &name);
template<typename Type, typename... Observers>
[[nodiscard]] utils::result<void, utils::error> attach(const std::string &name, Observers&&... observers) {
@@ -64,21 +87,33 @@ public:
return repo_.attach<Type, SuperType>(name, schema_observer<Type>{*this}, std::forward<Observers>(observers)...);
}
[[nodiscard]] utils::result<void, utils::error> create() const;
[[nodiscard]] utils::result<void, utils::error> drop() const;
[[nodiscard]] utils::result<void, utils::error> create(const sql::connection &conn) const;
[[nodiscard]] utils::result<void, utils::error> drop(const sql::connection &conn) const;
template<typename Type>
[[nodiscard]] utils::result<void, utils::error> drop_table();
[[nodiscard]] utils::result<void, utils::error> drop_table(const std::string &table_name) const;
[[nodiscard]] utils::result<void, utils::error> drop_table(const sql::connection &conn);
[[nodiscard]] utils::result<void, utils::error> drop_table(const std::string &table_name, const sql::connection &conn) const;
[[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;
[[nodiscard]] utils::result<std::vector<object::attribute>, utils::error> describe_table(const std::string &table_name, const sql::connection &conn) const;
[[nodiscard]] utils::result<bool, utils::error> table_exists(const std::string &table_name, const sql::connection &conn) const;
iterator begin();
iterator end();
const_iterator begin() const;
const_iterator end() const;
iterator find(const std::type_index& ti) { return schema_nodes_.find(ti); }
const_iterator find(const std::type_index& ti) const { return schema_nodes_.find(ti); }
iterator find(const std::string& name);
const_iterator find(const std::string& name) const;
const object::repository &repo() const { return repo_; }
object::repository &repo() { 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;
[[nodiscard]] sql::query_context build_add_constraint_context(const object::repository_node& node, const object::restriction& cons, const sql::connection &conn) const;
[[nodiscard]] sql::query_context build_drop_constraint_context(const object::repository_node& node, const object::restriction& cons, const sql::connection &conn) const;
void insert_table(const std::type_index& ti, const object::repository_node &node);
@@ -87,31 +122,30 @@ private:
friend class schema_observer;
object::repository repo_;
std::unordered_map<std::type_index, table> tables_;
sql::connection_pool &pool_;
std::unordered_map<std::type_index, schema_node> schema_nodes_;
};
template<typename Type>
utils::result<void, utils::error> schema::drop_table() {
utils::result<void, utils::error> schema::drop_table(const sql::connection &conn) {
auto info = repo_.info<Type>();
if (info) {
return drop_table(info->get().name());
return drop_table(info->get().name(), conn);
}
return utils::failure(info.err());
}
template <typename Type>
void schema_observer<Type>::on_attach(object::repository_node &node, const Type &prototype) {
void schema_observer<Type>::on_attach(const object::repository_node &node, const Type &/*prototype*/) const {
schema_.insert_table(typeid(Type), node);
}
template <typename Type>
void schema_observer<Type>::on_detach(object::repository_node &node, const Type &prototype) {}
void schema_observer<Type>::on_detach(const object::repository_node &/*node*/, const Type &/*prototype*/) const {}
template <typename Type>
void schema_observer<Type>::on_insert(Type &obj) {}
void schema_observer<Type>::on_insert(const Type &/*obj*/) {}
template <typename Type>
void schema_observer<Type>::on_update(Type &obj) {}
void schema_observer<Type>::on_update(const Type &/*obj*/) {}
template <typename Type>
void schema_observer<Type>::on_delete(Type &obj) {}
void schema_observer<Type>::on_delete(const Type &/*obj*/) {}
} // namespace matador::query
#endif //MATADOR_SCHEMA_HPP
+21 -9
View File
@@ -13,24 +13,36 @@ class table {
public:
table() = default;
table(const char *name); // NOLINT(*-explicit-constructor)
table(std::string name); // NOLINT(*-explicit-constructor)
table(std::string name, std::string as);
table(std::string name, std::string as, const std::vector<column> &columns);
table(const std::string& name); // NOLINT(*-explicit-constructor)
table(const std::string& name, const std::vector<column>& columns);
table(const table& other);
table& operator=(const table& other);
table(table&& other) noexcept;
table& operator=(table&& other) noexcept;
~table() = default;
table as(const std::string &a);
[[nodiscard]] table as(const std::string &alias) const;
[[nodiscard]] bool operator==(const table &x) const;
[[nodiscard]] table as(const std::string &a) const;
[[nodiscard]] const std::string& table_name() const;
[[nodiscard]] const std::string& name() const;
[[nodiscard]] const std::vector<column>& columns() const;
[[nodiscard]] bool has_alias() const;
[[nodiscard]] const std::string& name() const;
[[nodiscard]] const std::string& alias() const;
[[nodiscard]] const std::vector<column>& columns() const;
// ReSharper disable once CppNonExplicitConversionOperator
operator const std::vector<query::column>&() const; // NOLINT(*-explicit-constructor)
const class column* operator[](const std::string& column_name) const;
static const class column* column_by_name(const table &tab, const std::string& column_name);
protected:
static const column& create_column(class table& tab, const std::string& name);
private:
table(std::string name, std::string alias, const std::vector<column>& columns);
private:
friend class column;
+5 -4
View File
@@ -9,16 +9,17 @@
#include <string>
#include <ostream>
#define FIELD(x) const matador::query::column x{*this, #x, ""};
#define FIELD(x) const matador::query::column& x = create_column(*this, #x);
#define QUERY_HELPER(C, V, ...) \
namespace matador::query::meta { \
namespace internal { \
struct C##_query : table { \
C##_query() : table(#C) {} \
class C##_table : public table { \
public: \
C##_table() : table(#C) {} \
MAP(FIELD, __VA_ARGS__) \
}; } \
static const internal:: C##_query V; \
static const internal:: C##_table V; \
}
#endif //QUERY_QUERY_HELPER_HPP