added any type visitor and converter

This commit is contained in:
2023-11-21 20:07:07 +01:00
parent 171e8d36ce
commit 145c4dc0a3
28 changed files with 730 additions and 163 deletions
+131
View File
@@ -0,0 +1,131 @@
#ifndef QUERY_ANY_TYPE_TO_VISITOR_HPP
#define QUERY_ANY_TYPE_TO_VISITOR_HPP
#include <array>
#include <charconv>
#include <cstring>
#include <stdexcept>
#include <string>
#include <type_traits>
namespace matador::sql {
template < typename DestType, typename SourceType >
void convert(DestType &dest, SourceType source, typename std::enable_if<std::is_same<DestType, SourceType>::value>::type* = nullptr)
{
dest = source;
}
template < typename DestType, typename SourceType >
void convert(DestType &dest, SourceType source, typename std::enable_if<std::is_integral<DestType>::value && std::is_arithmetic<SourceType>::value && !std::is_same<DestType, SourceType>::value>::type* = nullptr)
{
dest = static_cast<DestType>(source);
}
template < typename DestType, typename SourceType >
void convert(DestType &dest, SourceType source, typename std::enable_if<std::is_floating_point<DestType>::value && std::is_arithmetic<SourceType>::value && !std::is_same<DestType, SourceType>::value>::type* = nullptr)
{
dest = static_cast<DestType>(source);
}
void convert(std::string &dest, bool source);
template < typename SourceType >
void convert(std::string &dest, SourceType source, typename std::enable_if<std::is_integral<SourceType>::value && !std::is_same<bool, SourceType>::value>::type* = nullptr)
{
std::array<char, 128> buffer{};
auto [ptr, ec] = std::to_chars(buffer.data(), buffer.data() + buffer.size(), source, 10);
if (ec == std::errc{}) {
dest.assign(buffer.data(), ptr);
} else {
throw std::logic_error("couldn't convert value to std::string");
}
}
template < typename SourceType >
void convert(std::string &dest, SourceType source, typename std::enable_if<std::is_floating_point<SourceType>::value>::type* = nullptr)
{
std::array<char, 128> buffer{};
auto [ptr, ec] = std::to_chars(buffer.data(), buffer.data() + buffer.size(), source);
if (ec == std::errc{}) {
dest.assign(buffer.data(), ptr);
} else {
throw std::logic_error("couldn't convert value to std::string");
}
}
void convert(std::string &dest, const char* source);
unsigned long long to_unsigned_long_long(const char *source);
template < typename DestType >
void convert(DestType &dest, const std::string &source, typename std::enable_if<std::is_integral<DestType>::value && std::is_unsigned<DestType>::value>::type* = nullptr)
{
dest = to_unsigned_long_long(source.c_str());
}
template < typename DestType >
void convert(DestType &dest, const char *source, typename std::enable_if<std::is_integral<DestType>::value && std::is_unsigned<DestType>::value>::type* = nullptr)
{
dest = to_unsigned_long_long(source);
}
long long to_long_long(const char *source);
template < typename DestType >
void convert(DestType &dest, const std::string &source, typename std::enable_if<std::is_integral<DestType>::value && std::is_signed<DestType>::value>::type* = nullptr)
{
dest = to_long_long(source.c_str());
}
template < typename DestType >
void convert(DestType &dest, const char *source, typename std::enable_if<std::is_integral<DestType>::value && std::is_signed<DestType>::value>::type* = nullptr)
{
dest = to_long_long(source);
}
long double to_double(const char *source);
template < typename DestType >
void convert(DestType &dest, const std::string &source, typename std::enable_if<std::is_floating_point<DestType>::value>::type* = nullptr)
{
dest = to_double(source.c_str());
}
template < typename DestType >
void convert(DestType &dest, const char *source, typename std::enable_if<std::is_floating_point<DestType>::value>::type* = nullptr)
{
dest = to_double(source);
}
template < typename DestType >
void convert(DestType &dest, bool source, typename std::enable_if<std::is_floating_point<DestType>::value>::type* = nullptr)
{
dest = static_cast<DestType>(source);
}
template < typename Type >
struct any_type_to_visitor
{
void operator()(char &x) { convert(result, x); }
void operator()(short &x) { convert(result, x); }
void operator()(int &x) { convert(result, x); }
void operator()(long &x) { convert(result, x); }
void operator()(long long &x) { convert(result, x); }
void operator()(unsigned char &x) { convert(result, x); }
void operator()(unsigned short &x) { convert(result, x); }
void operator()(unsigned int &x) { convert(result, x); }
void operator()(unsigned long &x) { convert(result, x); }
void operator()(unsigned long long &x) { convert(result, x); }
void operator()(bool &x) { convert(result, x); }
void operator()(float &x) { convert(result, x); }
void operator()(double &x) { convert(result, x); }
void operator()(const char *x) { convert(result, x); }
void operator()(std::string &x) { convert(result, x); }
Type result{};
};
}
#endif //QUERY_ANY_TYPE_TO_VISITOR_HPP
+52 -6
View File
@@ -2,6 +2,7 @@
#define QUERY_COLUMN_HPP
#include "matador/sql/any_type.hpp"
#include "matador/sql/any_type_to_visitor.hpp"
#include "matador/sql/types.hpp"
#include "matador/utils/field_attributes.hpp"
@@ -11,28 +12,42 @@
namespace matador::sql {
namespace detail {
}
class column {
public:
explicit column(std::string name)
: name_(std::move(name))
, attributes_(utils::null_attributes) {}
column(const column&) = default;
column& operator=(const column&) = default;
column(column&&) noexcept = default;
column& operator=(column&&) noexcept = default;
template<typename Type>
explicit column(std::string name, utils::field_attributes attr = utils::null_attributes)
: column(std::move(name), data_type_traits<Type>::builtin_type(attr.size()), attr)
{}
template<typename Type>
column(std::string name, const Type &, utils::field_attributes attr = utils::null_attributes)
: column(std::move(name), data_type_traits<Type>::builtin_type(attr.size()), attr)
{}
column(std::string name, data_type_t type, utils::field_attributes attr = utils::null_attributes);
template<typename Type>
column(std::string name, std::string ref_table, std::string ref_column, utils::field_attributes attr = utils::null_attributes)
: column(std::move(name), data_type_traits<Type>::builtin_type(attr.size()), ref_table, ref_column, attr)
{}
column(std::string name, data_type_t type, std::string ref_table, std::string ref_column, utils::field_attributes attr = utils::null_attributes);
column(std::string name, data_type_t type, size_t index, std::string ref_table, std::string ref_column, utils::field_attributes attr = utils::null_attributes);
[[nodiscard]] const std::string& name() const;
[[nodiscard]] size_t index() const;
[[nodiscard]] const utils::field_attributes& attributes() const;
[[nodiscard]] data_type_t type() const;
[[nodiscard]] const std::string& ref_table() const;
@@ -43,10 +58,40 @@ public:
return std::holds_alternative<Type>(value_);
}
template< typename Type >
std::optional<Type> value() const {
[[nodiscard]] std::string str() const;
template<typename Type>
void set(const Type &value, const utils::field_attributes &attr = utils::null_attributes)
{
type_ = data_type_traits<Type>::builtin_type(attr.size());
attributes_ = attr;
value_ = value;
}
void set(const std::string &value, const utils::field_attributes &attr)
{
type_ = data_type_traits<std::string>::builtin_type(attr.size());
attributes_ = attr;
value_ = value;
}
void set(const char *value, const utils::field_attributes &attr)
{
type_ = data_type_traits<std::string>::builtin_type(attr.size());
attributes_ = attr;
value_ = value;
}
template<class Type>
Type as() const
{
const Type* ptr= std::get_if<Type>(&value_);
return ptr ? std::make_optional<Type>(*ptr) : std::nullopt;
if (ptr) {
return *ptr;
}
any_type_to_visitor<Type> visitor;
std::visit(visitor, const_cast<any_type&>(value_));
return visitor.result;
}
private:
@@ -64,8 +109,9 @@ private:
static const data_type_index data_type_index_;
std::string name_;
size_t index_{};
utils::field_attributes attributes_;
data_type_t type_{};
data_type_t type_{data_type_t::type_unknown};
any_type value_;
std::string ref_table_;
std::string ref_column_;
@@ -107,7 +153,7 @@ column make_fk_column(const std::string &name, size_t size, const std::string &r
template < typename Type >
[[maybe_unused]] column make_fk_column(const std::string &name, const std::string &ref_table, const std::string &ref_column)
{
return {name, data_type_traits<Type>::builtin_type(0), ref_table, ref_column, { 0, utils::constraints::FOREIGN_KEY }};
return {name, data_type_traits<Type>::builtin_type(0), 0, ref_table, ref_column, { 0, utils::constraints::FOREIGN_KEY }};
}
template <>
+1 -1
View File
@@ -23,7 +23,7 @@ public:
column generate(const char *id, Type &x, const std::string &ref_table, const std::string &ref_column)
{
utils::access::process(*this, x);
return column{id, type_, ref_table, ref_column, { utils::constraints::FOREIGN_KEY }};
return column{id, type_, 0, ref_table, ref_column, { utils::constraints::FOREIGN_KEY }};
}
template<typename ValueType>
+1
View File
@@ -30,6 +30,7 @@ public:
[[nodiscard]] const connection_info& info() const;
[[nodiscard]] record describe(const std::string &table_name) const;
bool exists(const std::string &table_name) const;
template<class Type>
query_result<Type> fetch(const std::string &sql)
+1
View File
@@ -25,6 +25,7 @@ public:
virtual void prepare(const std::string &stmt) = 0;
virtual record describe(const std::string &table) = 0;
virtual bool exists(const std::string &table_name) = 0;
protected:
explicit connection_impl(const connection_info &info);
+2 -1
View File
@@ -57,6 +57,7 @@ enum class join_type_t {
struct query
{
std::string sql;
std::string table_name;
record prototype;
std::vector<any_type> host_vars;
};
@@ -128,7 +129,7 @@ public:
query_builder& offset(size_t count);
query_builder& limit(size_t count);
std::string compile();
query compile();
private:
void transition_to(state_t next);
+30 -24
View File
@@ -25,12 +25,8 @@ public:
query_intermediate(session &db, query_builder &query);
protected:
session& db();
query_builder& query();
private:
session &db_;
query_builder &query_;
session &session_;
query_builder &builder_;
};
class query_execute_finish : public query_intermediate
@@ -127,10 +123,20 @@ public:
query_order_by_intermediate order_by(const std::string &name);
};
class query_select_intermediate : public query_intermediate
class query_start_intermediate
{
public:
using query_intermediate::query_intermediate;
explicit query_start_intermediate(session &s);
protected:
session &session_;
query_builder builder_;
};
class query_select_intermediate : public query_start_intermediate
{
public:
query_select_intermediate(session &s, std::vector<std::string> column_names);
query_from_intermediate from(const std::string &table, const std::string &as = "");
};
@@ -144,50 +150,50 @@ public:
template<class Type>
query_execute_finish values(const Type &obj)
{
return {db(), query().values(value_extractor::extract(obj))};
return {session_, builder_.values(value_extractor::extract(obj))};
}
};
class query_create_intermediate : query_intermediate
class query_create_intermediate : query_start_intermediate
{
public:
query_create_intermediate(session &db, query_builder &query, table_repository &repo);
query_create_intermediate(session &s, table_repository &repo);
query_execute_finish table(const std::string &table, std::initializer_list<column> columns);
template<class Type>
query_execute_finish table(const std::string &table_name)
{
const auto &info = repository_.attach<Type>(table_name/*, record{column_generator::generate<Type>(repository_)}*/);
return {db(), query().table(table_name, info.prototype.columns())};
const auto &info = repository_.attach<Type>(table_name);
return {session_, builder_.table(table_name, info.prototype.columns())};
}
private:
table_repository &repository_;
};
class query_drop_intermediate : query_intermediate
class query_drop_intermediate : query_start_intermediate
{
public:
using query_intermediate::query_intermediate;
explicit query_drop_intermediate(session &s);
query_execute_finish table(const std::string &table);
};
class query_insert_intermediate : public query_intermediate
class query_insert_intermediate : public query_start_intermediate
{
public:
using query_intermediate::query_intermediate;
explicit query_insert_intermediate(session &s);
query_into_intermediate into(const std::string &table, std::initializer_list<std::string> column_names);
template<class Type>
query_into_intermediate into(const std::string &table)
{
return {db(), query().into(table, column_name_generator::generate<Type>())};
return {session_, builder_.into(table, column_name_generator::generate<Type>())};
}
template<class Type>
query_execute_finish into(const std::string &table, const Type &obj)
{
return {db(), query().into(table, column_name_generator::generate<Type>())
return {session_, builder_.into(table, column_name_generator::generate<Type>())
.values(value_extractor::extract(obj))};
}
};
@@ -208,16 +214,16 @@ public:
query_execute_where_intermediate where(const basic_condition &cond);
};
class query_update_intermediate : public query_intermediate
class query_update_intermediate : public query_start_intermediate
{
public:
using query_intermediate::query_intermediate;
query_update_intermediate(session &s, std::string table_name);
query_set_intermediate set(std::initializer_list<key_value_pair> columns);
template<class Type>
query_set_intermediate set(const Type &obj)
{
return {db(), query().set(key_value_generator::generate(obj))};
return {session_, builder_.set(key_value_generator::generate(obj))};
}
};
@@ -229,10 +235,10 @@ public:
query_execute_where_intermediate where(const basic_condition &cond);
};
class query_delete_intermediate : public query_intermediate
class query_delete_intermediate : public query_start_intermediate
{
public:
using query_intermediate::query_intermediate;
explicit query_delete_intermediate(session &s);
query_delete_from_intermediate from(const std::string &table);
};
+9 -3
View File
@@ -12,6 +12,8 @@
namespace matador::sql {
class dialect;
class session
{
public:
@@ -22,14 +24,15 @@ public:
template < class Type >
query_select_intermediate select()
{
return query_select_intermediate{*this, query_.select(column_name_generator::generate<Type>())};
return query_select_intermediate{*this, column_name_generator::generate<Type>()};
}
query_select_intermediate select(std::initializer_list<std::string> column_names);
query_insert_intermediate insert();
query_update_intermediate update(const std::string &table);
query_delete_intermediate remove();
[[nodiscard]] query_result<record> fetch(const std::string &sql) const;
[[nodiscard]] query_result<record> fetch(const query &q) const;
// [[nodiscard]] query_result<record> fetch(const std::string &sql) const;
[[nodiscard]] std::pair<size_t, std::string> execute(const std::string &sql) const;
template<typename Type>
@@ -40,6 +43,8 @@ public:
[[nodiscard]] const table_repository& tables() const;
const class dialect& dialect() const;
private:
friend class query_select_finish;
@@ -47,9 +52,10 @@ private:
private:
connection_pool<connection> &pool_;
query_builder query_;
const class dialect &dialect_;
table_repository table_repository_;
mutable std::unordered_map<std::string, record> prototypes_;
};
}
+2 -2
View File
@@ -180,7 +180,7 @@ template <> struct data_type_traits<const char*>
template <> struct data_type_traits<char*>
{
inline static database_type_t type(std::size_t size) { return size == 0 ? database_type_t::type_text : database_type_t::type_varchar; }
inline static data_type_t builtin_type(std::size_t size) { return size == 0 ? data_type_t::type_text : data_type_t::type_char_pointer; }
inline static data_type_t builtin_type(std::size_t size) { return size == 0 ? data_type_t::type_text : data_type_t::type_varchar; }
inline static unsigned long size() { return sizeof(char*); }
inline static const char* name() { return "char*"; }
};
@@ -188,7 +188,7 @@ template <> struct data_type_traits<char*>
template <> struct data_type_traits<std::string>
{
inline static database_type_t type(std::size_t size) { return size == 0 ? database_type_t::type_text : database_type_t::type_varchar; }
inline static data_type_t builtin_type(std::size_t size) { return size == 0 ? data_type_t::type_text : data_type_t::type_char_pointer; }
inline static data_type_t builtin_type(std::size_t size) { return size == 0 ? data_type_t::type_text : data_type_t::type_varchar; }
inline static unsigned long size() { return 1023; }
inline static const char* name() { return "std::string"; }
};
@@ -21,6 +21,7 @@ public:
~field_attributes() = default;
[[nodiscard]] size_t size() const;
void size(size_t size);
[[nodiscard]] constraints options() const;
private: