schema progress (does not compile)

This commit is contained in:
Sascha Kühl 2025-12-31 11:56:12 +01:00
parent d104222fdd
commit ab2d39407c
65 changed files with 1355 additions and 922 deletions

View File

@ -2,6 +2,7 @@
#define FOREIGN_NODE_COMPLETER_HPP #define FOREIGN_NODE_COMPLETER_HPP
#include "matador/object/internal/shadow_repository.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/many_to_many_relation.hpp"
#include "matador/object/repository_node.hpp" #include "matador/object/repository_node.hpp"
#include "matador/object/join_columns_collector.hpp" #include "matador/object/join_columns_collector.hpp"
@ -35,9 +36,9 @@ private:
using node_ptr = std::shared_ptr<repository_node>; using node_ptr = std::shared_ptr<repository_node>;
public: 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_); internal::shadow_repository shadow(node->repo_);
foreign_node_completer completer(shadow, observers...); foreign_node_completer completer(shadow, observers);
completer.complete_node(node); 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*/) {} static void on_has_many_to_many(const char * /*id*/, CollectionType &/*collection*/, const utils::foreign_attributes &/*attr*/) {}
private: 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) : repo_(shadow)
, log_(logger::create_logger("node_completer")) { , log_(logger::create_logger("node_completer"))
// observers_.emplace_back(observers...); , observers_(observers) {}
}
void complete_node(const std::shared_ptr<repository_node> &node) { void complete_node(const std::shared_ptr<repository_node> &node) {
nodes_.push(node); nodes_.push(node);
@ -91,75 +91,22 @@ private:
nodes_.pop(); 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> template<typename Type>
void attach_node() { void attach_node() {
if (repo_.contains(typeid(Type))) { if (repo_.contains(typeid(Type))) {
return; return;
} }
const auto node = repository_node::make_node<Type>(repo_.repo(), "", []{ return std::make_unique<Type>(); }); auto observers = internal::observer_list_copy_creator<NodeType, Type, Observers...>::copy_create(observers_);
if (auto result = repo_.attach_node(node)) {
foreign_node_completer<Type>::complete(result.value());
}
}
template<typename Type> if (repo_.is_node_announced(typeid(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
return; return;
} }
const auto node = repository_node::make_node<Type>(repo_.repo(), "", []{ return std::make_unique<Type>(); }, std::move(observers));
const auto foreign_node = result.value(); repo_.push_announce_node(typeid(Type), node);
result = repo_.find_node(name); // if (auto result = repo_.attach_node(node)) {
if (result) { // foreign_node_completer<Type>::complete(result.value(), {});
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);
} }
private: private:
@ -178,7 +125,7 @@ private:
internal::shadow_repository &repo_; internal::shadow_repository &repo_;
logger::logger log_; logger::logger log_;
join_columns_collector join_columns_collector_{}; 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<typename NodeType, template<typename> typename ...Observers>
template<class ForeignPointerType> 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>(); attach_node<typename ForeignPointerType::value_type>();
} }

View File

@ -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

View File

@ -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

View File

@ -40,6 +40,11 @@ public:
[[nodiscard]] std::shared_ptr<object> object_for_type(const std::type_index &ti) const; [[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; 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: private:
repository& repo_; repository& repo_;
}; };

View File

@ -51,17 +51,17 @@ private:
class object_generator { class object_generator {
private: 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: public:
template < class Type > 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); return generate(std::make_unique<Type>(), repo, name);
} }
template < class Type > template < class Type >
static std::shared_ptr<object> generate(std::unique_ptr<Type>&& t, repository &repo, const std::string &name) { static std::shared_ptr<object> generate(std::unique_ptr<Type>&& t, const repository &repo, const std::string &name) {
const internal::shadow_repository shadow_repo(repo); const internal::shadow_repository shadow_repo(const_cast<repository&>(repo));
const std::type_index ti(typeid(Type)); const std::type_index ti(typeid(Type));
if (shadow_repo.has_object_for_type(ti)) { if (shadow_repo.has_object_for_type(ti)) {
auto obj = shadow_repo.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); static std::shared_ptr<object> acquire_object(repository &repo, const std::type_index &ti, const std::string& name);
private: private:
repository &repo_; const repository &repo_;
std::shared_ptr<object> object_; std::shared_ptr<object> object_;
}; };
@ -167,7 +167,7 @@ void object_generator::create_fk_constraint(const std::string& name) const {
template<typename Type> template<typename Type>
std::shared_ptr<object> object_generator::fk_object() const { std::shared_ptr<object> object_generator::fk_object() const {
const auto ti = std::type_index(typeid(Type)); 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)) { if (const auto result = shadow_repo.basic_info(ti)) {
return result->get().object(); return result->get().object();
} }

View File

@ -9,21 +9,21 @@
namespace matador::object { namespace matador::object {
class repository_node; class repository_node;
template<typename Type> // template<typename Type>
class observer_ptr { // class observer_ptr {
public: // public:
explicit observer_ptr(std::unique_ptr<observer<Type>> &&observer) // explicit observer_ptr(std::unique_ptr<observer<Type>> &&o)
: observer(std::move(observer)) {} // : observer_(std::move(o)) {}
//
operator bool() const { return observer != nullptr; } // operator bool() const { return observer_ != nullptr; }
//
observer<Type> *get() const { return observer.get(); } // observer<Type> *get() const { return observer_.get(); }
observer<Type> &operator*() const { return *observer; } // observer<Type> &operator*() const { return *observer_; }
observer<Type> *operator->() const { return observer.get(); } // observer<Type> *operator->() const { return observer_.get(); }
//
private: // private:
std::unique_ptr<observer<Type>> observer; // std::unique_ptr<observer<Type>> observer_;
}; // };
template<typename Type> template<typename Type>
class object_info final : public basic_object_info { class object_info final : public basic_object_info {
public: public:
@ -31,10 +31,11 @@ public:
object_info(const std::shared_ptr<repository_node>& node, object_info(const std::shared_ptr<repository_node>& node,
std::shared_ptr<class object> &&obj, std::shared_ptr<class object> &&obj,
std::vector<std::unique_ptr<observer<Type>>>&& observers,
create_func&& creator) create_func&& creator)
: basic_object_info(node, std::move(obj)) : 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) explicit object_info(const std::shared_ptr<repository_node>& node)
: basic_object_info(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)); observers_.push_back(std::move(observer));
} }
const std::vector<std::unique_ptr<observer<Type>>>& observers() const {
return observers_;
}
private: private:
Type prototype_; Type prototype_;
create_func creator_{[]{ return std::make_unique<Type>(); }}; 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> template<typename Type>

View File

@ -63,7 +63,7 @@ public:
* @param node The attached repository_node * @param node The attached repository_node
* @param prototype The prototype object of the attached 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 * @brief Called on repository_node detached
@ -74,7 +74,7 @@ public:
* @param node The to be detached repository_node * @param node The to be detached repository_node
* @param prototype The prototype object of the detached 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. * @brief Called on object insertion.
@ -84,7 +84,7 @@ public:
* *
* @param obj The proxy of the inserted object. * @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. * @brief Called on object update.
@ -94,7 +94,7 @@ public:
* *
* @param obj The proxy of the updated object. * @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. * @brief Called on object deletion.
@ -104,7 +104,7 @@ public:
* *
* @param obj The proxy of the deleted object. * @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 { namespace internal {

View File

@ -92,7 +92,7 @@ private:
* no has_many or belongs_to * no has_many or belongs_to
* invalid relation -> error * invalid relation -> error
*/ */
template<typename Type> template<typename Type, template<typename> typename... Observers>
class relation_completer final { class relation_completer final {
private: private:
using node_ptr = std::shared_ptr<repository_node>; using node_ptr = std::shared_ptr<repository_node>;
@ -100,9 +100,9 @@ private:
public: public:
using endpoint_ptr = std::shared_ptr<relation_endpoint>; 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_); internal::shadow_repository shadow(node->repo_);
relation_completer completer(shadow); relation_completer completer(shadow, observers);
completer.complete_node_relations(node); 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); void on_has_many_to_many(const char *id, CollectionType &collection, const utils::foreign_attributes &attr);
private: private:
explicit relation_completer(internal::shadow_repository &shadow) explicit relation_completer(internal::shadow_repository &shadow, const std::vector<std::unique_ptr<observer<Type>>>& observers)
: schema_(shadow) : schema_(shadow)
, log_(logger::create_logger("relation_completer")) { , log_(logger::create_logger("relation_completer"))
} , observers_(observers) {}
void complete_node_relations(const std::shared_ptr<repository_node> &node) { void complete_node_relations(const std::shared_ptr<repository_node> &node) {
nodes_.push(node); nodes_.push(node);
@ -152,16 +152,19 @@ private:
static void link_relation_endpoints(const endpoint_ptr &endpoint, static void link_relation_endpoints(const endpoint_ptr &endpoint,
const endpoint_ptr &other_endpoint); const endpoint_ptr &other_endpoint);
node_ptr find_node(const std::type_index &ti) const;
private: private:
std::stack<node_ptr> nodes_; std::stack<node_ptr> nodes_;
internal::shadow_repository &schema_; internal::shadow_repository &schema_;
logger::logger log_; logger::logger log_;
join_columns_collector join_columns_collector_{}; 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> 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 char *join_column,
const utils::foreign_attributes &, const utils::foreign_attributes &,
std::enable_if_t<is_object_ptr<typename CollectionType::value_type>::value> * /*unused*/) { 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>; 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) // Check if the object_ptr type is already inserted in the schema (by id)
auto result = schema_.find_node(typeid(value_type)); auto foreign_node = find_node(typeid(value_type));
if (!result) { if (!foreign_node) {
// Todo: throw internal error or attach node // Todo: throw internal error or attach node
return; return;
} }
const auto foreign_node = result.value();
// has foreign node corresponding join column (join_column) // 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()) { 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); 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] { auto node = repository_node::make_node<relation_value_type>(schema_.repo(), id, [join_column] {
return std::make_unique<relation_value_type>("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) { if (!result) {
// Todo: throw internal error // Todo: throw internal error
return; 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> 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 &, const utils::foreign_attributes &,
std::enable_if_t<!is_object_ptr<typename CollectionType::value_type>::value> std::enable_if_t<!is_object_ptr<typename CollectionType::value_type>::value>
* /*unused*/) { * /*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] { auto node = repository_node::make_node<relation_value_type>(schema_.repo(), id, [join_column] {
return std::make_unique<relation_value_type>(join_column, "value"); return std::make_unique<relation_value_type>(join_column, "value");
}); }, {});
const auto result = schema_.attach_node(node); const auto result = schema_.attach_node(node);
if (!result) { if (!result) {
// Todo: throw internal exception // 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); link_relation_endpoints(local_endpoint, foreign_endpoint);
} }
template<typename Type> template<typename Type, template<typename> typename... Observers>
template<class CollectionType> 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*/, CollectionType &/*collection*/,
const char *join_column, const char *join_column,
const char *inverse_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> 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, CollectionType &collection,
const utils::foreign_attributes &attr) { const utils::foreign_attributes &attr) {
const auto join_columns = join_columns_collector_.collect<typename CollectionType::value_type::value_type>(); 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); attr);
} }
template<typename Type> template<typename Type, template<typename> typename... Observers>
template<class ForeignPointerType> 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*/, ForeignPointerType &/*obj*/,
const utils::foreign_attributes &/*attr*/) { const utils::foreign_attributes &/*attr*/) {
using value_type = typename ForeignPointerType::value_type; using value_type = typename ForeignPointerType::value_type;
const auto ti = std::type_index(typeid(value_type)); auto foreign_node = find_node(typeid(value_type));
const auto result = schema_.find_node(ti); if (!foreign_node) {
if (!result) { // Todo: throw internal error or attach node
// Node was not found
// Todo: Throw internal error
return; return;
} }
auto local_it = nodes_.top()->info().find_relation_endpoint(typeid(value_type)); auto local_it = nodes_.top()->info().find_relation_endpoint(typeid(value_type));
if (local_it == nodes_.top()->info().endpoint_end()) { 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); 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); link_relation_endpoints(local_it->second, foreign_it->second);
} }
} }
template<typename Type> template<typename Type, template<typename> typename... Observers>
template<class ForeignPointerType> 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*/, ForeignPointerType & /*obj*/,
const utils::foreign_attributes & /*attr*/) { const utils::foreign_attributes & /*attr*/) {
using value_type = typename ForeignPointerType::value_type; using value_type = typename ForeignPointerType::value_type;
const auto ti = std::type_index(typeid(value_type)); const auto ti = std::type_index(typeid(value_type));
auto result = schema_.find_node(ti); auto foreign_node = find_node(typeid(value_type));
if (!result) { if (!foreign_node) {
// Type was not found // Todo: throw internal error or attach node
// Todo: Throw internal error
return; return;
} }
// Type was found // Type was found
const auto &foreign_node = result.value();
// Check foreign node and relation endpoint // 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()) { 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 // 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> 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 relation_value_type = many_to_many_relation<NodeType, Type>;
using value_type = NodeType; using value_type = NodeType;
// Check if the object_ptr type is already inserted in the schema (by id) // Check if the object_ptr type is already inserted in the schema (by id)
auto result = schema_.find_node(typeid(value_type)); auto foreign_node = find_node(typeid(value_type));
if (!result) { if (!foreign_node) {
// Todo: throw internal error or attach node // Todo: throw internal error or attach node
return; return;
} }
const auto foreign_node = result.value(); auto result = schema_.find_node(name);
result = schema_.find_node(name);
if (result) { if (result) {
return; 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); 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); result = schema_.attach_node(node);
if (!result) { if (!result) {
// Todo: throw internal error // Todo: throw internal error
return; 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 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 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); link_relation_endpoints(foreign_endpoint, inverse_join_endpoint);
} }
template<typename Type> template<typename Type, template<typename> typename... Observers>
void relation_completer<Type>::register_relation_endpoints(const endpoint_ptr &endpoint, void relation_completer<Type, Observers...>::register_relation_endpoints(const endpoint_ptr &endpoint,
const endpoint_ptr &other_endpoint) { const endpoint_ptr &other_endpoint) {
endpoint->node_->info_->register_relation_endpoint(other_endpoint->node_->type_index(), 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); other_endpoint->node_->info_->register_relation_endpoint(endpoint->node_->type_index(), other_endpoint);
link_relation_endpoints(endpoint, other_endpoint); link_relation_endpoints(endpoint, other_endpoint);
} }
template<typename Type> template<typename Type, template<typename> typename... Observers>
void relation_completer<Type>::link_relation_endpoints(const endpoint_ptr &endpoint, const endpoint_ptr &other_endpoint) { void relation_completer<Type, Observers...>::link_relation_endpoints(const endpoint_ptr &endpoint, const endpoint_ptr &other_endpoint) {
endpoint->link_foreign_endpoint(other_endpoint); endpoint->link_foreign_endpoint(other_endpoint);
other_endpoint->link_foreign_endpoint(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 #endif //RELATION_COMPLETER_HPP

View File

@ -41,7 +41,7 @@ public:
void link_foreign_endpoint(const std::shared_ptr<relation_endpoint>& endpoint); void link_foreign_endpoint(const std::shared_ptr<relation_endpoint>& endpoint);
private: private:
template<typename Type> template<typename Type, template<typename> typename... Observers>
friend class relation_completer; friend class relation_completer;
template<typename Type, template<typename> typename ...Observers> template<typename Type, template<typename> typename ...Observers>
friend class foreign_node_completer; friend class foreign_node_completer;

View File

@ -38,44 +38,55 @@ public:
*/ */
explicit repository(std::string name = ""); explicit repository(std::string name = "");
template<typename Type, typename... Observers> template<typename Type, template<typename> typename... Observers>
[[nodiscard]] utils::result<void, utils::error> attach(const std::string &name, Observers&&... 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>(observers)...); return attach_type<Type, Observers...>(name, std::string{}, std::forward<Observers<Type>>(observers)...);
} }
template<typename Type, typename SuperType, typename... Observers> template<typename Type, typename SuperType, template<typename> typename... Observers>
[[nodiscard]] utils::result<void, utils::error> attach(const std::string &name, Observers&&... observers) { [[nodiscard]] utils::result<void, utils::error> attach(const std::string &name, Observers<Type>&&... observers) {
const auto ti = std::type_index(typeid(SuperType)); const auto ti = std::type_index(typeid(SuperType));
auto result = find_node(ti); auto result = find_node(ti);
if (!result) { if (!result) {
return utils::failure(make_error(error_code::NodeNotFound, "Parent node '" + std::string(ti.name()) + "' not found")); 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> template<typename Type, template<typename> typename... Observers>
[[nodiscard]] utils::result<void, utils::error> attach(const std::string &name, const std::string &parent, Observers&&... 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>(observers)...); return attach_type<Type, Observers...>(name, parent, std::forward<Observers<Type>>(observers)...);
} }
template<typename Type, typename... 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&&... 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() ) { 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 // 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) { if (auto result = attach_node(node, parent); !result) {
return utils::failure(result.err()); return utils::failure(result.err());
} }
foreign_node_completer<Type>::complete(node); const auto info = node->template info<Type>();
relation_completer<Type>::complete(node); foreign_node_completer<Type, Observers...>::complete(node, info.get().observers());
relation_completer<Type, Observers...>::complete(node, info.get().observers());
} else if (!has_node(name)) { } else if (!has_node(name)) {
it->second->update_name(name); it->second->update_name(name);
nodes_by_name_[name] = it->second; nodes_by_name_[name] = it->second;
if (const auto i = nodes_by_name_.find(""); i != nodes_by_name_.end()) { if (const auto i = nodes_by_name_.find(""); i != nodes_by_name_.end()) {
nodes_by_name_.erase(i); 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()); log_.info("attach: update node name to '%s' (type: %s)", it->second->name().c_str(), it->second->type_index().name());
} else { } else {
return utils::failure(make_error(error_code::NodeAlreadyExists, "Node '" + name + "' already exists")); 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; [[nodiscard]] std::shared_ptr<object> object_for_type(const std::type_index &ti) const;
void remove_object_for_type(const std::type_index &ti); 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: private:
friend class internal::shadow_repository; friend class internal::shadow_repository;
friend class repository_node; friend class repository_node;
@ -209,9 +225,11 @@ private:
t_type_index_node_map nodes_by_type_; t_type_index_node_map nodes_by_type_;
logger::logger log_; 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::type_index, attribute*> missing_references_;
std::unordered_map<std::string, std::type_index> expected_relation_nodes_; std::unordered_map<std::string, std::type_index> expected_relation_nodes_;
std::unordered_map<std::type_index, std::shared_ptr<object>> object_by_type_; std::unordered_map<std::type_index, std::shared_ptr<object>> object_by_type_;
}; };
} }

View File

@ -3,6 +3,7 @@
#include "matador/object/object_generator.hpp" #include "matador/object/object_generator.hpp"
#include "matador/object/object_info.hpp" #include "matador/object/object_info.hpp"
#include "matador/object/internal/observer_list_creator.hpp"
#include "matador/utils/error.hpp" #include "matador/utils/error.hpp"
#include "matador/utils/result.hpp" #include "matador/utils/result.hpp"
@ -20,22 +21,11 @@ public:
template< typename Type> template< typename Type>
using creator_func = std::function<std::unique_ptr<Type>()>; using creator_func = std::function<std::unique_ptr<Type>()>;
template < typename Type, typename... Observers > 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, Observers&&... observers) { static std::shared_ptr<repository_node> make_node(repository& repo,
const std::type_index ti(typeid(Type)); const std::string& name,
auto node = std::shared_ptr<repository_node>(new repository_node(repo, name, ti)); creator_func<Type> creator,
std::vector<std::unique_ptr<observer<Type>>>&& observers);
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;
}
static std::shared_ptr<repository_node> make_null_node(repository& repo); static std::shared_ptr<repository_node> make_null_node(repository& repo);
@ -74,11 +64,9 @@ private:
void unlink(); 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: private:
friend class repository; friend class repository;
template<typename Type> template<typename Type, template<typename> typename... Observers>
friend class relation_completer; friend class relation_completer;
template < typename NodeType, template<typename> typename ...Observers > template < typename NodeType, template<typename> typename ...Observers >
friend class foreign_node_completer; friend class foreign_node_completer;
@ -98,5 +86,24 @@ private:
size_t depth_{0}; 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 #endif //SCHEMA_NODE_HPP

View File

@ -24,7 +24,7 @@
namespace matador::orm { namespace matador::orm {
struct entity_query_data { struct entity_query_data {
std::shared_ptr<query::table> root_table; const query::table* root_table{nullptr};
std::string pk_column_name{}; std::string pk_column_name{};
std::vector<query::column> columns{}; std::vector<query::column> columns{};
std::unordered_map<std::string, sql::statement> lazy_loading_statements{}; 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 { class criteria_transformer final : public query::criteria_visitor {
public: 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::between_criteria& node ) override;
void visit( const query::binary_criteria& node ) override; void visit( const query::binary_criteria& node ) override;
void visit( const query::binary_column_criteria& node ) override; void visit( const query::binary_column_criteria& node ) override;
@ -49,7 +49,7 @@ private:
private: private:
const query::schema &repo_; 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 { class session_query_builder final {
@ -60,15 +60,16 @@ public:
template<class EntityType> template<class EntityType>
utils::result<entity_query_data, query_build_error> build(query::criteria_ptr clause = {}) { utils::result<entity_query_data, query_build_error> build(query::criteria_ptr clause = {}) {
const auto info = schema_.repo().info<EntityType>(); const auto it = schema_.find(typeid(EntityType));
if (!info) { if (it == schema_.end()) {
return utils::failure(query_build_error::UnknownType); 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))}); 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 }; entity_query_data_ = { &table_info_stack_.top().table };
processed_tables_.insert({info->get().name(), entity_query_data_.root_table}); processed_tables_.insert({it->second.name(), *entity_query_data_.root_table});
try { try {
access::process(*this, info->get().prototype()); EntityType obj;
access::process(*this, obj);
if (clause) { if (clause) {
criteria_transformer transformer{schema_, processed_tables_}; criteria_transformer transformer{schema_, processed_tables_};
@ -101,45 +102,77 @@ public:
} }
template<class Pointer> 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); on_foreign_object(id, obj, attr);
} }
template<class Pointer> 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); on_foreign_object(id, obj, attr);
} }
template<typename T>
struct NoopDeleter {
void operator()(const T*) const {}
};
template<class ContainerType> template<class ContainerType>
void on_has_many(const char * /*id*/, ContainerType &, const char *join_column, const utils::foreign_attributes &attr) { void on_has_many(const char * /*id*/, ContainerType &, const char *join_column, const utils::foreign_attributes &attr) {
if (attr.fetch() == utils::fetch_type::Eager) { if (attr.fetch() != utils::fetch_type::Eager) {
const auto result = schema_.repo().basic_info(typeid(typename ContainerType::value_type::value_type)); return;
if (!result) { }
const auto it = schema_.find(typeid(typename ContainerType::value_type::value_type));
if (it == schema_.end()) {
throw query_builder_exception{query_build_error::UnknownType}; throw query_builder_exception{query_build_error::UnknownType};
} }
const auto &info = result.value().get(); auto next = processed_tables_.find(it->second.name());
auto next = processed_tables_.find(info.name());
if (next != processed_tables_.end()) { if (next != processed_tables_.end()) {
// node already processed
return; 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; 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; typename ContainerType::value_type::value_type obj;
access::process(*this , obj); access::process(*this , obj);
table_info_stack_.pop(); table_info_stack_.pop();
if (!info.has_primary_key()) { if (!it->second.node().info().has_primary_key()) {
throw query_builder_exception{query_build_error::MissingPrimaryKey}; throw query_builder_exception{query_build_error::MissingPrimaryKey};
} }
append_join( append_join(
query::column{table_info_stack_.top().table.get(), table_info_stack_.top().info.get().primary_key_attribute()->name()}, query::column{&table_info_stack_.top().table, table_info_stack_.top().info.primary_key_attribute()->name()},
query::column{next->second.get(), join_column} 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> template<class ContainerType>
@ -147,38 +180,42 @@ public:
if (attr.fetch() != utils::fetch_type::Eager) { if (attr.fetch() != utils::fetch_type::Eager) {
return; return;
} }
const auto result = schema_.repo().basic_info(typeid(typename ContainerType::value_type::value_type)); const auto result = schema_.find(typeid(typename ContainerType::value_type::value_type));
if (!result) { if (result == schema_.end()) {
throw query_builder_exception{query_build_error::UnknownType}; throw query_builder_exception{query_build_error::UnknownType};
} }
const auto &info = result.value().get(); auto next = processed_tables_.find(result->second.name());
auto next = processed_tables_.find(info.name());
if (next != processed_tables_.end()) { if (next != processed_tables_.end()) {
// attribute was already processed
return; return;
} }
auto relation = processed_tables_.find(id); auto relation = processed_tables_.find(id);
if (relation == processed_tables_.end()) { 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; typename ContainerType::value_type::value_type obj;
access::process(*this , obj); access::process(*this , obj);
table_info_stack_.pop(); 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}; throw query_builder_exception{query_build_error::MissingPrimaryKey};
} }
append_join( append_join(
query::column{table_info_stack_.top().table.get(), table_info_stack_.top().info.get().primary_key_attribute()->name()}, query::column{&table_info_stack_.top().table, table_info_stack_.top().info.primary_key_attribute()->name()},
query::column{relation->second.get(), join_column} query::column{&relation->second, join_column}
); );
append_join( append_join(
query::column{relation->second.get(), inverse_join_column}, query::column{&relation->second, inverse_join_column},
query::column{next->second.get(), info.primary_key_attribute()->name()} query::column{&next->second, result->second.node().info().primary_key_attribute()->name()}
); );
} }
@ -187,40 +224,45 @@ public:
if (attr.fetch() != utils::fetch_type::Eager) { if (attr.fetch() != utils::fetch_type::Eager) {
return; return;
} }
const auto result = schema_.repo().basic_info(typeid(typename ContainerType::value_type::value_type)); const auto result = schema_.find(typeid(typename ContainerType::value_type::value_type));
if (!result) { if (result == schema_.end()) {
throw query_builder_exception{query_build_error::UnknownType}; throw query_builder_exception{query_build_error::UnknownType};
} }
const auto &info = result.value().get(); auto next = processed_tables_.find(result->second.name());
auto next = processed_tables_.find(info.name());
if (next != processed_tables_.end()) { if (next != processed_tables_.end()) {
// attribute was already processed
return; return;
} }
auto relation = processed_tables_.find(id); auto relation = processed_tables_.find(id);
if (relation == processed_tables_.end()) { 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};
} }
table_info_stack_.push({*result, std::make_shared<query::table>(info.name(), build_alias('t', ++table_index))}); const auto t = it->second.table().as(build_alias('t', ++table_index));
next = processed_tables_.insert({info.name(), table_info_stack_.top().table}).first; relation = processed_tables_.insert({id, t}).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; typename ContainerType::value_type::value_type obj;
access::process(*this , obj); access::process(*this , obj);
table_info_stack_.pop(); 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}; throw query_builder_exception{query_build_error::MissingPrimaryKey};
} }
const auto join_columns = join_columns_collector_.collect<typename ContainerType::value_type::value_type>(); const auto join_columns = join_columns_collector_.collect<typename ContainerType::value_type::value_type>();
append_join( append_join(
query::column{table_info_stack_.top().table.get(), table_info_stack_.top().info.get().primary_key_attribute()->name()}, query::column{&table_info_stack_.top().table, table_info_stack_.top().info.primary_key_attribute()->name()},
query::column{relation->second.get(), join_columns.inverse_join_column} query::column{&relation->second, join_columns.inverse_join_column}
); );
append_join( append_join(
query::column{relation->second.get(), join_columns.join_column}, query::column{&relation->second, join_columns.join_column},
query::column{next->second.get(), info.primary_key_attribute()->name()} query::column{&next->second, result->second.node().info().primary_key_attribute()->name()}
); );
} }
@ -234,12 +276,14 @@ private:
private: private:
struct table_info { struct table_info {
std::reference_wrapper<const object::basic_object_info> info; const object::basic_object_info &info;
std::shared_ptr<query::table> table; 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::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_; const query::schema &schema_;
entity_query_data entity_query_data_{}; entity_query_data entity_query_data_{};
unsigned int column_index{0}; unsigned int column_index{0};
@ -250,30 +294,31 @@ private:
template<class Pointer> template<class Pointer>
void session_query_builder::on_foreign_object(const char *id, Pointer &, const utils::foreign_attributes &attr) { 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>(); const auto it = schema_.find(typeid(typename Pointer::value_type));
if (!info) { if (it == schema_.end()) {
throw query_builder_exception{query_build_error::UnknownType}; 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}; 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) { 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()) { if (next != processed_tables_.end()) {
return; return;
} }
table_info_stack_.push({info.value(), foreign_table}); table_info_stack_.push({info, std::move(foreign_table)});
next = processed_tables_.insert({info->get().name(), table_info_stack_.top().table}).first; next = processed_tables_.insert({info.name(), table_info_stack_.top().table}).first;
typename Pointer::value_type obj; typename Pointer::value_type obj;
access::process(*this, obj); access::process(*this, obj);
table_info_stack_.pop(); table_info_stack_.pop();
append_join( append_join(
query::column{table_info_stack_.top().table.get(), id}, query::column{&table_info_stack_.top().table, id},
query::column{next->second.get(), info->get().primary_key_attribute()->name()} query::column{&next->second, info.primary_key_attribute()->name()}
); );
} else { } else {
push(id); push(id);
@ -281,8 +326,8 @@ void session_query_builder::on_foreign_object(const char *id, Pointer &, const u
using namespace matador::query; using namespace matador::query;
// create select query // create select query
auto result = matador::query::query::select(generator::columns<typename Pointer::value_type>(schema_, generator::column_generator_options::ForceLazy)) auto result = matador::query::query::select(generator::columns<typename Pointer::value_type>(schema_, generator::column_generator_options::ForceLazy))
.from(*foreign_table) .from(foreign_table)
.where(column(foreign_table.get(), info->get().primary_key_attribute()->name(), "") == _) .where(column(&foreign_table, info.primary_key_attribute()->name(), "") == _)
.prepare(executor_); .prepare(executor_);
if (!result) { if (!result) {
throw query_builder_exception(query_build_error::QueryError, result.release_error()); throw query_builder_exception(query_build_error::QueryError, result.release_error());

View File

@ -68,25 +68,25 @@ public:
operator column() const; // NOLINT(*-explicit-constructor) operator column() const; // NOLINT(*-explicit-constructor)
column_builder& not_null(); column_builder& not_null();
column_builder& primary_key();
column_builder& unique();
private: private:
std::string column_name_; std::string column_name_;
utils::basic_type type_{}; utils::basic_type type_{};
utils::constraints constraints_{}; utils::constraints constraints_{utils::constraints::NotNull};
size_t size_{0};
}; };
class table_builder { class table_builder {
public: public:
explicit table_builder(std::string name); explicit table_builder(std::string name);
table_builder& as(std::string table_alias);
// ReSharper disable once CppNonExplicitConversionOperator // ReSharper disable once CppNonExplicitConversionOperator
operator table() const; // NOLINT(*-explicit-constructor) operator table() const; // NOLINT(*-explicit-constructor)
private: private:
std::string table_name; std::string table_name;
std::string alias;
}; };
class constraint_builder { class constraint_builder {
@ -100,16 +100,16 @@ public:
operator class constraint() const; // NOLINT(*-explicit-constructor) operator class constraint() const; // NOLINT(*-explicit-constructor)
private: private:
std::string constraint_name; std::string constraint_name_;
std::string pk_column_name; std::string column_name_;
std::string fk_column_name; std::string ref_table_name_;
std::string table_name; std::string ref_column_name_;
std::string column_name; utils::constraints type_{};
}; };
constraint_builder constraint(std::string name); constraint_builder constraint(std::string name);
// table_builder table(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 #endif //MATADOR_BUILDER_HPP

View File

@ -8,6 +8,7 @@
#include <memory> #include <memory>
#include <string> #include <string>
#include <variant>
namespace matador::query { namespace matador::query {
@ -23,6 +24,9 @@ public:
column(const class table* tab, std::string name); 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, std::string alias);
column(const class table* tab, std::string name, utils::basic_type type, const utils::field_attributes& attributes); 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; [[nodiscard]] bool equals(const column &x) const;
@ -39,18 +43,15 @@ public:
[[nodiscard]] bool has_alias() const; [[nodiscard]] bool has_alias() const;
[[nodiscard]] const class table* table() const; [[nodiscard]] const class table* table() const;
void table(const query::table* t); void table(const query::table* tab);
// ReSharper disable once CppNonExplicitConversionOperator // ReSharper disable once CppNonExplicitConversionOperator
operator const std::string&() const; // NOLINT(*-explicit-constructor) operator const std::string&() const; // NOLINT(*-explicit-constructor)
private:
static query::table* default_table();
private: private:
friend class table; friend class table;
const query::table* table_{nullptr}; const class table* table_{nullptr};
std::string name_; std::string name_;
std::string alias_; std::string alias_;
utils::basic_type type_{utils::basic_type::Unknown}; utils::basic_type type_{utils::basic_type::Unknown};

View File

@ -13,7 +13,9 @@ public:
constraint() = default; 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);
constraint(std::string column_name, std::string table_name, utils::constraints type, std::string referenced_table, std::string referenced_column); 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 column_name() const;
[[nodiscard]] std::string table_name() const; [[nodiscard]] std::string table_name() const;
[[nodiscard]] const utils::constraints& type() const; [[nodiscard]] const utils::constraints& type() const;
@ -24,6 +26,7 @@ public:
[[nodiscard]] const std::string& referenced_column() const; [[nodiscard]] const std::string& referenced_column() const;
private: private:
std::string name_;
std::string column_name_; std::string column_name_;
std::string table_name_; std::string table_name_;
utils::constraints type_{}; utils::constraints type_{};

View File

@ -10,12 +10,12 @@ namespace matador::query {
class abstract_column_criteria : public abstract_criteria { class abstract_column_criteria : public abstract_criteria {
public: public:
abstract_column_criteria() = delete; 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: protected:
column column_; class column column_;
}; };
} }

View File

@ -4,15 +4,13 @@
#include "matador/query/criteria/abstract_column_criteria.hpp" #include "matador/query/criteria/abstract_column_criteria.hpp"
#include "matador/query/criteria/criteria_utils.hpp" #include "matador/query/criteria/criteria_utils.hpp"
#include "matador/utils/value.hpp"
namespace matador::query { namespace matador::query {
class between_criteria final : public abstract_column_criteria { class between_criteria final : public abstract_column_criteria {
public: public:
between_criteria() = delete; between_criteria() = delete;
between_criteria(column col, int64_t min, int64_t max); between_criteria(const class column& col, int64_t min, int64_t max);
between_criteria(column col, utils::placeholder min, utils::placeholder max); between_criteria(const class column& col, utils::placeholder min, utils::placeholder max);
void accept(criteria_visitor& visitor) const override; void accept(criteria_visitor& visitor) const override;

View File

@ -19,7 +19,7 @@ enum class binary_operator {
class binary_criteria final : public abstract_column_criteria { class binary_criteria final : public abstract_column_criteria {
public: public:
binary_criteria() = delete; 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; void accept( criteria_visitor& visitor ) const override;
@ -34,18 +34,18 @@ private:
class binary_column_criteria final : public abstract_criteria { class binary_column_criteria final : public abstract_criteria {
public: public:
binary_column_criteria() = delete; 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; 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]] binary_operator operand() const;
[[nodiscard]] const column& right_column() const; [[nodiscard]] const class column& right_column() const;
private: private:
column left_column_; class column left_column_;
binary_operator operator_{}; binary_operator operator_{};
column right_column_; class column right_column_;
}; };
} }
#endif //CRITERIA_BINARY_CRITERIA_NODE_HPP #endif //CRITERIA_BINARY_CRITERIA_NODE_HPP

View File

@ -4,10 +4,12 @@
#include "matador/query/criteria/abstract_column_criteria.hpp" #include "matador/query/criteria/abstract_column_criteria.hpp"
#include "matador/query/criteria/criteria_utils.hpp" #include "matador/query/criteria/criteria_utils.hpp"
#include "matador/query/column.hpp" #include "matador/query/table.hpp"
#include "matador/sql/query_context.hpp" #include "matador/sql/query_context.hpp"
namespace matador::query { namespace matador::query {
class column;
enum class collection_operator { enum class collection_operator {
In, In,
Out Out
@ -36,8 +38,8 @@ public:
* @param operand_ Operator to use * @param operand_ Operator to use
* @param values List of values * @param values List of values
*/ */
collection_criteria(column col, collection_operator operand_, std::vector<criteria_value> values); collection_criteria(const class 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::initializer_list<criteria_value> values);
void accept(criteria_visitor& visitor) const override; void accept(criteria_visitor& visitor) const override;
@ -52,7 +54,7 @@ private:
class collection_query_criteria final : public abstract_column_criteria { class collection_query_criteria final : public abstract_column_criteria {
public: public:
collection_query_criteria() = delete; 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; void accept(criteria_visitor& visitor) const override;

View File

@ -14,48 +14,48 @@ namespace matador::query {
class column; class column;
template<class Type> 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)); return std::make_unique<binary_criteria>(col, binary_operator::EQUALS, utils::value(val));
} }
template<class Type> 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)); return std::make_unique<binary_criteria>(col, binary_operator::NOT_EQUALS, utils::value(val));
} }
template<class Type> 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)); return std::make_unique<binary_criteria>(col, binary_operator::GREATER_THAN, utils::value(val));
} }
template<class Type> 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)); return std::make_unique<binary_criteria>(col, binary_operator::GREATER_THAN_OR_EQUAL, utils::value(val));
} }
template<class Type> 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)); return std::make_unique<binary_criteria>(col, binary_operator::LESS_THAN, utils::value(val));
} }
template<class Type> 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)); 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 class column &col_left, const class 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 column &col_left, const column &col_right); criteria_ptr operator>(const class column &col_left, const class 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 column &col_left, const column &col_right); criteria_ptr operator<(const class column &col_left, const class 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 column &col, utils::placeholder p); criteria_ptr operator==(const class 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 column &col, utils::placeholder p); criteria_ptr operator>(const class 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 column &col, utils::placeholder p); criteria_ptr operator<(const class 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&&(criteria_ptr left, criteria_ptr right); 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); criteria_ptr operator!(criteria_ptr clause);
template < class Type > 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; std::vector<criteria_value> values;
for ( auto &&arg : args ) { for ( auto &&arg : args ) {
values.emplace_back(utils::value{std::move(arg)}); values.emplace_back(utils::value{std::move(arg)});
@ -73,12 +73,12 @@ criteria_ptr in(const column &col, std::initializer_list<Type> args) {
} }
template <> 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 > 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; std::vector<criteria_value> values;
for ( auto &&arg : args ) { for ( auto &&arg : args ) {
values.emplace_back(utils::value{std::move(arg)}); values.emplace_back(utils::value{std::move(arg)});
@ -87,14 +87,14 @@ criteria_ptr out(const column &col, std::initializer_list<Type> args) {
} }
template <> 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 class 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, 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 #endif //CRITERIA_CRITERIA_OPERATORS_HPP

View File

@ -3,13 +3,13 @@
#include "matador/query/criteria/abstract_column_criteria.hpp" #include "matador/query/criteria/abstract_column_criteria.hpp"
#include "matador/query/column.hpp"
namespace matador::query { namespace matador::query {
class column;
class like_criteria final : public abstract_column_criteria { class like_criteria final : public abstract_column_criteria {
public: public:
like_criteria() = delete; 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; void accept(criteria_visitor &visitor) const override;

View File

@ -45,8 +45,6 @@ constexpr auto default_column_generator_options = column_generator_options::Forc
class column_generator { class column_generator {
public: public:
explicit column_generator(const std::string &table_name = "",
column_generator_options options = default_column_generator_options);
explicit column_generator(const schema &repo, explicit column_generator(const schema &repo,
const std::string &table_name = "", const std::string &table_name = "",
column_generator_options options = default_column_generator_options); column_generator_options options = default_column_generator_options);
@ -322,20 +320,5 @@ std::vector<column> columns(const Type &obj,
return generator.generate(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 #endif //MATADOR_GENERATOR_HPP

View File

@ -3,19 +3,18 @@
#include "matador/query/intermediates/query_intermediate.hpp" #include "matador/query/intermediates/query_intermediate.hpp"
#include "matador/query/intermediates/query_into_intermediate.hpp" #include "matador/query/intermediates/query_into_intermediate.hpp"
#include "matador/query/schema.hpp"
#include "matador/query/generator.hpp" #include "matador/query/generator.hpp"
namespace matador::query { namespace matador::query {
class query_insert_intermediate : public query_intermediate class query_insert_intermediate : public query_intermediate {
{
public: public:
query_insert_intermediate(); query_insert_intermediate();
template<class Type> template<class Type>
query_into_intermediate into(const table &tab, const object::repository &schema) { query_into_intermediate into(const table &tab, const schema &scm) {
return into(tab, generator::columns<Type>(schema)); 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::initializer_list<column> columns);
query_into_intermediate into(const table &tab, std::vector<column> &&columns); query_into_intermediate into(const table &tab, std::vector<column> &&columns);

View File

@ -4,6 +4,7 @@
#include "matador/query/query_intermediates.hpp" #include "matador/query/query_intermediates.hpp"
#include "matador/query/generator.hpp" #include "matador/query/generator.hpp"
#include "matador/query/schema.hpp"
namespace matador::sql { namespace matador::sql {
class connection; 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(const std::vector<std::string> &column_names);
[[nodiscard]] static query_select_intermediate select(std::vector<column> columns, std::initializer_list<column> additional_columns); [[nodiscard]] static query_select_intermediate select(std::vector<column> columns, std::initializer_list<column> additional_columns);
template<class Type> template<class Type>
[[nodiscard]] static query_select_intermediate select(const object::repository &schema) { [[nodiscard]] static query_select_intermediate select(const schema &scm) {
return select(generator::columns<Type>(schema)); return select(generator::columns<Type>(scm));
} }
[[nodiscard]] static query_insert_intermediate insert(); [[nodiscard]] static query_insert_intermediate insert();
[[nodiscard]] static query_update_intermediate update(const table &table); [[nodiscard]] static query_update_intermediate update(const table &table);

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 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); 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_add_constraint_string(const class constraint& c) const;
std::string build_drop_constraint_string(const class constraint& c); std::string build_drop_constraint_string(const class constraint& c) const;
std::string build_constraint_name(const class constraint& c); static std::string build_constraint_name(const class constraint& c);
protected: protected:
const query_data *data_{}; const query_data *data_{};

View File

@ -13,7 +13,6 @@ namespace matador::query {
class column; class column;
[[nodiscard]] std::string prepare_identifier(const sql::dialect& d, const column &col); [[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); [[nodiscard]] std::string prepare_criteria(const sql::dialect& d, const column &col);
} }
#endif //MATADOR_QUERY_UTILS_HPP #endif //MATADOR_QUERY_UTILS_HPP

View File

@ -10,6 +10,7 @@
namespace matador::sql { namespace matador::sql {
class connection_pool; class connection_pool;
class connection;
} }
namespace matador::query { namespace matador::query {
@ -34,20 +35,42 @@ class schema_observer final : public object::observer<Type> {
public: public:
explicit schema_observer(schema& s) explicit schema_observer(schema& s)
: schema_(s) {} : schema_(s) {}
void on_attach(object::repository_node &node, const Type &prototype) override; template<typename OtherType>
void on_detach(object::repository_node &node, const Type &prototype) override; explicit schema_observer(const schema_observer<OtherType> &x)
void on_insert(Type &obj) override; : schema_(x.schema_)
void on_update(Type &obj) override; {}
void on_delete(Type &obj) override; 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: private:
template < class OtherType >
friend class schema_observer;
schema& schema_; 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 { class schema final {
public: public:
explicit schema(sql::connection_pool &pool); using iterator = std::unordered_map<std::type_index, schema_node>::iterator;
schema(sql::connection_pool &pool, const std::string &name); 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> template<typename Type, typename... Observers>
[[nodiscard]] utils::result<void, utils::error> attach(const std::string &name, Observers&&... 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)...); 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> create(const sql::connection &conn) const;
[[nodiscard]] utils::result<void, utils::error> drop() const; [[nodiscard]] utils::result<void, utils::error> drop(const sql::connection &conn) const;
template<typename Type> template<typename Type>
[[nodiscard]] utils::result<void, utils::error> drop_table(); [[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; [[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<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; [[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_; } const object::repository &repo() const { return repo_; }
object::repository &repo() { return repo_; }
private: private:
[[nodiscard]] sql::query_context build_add_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; [[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); void insert_table(const std::type_index& ti, const object::repository_node &node);
@ -87,31 +122,30 @@ private:
friend class schema_observer; friend class schema_observer;
object::repository repo_; object::repository repo_;
std::unordered_map<std::type_index, table> tables_; std::unordered_map<std::type_index, schema_node> schema_nodes_;
sql::connection_pool &pool_;
}; };
template<typename Type> 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>(); auto info = repo_.info<Type>();
if (info) { if (info) {
return drop_table(info->get().name()); return drop_table(info->get().name(), conn);
} }
return utils::failure(info.err()); return utils::failure(info.err());
} }
template <typename Type> 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); schema_.insert_table(typeid(Type), node);
} }
template <typename Type> 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> template <typename Type>
void schema_observer<Type>::on_insert(Type &obj) {} void schema_observer<Type>::on_insert(const Type &/*obj*/) {}
template <typename Type> template <typename Type>
void schema_observer<Type>::on_update(Type &obj) {} void schema_observer<Type>::on_update(const Type &/*obj*/) {}
template <typename Type> template <typename Type>
void schema_observer<Type>::on_delete(Type &obj) {} void schema_observer<Type>::on_delete(const Type &/*obj*/) {}
} // namespace matador::query } // namespace matador::query
#endif //MATADOR_SCHEMA_HPP #endif //MATADOR_SCHEMA_HPP

View File

@ -13,24 +13,36 @@ class table {
public: public:
table() = default; table() = default;
table(const char *name); // NOLINT(*-explicit-constructor) table(const char *name); // NOLINT(*-explicit-constructor)
table(std::string name); // NOLINT(*-explicit-constructor) table(const std::string& name); // NOLINT(*-explicit-constructor)
table(std::string name, std::string as); table(const std::string& name, const std::vector<column>& columns);
table(std::string name, std::string as, 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]] 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]] 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 // ReSharper disable once CppNonExplicitConversionOperator
operator const std::vector<query::column>&() const; // NOLINT(*-explicit-constructor) 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: private:
friend class column; friend class column;

View File

@ -9,16 +9,17 @@
#include <string> #include <string>
#include <ostream> #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, ...) \ #define QUERY_HELPER(C, V, ...) \
namespace matador::query::meta { \ namespace matador::query::meta { \
namespace internal { \ namespace internal { \
struct C##_query : table { \ class C##_table : public table { \
C##_query() : table(#C) {} \ public: \
C##_table() : table(#C) {} \
MAP(FIELD, __VA_ARGS__) \ MAP(FIELD, __VA_ARGS__) \
}; } \ }; } \
static const internal:: C##_query V; \ static const internal:: C##_table V; \
} }
#endif //QUERY_QUERY_HELPER_HPP #endif //QUERY_QUERY_HELPER_HPP

View File

@ -108,6 +108,8 @@ add_library(matador-core STATIC
utils/uuid.cpp utils/uuid.cpp
utils/value.cpp utils/value.cpp
utils/version.cpp utils/version.cpp
../../include/matador/object/internal/observer_list_creator.hpp
../../include/matador/object/internal/observer_list_copy_creator.hpp
) )
target_link_libraries(matador-core ${CMAKE_DL_LIBS}) target_link_libraries(matador-core ${CMAKE_DL_LIBS})

View File

@ -16,8 +16,8 @@ attribute::attribute(std::string name,
: name_(std::move(name)) : name_(std::move(name))
, type_(type) , type_(type)
, options_(attr) , options_(attr)
, null_option_(null_opt) , null_option_(null_opt) {
{} }
const std::string &attribute::name() const { const std::string &attribute::name() const {
return name_; return name_;

View File

@ -4,7 +4,7 @@
#include "matador/object/repository_node.hpp" #include "matador/object/repository_node.hpp"
namespace matador::object::internal { namespace matador::object::internal {
shadow_repository::shadow_repository( repository& s ) shadow_repository::shadow_repository(repository& s)
: repo_(s) {} : repo_(s) {}
repository& shadow_repository::repo() const { repository& shadow_repository::repo() const {
@ -62,4 +62,20 @@ std::shared_ptr<object> shadow_repository::object_for_type(const std::type_index
void shadow_repository::remove_object_for_type(const std::type_index& ti) const { void shadow_repository::remove_object_for_type(const std::type_index& ti) const {
repo_.remove_object_for_type(ti); repo_.remove_object_for_type(ti);
} }
bool shadow_repository::is_node_announced(const std::type_index &ti) const {
return repo_.is_node_announced(ti);
}
void shadow_repository::push_announce_node(const std::type_index &ti, const node_ptr &node) const {
repo_.push_announce_node(ti, node);
}
shadow_repository::node_ptr shadow_repository::announce_node(const std::type_index &ti) const {
return repo_.announce_node(ti);
}
shadow_repository::node_ptr shadow_repository::pop_announce_node(const std::type_index &ti) const {
return repo_.pop_announce_node(ti);
}
} }

View File

@ -5,7 +5,7 @@
#include <algorithm> #include <algorithm>
namespace matador::object { namespace matador::object {
object_generator::object_generator(repository& repo, const std::shared_ptr<object>& object) object_generator::object_generator(const repository& repo, const std::shared_ptr<object>& object)
: repo_(repo) : repo_(repo)
, object_(object) {} , object_(object) {}

View File

@ -104,8 +104,7 @@ void repository::dump( std::ostream& os, const node_ptr& node ) {
} }
} }
utils::result<repository::node_ptr, utils::error> repository::attach_node(const std::shared_ptr<repository_node> &node, utils::result<repository::node_ptr, utils::error> repository::attach_node(const std::shared_ptr<repository_node> &node, const std::string &parent) {
const std::string &parent) {
if (has_node(node)) { if (has_node(node)) {
return utils::failure(make_error(error_code::NodeAlreadyExists, "Node '" + node->name() + "' already exists.")); return utils::failure(make_error(error_code::NodeAlreadyExists, "Node '" + node->name() + "' already exists."));
} }
@ -233,4 +232,24 @@ std::shared_ptr<object> repository::object_for_type(const std::type_index &ti) c
void repository::remove_object_for_type(const std::type_index &ti) { void repository::remove_object_for_type(const std::type_index &ti) {
object_by_type_.erase(ti); object_by_type_.erase(ti);
} }
bool repository::is_node_announced(const std::type_index &ti) const {
return announced_node_.count(ti) > 0;
}
void repository::push_announce_node(const std::type_index &ti, const node_ptr &node) {
announced_node_.insert({ti, node});
}
repository::node_ptr repository::announce_node(const std::type_index &ti) {
return announced_node_.find(ti)->second;
}
repository::node_ptr repository::pop_announce_node(const std::type_index &ti) {
const auto it = announced_node_.find(ti);
if (it != announced_node_.end()) {
announced_node_.erase(it);
}
return it->second;
}
} // namespace matador::object } // namespace matador::object

View File

@ -99,10 +99,4 @@ void repository_node::unlink() {
next_sibling_.reset(); next_sibling_.reset();
previous_sibling_.reset(); previous_sibling_.reset();
} }
utils::result<repository_node::node_ptr, utils::error> repository_node::make_and_attach_node(repository& repo, const std::string& name, const std::type_index& ti) {
const auto node = std::shared_ptr<repository_node>(new repository_node(repo, name, ti));
return repo.attach_node(node, "");
}
} }

View File

@ -227,7 +227,7 @@ query::fetchable_query session::build_select_query(entity_query_data &&data) {
.from(*data.root_table) .from(*data.root_table)
.join_left(data.joins) .join_left(data.joins)
.where(std::move(data.where_clause)) .where(std::move(data.where_clause))
.order_by({data.root_table.get(), data.pk_column_name}) .order_by({data.root_table, data.pk_column_name})
.asc(); .asc();
} }
} }

View File

@ -3,7 +3,7 @@
#include <iostream> #include <iostream>
namespace matador::orm { namespace matador::orm {
criteria_transformer::criteria_transformer(const query::schema& repo, const std::unordered_map<std::string, std::shared_ptr<query::table>>& tables_by_name) criteria_transformer::criteria_transformer(const query::schema& repo, const std::unordered_map<std::string, query::table>& tables_by_name)
: repo_(repo) : repo_(repo)
, tables_by_name_(tables_by_name) {} , tables_by_name_(tables_by_name) {}
@ -39,12 +39,15 @@ void criteria_transformer::visit( const query::not_criteria& node ) {
} }
void criteria_transformer::update_criteria_column(const query::abstract_column_criteria& node) const { void criteria_transformer::update_criteria_column(const query::abstract_column_criteria& node) const {
if (node.col().table() == nullptr) {
return;
}
const auto it = tables_by_name_.find(node.col().table()->name()); const auto it = tables_by_name_.find(node.col().table()->name());
if (it == tables_by_name_.end()) { if (it == tables_by_name_.end()) {
return; return;
} }
const_cast<query::column&>(node.col()).table(it->second.get()); const_cast<query::column&>(node.col()).table(&it->second);
} }
void session_query_builder::on_revision(const char *id, uint64_t &/*rev*/) { void session_query_builder::on_revision(const char *id, uint64_t &/*rev*/) {
@ -52,11 +55,11 @@ void session_query_builder::on_revision(const char *id, uint64_t &/*rev*/) {
} }
void session_query_builder::push(const std::string &column_name) { void session_query_builder::push(const std::string &column_name) {
const auto it = processed_tables_.find(table_info_stack_.top().info.get().name()); const auto it = processed_tables_.find(table_info_stack_.top().info.name());
if (it == processed_tables_.end()) { if (it == processed_tables_.end()) {
throw query_builder_exception{query_build_error::UnexpectedError}; throw query_builder_exception{query_build_error::UnexpectedError};
} }
entity_query_data_.columns.emplace_back(it->second.get(), column_name, build_alias('c', ++column_index)); entity_query_data_.columns.emplace_back(&it->second, column_name, build_alias('c', ++column_index));
} }
std::string session_query_builder::build_alias(const char prefix, const unsigned int count) { std::string session_query_builder::build_alias(const char prefix, const unsigned int count) {

View File

@ -4,52 +4,61 @@ namespace matador::query {
column_builder::column_builder(std::string column_name, const utils::basic_type type, const size_t size) column_builder::column_builder(std::string column_name, const utils::basic_type type, const size_t size)
: column_name_(std::move(column_name)) : column_name_(std::move(column_name))
, type_(type){} , type_(type)
, size_(size) {}
column_builder::operator class query::column() const { column_builder::operator class query::column() const {
return {column_name_}; return {nullptr, column_name_, type_, {size_, constraints_}};
} }
column_builder& column_builder::not_null() { column_builder& column_builder::not_null() {
constraints_ |= utils::constraints::NotNull;
return *this;
}
column_builder & column_builder::primary_key() {
constraints_ |= utils::constraints::PrimaryKey;
return *this;
}
column_builder & column_builder::unique() {
constraints_ |= utils::constraints::Unique;
return *this; return *this;
} }
table_builder::table_builder(std::string name) table_builder::table_builder(std::string name)
: table_name( std::move(name) ) {} : table_name( std::move(name) ) {}
table_builder& table_builder::as( std::string table_alias ) {
this->alias = std::move(table_alias);
return *this;
}
table_builder::operator class query::table() const { table_builder::operator class query::table() const {
return {table_name, alias, {}}; return {table_name, {}};
} }
constraint_builder& constraint_builder::constraint( std::string name ) { constraint_builder& constraint_builder::constraint( std::string name ) {
constraint_name = std::move(name); constraint_name_ = std::move(name);
return *this; return *this;
} }
constraint_builder& constraint_builder::primary_key( std::string name ) { constraint_builder& constraint_builder::primary_key( std::string name ) {
pk_column_name = std::move(name); column_name_ = std::move(name);
type_ = utils::constraints::PrimaryKey;
return *this; return *this;
} }
constraint_builder& constraint_builder::foreign_key( std::string name ) { constraint_builder& constraint_builder::foreign_key( std::string name ) {
fk_column_name = std::move(name); column_name_ = std::move(name);
type_ = utils::constraints::ForeignKey;
return *this; return *this;
} }
constraint_builder& constraint_builder::references( std::string table, std::string column ) { constraint_builder& constraint_builder::references( std::string table, std::string column ) {
this->table_name = std::move(table); this->ref_table_name_ = std::move(table);
this->column_name = std::move(column); this->ref_column_name_ = std::move(column);
return *this; return *this;
} }
constraint_builder::operator class constraint() const { constraint_builder::operator class constraint() const {
return {}; return {constraint_name_, column_name_, ref_table_name_, type_, ref_table_name_, ref_column_name_};
} }
constraint_builder constraint( std::string name ) { constraint_builder constraint( std::string name ) {

View File

@ -18,7 +18,7 @@ column operator ""_col(const char *name, const size_t len) {
throw std::invalid_argument("Invalid column name: multiple dots found"); throw std::invalid_argument("Invalid column name: multiple dots found");
} }
return column{new table(str.substr(0, pos)), str.substr(pos + 1)}; return column{str.substr(pos + 1)};
} }
column::column(const char *name) column::column(const char *name)
@ -26,27 +26,25 @@ column::column(const char *name)
{} {}
column::column(std::string name) column::column(std::string name)
: table_(default_table()) : name_(std::move(name)) {}
, name_(std::move(name)) {}
column::column(std::string name, std::string alias) column::column(std::string name, std::string alias)
: table_(default_table()) : name_(std::move(name))
, name_(std::move(name))
, alias_(std::move(alias)) {} , alias_(std::move(alias)) {}
column::column(const sql::sql_function_t func, std::string name) column::column(const sql::sql_function_t func, std::string name)
: table_(default_table()) : name_(std::move(name))
, name_(std::move(name))
, function_(func) {} , function_(func) {}
column::column(const class table* tab, std::string name) column::column(const class table* tab, std::string name)
: table_(tab) : table_(tab)
, name_(std::move(name)) {} , name_(std::move(name)) {}
column::column(const class query::table* tab, std::string name, std::string alias) column::column(const class table* tab, std::string name, std::string alias)
: table_(tab) : table_(tab)
, name_(std::move(name)) , name_(std::move(name))
, alias_(std::move(alias)) {} , alias_(std::move(alias)) {}
column::column(const class query::table* tab, std::string name, column::column(const class table* tab,
std::string name,
const utils::basic_type type, const utils::basic_type type,
const utils::field_attributes& attributes) const utils::field_attributes& attributes)
: table_(tab) : table_(tab)
@ -54,16 +52,53 @@ column::column(const class query::table* tab, std::string name,
, type_(type) , type_(type)
, attributes_(attributes) {} , attributes_(attributes) {}
column::column(const class table* tab,
std::string name,
std::string alias,
utils::basic_type type,
const utils::field_attributes &attributes)
: table_(tab)
, name_(std::move(name))
, alias_(std::move(alias))
, type_(type)
, attributes_(attributes) {}
column & column::operator=(const column &other) {
if (this == &other) {
return *this;
}
table_ = other.table_;
name_ = other.name_;
alias_ = other.alias_;
type_ = other.type_;
attributes_ = other.attributes_;
return *this;
}
column::column(const column &other)
: table_(other.table_)
, name_(other.name_)
, alias_(other.alias_)
, type_(other.type_)
, attributes_(other.attributes_) {
}
bool column::equals(const column &x) const { bool column::equals(const column &x) const {
if (table_ != nullptr && x.table_ != nullptr) {
return *table_ == *x.table_ && return *table_ == *x.table_ &&
name_ == x.name_ && name_ == x.name_ &&
alias_ == x.alias_ && alias_ == x.alias_ &&
function_ == x.function_; function_ == x.function_;
}
return name_ == x.name_ &&
alias_ == x.alias_ &&
function_ == x.function_;
} }
column column::as(std::string a) { column column::as(std::string a) {
alias_ = std::move(a); alias_ = std::move(a);
return *this; return {table_, name_, alias_, type_, attributes_};
} }
const std::string& column::name() const { const std::string& column::name() const {
@ -109,10 +144,4 @@ void column::table(const query::table* tab) {
column::operator const std::string&() const { column::operator const std::string&() const {
return name_; return name_;
} }
query::table* column::default_table() {
static query::table default_table;
return &default_table;
}
} }

View File

@ -15,6 +15,23 @@ constraint::constraint(std::string column_name, std::string table_name, utils::c
, referenced_table_(std::move(referenced_table)) , referenced_table_(std::move(referenced_table))
, referenced_column_(std::move(referenced_column)) {} , referenced_column_(std::move(referenced_column)) {}
constraint::constraint(std::string name,
std::string column_name,
std::string table_name,
utils::constraints type,
std::string referenced_table,
std::string referenced_column)
: name_(std::move(name))
, column_name_(std::move(column_name))
, table_name_(std::move(table_name))
, type_(type)
, referenced_table_(std::move(referenced_table))
, referenced_column_(std::move(referenced_column)) {}
std::string constraint::name() const {
return name_;
}
std::string constraint::column_name() const { std::string constraint::column_name() const {
return column_name_; return column_name_;
} }

View File

@ -1,8 +1,8 @@
#include "matador/query/criteria/abstract_column_criteria.hpp" #include "matador/query/criteria/abstract_column_criteria.hpp"
namespace matador::query { namespace matador::query {
abstract_column_criteria::abstract_column_criteria(column col) abstract_column_criteria::abstract_column_criteria(const class column& col)
: column_(std::move(col)) {} : column_(col) {}
const column& abstract_column_criteria::col() const { const column& abstract_column_criteria::col() const {
return column_; return column_;

View File

@ -3,14 +3,14 @@
#include "matador/query/criteria/criteria_visitor.hpp" #include "matador/query/criteria/criteria_visitor.hpp"
namespace matador::query{ namespace matador::query{
between_criteria::between_criteria(column col, const int64_t min, const int64_t max) between_criteria::between_criteria(const class column& col, const int64_t min, const int64_t max)
: abstract_column_criteria(std::move(col)) : abstract_column_criteria(col)
, min_(utils::value{min}) , min_(utils::value{min})
, max_(utils::value{max}) , max_(utils::value{max})
{} {}
between_criteria::between_criteria(column col, utils::placeholder min, utils::placeholder max) between_criteria::between_criteria(const class column& col, utils::placeholder min, utils::placeholder max)
: abstract_column_criteria(std::move(col)) : abstract_column_criteria(col)
, min_(min) , min_(min)
, max_(max) , max_(max)
{} {}

View File

@ -3,8 +3,8 @@
#include "matador/query/criteria/criteria_visitor.hpp" #include "matador/query/criteria/criteria_visitor.hpp"
namespace matador::query { namespace matador::query {
binary_criteria::binary_criteria(column col, const binary_operator operand, criteria_value value) binary_criteria::binary_criteria(const class column& col, const binary_operator operand, criteria_value value)
: abstract_column_criteria(std::move(col)) : abstract_column_criteria(col)
, operator_(operand) , operator_(operand)
, value_(std::move(value)) , value_(std::move(value))
{} {}
@ -21,16 +21,16 @@ const criteria_value& binary_criteria::value() const {
return value_; return value_;
} }
binary_column_criteria::binary_column_criteria(column left_column, binary_operator operand, column right_column) binary_column_criteria::binary_column_criteria(const class column& left_column, const binary_operator operand, const class column& right_column)
: left_column_(std::move(left_column)) : left_column_(left_column)
, operator_(operand) , operator_(operand)
, right_column_(std::move(right_column)){} , right_column_(right_column){}
void binary_column_criteria::accept(criteria_visitor& visitor) const { void binary_column_criteria::accept(criteria_visitor& visitor) const {
visitor.visit(*this); visitor.visit(*this);
} }
const column& binary_column_criteria::left_column() const { const class column& binary_column_criteria::left_column() const {
return left_column_; return left_column_;
} }
@ -38,7 +38,7 @@ binary_operator binary_column_criteria::operand() const {
return operator_; return operator_;
} }
const column& binary_column_criteria::right_column() const { const class column& binary_column_criteria::right_column() const {
return right_column_; return right_column_;
} }
} }

View File

@ -1,16 +1,17 @@
#include "matador/query/criteria/collection_criteria.hpp" #include "matador/query/criteria/collection_criteria.hpp"
#include "matador/query/criteria/criteria_visitor.hpp" #include "matador/query/criteria/criteria_visitor.hpp"
#include "matador/query/column.hpp"
namespace matador::query { namespace matador::query {
collection_criteria::collection_criteria(column col, const collection_operator operand_, std::vector<criteria_value> values ) collection_criteria::collection_criteria(const class column& col, const collection_operator operand_, std::vector<criteria_value> values )
: abstract_column_criteria(std::move(col)) : abstract_column_criteria(col)
, operand_(operand_) , operand_(operand_)
, values_(std::move(values)) , values_(std::move(values))
{} {}
collection_criteria::collection_criteria(column col, const collection_operator operand_, const std::initializer_list<criteria_value> values ) collection_criteria::collection_criteria(const class column& col, const collection_operator operand_, const std::initializer_list<criteria_value> values )
: abstract_column_criteria(std::move(col)) : abstract_column_criteria(col)
, operand_(operand_) , operand_(operand_)
, values_(values) , values_(values)
{} {}
@ -27,8 +28,8 @@ const std::vector<criteria_value>& collection_criteria::values() const {
return values_; return values_;
} }
collection_query_criteria::collection_query_criteria(column col, collection_operator operand_, sql::query_context ctx) collection_query_criteria::collection_query_criteria(const class column& col, collection_operator operand_, sql::query_context ctx)
: abstract_column_criteria(std::move(col)) : abstract_column_criteria(col)
, operand_(operand_) , operand_(operand_)
, query_context_(std::move(ctx)){ , query_context_(std::move(ctx)){
} }

View File

@ -1,10 +1,11 @@
#include "matador/query/criteria/like_criteria.hpp" #include "matador/query/criteria/like_criteria.hpp"
#include "matador/query/criteria/criteria_visitor.hpp" #include "matador/query/criteria/criteria_visitor.hpp"
#include "matador/query/column.hpp"
namespace matador::query { namespace matador::query {
like_criteria::like_criteria(column col, std::string pattern) like_criteria::like_criteria(const class column& col, std::string pattern)
: abstract_column_criteria(std::move(col)) : abstract_column_criteria(col)
, pattern_(std::move(pattern)){} , pattern_(std::move(pattern)){}
void like_criteria::accept(criteria_visitor &visitor) const { void like_criteria::accept(criteria_visitor &visitor) const {

View File

@ -1,11 +1,6 @@
#include "matador/query/generator.hpp" #include "matador/query/generator.hpp"
namespace matador::query::generator { namespace matador::query::generator {
column_generator::column_generator(const std::string& table_name, const column_generator_options options)
: options_(options) {
table_stack_.push(table_name.empty() ? std::make_shared<table>() : std::make_shared<table>(table_name));
}
column_generator::column_generator(const schema& repo, const std::string& table_name, const column_generator_options options) column_generator::column_generator(const schema& repo, const std::string& table_name, const column_generator_options options)
: repo_(std::cref(repo)) : repo_(std::cref(repo))
, options_(options) { , options_(options) {

View File

@ -4,6 +4,8 @@
#include "matador/query/constraint.hpp" #include "matador/query/constraint.hpp"
#include "matador/object/object.hpp"
#include <vector> #include <vector>
namespace matador::query { namespace matador::query {
@ -26,41 +28,55 @@ executable_query query_create_table_columns_intermediate::constraints(const std:
return this->constraints(std::list(constraints)); return this->constraints(std::list(constraints));
} }
executable_query query_create_table_columns_intermediate::constraints(std::initializer_list<constraint> constraints) { executable_query query_create_table_columns_intermediate::constraints(const std::initializer_list<constraint> constraints) {
return {context_}; return this->constraints(std::list(constraints));
} }
executable_query query_create_table_columns_intermediate::constraints(const std::list<constraint>& restrictions){ executable_query query_create_table_columns_intermediate::constraints(const std::list<constraint>& constraints){
context_->parts.push_back(std::make_unique<internal::query_create_table_constraints_part>(constraints));
return {context_}; return {context_};
} }
executable_query query_create_table_columns_intermediate::constraints(const std::list<object::restriction>& restrictions) { executable_query query_create_table_columns_intermediate::constraints(const std::list<object::restriction>& restrictions) {
std::list<constraint> constraints; std::list<constraint> constraints;
for ( const auto& restr : restrictions ) { for (const auto& restr : restrictions) {
if (restr.is_primary_key_constraint()) {
constraints.emplace_back(restr.column_name(), restr.owner()->name(), restr.attribute().attributes().options());
} else if (restr.is_foreign_key_constraint()) {
constraints.emplace_back(restr.column_name(), restr.owner()->name(), restr.attribute().attributes().options(), restr.ref_table_name(), restr.ref_column_name());
} else if (restr.is_unique_constraint()) {
constraints.emplace_back(restr.column_name(), restr.owner()->name(), restr.attribute().attributes().options());
}
} }
context_->parts.push_back(std::make_unique<internal::query_create_table_constraints_part>(constraints)); context_->parts.push_back(std::make_unique<internal::query_create_table_constraints_part>(constraints));
return {context_}; return {context_};
} }
query_create_table_columns_intermediate query_create_table_intermediate::columns(std::initializer_list<object::attribute> attributes) { query_create_table_columns_intermediate query_create_table_intermediate::columns(const std::initializer_list<object::attribute> attributes) {
return columns(std::list(attributes)); return columns(std::list(attributes));
} }
query_create_table_columns_intermediate query_create_table_intermediate::columns(const std::list<object::attribute>& attributes) { query_create_table_columns_intermediate query_create_table_intermediate::columns(const std::list<object::attribute>& attributes) {
std::list<column> columns; std::list<column> columns;
for (const auto& attr : attributes) { for (const auto& attr : attributes) {
auto options = attr.attributes().options();
if (!attr.is_nullable()) {
options |= utils::constraints::NotNull;
}
columns.emplace_back(nullptr, attr.name(), attr.type(), utils::field_attributes{attr.attributes().size(), options});
} }
context_->parts.push_back(std::make_unique<internal::query_create_table_columns_part>(columns)); context_->parts.push_back(std::make_unique<internal::query_create_table_columns_part>(columns));
return {context_}; return {context_};
} }
query_create_table_columns_intermediate query_create_table_intermediate::columns(std::initializer_list<column> columns) { query_create_table_columns_intermediate query_create_table_intermediate::columns(std::initializer_list<column> columns) {
return {context_}; return this->columns(std::list(columns));
} }
query_create_table_columns_intermediate query_create_table_intermediate::columns(const std::list<column>& columns) { query_create_table_columns_intermediate query_create_table_intermediate::columns(const std::list<column>& columns) {
context_->parts.push_back(std::make_unique<internal::query_create_table_columns_part>(columns));
return {context_}; return {context_};
} }
} }

View File

@ -45,8 +45,11 @@ std::string handle_column(sql::query_context &ctx, const sql::dialect *d, const
ctx.prototype.emplace_back(col.name()); ctx.prototype.emplace_back(col.name());
} }
if (col.table() != nullptr) {
if (const auto it = data.tables.find(col.table()->name()); it != data.tables.end()) { if (const auto it = data.tables.find(col.table()->name()); it != data.tables.end()) {
return prepare_identifier(*d, it->second, {col.name(), col.alias()}); return prepare_identifier(*d,{&it->second, col.name(), col.alias()});
}
} }
return prepare_identifier(*d, col); return prepare_identifier(*d, col);
@ -125,7 +128,7 @@ void query_compiler::visit(internal::query_drop_key_constraint_part_by_name& par
query_.sql += " " + dialect_->token_at(part.token()) + " " + part.name(); query_.sql += " " + dialect_->token_at(part.token()) + " " + part.name();
} }
void query_compiler::visit(internal::query_drop_key_constraint_part_by_constraint& part) { void query_compiler::visit(internal::query_drop_key_constraint_part_by_constraint& /*part*/) {
} }
void query_compiler::visit(internal::query_select_part &part) { void query_compiler::visit(internal::query_select_part &part) {
@ -158,8 +161,7 @@ void query_compiler::visit(internal::query_from_part &part) {
query_.sql += " " + build_table_name(part.token(), *dialect_, part.table()); query_.sql += " " + build_table_name(part.token(), *dialect_, part.table());
} }
void query_compiler::visit(internal::query_join_part &part) void query_compiler::visit(internal::query_join_part &part) {
{
query_.sql += " " + build_table_name(part.token(), *dialect_, part.table()); query_.sql += " " + build_table_name(part.token(), *dialect_, part.table());
} }
@ -403,9 +405,9 @@ std::string build_create_column(const column &col, const sql::dialect &d) {
std::string build_constraint(const constraint& cons, const sql::dialect& d) { std::string build_constraint(const constraint& cons, const sql::dialect& d) {
std::string result; std::string result;
// if (!cons.name().empty()) { if (!cons.name().empty()) {
// result.append(d.constraint()).append(" ").append(cons.name()).append(" "); result.append(d.constraint()).append(" ").append(cons.name()).append(" ");
// } }
if (cons.is_primary_key_constraint()) { if (cons.is_primary_key_constraint()) {
result result
.append(d.primary_key()) .append(d.primary_key())
@ -432,11 +434,11 @@ std::string build_constraint(const constraint& cons, const sql::dialect& d) {
std::string query_compiler::build_table_name(const sql::dialect_token token, const sql::dialect &d, const table& t) { std::string query_compiler::build_table_name(const sql::dialect_token token, const sql::dialect &d, const table& t) {
return d.token_at(token) + " " + return d.token_at(token) + " " +
(!d.default_schema_name().empty() ? d.prepare_identifier_string(d.default_schema_name()) + "." : "") + (!d.default_schema_name().empty() ? d.prepare_identifier_string(d.default_schema_name()) + "." : "") +
d.prepare_identifier_string(t.name()) + d.prepare_identifier_string(t.table_name()) +
(t.alias().empty() ? "" : " " + d.prepare_identifier_string(t.alias())); (!t.has_alias() ? "" : " " + d.prepare_identifier_string(t.name()));
} }
std::string query_compiler::build_add_constraint_string(const class constraint &c) { std::string query_compiler::build_add_constraint_string(const class constraint &c) const {
std::string result = dialect_->add_constraint() + " " + build_constraint_name(c) + " "; std::string result = dialect_->add_constraint() + " " + build_constraint_name(c) + " ";
if (c.is_primary_key_constraint()) { if (c.is_primary_key_constraint()) {
result.append(dialect_->primary_key()).append(" (").append(c.column_name()).append(")"); result.append(dialect_->primary_key()).append(" (").append(c.column_name()).append(")");
@ -448,7 +450,7 @@ std::string query_compiler::build_add_constraint_string(const class constraint &
return result; return result;
} }
std::string query_compiler::build_drop_constraint_string(const class constraint &c) { std::string query_compiler::build_drop_constraint_string(const class constraint &c) const {
return dialect_->drop_constraint() + " " + build_constraint_name(c); return dialect_->drop_constraint() + " " + build_constraint_name(c);
} }

View File

@ -3,15 +3,11 @@
#include "matador/query/table.hpp" #include "matador/query/table.hpp"
namespace matador::query { namespace matador::query {
std::string prepare_identifier( const sql::dialect& d, const column& col ) { std::string prepare_identifier(const sql::dialect& d, const column& col) {
return prepare_identifier(d, *col.table(), col);
}
std::string prepare_identifier( const sql::dialect& d, const table& tab, const column& col ) {
std::string result; std::string result;
if (!col.is_function()) { if (!col.is_function()) {
if (!tab.name().empty()) { if (col.table()) {
result = d.prepare_identifier_string(tab.has_alias() ? tab.alias() : tab.name()) + "."; result = d.prepare_identifier_string(col.table()->name()) + ".";
} }
result += d.prepare_identifier_string(col.name()); result += d.prepare_identifier_string(col.name());
} else { } else {
@ -26,14 +22,10 @@ std::string prepare_identifier( const sql::dialect& d, const table& tab, const c
std::string prepare_criteria(const sql::dialect& d, const column& col) { std::string prepare_criteria(const sql::dialect& d, const column& col) {
std::string result; std::string result;
if (!col.is_function()) { if (!col.is_function()) {
// if (!col.alias.empty()) { if (col.table()) {
// result = col.alias; result = d.prepare_identifier_string(col.table()->name()) + ".";
// } else {
if (!col.table()->name().empty()) {
result = d.prepare_identifier_string(col.table()->has_alias() ? col.table()->alias() : col.table()->name()) + ".";
} }
result += d.prepare_identifier_string(col.name()); result += d.prepare_identifier_string(col.name());
// }
} else { } else {
result = d.sql_function_at(col.function()) + "(" + col.name() + ")"; result = d.sql_function_at(col.function()) + "(" + col.name() + ")";
} }

View File

@ -1,3 +1,5 @@
#include <utility>
#include "matador/query/schema.hpp" #include "matador/query/schema.hpp"
#include "matador/query/query.hpp" #include "matador/query/query.hpp"
@ -7,19 +9,30 @@
#include "matador/sql/backend_provider.hpp" #include "matador/sql/backend_provider.hpp"
#include "matador/sql/connection_pool.hpp" #include "matador/sql/connection_pool.hpp"
#include "matador/sql/dialect.hpp" #include "matador/sql/dialect.hpp"
#include "matador/sql/error_code.hpp"
namespace matador::query { namespace matador::query {
schema::schema(sql::connection_pool& pool) schema_node::schema_node(class table tab, const object::repository_node& node)
: repo_(sql::backend_provider::instance().connection_dialect(pool.info().type).default_schema_name()) : table_(std::move(tab))
, pool_(pool) { , node_(std::move(node)) {
} }
schema::schema(sql::connection_pool &pool, const std::string& name) const std::string & schema_node::name() const {
: repo_(name) return table_.name();
, pool_(pool) {} }
utils::result<void, utils::error> schema::create() const { const table &schema_node::table() const {
return table_;
}
const object::repository_node& schema_node::node() const {
return node_;
}
schema::schema(const std::string &name)
: repo_(name) {
}
utils::result<void, utils::error> schema::create(const sql::connection &conn) const {
// Step 1: Build dependency graph // Step 1: Build dependency graph
// std::unordered_map<std::string, std::vector<std::string> > dependency_graph; // std::unordered_map<std::string, std::vector<std::string> > dependency_graph;
// std::unordered_map<std::string, std::pair<int,object::repository::node_ptr>> in_degree; // std::unordered_map<std::string, std::pair<int,object::repository::node_ptr>> in_degree;
@ -50,9 +63,8 @@ utils::result<void, utils::error> schema::create() const {
// } // }
std::vector<std::string> fk_sql_commands; std::vector<std::string> fk_sql_commands;
const auto c = pool_.acquire();
const auto q = query::query::create().schema( repo_.name() ).compile( *c ); const auto q = query::query::create().schema(repo_.name()).compile(conn);
std::cout << q.sql << std::endl; std::cout << q.sql << std::endl;
// create plain tables without constraints // create plain tables without constraints
@ -61,38 +73,38 @@ utils::result<void, utils::error> schema::create() const {
.table(node->name()) .table(node->name())
.columns(node->info().attributes()) .columns(node->info().attributes())
// .constraints(node->info().constraints()) // .constraints(node->info().constraints())
.compile(*c); .compile(conn);
std::cout << ctx.sql << std::endl; std::cout << ctx.sql << std::endl;
if (auto result = c->execute(ctx.sql); !result) { if (auto result = conn.execute(ctx.sql); !result) {
return utils::failure(result.err()); return utils::failure(result.err());
} }
} }
// create primary key constraints // create primary key constraints
for (const auto &node: repo_) { for (const auto &node: repo_) {
for (const auto& cons : node->info().constraints()) { for (const auto &cons: node->info().constraints()) {
if (!cons.is_primary_key_constraint()) { if (!cons.is_primary_key_constraint()) {
continue; continue;
} }
auto ctx = build_add_constraint_context(*node, cons); auto ctx = build_add_constraint_context(*node, cons, conn);
std::cout << ctx.sql << std::endl; std::cout << ctx.sql << std::endl;
if (auto result = c->execute(ctx.sql); !result) { if (auto result = conn.execute(ctx.sql); !result) {
return utils::failure(result.err()); return utils::failure(result.err());
} }
} }
} }
// create table constraints // create table constraints
for (const auto &node: repo_) { for (const auto &node: repo_) {
for (const auto& cons : node->info().constraints()) { for (const auto &cons: node->info().constraints()) {
if (cons.is_primary_key_constraint()) { if (cons.is_primary_key_constraint()) {
continue; continue;
} }
auto ctx = build_add_constraint_context(*node, cons); auto ctx = build_add_constraint_context(*node, cons, conn);
std::cout << ctx.sql << std::endl; std::cout << ctx.sql << std::endl;
if (auto result = c->execute(ctx.sql); !result) { if (auto result = conn.execute(ctx.sql); !result) {
return utils::failure(result.err()); return utils::failure(result.err());
} }
} }
@ -100,21 +112,20 @@ utils::result<void, utils::error> schema::create() const {
return utils::ok<void>(); return utils::ok<void>();
} }
utils::result<void, utils::error> schema::drop() const { utils::result<void, utils::error> schema::drop(const sql::connection &conn) const {
auto c = pool_.acquire();
// drop table primary key constraints // drop table primary key constraints
for (const auto &node: repo_) { for (const auto &node: repo_) {
for (const auto& cons : node->info().constraints()) { for (const auto &cons: node->info().constraints()) {
if (cons.is_primary_key_constraint()) { if (cons.is_primary_key_constraint()) {
continue; continue;
} }
auto ctx = query::query::alter() auto ctx = query::query::alter()
.table(node->name()) .table(node->name())
.drop_constraint(cons) .drop_constraint(cons)
.compile(*c); .compile(conn);
std::cout << ctx.sql << std::endl; std::cout << ctx.sql << std::endl;
if (auto result = c->execute(ctx.sql); !result) { if (auto result = conn.execute(ctx.sql); !result) {
return utils::failure(result.err()); return utils::failure(result.err());
} }
} }
@ -122,17 +133,17 @@ utils::result<void, utils::error> schema::drop() const {
// drop table constraints // drop table constraints
for (const auto &node: repo_) { for (const auto &node: repo_) {
for (const auto& cons : node->info().constraints()) { for (const auto &cons: node->info().constraints()) {
if (!cons.is_primary_key_constraint()) { if (!cons.is_primary_key_constraint()) {
continue; continue;
} }
auto ctx = query::query::alter() auto ctx = query::query::alter()
.table(node->name()) .table(node->name())
.drop_constraint(cons) .drop_constraint(cons)
.compile(*c); .compile(conn);
std::cout << ctx.sql << std::endl; std::cout << ctx.sql << std::endl;
if (auto result = c->execute(ctx.sql); !result) { if (auto result = conn.execute(ctx.sql); !result) {
return utils::failure(result.err()); return utils::failure(result.err());
} }
} }
@ -142,10 +153,10 @@ utils::result<void, utils::error> schema::drop() const {
for (const auto &node: repo_) { for (const auto &node: repo_) {
auto ctx = query::query::drop() auto ctx = query::query::drop()
.table(node->name()) .table(node->name())
.compile(*c); .compile(conn);
std::cout << ctx.sql << std::endl; std::cout << ctx.sql << std::endl;
if (auto result = c->execute(ctx.sql); !result) { if (auto result = conn.execute(ctx.sql); !result) {
return utils::failure(result.err()); return utils::failure(result.err());
} }
} }
@ -153,11 +164,10 @@ utils::result<void, utils::error> schema::drop() const {
return utils::ok<void>(); return utils::ok<void>();
} }
utils::result<void, utils::error> schema::drop_table(const std::string& table_name) const { utils::result<void, utils::error> schema::drop_table(const std::string &table_name, const sql::connection &conn) const {
const auto c = pool_.acquire();
auto result = query::query::drop() auto result = query::query::drop()
.table(table_name) .table(table_name)
.execute(*c); .execute(conn);
if (result.is_error()) { if (result.is_error()) {
return utils::failure(result.err()); return utils::failure(result.err());
} }
@ -165,50 +175,87 @@ utils::result<void, utils::error> schema::drop_table(const std::string& table_na
return utils::ok<void>(); return utils::ok<void>();
} }
utils::result<std::vector<object::attribute>, utils::error> schema::describe_table(const std::string& table_name) const { utils::result<std::vector<object::attribute>, utils::error>
const auto c = pool_.acquire(); schema::describe_table(const std::string &table_name, const sql::connection &conn) const {
if (!c.valid()) { // if (!conn.valid()) {
return utils::failure(utils::error(sql::error_code::FAILURE, "Failed to acquire connection.")); // return utils::failure(utils::error(sql::error_code::FAILURE, "Failed to acquire connection."));
} // }
return utils::ok(c->describe(table_name).release()); return utils::ok(conn.describe(table_name).release());
} }
utils::result<bool, utils::error> schema::table_exists(const std::string& table_name) const { utils::result<bool, utils::error> schema::table_exists(const std::string &table_name, const sql::connection &conn) const {
const auto c = pool_.acquire(); // if (!c.valid()) {
if (!c.valid()) { // return utils::failure(utils::error(sql::error_code::FAILURE, "Failed to acquire connection."));
return utils::failure(utils::error(sql::error_code::FAILURE, "Failed to acquire connection.")); // }
} return conn.exists(repo_.name(), table_name);
return c->exists(repo_.name(), table_name);
} }
sql::query_context schema::build_add_constraint_context( const object::repository_node& node, const object::restriction& cons ) const { schema::iterator schema::begin() {
return schema_nodes_.begin();
}
schema::iterator schema::end() {
return schema_nodes_.end();
}
schema::const_iterator schema::begin() const {
return schema_nodes_.begin();
}
schema::const_iterator schema::end() const {
return schema_nodes_.end();
}
schema::iterator schema::find(const std::string &name) {
const auto result = repo_.basic_info(name);
if (!result) {
return schema_nodes_.end();
}
return schema_nodes_.find(result->get().type_index());
}
schema::const_iterator schema::find(const std::string &name) const {
const auto result = repo_.basic_info(name);
if (!result) {
return schema_nodes_.end();
}
return schema_nodes_.find(result->get().type_index());
}
sql::query_context schema::build_add_constraint_context(const object::repository_node &node,
const object::restriction &cons,
const sql::connection &conn) const {
if (cons.is_foreign_key_constraint()) { if (cons.is_foreign_key_constraint()) {
return query::query::alter() return query::query::alter()
.table(node.name()) .table(node.name())
.add_constraint(cons) .add_constraint(cons)
.compile(*pool_.acquire()); .compile(conn);
} }
if (cons.is_primary_key_constraint()) { if (cons.is_primary_key_constraint()) {
return query::query::alter() return query::query::alter()
.table(node.name()) .table(node.name())
.add_constraint(cons) .add_constraint(cons)
.compile(*pool_.acquire()); .compile(conn);
} }
return {}; return {};
} }
sql::query_context schema::build_drop_constraint_context( const object::repository_node& node, const object::restriction& cons ) const { sql::query_context schema::build_drop_constraint_context(const object::repository_node &node,
const object::restriction &cons,
const sql::connection &conn) const {
return query::query::alter() return query::query::alter()
.table(node.name()) .table(node.name())
.drop_constraint(cons) .drop_constraint(cons)
.compile(*pool_.acquire()); .compile(conn);
} }
void schema::insert_table(const std::type_index& ti, const object::repository_node& node) { void schema::insert_table(const std::type_index &ti, const object::repository_node &node) {
std::vector<column> columns; std::vector<column> columns;
for (const auto &attr : node.info().attributes()) { for (const auto &attr: node.info().attributes()) {
columns.emplace_back(nullptr, attr.name(), attr.type(), attr.attributes()); columns.emplace_back(nullptr, attr.name(), attr.type(), attr.attributes());
} }
std::ignore = tables_.insert({ti, table(node.name(), "", columns)}).first; std::ignore = schema_nodes_.insert({ti, schema_node{table(node.name(), columns), node}}).first;
} }
} // namespace matador::query } // namespace matador::query

View File

@ -1,3 +1,5 @@
#include <utility>
#include "matador/query/table.hpp" #include "matador/query/table.hpp"
namespace matador::query { namespace matador::query {
@ -6,46 +8,63 @@ table::table(const char* name)
: table(std::string(name)) : table(std::string(name))
{} {}
table::table(std::string name) table::table(const std::string& name)
: name_(std::move(name)) : table(name, name, {}) {}
{}
table::table(std::string name, std::string as) table::table(const std::string& name, const std::vector<column> &columns)
: name_(std::move(name)) : table(name, name, columns) {
, alias_(std::move(as)) }
{}
table::table( std::string name, std::string as, const std::vector<query::column>& columns ) table::table(std::string name, std::string alias, const std::vector<column> &columns)
: name_(std::move(name)) : name_(std::move(name))
, alias_(std::move(as)) , alias_(std::move(alias))
, columns_(columns) { , columns_(columns) {
for (auto& col : columns_) { for (auto &col : columns_) {
col.table_ = this; col.table(this);
} }
} }
bool table::operator==( const table& x ) const { table::table(const table &other)
return name_ == x.name_; : table(other.name_, other.alias_, other.columns_) {
for (auto &col : columns_) {
col.table(this);
}
} }
table table::as(const std::string &a) { table & table::operator=(const table &other) {
alias_ = a; if (this == &other) {
return *this;
}
return *this = table(other);
}
table::table(table &&other) noexcept {
*this = std::move(other);
}
table & table::operator=(table &&other) noexcept {
name_ = std::move(other.name_);
alias_ = std::move(other.alias_);
columns_ = std::move(other.columns_);
for (auto &col : columns_) {
col.table(this);
}
return *this; return *this;
} }
table table::as(const std::string &a) const { bool table::operator==(const table& x) const {
return { name_, a, columns_ }; return name_ == x.name_ && alias_ == x.alias_;
} }
bool table::has_alias() const { table table::as(const std::string &alias) const {
return !alias_.empty(); return { name_, alias, columns_ };
} }
const std::string& table::name() const { const std::string & table::table_name() const {
return name_; return name_;
} }
const std::string& table::alias() const { const std::string& table::name() const {
return alias_; return alias_;
} }
@ -53,10 +72,39 @@ const std::vector<column>& table::columns() const {
return columns_; return columns_;
} }
bool table::has_alias() const {
return name_ != alias_;
}
table::operator const std::vector<query::column>&() const { table::operator const std::vector<query::column>&() const {
return columns_; return columns_;
} }
const class column* table::operator[](const std::string &column_name) const {
for (const auto &col : columns_) {
if (col.name() == column_name) {
return &col;
}
}
return nullptr;
}
const class column * table::column_by_name(const table &tab, const std::string &column_name) {
for (const auto &col : tab.columns_) {
if (col.name() == column_name) {
return &col;
}
}
return nullptr;
}
const column& table::create_column(class table &tab, const std::string &name) {
tab.columns_.emplace_back(name);
tab.columns_.back().table(&tab);
return tab.columns_.back();
}
table operator ""_tab(const char *name, size_t len) { table operator ""_tab(const char *name, size_t len) {
return {{name, len}}; return {{name, len}};
} }

View File

@ -1,15 +1,13 @@
#include "catch2/catch_test_macros.hpp" #include "catch2/catch_test_macros.hpp"
#include "catch2/matchers/catch_matchers_string.hpp" #include "catch2/matchers/catch_matchers_string.hpp"
#include "matador/object/attribute.hpp"
#include "matador/object/repository.hpp"
#include "matador/sql/connection.hpp" #include "matador/sql/connection.hpp"
#include "matador/sql/dialect.hpp" #include "matador/sql/dialect.hpp"
#include "matador/query/criteria.hpp" #include "matador/query/criteria.hpp"
#include "matador/query/generator.hpp" #include "matador/query/generator.hpp"
#include "matador/query/query.hpp" #include "matador/query/query.hpp"
#include "matador/query/schema.hpp"
#include "matador/utils/basic_types.hpp" #include "matador/utils/basic_types.hpp"
#include "matador/utils/string.hpp" #include "matador/utils/string.hpp"
@ -25,9 +23,9 @@ using namespace matador::sql;
using namespace matador::object; using namespace matador::object;
using namespace matador::query; using namespace matador::query;
TEST_CASE_METHOD( QueryFixture, "Insert and select basic datatypes", "[query][datatypes]" ) { TEST_CASE_METHOD(QueryFixture, "Insert and select basic datatypes", "[query][datatypes]") {
REQUIRE(repo.attach<types>("types")); REQUIRE(repo.attach<types>("types"));
auto obj = object_generator::generate<types>(repo, "types"); auto obj = object_generator::generate<types>(repo.repo(), "types");
auto res = query::create() auto res = query::create()
.table(obj->name()) .table(obj->name())
.columns(obj->attributes()) .columns(obj->attributes())
@ -290,7 +288,7 @@ TEST_CASE_METHOD(QueryFixture, "Test describe table", "[query][describe][table]"
using namespace matador::sql; using namespace matador::sql;
REQUIRE(repo.attach<types>("types")); REQUIRE(repo.attach<types>("types"));
auto obj = object_generator::generate<types>(repo, "types"); auto obj = object_generator::generate<types>(repo.repo(), "types");
auto res = query::create() auto res = query::create()
.table(obj->name()) .table(obj->name())
.columns(obj->attributes()) .columns(obj->attributes())
@ -368,7 +366,7 @@ TEST_CASE_METHOD(QueryFixture, "Test primary key", "[query][primary key]") {
using namespace matador::sql; using namespace matador::sql;
REQUIRE(repo.attach<pk>("pk")); REQUIRE(repo.attach<pk>("pk"));
auto obj = object_generator::generate<pk>(repo, "pk"); auto obj = object_generator::generate<pk>(repo.repo(), "pk");
auto res = query::create() auto res = query::create()
.table(obj->name()) .table(obj->name())
.columns(obj->attributes()) .columns(obj->attributes())
@ -400,7 +398,7 @@ TEST_CASE_METHOD(QueryFixture, "Test primary key prepared", "[query][primary key
using namespace matador::sql; using namespace matador::sql;
REQUIRE(repo.attach<pk>("pk")); REQUIRE(repo.attach<pk>("pk"));
auto obj = object_generator::generate<pk>(repo, "pk"); auto obj = object_generator::generate<pk>(repo.repo(), "pk");
auto res = query::create() auto res = query::create()
.table(obj->name()) .table(obj->name())
.columns(obj->attributes()) .columns(obj->attributes())

View File

@ -4,6 +4,8 @@
#include "matador/sql/dialect.hpp" #include "matador/sql/dialect.hpp"
#include "connection.hpp"
#include "catch2/catch_test_macros.hpp" #include "catch2/catch_test_macros.hpp"
namespace matador::test { namespace matador::test {

View File

@ -1,12 +1,10 @@
#ifndef MATADOR_QUERY_FIXTURE_HPP #ifndef MATADOR_QUERY_FIXTURE_HPP
#define MATADOR_QUERY_FIXTURE_HPP #define MATADOR_QUERY_FIXTURE_HPP
#include "matador/object/repository.hpp" #include "matador/query/schema.hpp"
#include "matador/sql/connection.hpp" #include "matador/sql/connection.hpp"
#include "connection.hpp"
#include <stack> #include <stack>
namespace matador::test { namespace matador::test {
@ -22,7 +20,7 @@ public:
protected: protected:
sql::connection db; sql::connection db;
std::stack <std::string> tables_to_drop; std::stack <std::string> tables_to_drop;
object::repository repo; query::schema repo;
private: private:
void drop_table_if_exists(const std::string &table_name) const; void drop_table_if_exists(const std::string &table_name) const;

View File

@ -2,6 +2,7 @@
#include "matador/sql/connection.hpp" #include "matador/sql/connection.hpp"
#include "matador/query/builder.hpp"
#include "matador/query/criteria.hpp" #include "matador/query/criteria.hpp"
#include "matador/query/query.hpp" #include "matador/query/query.hpp"
#include "matador/query/column.hpp" #include "matador/query/column.hpp"
@ -23,26 +24,31 @@ using namespace matador::utils;
TEST_CASE_METHOD(QueryFixture, "Test all data types for record", "[query][record][data types]") { TEST_CASE_METHOD(QueryFixture, "Test all data types for record", "[query][record][data types]") {
check_table_not_exists("types"); check_table_not_exists("types");
const table tab("types");
// auto r = query::create().table(tab).columns({
// column("id", basic_type::UInt32)
// });
auto res = query::create() auto res = query::create()
.table("types") .table(tab)
.columns({ .columns({
attribute("id", basic_type::UInt32), column("id", basic_type::UInt32),
attribute("val_char", basic_type::Int8), column("val_char", basic_type::Int8),
attribute("val_short", basic_type::Int16), column("val_short", basic_type::Int16),
attribute("val_int", basic_type::Int32), column("val_int", basic_type::Int32),
attribute("val_long_long", basic_type::Int64), column("val_long_long", basic_type::Int64),
attribute("val_uchar", basic_type::UInt8), column("val_uchar", basic_type::UInt8),
attribute("val_ushort", basic_type::UInt16), column("val_ushort", basic_type::UInt16),
attribute("val_uint", basic_type::UInt32), column("val_uint", basic_type::UInt32),
attribute("val_ulong_long", basic_type::UInt64), column("val_ulong_long", basic_type::UInt64),
attribute("val_bool", basic_type::Boolean), column("val_bool", basic_type::Boolean),
attribute("val_float", basic_type::Float), column("val_float", basic_type::Float),
attribute("val_double", basic_type::Double), column("val_double", basic_type::Double),
attribute("val_string", basic_type::Text), column("val_string", basic_type::Text),
attribute("val_varchar", basic_type::Varchar, 63), column("val_varchar", basic_type::Varchar, 63),
// attribute("val_date", basic_type::type_date), // column("val_date", basic_type::type_date),
// attribute("val_time", basic_type::type_time), // column("val_time", basic_type::type_time),
attribute("val_blob", basic_type::Blob), column("val_blob", basic_type::Blob),
}) })
.constraints({ .constraints({
constraint("PK_types").primary_key("id") constraint("PK_types").primary_key("id")
@ -126,9 +132,9 @@ TEST_CASE_METHOD(QueryFixture, "Create and drop table statement", "[query][recor
auto res = query::create() auto res = query::create()
.table("person") .table("person")
.columns({ .columns({
attribute("id", basic_type::UInt32), column("id", basic_type::UInt32),
attribute("name", basic_type::Varchar, 255), column("name", basic_type::Varchar, 255),
attribute("age", basic_type::UInt16) column("age", basic_type::UInt16)
}) })
.constraints({ .constraints({
constraint("PK_person").primary_key("id") constraint("PK_person").primary_key("id")
@ -154,9 +160,9 @@ TEST_CASE_METHOD(QueryFixture, "Create and drop table statement with foreign key
auto res = query::create() auto res = query::create()
.table("airplane") .table("airplane")
.columns({ .columns({
attribute("id", basic_type::UInt32), column("id", basic_type::UInt32),
attribute("brand", basic_type::Varchar, 255), column("brand", basic_type::Varchar, 255),
attribute("model", basic_type::Varchar, 255), column("model", basic_type::Varchar, 255),
}) })
.constraints({ .constraints({
constraint("PK_airplane").primary_key("id"), constraint("PK_airplane").primary_key("id"),
@ -171,9 +177,9 @@ TEST_CASE_METHOD(QueryFixture, "Create and drop table statement with foreign key
res = query::create() res = query::create()
.table("flight") .table("flight")
.columns({ .columns({
attribute("id", basic_type::UInt32), column("id", basic_type::UInt32),
attribute("airplane_id", basic_type::UInt32), column("airplane_id", basic_type::UInt32),
attribute("pilot_name", basic_type::Varchar, 255) column("pilot_name", basic_type::Varchar, 255)
}) })
.constraints({ .constraints({
constraint("PK_flight").primary_key("id"), constraint("PK_flight").primary_key("id"),
@ -208,9 +214,9 @@ TEST_CASE_METHOD(QueryFixture, "Execute insert record statement", "[query][recor
auto res = query::create() auto res = query::create()
.table("person") .table("person")
.columns({ .columns({
attribute("id", basic_type::UInt32), column("id", basic_type::UInt32),
attribute("name", basic_type::Varchar, 255), column("name", basic_type::Varchar, 255),
attribute("age", basic_type::UInt16) column("age", basic_type::UInt16)
}) })
.constraints({ .constraints({
constraint("PK_person").primary_key("id") constraint("PK_person").primary_key("id")
@ -251,9 +257,9 @@ TEST_CASE_METHOD(QueryFixture, "Execute insert record statement with foreign key
auto res = query::create() auto res = query::create()
.table("airplane") .table("airplane")
.columns({ .columns({
attribute("id", basic_type::UInt32), column("id", basic_type::UInt32),
attribute("brand", basic_type::Varchar, 255), column("brand", basic_type::Varchar, 255),
attribute("model", basic_type::Varchar, 255), column("model", basic_type::Varchar, 255),
}) })
.constraints({ .constraints({
constraint("PK_airplane").primary_key("id"), constraint("PK_airplane").primary_key("id"),
@ -266,9 +272,9 @@ TEST_CASE_METHOD(QueryFixture, "Execute insert record statement with foreign key
res = query::create() res = query::create()
.table("flight") .table("flight")
.columns({ .columns({
attribute("id", basic_type::UInt32), column("id", basic_type::UInt32),
attribute("airplane_id", basic_type::UInt32), column("airplane_id", basic_type::UInt32),
attribute("pilot_name", basic_type::Varchar, 255) column("pilot_name", basic_type::Varchar, 255)
}) })
.constraints({ .constraints({
constraint("PK_flight").primary_key("id"), constraint("PK_flight").primary_key("id"),
@ -314,9 +320,9 @@ TEST_CASE_METHOD(QueryFixture, "Execute update record statement", "[query][recor
auto res = query::create() auto res = query::create()
.table("person") .table("person")
.columns({ .columns({
attribute("id", basic_type::UInt32), column("id", basic_type::UInt32),
attribute("name", basic_type::Varchar, 255), column("name", basic_type::Varchar, 255),
attribute("age", basic_type::UInt16) column("age", basic_type::UInt16)
}) })
.constraints({ .constraints({
constraint("PK_person").primary_key("id") constraint("PK_person").primary_key("id")
@ -367,9 +373,9 @@ TEST_CASE_METHOD(QueryFixture, "Execute select statement", "[query][record]")
auto res = query::create() auto res = query::create()
.table("person") .table("person")
.columns({ .columns({
attribute("id", basic_type::UInt32), column("id", basic_type::UInt32),
attribute("name", basic_type::Varchar, 255), column("name", basic_type::Varchar, 255),
attribute("age", basic_type::UInt16) column("age", basic_type::UInt16)
}) })
.constraints({ .constraints({
constraint("PK_person").primary_key("id") constraint("PK_person").primary_key("id")
@ -427,9 +433,9 @@ TEST_CASE_METHOD(QueryFixture, "Execute select statement with order by", "[query
auto res = query::create() auto res = query::create()
.table("person") .table("person")
.columns({ .columns({
attribute("id", basic_type::UInt32), column("id", basic_type::UInt32),
attribute("name", basic_type::Varchar, 255), column("name", basic_type::Varchar, 255),
attribute("age", basic_type::UInt16) column("age", basic_type::UInt16)
}) })
.constraints({ .constraints({
constraint("PK_person").primary_key("id") constraint("PK_person").primary_key("id")
@ -473,9 +479,9 @@ TEST_CASE_METHOD(QueryFixture, "Execute select statement with group by and order
auto res = query::create() auto res = query::create()
.table("person") .table("person")
.columns({ .columns({
attribute("id", basic_type::UInt32), column("id", basic_type::UInt32),
attribute("name", basic_type::Varchar, 255), column("name", basic_type::Varchar, 255),
attribute("age", basic_type::UInt16) column("age", basic_type::UInt16)
}) })
.constraints({ .constraints({
constraint("PK_person").primary_key("id") constraint("PK_person").primary_key("id")
@ -526,9 +532,9 @@ TEST_CASE_METHOD(QueryFixture, "Execute delete statement", "[query][record]") {
auto res = query::create() auto res = query::create()
.table("person") .table("person")
.columns({ .columns({
attribute("id", basic_type::UInt32), column("id", basic_type::UInt32),
attribute("name", basic_type::Varchar, 255), column("name", basic_type::Varchar, 255),
attribute("age", basic_type::UInt16) column("age", basic_type::UInt16)
}) })
.constraints({ .constraints({
constraint("PK_person").primary_key("id") constraint("PK_person").primary_key("id")
@ -576,8 +582,8 @@ TEST_CASE_METHOD(QueryFixture, "Test quoted identifier record", "[query][record]
auto res = query::create() auto res = query::create()
.table("quotes") .table("quotes")
.columns({ .columns({
attribute("from", basic_type::Varchar, 255), column("from", basic_type::Varchar, 255),
attribute("to", basic_type::Varchar, 255) column("to", basic_type::Varchar, 255)
}) })
.execute(db); .execute(db);
REQUIRE(res.is_ok()); REQUIRE(res.is_ok());
@ -637,9 +643,9 @@ TEST_CASE_METHOD(QueryFixture, "Test create record", "[query][record][create]")
auto res = query::create() auto res = query::create()
.table("person") .table("person")
.columns({ .columns({
attribute("id", basic_type::UInt32), column("id", basic_type::UInt32),
attribute("name", basic_type::Varchar, 255), column("name", basic_type::Varchar, 255),
attribute("age", basic_type::UInt16) column("age", basic_type::UInt16)
}) })
.constraints({ .constraints({
constraint("PK_person").primary_key("id") constraint("PK_person").primary_key("id")
@ -664,9 +670,9 @@ TEST_CASE_METHOD(QueryFixture, "Test insert record", "[query][record][insert]")
auto res = query::create() auto res = query::create()
.table("person") .table("person")
.columns({ .columns({
attribute("id", basic_type::UInt32), column("id", basic_type::UInt32),
attribute("name", basic_type::Varchar, 255), column("name", basic_type::Varchar, 255),
attribute("age", basic_type::UInt16) column("age", basic_type::UInt16)
}) })
.constraints({ .constraints({
constraint("PK_person").primary_key("id") constraint("PK_person").primary_key("id")
@ -701,9 +707,9 @@ TEST_CASE_METHOD(QueryFixture, "Test update record", "[query][record][update]")
auto res = query::create() auto res = query::create()
.table("person") .table("person")
.columns({ .columns({
attribute("id", basic_type::UInt32), column("id", basic_type::UInt32),
attribute("name", basic_type::Varchar, 255), column("name", basic_type::Varchar, 255),
attribute("age", basic_type::UInt16) column("age", basic_type::UInt16)
}) })
.constraints({ .constraints({
constraint("PK_person").primary_key("id") constraint("PK_person").primary_key("id")
@ -755,9 +761,9 @@ TEST_CASE_METHOD(QueryFixture, "Test prepared record statement", "[query][record
auto stmt = query::create() auto stmt = query::create()
.table("person") .table("person")
.columns({ .columns({
attribute("id", basic_type::UInt32), column("id", basic_type::UInt32),
attribute("name", basic_type::Varchar, 255), column("name", basic_type::Varchar, 255),
attribute("age", basic_type::UInt16) column("age", basic_type::UInt16)
}) })
.constraints({ .constraints({
constraint("PK_person").primary_key("id") constraint("PK_person").primary_key("id")
@ -785,7 +791,7 @@ TEST_CASE_METHOD(QueryFixture, "Test scalar result", "[query][record][scalar][re
auto res = query::create() auto res = query::create()
.table("person") .table("person")
.columns({ .columns({
attribute("id", basic_type::UInt32) column("id", basic_type::UInt32)
}) })
.constraints({ .constraints({
constraint("PK_person").primary_key("id") constraint("PK_person").primary_key("id")

View File

@ -20,7 +20,7 @@ using namespace matador::test;
TEST_CASE_METHOD(QueryFixture, "Test create statement", "[query][statement][create]") { TEST_CASE_METHOD(QueryFixture, "Test create statement", "[query][statement][create]") {
REQUIRE(repo.attach<matador::test::person>("person")); REQUIRE(repo.attach<matador::test::person>("person"));
const auto obj = object_generator::generate<person>(repo, "person"); const auto obj = object_generator::generate<person>(repo.repo(), "person");
auto stmt = query::create() auto stmt = query::create()
.table(obj->name()) .table(obj->name())
.columns(obj->attributes()) .columns(obj->attributes())
@ -47,7 +47,7 @@ TEST_CASE_METHOD(QueryFixture, "Test insert statement", "[query][statement][inse
using namespace matador::test; using namespace matador::test;
REQUIRE(repo.attach<person>("person")); REQUIRE(repo.attach<person>("person"));
const auto obj = object_generator::generate<person>(repo, "person"); const auto obj = object_generator::generate<person>(repo.repo(), "person");
auto stmt = query::create() auto stmt = query::create()
.table(obj->name()) .table(obj->name())
.columns(obj->attributes()) .columns(obj->attributes())
@ -92,7 +92,7 @@ TEST_CASE_METHOD(QueryFixture, "Test update statement", "[query][statement][upda
using namespace matador::utils; using namespace matador::utils;
REQUIRE(repo.attach<matador::test::person>("person")); REQUIRE(repo.attach<matador::test::person>("person"));
const auto obj = object_generator::generate<person>(repo, "person"); const auto obj = object_generator::generate<person>(repo.repo(), "person");
auto stmt = query::create() auto stmt = query::create()
.table(obj->name()) .table(obj->name())
.columns(obj->attributes()) .columns(obj->attributes())
@ -161,7 +161,7 @@ TEST_CASE_METHOD(QueryFixture, "Test delete statement", "[query][statement][dele
using namespace matador::test; using namespace matador::test;
REQUIRE(repo.attach<matador::test::person>("person")); REQUIRE(repo.attach<matador::test::person>("person"));
const auto obj = object_generator::generate<person>(repo, "person"); const auto obj = object_generator::generate<person>(repo.repo(), "person");
auto stmt = query::create() auto stmt = query::create()
.table(obj->name()) .table(obj->name())
.columns(obj->attributes()) .columns(obj->attributes())
@ -251,7 +251,7 @@ TEST_CASE_METHOD(QueryFixture, "Test reuse prepared statement", "[query][stateme
using namespace matador::test; using namespace matador::test;
REQUIRE(repo.attach<matador::test::person>("person")); REQUIRE(repo.attach<matador::test::person>("person"));
const auto obj = object_generator::generate<person>(repo, "person"); const auto obj = object_generator::generate<person>(repo.repo(), "person");
auto stmt = query::create() auto stmt = query::create()
.table(obj->name()) .table(obj->name())
.columns(obj->attributes()) .columns(obj->attributes())

View File

@ -1,7 +1,6 @@
#include "catch2/catch_test_macros.hpp" #include "catch2/catch_test_macros.hpp"
#include "matador/object/attribute.hpp" #include "matador/query/builder.hpp"
#include "matador/query/criteria.hpp" #include "matador/query/criteria.hpp"
#include "matador/query/generator.hpp" #include "matador/query/generator.hpp"
#include "matador/query/query.hpp" #include "matador/query/query.hpp"
@ -23,7 +22,7 @@ TEST_CASE_METHOD(QueryFixture, "Create table with foreign key relation", "[query
.and_then( [this] { return repo.attach<flight>("flight");} ); .and_then( [this] { return repo.attach<flight>("flight");} );
REQUIRE(result.is_ok()); REQUIRE(result.is_ok());
auto obj = object_generator::generate<airplane>(repo, "airplane"); auto obj = object_generator::generate<airplane>(repo.repo(), "airplane");
auto res = query::create() auto res = query::create()
.table(obj->name()) .table(obj->name())
.columns(obj->attributes()) .columns(obj->attributes())
@ -35,7 +34,7 @@ TEST_CASE_METHOD(QueryFixture, "Create table with foreign key relation", "[query
check_table_exists("airplane"); check_table_exists("airplane");
tables_to_drop.emplace("airplane"); tables_to_drop.emplace("airplane");
obj = object_generator::generate<flight>(repo, "flight"); obj = object_generator::generate<flight>(repo.repo(), "flight");
res = query::create() res = query::create()
.table(obj->name()) .table(obj->name())
.columns(obj->attributes()) .columns(obj->attributes())
@ -50,7 +49,7 @@ TEST_CASE_METHOD(QueryFixture, "Create table with foreign key relation", "[query
TEST_CASE_METHOD(QueryFixture, "Execute select statement with where clause", "[query][where]") { TEST_CASE_METHOD(QueryFixture, "Execute select statement with where clause", "[query][where]") {
REQUIRE(repo.attach<person>("person")); REQUIRE(repo.attach<person>("person"));
const auto obj = object_generator::generate<person>(repo, "person"); const auto obj = object_generator::generate<person>(repo.repo(), "person");
auto res = query::create() auto res = query::create()
.table(obj->name()) .table(obj->name())
.columns(obj->attributes()) .columns(obj->attributes())
@ -110,9 +109,9 @@ TEST_CASE_METHOD(QueryFixture, "Execute insert statement", "[query][insert]") {
auto res = query::create() auto res = query::create()
.table("person") .table("person")
.columns({ .columns({
attribute("id", matador::utils::basic_type::UInt32), column("id", matador::utils::basic_type::UInt32),
attribute("name", matador::utils::basic_type::Varchar, 255), column("name", matador::utils::basic_type::Varchar, 255),
attribute("color", matador::utils::basic_type::Varchar, 63) column("color", matador::utils::basic_type::Varchar, 63)
}) })
.constraints({ .constraints({
constraint("PK_person").primary_key("id") constraint("PK_person").primary_key("id")

View File

@ -15,46 +15,48 @@ using namespace matador::test;
TEST_CASE_METHOD(SchemaFixture, "Test schema one-two-many", "[schema][one-to-many]") { TEST_CASE_METHOD(SchemaFixture, "Test schema one-two-many", "[schema][one-to-many]") {
using namespace matador::test; using namespace matador::test;
query::schema repo(pool/*, "NoopSchema"*/); query::schema repo;
auto result = repo.attach<department>("departments") auto result = repo.attach<department>("departments")
.and_then([&repo] { return repo.attach<employee>("employees"); }); .and_then([&repo] { return repo.attach<employee>("employees"); });
REQUIRE(result); REQUIRE(result);
result = repo.create(); auto conn = pool.acquire();
result = repo.create(*conn);
REQUIRE(result); REQUIRE(result);
auto exists_result = repo.table_exists("departments"); auto exists_result = repo.table_exists("departments", *conn);
REQUIRE(exists_result.is_ok()); REQUIRE(exists_result.is_ok());
REQUIRE(exists_result.value()); REQUIRE(exists_result.value());
result = repo.drop(); result = repo.drop(*conn);
REQUIRE(result); REQUIRE(result);
exists_result = repo.table_exists("departments"); exists_result = repo.table_exists("departments", *conn);
REQUIRE(exists_result.is_ok()); REQUIRE(exists_result.is_ok());
REQUIRE(!exists_result.value()); REQUIRE(!exists_result.value());
} }
TEST_CASE_METHOD(SchemaFixture, "Test schema many-to-many", "[schema][many-to-many]") { TEST_CASE_METHOD(SchemaFixture, "Test schema many-to-many", "[schema][many-to-many]") {
using namespace matador::test; using namespace matador::test;
query::schema repo(pool/*, "NoopSchema"*/); query::schema repo;
auto result = repo.attach<recipe>("recipes") auto result = repo.attach<recipe>("recipes")
.and_then([&repo] { return repo.attach<ingredient>("ingredients"); }); .and_then([&repo] { return repo.attach<ingredient>("ingredients"); });
REQUIRE(result); REQUIRE(result);
result = repo.create(); auto conn = pool.acquire();
result = repo.create(*conn);
REQUIRE(result); REQUIRE(result);
auto exists_result = repo.table_exists("recipes"); auto exists_result = repo.table_exists("recipes", *conn);
REQUIRE(exists_result.is_ok()); REQUIRE(exists_result.is_ok());
REQUIRE(exists_result.value()); REQUIRE(exists_result.value());
result = repo.drop(); result = repo.drop(*conn);
REQUIRE(result); REQUIRE(result);
exists_result = repo.table_exists("recipes"); exists_result = repo.table_exists("recipes", *conn);
REQUIRE(exists_result.is_ok()); REQUIRE(exists_result.is_ok());
REQUIRE(!exists_result.value()); REQUIRE(!exists_result.value());
} }

View File

@ -23,18 +23,15 @@ using namespace matador::test;
namespace matador::test::detail { namespace matador::test::detail {
template<class Type, typename... Args> template<class Type, typename... Args>
[[maybe_unused]] object_ptr<Type> make_object_ptr(Args&&... args) [[maybe_unused]] object_ptr<Type> make_object_ptr(Args&&... args) {
{
return object_ptr(new Type(std::forward<Args>(args)...)); return object_ptr(new Type(std::forward<Args>(args)...));
} }
} }
class StatementTestFixture : public QueryFixture class StatementTestFixture : public QueryFixture {
{
public: public:
StatementTestFixture() StatementTestFixture() {
{ const auto obj = object_generator::generate<airplane>(repo.repo(), "airplane");
const auto obj = object_generator::generate<airplane>(repo, "airplane");
const auto res = query::create() const auto res = query::create()
.table(obj->name()) .table(obj->name())
.columns(obj->attributes()) .columns(obj->attributes())

View File

@ -22,7 +22,7 @@ class TypeTraitsTestFixture : public QueryFixture
public: public:
TypeTraitsTestFixture() { TypeTraitsTestFixture() {
REQUIRE(db.open()); REQUIRE(db.open());
const auto obj = matador::object::object_generator::generate<location>(repo, "location"); const auto obj = matador::object::object_generator::generate<location>(repo.repo(), "location");
const auto res = query::create() const auto res = query::create()
.table(obj->name()) .table(obj->name())
.columns(obj->attributes()) .columns(obj->attributes())

View File

@ -75,16 +75,6 @@ TEST_CASE("Test next and previous of schema node", "[schema_node][next][previous
REQUIRE(++it == repo.end()); REQUIRE(++it == repo.end());
} }
TEST_CASE("Test automatic creating of a relation table with foreign key", "[schema][relation_table][foreign_key]") {
object::repository repo;
REQUIRE(repo.empty());
auto res = repo.attach<test::department>("department");
REQUIRE(res.is_ok());
REQUIRE(repo.size() == 2);
}
TEST_CASE("Test automatic creating of a relation table with values", "[schema][relation_table][values]") { TEST_CASE("Test automatic creating of a relation table with values", "[schema][relation_table][values]") {
object::repository repo; object::repository repo;
@ -175,22 +165,13 @@ TEST_CASE("Test many to many relation", "[relation][many-to-many]") {
template<typename Type> template<typename Type>
class test_observer : public matador::object::observer<Type> { class test_observer : public matador::object::observer<Type> {
public: public:
void on_attach(object::repository_node& node, const Type& prototype) override { void on_attach(const object::repository_node& /*node*/, const Type& /*prototype*/) const override {}
int i = 0; void on_detach(const object::repository_node& /*node*/, const Type& /*prototype*/) const override {}
} void on_insert(const Type& /*obj*/) override {}
void on_detach(object::repository_node& node, const Type& prototype) override { void on_update(const Type& /*obj*/) override {}
void on_delete(const Type& /*obj*/) override {}
}
void on_insert(Type& obj) override {
}
void on_update(Type& obj) override {
}
void on_delete(Type& obj) override {
}
}; };
TEST_CASE("Test repository observer", "[repository][observer]") { TEST_CASE("Test repository observer", "[repository][observer]") {
object::repository repo; object::repository repo;

View File

@ -12,6 +12,8 @@
#include "matador/query/table.hpp" #include "matador/query/table.hpp"
#include "matador/query/schema.hpp" #include "matador/query/schema.hpp"
#include "matador/utils/macro_map.hpp"
#include "matador/orm/session_query_builder.hpp" #include "matador/orm/session_query_builder.hpp"
#include "../backend/test_connection.hpp" #include "../backend/test_connection.hpp"
@ -33,26 +35,63 @@ using namespace matador::utils;
using namespace matador::sql; using namespace matador::sql;
using namespace matador::test; using namespace matador::test;
// #define FIELD(FIELD_NAME) const matador::query::column& FIELD_NAME = create_column(*this, #FIELD_NAME);
//
// #define META_TABLE(TABLE_NAME, VARIABLE_NAME, ...) \
// namespace matador::query::meta { \
// namespace internal { \
// class TABLE_NAME##_table : public table { \
// public: \
// TABLE_NAME##_table() : table(#TABLE_NAME) {} \
// MAP(FIELD, __VA_ARGS__) \
// }; } \
// static const internal:: TABLE_NAME##_table VARIABLE_NAME; \
// }
//
// META_TABLE( books, BOOK, id, author_id, title, published_in )
class book_table : public table {
public:
book_table()
: table("books", {"id", "title", "author_id"})
, id(*column_by_name(*this, "id"))
, title(*column_by_name(*this, "id"))
, author_id(*column_by_name(*this, "author_id")) {
}
const column& id;
const column& title;
const column& author_id;
};
book_table BOOK;
using namespace matador::test;
TEST_CASE("Create sql query data for entity with eager has one", "[query][entity][builder]") { TEST_CASE("Create sql query data for entity with eager has one", "[query][entity][builder]") {
using namespace matador::test; using namespace matador::test;
backend_provider::instance().register_backend("noop", std::make_unique<orm::test_backend_service>()); backend_provider::instance().register_backend("noop", std::make_unique<orm::test_backend_service>());
connection db("noop://noop.db"); connection db("noop://noop.db");
connection_pool pool("noop://noop.db", 4); connection_pool pool("noop://noop.db", 4);
schema scm(pool); schema scm;
auto result = scm.attach<airplane>("airplanes") auto result = scm.attach<airplane>("airplanes")
.and_then( [&scm] { return scm.attach<flight>("flights"); } ); .and_then( [&scm] { return scm.attach<flight>("flights"); } );
REQUIRE(result); REQUIRE(result);
session_query_builder eqb(scm, db); session_query_builder eqb(scm, db);
auto data = eqb.build<flight>("flights.id"_col == _); const auto it = scm.find(typeid(flight));
REQUIRE(it != scm.end());
const auto* col = it->second.table()["id"];
REQUIRE(col);
auto data = eqb.build<flight>(*col == _);
REQUIRE(data.is_ok()); REQUIRE(data.is_ok());
REQUIRE(data->root_table->name() == "flights"); REQUIRE(data->root_table->table_name() == "flights");
REQUIRE(data->joins.size() == 1); REQUIRE(data->joins.size() == 1);
const auto flights = table("flights"); const auto flights = table("flights").as("t01");
const auto airplanes = table("airplanes"); const auto airplanes = table("airplanes").as("t02");
const std::vector<column> expected_columns { const std::vector<column> expected_columns {
{ &flights, "id", "c01" }, { &flights, "id", "c01" },
{ &airplanes, "id", "c02" }, { &airplanes, "id", "c02" },
@ -73,7 +112,7 @@ TEST_CASE("Create sql query data for entity with eager has one", "[query][entity
size_t index{0}; size_t index{0};
criteria_evaluator evaluator(db.dialect(), qc); criteria_evaluator evaluator(db.dialect(), qc);
for (const auto &[join_table, condition] : data->joins) { for (const auto &[join_table, condition] : data->joins) {
REQUIRE(join_table->name() == expected_join_data[index].first); REQUIRE(join_table->table_name() == expected_join_data[index].first);
REQUIRE(evaluator.evaluate(*condition) == expected_join_data[index].second); REQUIRE(evaluator.evaluate(*condition) == expected_join_data[index].second);
++index; ++index;
} }
@ -89,20 +128,24 @@ TEST_CASE("Create sql query data for entity with eager belongs to", "[query][ent
connection db("noop://noop.db"); connection db("noop://noop.db");
connection_pool pool("noop://noop.db", 4); connection_pool pool("noop://noop.db", 4);
schema scm(pool); schema scm;
auto result = scm.attach<author>("authors") auto result = scm.attach<author>("authors")
.and_then( [&scm] { return scm.attach<book>("books"); } ); .and_then( [&scm] { return scm.attach<book>("books"); } );
REQUIRE(result); REQUIRE(result);
session_query_builder eqb(scm, db); session_query_builder eqb(scm, db);
auto data = eqb.build<book>("books.id"_col == _); const auto it = scm.find(typeid(book));
REQUIRE(it != scm.end());
const auto* col = it->second.table()["id"];
REQUIRE(col);
auto data = eqb.build<book>(*col == _);
REQUIRE(data.is_ok()); REQUIRE(data.is_ok());
REQUIRE(data->root_table->name() == "books"); REQUIRE(data->root_table->table_name() == "books");
REQUIRE(data->joins.size() == 1); REQUIRE(data->joins.size() == 1);
const auto books = table("books"); const auto books = table("books").as("t01");
const auto authors = table("authors"); const auto authors = table("authors").as("t02");
const std::vector<column> expected_columns { const std::vector<column> expected_columns {
{ &books, "id", "c01" }, { &books, "id", "c01" },
{ &books, "title", "c02" }, { &books, "title", "c02" },
@ -127,7 +170,7 @@ TEST_CASE("Create sql query data for entity with eager belongs to", "[query][ent
size_t index{0}; size_t index{0};
criteria_evaluator evaluator(db.dialect(), qc); criteria_evaluator evaluator(db.dialect(), qc);
for (const auto & [join_table, clause] : data->joins) { for (const auto & [join_table, clause] : data->joins) {
REQUIRE(join_table->name() == expected_join_data[index].first); REQUIRE(join_table->table_name() == expected_join_data[index].first);
REQUIRE(evaluator.evaluate(*clause) == expected_join_data[index].second); REQUIRE(evaluator.evaluate(*clause) == expected_join_data[index].second);
++index; ++index;
} }
@ -154,7 +197,7 @@ TEST_CASE("Create sql query data for entity with eager has many belongs to", "[q
connection db("noop://noop.db"); connection db("noop://noop.db");
connection_pool pool("noop://noop.db", 4); connection_pool pool("noop://noop.db", 4);
schema scm(pool); schema scm;
auto result = scm.attach<product>("products") auto result = scm.attach<product>("products")
.and_then( [&scm] { return scm.attach<order_details>("order_details"); } ) .and_then( [&scm] { return scm.attach<order_details>("order_details"); } )
.and_then( [&scm] { return scm.attach<supplier>("suppliers"); } ) .and_then( [&scm] { return scm.attach<supplier>("suppliers"); } )
@ -164,13 +207,17 @@ TEST_CASE("Create sql query data for entity with eager has many belongs to", "[q
session_query_builder eqb(scm, db); session_query_builder eqb(scm, db);
auto data = eqb.build<order>("orders.order_id"_col == _); const auto it = scm.find(typeid(order));
REQUIRE(it != scm.end());
const auto* col = it->second.table()["order_id"];
REQUIRE(col);
auto data = eqb.build<order>(*col == _);
REQUIRE(data.is_ok()); REQUIRE(data.is_ok());
REQUIRE(data->root_table->name() == "orders"); REQUIRE(data->root_table->table_name() == "orders");
REQUIRE(data->joins.size() == 1); REQUIRE(data->joins.size() == 1);
const auto orders = table("orders"); const auto orders = table("orders").as("t01");
const auto order_details = table("order_details"); const auto order_details = table("order_details").as("t02");
const std::vector<column> expected_columns = { const std::vector<column> expected_columns = {
{ &orders, "order_id", "c01" }, { &orders, "order_id", "c01" },
{ &orders, "order_date", "c02" }, { &orders, "order_date", "c02" },
@ -201,7 +248,7 @@ TEST_CASE("Create sql query data for entity with eager has many belongs to", "[q
size_t index{0}; size_t index{0};
criteria_evaluator evaluator(db.dialect(), qc); criteria_evaluator evaluator(db.dialect(), qc);
for (const auto &jd : data->joins) { for (const auto &jd : data->joins) {
REQUIRE(jd.join_table->name() == expected_join_data[index].first); REQUIRE(jd.join_table->table_name() == expected_join_data[index].first);
REQUIRE(evaluator.evaluate(*jd.condition) == expected_join_data[index].second); REQUIRE(evaluator.evaluate(*jd.condition) == expected_join_data[index].second);
++index; ++index;
} }
@ -217,20 +264,24 @@ TEST_CASE("Create sql query data for entity with eager many to many", "[query][e
connection db("noop://noop.db"); connection db("noop://noop.db");
connection_pool pool("noop://noop.db", 4); connection_pool pool("noop://noop.db", 4);
schema scm(pool); schema scm;
auto result = scm.attach<recipe>("recipes") auto result = scm.attach<recipe>("recipes")
.and_then( [&scm] { return scm.attach<ingredient>("ingredients"); } ); .and_then( [&scm] { return scm.attach<ingredient>("ingredients"); } );
REQUIRE(result); REQUIRE(result);
session_query_builder eqb(scm, db); session_query_builder eqb(scm, db);
auto data = eqb.build<ingredient>("ingredients.id"_col == _); const auto it = scm.find(typeid(ingredient));
REQUIRE(it != scm.end());
const auto* col = it->second.table()["id"];
REQUIRE(col);
auto data = eqb.build<ingredient>(*col == _);
REQUIRE(data.is_ok()); REQUIRE(data.is_ok());
REQUIRE(data->root_table->name() == "ingredients"); REQUIRE(data->root_table->table_name() == "ingredients");
REQUIRE(data->joins.size() == 2); REQUIRE(data->joins.size() == 2);
const auto ingredients = table("ingredients"); const auto ingredients = table("ingredients").as("t01");
const auto recipes = table("recipes"); const auto recipes = table("recipes").as("t03");
const std::vector<column> expected_columns { const std::vector<column> expected_columns {
{ &ingredients, "id", "c01" }, { &ingredients, "id", "c01" },
{ &ingredients, "name", "c02" }, { &ingredients, "name", "c02" },
@ -251,7 +302,7 @@ TEST_CASE("Create sql query data for entity with eager many to many", "[query][e
size_t index{0}; size_t index{0};
criteria_evaluator evaluator(db.dialect(), qc); criteria_evaluator evaluator(db.dialect(), qc);
for (const auto &jd : data->joins) { for (const auto &jd : data->joins) {
REQUIRE(jd.join_table->name() == expected_join_data[index].first); REQUIRE(jd.join_table->table_name() == expected_join_data[index].first);
REQUIRE(evaluator.evaluate(*jd.condition) == expected_join_data[index].second); REQUIRE(evaluator.evaluate(*jd.condition) == expected_join_data[index].second);
++index; ++index;
} }
@ -267,20 +318,24 @@ TEST_CASE("Create sql query data for entity with eager many to many (inverse par
connection db("noop://noop.db"); connection db("noop://noop.db");
connection_pool pool("noop://noop.db", 4); connection_pool pool("noop://noop.db", 4);
schema scm(pool); schema scm;
auto result = scm.attach<student>("students") auto result = scm.attach<student>("students")
.and_then( [&scm] { return scm.attach<course>("courses"); } ); .and_then( [&scm] { return scm.attach<course>("courses"); } );
REQUIRE(result); REQUIRE(result);
session_query_builder eqb(scm, db); session_query_builder eqb(scm, db);
auto data = eqb.build<course>("courses.id"_col == _); const auto it = scm.find(typeid(course));
REQUIRE(it != scm.end());
const auto* col = it->second.table()["id"];
REQUIRE(col);
auto data = eqb.build<course>(*col == _);
REQUIRE(data.is_ok()); REQUIRE(data.is_ok());
REQUIRE(data->root_table->name() == "courses"); REQUIRE(data->root_table->table_name() == "courses");
REQUIRE(data->joins.size() == 2); REQUIRE(data->joins.size() == 2);
const auto courses = table("courses"); const auto courses = table("courses").as("t01");
const auto students = table("students"); const auto students = table("students").as("t03");
const std::vector<column> expected_columns { const std::vector<column> expected_columns {
{ &courses, "id", "c01" }, { &courses, "id", "c01" },
{ &courses, "title", "c02" }, { &courses, "title", "c02" },
@ -301,7 +356,7 @@ TEST_CASE("Create sql query data for entity with eager many to many (inverse par
size_t index{0}; size_t index{0};
criteria_evaluator evaluator(db.dialect(), qc); criteria_evaluator evaluator(db.dialect(), qc);
for (const auto &jd : data->joins) { for (const auto &jd : data->joins) {
REQUIRE(jd.join_table->name() == expected_join_data[index].first); REQUIRE(jd.join_table->table_name() == expected_join_data[index].first);
REQUIRE(evaluator.evaluate(*jd.condition) == expected_join_data[index].second); REQUIRE(evaluator.evaluate(*jd.condition) == expected_join_data[index].second);
++index; ++index;
} }
@ -317,7 +372,7 @@ TEST_CASE("Test eager relationship", "[session][eager]") {
connection db("noop://noop.db"); connection db("noop://noop.db");
connection_pool pool("noop://noop.db", 4); connection_pool pool("noop://noop.db", 4);
schema scm(pool); schema scm;
auto result = scm.attach<department>("departments") auto result = scm.attach<department>("departments")
.and_then( [&scm] { return scm.attach<employee>("employees"); } ); .and_then( [&scm] { return scm.attach<employee>("employees"); } );
REQUIRE(result); REQUIRE(result);
@ -331,7 +386,7 @@ TEST_CASE("Test eager relationship", "[session][eager]") {
.from(*data->root_table) .from(*data->root_table)
.join_left(data->joins) .join_left(data->joins)
.where(std::move(data->where_clause)) .where(std::move(data->where_clause))
.order_by(column{data->root_table.get(), data->pk_column_name}) .order_by(column{data->root_table, data->pk_column_name})
.asc() .asc()
.str(db); .str(db);

View File

@ -32,18 +32,18 @@ TEST_CASE("Test column value generator", "[generator][column_value]") {
} }
} }
TEST_CASE("Test column generator", "[generator][column]") { // TEST_CASE("Test column generator", "[generator][column]") {
SECTION("Test column generator for simple table") { // SECTION("Test column generator for simple table") {
const std::vector expected_columns { // const std::vector expected_columns {
column("id"), // column("id"),
column("brand"), // column("brand"),
column("model"), // column("model"),
}; // };
const auto result = generator::columns<airplane>(); // const auto result = generator::columns<airplane>();
REQUIRE(result.size() == expected_columns.size()); // REQUIRE(result.size() == expected_columns.size());
auto it = result.begin(); // auto it = result.begin();
for (const auto& c : expected_columns) { // for (const auto& c : expected_columns) {
REQUIRE(c.equals( *it++)); // REQUIRE(c.equals( *it++));
} // }
} // }
} // }

View File

@ -39,9 +39,9 @@ TEST_CASE_METHOD(QueryFixture, "Test create table sql statement string", "[query
auto result = query::create() auto result = query::create()
.table({"person"}) .table({"person"})
.columns({ .columns({
attribute("id", basic_type::UInt32), column("id", basic_type::UInt32),
attribute("name", basic_type::Varchar, 255), column("name", basic_type::Varchar, 255),
attribute("age", basic_type::UInt16) column("age", basic_type::UInt16)
}) })
.constraints({ .constraints({
constraint("PK_person").primary_key({"id"}) constraint("PK_person").primary_key({"id"})
@ -53,10 +53,10 @@ TEST_CASE_METHOD(QueryFixture, "Test create table sql statement string", "[query
auto ctx = query::create() auto ctx = query::create()
.table("person") .table("person")
.columns({ .columns({
attribute("id", basic_type::UInt32), column("id", basic_type::UInt32),
attribute("name", basic_type::Varchar, {255, constraints::Unique}), column("name", basic_type::Varchar, 255).unique(),
attribute("age", basic_type::UInt16), column("age", basic_type::UInt16),
attribute("address", basic_type::UInt32) column("address", basic_type::UInt32)
}) })
.constraints({ .constraints({
constraint("PK_person").primary_key({"id"}), constraint("PK_person").primary_key({"id"}),
@ -221,9 +221,9 @@ TEST_CASE_METHOD(QueryFixture, "Test create, insert and select a blob column", "
auto result = query::create() auto result = query::create()
.table("person") .table("person")
.columns({ .columns({
attribute("id", basic_type::UInt32), column("id", basic_type::UInt32),
attribute("name", basic_type::Varchar, 255), column("name", basic_type::Varchar, 255),
attribute("data", basic_type::Blob) column("data", basic_type::Blob)
}) })
.constraints({ .constraints({
constraint("PK_person").primary_key({"id"}) constraint("PK_person").primary_key({"id"})
@ -247,10 +247,14 @@ TEST_CASE_METHOD(QueryFixture, "Test create, insert and select a blob column", "
} }
TEST_CASE_METHOD(QueryFixture, "Test select statement with join_left", "[query][statement][join_left]") { TEST_CASE_METHOD(QueryFixture, "Test select statement with join_left", "[query][statement][join_left]") {
const auto ap = table("airplane").as("ap");
const auto f = table("flight").as("f");
const class matador::query::column col1 = {&f, "airplane_id"};
const class matador::query::column col2 = {&ap, "id"};
const auto result = query::select({"f.id", "ap.brand", "f.pilot_name"}) const auto result = query::select({"f.id", "ap.brand", "f.pilot_name"})
.from({"flight", "f"}) .from(table{"flight"}.as("f"))
.join_left({"airplane", "ap"}) .join_left(table{"airplane"}.as("ap"))
.on("f.airplane_id"_col == "ap.id"_col) .on(col1 == col2)
.str(*db); .str(*db);
REQUIRE(result == R"(SELECT "f"."id", "ap"."brand", "f"."pilot_name" FROM "flight" "f" LEFT JOIN "airplane" "ap" ON "f"."airplane_id" = "ap"."id")"); REQUIRE(result == R"(SELECT "f"."id", "ap"."brand", "f"."pilot_name" FROM "flight" "f" LEFT JOIN "airplane" "ap" ON "f"."airplane_id" = "ap"."id")");

View File

@ -26,7 +26,7 @@ TEST_CASE("Generate columns from object", "[column][generator]") {
backend_provider::instance().register_backend("noop", std::make_unique<orm::test_backend_service>()); backend_provider::instance().register_backend("noop", std::make_unique<orm::test_backend_service>());
connection_pool pool("noop://noop.db", 4); connection_pool pool("noop://noop.db", 4);
schema s(pool); schema s;
auto result = s.attach<product>("product"); auto result = s.attach<product>("product");
REQUIRE( result ); REQUIRE( result );
@ -56,7 +56,7 @@ TEST_CASE("Generate columns for object with has many relation", "[column][genera
backend_provider::instance().register_backend("noop", std::make_unique<orm::test_backend_service>()); backend_provider::instance().register_backend("noop", std::make_unique<orm::test_backend_service>());
connection_pool pool("noop://noop.db", 4); connection_pool pool("noop://noop.db", 4);
schema s(pool); schema s;
auto result = s.attach<supplier>("supplier") auto result = s.attach<supplier>("supplier")
.and_then( [&s] { return s.attach<category>("categories"); } ) .and_then( [&s] { return s.attach<category>("categories"); } )
.and_then( [&s] { return s.attach<order_details>("order_details"); } ) .and_then( [&s] { return s.attach<order_details>("order_details"); } )
@ -99,7 +99,7 @@ TEST_CASE("Generate columns for object with eager foreign key relation", "[colum
backend_provider::instance().register_backend("noop", std::make_unique<orm::test_backend_service>()); backend_provider::instance().register_backend("noop", std::make_unique<orm::test_backend_service>());
connection_pool pool("noop://noop.db", 4); connection_pool pool("noop://noop.db", 4);
schema s(pool); schema s;
auto result = s.attach<book>("books") auto result = s.attach<book>("books")
.and_then( [&s] { return s.attach<author>("authors"); } ); .and_then( [&s] { return s.attach<author>("authors"); } );
REQUIRE(result); REQUIRE(result);