renamed foreign class to entity, introduced interface class query_result_reader

This commit is contained in:
Sascha Kuehl 2023-11-24 17:40:57 +01:00
parent 700cbc0652
commit c2a96f4cbd
18 changed files with 285 additions and 207 deletions

View File

@ -1,7 +1,7 @@
# Todo # Todo
- Add is_valid() method to connection & connection_impl - Add is_valid() method to connection & connection_impl
- Read in foreign fields - Read in entity fields
- Add special handling for update in backends - Add special handling for update in backends
- Add PostgreSQL backend - Add PostgreSQL backend
- Add MySQL/MariaDB backend - Add MySQL/MariaDB backend

View File

@ -2,14 +2,14 @@ set(HEADER
include/sqlite_connection.hpp include/sqlite_connection.hpp
include/sqlite_error.hpp include/sqlite_error.hpp
include/sqlite_dialect.hpp include/sqlite_dialect.hpp
include/sqlite_query_result.hpp include/sqlite_result_reader.hpp
) )
set(SOURCES set(SOURCES
src/sqlite_connection.cpp src/sqlite_connection.cpp
src/sqlite_error.cpp src/sqlite_error.cpp
src/sqlite_dialect.cpp src/sqlite_dialect.cpp
src/sqlite_query_result.cpp src/sqlite_result_reader.cpp
) )
add_library(matador-sqlite SHARED ${SOURCES} ${HEADER}) add_library(matador-sqlite SHARED ${SOURCES} ${HEADER})

View File

@ -14,6 +14,8 @@
#include "matador/sql/connection_impl.hpp" #include "matador/sql/connection_impl.hpp"
#include "sqlite_result_reader.hpp"
#include <sqlite3.h> #include <sqlite3.h>
namespace matador::backends::sqlite { namespace matador::backends::sqlite {
@ -35,9 +37,18 @@ public:
bool exists(const std::string &table_name) override; bool exists(const std::string &table_name) override;
private:
struct fetch_context
{
sql::record prototype;
sqlite_result_reader::rows rows;
};
private: private:
static int parse_result(void* param, int column_count, char** values, char** columns); static int parse_result(void* param, int column_count, char** values, char** columns);
fetch_context fetch_internal(const std::string &stmt);
private: private:
sqlite3 *sqlite_db_{}; sqlite3 *sqlite_db_{};
}; };

View File

@ -1,24 +1,27 @@
#ifndef QUERY_SQLITE_QUERY_RESULT_HPP #ifndef QUERY_SQLITE_RESULT_READER_HPP
#define QUERY_SQLITE_QUERY_RESULT_HPP #define QUERY_SQLITE_RESULT_READER_HPP
#include "matador/sql/query_result_impl.hpp" #include "matador/sql/query_result_reader.hpp"
#include "matador/sql/record.hpp"
#include <vector> #include <vector>
namespace matador::backends::sqlite { namespace matador::backends::sqlite {
class sqlite_query_result : public sql::query_result_impl { class sqlite_result_reader : public sql::query_result_reader
{
public: public:
using columns = std::vector<char*>; using columns = std::vector<char*>;
using rows = std::vector<columns>; using rows = std::vector<columns>;
public: public:
sqlite_query_result(sql::record prototype, rows result); sqlite_result_reader(rows result, size_t column_count);
~sqlite_query_result() override; ~sqlite_result_reader() override;
size_t column_count() const override; size_t column_count() const override;
[[nodiscard]] const char* column(size_t index) const override;
[[nodiscard]] bool fetch() override;
void read_value(const char *id, size_t index, char &value) override; void read_value(const char *id, size_t index, char &value) override;
void read_value(const char *id, size_t index, short &value) override; void read_value(const char *id, size_t index, short &value) override;
void read_value(const char *id, size_t index, int &value) override; void read_value(const char *id, size_t index, int &value) override;
@ -37,20 +40,12 @@ public:
void read_value(const char *id, size_t index, std::string &value, size_t s) override; void read_value(const char *id, size_t index, std::string &value, size_t s) override;
void read_value(const char *id, size_t index, sql::any_type &value, sql::data_type_t type, size_t size) override; void read_value(const char *id, size_t index, sql::any_type &value, sql::data_type_t type, size_t size) override;
[[nodiscard]] const char* column(size_t index) const override;
[[nodiscard]] bool fetch() override;
private:
friend class sqlite_connection;
private:
void push_back(char **row_values, int column_count);
private: private:
rows result_; rows result_;
long long row_index_ = -1; long long row_index_ = -1;
size_t column_count_{};
}; };
} }
#endif //QUERY_SQLITE_QUERY_RESULT_HPP #endif //QUERY_SQLITE_RESULT_READER_HPP

View File

@ -1,6 +1,6 @@
#include "sqlite_connection.hpp" #include "sqlite_connection.hpp"
#include "sqlite_error.hpp" #include "sqlite_error.hpp"
#include "sqlite_query_result.hpp" #include "sqlite_result_reader.hpp"
#include "matador/sql/record.hpp" #include "matador/sql/record.hpp"
@ -37,17 +37,11 @@ bool sqlite_connection::is_open()
return sqlite_db_ != nullptr; return sqlite_db_ != nullptr;
} }
struct fetch_context
{
sql::record prototype;
sqlite_query_result::rows rows;
};
int sqlite_connection::parse_result(void* param, int column_count, char** values, char** columns) int sqlite_connection::parse_result(void* param, int column_count, char** values, char** columns)
{ {
auto *context = static_cast<fetch_context*>(param); auto *context = static_cast<fetch_context*>(param);
sqlite_query_result::columns column; sqlite_result_reader::columns column;
for(int i = 0; i < column_count; ++i) { for(int i = 0; i < column_count; ++i) {
// copy and store column data; // copy and store column data;
if (values[i] == nullptr) { if (values[i] == nullptr) {
@ -73,6 +67,17 @@ int sqlite_connection::parse_result(void* param, int column_count, char** values
return 0; return 0;
} }
sqlite_connection::fetch_context sqlite_connection::fetch_internal(const std::string &stmt)
{
fetch_context context;
char *errmsg = nullptr;
const int ret = sqlite3_exec(sqlite_db_, stmt.c_str(), parse_result, &context, &errmsg);
throw_sqlite_error(ret, sqlite_db_, "sqlite", stmt);
return context;
}
size_t sqlite_connection::execute(const std::string &stmt) size_t sqlite_connection::execute(const std::string &stmt)
{ {
char *errmsg = nullptr; char *errmsg = nullptr;
@ -85,13 +90,9 @@ size_t sqlite_connection::execute(const std::string &stmt)
std::unique_ptr<sql::query_result_impl> sqlite_connection::fetch(const std::string &stmt) std::unique_ptr<sql::query_result_impl> sqlite_connection::fetch(const std::string &stmt)
{ {
fetch_context context; auto context = fetch_internal(stmt);
char *errmsg = nullptr;
const int ret = sqlite3_exec(sqlite_db_, stmt.c_str(), parse_result, &context, &errmsg);
throw_sqlite_error(ret, sqlite_db_, "sqlite", stmt); return std::move(std::make_unique<sql::query_result_impl>(std::make_unique<sqlite_result_reader>(std::move(context.rows), context.prototype.size()), std::move(context.prototype)));
return std::move(std::make_unique<sqlite_query_result>(std::move(context.prototype), std::move(context.rows)));
} }
void sqlite_connection::prepare(const std::string &stmt) void sqlite_connection::prepare(const std::string &stmt)
@ -135,21 +136,21 @@ sql::data_type_t string2type(const char *type)
sql::record sqlite_connection::describe(const std::string& table) sql::record sqlite_connection::describe(const std::string& table)
{ {
std::string stmt("PRAGMA table_info(" + table + ")"); const auto result = fetch_internal("PRAGMA table_info(" + table + ")");
const auto result = fetch("PRAGMA table_info(" + table + ")");
sqlite_result_reader reader(std::move(result.rows), result.prototype.size());
sql::record prototype; sql::record prototype;
while (result->fetch()) { while (reader.fetch()) {
char *end = nullptr; char *end = nullptr;
// Todo: add index to column // Todo: add index to column
auto index = strtoul(result->column(0), &end, 10); auto index = strtoul(reader.column(0), &end, 10);
std::string name = result->column(1); std::string name = reader.column(1);
// Todo: extract size // Todo: extract size
auto type = (string2type(result->column(2))); auto type = (string2type(reader.column(2)));
end = nullptr; end = nullptr;
utils::constraints options{}; utils::constraints options{};
if (strtoul(result->column(3), &end, 10) == 0) { if (strtoul(reader.column(3), &end, 10) == 0) {
options = utils::constraints::NOT_NULL; options = utils::constraints::NOT_NULL;
} }
// f.default_value(res->column(4)); // f.default_value(res->column(4));
@ -161,15 +162,16 @@ sql::record sqlite_connection::describe(const std::string& table)
bool sqlite_connection::exists(const std::string &table_name) bool sqlite_connection::exists(const std::string &table_name)
{ {
const auto result = fetch("SELECT COUNT(*) FROM sqlite_master WHERE type='table' AND tbl_name='" + table_name + "' LIMIT 1"); const auto result = fetch_internal("SELECT COUNT(*) FROM sqlite_master WHERE type='table' AND tbl_name='" + table_name + "' LIMIT 1");
sqlite_result_reader reader(std::move(result.rows), result.prototype.size());
if (!result->fetch()) { if (!reader.fetch()) {
// Todo: throw an exception? // Todo: throw an exception?
return false; return false;
} }
int v{}; int v{};
result->read_value(nullptr, 0, v); reader.read_value(nullptr, 0, v);
return v == 1; return v == 1;
} }

View File

@ -1,11 +1,9 @@
#include "sqlite_query_result.hpp" #include "sqlite_result_reader.hpp"
#include <algorithm> #include <algorithm>
#include <cstring> #include <cstring>
#include <stdexcept> #include <stdexcept>
#include <sqlite3.h>
namespace matador::backends::sqlite { namespace matador::backends::sqlite {
template < class Type > template < class Type >
@ -50,12 +48,11 @@ void read(Type &x, const char *val, typename std::enable_if<std::is_floating_poi
} }
} }
sqlite_query_result::sqlite_query_result(sql::record prototype, sqlite_query_result::rows result) sqlite_result_reader::sqlite_result_reader(sqlite_result_reader::rows result, size_t column_count)
: sql::query_result_impl(std::move(prototype)) : result_(std::move(result))
, result_(std::move(result)) , column_count_(column_count) {}
{}
sqlite_query_result::~sqlite_query_result() sqlite_result_reader::~sqlite_result_reader()
{ {
std::for_each(result_.begin(), result_.end(), [](rows ::value_type& row) { std::for_each(result_.begin(), result_.end(), [](rows ::value_type& row) {
std::for_each(row.begin(), row.end(), [](const char *val) { std::for_each(row.begin(), row.end(), [](const char *val) {
@ -64,77 +61,87 @@ sqlite_query_result::~sqlite_query_result()
}); });
} }
size_t sqlite_query_result::column_count() const size_t sqlite_result_reader::column_count() const
{ {
return prototype_.size(); return column_count_;
} }
void sqlite_query_result::read_value(const char *id, size_t index, char &value) const char* sqlite_result_reader::column(size_t index) const
{
return result_[row_index_][index];
}
bool sqlite_result_reader::fetch()
{
return ++row_index_ < result_.size();
}
void sqlite_result_reader::read_value(const char *id, size_t index, char &value)
{ {
read(value, result_[row_index_][index]); read(value, result_[row_index_][index]);
} }
void sqlite_query_result::read_value(const char *id, size_t index, short &value) void sqlite_result_reader::read_value(const char *id, size_t index, short &value)
{ {
read(value, result_[row_index_][index]); read(value, result_[row_index_][index]);
} }
void sqlite_query_result::read_value(const char *id, size_t index, int &value) void sqlite_result_reader::read_value(const char *id, size_t index, int &value)
{ {
read(value, result_[row_index_][index]); read(value, result_[row_index_][index]);
} }
void sqlite_query_result::read_value(const char *id, size_t index, long &value) void sqlite_result_reader::read_value(const char *id, size_t index, long &value)
{ {
read(value, result_[row_index_][index]); read(value, result_[row_index_][index]);
} }
void sqlite_query_result::read_value(const char *id, size_t index, long long int &value) void sqlite_result_reader::read_value(const char *id, size_t index, long long int &value)
{ {
read(value, result_[row_index_][index]); read(value, result_[row_index_][index]);
} }
void sqlite_query_result::read_value(const char *id, size_t index, unsigned char &value) void sqlite_result_reader::read_value(const char *id, size_t index, unsigned char &value)
{ {
read(value, result_[row_index_][index]); read(value, result_[row_index_][index]);
} }
void sqlite_query_result::read_value(const char *id, size_t index, unsigned short &value) void sqlite_result_reader::read_value(const char *id, size_t index, unsigned short &value)
{ {
read(value, result_[row_index_][index]); read(value, result_[row_index_][index]);
} }
void sqlite_query_result::read_value(const char *id, size_t index, unsigned int &value) void sqlite_result_reader::read_value(const char *id, size_t index, unsigned int &value)
{ {
read(value, result_[row_index_][index]); read(value, result_[row_index_][index]);
} }
void sqlite_query_result::read_value(const char *id, size_t index, unsigned long &value) void sqlite_result_reader::read_value(const char *id, size_t index, unsigned long &value)
{ {
read(value, result_[row_index_][index]); read(value, result_[row_index_][index]);
} }
void sqlite_query_result::read_value(const char *id, size_t index, unsigned long long int &value) void sqlite_result_reader::read_value(const char *id, size_t index, unsigned long long int &value)
{ {
read(value, result_[row_index_][index]); read(value, result_[row_index_][index]);
} }
void sqlite_query_result::read_value(const char *id, size_t index, bool &value) void sqlite_result_reader::read_value(const char *id, size_t index, bool &value)
{ {
read(value, result_[row_index_][index]); read(value, result_[row_index_][index]);
} }
void sqlite_query_result::read_value(const char *id, size_t index, float &value) void sqlite_result_reader::read_value(const char *id, size_t index, float &value)
{ {
read(value, result_[row_index_][index]); read(value, result_[row_index_][index]);
} }
void sqlite_query_result::read_value(const char *id, size_t index, double &value) void sqlite_result_reader::read_value(const char *id, size_t index, double &value)
{ {
read(value, result_[row_index_][index]); read(value, result_[row_index_][index]);
} }
void sqlite_query_result::read_value(const char *id, size_t index, char *value, size_t size) void sqlite_result_reader::read_value(const char *id, size_t index, char *value, size_t size)
{ {
auto val = result_[row_index_][index]; auto val = result_[row_index_][index];
size_t len = strlen(val); size_t len = strlen(val);
@ -154,47 +161,16 @@ void sqlite_query_result::read_value(const char *id, size_t index, char *value,
} }
} }
void sqlite_query_result::read_value(const char *id, size_t index, std::string &value) void sqlite_result_reader::read_value(const char *id, size_t index, std::string &value)
{ {
value.assign(result_[row_index_][index]); value.assign(result_[row_index_][index]);
} }
void sqlite_query_result::read_value(const char *id, size_t index, std::string &value, size_t s) void sqlite_result_reader::read_value(const char *id, size_t index, std::string &value, size_t s)
{ {
value.assign(result_[row_index_][index]); value.assign(result_[row_index_][index]);
} }
void sqlite_query_result::push_back(char **row_values, int column_count)
{
columns data;
for(int i = 0; i < column_count; ++i) {
// copy and store column data;
if (row_values[i] == nullptr) {
auto val = new char[1];
val[0] = '\0';
data.push_back(val);
} else {
size_t size = strlen(row_values[i]);
auto val = new char[size + 1];
std::memcpy(val, row_values[i], size);
val[size] = '\0';
data.push_back(val);
}
}
result_.emplace_back(data);
}
const char* sqlite_query_result::column(size_t index) const
{
return result_[row_index_][index];
}
bool sqlite_query_result::fetch()
{
column_index_ = 0;
return ++row_index_ < result_.size();
}
template < typename Type > template < typename Type >
void convert(const char *valstr, sql::any_type &value) void convert(const char *valstr, sql::any_type &value)
{ {
@ -203,7 +179,7 @@ void convert(const char *valstr, sql::any_type &value)
value = val; value = val;
} }
void sqlite_query_result::read_value(const char *id, size_t index, sql::any_type &value, sql::data_type_t type, size_t size) void sqlite_result_reader::read_value(const char *id, size_t index, sql::any_type &value, sql::data_type_t type, size_t size)
{ {
switch (type) { switch (type) {
case sql::data_type_t::type_char: case sql::data_type_t::type_char:

View File

@ -0,0 +1,47 @@
#ifndef QUERY_ENTITY_HPP
#define QUERY_ENTITY_HPP
#include <memory>
namespace matador::sql {
template < class Type >
class entity
{
public:
using value_type = Type;
using pointer = value_type*;
using reference = value_type&;
entity() = default;
explicit entity(Type *obj)
: obj_(obj) {}
entity(const entity&) = default;
entity& operator=(const entity&) = default;
entity(entity&&) noexcept = default;
entity& operator=(entity&&) noexcept = default;
~entity() = default;
void reset(Type *obj) { obj_.reset(obj); }
pointer operator->() { return obj_.get(); }
const value_type* operator->() const { return obj_.get(); }
reference operator*() { return *obj_; }
const value_type& operator*() const { return *obj_; }
pointer get() { return obj_.get(); }
const value_type* get() const { return obj_.get(); }
private:
std::shared_ptr<value_type> obj_;
};
template<class Type, typename... Args>
[[maybe_unused]] entity<Type> make_entity(Args&&... args)
{
return entity(new Type(std::forward<Args>(args)...));
}
}
#endif //QUERY_ENTITY_HPP

View File

@ -1,42 +0,0 @@
#ifndef QUERY_FOREIGN_HPP
#define QUERY_FOREIGN_HPP
#include <memory>
namespace matador::sql {
template < class Type >
class foreign
{
public:
using value_type = Type;
using pointer = value_type*;
using reference = value_type&;
foreign() = default;
explicit foreign(Type *obj)
: obj_(obj) {}
foreign(const foreign&) = default;
foreign& operator=(const foreign&) = default;
foreign(foreign&&) noexcept = default;
foreign& operator=(foreign&&) noexcept = default;
~foreign() = default;
pointer operator->() { return obj_.get(); }
const value_type* operator->() const { return obj_.get(); }
reference operator*() { return *obj_; }
const value_type& operator*() const { return *obj_; }
private:
std::shared_ptr<value_type> obj_;
};
template<class Type, typename... Args>
[[maybe_unused]] foreign<Type> make_foreign(Args&&... args)
{
return foreign(new Type(std::forward<Args>(args)...));
}
}
#endif //QUERY_FOREIGN_HPP

View File

@ -5,44 +5,61 @@
#include "matador/utils/field_attributes.hpp" #include "matador/utils/field_attributes.hpp"
#include "matador/sql/any_type.hpp" #include "matador/sql/any_type.hpp"
#include "matador/sql/query_result_reader.hpp"
#include "matador/sql/record.hpp" #include "matador/sql/record.hpp"
#include "matador/sql/types.hpp" #include "matador/sql/types.hpp"
#include <memory>
#include <string> #include <string>
namespace matador::sql { namespace matador::sql {
namespace detail {
class pk_reader
{
public:
explicit pk_reader(query_result_reader &reader);
template<class Type>
void read(Type &obj, size_t column_index)
{
column_index_ = column_index;
utils::access::process(*this, obj);
}
template<typename ValueType>
void on_primary_key(const char *id, ValueType &value, typename std::enable_if<std::is_integral<ValueType>::value && !std::is_same<bool, ValueType>::value>::type* = 0);
void on_primary_key(const char *id, std::string &value, size_t size);
void on_revision(const char * /*id*/, unsigned long long &/*rev*/) {}
template < class Type >
void on_attribute(const char * /*id*/, Type &/*x*/, const utils::field_attributes &/*attr*/ = utils::null_attributes) {}
template < class Pointer >
void on_belongs_to(const char *id, Pointer &x, utils::cascade_type) {}
template < class Pointer >
void on_has_one(const char *id, Pointer &x, utils::cascade_type) {}
template<class ContainerType>
void on_has_many(const char *, ContainerType &, const char *, const char *, utils::cascade_type) {}
template<class ContainerType>
void on_has_many(const char *, ContainerType &, utils::cascade_type) {}
private:
size_t column_index_{};
query_result_reader &reader_;
};
}
class query_result_impl class query_result_impl
{ {
public: public:
virtual ~query_result_impl() = default; query_result_impl(std::unique_ptr<query_result_reader> &&reader, record prototype);
virtual size_t column_count() const = 0;
virtual void read_value(const char *id, size_t index, char &value) = 0;
virtual void read_value(const char *id, size_t index, short &value) = 0;
virtual void read_value(const char *id, size_t index, int &value) = 0;
virtual void read_value(const char *id, size_t index, long &value) = 0;
virtual void read_value(const char *id, size_t index, long long &value) = 0;
virtual void read_value(const char *id, size_t index, unsigned char &value) = 0;
virtual void read_value(const char *id, size_t index, unsigned short &value) = 0;
virtual void read_value(const char *id, size_t index, unsigned int &value) = 0;
virtual void read_value(const char *id, size_t index, unsigned long &value) = 0;
virtual void read_value(const char *id, size_t index, unsigned long long &value) = 0;
virtual void read_value(const char *id, size_t index, bool &value) = 0;
virtual void read_value(const char *id, size_t index, float &value) = 0;
virtual void read_value(const char *id, size_t index, double &value) = 0;
// virtual void read_value(const char *id, size_t index, matador::time &value) = 0;
// virtual void read_value(const char *id, size_t index, matador::date &value) = 0;
virtual void read_value(const char *id, size_t index, char *value, size_t s) = 0;
virtual void read_value(const char *id, size_t index, std::string &value) = 0;
virtual void read_value(const char *id, size_t index, std::string &value, size_t s) = 0;
virtual void read_value(const char *id, size_t index, any_type &value, data_type_t type, size_t size) = 0;
template<typename ValueType> template<typename ValueType>
void on_primary_key(const char *id, ValueType &value, typename std::enable_if<std::is_integral<ValueType>::value && !std::is_same<bool, ValueType>::value>::type* = 0) void on_primary_key(const char *id, ValueType &value, typename std::enable_if<std::is_integral<ValueType>::value && !std::is_same<bool, ValueType>::value>::type* = 0)
{ {
read_value(id, column_index_++, value); reader_->read_value(id, column_index_++, value);
} }
void on_primary_key(const char *id, std::string &value, size_t size); void on_primary_key(const char *id, std::string &value, size_t size);
void on_revision(const char *id, unsigned long long &rev); void on_revision(const char *id, unsigned long long &rev);
@ -50,16 +67,28 @@ public:
template < class Type > template < class Type >
void on_attribute(const char *id, Type &x, const utils::field_attributes &/*attr*/ = utils::null_attributes) void on_attribute(const char *id, Type &x, const utils::field_attributes &/*attr*/ = utils::null_attributes)
{ {
read_value(id, column_index_++, x); reader_->read_value(id, column_index_++, x);
} }
void on_attribute(const char *id, char *value, const utils::field_attributes &attr = utils::null_attributes); void on_attribute(const char *id, char *value, const utils::field_attributes &attr = utils::null_attributes);
void on_attribute(const char *id, std::string &value, const utils::field_attributes &attr = utils::null_attributes); void on_attribute(const char *id, std::string &value, const utils::field_attributes &attr = utils::null_attributes);
void on_attribute(const char *id, any_type &value, data_type_t type, const utils::field_attributes &attr = utils::null_attributes); void on_attribute(const char *id, any_type &value, data_type_t type, const utils::field_attributes &attr = utils::null_attributes);
template < class Pointer > template < class Pointer >
void on_belongs_to(const char *id, Pointer &x, utils::cascade_type) {} void on_belongs_to(const char * /*id*/, Pointer &x, utils::cascade_type)
{
if (!x.get()) {
x.reset(new typename Pointer::value_type);
}
pk_reader_.read(*x, column_index_++);
}
template < class Pointer > template < class Pointer >
void on_has_one(const char *id, Pointer &x, utils::cascade_type) {} void on_has_one(const char * /*id*/, Pointer &x, utils::cascade_type)
{
if (!x.get()) {
x.reset(new typename Pointer::value_type);
}
pk_reader_.read(*x, column_index_++);
}
template<class ContainerType> template<class ContainerType>
void on_has_many(const char *, ContainerType &, const char *, const char *, utils::cascade_type) {} void on_has_many(const char *, ContainerType &, const char *, const char *, utils::cascade_type) {}
@ -72,26 +101,32 @@ public:
template<class Type> template<class Type>
bool fetch(Type &obj) bool fetch(Type &obj)
{ {
if (!fetch()) { column_index_ = 0;
if (!reader_->fetch()) {
return false; return false;
} }
matador::utils::access::process(*this, obj); matador::utils::access::process(*this, obj);
return true; return true;
} }
[[nodiscard]] virtual const char* column(size_t index) const = 0; [[nodiscard]] const record& prototype() const;
[[nodiscard]] virtual bool fetch() = 0;
const record& prototype() const;
protected:
explicit query_result_impl(record prototype);
protected: protected:
size_t column_index_ = 0; size_t column_index_ = 0;
record prototype_; record prototype_;
std::unique_ptr<query_result_reader> reader_;
detail::pk_reader pk_reader_;
}; };
namespace detail {
template<typename ValueType>
void detail::pk_reader::on_primary_key(const char *id, ValueType &value, typename std::enable_if<std::is_integral<ValueType>::value && !std::is_same<bool, ValueType>::value>::type *)
{
reader_.read_value(id, column_index_++, value);
}
}
} }
#endif //QUERY_QUERY_RESULT_IMPL_HPP #endif //QUERY_QUERY_RESULT_IMPL_HPP

View File

@ -0,0 +1,40 @@
#ifndef QUERY_QUERY_RESULT_READER_HPP
#define QUERY_QUERY_RESULT_READER_HPP
#include "matador/sql/any_type.hpp"
#include "matador/sql/types.hpp"
namespace matador::sql {
class query_result_reader
{
public:
virtual ~query_result_reader() = default;
[[nodiscard]] virtual size_t column_count() const = 0;
[[nodiscard]] virtual const char* column(size_t index) const = 0;
[[nodiscard]] virtual bool fetch() = 0;
virtual void read_value(const char *id, size_t index, char &value) = 0;
virtual void read_value(const char *id, size_t index, short &value) = 0;
virtual void read_value(const char *id, size_t index, int &value) = 0;
virtual void read_value(const char *id, size_t index, long &value) = 0;
virtual void read_value(const char *id, size_t index, long long &value) = 0;
virtual void read_value(const char *id, size_t index, unsigned char &value) = 0;
virtual void read_value(const char *id, size_t index, unsigned short &value) = 0;
virtual void read_value(const char *id, size_t index, unsigned int &value) = 0;
virtual void read_value(const char *id, size_t index, unsigned long &value) = 0;
virtual void read_value(const char *id, size_t index, unsigned long long &value) = 0;
virtual void read_value(const char *id, size_t index, bool &value) = 0;
virtual void read_value(const char *id, size_t index, float &value) = 0;
virtual void read_value(const char *id, size_t index, double &value) = 0;
// virtual void read_value(const char *id, size_t index, matador::time &value) = 0;
// virtual void read_value(const char *id, size_t index, matador::date &value) = 0;
virtual void read_value(const char *id, size_t index, char *value, size_t s) = 0;
virtual void read_value(const char *id, size_t index, std::string &value) = 0;
virtual void read_value(const char *id, size_t index, std::string &value, size_t s) = 0;
virtual void read_value(const char *id, size_t index, any_type &value, data_type_t type, size_t size) = 0;
};
}
#endif //QUERY_QUERY_RESULT_READER_HPP

View File

@ -44,10 +44,11 @@ set(SQL_HEADER
../include/matador/sql/value_extractor.hpp ../include/matador/sql/value_extractor.hpp
../include/matador/sql/any_type.hpp ../include/matador/sql/any_type.hpp
../include/matador/sql/key_value_generator.hpp ../include/matador/sql/key_value_generator.hpp
../include/matador/sql/foreign.hpp ../include/matador/sql/entity.hpp
../include/matador/sql/fk_value_extractor.hpp ../include/matador/sql/fk_value_extractor.hpp
"../include/matador/sql/table_repository.hpp" "../include/matador/sql/table_repository.hpp"
../include/matador/sql/any_type_to_visitor.hpp) ../include/matador/sql/any_type_to_visitor.hpp
../include/matador/sql/query_result_reader.hpp)
set(UTILS_HEADER set(UTILS_HEADER
../include/matador/utils/field_attributes.hpp ../include/matador/utils/field_attributes.hpp

View File

@ -1,31 +1,45 @@
#include "matador/sql/query_result_impl.hpp" #include "matador/sql/query_result_impl.hpp"
#include "matador/sql/query_result_reader.hpp"
namespace matador::sql { namespace matador::sql {
detail::pk_reader::pk_reader(query_result_reader &reader)
: reader_(reader) {}
void detail::pk_reader::on_primary_key(const char *id, std::string &value, size_t size) {
reader_.read_value(id, column_index_, value, size);
}
query_result_impl::query_result_impl(std::unique_ptr<query_result_reader> &&reader, record prototype)
: prototype_(std::move(prototype))
, reader_(std::move(reader))
, pk_reader_(*reader_)
{}
void query_result_impl::on_primary_key(const char *id, std::string &value, size_t size) void query_result_impl::on_primary_key(const char *id, std::string &value, size_t size)
{ {
read_value(id, column_index_++, value, size); reader_->read_value(id, column_index_++, value, size);
} }
void query_result_impl::on_revision(const char *id, unsigned long long int &rev) void query_result_impl::on_revision(const char *id, unsigned long long int &rev)
{ {
read_value(id, column_index_++, rev); reader_->read_value(id, column_index_++, rev);
} }
void query_result_impl::on_attribute(const char *id, char *value, const utils::field_attributes &attr) void query_result_impl::on_attribute(const char *id, char *value, const utils::field_attributes &attr)
{ {
read_value(id, column_index_++, value, attr.size()); reader_->read_value(id, column_index_++, value, attr.size());
} }
void query_result_impl::on_attribute(const char *id, std::string &value, const utils::field_attributes &attr) void query_result_impl::on_attribute(const char *id, std::string &value, const utils::field_attributes &attr)
{ {
read_value(id, column_index_++, value, attr.size()); reader_->read_value(id, column_index_++, value, attr.size());
} }
void void
query_result_impl::on_attribute(const char *id, any_type &value, data_type_t type, const utils::field_attributes &attr) query_result_impl::on_attribute(const char *id, any_type &value, data_type_t type, const utils::field_attributes &attr)
{ {
read_value(id, column_index_++, value, type, attr.size()); reader_->read_value(id, column_index_++, value, type, attr.size());
} }
const record& query_result_impl::prototype() const const record& query_result_impl::prototype() const
@ -33,8 +47,4 @@ const record& query_result_impl::prototype() const
return prototype_; return prototype_;
} }
query_result_impl::query_result_impl(record prototype)
: prototype_(std::move(prototype))
{}
} }

View File

@ -107,7 +107,7 @@ void logger::log(log_level lvl, const char *message) const
std::snprintf(timestamp_buffer + std::strftime(timestamp_buffer, std::snprintf(timestamp_buffer + std::strftime(timestamp_buffer,
sizeof timestamp_buffer - 3, sizeof timestamp_buffer - 3,
"%F %T.", "%F %T.",
std::localtime(&coarse)), 4, "%03ld", fine.time_since_epoch().count() % 1000); std::localtime(&coarse)), 4, "%03lld", fine.time_since_epoch().count() % 1000);
char buffer[1024]; char buffer[1024];
#ifdef _MSC_VER #ifdef _MSC_VER

View File

@ -122,10 +122,10 @@ TEST_CASE("Select statement with foreign key", "[session]") {
REQUIRE(res.first == 0); REQUIRE(res.first == 0);
REQUIRE(res.second == R"(CREATE TABLE "flight" ("id" BIGINT, "airplane_id" BIGINT, "pilot_name" VARCHAR(255), CONSTRAINT PK_flight PRIMARY KEY (id), CONSTRAINT FK_flight_airplane_id FOREIGN KEY (airplane_id) REFERENCES airplane(id)))"); REQUIRE(res.second == R"(CREATE TABLE "flight" ("id" BIGINT, "airplane_id" BIGINT, "pilot_name" VARCHAR(255), CONSTRAINT PK_flight PRIMARY KEY (id), CONSTRAINT FK_flight_airplane_id FOREIGN KEY (airplane_id) REFERENCES airplane(id)))");
std::vector<foreign<airplane>> planes { std::vector<entity<airplane>> planes {
make_foreign<airplane>(1, "Airbus", "A380"), make_entity<airplane>(1, "Airbus", "A380"),
make_foreign<airplane>(2, "Boeing", "707"), make_entity<airplane>(2, "Boeing", "707"),
make_foreign<airplane>(3, "Boeing", "747") make_entity<airplane>(3, "Boeing", "747")
}; };
for (const auto &plane : planes) { for (const auto &plane : planes) {
@ -136,13 +136,16 @@ TEST_CASE("Select statement with foreign key", "[session]") {
auto count = s.select({count_all()}).from("airplane").fetch_value<int>(); auto count = s.select({count_all()}).from("airplane").fetch_value<int>();
REQUIRE(count == 3); REQUIRE(count == 3);
flight f4711{4, *planes.begin(), "hans"}; flight f4711{4, planes.at(1), "hans"};
res = s.insert().into<flight>("flight").values(f4711).execute(); res = s.insert().into<flight>("flight").values(f4711).execute();
REQUIRE(res.first == 1); REQUIRE(res.first == 1);
auto f = *s.select<flight>().from("flight").fetch_all<flight>().begin(); auto f = *s.select<flight>().from("flight").fetch_all<flight>().begin();
REQUIRE(f.id == 4);
REQUIRE(f.pilot_name == "hans");
REQUIRE(f.airplane.get() != nullptr);
REQUIRE(f.airplane->id == 2);
s.drop().table("flight").execute(); s.drop().table("flight").execute();
s.drop().table("airplane").execute(); s.drop().table("airplane").execute();

View File

@ -14,9 +14,9 @@ TEST_CASE("Extract values object", "[value extractor]") {
p.units_in_stock = 100; p.units_in_stock = 100;
p.unit_price = 49; p.unit_price = 49;
p.quantity_per_unit = "pcs"; p.quantity_per_unit = "pcs";
p.category = make_foreign<matador::test::category>(); p.category = make_entity<matador::test::category>();
p.category->id = 7; p.category->id = 7;
p.supplier = make_foreign<matador::test::supplier>();; p.supplier = make_entity<matador::test::supplier>();;
p.supplier->id = 13; p.supplier->id = 13;
p.product_name = "candle"; p.product_name = "candle";

View File

@ -8,7 +8,7 @@
#include "matador/utils/cascade_type.hpp" #include "matador/utils/cascade_type.hpp"
#include "matador/utils/field_attributes.hpp" #include "matador/utils/field_attributes.hpp"
#include "matador/sql/foreign.hpp" #include "matador/sql/entity.hpp"
#include <string> #include <string>
@ -21,7 +21,7 @@ struct airplane
: id(id) : id(id)
, brand(std::move(b)) , brand(std::move(b))
, model(std::move(m)) {} , model(std::move(m)) {}
unsigned long id; unsigned long id{};
std::string brand; std::string brand;
std::string model; std::string model;

View File

@ -7,15 +7,15 @@
#include "matador/utils/cascade_type.hpp" #include "matador/utils/cascade_type.hpp"
#include "matador/utils/field_attributes.hpp" #include "matador/utils/field_attributes.hpp"
#include "matador/sql/foreign.hpp" #include "matador/sql/entity.hpp"
#include <string> #include <string>
namespace matador::test { namespace matador::test {
struct flight { struct flight {
unsigned long id; unsigned long id{};
sql::foreign<test::airplane> airplane; sql::entity<test::airplane> airplane;
std::string pilot_name; std::string pilot_name;
template<class Operator> template<class Operator>

View File

@ -8,7 +8,7 @@
#include "matador/utils/cascade_type.hpp" #include "matador/utils/cascade_type.hpp"
#include "matador/utils/field_attributes.hpp" #include "matador/utils/field_attributes.hpp"
#include "matador/sql/foreign.hpp" #include "matador/sql/entity.hpp"
#include <string> #include <string>
@ -17,8 +17,8 @@ namespace matador::test {
struct product struct product
{ {
std::string product_name; std::string product_name;
sql::foreign<test::supplier> supplier; sql::entity<test::supplier> supplier;
sql::foreign<test::category> category; sql::entity<test::category> category;
std::string quantity_per_unit; std::string quantity_per_unit;
unsigned int unit_price; unsigned int unit_price;
unsigned int units_in_stock; unsigned int units_in_stock;