implemented lazy loading for object_ptr and belongs_to
This commit is contained in:
@@ -25,7 +25,8 @@ public:
|
||||
* @param info The database connection info data
|
||||
* @param sql_logger The logging handler
|
||||
*/
|
||||
explicit connection(const connection_info& info, const logger_ptr &sql_logger = null_logger);
|
||||
explicit connection(const connection_info& info, logger_ptr sql_logger = null_logger);
|
||||
explicit connection(const connection_info& info, std::shared_ptr<producer_resolver_factory> resolver_factory, logger_ptr sql_logger = null_logger);
|
||||
/**
|
||||
* @brief Creates a database connection from a connection string.
|
||||
*
|
||||
@@ -33,6 +34,7 @@ public:
|
||||
* @param sql_logger The logging handler
|
||||
*/
|
||||
explicit connection(const std::string &dns, const logger_ptr &sql_logger = null_logger);
|
||||
explicit connection(const std::string &dns, std::shared_ptr<producer_resolver_factory> resolver_factory, const logger_ptr &sql_logger = null_logger);
|
||||
/**
|
||||
* Copies a given connection
|
||||
*
|
||||
@@ -138,6 +140,7 @@ public:
|
||||
[[nodiscard]] std::string str( const query_context& ctx ) const override;
|
||||
|
||||
[[nodiscard]] const class dialect &dialect() const override;
|
||||
[[nodiscard]] std::shared_ptr<producer_resolver_factory> resolver_factory() const override;
|
||||
|
||||
private:
|
||||
[[nodiscard]] utils::result<std::unique_ptr<statement_impl>, utils::error> perform_prepare(const query_context &ctx) const;
|
||||
@@ -149,6 +152,7 @@ private:
|
||||
|
||||
std::unique_ptr<connection_impl> connection_;
|
||||
std::shared_ptr<abstract_sql_logger> logger_ = std::make_shared<null_sql_logger>();
|
||||
std::shared_ptr<producer_resolver_factory> resolver_factory_ = std::make_shared<producer_resolver_factory>();
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -46,6 +46,7 @@ private:
|
||||
class connection_pool {
|
||||
public:
|
||||
connection_pool(const std::string &dns, size_t count);
|
||||
connection_pool(const std::string &dns, size_t count, std::function<connection(const connection_info &)> &&connection_creator);
|
||||
|
||||
connection_ptr acquire();
|
||||
connection_ptr try_acquire();
|
||||
@@ -74,6 +75,7 @@ private:
|
||||
connection_map idle_connections_;
|
||||
|
||||
const connection_info info_;
|
||||
std::function<connection(const connection_info &)> connection_creator_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#ifndef EXECUTOR_HPP
|
||||
#define EXECUTOR_HPP
|
||||
|
||||
#include "matador/sql/producer_resolver_factory.hpp"
|
||||
|
||||
#include "matador/utils/error.hpp"
|
||||
#include "matador/utils/result.hpp"
|
||||
|
||||
@@ -20,6 +22,7 @@ public:
|
||||
[[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;
|
||||
[[nodiscard]] virtual std::shared_ptr<producer_resolver_factory> resolver_factory() const = 0;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -28,6 +28,9 @@ public:
|
||||
field(field &&x) noexcept;
|
||||
field& operator=(field &&x) noexcept;
|
||||
|
||||
bool operator==(const field& rhs) const;
|
||||
bool operator!=(const field& rhs) const;
|
||||
|
||||
template<typename Type>
|
||||
field& operator=(Type value) {
|
||||
value_ = std::move(value);
|
||||
|
||||
@@ -7,11 +7,13 @@
|
||||
#include "matador/sql/object_parameter_binder.hpp"
|
||||
|
||||
#include "matador/utils/data_type_traits.hpp"
|
||||
#include "matador/utils/error.hpp"
|
||||
#include "matador/utils/result.hpp"
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace matador::sql {
|
||||
|
||||
class query_result_impl;
|
||||
class sql_error;
|
||||
|
||||
class statement_impl {
|
||||
|
||||
@@ -40,6 +40,8 @@ public:
|
||||
[[nodiscard]] std::unique_ptr<utils::attribute_writer> create_binder() const;
|
||||
|
||||
protected:
|
||||
friend class statement;
|
||||
|
||||
std::unique_ptr<statement_impl> statement_;
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
#ifndef MATADOR_IDENTIFIER_READER_HPP
|
||||
#define MATADOR_IDENTIFIER_READER_HPP
|
||||
|
||||
#include "matador/utils/access.hpp"
|
||||
#include "matador/utils/identifier.hpp"
|
||||
#include "matador/utils/primary_key_attribute.hpp"
|
||||
|
||||
namespace matador::sql {
|
||||
class query_result_reader;
|
||||
}
|
||||
|
||||
namespace matador::sql::internal {
|
||||
class identifier_reader final {
|
||||
public:
|
||||
explicit identifier_reader(query_result_reader &reader);
|
||||
|
||||
template<class Type>
|
||||
utils::identifier read(const Type &obj, const size_t column_index) {
|
||||
identifier_.clear();
|
||||
column_index_ = column_index;
|
||||
access::process(*this, obj);
|
||||
return identifier_;
|
||||
}
|
||||
|
||||
template<typename ValueType>
|
||||
void on_primary_key(const char *id, ValueType &value, const utils::primary_key_attribute& attr = utils::default_pk_attributes) {
|
||||
utils::data_type_traits<ValueType>::read_value(reader_, id, column_index_, value, attr.size());
|
||||
identifier_ = value;
|
||||
}
|
||||
|
||||
static void on_revision(const char * /*id*/, uint64_t &/*rev*/) {}
|
||||
template < class Type >
|
||||
static void on_attribute(const char * /*id*/, Type &/*x*/, const utils::field_attributes &/*attr*/ = utils::null_attributes) {}
|
||||
template < class Pointer >
|
||||
static void on_belongs_to(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/) {}
|
||||
template < class Pointer >
|
||||
static void on_has_one(const char * /*id*/, Pointer &/*x*/, const utils::foreign_attributes &/*attr*/) {}
|
||||
template<class ContainerType>
|
||||
static void on_has_many(const char * /*id*/, ContainerType &, const char *, const utils::foreign_attributes &/*attr*/) {}
|
||||
template<class ContainerType>
|
||||
static void on_has_many_to_many(const char * /*id*/, ContainerType & /*c*/, const char * /*join_column*/, const char * /*inverse_join_column*/, const utils::foreign_attributes &/*attr*/) {}
|
||||
template<class ContainerType>
|
||||
static void on_has_many_to_many(const char * /*id*/, ContainerType & /*c*/, const utils::foreign_attributes &/*attr*/) {}
|
||||
|
||||
private:
|
||||
query_result_reader &reader_;
|
||||
size_t column_index_{};
|
||||
utils::identifier identifier_;
|
||||
};
|
||||
}
|
||||
#endif //MATADOR_IDENTIFIER_READER_HPP
|
||||
@@ -0,0 +1,33 @@
|
||||
#ifndef MATADOR_IDENTIFIER_STATEMENT_BINDER_HPP
|
||||
#define MATADOR_IDENTIFIER_STATEMENT_BINDER_HPP
|
||||
|
||||
#include "matador/utils/identifier.hpp"
|
||||
|
||||
namespace matador::sql {
|
||||
class statement;
|
||||
|
||||
class identifier_statement_binder : public utils::identifier_serializer {
|
||||
public:
|
||||
explicit identifier_statement_binder(statement &stmt, size_t index = 0);
|
||||
|
||||
void bind(const utils::identifier &id);
|
||||
|
||||
void serialize(int8_t &, const utils::field_attributes &) override;
|
||||
void serialize(int16_t &, const utils::field_attributes &) override;
|
||||
void serialize(int32_t &, const utils::field_attributes &) override;
|
||||
void serialize(int64_t &, const utils::field_attributes &) override;
|
||||
void serialize(uint8_t &, const utils::field_attributes &) override;
|
||||
void serialize(uint16_t &, const utils::field_attributes &) override;
|
||||
void serialize(uint32_t &, const utils::field_attributes &) override;
|
||||
void serialize(uint64_t &, const utils::field_attributes &) override;
|
||||
void serialize(const char *, const utils::field_attributes &) override;
|
||||
void serialize(std::string &, const utils::field_attributes &) override;
|
||||
void serialize(utils::null_type_t &, const utils::field_attributes &) override;
|
||||
|
||||
private:
|
||||
statement &stmt_;
|
||||
size_t index_{};
|
||||
};
|
||||
|
||||
}
|
||||
#endif //MATADOR_IDENTIFIER_STATEMENT_BINDER_HPP
|
||||
@@ -10,16 +10,17 @@
|
||||
|
||||
#include "matador/sql/interface/query_result_reader.hpp"
|
||||
#include "matador/sql/internal/query_result_pk_resolver.hpp"
|
||||
#include "matador/sql/internal/identifier_reader.hpp"
|
||||
#include "matador/sql/record.hpp"
|
||||
|
||||
#include "matador/object/attribute.hpp"
|
||||
#include "matador/object/object_proxy.hpp"
|
||||
#include "matador/object/object_resolver_factory.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <stack>
|
||||
#include <string>
|
||||
#include <typeindex>
|
||||
#include <unordered_set>
|
||||
|
||||
namespace matador::utils {
|
||||
class value;
|
||||
@@ -73,9 +74,9 @@ private:
|
||||
class query_result_impl {
|
||||
public:
|
||||
query_result_impl(std::unique_ptr<query_result_reader> &&reader,
|
||||
std::vector<object::attribute> &&prototype, size_t column_index = 0);
|
||||
query_result_impl(std::unique_ptr<query_result_reader> &&reader,
|
||||
const std::vector<object::attribute> &prototype, size_t column_index = 0);
|
||||
std::vector<object::attribute> prototype,
|
||||
const std::shared_ptr<object::object_resolver_factory>& resolver_factory,
|
||||
size_t column_index = 0);
|
||||
|
||||
template<typename ValueType>
|
||||
void on_primary_key(const char *id, ValueType &value, const utils::primary_key_attribute& attr = utils::default_pk_attributes) {
|
||||
@@ -122,17 +123,19 @@ public:
|
||||
}
|
||||
|
||||
template<class ContainerType>
|
||||
void on_has_many(const char * /*id*/, ContainerType &cont, const char * /*join_column*/,
|
||||
const utils::foreign_attributes &attr) {
|
||||
void on_has_many(const char * /*id*/, ContainerType &cont, const char * /*join_column*/, const utils::foreign_attributes &attr) {
|
||||
using value_type = typename ContainerType::value_type::value_type;
|
||||
auto resolver = resolver_factory_->resolver<value_type>();
|
||||
|
||||
if (attr.fetch() == utils::fetch_type::Lazy) {
|
||||
// pk_reader_.read(*id, column_index_++);
|
||||
} else {
|
||||
const auto ti = std::type_index(typeid(typename ContainerType::value_type::value_type));
|
||||
auto obj = std::make_unique<typename ContainerType::value_type::value_type>();
|
||||
const auto ti = std::type_index(typeid(value_type));
|
||||
auto obj = std::make_shared<typename ContainerType::value_type::value_type>();
|
||||
type_stack_.push(ti);
|
||||
access::process(*this, *obj);
|
||||
type_stack_.pop();
|
||||
auto ptr = typename ContainerType::value_type(obj.release());
|
||||
auto ptr = typename ContainerType::value_type(std::make_shared<object::object_proxy<value_type>>(resolver, obj));
|
||||
const auto pk = ptr.primary_key();
|
||||
if (ptr.primary_key().is_valid()) {
|
||||
cont.push_back(ptr);
|
||||
@@ -194,16 +197,18 @@ private:
|
||||
|
||||
template<class Pointer>
|
||||
void on_foreign_key(Pointer &x, const utils::foreign_attributes &attr) {
|
||||
if (x.empty()) {
|
||||
x.reset(new typename Pointer::value_type);
|
||||
}
|
||||
const auto resolver = resolver_factory_->resolver<typename Pointer::value_type>();
|
||||
if (attr.fetch() == utils::fetch_type::Lazy) {
|
||||
pk_reader_.read(*x, column_index_++);
|
||||
typename Pointer::value_type obj;
|
||||
auto pk = id_reader_.read(obj, column_index_++);
|
||||
x = Pointer(std::make_shared<object::object_proxy<typename Pointer::value_type>>(resolver, pk));
|
||||
} else {
|
||||
auto obj = std::make_shared<typename Pointer::value_type>();
|
||||
const auto ti = std::type_index(typeid(*x));
|
||||
type_stack_.push(ti);
|
||||
access::process(*this, *x);
|
||||
access::process(*this, *obj);
|
||||
type_stack_.pop();
|
||||
x = Pointer(std::make_shared<object::object_proxy<typename Pointer::value_type>>(resolver, obj));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -211,6 +216,8 @@ protected:
|
||||
size_t column_index_ = 0;
|
||||
std::vector<object::attribute> prototype_;
|
||||
std::unique_ptr<query_result_reader> reader_;
|
||||
std::shared_ptr<object::object_resolver_factory> resolver_factory_;
|
||||
internal::identifier_reader id_reader_;
|
||||
detail::pk_reader pk_reader_;
|
||||
std::stack<std::type_index> type_stack_;
|
||||
utils::identifier current_pk_{};
|
||||
|
||||
@@ -50,9 +50,9 @@ public:
|
||||
template<class ContainerType>
|
||||
static void on_has_many(const char * /*id*/, ContainerType &, const char *, const utils::foreign_attributes &/*attr*/) {}
|
||||
template<class ContainerType>
|
||||
static void on_has_many_to_many(const char *id, ContainerType &c, const char *join_column, const char *inverse_join_column, const utils::foreign_attributes &/*attr*/) {}
|
||||
static void on_has_many_to_many(const char * /*id*/, ContainerType & /*c*/, const char * /*join_column*/, const char * /*inverse_join_column*/, const utils::foreign_attributes &/*attr*/) {}
|
||||
template<class ContainerType>
|
||||
static void on_has_many_to_many(const char *id, ContainerType &c, const utils::foreign_attributes &/*attr*/) {}
|
||||
static void on_has_many_to_many(const char * /*id*/, ContainerType & /*c*/, const utils::foreign_attributes &/*attr*/) {}
|
||||
|
||||
private:
|
||||
template<class Type>
|
||||
@@ -60,8 +60,8 @@ private:
|
||||
if (fetch == utils::fetch_type::Lazy) {
|
||||
++column_index_;
|
||||
} else {
|
||||
const Type obj;
|
||||
type_stack_.push(typeid(Type));
|
||||
const Type obj{};
|
||||
type_stack_.emplace(typeid(Type));
|
||||
access::process(*this, obj);
|
||||
type_stack_.pop();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
#ifndef MATADOR_RESOLVER_PRODUCER_HPP
|
||||
#define MATADOR_RESOLVER_PRODUCER_HPP
|
||||
|
||||
#include "matador/object/object_resolver.hpp"
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace matador::sql {
|
||||
class executor;
|
||||
class resolver_producer {
|
||||
public:
|
||||
virtual ~resolver_producer() = default;
|
||||
virtual std::shared_ptr<object::abstract_object_resolver> produce(executor &exec) = 0;
|
||||
|
||||
[[nodiscard]] const std::type_index& type() const;
|
||||
|
||||
protected:
|
||||
explicit resolver_producer(const std::type_index &type);
|
||||
|
||||
private:
|
||||
std::type_index type_;
|
||||
};
|
||||
}
|
||||
#endif //MATADOR_RESOLVER_PRODUCER_HPP
|
||||
@@ -0,0 +1,35 @@
|
||||
#ifndef MATADOR_STATEMENT_OBJECT_RESOLVER_HPP
|
||||
#define MATADOR_STATEMENT_OBJECT_RESOLVER_HPP
|
||||
|
||||
#include "matador/object/object_resolver.hpp"
|
||||
|
||||
#include "matador/sql/statement.hpp"
|
||||
#include "matador/sql/internal/identifier_statement_binder.hpp"
|
||||
|
||||
namespace matador::sql {
|
||||
template<typename Type>
|
||||
class statement_object_resolver : public object::object_resolver<Type> {
|
||||
public:
|
||||
explicit statement_object_resolver(statement stmt)
|
||||
: statement_(std::move(stmt)) {}
|
||||
|
||||
std::shared_ptr<Type> resolve(const utils::identifier &id) override;
|
||||
protected:
|
||||
statement statement_;
|
||||
std::type_index index{typeid(Type)};
|
||||
};
|
||||
|
||||
template<typename Type>
|
||||
std::shared_ptr<Type> statement_object_resolver<Type>::resolve(const utils::identifier &id) {
|
||||
identifier_statement_binder binder(statement_);
|
||||
binder.bind(id);
|
||||
|
||||
auto result = statement_.template fetch_one<Type>();
|
||||
if (!result) {
|
||||
return nullptr;
|
||||
}
|
||||
return std::make_shared<Type>(*result);
|
||||
}
|
||||
|
||||
}
|
||||
#endif //MATADOR_STATEMENT_OBJECT_RESOLVER_HPP
|
||||
@@ -0,0 +1,21 @@
|
||||
#ifndef MATADOR_RESOLVER_FACTORY_HPP
|
||||
#define MATADOR_RESOLVER_FACTORY_HPP
|
||||
|
||||
#include "matador/object/object_resolver_factory.hpp"
|
||||
|
||||
#include "matador/sql/internal/resolver_producer.hpp"
|
||||
|
||||
namespace matador::sql {
|
||||
class executor;
|
||||
|
||||
class producer_resolver_factory : public object::object_resolver_factory {
|
||||
public:
|
||||
|
||||
std::shared_ptr<object::abstract_object_resolver> acquire_resolver(const std::type_index &type) override;
|
||||
void register_resolver(std::shared_ptr<object::abstract_object_resolver> &&resolver) override;
|
||||
|
||||
private:
|
||||
std::unordered_map<std::type_index, std::shared_ptr<object::abstract_object_resolver>> resolvers_;
|
||||
};
|
||||
}
|
||||
#endif //MATADOR_RESOLVER_FACTORY_HPP
|
||||
@@ -2,31 +2,29 @@
|
||||
#define QUERY_QUERY_DATA_HPP
|
||||
|
||||
#include "matador/object/attribute.hpp"
|
||||
#include "matador/object/object_resolver_factory.hpp"
|
||||
|
||||
#include "matador/utils/types.hpp"
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
namespace matador::sql {
|
||||
|
||||
enum class sql_command {
|
||||
SQL_UNKNOWN,
|
||||
SQL_CREATE,
|
||||
SQL_CREATE_TABLE,
|
||||
SQL_CREATE_SCHEMA,
|
||||
SQL_CREATE_DATABASE,
|
||||
SQL_UPDATE,
|
||||
SQL_INSERT,
|
||||
SQL_DELETE,
|
||||
SQL_SELECT,
|
||||
SQL_DROP,
|
||||
SQL_DROP_TABLE,
|
||||
SQL_DROP_SCHEMA,
|
||||
SQL_DROP_DATABASE,
|
||||
SQL_ALTER,
|
||||
SQL_ALTER_TABLE,
|
||||
SQL_ALTER_SCHEMA
|
||||
};
|
||||
SQL_UNKNOWN,
|
||||
SQL_CREATE,
|
||||
SQL_CREATE_TABLE,
|
||||
SQL_CREATE_SCHEMA,
|
||||
SQL_CREATE_DATABASE,
|
||||
SQL_UPDATE,
|
||||
SQL_INSERT,
|
||||
SQL_DELETE,
|
||||
SQL_SELECT,
|
||||
SQL_DROP,
|
||||
SQL_DROP_TABLE,
|
||||
SQL_DROP_SCHEMA,
|
||||
SQL_DROP_DATABASE,
|
||||
SQL_ALTER,
|
||||
SQL_ALTER_TABLE,
|
||||
SQL_ALTER_SCHEMA
|
||||
};
|
||||
|
||||
struct sql_command_info {
|
||||
std::string sql;
|
||||
@@ -40,14 +38,10 @@ struct query_context {
|
||||
std::string schema_name{};
|
||||
std::string table_name{};
|
||||
std::vector<object::attribute> prototype{};
|
||||
// std::vector<std::string> result_vars{};
|
||||
std::vector<std::string> bind_vars{};
|
||||
std::vector<utils::database_type> bind_types{};
|
||||
|
||||
// std::unordered_map<std::string, std::string> column_aliases{};
|
||||
// std::unordered_map<std::string, std::string> table_aliases{};
|
||||
std::shared_ptr<object::object_resolver_factory> resolver_factory{};
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif //QUERY_QUERY_DATA_HPP
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
#ifndef MATADOR_QUERY_RECORD_RESULT_HPP
|
||||
#define MATADOR_QUERY_RECORD_RESULT_HPP
|
||||
|
||||
#include "matador/sql/query_result.hpp"
|
||||
|
||||
namespace matador::sql {
|
||||
|
||||
template <>
|
||||
class query_result<record>;
|
||||
|
||||
template <>
|
||||
class query_result_iterator<record> {
|
||||
public:
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
using value_type = record;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using self = query_result_iterator; /**< Shortcut for this class. */
|
||||
using pointer = value_type*; /**< Shortcut for the pointer type. */
|
||||
using reference = value_type&; /**< Shortcut for the reference type */
|
||||
|
||||
public:
|
||||
query_result_iterator() = default;
|
||||
explicit query_result_iterator(query_result<record> *res)
|
||||
: result_(res)
|
||||
{}
|
||||
query_result_iterator(query_result<record> *res, record rec)
|
||||
: record_(std::move(rec))
|
||||
, result_(res)
|
||||
{}
|
||||
query_result_iterator(query_result_iterator&& x) noexcept
|
||||
: record_(std::move(x.record_))
|
||||
, result_(x.result_)
|
||||
{}
|
||||
query_result_iterator& operator=(query_result_iterator&& x) noexcept {
|
||||
result_ = x.result_;
|
||||
record_ = std::move(x.record_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
~query_result_iterator() = default;
|
||||
|
||||
bool operator==(const query_result_iterator& rhs) const {
|
||||
return record_ == rhs.record_;
|
||||
}
|
||||
|
||||
bool operator!=(const query_result_iterator& rhs) const {
|
||||
return !(*this == rhs);
|
||||
}
|
||||
|
||||
self& operator++();
|
||||
self operator++(int);
|
||||
|
||||
pointer operator->() { return &record_; }
|
||||
reference operator*() { return record_; }
|
||||
record release() { return std::move(record_); }
|
||||
|
||||
private:
|
||||
record record_;
|
||||
query_result<record> *result_{nullptr};
|
||||
};
|
||||
|
||||
template<>
|
||||
class query_result<record> final {
|
||||
public:
|
||||
using iterator = query_result_iterator<record>;
|
||||
|
||||
query_result(std::unique_ptr<query_result_impl> &&impl, const std::vector<object::attribute> &prototype)
|
||||
: impl_(std::move(impl))
|
||||
, prototype_(prototype) {}
|
||||
|
||||
iterator begin() { return std::move(++iterator(this)); }
|
||||
iterator end() { return {}; }
|
||||
|
||||
private:
|
||||
friend class query_result_iterator<record>;
|
||||
|
||||
[[nodiscard]] record create() const;
|
||||
void bind(const record& obj) const;
|
||||
bool fetch(record& obj) const;
|
||||
|
||||
protected:
|
||||
std::unique_ptr<query_result_impl> impl_;
|
||||
std::vector<object::attribute> prototype_;
|
||||
};
|
||||
|
||||
inline record query_result<record>::create() const {
|
||||
record rec;
|
||||
int index{0};
|
||||
for (const auto &col: prototype_) {
|
||||
rec.append({
|
||||
col.name(),
|
||||
col.type(),
|
||||
col.attributes().options(),
|
||||
col.attributes().size(),
|
||||
index++
|
||||
});
|
||||
}
|
||||
return rec;
|
||||
|
||||
}
|
||||
|
||||
inline void query_result<record>::bind(const record &obj) const {
|
||||
impl_->bind(obj);
|
||||
}
|
||||
|
||||
inline bool query_result<record>::fetch(record &obj) const {
|
||||
return impl_->fetch(obj);
|
||||
}
|
||||
|
||||
inline query_result_iterator<record>::self & query_result_iterator<record>::operator++() {
|
||||
record_ = result_->create();
|
||||
result_->bind(record_);
|
||||
if (!result_->fetch(record_)) {
|
||||
record_.clear();
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline query_result_iterator<record>::self query_result_iterator<record>::operator++(int) {
|
||||
self tmp(result_, record_);
|
||||
|
||||
record_ = result_->create();
|
||||
result_->bind(record_);
|
||||
if (!result_->fetch(record_)) {
|
||||
record_.clear();
|
||||
}
|
||||
|
||||
return tmp;
|
||||
}
|
||||
}
|
||||
#endif //MATADOR_QUERY_RECORD_RESULT_HPP
|
||||
@@ -2,22 +2,24 @@
|
||||
#define QUERY_QUERY_RESULT_HPP
|
||||
|
||||
#include "matador/object/attribute.hpp"
|
||||
#include "matador/object/object_ptr.hpp"
|
||||
|
||||
#include "matador/sql/internal/query_result_impl.hpp"
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
namespace matador::sql {
|
||||
#include "matador/object/object.hpp"
|
||||
|
||||
namespace matador::sql {
|
||||
class record;
|
||||
class query_result_impl;
|
||||
|
||||
template < typename Type >
|
||||
class query_result;
|
||||
|
||||
template < typename Type >
|
||||
class query_result_iterator
|
||||
{
|
||||
class query_result_iterator {
|
||||
public:
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
using value_type = Type;
|
||||
@@ -31,7 +33,7 @@ public:
|
||||
explicit query_result_iterator(query_result<Type> *res)
|
||||
: result_(res)
|
||||
{}
|
||||
query_result_iterator(query_result<Type> *res, std::unique_ptr<Type> obj)
|
||||
query_result_iterator(query_result<Type> *res, object::object_ptr<Type> obj)
|
||||
: obj_(std::move(obj))
|
||||
, result_(res)
|
||||
{}
|
||||
@@ -48,19 +50,20 @@ public:
|
||||
|
||||
~query_result_iterator() = default;
|
||||
|
||||
bool operator==(const query_result_iterator& rhs) {
|
||||
bool operator==(const query_result_iterator& rhs) const {
|
||||
return obj_ == rhs.obj_;
|
||||
}
|
||||
|
||||
bool operator!=(const query_result_iterator& rhs) {
|
||||
return obj_ != rhs.obj_;
|
||||
bool operator!=(const query_result_iterator& rhs) const {
|
||||
return !operator==(rhs);
|
||||
}
|
||||
|
||||
self& operator++() {
|
||||
obj_.reset(result_->create());
|
||||
result_->bind(*obj_);
|
||||
if (!result_->fetch(*obj_)) {
|
||||
obj_.reset();
|
||||
auto obj = result_->create();
|
||||
result_->bind(*obj);
|
||||
obj_.reset();
|
||||
if (result_->fetch(*obj)) {
|
||||
obj_ = object::object_ptr<Type>(std::make_shared<object::object_proxy<Type>>(result_->resolver_, std::move(obj)));
|
||||
}
|
||||
|
||||
return *this;
|
||||
@@ -69,10 +72,11 @@ public:
|
||||
self operator++(int) {
|
||||
const self tmp(result_, obj_);
|
||||
|
||||
obj_.reset(result_->create());
|
||||
result_->bind(*obj_);
|
||||
if (!result_->fetch(*obj_)) {
|
||||
obj_.reset();
|
||||
auto obj = result_->create();
|
||||
result_->bind(*obj);
|
||||
obj_.reset();
|
||||
if (result_->fetch(*obj)) {
|
||||
obj_ = object::object_ptr<Type>(std::make_shared<object::object_proxy<Type>>(result_->resolver_, std::move(obj)));
|
||||
}
|
||||
|
||||
return tmp;
|
||||
@@ -82,50 +86,37 @@ public:
|
||||
return obj_.get();
|
||||
}
|
||||
|
||||
reference operator*() {
|
||||
return *obj_;
|
||||
object::object_ptr<Type> operator*() {
|
||||
return obj_;
|
||||
}
|
||||
|
||||
pointer get() {
|
||||
return obj_.get();
|
||||
}
|
||||
|
||||
pointer release() {
|
||||
return obj_.release();
|
||||
object::object_ptr<Type> optr() {
|
||||
return obj_;
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<Type> obj_;
|
||||
object::object_ptr<Type> obj_;
|
||||
query_result<Type> *result_{nullptr};
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
|
||||
template < typename Type >
|
||||
Type* create_prototype(const std::vector<object::attribute> &/*prototype*/) {
|
||||
return new Type{};
|
||||
std::shared_ptr<Type> create_prototype(const std::vector<object::attribute> &/*prototype*/) {
|
||||
return std::make_shared<Type>();
|
||||
}
|
||||
|
||||
template <>
|
||||
record* create_prototype<record>(const std::vector<object::attribute> &prototype);
|
||||
|
||||
record create_prototype(const std::vector<object::attribute> &prototype);
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
class query_result final {
|
||||
public:
|
||||
using iterator = query_result_iterator<Type>;
|
||||
using creator_func = std::function<Type*()>;
|
||||
using creator_func = std::function<std::shared_ptr<Type>()>;
|
||||
|
||||
public:
|
||||
// explicit query_result(std::unique_ptr<query_result_impl> &&impl)
|
||||
// : impl_(std::move(impl))
|
||||
// , creator_([this] {
|
||||
// return detail::create_prototype<Type>(impl_->prototype());
|
||||
// }) {}
|
||||
|
||||
query_result(std::unique_ptr<query_result_impl> &&impl, creator_func&& creator)
|
||||
query_result(std::unique_ptr<query_result_impl> &&impl, const std::shared_ptr<object::object_resolver<Type>> &resolver, creator_func&& creator)
|
||||
: impl_(std::move(impl))
|
||||
, resolver_(resolver)
|
||||
, creator_(std::move(creator)) {}
|
||||
|
||||
iterator begin() { return std::move(++iterator(this)); }
|
||||
@@ -134,17 +125,18 @@ public:
|
||||
private:
|
||||
friend class query_result_iterator<Type>;
|
||||
|
||||
Type* create();
|
||||
std::shared_ptr<Type> create();
|
||||
void bind(const Type& obj);
|
||||
bool fetch(Type& obj);
|
||||
|
||||
protected:
|
||||
std::unique_ptr<query_result_impl> impl_;
|
||||
std::shared_ptr<object::object_resolver<Type>> resolver_;
|
||||
creator_func creator_;
|
||||
};
|
||||
|
||||
template<typename Type>
|
||||
Type *query_result<Type>::create() {
|
||||
std::shared_ptr<Type> query_result<Type>::create() {
|
||||
return creator_();
|
||||
}
|
||||
|
||||
@@ -157,6 +149,6 @@ template<typename Type>
|
||||
bool query_result<Type>::fetch(Type &obj) {
|
||||
return impl_->fetch(obj);
|
||||
}
|
||||
|
||||
} // namespace matador::sql
|
||||
}
|
||||
// namespace matador::sql
|
||||
#endif //QUERY_QUERY_RESULT_HPP
|
||||
|
||||
@@ -28,6 +28,9 @@ public:
|
||||
record& operator=(record&&) noexcept = default;
|
||||
~record() = default;
|
||||
|
||||
bool operator==(const record& rhs) const;
|
||||
bool operator!=(const record& rhs) const;
|
||||
|
||||
template<class Operator>
|
||||
void process(Operator &op) {
|
||||
for(auto &f : fields_) {
|
||||
|
||||
@@ -2,20 +2,20 @@
|
||||
#define QUERY_STATEMENT_HPP
|
||||
|
||||
#include "matador/sql/abstract_sql_logger.hpp"
|
||||
#include "matador/sql/error_code.hpp"
|
||||
#include "matador/sql/query_result.hpp"
|
||||
|
||||
#include "matador/sql/interface/statement_proxy.hpp"
|
||||
|
||||
#include "matador/object/basic_repository.hpp"
|
||||
|
||||
#include "matador/utils/error.hpp"
|
||||
#include "matador/utils/result.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
|
||||
|
||||
namespace matador::sql {
|
||||
namespace detail {
|
||||
template<class Type>
|
||||
class identifier_binder;
|
||||
}
|
||||
|
||||
class statement_impl;
|
||||
class statement_proxy;
|
||||
@@ -104,7 +104,10 @@ public:
|
||||
* @return The query result set
|
||||
*/
|
||||
template<class Type>
|
||||
utils::result<std::unique_ptr<Type>, utils::error> fetch_one();
|
||||
utils::result<object::object_ptr<Type>, utils::error> fetch_one();
|
||||
|
||||
template<class Type>
|
||||
utils::result<std::shared_ptr<Type>, utils::error> fetch_one_raw();
|
||||
/**
|
||||
* Fetches the first result of a prepared statement.
|
||||
* The type is a record representing an unknown variable type.
|
||||
@@ -140,10 +143,6 @@ public:
|
||||
|
||||
[[nodiscard]] utils::result<std::unique_ptr<query_result_impl>, utils::error> fetch_internal() const;
|
||||
|
||||
private:
|
||||
template<class Type>
|
||||
friend class detail::identifier_binder;
|
||||
|
||||
private:
|
||||
std::shared_ptr<statement_proxy> statement_proxy_;
|
||||
std::unique_ptr<utils::attribute_writer> bindings_;
|
||||
@@ -165,31 +164,51 @@ statement &statement::bind(const Type &obj) {
|
||||
template<class Type>
|
||||
utils::result<query_result<Type>, utils::error> statement::fetch() {
|
||||
std::cout << statement_proxy_->sql() << std::endl;
|
||||
return statement_proxy_->fetch(*bindings_).and_then([](std::unique_ptr<query_result_impl> &&value) {
|
||||
return statement_proxy_->fetch(*bindings_).and_then([this](std::unique_ptr<query_result_impl> &&value) {
|
||||
auto resolver = statement_proxy_->statement_->query_.resolver_factory->resolver<Type>();
|
||||
const auto prototype = value->prototype();
|
||||
return utils::ok(query_result<Type>(std::forward<decltype(value)>(value), [prototype] {
|
||||
return utils::ok(query_result<Type>(std::forward<decltype(value)>(value), resolver, [prototype] {
|
||||
return detail::create_prototype<Type>(prototype);
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
template<class Type>
|
||||
utils::result<std::unique_ptr<Type>, utils::error> statement::fetch_one() {
|
||||
utils::result<object::object_ptr<Type>, utils::error> statement::fetch_one() {
|
||||
std::cout << statement_proxy_->sql() << std::endl;
|
||||
auto result = statement_proxy_->fetch(*bindings_);
|
||||
if (!result.is_ok()) {
|
||||
return utils::failure(result.err());
|
||||
}
|
||||
auto resolver = statement_proxy_->statement_->query_.resolver_factory->resolver<Type>();
|
||||
const auto prototype = result.value()->prototype();
|
||||
auto records = query_result<Type>(result.release(), [prototype] {
|
||||
auto records = query_result<Type>(result.release(), resolver, [prototype] {
|
||||
return detail::create_prototype<Type>(prototype);
|
||||
});
|
||||
auto first = records.begin();
|
||||
if (first == records.end()) {
|
||||
return utils::ok(std::unique_ptr<Type>{nullptr});
|
||||
return utils::failure(utils::error{
|
||||
error_code::FETCH_FAILED,
|
||||
"Failed to find entity."
|
||||
});
|
||||
}
|
||||
|
||||
return utils::ok(std::unique_ptr<Type>{first.release()});
|
||||
return utils::ok(first.optr());
|
||||
}
|
||||
|
||||
template<class Type>
|
||||
utils::result<std::shared_ptr<Type>, utils::error> statement::fetch_one_raw() {
|
||||
auto result = statement_proxy_->fetch(*bindings_);
|
||||
if (!result.is_ok()) {
|
||||
return utils::failure(result.err());
|
||||
}
|
||||
|
||||
auto obj = std::make_shared<Type>();
|
||||
(*result)->bind(*obj);
|
||||
if (!(*result)->fetch(*obj)) {
|
||||
return utils::ok(std::shared_ptr<Type>{});
|
||||
}
|
||||
return utils::ok(obj);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@ private:
|
||||
std::mutex mutex_;
|
||||
|
||||
connection_pool &pool_;
|
||||
const sql::dialect &dialect_;
|
||||
const dialect &dialect_;
|
||||
|
||||
utils::message_bus &bus_;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user