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
- Add is_valid() method to connection & connection_impl
- Read in foreign fields
- Read in entity fields
- Add special handling for update in backends
- Add PostgreSQL backend
- Add MySQL/MariaDB backend

View File

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

View File

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

View File

@ -1,24 +1,27 @@
#ifndef QUERY_SQLITE_QUERY_RESULT_HPP
#define QUERY_SQLITE_QUERY_RESULT_HPP
#ifndef QUERY_SQLITE_RESULT_READER_HPP
#define QUERY_SQLITE_RESULT_READER_HPP
#include "matador/sql/query_result_impl.hpp"
#include "matador/sql/record.hpp"
#include "matador/sql/query_result_reader.hpp"
#include <vector>
namespace matador::backends::sqlite {
class sqlite_query_result : public sql::query_result_impl {
class sqlite_result_reader : public sql::query_result_reader
{
public:
using columns = std::vector<char*>;
using rows = std::vector<columns>;
public:
sqlite_query_result(sql::record prototype, rows result);
~sqlite_query_result() override;
sqlite_result_reader(rows result, size_t column_count);
~sqlite_result_reader() 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, short &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, 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:
rows result_;
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_error.hpp"
#include "sqlite_query_result.hpp"
#include "sqlite_result_reader.hpp"
#include "matador/sql/record.hpp"
@ -37,17 +37,11 @@ bool sqlite_connection::is_open()
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)
{
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) {
// copy and store column data;
if (values[i] == nullptr) {
@ -73,6 +67,17 @@ int sqlite_connection::parse_result(void* param, int column_count, char** values
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)
{
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)
{
fetch_context context;
char *errmsg = nullptr;
const int ret = sqlite3_exec(sqlite_db_, stmt.c_str(), parse_result, &context, &errmsg);
auto context = fetch_internal(stmt);
throw_sqlite_error(ret, sqlite_db_, "sqlite", stmt);
return std::move(std::make_unique<sqlite_query_result>(std::move(context.prototype), std::move(context.rows)));
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)));
}
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)
{
std::string stmt("PRAGMA table_info(" + table + ")");
const auto result = fetch("PRAGMA table_info(" + table + ")");
const auto result = fetch_internal("PRAGMA table_info(" + table + ")");
sqlite_result_reader reader(std::move(result.rows), result.prototype.size());
sql::record prototype;
while (result->fetch()) {
while (reader.fetch()) {
char *end = nullptr;
// Todo: add index to column
auto index = strtoul(result->column(0), &end, 10);
std::string name = result->column(1);
auto index = strtoul(reader.column(0), &end, 10);
std::string name = reader.column(1);
// Todo: extract size
auto type = (string2type(result->column(2)));
auto type = (string2type(reader.column(2)));
end = nullptr;
utils::constraints options{};
if (strtoul(result->column(3), &end, 10) == 0) {
if (strtoul(reader.column(3), &end, 10) == 0) {
options = utils::constraints::NOT_NULL;
}
// 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)
{
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?
return false;
}
int v{};
result->read_value(nullptr, 0, v);
reader.read_value(nullptr, 0, v);
return v == 1;
}

View File

@ -1,11 +1,9 @@
#include "sqlite_query_result.hpp"
#include "sqlite_result_reader.hpp"
#include <algorithm>
#include <cstring>
#include <stdexcept>
#include <sqlite3.h>
namespace matador::backends::sqlite {
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)
: sql::query_result_impl(std::move(prototype))
, result_(std::move(result))
{}
sqlite_result_reader::sqlite_result_reader(sqlite_result_reader::rows result, size_t column_count)
: 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(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]);
}
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]);
}
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]);
}
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]);
}
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]);
}
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]);
}
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]);
}
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]);
}
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]);
}
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]);
}
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]);
}
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]);
}
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]);
}
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];
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]);
}
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]);
}
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 >
void convert(const char *valstr, sql::any_type &value)
{
@ -203,7 +179,7 @@ void convert(const char *valstr, sql::any_type &value)
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) {
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/sql/any_type.hpp"
#include "matador/sql/query_result_reader.hpp"
#include "matador/sql/record.hpp"
#include "matador/sql/types.hpp"
#include <memory>
#include <string>
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
{
public:
virtual ~query_result_impl() = default;
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;
query_result_impl(std::unique_ptr<query_result_reader> &&reader, record prototype);
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)
{
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_revision(const char *id, unsigned long long &rev);
@ -50,16 +67,28 @@ public:
template < class Type >
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, 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);
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 >
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>
void on_has_many(const char *, ContainerType &, const char *, const char *, utils::cascade_type) {}
@ -72,26 +101,32 @@ public:
template<class Type>
bool fetch(Type &obj)
{
if (!fetch()) {
column_index_ = 0;
if (!reader_->fetch()) {
return false;
}
matador::utils::access::process(*this, obj);
return true;
}
[[nodiscard]] virtual const char* column(size_t index) const = 0;
[[nodiscard]] virtual bool fetch() = 0;
const record& prototype() const;
protected:
explicit query_result_impl(record prototype);
[[nodiscard]] const record& prototype() const;
protected:
size_t column_index_ = 0;
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

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/any_type.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/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
../include/matador/utils/field_attributes.hpp

View File

@ -1,31 +1,45 @@
#include "matador/sql/query_result_impl.hpp"
#include "matador/sql/query_result_reader.hpp"
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)
{
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)
{
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)
{
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)
{
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, 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
@ -33,8 +47,4 @@ const record& query_result_impl::prototype() const
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,
sizeof timestamp_buffer - 3,
"%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];
#ifdef _MSC_VER

View File

@ -122,10 +122,10 @@ TEST_CASE("Select statement with foreign key", "[session]") {
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)))");
std::vector<foreign<airplane>> planes {
make_foreign<airplane>(1, "Airbus", "A380"),
make_foreign<airplane>(2, "Boeing", "707"),
make_foreign<airplane>(3, "Boeing", "747")
std::vector<entity<airplane>> planes {
make_entity<airplane>(1, "Airbus", "A380"),
make_entity<airplane>(2, "Boeing", "707"),
make_entity<airplane>(3, "Boeing", "747")
};
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>();
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();
REQUIRE(res.first == 1);
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("airplane").execute();

View File

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

View File

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

View File

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

View File

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