query/source/core/object/repository.cpp

203 lines
6.9 KiB
C++

#include <utility>
#include "matador/object/repository.hpp"
namespace matador::object {
utils::error make_error(const error_code ec, const std::string &msg) {
return utils::error(ec, msg);
}
repository::repository(std::string name)
: name_(std::move(name))
, root_(repository_node::make_null_node(*this))
, log_(logger::create_logger("schema")) {
root_->first_child_ = std::shared_ptr<repository_node>(new repository_node(*this));
root_->last_child_ = std::shared_ptr<repository_node>(new repository_node(*this));
root_->first_child_->next_sibling_ = root_->last_child_;
root_->last_child_->previous_sibling_ = root_->first_child_;
}
utils::result<void, utils::error> repository::detach(const node_ptr &node) {
log_.debug("detach node '%s' (type: %s)", node->name().c_str(), node->type_index().name());
remove_node(node);
return utils::ok<void>();
}
repository::const_iterator repository::begin() const {
return const_iterator(root_->first_child_->next_sibling_);
}
repository::const_iterator repository::end() const {
return const_iterator(root_->last_child_);
}
bool repository::empty() const {
return root_->first_child_ == root_->last_child_->previous_sibling_;
}
size_t repository::size() const {
return static_cast<size_t>(std::distance(begin(), end()));
}
std::string repository::name() const {
return name_;
}
bool repository::contains( const std::string& name ) const {
return nodes_by_name_.count(name) > 0;
}
bool repository::contains( const std::type_index& index ) const {
return nodes_by_type_.count(index) > 0;
}
utils::result<std::shared_ptr<attribute_definition>, utils::error> repository::reference_column(const std::type_index &type_index) const {
const auto result = find_node(type_index);
if (result) {
return utils::ok((*result)->info().reference_column());
}
return utils::failure(result.err());
}
void repository::dump(std::ostream &os) const {
for (const auto &node : *this) {
dump(os, node);
}
os << "\n";
}
void repository::dump( std::ostream& os, const node_ptr& node ) {
os << "node [" << node->name() << "] (" << node->type_index().name() << ")\n";
for (auto it = node->info().endpoint_begin(); it != node->info().endpoint_end(); ++it) {
os << " " << node->name() << "::" << it->second->field_name() << " (" << it->second->type_name() << ")";
if (it->second->foreign_endpoint()) {
os << " <---> " << it->second->node().name() << "::" << it->second->foreign_endpoint()->field_name() << " (" << it->second->foreign_endpoint()->type_name() << ")\n";
} else {
os << " -> " << it->second->node().name() << " (type: " << it->second->node().type_index().name() << ")\n";
}
}
}
utils::result<repository::node_ptr, utils::error> repository::attach_node(const std::shared_ptr<repository_node> &node,
const std::string &parent) {
if (has_node(node)) {
return utils::failure(make_error(error_code::NodeAlreadyExists, "Node '" + node->name() + "' already exists."));
}
log_.info("attach: insert node '%s' (type: %s)", node->name().c_str(), node->type_index().name());
// set node to root node
auto parent_node = root_;
if (!parent.empty()) {
auto result = find_node(parent);
if (!result.is_ok() && result.err().ec() != error_code::NodeNotFound) {
return result;
}
parent_node = *result;
}
insert_node(parent_node, node);
// Todo: check return value
nodes_by_name_.insert({node->name(), node});
nodes_by_type_.insert({node->type_index(), node});
return utils::ok(node);
}
// utils::result<schema::node_ptr, utils::error> schema::attach_node(const std::shared_ptr<schema_node> &node,
// const std::type_index &type_index) {
// if (has_node(node)) {
// return utils::failure(make_error(error_code::NodeAlreadyExists, "Node '" + node->name() + "' already exists."));
// }
// auto result = find_node(type_index);
// if (!result.is_ok() && result.err().ec() != error_code::NodeNotFound) {
// return result;
// }
//
// insert_node(*result, node);
//
// // Todo: check return value
// nodes_by_name_.insert({node->name(), node})/*.first*/;
// nodes_by_type_.insert({node->type_index(), node});
//
// return utils::ok(node);
// }
utils::result<repository::node_ptr, utils::error> repository::find_node(const std::string &name) const {
// first search in the prototype map
const auto i = nodes_by_name_.find(name);
if (i == nodes_by_name_.end()) {
return utils::failure(make_error(error_code::NodeNotFound, "Couldn't find node by name '" + name + "'"));
}
return utils::ok(i->second);
}
utils::result<repository::node_ptr, utils::error> repository::find_node(const std::type_index &type_index) const {
const auto i = nodes_by_type_.find(type_index);
if (i == nodes_by_type_.end()) {
return utils::failure(make_error(error_code::NodeNotFound,
"Couldn't find node by type '" + std::string(type_index.name()) + "'"));
}
return utils::ok(i->second);
}
void repository::insert_node(const node_ptr &parent, const node_ptr &child) {
child->parent_ = parent;
child->previous_sibling_ = parent->last_child_->previous_sibling_;
child->next_sibling_ = parent->last_child_;
/*
* +-----------------------------<- (first) parent (last) -> ----------------------------+
* | |
* first (next) -> <- (prev) child_1 (next) -> <- (prev) new_child (next) -> <- (prev) last
* ^^^^^^^ inserted ^^^^^^
*/
parent->last_child_->previous_sibling_->next_sibling_ = child;
parent->last_child_->previous_sibling_ = child;
// set depth
// child->depth = depth + 1;
}
void repository::remove_node(const node_ptr &node) {
auto next = node->next();
std::stack<node_ptr> nodes_to_remove;
nodes_to_remove.push(node);
while (!nodes_to_remove.empty()) {
const auto current = nodes_to_remove.top();
if (current->has_children()) {
// Push all children to the stack (from right to left to maintain order)
auto child = current->last_child_->previous_sibling_;
while (child != current->first_child_) {
nodes_to_remove.push(child);
child = child->previous_sibling_;
}
continue;
}
// No children left, safe to remove this node
nodes_to_remove.pop();
current->unlink();
nodes_by_name_.erase(current->name());
nodes_by_type_.erase(current->type_index());
}
}
bool repository::has_node(const std::string &name) const {
return nodes_by_name_.count(name) > 0;
}
bool repository::has_node(const std::type_index &index) const {
return nodes_by_type_.count(index) > 0;
}
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;
}
} // namespace matador::object