added data binding traits

This commit is contained in:
Sascha Kuehl 2023-12-11 17:20:42 +01:00
parent 8ad13076c8
commit 1c92e07173
17 changed files with 378 additions and 146 deletions

View File

@ -2,7 +2,9 @@
#define QUERY_OBJECT_BINDER_HPP #define QUERY_OBJECT_BINDER_HPP
#include "matador/sql/parameter_binder.hpp" #include "matador/sql/parameter_binder.hpp"
#include "matador/sql/types.hpp"
#include "matador/utils/access.hpp"
#include "matador/utils/cascade_type.hpp" #include "matador/utils/cascade_type.hpp"
#include "matador/utils/field_attributes.hpp" #include "matador/utils/field_attributes.hpp"
@ -10,37 +12,31 @@
namespace matador::sql { namespace matador::sql {
class object_binder namespace detail {
class fk_binder
{ {
public: public:
explicit object_binder(parameter_binder &binder); explicit fk_binder(parameter_binder &binder);
void reset(); template<class Type>
void bind(Type &obj, size_t column_index)
template < class V >
void on_primary_key(const char *id, V &val, typename std::enable_if<std::is_integral<V>::value && !std::is_same<bool, V>::value>::type* = 0)
{ {
binder_.bind(index_++, val); index_ = column_index;
} utils::access::process(*this, obj);
void on_primary_key(const char *id, std::string &, size_t);
void on_revision(const char *id, unsigned long long &/*rev*/);
template<typename Type>
void on_attribute(const char *id, Type &val, const utils::field_attributes &/*attr*/ = utils::null_attributes)
{
binder_.bind(index_++, val);
} }
template<class Type, template < class ... > class Pointer> template<typename ValueType>
void on_belongs_to(const char *id, Pointer<Type> &x, utils::cascade_type) 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);
// binder_.bind(index_++, val); void on_revision(const char * /*id*/, unsigned long long &/*rev*/) {}
}
template<class Type, template < class ... > class Pointer> template < class Type >
void on_has_one(const char *id, Pointer<Type> &x, utils::cascade_type) void on_attribute(const char * /*id*/, Type &/*x*/, const utils::field_attributes &/*attr*/ = utils::null_attributes) {}
{ template < class Pointer >
// binder_.bind(index_++, val); 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> 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) {}
template<class ContainerType> template<class ContainerType>
@ -51,5 +47,58 @@ private:
size_t index_{0}; size_t index_{0};
}; };
}
class object_binder
{
public:
explicit object_binder(parameter_binder &binder);
void reset();
template < class Type >
void on_primary_key(const char *id, Type &val, typename std::enable_if<std::is_integral<Type>::value && !std::is_same<bool, Type>::value>::type* = 0)
{
data_type_traits<Type>::bind_value(binder_, index_++, val);
}
void on_primary_key(const char *id, std::string &, size_t size);
void on_revision(const char *id, unsigned long long &/*rev*/);
template<typename Type>
void on_attribute(const char *id, Type &val, const utils::field_attributes &/*attr*/ = utils::null_attributes)
{
data_type_traits<Type>::bind_value(binder_, index_++, val);
}
template<class Type, template < class ... > class Pointer>
void on_belongs_to(const char *id, Pointer<Type> &x, utils::cascade_type)
{
fk_binder_.bind(index_++, x);
}
template<class Type, template < class ... > class Pointer>
void on_has_one(const char *id, Pointer<Type> &x, utils::cascade_type)
{
fk_binder_.bind(index_++, x);
}
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:
parameter_binder &binder_;
size_t index_{0};
detail::fk_binder fk_binder_;
};
namespace detail {
template<typename ValueType>
void fk_binder::on_primary_key(const char *id, ValueType &value, typename std::enable_if<std::is_integral<ValueType>::value && !std::is_same<bool, ValueType>::value>::type *)
{
data_type_traits<ValueType>::bind_value(binder_, index_++, value);
}
}
} }
#endif //QUERY_OBJECT_BINDER_HPP #endif //QUERY_OBJECT_BINDER_HPP

View File

@ -123,7 +123,7 @@ namespace detail {
template<typename ValueType> 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 *) 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); data_type_traits<ValueType>::read_value(reader_, id, column_index_++, value);
} }
} }

View File

@ -23,6 +23,8 @@ public:
return *this; return *this;
} }
statement& bind(size_t pos, const char *value);
statement& bind(size_t pos, std::string &val, size_t size); statement& bind(size_t pos, std::string &val, size_t size);
template < class Type > template < class Type >

View File

@ -14,14 +14,15 @@ class connection;
struct cache_info struct cache_info
{ {
std::unique_ptr<statement> statement_; statement statement_;
// std::unique_ptr<statement> statement_;
size_t connection_id_; size_t connection_id_;
}; };
class statement_cache class statement_cache
{ {
public: public:
statement& acquire(const std::string &stmt, const connection &conn); statement& acquire(query_context &&context, const connection &conn);
void release(const statement &stmt); void release(const statement &stmt);
private: private:

View File

@ -4,6 +4,7 @@
#include "matador/sql/query_context.hpp" #include "matador/sql/query_context.hpp"
#include "matador/sql/query_result_impl.hpp" #include "matador/sql/query_result_impl.hpp"
#include "matador/sql/parameter_binder.hpp" #include "matador/sql/parameter_binder.hpp"
#include "matador/sql/types.hpp"
#include <memory> #include <memory>
@ -20,15 +21,20 @@ public:
virtual size_t execute() = 0; virtual size_t execute() = 0;
virtual std::unique_ptr<query_result_impl> fetch() = 0; virtual std::unique_ptr<query_result_impl> fetch() = 0;
template < class V > template < class Type >
void bind(size_t pos, V &val) void bind(size_t pos, Type &val)
{ {
binder().bind(pos, val); data_type_traits<Type>::bind_value(binder(), pos, val);
}
void bind(size_t pos, const char *value, size_t size)
{
data_type_traits<const char*>::bind_value(binder(), pos, value, size);
} }
void bind(size_t pos, std::string &val, size_t size) void bind(size_t pos, std::string &val, size_t size)
{ {
binder().bind(pos, val, size); data_type_traits<std::string>::bind_value(binder(), pos, val, size);
} }
virtual void reset() = 0; virtual void reset() = 0;

View File

@ -1,12 +1,15 @@
#ifndef QUERY_TYPES_HPP #ifndef QUERY_TYPES_HPP
#define QUERY_TYPES_HPP #define QUERY_TYPES_HPP
#include "matador/sql/any_type.hpp"
#include <cstdint> #include <cstdint>
#include <string> #include <string>
namespace matador::sql { namespace matador::sql {
class query_result_reader; class query_result_reader;
class parameter_binder;
/** /**
* @brief Enumeration type of all supported builtin data types * @brief Enumeration type of all supported builtin data types
@ -34,26 +37,6 @@ enum class data_type_t : uint8_t {
type_null, /*!< Data type null */ type_null, /*!< Data type null */
type_unknown /*!< Data type unknown */ type_unknown /*!< Data type unknown */
}; };
/**
* @brief Enumeration of database data types
*/
enum struct database_type_t : uint8_t {
type_char = 0, /*!< Data type char */
type_float, /*!< Data type float */
type_double, /*!< Data type double */
type_smallint, /*!< Data type small int */
type_int, /*!< Data type integer */
type_bigint, /*!< Data type big integer */
type_bool, /*!< Data type bool */
type_char_pointer, /*!< Data type character pointer */
type_varchar, /*!< Data type varchar */
type_text, /*!< Data type text */
type_date, /*!< Data type date */
type_time, /*!< Data type time */
type_blob, /*!< Data type blob */
type_null, /*!< Data type null */
type_unknown /*!< Data type unknown */
};
enum class sql_function_t { enum class sql_function_t {
NONE, NONE,
@ -79,146 +62,130 @@ struct data_type_traits;
/// @cond MATADOR_DEV /// @cond MATADOR_DEV
template <> struct data_type_traits<char, void> template <> struct data_type_traits<char, void>
{ {
// inline static database_type_t type(std::size_t /*size*/) { return database_type_t::type_char; }
inline static data_type_t builtin_type(std::size_t /*size*/) { return data_type_t::type_char; } inline static data_type_t builtin_type(std::size_t /*size*/) { return data_type_t::type_char; }
static void read_value(query_result_reader &reader, const char *id, size_t index, char &value); static void read_value(query_result_reader &reader, const char *id, size_t index, char &value);
// inline static unsigned long size() { return sizeof(char); } static void bind_value(parameter_binder &binder, size_t index, char &value);
// inline static const char* name() { return "char"; } inline static any_type create_value(char &value) { return value; }
}; };
template <> struct data_type_traits<short, void> template <> struct data_type_traits<short, void>
{ {
// inline static database_type_t type(std::size_t /*size*/) { return database_type_t::type_smallint; }
inline static data_type_t builtin_type(std::size_t /*size*/) { return data_type_t::type_short; } inline static data_type_t builtin_type(std::size_t /*size*/) { return data_type_t::type_short; }
static void read_value(query_result_reader &reader, const char *id, size_t index, short &value); static void read_value(query_result_reader &reader, const char *id, size_t index, short &value);
// inline static unsigned long size() { return sizeof(short); } static void bind_value(parameter_binder &binder, size_t index, short &value);
// inline static const char* name() { return "short"; } inline static any_type create_value(short &value) { return value; }
}; };
template <> struct data_type_traits<int, void> template <> struct data_type_traits<int, void>
{ {
// inline static database_type_t type(std::size_t /*size*/) { return database_type_t::type_int; }
inline static data_type_t builtin_type(std::size_t /*size*/) { return data_type_t::type_int; } inline static data_type_t builtin_type(std::size_t /*size*/) { return data_type_t::type_int; }
static void read_value(query_result_reader &reader, const char *id, size_t index, int &value); static void read_value(query_result_reader &reader, const char *id, size_t index, int &value);
// inline static unsigned long size() { return sizeof(int); } static void bind_value(parameter_binder &binder, size_t index, int &value);
// inline static const char* name() { return "int"; } inline static any_type create_value(int &value) { return value; }
}; };
template <> struct data_type_traits<long, void> template <> struct data_type_traits<long, void>
{ {
// inline static database_type_t type(std::size_t /*size*/) { return database_type_t::type_bigint; }
inline static data_type_t builtin_type(std::size_t /*size*/) { return data_type_t::type_long; } inline static data_type_t builtin_type(std::size_t /*size*/) { return data_type_t::type_long; }
static void read_value(query_result_reader &reader, const char *id, size_t index, long &value); static void read_value(query_result_reader &reader, const char *id, size_t index, long &value);
// inline static unsigned long size() { return sizeof(long); } static void bind_value(parameter_binder &binder, size_t index, long &value);
// inline static const char* name() { return "long"; } inline static any_type create_value(long &value) { return value; }
}; };
template <> struct data_type_traits<long long, void> template <> struct data_type_traits<long long, void>
{ {
// inline static database_type_t type(std::size_t /*size*/) { return database_type_t::type_bigint; }
inline static data_type_t builtin_type(std::size_t /*size*/) { return data_type_t::type_long_long; } inline static data_type_t builtin_type(std::size_t /*size*/) { return data_type_t::type_long_long; }
static void read_value(query_result_reader &reader, const char *id, size_t index, long long &value); static void read_value(query_result_reader &reader, const char *id, size_t index, long long &value);
// inline static unsigned long size() { return sizeof(long long); } static void bind_value(parameter_binder &binder, size_t index, long long &value);
// inline static const char* name() { return "long long"; } inline static any_type create_value(long long &value) { return value; }
}; };
template <> struct data_type_traits<unsigned char, void> template <> struct data_type_traits<unsigned char, void>
{ {
// inline static database_type_t type(std::size_t /*size*/) { return database_type_t::type_char; }
inline static data_type_t builtin_type(std::size_t /*size*/) { return data_type_t::type_unsigned_char; } inline static data_type_t builtin_type(std::size_t /*size*/) { return data_type_t::type_unsigned_char; }
static void read_value(query_result_reader &reader, const char *id, size_t index, unsigned char &value); static void read_value(query_result_reader &reader, const char *id, size_t index, unsigned char &value);
// inline static unsigned long size() { return sizeof(unsigned char); } static void bind_value(parameter_binder &binder, size_t index, unsigned char &value);
// inline static const char* name() { return "unsigned char"; } inline static any_type create_value(unsigned char &value) { return value; }
}; };
template <> struct data_type_traits<unsigned short, void> template <> struct data_type_traits<unsigned short, void>
{ {
// inline static database_type_t type(std::size_t /*size*/) { return database_type_t::type_smallint; }
inline static data_type_t builtin_type(std::size_t /*size*/) { return data_type_t::type_unsigned_short; } inline static data_type_t builtin_type(std::size_t /*size*/) { return data_type_t::type_unsigned_short; }
static void read_value(query_result_reader &reader, const char *id, size_t index, unsigned short &value); static void read_value(query_result_reader &reader, const char *id, size_t index, unsigned short &value);
// inline static unsigned long size() { return sizeof(unsigned short); } static void bind_value(parameter_binder &binder, size_t index, unsigned short &value);
// inline static const char* name() { return "unsigned short"; } inline static any_type create_value(unsigned short &value) { return value; }
}; };
template <> struct data_type_traits<unsigned int, void> template <> struct data_type_traits<unsigned int, void>
{ {
// inline static database_type_t type(std::size_t /*size*/) { return database_type_t::type_int; }
inline static data_type_t builtin_type(std::size_t /*size*/) { return data_type_t::type_unsigned_int; } inline static data_type_t builtin_type(std::size_t /*size*/) { return data_type_t::type_unsigned_int; }
static void read_value(query_result_reader &reader, const char *id, size_t index, unsigned int &value); static void read_value(query_result_reader &reader, const char *id, size_t index, unsigned int &value);
// inline static unsigned long size() { return sizeof(unsigned int); } static void bind_value(parameter_binder &binder, size_t index, unsigned int &value);
// inline static const char* name() { return "unsigned int"; } inline static any_type create_value(unsigned int &value) { return value; }
}; };
template <> struct data_type_traits<unsigned long, void> template <> struct data_type_traits<unsigned long, void>
{ {
// inline static database_type_t type(std::size_t /*size*/ = 0) { return database_type_t::type_bigint; }
inline static data_type_t builtin_type(std::size_t /*size*/ = 0) { return data_type_t::type_unsigned_long; } inline static data_type_t builtin_type(std::size_t /*size*/ = 0) { return data_type_t::type_unsigned_long; }
static void read_value(query_result_reader &reader, const char *id, size_t index, unsigned long &value); static void read_value(query_result_reader &reader, const char *id, size_t index, unsigned long &value);
// inline static unsigned long size() { return sizeof(unsigned long); } static void bind_value(parameter_binder &binder, size_t index, unsigned long &value);
// inline static const char* name() { return "unsigned long"; } inline static any_type create_value(unsigned long &value) { return value; }
}; };
template <> struct data_type_traits<unsigned long long, void> template <> struct data_type_traits<unsigned long long, void>
{ {
// inline static database_type_t type(std::size_t /*size*/) { return database_type_t::type_bigint; }
inline static data_type_t builtin_type(std::size_t /*size*/) { return data_type_t::type_unsigned_long_long; } inline static data_type_t builtin_type(std::size_t /*size*/) { return data_type_t::type_unsigned_long_long; }
static void read_value(query_result_reader &reader, const char *id, size_t index, unsigned long long &value); static void read_value(query_result_reader &reader, const char *id, size_t index, unsigned long long &value);
// inline static unsigned long size() { return sizeof(unsigned long long); } static void bind_value(parameter_binder &binder, size_t index, unsigned long long &value);
// inline static const char* name() { return "unsigned long long"; } inline static any_type create_value(unsigned long long &value) { return value; }
}; };
template <> struct data_type_traits<bool, void> template <> struct data_type_traits<bool, void>
{ {
// inline static database_type_t type(std::size_t /*size*/) { return database_type_t::type_bool; }
inline static data_type_t builtin_type(std::size_t /*size*/) { return data_type_t::type_bool; } inline static data_type_t builtin_type(std::size_t /*size*/) { return data_type_t::type_bool; }
static void read_value(query_result_reader &reader, const char *id, size_t index, bool &value); static void read_value(query_result_reader &reader, const char *id, size_t index, bool &value);
// inline static unsigned long size() { return sizeof(bool); } static void bind_value(parameter_binder &binder, size_t index, bool &value);
// inline static const char* name() { return "bool"; } inline static any_type create_value(bool &value) { return value; }
}; };
template <> struct data_type_traits<float, void> template <> struct data_type_traits<float, void>
{ {
// inline static database_type_t type(std::size_t /*size*/) { return database_type_t::type_float; }
inline static data_type_t builtin_type(std::size_t /*size*/) { return data_type_t::type_float; } inline static data_type_t builtin_type(std::size_t /*size*/) { return data_type_t::type_float; }
static void read_value(query_result_reader &reader, const char *id, size_t index, float &value); static void read_value(query_result_reader &reader, const char *id, size_t index, float &value);
// inline static unsigned long size() { return sizeof(float); } static void bind_value(parameter_binder &binder, size_t index, float &value);
// inline static const char* name() { return "float"; } inline static any_type create_value(float &value) { return value; }
}; };
template <> struct data_type_traits<double, void> template <> struct data_type_traits<double, void>
{ {
// inline static database_type_t type(std::size_t /*size*/) { return database_type_t::type_double; }
inline static data_type_t builtin_type(std::size_t /*size*/) { return data_type_t::type_double; } inline static data_type_t builtin_type(std::size_t /*size*/) { return data_type_t::type_double; }
static void read_value(query_result_reader &reader, const char *id, size_t index, double &value); static void read_value(query_result_reader &reader, const char *id, size_t index, double &value);
// inline static unsigned long size() { return sizeof(double); } static void bind_value(parameter_binder &binder, size_t index, double &value);
// inline static const char* name() { return "double"; } inline static any_type create_value(double &value) { return value; }
}; };
template <> struct data_type_traits<const char*, void> template <> struct data_type_traits<const char*, void>
{ {
// 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_char_pointer; }
static void read_value(query_result_reader &reader, const char *id, size_t index, const char* value, size_t size); static void read_value(query_result_reader &reader, const char *id, size_t index, const char* value, size_t size);
// inline static unsigned long size() { return sizeof(const char*); } static void bind_value(parameter_binder &binder, size_t index, const char *value, size_t size = 0);
// inline static const char* name() { return "const char*"; } inline static any_type create_value(const char *value) { return value; }
}; };
template <> struct data_type_traits<char*, void> template <> struct data_type_traits<char*, void>
{ {
// 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_varchar; } inline static data_type_t builtin_type(std::size_t size) { return size == 0 ? data_type_t::type_text : data_type_t::type_varchar; }
static void read_value(query_result_reader &reader, const char *id, size_t index, char *value, size_t size); static void read_value(query_result_reader &reader, const char *id, size_t index, char *value, size_t size);
// inline static unsigned long size() { return sizeof(char*); } static void bind_value(parameter_binder &binder, size_t index, char *value, size_t size = 0);
// inline static const char* name() { return "char*"; } inline static any_type create_value(const char *value) { return value; }
}; };
template <> struct data_type_traits<std::string, void> template <> struct data_type_traits<std::string, void>
{ {
// 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_varchar; } inline static data_type_t builtin_type(std::size_t size) { return size == 0 ? data_type_t::type_text : data_type_t::type_varchar; }
static void read_value(query_result_reader &reader, const char *id, size_t index, std::string &value, size_t size); static void read_value(query_result_reader &reader, const char *id, size_t index, std::string &value, size_t size);
// inline static unsigned long size() { return 1023; } static void bind_value(parameter_binder &binder, size_t index, std::string &value, size_t size = 0);
// inline static const char* name() { return "std::string"; } inline static any_type create_value(std::string &value) { return value; }
}; };
//template <> struct data_type_traits<matador::date> //template <> struct data_type_traits<matador::date>
@ -240,14 +207,16 @@ template <> struct data_type_traits<std::string, void>
template < typename EnumType > template < typename EnumType >
struct data_type_traits<EnumType, typename std::enable_if<std::is_enum<EnumType>::value>::type> struct data_type_traits<EnumType, typename std::enable_if<std::is_enum<EnumType>::value>::type>
{ {
// inline static database_type_t type(std::size_t /*size*/) { return database_type_t::type_int; }
inline static data_type_t builtin_type(std::size_t /*size*/) { return data_type_t::type_int; } inline static data_type_t builtin_type(std::size_t /*size*/) { return data_type_t::type_int; }
static void read_value(query_result_reader &reader, const char *id, size_t index, EnumType &value) static void read_value(query_result_reader &reader, const char *id, size_t index, EnumType &value)
{ {
data_type_traits<int>::read_value(reader, id, index, reinterpret_cast<int&>(value)); data_type_traits<int>::read_value(reader, id, index, reinterpret_cast<int&>(value));
} }
// inline static unsigned long size() { return sizeof(int); } static void bind_value(parameter_binder &binder, size_t index, EnumType &value)
// inline static const char* name() { return "int"; } {
data_type_traits<int>::bind_value(binder, index, (int&)value);
}
inline static any_type create_value(EnumType &value) { return (int)value; }
}; };
/// @endcond /// @endcond

View File

@ -2,6 +2,7 @@
#define QUERY_VALUE_EXTRACTOR_HPP #define QUERY_VALUE_EXTRACTOR_HPP
#include "matador/sql/fk_value_extractor.hpp" #include "matador/sql/fk_value_extractor.hpp"
#include "matador/sql/types.hpp"
#include <vector> #include <vector>
@ -56,14 +57,9 @@ public:
private: private:
template<typename Type> template<typename Type>
void append(Type &value, typename std::enable_if<!std::is_enum<Type>::value>::type* = 0) void append(Type &value)
{ {
values_.emplace_back(value); values_.emplace_back(data_type_traits<Type>::create_value(value));
}
template<typename Type>
void append(Type &value, typename std::enable_if<std::is_enum<Type>::value>::type* = 0)
{
values_.emplace_back((int)value);
} }
private: private:

View File

@ -0,0 +1,50 @@
#ifndef QUERY_ENUM_MAPPER_HPP
#define QUERY_ENUM_MAPPER_HPP
#include <optional>
#include <string>
#include <unordered_map>
namespace matador::utils {
template < typename EnumType, class Enable = void >
class enum_mapper;
template < typename EnumType>
class enum_mapper<EnumType, typename std::enable_if<std::is_enum<EnumType>::value>::type>
{
public:
using enum_to_string_map = std::unordered_map<EnumType, std::string>;
using string_to_enum_map = std::unordered_map<std::string, EnumType>;
explicit enum_mapper(enum_to_string_map enum_map)
: enum_to_string_map_(std::move(enum_map))
{
for (const auto &elem : enum_to_string_map_) {
string_to_enum_map_.emplace(elem.second, elem.first);
}
}
std::optional<EnumType> to_enum(const std::string &enum_string) const {
if (const auto it = string_to_enum_map_.find(enum_string); it != string_to_enum_map_.end()) {
return { it->second };
}
return std::nullopt;
}
std::string to_string(EnumType enum_value) const {
if (const auto it = enum_to_string_map_.find(enum_value); it != enum_to_string_map_.end()) {
return it->second;
}
return {};
}
private:
enum_to_string_map enum_to_string_map_;
string_to_enum_map string_to_enum_map_;
};
}
#endif //QUERY_ENUM_MAPPER_HPP

View File

@ -77,7 +77,8 @@ set(UTILS_HEADER
../include/matador/utils/access.hpp ../include/matador/utils/access.hpp
../include/matador/utils/identifier.hpp ../include/matador/utils/identifier.hpp
../include/matador/utils/cascade_type.hpp ../include/matador/utils/cascade_type.hpp
../include/matador/utils/logger.hpp) ../include/matador/utils/logger.hpp
../include/matador/utils/enum_mapper.hpp)
set(UTILS_SOURCES set(UTILS_SOURCES
utils/field_attributes.cpp utils/field_attributes.cpp

View File

@ -3,22 +3,35 @@
namespace matador::sql { namespace matador::sql {
object_binder::object_binder(parameter_binder &binder) namespace detail {
fk_binder::fk_binder(parameter_binder &binder)
: binder_(binder) {} : binder_(binder) {}
void fk_binder::on_primary_key(const char *id, std::string &value, size_t size)
{
data_type_traits<std::string>::bind_value(binder_, index_++, value);
}
}
object_binder::object_binder(parameter_binder &binder)
: binder_(binder)
, fk_binder_(binder) {}
void object_binder::reset() void object_binder::reset()
{ {
index_ = 0; index_ = 0;
} }
void object_binder::on_primary_key(const char *id, std::string &val, size_t) void object_binder::on_primary_key(const char *id, std::string &val, size_t size)
{ {
binder_.bind(index_++, val); data_type_traits<std::string>::bind_value(binder_, index_++, val, size);
} }
void object_binder::on_revision(const char *id, unsigned long long int &rev) void object_binder::on_revision(const char *id, unsigned long long int &rev)
{ {
binder_.bind(index_++, rev); data_type_traits<unsigned long long>::bind_value(binder_, index_++, rev);
} }
} }

View File

@ -6,8 +6,9 @@ namespace matador::sql {
detail::pk_reader::pk_reader(query_result_reader &reader) detail::pk_reader::pk_reader(query_result_reader &reader)
: reader_(reader) {} : reader_(reader) {}
void detail::pk_reader::on_primary_key(const char *id, std::string &value, size_t size) { void detail::pk_reader::on_primary_key(const char *id, std::string &value, size_t size)
reader_.read_value(id, column_index_, value, size); {
data_type_traits<std::string>::read_value(reader_, id, column_index_++, value, size);
} }
query_result_impl::query_result_impl(std::unique_ptr<query_result_reader> &&reader, record prototype) query_result_impl::query_result_impl(std::unique_ptr<query_result_reader> &&reader, record prototype)

View File

@ -8,6 +8,12 @@ statement::statement(std::unique_ptr<statement_impl> impl, const utils::logger &
, object_binder_(statement_->binder()) , object_binder_(statement_->binder())
{} {}
statement &statement::bind(size_t pos, const char *value)
{
statement_->bind(pos, value, 0);
return *this;
}
statement &statement::bind(size_t pos, std::string &val, size_t size) statement &statement::bind(size_t pos, std::string &val, size_t size)
{ {
statement_->bind(pos, val, size); statement_->bind(pos, val, size);

View File

@ -1,14 +1,16 @@
#include "matador/sql/connection.hpp"
#include "matador/sql/statement_cache.hpp" #include "matador/sql/statement_cache.hpp"
namespace matador::sql { namespace matador::sql {
statement &statement_cache::acquire(const std::string &stmt, const connection &conn) { statement &statement_cache::acquire(query_context &&context, const connection &conn) {
std::lock_guard<std::mutex> guard(mutex_); std::lock_guard<std::mutex> guard(mutex_);
auto key = hash_(stmt); auto key = hash_(context.sql);
auto it = statement_map_.find(key); auto it = statement_map_.find(key);
if (it == statement_map_.end()) { if (it == statement_map_.end()) {
cache_info info {conn.prepare(std::move(context)), 1};
// it = statement_map_.emplace(key, {conn.prepare(std::move(context))});
} }
return *it->second.statement_; return it->second.statement_;
} }
void statement_cache::release(const statement &stmt) { void statement_cache::release(const statement &stmt) {

View File

@ -1,5 +1,6 @@
#include "matador/sql/types.hpp" #include "matador/sql/types.hpp"
#include "matador/sql/parameter_binder.hpp"
#include "matador/sql/query_result_reader.hpp" #include "matador/sql/query_result_reader.hpp"
namespace matador::sql { namespace matador::sql {
@ -9,77 +10,159 @@ void data_type_traits<char>::read_value(query_result_reader &reader, const char
reader.read_value(id, index, value); reader.read_value(id, index, value);
} }
void data_type_traits<char>::bind_value(parameter_binder &binder, size_t index, char &value)
{
binder.bind(index, value);
}
void data_type_traits<short>::read_value(query_result_reader &reader, const char *id, size_t index, short &value) void data_type_traits<short>::read_value(query_result_reader &reader, const char *id, size_t index, short &value)
{ {
reader.read_value(id, index, value); reader.read_value(id, index, value);
} }
void data_type_traits<short>::bind_value(parameter_binder &binder, size_t index, short &value)
{
binder.bind(index, value);
}
void data_type_traits<int>::read_value(query_result_reader &reader, const char *id, size_t index, int &value) void data_type_traits<int>::read_value(query_result_reader &reader, const char *id, size_t index, int &value)
{ {
reader.read_value(id, index, value); reader.read_value(id, index, value);
} }
void data_type_traits<int>::bind_value(parameter_binder &binder, size_t index, int &value)
{
binder.bind(index, value);
}
void data_type_traits<long>::read_value(query_result_reader &reader, const char *id, size_t index, long &value) void data_type_traits<long>::read_value(query_result_reader &reader, const char *id, size_t index, long &value)
{ {
reader.read_value(id, index, value); reader.read_value(id, index, value);
} }
void data_type_traits<long>::bind_value(parameter_binder &binder, size_t index, long &value)
{
binder.bind(index, value);
}
void data_type_traits<long long>::read_value(query_result_reader &reader, const char *id, size_t index, long long &value) void data_type_traits<long long>::read_value(query_result_reader &reader, const char *id, size_t index, long long &value)
{ {
reader.read_value(id, index, value); reader.read_value(id, index, value);
} }
void data_type_traits<long long int>::bind_value(parameter_binder &binder, size_t index, long long int &value)
{
binder.bind(index, value);
}
void data_type_traits<unsigned char>::read_value(query_result_reader &reader, const char *id, size_t index, unsigned char &value) void data_type_traits<unsigned char>::read_value(query_result_reader &reader, const char *id, size_t index, unsigned char &value)
{ {
reader.read_value(id, index, value); reader.read_value(id, index, value);
} }
void data_type_traits<unsigned char>::bind_value(parameter_binder &binder, size_t index, unsigned char &value)
{
binder.bind(index, value);
}
void data_type_traits<unsigned short>::read_value(query_result_reader &reader, const char *id, size_t index, unsigned short &value) void data_type_traits<unsigned short>::read_value(query_result_reader &reader, const char *id, size_t index, unsigned short &value)
{ {
reader.read_value(id, index, value); reader.read_value(id, index, value);
} }
void data_type_traits<unsigned short>::bind_value(parameter_binder &binder, size_t index, unsigned short &value)
{
binder.bind(index, value);
}
void data_type_traits<unsigned int>::read_value(query_result_reader &reader, const char *id, size_t index, unsigned int &value) void data_type_traits<unsigned int>::read_value(query_result_reader &reader, const char *id, size_t index, unsigned int &value)
{ {
reader.read_value(id, index, value); reader.read_value(id, index, value);
} }
void data_type_traits<unsigned int>::bind_value(parameter_binder &binder, size_t index, unsigned int &value)
{
binder.bind(index, value);
}
void data_type_traits<unsigned long>::read_value(query_result_reader &reader, const char *id, size_t index, unsigned long &value) void data_type_traits<unsigned long>::read_value(query_result_reader &reader, const char *id, size_t index, unsigned long &value)
{ {
reader.read_value(id, index, value); reader.read_value(id, index, value);
} }
void data_type_traits<unsigned long>::bind_value(parameter_binder &binder, size_t index, unsigned long &value)
{
binder.bind(index, value);
}
void data_type_traits<unsigned long long>::read_value(query_result_reader &reader, const char *id, size_t index, unsigned long long &value) void data_type_traits<unsigned long long>::read_value(query_result_reader &reader, const char *id, size_t index, unsigned long long &value)
{ {
reader.read_value(id, index, value); reader.read_value(id, index, value);
} }
void data_type_traits<unsigned long long int>::bind_value(parameter_binder &binder, size_t index, unsigned long long int &value)
{
binder.bind(index, value);
}
void data_type_traits<bool>::read_value(query_result_reader &reader, const char *id, size_t index, bool &value) void data_type_traits<bool>::read_value(query_result_reader &reader, const char *id, size_t index, bool &value)
{ {
reader.read_value(id, index, value); reader.read_value(id, index, value);
} }
void data_type_traits<bool>::bind_value(parameter_binder &binder, size_t index, bool &value)
{
binder.bind(index, value);
}
void data_type_traits<float>::read_value(query_result_reader &reader, const char *id, size_t index, float &value) void data_type_traits<float>::read_value(query_result_reader &reader, const char *id, size_t index, float &value)
{ {
reader.read_value(id, index, value); reader.read_value(id, index, value);
} }
void data_type_traits<float>::bind_value(parameter_binder &binder, size_t index, float &value)
{
binder.bind(index, value);
}
void data_type_traits<double>::read_value(query_result_reader &reader, const char *id, size_t index, double &value) void data_type_traits<double>::read_value(query_result_reader &reader, const char *id, size_t index, double &value)
{ {
reader.read_value(id, index, value); reader.read_value(id, index, value);
} }
void data_type_traits<double>::bind_value(parameter_binder &binder, size_t index, double &value)
{
binder.bind(index, value);
}
void data_type_traits<const char*>::read_value(query_result_reader &reader, const char *id, size_t index, const char* value, size_t size) void data_type_traits<const char*>::read_value(query_result_reader &reader, const char *id, size_t index, const char* value, size_t size)
{ {
reader.read_value(id, index, const_cast<char*>(value), size); reader.read_value(id, index, const_cast<char*>(value), size);
} }
void data_type_traits<const char *>::bind_value(parameter_binder &binder, size_t index, const char *value, size_t size)
{
binder.bind(index, value, size);
}
void data_type_traits<char*>::read_value(query_result_reader &reader, const char *id, size_t index, char* value, size_t size) void data_type_traits<char*>::read_value(query_result_reader &reader, const char *id, size_t index, char* value, size_t size)
{ {
reader.read_value(id, index, value, size); reader.read_value(id, index, value, size);
} }
void data_type_traits<char *>::bind_value(parameter_binder &binder, size_t index, char *value, size_t size)
{
binder.bind(index, value, size);
}
void data_type_traits<std::string>::read_value(query_result_reader &reader, const char *id, size_t index, std::string &value, size_t size) void data_type_traits<std::string>::read_value(query_result_reader &reader, const char *id, size_t index, std::string &value, size_t size)
{ {
reader.read_value(id, index, value, size); reader.read_value(id, index, value, size);
} }
void data_type_traits<std::string>::bind_value(parameter_binder &binder, size_t index, std::string &value, size_t size)
{
binder.bind(index, value, size);
}
} }

View File

@ -7,25 +7,16 @@
using namespace matador; using namespace matador;
class TestConnection
{
public:
explicit TestConnection(sql::connection_info info)
: info_(std::move(info)) {}
void open() {}
private:
sql::connection_info info_;
};
TEST_CASE("Acquire prepared statement", "[statement cache]") { TEST_CASE("Acquire prepared statement", "[statement cache]") {
sql::statement_cache cache; sql::statement_cache cache;
sql::connection_pool<TestConnection> pool("sqlite://sqlite.db", 4); sql::connection_pool<sql::connection> pool("sqlite://sqlite.db", 4);
// sql::session s(pool); sql::session s(pool);
// auto conn = pool.acquire(); auto conn = pool.acquire();
std::string sql = R"(SELECT * FROM person WHERE name = 'george')"; std::string sql = R"(SELECT * FROM person WHERE name = 'george')";
// auto stmt = cache.acquire(sql, conn); // auto &stmt = cache.acquire(sql, *conn);
} }

View File

@ -4,6 +4,8 @@
#include "matador/sql/connection_pool.hpp" #include "matador/sql/connection_pool.hpp"
#include "matador/sql/session.hpp" #include "matador/sql/session.hpp"
#include "matador/utils/enum_mapper.hpp"
#include "Databases.hpp" #include "Databases.hpp"
#include "models/location.hpp" #include "models/location.hpp"
@ -25,7 +27,7 @@ public:
.table<location>("location") .table<location>("location")
.execute(); .execute();
REQUIRE(res.first == 0); REQUIRE(res.first == 0);
REQUIRE(res.second == R"(CREATE TABLE "location" ("id" BIGINT, "name" VARCHAR(255), "coordinate_x" INTEGER, "coordinate_y" INTEGER, "coordinate_z" INTEGER, "color" INTEGER, CONSTRAINT PK_location PRIMARY KEY (id)))"); REQUIRE(res.second == R"(CREATE TABLE "location" ("id" BIGINT, "name" VARCHAR(255), "coordinate_x" INTEGER, "coordinate_y" INTEGER, "coordinate_z" INTEGER, "color" TEXT, CONSTRAINT PK_location PRIMARY KEY (id)))");
} }
~TypeTraitsTestFixture() ~TypeTraitsTestFixture()
@ -41,19 +43,78 @@ private:
matador::sql::session session_; matador::sql::session session_;
}; };
static const matador::utils::enum_mapper<Color> color_enum({
{Color::Green, "green"},
{Color::Red, "red"},
{Color::Blue, "blue"},
{Color::Yellow, "yellow"},
{Color::Black, "black"},
{Color::White, "white"},
{Color::Brown, "brown"}
});
namespace matador::sql {
template<>
struct data_type_traits<Color, void>
{
inline static data_type_t builtin_type(std::size_t size)
{ return data_type_traits<std::string>::builtin_type(size); }
static void read_value(query_result_reader &reader, const char *id, size_t index, Color &value)
{
std::string enum_string;
reader.read_value(id, index, enum_string, 64);
auto enum_opt = color_enum.to_enum(enum_string);
if (enum_opt) {
value = enum_opt.value();
}
}
static any_type create_value(Color &value)
{
return color_enum.to_string(value);
}
static void bind_value(parameter_binder &binder, size_t index, Color &value)
{
binder.bind(index, color_enum.to_string(value));
}
};
}
TEMPLATE_TEST_CASE_METHOD(TypeTraitsTestFixture, "Special handling of attributes with type traits", "[typetraits]", Sqlite, Postgres) TEMPLATE_TEST_CASE_METHOD(TypeTraitsTestFixture, "Special handling of attributes with type traits", "[typetraits]", Sqlite, Postgres)
{ {
auto &s = TypeTraitsTestFixture<TestType>::session(); auto &s = TypeTraitsTestFixture<TestType>::session();
SECTION("Insert and select with direct execution") {
location loc{1, "center", {1, 2, 3}, Color::Black}; location loc{1, "center", {1, 2, 3}, Color::Black};
auto res = s.insert().template into<location>("location").values(loc).execute(); auto res = s.insert().template into<location>("location").values(loc).execute();
REQUIRE(res.first == 1); REQUIRE(res.first == 1);
auto result = s.template select<location>().from("location").template fetch_all<location>(); auto result = s.template select<location>().from("location").
template fetch_all<location>();
for (const auto &l : result) { for (const auto &l: result) {
REQUIRE(l.name == "center"); REQUIRE(l.name == "center");
} }
}
SECTION("Insert and select with prepared statement") {
location loc{1, "center", {1, 2, 3}, Color::Black};
auto stmt = s.insert().template into<location>("location").template values<location>().prepare();
auto res = stmt.bind(loc).execute();
REQUIRE(res == 1);
auto result = s.template select<location>().from("location").
template fetch_all<location>();
for (const auto &l: result) {
REQUIRE(l.name == "center");
}
}
} }

View File

@ -23,4 +23,5 @@ void attribute(Operator &op, const char *id, test::coordinate &value, const fiel
} }
} }
#endif //QUERY_COORDINATE_HPP #endif //QUERY_COORDINATE_HPP