diff --git a/include/matador/object/basic_object_info.hpp b/include/matador/object/basic_object_info.hpp index b057488..8301d96 100644 --- a/include/matador/object/basic_object_info.hpp +++ b/include/matador/object/basic_object_info.hpp @@ -1,6 +1,7 @@ #ifndef BASIC_PROTOTYPE_INFO_HPP #define BASIC_PROTOTYPE_INFO_HPP +#include #include namespace matador::object { @@ -12,6 +13,7 @@ public: virtual ~basic_object_info() = default; [[nodiscard]] std::type_index type_index() const; + [[nodiscard]] std::string name() const; protected: basic_object_info(schema_node &node, std::type_index type_index); @@ -27,8 +29,15 @@ public: explicit object_info(schema_node &node) : basic_object_info(node, typeid(Type)) {} + const Type &prototype() const { return prototype_; } + +private: + Type prototype_; }; +template +using object_info_ref = std::reference_wrapper>; + namespace detail { struct null_type {}; } diff --git a/include/matador/object/schema.hpp b/include/matador/object/schema.hpp index 9e4780b..086f730 100644 --- a/include/matador/object/schema.hpp +++ b/include/matador/object/schema.hpp @@ -83,6 +83,16 @@ public: */ [[nodiscard]] std::string name() const; + 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()); + } + private: using node_ptr = std::shared_ptr; using t_node_map = std::unordered_map; diff --git a/include/matador/object/schema_node.hpp b/include/matador/object/schema_node.hpp index 69b3bb9..ae6f647 100644 --- a/include/matador/object/schema_node.hpp +++ b/include/matador/object/schema_node.hpp @@ -46,6 +46,11 @@ public: [[nodiscard]] node_ptr next() const; [[nodiscard]] node_ptr prev() const; + template + object_info_ref info() const { + return std::ref(static_cast&>(*info_)); + } + private: explicit schema_node(schema& tree); template < typename Type > diff --git a/include/matador/orm/session.hpp b/include/matador/orm/session.hpp new file mode 100644 index 0000000..86569ff --- /dev/null +++ b/include/matador/orm/session.hpp @@ -0,0 +1,171 @@ +#ifndef QUERY_SESSION_HPP +#define QUERY_SESSION_HPP + +#include "matador/sql/connection.hpp" +#include "matador/sql/connection_pool.hpp" +// #include "matador/sql/entity_query_builder.hpp" +#include "matador/sql/statement.hpp" + +#include "matador/object/object_ptr.hpp" +#include "matador/object/schema.hpp" + +#include + +namespace matador::orm { + +class dialect; + +enum class session_error { + Ok = 0, + NoConnectionAvailable, + UnknownType, + FailedToBuildQuery, + FailedToFindObject +}; + +class session +{ +public: + explicit session(sql::connection_pool &pool); + + template + void attach(const std::string &table_name); + + void create_schema(); + + template + object::object_ptr insert(Type *obj); + + template< class Type, typename... Args > + object::object_ptr insert(Args&&... args) { + return insert(new Type(std::forward(args)...)); + } + + template + utils::result, session_error> find(const PrimaryKeyType &pk) { + auto c = pool_.acquire(); + if (!c.valid()) { + return utils::failure(session_error::NoConnectionAvailable); + } + auto info = schema_->info(); + if (!info) { + return utils::failure(session_error::UnknownType); + } + + entity_query_builder eqb(*schema_); + auto data = eqb.build(pk); + if (!data.is_ok()) { + return utils::failure(session_error::FailedToBuildQuery); + } + + auto obj = build_select_query(c, data.release()).template fetch_one(); + + if (!obj) { + return utils::failure(session_error::FailedToFindObject); + } + return utils::ok(object::object_ptr{ obj.release() }); + } + + template + utils::result, session_error> find() { + auto c = pool_.acquire(); + if (!c.valid()) { + return utils::failure(session_error::NoConnectionAvailable); + } + auto info = schema_->info(); + if (!info) { + return utils::failure(session_error::UnknownType); + } + + entity_query_builder eqb(*schema_); + auto data = eqb.build(); + if (!data.is_ok()) { + return utils::failure(session_error::FailedToBuildQuery); + } + + return utils::ok(build_select_query(c, data.release()).template fetch_all()); + } + + template + utils::result select() { + auto c = pool_.acquire(); + if (!c.valid()) { + return utils::failure(session_error::NoConnectionAvailable); + } + auto info = schema_->info(); + if (!info) { + return utils::failure(session_error::UnknownType); + } + + entity_query_builder eqb(*schema_); + auto data = eqb.build(); + if (!data.is_ok()) { + return utils::failure(session_error::FailedToBuildQuery); + } + + return utils::ok(build_select_query(c, data.release()).template fetch_all()); + } + + template + void drop_table(); + void drop_table(const std::string &table_name); + + [[nodiscard]] sql::query_result fetch(const query_context &q) const; +// [[nodiscard]] query_result fetch(const std::string &sql) const; + [[nodiscard]] size_t execute(const std::string &sql) const; + [[nodiscard]] sql::statement prepare(query_context q) const; + + [[nodiscard]] std::vector describe_table(const std::string &table_name) const; + [[nodiscard]] bool table_exists(const std::string &table_name) const; + + [[nodiscard]] const sql::dialect& dialect() const; + +private: + friend class query_select; + + [[nodiscard]] std::unique_ptr fetch(const std::string &sql) const; + + query_select build_select_query(sql::connection_ptr &conn, entity_query_data &&data) const; + +private: + sql::connection_pool &pool_; + const sql::dialect &dialect_; + + std::unique_ptr schema_; + mutable std::unordered_map prototypes_; +}; + +template +void session::attach(const std::string &table_name) +{ + schema_->attach(table_name); +} + +template +object::object_ptr session::insert(Type *obj) +{ + auto c = pool_.acquire(); + auto info = schema_->info(); + if (!info) { + return {}; + } + c->query(*schema_) + .insert() + .into(info->name, column_generator::generate(*schema_, true)) + .values(*obj) + .execute(); + + return object::object_ptr{obj}; +} + +template +void session::drop_table() +{ + auto info = schema_->info(); + if (info) { + return drop_table(info.name); + } + +} +} +#endif //QUERY_SESSION_HPP diff --git a/source/core/object/basic_object_info.cpp b/source/core/object/basic_object_info.cpp index 7158b5b..c285cf4 100644 --- a/source/core/object/basic_object_info.cpp +++ b/source/core/object/basic_object_info.cpp @@ -1,5 +1,7 @@ #include "matador/object/basic_object_info.hpp" +#include "matador/object/schema_node.hpp" + #include namespace matador::object { @@ -8,6 +10,11 @@ basic_object_info::basic_object_info(schema_node &node, const std::type_index ty : node_(node) , type_index_(type_index) {} -std::type_index basic_object_info::type_index() const { return type_index_; } +std::type_index basic_object_info::type_index() const { + return type_index_; +} +std::string basic_object_info::name() const { + return node_.name(); +} } // namespace matador::object diff --git a/source/orm/CMakeLists.txt b/source/orm/CMakeLists.txt index bdebd83..9596015 100644 --- a/source/orm/CMakeLists.txt +++ b/source/orm/CMakeLists.txt @@ -40,6 +40,7 @@ add_library(matador-orm STATIC ../../include/matador/query/query_intermediates.hpp ../../include/matador/query/query_part.hpp ../../include/matador/query/value_extractor.hpp + ../../include/matador/orm/session.hpp ../../include/matador/sql/abstract_sql_logger.hpp ../../include/matador/sql/backend_provider.hpp ../../include/matador/sql/column.hpp @@ -102,6 +103,7 @@ add_library(matador-orm STATIC query/query_part.cpp query/query_update_intermediate.cpp query/value_extractor.cpp + orm/session.cpp sql/backend_provider.cpp sql/column.cpp sql/column_definition.cpp diff --git a/source/orm/orm/session.cpp b/source/orm/orm/session.cpp new file mode 100644 index 0000000..bbadff3 --- /dev/null +++ b/source/orm/orm/session.cpp @@ -0,0 +1,117 @@ +#include "matador/orm/session.hpp" + +#include "matador/sql/backend_provider.hpp" + +#include + +namespace matador::orm { + +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())){} + +void session::create_schema() +{ + auto c = pool_.acquire(); + for (const auto &t : *schema_) { + c->query(*schema_).create().table(t.second.name, t.second.prototype.columns()).execute(); + } +} + +void session::drop_table(const std::string &table_name) +{ + auto c = pool_.acquire(); + if (!c.valid()) { + throw std::logic_error("no database connection available"); + } + + c->query(*schema_).drop().table(table_name).execute(); +} + +sql::query_result session::fetch(const query_context &q) const +{ + auto c = pool_.acquire(); + if (!c.valid()) { + throw std::logic_error("no database connection available"); + } + auto it = prototypes_.find(q.table.name); + if (it == prototypes_.end()) { + it = prototypes_.emplace(q.table.name, c->describe(q.table.name)).first; + } + // adjust columns from given query + for (auto &col : q.prototype) { + if (const auto rit = it->second.find(col.name()); col.type() == utils::basic_type::type_unknown && rit != it->second.end()) { + const_cast(col).type(rit->type()); + } + } + auto res = c->fetch(q.sql); + return sql::query_result{std::move(res), q.prototype}; +} + +//query_result session::fetch(const std::string &sql) const +//{ +// return query_result(std::unique_ptr()); +//} + +size_t session::execute(const std::string &sql) const { + auto c = pool_.acquire(); + if (!c.valid()) { + throw std::logic_error("no database connection available"); + } + return c->execute(sql); +} + +sql::statement session::prepare(query_context q) const +{ + auto c = pool_.acquire(); + if (!c.valid()) { + throw std::logic_error("no database connection available"); + } + return c->prepare(std::move(q)); +} + +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"); + } + return c->describe(table_name); +} + +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"); + } + return c->exists(dialect_.default_schema_name(), table_name); +} + +const class dialect &session::dialect() const +{ + return dialect_; +} + +std::unique_ptr session::fetch(const std::string &sql) const +{ + auto c = pool_.acquire(); + if (!c.valid()) { + throw std::logic_error("no database connection available"); + } + return c->fetch(sql); +} + +query_select session::build_select_query(sql::connection_ptr &conn, entity_query_data &&data) const +{ + return conn->query(*schema_) + .select(data.columns) + .from(data.root_table_name) + .join_left(data.joins) + .where(std::move(data.where_clause)) + .order_by({data.root_table_name, data.pk_column_}) + .asc(); +} + +} \ No newline at end of file