progress on combining foreign_node_completer and relation_completer

This commit is contained in:
Sascha Kühl 2025-12-05 15:38:35 +01:00
parent 98da0884f1
commit 2e354b435c
20 changed files with 195 additions and 108 deletions

View File

@ -27,7 +27,7 @@ struct author {
field::attribute( op, "date_of_birth", date_of_birth, 31 ); field::attribute( op, "date_of_birth", date_of_birth, 31 );
field::attribute( op, "year_of_birth", year_of_birth ); field::attribute( op, "year_of_birth", year_of_birth );
field::attribute( op, "distinguished", distinguished ); field::attribute( op, "distinguished", distinguished );
field::has_many( op, "books", books, "author_id", matador::utils::default_foreign_attributes ); field::has_many( op, "books", books, "author_id", matador::utils::CascadeNoneFetchLazy );
} }
}; };
} }

View File

@ -18,7 +18,7 @@ struct book {
namespace field = matador::access; namespace field = matador::access;
field::primary_key( op, "id", id ); field::primary_key( op, "id", id );
field::attribute( op, "title", title, 511 ); field::attribute( op, "title", title, 511 );
field::belongs_to( op, "author_id", book_author, matador::utils::default_foreign_attributes ); field::belongs_to( op, "author_id", book_author, matador::utils::CascadeNoneFetchLazy );
field::attribute( op, "published_in", published_in ); field::attribute( op, "published_in", published_in );
} }
}; };

View File

@ -49,7 +49,7 @@ struct book {
namespace field = matador::access; namespace field = matador::access;
field::primary_key( op, "id", id ); field::primary_key( op, "id", id );
field::attribute( op, "title", title, 511 ); field::attribute( op, "title", title, 511 );
field::has_one( op, "author_id", book_author, matador::utils::default_foreign_attributes ); field::has_one( op, "author_id", book_author, matador::utils::CascadeNoneFetchLazy );
field::attribute( op, "published_in", published_in ); field::attribute( op, "published_in", published_in );
} }
}; };
@ -89,7 +89,7 @@ struct job {
void process( Operator& op ) { void process( Operator& op ) {
namespace field = matador::access; namespace field = matador::access;
field::primary_key( op, "id", id ); field::primary_key( op, "id", id );
field::belongs_to( op, "payload", data, matador::utils::default_foreign_attributes ); field::belongs_to( op, "payload", data, matador::utils::CascadeNoneFetchLazy );
field::attribute( op, "type", type, 511 ); field::attribute( op, "type", type, 511 );
field::attribute( op, "description", description, 511 ); field::attribute( op, "description", description, 511 );
field::attribute( op, "state", state ); field::attribute( op, "state", state );

View File

@ -82,7 +82,7 @@ struct profile {
field::primary_key( op, "id", id ); field::primary_key( op, "id", id );
field::attribute( op, "first_name", first_name, 255 ); field::attribute( op, "first_name", first_name, 255 );
field::attribute( op, "last_name", last_name, 255 ); field::attribute( op, "last_name", last_name, 255 );
field::belongs_to( op, "user_id", user, matador::utils::default_foreign_attributes ); field::belongs_to( op, "user_id", user, matador::utils::CascadeNoneFetchLazy );
} }
}; };
struct user { struct user {
@ -95,7 +95,7 @@ struct user {
namespace field = matador::access; namespace field = matador::access;
field::primary_key( op, "id", id ); field::primary_key( op, "id", id );
field::attribute( op, "username", username, 255 ); field::attribute( op, "username", username, 255 );
field::has_one(op, "profile_id", profile, matador::utils::default_foreign_attributes ); field::has_one(op, "profile_id", profile, matador::utils::CascadeNoneFetchLazy );
} }
}; };
@ -119,7 +119,7 @@ struct person_repo {
void process(Operator &op) { void process(Operator &op) {
namespace field = matador::access; namespace field = matador::access;
field::primary_key( op, "id", id ); field::primary_key( op, "id", id );
field::has_many( op, "person_list", person_list, "person_id", matador::utils::default_foreign_attributes ); field::has_many( op, "person_list", person_list, "person_id", matador::utils::CascadeNoneFetchLazy );
} }
}; };
} }

View File

@ -14,7 +14,7 @@ struct IdListPayload : Payload {
void process( Operator& op ) { void process( Operator& op ) {
namespace field = matador::access; namespace field = matador::access;
field::process( op, *matador::base_class<Payload>( this ) ); field::process( op, *matador::base_class<Payload>( this ) );
field::has_many( op, "payload_ids", payload_ids, "payload_id", matador::utils::default_foreign_attributes ); field::has_many( op, "payload_ids", payload_ids, "payload_id", matador::utils::CascadeNoneFetchLazy );
} }
}; };
} }

View File

@ -19,6 +19,7 @@ namespace matador::object {
* that all foreign nodes needed by the given node * that all foreign nodes needed by the given node
* relations are attached in schema. * relations are attached in schema.
*/ */
template < typename NodeType >
class foreign_node_completer final { class foreign_node_completer final {
private: private:
using node_ptr = std::shared_ptr<repository_node>; using node_ptr = std::shared_ptr<repository_node>;
@ -27,9 +28,9 @@ public:
template<class Type> template<class Type>
static void complete(const std::shared_ptr<repository_node> &node) { static void complete(const std::shared_ptr<repository_node> &node) {
internal::shadow_repository shadow(node->repo_); internal::shadow_repository shadow(node->repo_);
foreign_node_completer completer(shadow); foreign_node_completer<Type> completer(shadow);
completer.complete_node<Type>(node); completer.complete_node(node);
} }
template<class PrimaryKeyType> template<class PrimaryKeyType>
@ -56,13 +57,14 @@ 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 foreign_node_completer(internal::shadow_repository &shadow); explicit foreign_node_completer(internal::shadow_repository &shadow)
: repo_(shadow)
, log_(logger::create_logger("node_completer")) {}
template<typename Type>
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);
Type obj; NodeType obj;
access::process(*this, obj); access::process(*this, obj);
nodes_.pop(); nodes_.pop();
} }
@ -77,6 +79,21 @@ private:
complete<Type>(result.value()); complete<Type>(result.value());
} }
} }
template<typename Type>
void attach_relation_node(const std::string &name) {
if (repo_.contains(typeid(Type))) {
return;
}
const auto node = repository_node::make_node<Type>(repo_.repo(), "");
if (auto result = repo_.attach_node(node)) {
complete<Type>(result.value());
}
}
private:
template< typename Type >
friend class foreign_node_completer;
private: private:
std::stack<node_ptr> nodes_; std::stack<node_ptr> nodes_;
internal::shadow_repository &repo_; internal::shadow_repository &repo_;
@ -85,29 +102,34 @@ private:
}; };
template < typename NodeType >
template<class ForeignPointerType> template<class ForeignPointerType>
void foreign_node_completer::on_belongs_to( const char* /*id*/, ForeignPointerType&, const utils::foreign_attributes& ) { void foreign_node_completer<NodeType>::on_belongs_to( const char* /*id*/, ForeignPointerType&, const utils::foreign_attributes& ) {
attach_node<typename ForeignPointerType::value_type>(); attach_node<typename ForeignPointerType::value_type>();
} }
template < typename NodeType >
template<class ForeignPointerType> template<class ForeignPointerType>
void foreign_node_completer::on_has_one( const char*, ForeignPointerType&, const utils::foreign_attributes& ) { void foreign_node_completer<NodeType>::on_has_one( const char*, ForeignPointerType&, const utils::foreign_attributes& ) {
attach_node<typename ForeignPointerType::value_type>(); attach_node<typename ForeignPointerType::value_type>();
} }
template < typename NodeType >
template<class CollectionType> template<class CollectionType>
void foreign_node_completer::on_has_many( const char* /*id*/, CollectionType&, const char* /*join_column*/, const utils::foreign_attributes& /*attr*/, std::enable_if_t<is_object_ptr<typename CollectionType::value_type>::value>* ) { void foreign_node_completer<NodeType>::on_has_many( const char* /*id*/, CollectionType&, const char* /*join_column*/, const utils::foreign_attributes& /*attr*/, std::enable_if_t<is_object_ptr<typename CollectionType::value_type>::value>* ) {
attach_node<typename CollectionType::value_type::value_type>(); attach_node<typename CollectionType::value_type::value_type>();
} }
template < typename NodeType >
template<class CollectionType> template<class CollectionType>
void foreign_node_completer::on_has_many_to_many( const char* /*id*/, CollectionType& /*collection*/, const char* /*join_column*/, const char* /*inverse_join_column*/, const utils::foreign_attributes& /*attr*/ ) { void foreign_node_completer<NodeType>::on_has_many_to_many( const char* id, CollectionType& /*collection*/, const char* /*join_column*/, const char* /*inverse_join_column*/, const utils::foreign_attributes& /*attr*/ ) {
attach_node<typename CollectionType::value_type::value_type>(/*id*/); attach_relation_node<typename CollectionType::value_type::value_type>(id);
} }
template < typename NodeType >
template<class CollectionType> template<class CollectionType>
void foreign_node_completer::on_has_many_to_many( const char* /*id*/, CollectionType& /*collection*/, const utils::foreign_attributes& /*attr*/ ) { void foreign_node_completer<NodeType>::on_has_many_to_many( const char* id, CollectionType& /*collection*/, const utils::foreign_attributes& /*attr*/ ) {
attach_node<typename CollectionType::value_type::value_type>(/*id*/); attach_relation_node<typename CollectionType::value_type::value_type>(id);
} }
} }

View File

@ -19,8 +19,8 @@ public:
template<class Operator> template<class Operator>
void process(Operator &op) { void process(Operator &op) {
namespace field = matador::access; namespace field = matador::access;
field::belongs_to(op, local_name_.c_str(), local_, utils::default_foreign_attributes); field::belongs_to(op, local_name_.c_str(), local_, utils::CascadeNoneFetchLazy);
field::belongs_to(op, remote_name_.c_str(), remote_, utils::default_foreign_attributes); field::belongs_to(op, remote_name_.c_str(), remote_, utils::CascadeNoneFetchLazy);
} }
object_ptr<LocalType> local() const { return local_; } object_ptr<LocalType> local() const { return local_; }
@ -44,7 +44,7 @@ public:
template<class Operator> template<class Operator>
void process(Operator &op) { void process(Operator &op) {
namespace field = matador::access; namespace field = matador::access;
field::belongs_to(op, local_name_.c_str(), local_, utils::default_foreign_attributes); field::belongs_to(op, local_name_.c_str(), local_, utils::CascadeNoneFetchLazy);
field::attribute(op, type_name_.c_str(), value_); field::attribute(op, type_name_.c_str(), value_);
} }

View File

@ -257,7 +257,9 @@ void relation_completer<Type>::on_has_many_to_many(const char *id,
const auto foreign_node = result.value(); const auto foreign_node = result.value();
result = schema_.find_node(id); result = schema_.find_node(id);
if (!result) { if (result) {
return;
}
// Relation not found. // Relation not found.
auto creator = [join_column, inverse_join_column] { auto creator = [join_column, inverse_join_column] {
return std::make_unique<relation_value_type>(join_column, inverse_join_column); return std::make_unique<relation_value_type>(join_column, inverse_join_column);
@ -281,12 +283,10 @@ void relation_completer<Type>::on_has_many_to_many(const char *id,
// register endpoints in relation node // register endpoints in relation node
node->info_->register_relation_endpoint(nodes_.top()->type_index(), join_endpoint); node->info_->register_relation_endpoint(nodes_.top()->type_index(), join_endpoint);
node->info_->register_relation_endpoint(typeid(typename CollectionType::value_type::value_type), inverse_join_endpoint); node->info_->register_relation_endpoint(typeid(typename CollectionType::value_type::value_type), inverse_join_endpoint);
// link endpoints // link endpoints
link_relation_endpoints(local_endpoint, join_endpoint); link_relation_endpoints(local_endpoint, join_endpoint);
link_relation_endpoints(foreign_endpoint, inverse_join_endpoint); link_relation_endpoints(foreign_endpoint, inverse_join_endpoint);
} }
}
template<typename Type> template<typename Type>
template<class CollectionType> template<class CollectionType>

View File

@ -45,7 +45,7 @@ public:
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::complete<Type>(node); foreign_node_completer<Type>::template complete<Type>(node);
relation_completer<Type>::complete(node); relation_completer<Type>::complete(node);
} else if (!has_node(name)) { } else if (!has_node(name)) {
it->second->update_name(name); it->second->update_name(name);
@ -177,10 +177,19 @@ private:
static void insert_node(const node_ptr &parent, const node_ptr &child); static void insert_node(const node_ptr &parent, const node_ptr &child);
void remove_node(const node_ptr &node); void remove_node(const node_ptr &node);
bool expecting_relation_node(const std::string &name) const;
template<typename NodeType>
void expect_relation_node(const std::string &name) {
expected_relation_nodes_[name] = std::type_index(typeid(NodeType));
}
void remove_expected_relation_node(const std::string &name);
private: private:
friend class internal::shadow_repository; friend class internal::shadow_repository;
friend class repository_node; friend class repository_node;
friend class attribute_generator; friend class attribute_generator;
template < typename NodeType >
friend class foreign_node_completer;
std::string name_; std::string name_;
std::shared_ptr<repository_node> root_; std::shared_ptr<repository_node> root_;
@ -190,6 +199,7 @@ private:
logger::logger log_; logger::logger log_;
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_;
}; };
} }

View File

@ -96,6 +96,7 @@ private:
friend class repository; friend class repository;
template<typename Type> template<typename Type>
friend class relation_completer; friend class relation_completer;
template < typename NodeType >
friend class foreign_node_completer; friend class foreign_node_completer;
friend class const_repository_node_iterator; friend class const_repository_node_iterator;

View File

@ -212,15 +212,15 @@ public:
template < class Type > template < class Type >
static void on_attribute(const char * /*id*/, Type &/*x*/, const utils::field_attributes &/*attr*/ = utils::null_attributes) {} static void on_attribute(const char * /*id*/, Type &/*x*/, const utils::field_attributes &/*attr*/ = utils::null_attributes) {}
template < class Pointer > template < class Pointer >
static void on_belongs_to(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/ = utils::default_foreign_attributes) {} static void on_belongs_to(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/ = utils::CascadeNoneFetchLazy) {}
template < class Pointer > template < class Pointer >
static void on_has_one(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/ = utils::default_foreign_attributes) {} static void on_has_one(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/ = utils::CascadeNoneFetchLazy) {}
template<class ContainerType> template<class ContainerType>
static void on_has_many(const char * /*id*/, static void on_has_many(const char * /*id*/,
ContainerType &/*c*/, ContainerType &/*c*/,
const char * /*join_column*/, const char * /*join_column*/,
const utils::foreign_attributes &/*attr*/ = utils::default_foreign_attributes) {} const utils::foreign_attributes &/*attr*/ = utils::CascadeNoneFetchLazy) {}
template<class ContainerType> template<class ContainerType>
static void on_has_many_to_many(const char * /*id*/, static void on_has_many_to_many(const char * /*id*/,
ContainerType &/*c*/, ContainerType &/*c*/,

View File

@ -34,15 +34,15 @@ public:
template < class Type > template < class Type >
static void on_attribute(const char * /*id*/, Type &/*x*/, const utils::field_attributes &/*attr*/ = utils::null_attributes) {} static void on_attribute(const char * /*id*/, Type &/*x*/, const utils::field_attributes &/*attr*/ = utils::null_attributes) {}
template < class Pointer > template < class Pointer >
static void on_belongs_to(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/ = utils::default_foreign_attributes) {} static void on_belongs_to(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/ = utils::CascadeNoneFetchLazy) {}
template < class Pointer > template < class Pointer >
static void on_has_one(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/ = utils::default_foreign_attributes) {} static void on_has_one(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/ = utils::CascadeNoneFetchLazy) {}
template<class ContainerType> template<class ContainerType>
static void on_has_many(const char * /*id*/, static void on_has_many(const char * /*id*/,
ContainerType &/*c*/, ContainerType &/*c*/,
const char * /*join_column*/, const char * /*join_column*/,
const utils::foreign_attributes &/*attr*/ = utils::default_foreign_attributes) {} const utils::foreign_attributes &/*attr*/ = utils::CascadeNoneFetchLazy) {}
template<class ContainerType> template<class ContainerType>
static void on_has_many_to_many(const char * /*id*/, static void on_has_many_to_many(const char * /*id*/,
ContainerType &/*c*/, ContainerType &/*c*/,
@ -88,18 +88,18 @@ public:
void on_attribute(const char *id, utils::value &val, const utils::field_attributes &attr = utils::null_attributes); void on_attribute(const char *id, utils::value &val, const utils::field_attributes &attr = utils::null_attributes);
template<class Type, template < class ... > class Pointer> template<class Type, template < class ... > class Pointer>
void on_belongs_to(const char *id, Pointer<Type> &x, const utils::foreign_attributes &/*attr*/ = utils::default_foreign_attributes) { void on_belongs_to(const char *id, Pointer<Type> &x, const utils::foreign_attributes &/*attr*/ = utils::CascadeNoneFetchLazy) {
fk_result_binder_.bind(*x, id, index_++, *binder_); fk_result_binder_.bind(*x, id, index_++, *binder_);
} }
template<class Type, template < class ... > class Pointer> template<class Type, template < class ... > class Pointer>
void on_has_one(const char *id, Pointer<Type> &x, const utils::foreign_attributes &/*attr*/ = utils::default_foreign_attributes) { void on_has_one(const char *id, Pointer<Type> &x, const utils::foreign_attributes &/*attr*/ = utils::CascadeNoneFetchLazy) {
fk_result_binder_.bind(*x, id, index_++, *binder_); fk_result_binder_.bind(*x, id, index_++, *binder_);
} }
template<class ContainerType> template<class ContainerType>
static void on_has_many(const char * /*id*/, static void on_has_many(const char * /*id*/,
ContainerType &/*c*/, ContainerType &/*c*/,
const char * /*join_column*/, const char * /*join_column*/,
const utils::foreign_attributes &/*attr*/ = utils::default_foreign_attributes) {} const utils::foreign_attributes &/*attr*/ = utils::CascadeNoneFetchLazy) {}
template<class ContainerType> template<class ContainerType>
static void on_has_many_to_many(const char * /*id*/, static void on_has_many_to_many(const char * /*id*/,
ContainerType &/*c*/, ContainerType &/*c*/,

View File

@ -29,18 +29,18 @@ public:
} }
template<class Type, template < class ... > class Pointer> template<class Type, template < class ... > class Pointer>
void on_belongs_to(const char * /*id*/, Pointer<Type> &x, const utils::foreign_attributes &/*attr*/ = utils::default_foreign_attributes) { void on_belongs_to(const char * /*id*/, Pointer<Type> &x, const utils::foreign_attributes &/*attr*/ = utils::CascadeNoneFetchLazy) {
pk_binder_.bind(*x, index_++, *binder_); pk_binder_.bind(*x, index_++, *binder_);
} }
template<class Type, template < class ... > class Pointer> template<class Type, template < class ... > class Pointer>
void on_has_one(const char * /*id*/, Pointer<Type> &x, const utils::foreign_attributes &/*attr*/ = utils::default_foreign_attributes) { void on_has_one(const char * /*id*/, Pointer<Type> &x, const utils::foreign_attributes &/*attr*/ = utils::CascadeNoneFetchLazy) {
pk_binder_.bind(*x, index_++, *binder_); pk_binder_.bind(*x, index_++, *binder_);
} }
template<class ContainerType> template<class ContainerType>
static void on_has_many(const char * /*id*/, static void on_has_many(const char * /*id*/,
ContainerType &/*c*/, ContainerType &/*c*/,
const char * /*join_column*/, const char * /*join_column*/,
const utils::foreign_attributes &/*attr*/ = utils::default_foreign_attributes) {} const utils::foreign_attributes &/*attr*/ = utils::CascadeNoneFetchLazy) {}
template<class ContainerType> template<class ContainerType>
static void on_has_many_to_many(const char * /*id*/, static void on_has_many_to_many(const char * /*id*/,
ContainerType &/*c*/, ContainerType &/*c*/,

View File

@ -26,15 +26,15 @@ public:
template < class Type > template < class Type >
static void on_attribute(const char * /*id*/, Type &/*x*/, const utils::field_attributes &/*attr*/ = utils::null_attributes) {} static void on_attribute(const char * /*id*/, Type &/*x*/, const utils::field_attributes &/*attr*/ = utils::null_attributes) {}
template < class Pointer > template < class Pointer >
static void on_belongs_to(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/ = utils::default_foreign_attributes) {} static void on_belongs_to(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/ = utils::CascadeNoneFetchLazy) {}
template < class Pointer > template < class Pointer >
static void on_has_one(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/ = utils::default_foreign_attributes) {} static void on_has_one(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/ = utils::CascadeNoneFetchLazy) {}
template<class ContainerType> template<class ContainerType>
static void on_has_many(const char * /*id*/, static void on_has_many(const char * /*id*/,
ContainerType &/*c*/, ContainerType &/*c*/,
const char * /*join_column*/, const char * /*join_column*/,
const utils::foreign_attributes &/*attr*/ = utils::default_foreign_attributes) {} const utils::foreign_attributes &/*attr*/ = utils::CascadeNoneFetchLazy) {}
template<class ContainerType> template<class ContainerType>
static void on_has_many_to_many(const char * /*id*/, static void on_has_many_to_many(const char * /*id*/,
ContainerType &/*c*/, ContainerType &/*c*/,

View File

@ -4,6 +4,7 @@
#include "matador/utils/fetch_type.hpp" #include "matador/utils/fetch_type.hpp"
#include "matador/utils/cascade_type.hpp" #include "matador/utils/cascade_type.hpp"
// ReSharper disable CppNonExplicitConvertingConstructor
namespace matador::utils { namespace matador::utils {
class foreign_attributes class foreign_attributes
@ -27,7 +28,9 @@ private:
fetch_type fetch_{fetch_type::LAZY}; fetch_type fetch_{fetch_type::LAZY};
}; };
const foreign_attributes default_foreign_attributes {}; const foreign_attributes CascadeNoneFetchLazy {};
const foreign_attributes CascadeAllFetchLazy {cascade_type::ALL, fetch_type::LAZY};
const foreign_attributes CascadeAllFetchEager {cascade_type::ALL, fetch_type::EAGER};
} }

View File

@ -1,11 +0,0 @@
#include "matador/object/foreign_node_completer.hpp"
#include "matador/object/repository.hpp"
#include "matador/logger/logger.hpp"
namespace matador::object {
foreign_node_completer::foreign_node_completer(internal::shadow_repository &shadow)
: repo_(shadow)
, log_(logger::create_logger("node_completer")) {}
}

View File

@ -201,4 +201,12 @@ bool repository::has_node(const std::type_index &index) const {
bool repository::has_node(const node_ptr& node) const { bool repository::has_node(const node_ptr& node) const {
return nodes_by_name_.count(node->name()) > 0 || nodes_by_type_.count(node->type_index()) > 0; return nodes_by_name_.count(node->name()) > 0 || nodes_by_type_.count(node->type_index()) > 0;
} }
bool repository::expecting_relation_node( const std::string& name ) const {
return expected_relation_nodes_.count(name) > 0;
}
void repository::remove_expected_relation_node( const std::string& name ) {
expected_relation_nodes_.erase(name);
}
} // namespace matador::object } // namespace matador::object

View File

@ -8,11 +8,12 @@
#include "matador/orm/schema.hpp" #include "matador/orm/schema.hpp"
#include "../models/department.hpp" #include "../models/department.hpp"
#include "../models/recipe.hpp"
using namespace matador; using namespace matador;
using namespace matador::test; using namespace matador::test;
TEST_CASE_METHOD(SchemaFixture, "Test schema one-two-many", "[schema]") { TEST_CASE_METHOD(SchemaFixture, "Test schema one-two-many", "[schema][one-to-many]") {
using namespace matador::test; using namespace matador::test;
orm::schema repo(pool/*, "NoopSchema"*/); orm::schema repo(pool/*, "NoopSchema"*/);
@ -34,3 +35,26 @@ TEST_CASE_METHOD(SchemaFixture, "Test schema one-two-many", "[schema]") {
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]") {
using namespace matador::test;
orm::schema repo(pool/*, "NoopSchema"*/);
auto result = repo.attach<recipe>("recipes")
.and_then( [&repo] { return repo.attach<ingredient>("ingredients"); } );
REQUIRE(result);
result = repo.create();
REQUIRE(result);
auto exists_result = repo.table_exists("recipes");
REQUIRE(exists_result.is_ok());
REQUIRE(exists_result.value());
result = repo.drop();
REQUIRE(result);
exists_result = repo.table_exists("recipes");
REQUIRE(exists_result.is_ok());
REQUIRE(!exists_result.value());
}

View File

@ -3,6 +3,7 @@
#include "matador/object/repository.hpp" #include "matador/object/repository.hpp"
#include "../../models/department.hpp" #include "../../models/department.hpp"
#include "../../models/recipe.hpp"
struct node {}; struct node {};
@ -30,50 +31,51 @@ struct names {
}; };
TEST_CASE("Test empty prototype tree", "[schema_node][empty]") { TEST_CASE("Test empty prototype tree", "[schema_node][empty]") {
const object::repository tree; const object::repository repo;
REQUIRE( tree.empty() ); REQUIRE( repo.empty() );
} }
TEST_CASE("Test add type to prototype tree", "[schema_node][add]") { TEST_CASE("Test add type to prototype tree", "[schema_node][add]") {
object::repository tree; object::repository repo;
REQUIRE( tree.empty() ); REQUIRE( repo.empty() );
auto res = tree.attach<person>("person"); auto res = repo.attach<person>("person");
REQUIRE( res.is_ok() ); REQUIRE( res.is_ok() );
res = tree.attach<student, person>("student"); res = repo.attach<student, person>("student");
REQUIRE( res.is_ok() ); REQUIRE( res.is_ok() );
res = tree.attach<teacher, person>("teacher"); res = repo.attach<teacher, person>("teacher");
REQUIRE( res.is_ok() ); REQUIRE( res.is_ok() );
REQUIRE( !tree.empty() ); REQUIRE( !repo.empty() );
REQUIRE( tree.size() == 3 ); REQUIRE( repo.size() == 3 );
} }
TEST_CASE("Test next and previous of schema node", "[schema_node][next][previous]") { TEST_CASE("Test next and previous of schema node", "[schema_node][next][previous]") {
object::repository tree; object::repository repo;
REQUIRE( tree.empty() ); REQUIRE( repo.empty() );
auto res = tree.attach<person>("person"); auto res = repo.attach<person>("person");
REQUIRE( res.is_ok() ); REQUIRE( res.is_ok() );
REQUIRE( tree.size() == 1 ); REQUIRE( repo.size() == 1 );
auto it = tree.begin(); auto it = repo.begin();
REQUIRE( it->name() == "person" ); REQUIRE( it->name() == "person" );
REQUIRE( (--it)->name() == "person" ); REQUIRE( (--it)->name() == "person" );
REQUIRE( ++it == tree.end() ); REQUIRE( ++it == repo.end() );
} }
TEST_CASE("Test automatic creating of a relation table with foreign key", "[schema][relation_table][foreign_key]") { TEST_CASE("Test automatic creating of a relation table with foreign key", "[schema][relation_table][foreign_key]") {
object::repository tree; object::repository repo;
REQUIRE( tree.empty() ); REQUIRE( repo.empty() );
auto res = tree.attach<test::department>("department"); auto res = repo.attach<test::department>("department");
REQUIRE( res.is_ok() ); 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]") {
@ -84,3 +86,31 @@ TEST_CASE("Test automatic creating of a relation table with values", "[schema][r
auto res = repo.attach<names>("names"); auto res = repo.attach<names>("names");
REQUIRE( res.is_ok() ); REQUIRE( res.is_ok() );
} }
TEST_CASE("Test one to many", "[relation][one-to-many]") {
object::repository repo;
REQUIRE( repo.empty() );
auto res = repo.attach<test::department>("departments")
.and_then( [&repo] { return repo.attach<test::employee>("employees"); } );
REQUIRE( res.is_ok() );
REQUIRE(repo.size() == 2);
REQUIRE(repo.contains("departments"));
REQUIRE(repo.contains("employees"));
}
TEST_CASE("Test many to many relation", "[relation][many-to-many]") {
object::repository repo;
REQUIRE(repo.empty());
auto result = repo.attach<test::recipe>("recipes")
.and_then( [&repo] { return repo.attach<test::ingredient>("ingredients"); } );
REQUIRE(result);
REQUIRE(repo.size() == 3);
REQUIRE(repo.contains("ingredients"));
REQUIRE(repo.contains("recipes"));
REQUIRE(repo.contains("recipe_ingredients"));
}

View File

@ -21,8 +21,8 @@ struct order_details
void process(Operator &op) { void process(Operator &op) {
namespace field = matador::access; namespace field = matador::access;
field::primary_key(op, "order_details_id", order_details_id); field::primary_key(op, "order_details_id", order_details_id);
field::belongs_to(op, "order_id", order_, utils::default_foreign_attributes); field::belongs_to(op, "order_id", order_, utils::CascadeNoneFetchLazy);
field::has_one(op, "product_id", product_, utils::default_foreign_attributes); field::has_one(op, "product_id", product_, utils::CascadeNoneFetchLazy);
} }
}; };