diff --git a/source/orm/orm/session.cpp b/source/orm/orm/session.cpp index 24d9f53..d54ec94 100644 --- a/source/orm/orm/session.cpp +++ b/source/orm/orm/session.cpp @@ -4,35 +4,103 @@ #include "matador/query/query.hpp" +#include #include namespace matador::orm { - -utils::error make_error( const error_code ec, const std::string& msg ) { - return utils::error(ec, msg); +utils::error make_error(const error_code ec, const std::string &msg) { + return utils::error(ec, msg); } session::session(sql::connection_pool &pool) -: pool_(pool) -, dialect_(sql::backend_provider::instance().connection_dialect(pool_.info().type)) -, schema_(std::make_unique(dialect_.default_schema_name())){} + : pool_(pool) + , dialect_(sql::backend_provider::instance().connection_dialect(pool_.info().type)) + , schema_(std::make_unique(dialect_.default_schema_name())) { +} utils::result session::create_schema() const { - std::vector> relations_nodes; + std::vector > relations_nodes; auto c = pool_.acquire(); - for (const auto &node : *schema_) { + for (const auto &node: *schema_) { // if (!node->info().has_primary_key()) { - // relations_nodes.push_back(node); - // continue; + // relations_nodes.push_back(node); + // continue; // } auto result = query::query::create() - .table(node->name(), node->info().definition().columns()) - .execute(*c); - if ( !result ) { + .table(node->name(), node->info().definition().columns()) + .execute(*c); + if (!result) { return utils::failure(result.err()); } } return utils::ok(); + + + // Step 1: Build dependency graph + std::unordered_map > dependency_graph; + std::unordered_map> in_degree; + + for (const auto &node: *schema_) { + for (auto it = node->info().endpoint_begin(); it != node->info().endpoint_end(); ++it) { + dependency_graph[node->name()].push_back(it->second->node().name()); + + in_degree[it->second->node().name()] = std::make_pair(0, it->second->node()); + in_degree[it->second->node().name()]++; + } + + // Ensure the current node exists in the graph representation + + if (in_degree.find(node->name()) == in_degree.end()) { + in_degree[node->name()] = 0; + } + } + + // Step 2: Perform topological sorting (Kahn's Algorithm) + std::queue zero_in_degree; + std::vector sorted_order; + + for (const auto &[table, degree]: in_degree) { + if (degree == 0) { + zero_in_degree.push(table); + } + } + + while (!zero_in_degree.empty()) { + auto current = zero_in_degree.front(); + zero_in_degree.pop(); + sorted_order.push_back(current); + + for (const auto &neighbor: dependency_graph[current]) { + in_degree[neighbor]--; + + if (in_degree[neighbor] == 0) { + zero_in_degree.push(neighbor); + } + } + } + + // Step 3: Check for cycles + + if (sorted_order.size() != in_degree.size()) { + throw std::logic_error("Cycle detected in table dependencies"); + } + + // Step 4: Create tables in the sorted order + + for (const auto &table_name : sorted_order) { + // schema_. + // auto result = query::query::create() + // + // .table(table_name, /* Pass table definition here */) + // + // .execute(*c); + // + // if (!result) { + // + // return utils::failure(result.err()); + // + // } + } } utils::result session::drop_table(const std::string &table_name) const { @@ -42,8 +110,8 @@ utils::result session::drop_table(const std::string &table_n } auto result = query::query::drop() - .table(table_name) - .execute(*c); + .table(table_name) + .execute(*c); if (result.is_error()) { return utils::failure(result.err()); } @@ -51,8 +119,7 @@ utils::result session::drop_table(const std::string &table_n return utils::ok(); } -utils::result, utils::error> session::fetch(const sql::query_context &q) const -{ +utils::result, utils::error> session::fetch(const sql::query_context &q) const { auto c = pool_.acquire(); if (!c.valid()) { throw std::logic_error("no database connection available"); @@ -66,9 +133,9 @@ utils::result, utils::error> session::fetch(const it = prototypes_.emplace(q.table.name, *result).first; } // adjust columns from given query - for (auto &col : q.prototype) { + for (auto &col: q.prototype) { if (const auto rit = it->second.find(col.name()); rit != it->second.end()) { - const_cast(col).type(rit->type()); + const_cast(col).type(rit->type()); } } auto res = c->fetch(q); @@ -83,8 +150,7 @@ size_t session::execute(const std::string &sql) const { return c->execute(sql); } -sql::statement session::prepare(const sql::query_context& q) const -{ +sql::statement session::prepare(const sql::query_context &q) const { auto c = pool_.acquire(); if (!c.valid()) { throw std::logic_error("no database connection available"); @@ -92,8 +158,7 @@ sql::statement session::prepare(const sql::query_context& q) const return c->prepare(q).release(); } -std::vector session::describe_table(const std::string &table_name) const -{ +std::vector session::describe_table(const std::string &table_name) const { auto c = pool_.acquire(); if (!c.valid()) { throw std::logic_error("no database connection available"); @@ -101,8 +166,7 @@ std::vector session::describe_table(const std::str return c->describe(table_name).release(); } -bool session::table_exists(const std::string &table_name) const -{ +bool session::table_exists(const std::string &table_name) const { auto c = pool_.acquire(); if (!c.valid()) { throw std::logic_error("no database connection available"); @@ -110,22 +174,20 @@ bool session::table_exists(const std::string &table_name) const return c->exists(dialect_.default_schema_name(), table_name); } -const class sql::dialect &session::dialect() const -{ +const class sql::dialect &session::dialect() const { return dialect_; } -void session::dump_schema( std::ostream& os ) const { - schema_->dump(os); +void session::dump_schema(std::ostream &os) const { + schema_->dump(os); } query::fetchable_query session::build_select_query(entity_query_data &&data) { return query::query::select(data.columns) - .from(*data.root_table) - .join_left(data.joins) - .where(std::move(data.where_clause)) - .order_by(sql::column{data.root_table, data.pk_column_name}) - .asc(); + .from(*data.root_table) + .join_left(data.joins) + .where(std::move(data.where_clause)) + .order_by(sql::column{data.root_table, data.pk_column_name}) + .asc(); +} } - -} \ No newline at end of file