diff --git a/demo/work.cpp b/demo/work.cpp index 46f33dd..a8fec36 100644 --- a/demo/work.cpp +++ b/demo/work.cpp @@ -25,24 +25,47 @@ using namespace matador; using namespace work::models; +// Proposal for polymorphic classes: +// object_ptr::as does the following checks; +// +// 1. The requested type has super class +// 2. Super class has discriminator column defined +// 3. Super class has discriminator value defined +// 4. Discriminator value is mapped to the requested type +// +// If all checks succeed, the requested is fetched from +// the database. +// schema.attach("payloads", make_polymorph("type")); +// schema.attach("id_list_payloads", make_polymorph_type("IdPayload")); +// schema.attach("id_payloads"make_polymorph_type("IdListPayload")); +// object::object_ptr payload; +// auto result = payload.as(); +// if (result.is_ok()) { +// const auto& is_payload = result.value(); +// // Use requested type +// id_payload->id = 1; +// } +// payload.is_polymorphic(); +// payload.is_polymorphic_type(); + int main() { object::schema schema("Administration"); auto result = schema.attach("collection_center") - .and_then([&schema] { return schema.attach("internal_user_directory"); }) + .and_then([&schema] { return schema.attach("internal_user_directories"); }) .and_then([&schema] { return schema.attach("ldap_group_schema_settings"); }) .and_then([&schema] { return schema.attach("ldap_import_settings"); }) - .and_then([&schema] { return schema.attach("ldap_user_directory"); } ) + .and_then([&schema] { return schema.attach("ldap_user_directories"); } ) .and_then([&schema] { return schema.attach("ldap_user_schema_settings"); }) - .and_then([&schema] { return schema.attach("login_history"); }) - .and_then([&schema] { return schema.attach("scenario"); }) - .and_then([&schema] { return schema.attach("user"); }) - .and_then([&schema] { return schema.attach("user_directory"); }) - .and_then([&schema] { return schema.attach("user_session"); }) + .and_then([&schema] { return schema.attach("login_histories"); }) + .and_then([&schema] { return schema.attach("scenarios"); }) + .and_then([&schema] { return schema.attach("users"); }) + .and_then([&schema] { return schema.attach("user_directories"); }) + .and_then([&schema] { return schema.attach("user_sessions"); }) .and_then([&schema] { return schema.attach("jobs"); }) - .and_then([&schema] { return schema.attach("id_payloads"); }) - .and_then([&schema] { return schema.attach("id_list_payloads"); }) - .and_then([&schema] { return schema.attach("payloads"); }) + .and_then([&schema] { return schema.attach("payloads"); }) + .and_then([&schema] { return schema.attach("id_list_payloads"); }) + .and_then([&schema] { return schema.attach("id_payloads"); }) .and_then([&schema] { return schema.attach("tasks"); }); if (!result.is_ok()) { diff --git a/include/matador/object/basic_object_info.hpp b/include/matador/object/basic_object_info.hpp index 138d807..2c841c8 100644 --- a/include/matador/object/basic_object_info.hpp +++ b/include/matador/object/basic_object_info.hpp @@ -26,27 +26,31 @@ public: [[nodiscard]] const object_definition& definition() const; [[nodiscard]] std::shared_ptr reference_column() const; + bool has_primary_key() const; + [[nodiscard]] const utils::identifier& primary_key() const; + void register_relation_endpoint(const std::type_index &type, const relation_endpoint &endpoint); void unregister_relation_endpoint(const std::type_index &type); - const_endpoint_iterator find_relation_endpoint(const std::type_index &type) const; + [[nodiscard]] const_endpoint_iterator find_relation_endpoint(const std::type_index &type) const; endpoint_iterator find_relation_endpoint(const std::type_index &type); - const_endpoint_iterator find_relation_endpoint(const std::string &field) const; + [[nodiscard]] const_endpoint_iterator find_relation_endpoint(const std::string &field) const; endpoint_iterator find_relation_endpoint(const std::string &field); endpoint_iterator endpoint_begin(); - const_endpoint_iterator endpoint_begin() const; + [[nodiscard]] const_endpoint_iterator endpoint_begin() const; endpoint_iterator endpoint_end(); - const_endpoint_iterator endpoint_end() const; + [[nodiscard]] const_endpoint_iterator endpoint_end() const; - std::size_t endpoints_size() const; - bool endpoints_empty() const; + [[nodiscard]] std::size_t endpoints_size() const; + [[nodiscard]] bool endpoints_empty() const; protected: basic_object_info(std::shared_ptr node, std::type_index type_index, utils::identifier &&pk, std::shared_ptr &&pk_column, object_definition &&definition); basic_object_info(std::shared_ptr node, std::type_index type_index, utils::identifier &&pk, std::shared_ptr &&pk_column); + basic_object_info(std::shared_ptr node, std::type_index type_index, object_definition &&definition); protected: std::shared_ptr node_; /**< prototype node of the represented object type */ diff --git a/include/matador/object/schema.hpp b/include/matador/object/schema.hpp index 75ab7c1..548089c 100644 --- a/include/matador/object/schema.hpp +++ b/include/matador/object/schema.hpp @@ -1,6 +1,7 @@ #ifndef SCHEMA_HPP #define SCHEMA_HPP +#include "matador/object/many_to_many_relation.hpp" #include "matador/object/primary_key_resolver.hpp" #include "matador/object/error_code.hpp" #include "matador/object/schema_node.hpp" @@ -20,6 +21,38 @@ utils::error make_error(error_code ec, const std::string& msg); class schema; +/* + * 1. has_many (MM) + * no belongs to + * relation table is needed + * - element type is a foreign table (FT), + * then relation table must look like follows: + * relation_table + * where MM and FT must be defined as belongs to + * - element type if a builtin type BT (i.e. string, int, etc.), + * then the relation table must look like follows: + * relation_table + * where MM as belongs to and BT as given type + * + * 2. has_many_to_many (MM1, MM2) + * relation_table is needed + * relation_table + * where MM1 and MM2 must be defined as belongs to + * + * 3. hans_many (MM) <-> belongs_to (BT) + * belongs_to has foreign key to the has_many side + * no relation table needed + * + * 4. has_one to belongs_to + * no relation table is needed + * + * 5. has_many (MM) <-> has_one (HO) + * invalid relation -> error + * + * 6. has_one + * no has_many or belongs_to + * invalid relation -> error + */ template class relation_completer final { public: @@ -33,15 +66,15 @@ public: } template < class PrimaryKeyType > - void on_primary_key(const char * /*id*/, PrimaryKeyType &/*pk*/, std::enable_if_t && !std::is_same_v>* = nullptr) {} - void on_primary_key(const char * /*id*/, std::string &/*pk*/, size_t /*size*/) {} - void on_revision(const char * /*id*/, uint64_t &/*rev*/) {} + static void on_primary_key(const char * /*id*/, PrimaryKeyType &/*pk*/, std::enable_if_t && !std::is_same_v>* = nullptr) {} + static void on_primary_key(const char * /*id*/, std::string &/*pk*/, size_t /*size*/) {} + static void on_revision(const char * /*id*/, uint64_t &/*rev*/) {} template - void on_attribute(const char * /*id*/, AttributeType &/*val*/, const utils::field_attributes &/*attr*/ = utils::null_attributes) {} + static void on_attribute(const char * /*id*/, AttributeType &/*val*/, const utils::field_attributes &/*attr*/ = utils::null_attributes) {} template - void on_attribute(const char * /*id*/, std::optional &/*val*/, const utils::field_attributes &/*attr*/ = utils::null_attributes) {} + static void on_attribute(const char * /*id*/, std::optional &/*val*/, const utils::field_attributes &/*attr*/ = utils::null_attributes) {} template void on_belongs_to(const char * /*id*/, ForeignPointerType &/*obj*/, const utils::foreign_attributes &/*attr*/) { @@ -53,11 +86,13 @@ public: } template - void on_has_many(const char * /*id*/, CollectionType &, const char *, const utils::foreign_attributes &/*attr*/) {} + void on_has_many(const char * /*id*/, CollectionType &, const char *, const utils::foreign_attributes &/*attr*/); + template - void on_has_many_to_many(const char * /*id*/, CollectionType &/*col*/, const char * /*join_column*/, const char * /*inverse_join_column*/, const utils::foreign_attributes &/*attr*/) {} + void on_has_many_to_many(const char *id, CollectionType &collection, const char *join_column, const char *inverse_join_column, const utils::foreign_attributes &attr); + template - void on_has_many_to_many(const char * /*id*/, ContainerType &/*col*/, const utils::foreign_attributes &/*attr*/) {} + void on_has_many_to_many(const char *id, ContainerType &collection, const utils::foreign_attributes &attr); private: template @@ -109,9 +144,9 @@ public: return utils::ok(); } - template + template [[nodiscard]] utils::result attach(const std::string name) { - const auto ti = std::type_index(typeid(ParentType)); + const auto ti = std::type_index(typeid(SuperType)); auto result = find_node(ti); if (!result) { return utils::failure(make_error(error_code::NodeNotFound, "Parent node '" + std::string(ti.name()) + "' not found")); @@ -208,6 +243,36 @@ private: t_type_index_node_map expected_node_map_; }; +template +template +void relation_completer::on_has_many( const char*, CollectionType&, const char*, const utils::foreign_attributes& ) { + + +} + +template +template +void relation_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) { + auto result = schema_.find_node(id); + if (result) { + } else { + // + using relation_type = many_to_many_relation; + auto creator = [join_column, inverse_join_column] { + return new many_to_many_relation(join_column, inverse_join_column); + }; + + auto node = schema_node::make_relation_node(schema_, id); + + schema_.attach_node(node, typeid(relation_type)); + } +} + +template +template +void relation_completer::on_has_many_to_many( const char *id, ContainerType &collection, const utils::foreign_attributes &attr ) { +} + template template void relation_completer::on_foreign_key() { diff --git a/include/matador/object/schema_node.hpp b/include/matador/object/schema_node.hpp index 9146fd7..32b6734 100644 --- a/include/matador/object/schema_node.hpp +++ b/include/matador/object/schema_node.hpp @@ -33,6 +33,19 @@ public: return node; } + template < typename Type > + static std::shared_ptr make_relation_node(schema& tree, const std::string& name) { + auto node = std::shared_ptr(new schema_node(tree, name)); + + auto info = std::make_unique>( + node, + object_definition{attribute_definition_generator::generate(tree)} + ); + node->info_ = std::move(info); + + return node; + } + static std::shared_ptr make_null_node(schema& tree); schema_node(const schema_node& other) = delete; diff --git a/source/core/object/basic_object_info.cpp b/source/core/object/basic_object_info.cpp index b0aeb55..5e7d1d2 100644 --- a/source/core/object/basic_object_info.cpp +++ b/source/core/object/basic_object_info.cpp @@ -27,6 +27,13 @@ basic_object_info::basic_object_info(std::shared_ptr node, , pk_column_(std::move(pk_column)) { } +basic_object_info::basic_object_info(std::shared_ptr node, + const std::type_index type_index, + object_definition &&definition) +: node_(std::move(node)) +, type_index_(type_index) +, definition_(std::move(definition)) {} + std::type_index basic_object_info::type_index() const { return type_index_; } @@ -43,6 +50,14 @@ std::shared_ptr basic_object_info::reference_column() cons return pk_column_; } +bool basic_object_info::has_primary_key() const { + return identifier_.has_value(); +} + +const utils::identifier& basic_object_info::primary_key() const { + return identifier_.value(); +} + void basic_object_info::register_relation_endpoint(const std::type_index &type, const relation_endpoint &endpoint) { relation_endpoints_.insert(std::make_pair(type, endpoint)); }