added any type visitor and converter
This commit is contained in:
@@ -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
|
||||
@@ -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 <>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
@@ -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_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user