#ifndef SCHEMA_HPP #define SCHEMA_HPP #include "matador/logger/log_manager.hpp" #include "matador/object/error_code.hpp" #include "matador/object/foreign_node_completer.hpp" #include "matador/object/relation_completer.hpp" #include "matador/object/schema_node.hpp" #include "matador/object/schema_node_iterator.hpp" #include "matador/utils/result.hpp" #include "matador/utils/error.hpp" #include "matador/logger/logger.hpp" #include #include #include namespace matador::object { namespace internal { class shadow_schema; } utils::error make_error(error_code ec, const std::string &msg); class schema { public: typedef const_schema_node_iterator const_iterator; /**< Shortcut for the list const iterator. */ using node_ptr = std::shared_ptr; /** * Creates an empty schema */ explicit schema(std::string name = ""); template [[nodiscard]] utils::result attach(const std::string &name, const std::string &parent = "") { if (const auto it = nodes_by_type_.find(typeid(Type)); it == nodes_by_type_.end() ) { // if the type was not found auto node = schema_node::make_node(*this, name); if (auto result = attach_node(node, parent); !result) { return utils::failure(result.err()); } foreign_node_completer::complete(node); relation_completer::complete(node); } else if (!has_node(name)) { it->second->update_name(name); nodes_by_name_[name] = it->second; relation_completer::complete(it->second); log_.info("attach: update node name to '%s' (type: %s)", it->second->name().c_str(), it->second->type_index().name()); } else { // remove_node( ) return utils::failure(make_error(error_code::NodeAlreadyExists, "Node '" + name + "' already exists")); } return utils::ok(); } template [[nodiscard]] utils::result attach(const std::string &name) { const auto ti = std::type_index(typeid(SuperType)); auto result = find_node(ti); if (!result) { return utils::failure(make_error(error_code::NodeNotFound, "Parent node '" + std::string(ti.name()) + "' not found")); } return attach(name, (*result)->name()); } /** * Detaches a given node from the schema. If the * node is a parent of other nodes, these nodes are * detached as well. * * @param node Node to detach from schema * @return Result object indicating success or failure */ [[nodiscard]] utils::result detach(const node_ptr &node); /** * Return the first schema node. * * @return The first schema node iterator. */ [[nodiscard]] const_iterator begin() const; /** * Return the last schema node. * * @return The last schema node iterator. */ [[nodiscard]] const_iterator end() const; /** * Returns true if the schema contains * no schema nodes. * * @return True if the schema is empty */ [[nodiscard]] bool empty() const; /** * Returns the current number of the schema node. * * @return Number of schema nodes */ [[nodiscard]] size_t size() const; /** * Returns the name of the schema. * * @return The name of the schema */ [[nodiscard]] std::string name() const; [[nodiscard]] bool contains(const std::string &name) const; [[nodiscard]] bool contains(const std::type_index &index) const; template < typename Type > [[nodiscard]] bool contains() const { return contains(std::type_index(typeid(Type))); } template [[nodiscard]] utils::result, utils::error> info() const { auto result = find_node(std::type_index(typeid(Type))); if (!result) { return utils::failure(result.err()); } return utils::ok(result.value()->info()); } template [[nodiscard]] utils::result basic_info() const { auto result = find_node(std::type_index(typeid(Type))); if (!result) { return utils::failure(result.err()); } return utils::ok(basic_object_info_ref{result.value()->info()}); } [[nodiscard]] utils::result, utils::error> reference_column( const std::type_index &type_index) const; void dump(std::ostream &os) const; static void dump(std::ostream &os, const node_ptr& node); private: using t_node_map = std::unordered_map; using t_type_index_node_map = std::unordered_map; [[nodiscard]] utils::result attach_node(const node_ptr &node, const std::string &parent); // [[nodiscard]] utils::result attach_node(const node_ptr &node, const std::type_index &type_index); [[nodiscard]] utils::result find_node(const std::string &name) const; [[nodiscard]] utils::result find_node(const std::type_index &type_index) const; template [[nodiscard]] utils::result find_node() const { return find_node(std::type_index(typeid(Type))); } [[nodiscard]] bool has_node(const std::string &name) const; [[nodiscard]] bool has_node(const std::type_index &index) const; [[nodiscard]] bool has_node(const node_ptr& node) const; static void insert_node(const node_ptr &parent, const node_ptr &child); void remove_node(const node_ptr &node); private: friend class internal::shadow_schema; friend class schema_node; friend class attribute_definition_generator; std::string name_; std::shared_ptr root_; t_node_map nodes_by_name_; t_type_index_node_map nodes_by_type_; logger::logger log_; std::unordered_map > missing_references_; }; } #endif //SCHEMA_HPP