Compare commits

..

No commits in common. "2fdbfc651e592c85bb7b72509c4cffed43065322" and "a32330ef5bcd33bd39ccfde0fb6913ebf7b7ee4b" have entirely different histories.

22 changed files with 106 additions and 137 deletions

View File

@ -7,7 +7,7 @@
namespace matador::backends::postgres {
class postgres_parameter_binder final : public sql::parameter_binder {
class postgres_parameter_binder final : public sql::interface::parameter_binder {
public:
struct bind_data {
explicit bind_data(size_t size);

View File

@ -13,8 +13,8 @@ class postgres_statement final : public sql::statement_impl
public:
postgres_statement(PGconn *db, std::string name, const sql::query_context &query);
utils::result<size_t, utils::error> execute(const sql::parameter_binder& bindings) override;
utils::result<std::unique_ptr<sql::query_result_impl>, utils::error> fetch(const sql::parameter_binder& bindings) override;
utils::result<size_t, utils::error> execute(const sql::interface::parameter_binder& bindings) override;
utils::result<std::unique_ptr<sql::query_result_impl>, utils::error> fetch(const sql::interface::parameter_binder& bindings) override;
void reset() override;
protected:

View File

@ -11,7 +11,7 @@ postgres_statement::postgres_statement(PGconn *db, std::string name, const sql::
, name_(std::move(name))
{}
utils::result<size_t, utils::error> postgres_statement::execute(const sql::parameter_binder& bindings) {
utils::result<size_t, utils::error> postgres_statement::execute(const sql::interface::parameter_binder& bindings) {
const auto* postgres_bindings = dynamic_cast<const postgres_parameter_binder*>(&bindings);
if (!postgres_bindings) {
return utils::failure(utils::error(sql::error_code::EXECUTE_FAILED, "Failed to cast bindings to postgres bindings"));
@ -33,10 +33,10 @@ utils::result<size_t, utils::error> postgres_statement::execute(const sql::param
return utils::ok(static_cast<size_t>(0));
}
return utils::ok(static_cast<size_t>(std::stoul(tuples)));
return utils::ok((std::stoul(tuples)));
}
utils::result<std::unique_ptr<sql::query_result_impl>, utils::error> postgres_statement::fetch(const sql::parameter_binder& bindings) {
utils::result<std::unique_ptr<sql::query_result_impl>, utils::error> postgres_statement::fetch(const sql::interface::parameter_binder& bindings) {
const auto* postgres_bindings = dynamic_cast<const postgres_parameter_binder*>(&bindings);
if (!postgres_bindings) {
return utils::failure(utils::error(sql::error_code::EXECUTE_FAILED, "Failed to cast bindings to postgres bindings"));

View File

@ -11,8 +11,7 @@ enum class error_code : uint8_t {
NoConnectionAvailable,
UnknownType,
FailedToBuildQuery,
FailedToFindObject,
Failed
FailedToFindObject
};
class orm_category_impl final : public std::error_category

View File

@ -9,9 +9,7 @@
#include "matador/sql/column_generator.hpp"
#include "matador/sql/connection.hpp"
#include "matador/sql/connection_pool.hpp"
#include "matador/sql/executor.hpp"
#include "matador/sql/statement.hpp"
#include "matador/sql/statement_cache.hpp"
#include "matador/object/object_ptr.hpp"
#include "matador/object/object_definition.hpp"
@ -23,15 +21,9 @@ namespace matador::orm {
utils::error make_error(error_code ec, const std::string &msg);
struct session_context {
utils::message_bus &bus;
sql::connection_pool &pool;
size_t cache_size{500};
};
class session final : public sql::executor {
class session final {
public:
explicit session(session_context &&ctx);
explicit session(sql::connection_pool &pool);
template<typename Type>
[[nodiscard]] utils::result<void, utils::error> attach(const std::string &table_name) const;
@ -50,10 +42,10 @@ public:
template<typename Type, typename PrimaryKeyType>
utils::result<object::object_ptr<Type>, utils::error> find(const PrimaryKeyType &pk) {
// auto c = pool_.acquire();
// if (!c.valid()) {
// return utils::failure(make_error(error_code::NoConnectionAvailable, "Failed to acquire connection."));
// }
auto c = pool_.acquire();
if (!c.valid()) {
return utils::failure(make_error(error_code::NoConnectionAvailable, "Failed to acquire connection."));
}
auto info = schema_->info<Type>();
if (!info) {
return utils::failure(make_error(error_code::UnknownType, "Failed to determine requested type."));
@ -65,7 +57,7 @@ public:
return utils::failure(make_error(error_code::FailedToBuildQuery, "Failed to build query for type " + info->get().name() + "."));
}
auto obj = build_select_query(data.release()).template fetch_one<Type>(*this);
auto obj = build_select_query(data.release()).template fetch_one<Type>(*c);
if (!obj) {
return utils::failure(obj.err());
@ -78,10 +70,10 @@ public:
template<typename Type>
utils::result<sql::query_result<Type>, utils::error> find() {
// const auto c = pool_.acquire();
// if (!c.valid()) {
// return utils::failure(make_error(error_code::NoConnectionAvailable, "Failed to acquire connection."));
// }
const auto c = pool_.acquire();
if (!c.valid()) {
return utils::failure(make_error(error_code::NoConnectionAvailable, "Failed to acquire connection."));
}
auto info = schema_->info<Type>();
if (!info) {
return utils::failure(make_error(error_code::UnknownType, "Failed to determine requested type."));
@ -93,46 +85,43 @@ public:
return utils::failure(make_error(error_code::FailedToBuildQuery, "Failed to build query for type " + info->get().name() + "."));
}
return build_select_query(data.release()).template fetch_all<Type>(*this);
return build_select_query(data.release()).template fetch_all<Type>(*c);
}
template<typename Type>
utils::result<query::query_from_intermediate, utils::error> select() {
auto c = pool_.acquire();
if (!c.valid()) {
return utils::failure(make_error(error_code::NoConnectionAvailable, "Failed to acquire connection."));
}
auto info = schema_->info<Type>();
if (!info) {
return utils::failure(make_error(error_code::UnknownType, "Failed to determine requested type."));
}
session_query_builder eqb(*schema_);
auto data = eqb.build<Type>();
if (!data.is_ok()) {
return utils::failure(make_error(error_code::FailedToBuildQuery, "Failed to build query for type " + info->get().name() + "."));
}
return utils::ok(build_select_query(data.release()).template fetch_all<Type>(*c));
}
// template<typename Type>
// utils::result<query::query_from_intermediate, utils::error> select() {
// auto c = pool_.acquire();
// if (!c.valid()) {
// return utils::failure(make_error(error_code::NoConnectionAvailable, "Failed to acquire connection."));
// }
// auto info = schema_->info<Type>();
// if (!info) {
// return utils::failure(make_error(error_code::UnknownType, "Failed to determine requested type."));
// }
//
// session_query_builder eqb(*schema_);
// auto data = eqb.build<Type>();
// if (!data.is_ok()) {
// return utils::failure(make_error(error_code::FailedToBuildQuery, "Failed to build query for type " + info->get().name() + "."));
// }
//
// return utils::ok(build_select_query(data.release()).template fetch_all<Type>(*c));
// }
//
template<typename Type>
utils::result<void, utils::error> drop_table();
utils::result<void, utils::error> drop_table(const std::string &table_name) const;
[[nodiscard]] utils::result<sql::query_result<sql::record>, utils::error> fetch_all(const sql::query_context &q) const;
[[nodiscard]] utils::result<size_t, utils::error> execute(const std::string &sql) const;
[[nodiscard]] utils::result<sql::query_result<sql::record>, utils::error> fetch(const sql::query_context &q) const;
[[nodiscard]] size_t execute(const std::string &sql) const;
[[nodiscard]] sql::statement prepare(const sql::query_context& q) const;
[[nodiscard]] std::vector<object::attribute_definition> describe_table(const std::string &table_name) const;
[[nodiscard]] bool table_exists(const std::string &table_name) const;
void dump_schema(std::ostream &os) const;
[[nodiscard]] const sql::dialect& dialect() const;
[[nodiscard]] utils::result<std::unique_ptr<sql::query_result_impl>, utils::error> fetch(const sql::query_context &ctx) const override;
[[nodiscard]] utils::result<size_t, utils::error> execute(const sql::query_context &ctx) const override;
[[nodiscard]] utils::result<sql::statement, utils::error> prepare(const sql::query_context &ctx) override;
[[nodiscard]] std::string str( const sql::query_context& ctx ) const override;
[[nodiscard]] const sql::dialect& dialect() const override;
void dump_schema(std::ostream &os) const;
private:
friend class query_select;
@ -140,7 +129,7 @@ private:
static query::fetchable_query build_select_query(entity_query_data &&data);
private:
mutable sql::statement_cache cache_;
sql::connection_pool &pool_;
const sql::dialect &dialect_;
std::unique_ptr<object::schema> schema_;
@ -158,8 +147,9 @@ utils::result<void, utils::error> session::attach( const std::string& table_name
}
template<typename Type>
utils::result<object::object_ptr<Type>, utils::error> session::insert(Type *obj) {
// auto c = pool_.acquire();
utils::result<object::object_ptr<Type>, utils::error> session::insert(Type *obj)
{
auto c = pool_.acquire();
auto info = schema_->info<Type>();
if (!info) {
return utils::failure(info.err());
@ -168,7 +158,7 @@ utils::result<object::object_ptr<Type>, utils::error> session::insert(Type *obj)
auto res = query::query::insert()
.into(info->get().name(), sql::column_generator::generate<Type>(*schema_, true))
.values(*obj)
.execute(*this);
.execute(*c);
if (!res) {
return utils::failure(res.err());
}

View File

@ -8,6 +8,7 @@
namespace matador::sql {
class executor;
class prepared_executor;
class statement;
struct query_context;
}
@ -19,7 +20,7 @@ public:
using query_intermediate::query_intermediate;
[[nodiscard]] utils::result<size_t, utils::error> execute(const sql::executor &exec) const;
[[nodiscard]] utils::result<sql::statement, utils::error> prepare(sql::executor &exec) const;
[[nodiscard]] utils::result<sql::statement, utils::error> prepare(sql::prepared_executor &exec) const;
[[nodiscard]] sql::query_context compile(const sql::executor &exec) const;
[[nodiscard]] std::string str(const sql::executor &exec) const;
};

View File

@ -13,6 +13,7 @@
namespace matador::sql {
class executor;
class prepared_executor;
class statement;
}
@ -68,7 +69,7 @@ public:
return utils::ok(std::optional<Type>{std::nullopt});
}
[[nodiscard]] utils::result<sql::statement, utils::error> prepare(sql::executor &exec) const;
[[nodiscard]] utils::result<sql::statement, utils::error> prepare(sql::prepared_executor &exec) const;
[[nodiscard]] std::string str(const sql::executor &exec) const;

View File

@ -16,7 +16,7 @@ class connection_impl;
/**
* @brief The connection class represents a connection to a database.
*/
class connection final : public executor {
class connection final : public executor, public prepared_executor {
public:
using logger_ptr = std::shared_ptr<abstract_sql_logger>;
/**

View File

@ -12,13 +12,22 @@ struct query_context;
class query_result_impl;
class statement;
class executor {
class dialect_executor_mixin {
public:
virtual ~executor() = default;
virtual ~dialect_executor_mixin() = default;
[[nodiscard]] virtual const class dialect& dialect() const = 0;
};
class prepared_executor : public dialect_executor_mixin {
public:
[[nodiscard]] virtual utils::result<statement, utils::error> prepare(const query_context &ctx) = 0;
};
class executor : public dialect_executor_mixin {
public:
[[nodiscard]] virtual utils::result<size_t, utils::error> execute(const query_context &ctx) const = 0;
[[nodiscard]] virtual utils::result<std::unique_ptr<query_result_impl>, utils::error> fetch(const query_context &ctx) const = 0;
[[nodiscard]] virtual utils::result<statement, utils::error> prepare(const query_context &ctx) = 0;
[[nodiscard]] virtual std::string str(const query_context &ctx) const = 0;
};

View File

@ -123,8 +123,6 @@ public:
[[nodiscard]] std::string sql() const;
[[nodiscard]] utils::result<std::unique_ptr<query_result_impl>, utils::error> fetch_internal() const;
private:
template<class Type>
friend class detail::identifier_binder;

View File

@ -68,7 +68,6 @@ public:
return bus_.subscribe<EventType>(handler);
}
connection_pool& pool() const;
private:
size_t max_size_{};

View File

@ -18,8 +18,6 @@ std::string orm_category_impl::message(const int ev) const {
return "Failed to build query";
case error_code::FailedToFindObject:
return "Failed to find object";
case error_code::Failed:
return "Failed";
default:
return "Unknown error";
}

View File

@ -12,9 +12,9 @@ utils::error make_error(const error_code ec, const std::string &msg) {
return utils::error(ec, msg);
}
session::session(session_context&& ctx)
: cache_(ctx.bus, ctx.pool, ctx.cache_size)
, dialect_(sql::backend_provider::instance().connection_dialect(ctx.pool.info().type))
session::session(sql::connection_pool &pool)
: pool_(pool)
, dialect_(sql::backend_provider::instance().connection_dialect(pool_.info().type))
, schema_(std::make_unique<object::schema>(dialect_.default_schema_name())) {
}
@ -49,7 +49,7 @@ utils::result<void, utils::error> session::create_schema() const {
}
std::vector<std::string> fk_sql_commands;
auto c = cache_.pool().acquire();
auto c = pool_.acquire();
for (const auto &node: *schema_) {
auto ctx = query::query::create()
.table(node->name(), node->info().definition().columns())
@ -75,9 +75,14 @@ utils::result<void, utils::error> session::create_schema() const {
}
utils::result<void, utils::error> session::drop_table(const std::string &table_name) const {
auto c = pool_.acquire();
if (!c.valid()) {
throw std::logic_error("no database connection available");
}
auto result = query::query::drop()
.table(table_name)
.execute(*this);
.execute(*c);
if (result.is_error()) {
return utils::failure(result.err());
}
@ -85,10 +90,10 @@ utils::result<void, utils::error> session::drop_table(const std::string &table_n
return utils::ok<void>();
}
utils::result<sql::query_result<sql::record>, utils::error> session::fetch_all(const sql::query_context &q) const {
auto c = cache_.pool().acquire();
utils::result<sql::query_result<sql::record>, utils::error> session::fetch(const sql::query_context &q) const {
auto c = pool_.acquire();
if (!c.valid()) {
return utils::failure(make_error(error_code::NoConnectionAvailable, "Failed to acquire connection."));
throw std::logic_error("no database connection available");
}
auto it = prototypes_.find(q.table.name);
if (it == prototypes_.end()) {
@ -104,19 +109,28 @@ utils::result<sql::query_result<sql::record>, utils::error> session::fetch_all(c
const_cast<object::attribute_definition &>(col).type(rit->type());
}
}
auto res = fetch(q);
if (!res) {
return utils::failure(res.err());
}
auto res = c->fetch(q);
return utils::ok(sql::query_result<sql::record>{std::move(*res)});
}
utils::result<size_t, utils::error> session::execute(const std::string &sql) const {
return execute(sql::query_context{sql});
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(const sql::query_context &q) const {
auto c = pool_.acquire();
if (!c.valid()) {
throw std::logic_error("no database connection available");
}
return c->prepare(q).release();
}
std::vector<object::attribute_definition> session::describe_table(const std::string &table_name) const {
const auto c = cache_.pool().acquire();
auto c = pool_.acquire();
if (!c.valid()) {
throw std::logic_error("no database connection available");
}
@ -124,7 +138,7 @@ std::vector<object::attribute_definition> session::describe_table(const std::str
}
bool session::table_exists(const std::string &table_name) const {
const auto c = cache_.pool().acquire();
auto c = pool_.acquire();
if (!c.valid()) {
throw std::logic_error("no database connection available");
}
@ -139,34 +153,6 @@ void session::dump_schema(std::ostream &os) const {
schema_->dump(os);
}
utils::result<std::unique_ptr<sql::query_result_impl>, utils::error> session::fetch(const sql::query_context& ctx) const {
if (const auto result = cache_.acquire(ctx); !result) {
return utils::failure(result.err());
} else if (auto fetch_result = result->fetch_internal(); !fetch_result) {
return utils::failure(fetch_result.err());
} else {
return fetch_result;
}
}
utils::result<size_t, utils::error> session::execute(const sql::query_context& ctx) const {
if (const auto result = cache_.acquire(ctx); !result) {
return utils::failure(result.err());
} else if (auto exec_result = result->execute(); !exec_result) {
return utils::failure(exec_result.err());
} else {
return exec_result;
}
}
utils::result<sql::statement, utils::error> session::prepare(const sql::query_context& ctx) {
return cache_.acquire(ctx);
}
std::string session::str(const sql::query_context& ctx) const {
return ctx.sql;
}
query::fetchable_query session::build_select_query(entity_query_data &&data) {
return query::query::select(data.columns)
.from(*data.root_table)

View File

@ -12,7 +12,7 @@ utils::result<size_t, utils::error> executable_query::execute(const sql::executo
return exec.execute(compiler.compile(*context_, exec.dialect(), std::nullopt));
}
utils::result<sql::statement, utils::error> executable_query::prepare(sql::executor &exec) const {
utils::result<sql::statement, utils::error> executable_query::prepare(sql::prepared_executor &exec) const {
query_compiler compiler;
context_->mode = query_mode::Prepared;
return exec.prepare(compiler.compile(*context_, exec.dialect(), std::nullopt));

View File

@ -43,7 +43,7 @@ utils::result<std::unique_ptr<sql::query_result_impl>, utils::error> fetchable_q
return exec.fetch(compiler.compile(*context_, exec.dialect(), std::nullopt));
}
utils::result<sql::statement, utils::error> fetchable_query::prepare(sql::executor &exec) const {
utils::result<sql::statement, utils::error> fetchable_query::prepare(sql::prepared_executor &exec) const {
query_compiler compiler;
context_->mode = query_mode::Prepared;
return exec.prepare(compiler.compile(*context_, exec.dialect(), std::nullopt));

View File

@ -98,14 +98,4 @@ void statement::reset() const
std::string statement::sql() const {
return statement_proxy_->sql();
}
utils::result<std::unique_ptr<query_result_impl>, utils::error> statement::fetch_internal() const {
auto result = statement_proxy_->fetch(*bindings_);
if (!result.is_ok()) {
return utils::failure(result.err());
}
// logger_.info(statement_->query_.sql);
return result;
}
}

View File

@ -205,7 +205,4 @@ bool statement_cache::empty() const {
return cache_map_.empty();
}
connection_pool& statement_cache::pool() const {
return pool_;
}
}

View File

@ -5,7 +5,7 @@
namespace matador::test {
SessionFixture::SessionFixture()
: pool(connection::dns, 4), ses({bus, pool}) {}
: pool(connection::dns, 4), ses(pool) {}
SessionFixture::~SessionFixture() {
while (!tables_to_drop.empty()) {

View File

@ -3,8 +3,6 @@
#include "matador/orm/session.hpp"
#include "matador/utils/message_bus.hpp"
#include "connection.hpp"
#include <stack>
@ -20,7 +18,6 @@ protected:
sql::connection_pool pool;
std::stack <std::string> tables_to_drop;
orm::session ses;
utils::message_bus bus;
private:
void drop_table_if_exists(const std::string &table_name) const;

View File

@ -234,4 +234,7 @@ TEST_CASE_METHOD(SessionFixture, "Use session to find all objects with many-to-m
recipes.push_back(std::make_unique<recipe>(7, "Apple Crumble"));
recipes.push_back(std::make_unique<recipe>(8, "Beans Chili"));
recipes.push_back(std::make_unique<recipe>(9, "Fruit Salad"));
}

View File

@ -15,13 +15,13 @@ class StatementCacheFixture
{
public:
StatementCacheFixture()
: pool(test::connection::dns, 4)//, ses(pool)
: pool(test::connection::dns, 4), ses(pool)
{}
~StatementCacheFixture() = default;
protected:
sql::connection_pool pool;
// orm::session ses;
orm::session ses;
};
TEST_CASE_METHOD(StatementCacheFixture, "Acquire prepared statement", "[statement cache]") {

View File

@ -14,7 +14,8 @@ utils::result<size_t, utils::error> test_statement::execute(const sql::parameter
using namespace std::chrono_literals;
std::mt19937 rng(query_.sql.size());
std::uniform_int_distribution dist(10, 50);
std::this_thread::sleep_for(std::chrono::milliseconds(dist(rng)));
std::this_thread::sleep_for(std::chrono::milliseconds(50));
// std::this_thread::sleep_for(std::chrono::milliseconds(dist(rng)));
return utils::ok(static_cast<size_t>(8));
}