From 1c92e0717381416e5540f2d5bfd025b835771f11 Mon Sep 17 00:00:00 2001 From: Sascha Kuehl Date: Mon, 11 Dec 2023 17:20:42 +0100 Subject: [PATCH] added data binding traits --- include/matador/sql/object_binder.hpp | 99 ++++++++++++++----- include/matador/sql/query_result_impl.hpp | 2 +- include/matador/sql/statement.hpp | 2 + include/matador/sql/statement_cache.hpp | 5 +- include/matador/sql/statement_impl.hpp | 14 ++- include/matador/sql/types.hpp | 111 ++++++++-------------- include/matador/sql/value_extractor.hpp | 10 +- include/matador/utils/enum_mapper.hpp | 50 ++++++++++ src/CMakeLists.txt | 3 +- src/sql/object_binder.cpp | 21 +++- src/sql/query_result_impl.cpp | 5 +- src/sql/statement.cpp | 6 ++ src/sql/statement_cache.cpp | 10 +- src/sql/types.cpp | 83 ++++++++++++++++ test/StatementCacheTest.cpp | 21 ++-- test/TypeTraitsTest.cpp | 81 ++++++++++++++-- test/models/coordinate.hpp | 1 + 17 files changed, 378 insertions(+), 146 deletions(-) create mode 100644 include/matador/utils/enum_mapper.hpp diff --git a/include/matador/sql/object_binder.hpp b/include/matador/sql/object_binder.hpp index 55a9c6e..6a11ea1 100644 --- a/include/matador/sql/object_binder.hpp +++ b/include/matador/sql/object_binder.hpp @@ -2,7 +2,9 @@ #define QUERY_OBJECT_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/field_attributes.hpp" @@ -10,37 +12,31 @@ namespace matador::sql { -class object_binder +namespace detail { +class fk_binder { public: - explicit object_binder(parameter_binder &binder); + explicit fk_binder(parameter_binder &binder); - void reset(); - - template < class V > - void on_primary_key(const char *id, V &val, typename std::enable_if::value && !std::is_same::value>::type* = 0) + template + void bind(Type &obj, size_t column_index) { - binder_.bind(index_++, val); - } - void on_primary_key(const char *id, std::string &, size_t); - void on_revision(const char *id, unsigned long long &/*rev*/); - - template - void on_attribute(const char *id, Type &val, const utils::field_attributes &/*attr*/ = utils::null_attributes) - { - binder_.bind(index_++, val); + index_ = column_index; + utils::access::process(*this, obj); } - template class Pointer> - void on_belongs_to(const char *id, Pointer &x, utils::cascade_type) - { -// binder_.bind(index_++, val); - } - template class Pointer> - void on_has_one(const char *id, Pointer &x, utils::cascade_type) - { -// binder_.bind(index_++, val); - } + template + void on_primary_key(const char *id, ValueType &value, typename std::enable_if::value && !std::is_same::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 void on_has_many(const char *, ContainerType &, const char *, const char *, utils::cascade_type) {} template @@ -51,5 +47,58 @@ private: 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::value && !std::is_same::value>::type* = 0) + { + data_type_traits::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 + void on_attribute(const char *id, Type &val, const utils::field_attributes &/*attr*/ = utils::null_attributes) + { + data_type_traits::bind_value(binder_, index_++, val); + } + + template class Pointer> + void on_belongs_to(const char *id, Pointer &x, utils::cascade_type) + { + fk_binder_.bind(index_++, x); + } + template class Pointer> + void on_has_one(const char *id, Pointer &x, utils::cascade_type) + { + fk_binder_.bind(index_++, x); + } + template + void on_has_many(const char *, ContainerType &, const char *, const char *, utils::cascade_type) {} + template + 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 +void fk_binder::on_primary_key(const char *id, ValueType &value, typename std::enable_if::value && !std::is_same::value>::type *) +{ + data_type_traits::bind_value(binder_, index_++, value); +} + +} } #endif //QUERY_OBJECT_BINDER_HPP diff --git a/include/matador/sql/query_result_impl.hpp b/include/matador/sql/query_result_impl.hpp index 9f110a7..7314578 100644 --- a/include/matador/sql/query_result_impl.hpp +++ b/include/matador/sql/query_result_impl.hpp @@ -123,7 +123,7 @@ namespace detail { template void detail::pk_reader::on_primary_key(const char *id, ValueType &value, typename std::enable_if::value && !std::is_same::value>::type *) { - reader_.read_value(id, column_index_++, value); + data_type_traits::read_value(reader_, id, column_index_++, value); } } diff --git a/include/matador/sql/statement.hpp b/include/matador/sql/statement.hpp index 0a388ba..5ad2a42 100644 --- a/include/matador/sql/statement.hpp +++ b/include/matador/sql/statement.hpp @@ -23,6 +23,8 @@ public: return *this; } + statement& bind(size_t pos, const char *value); + statement& bind(size_t pos, std::string &val, size_t size); template < class Type > diff --git a/include/matador/sql/statement_cache.hpp b/include/matador/sql/statement_cache.hpp index f5f45a2..1cda0ba 100644 --- a/include/matador/sql/statement_cache.hpp +++ b/include/matador/sql/statement_cache.hpp @@ -14,14 +14,15 @@ class connection; struct cache_info { - std::unique_ptr statement_; + statement statement_; +// std::unique_ptr statement_; size_t connection_id_; }; class statement_cache { public: - statement& acquire(const std::string &stmt, const connection &conn); + statement& acquire(query_context &&context, const connection &conn); void release(const statement &stmt); private: diff --git a/include/matador/sql/statement_impl.hpp b/include/matador/sql/statement_impl.hpp index 3cb2a19..68881aa 100644 --- a/include/matador/sql/statement_impl.hpp +++ b/include/matador/sql/statement_impl.hpp @@ -4,6 +4,7 @@ #include "matador/sql/query_context.hpp" #include "matador/sql/query_result_impl.hpp" #include "matador/sql/parameter_binder.hpp" +#include "matador/sql/types.hpp" #include @@ -20,15 +21,20 @@ public: virtual size_t execute() = 0; virtual std::unique_ptr fetch() = 0; - template < class V > - void bind(size_t pos, V &val) + template < class Type > + void bind(size_t pos, Type &val) { - binder().bind(pos, val); + data_type_traits::bind_value(binder(), pos, val); + } + + void bind(size_t pos, const char *value, size_t size) + { + data_type_traits::bind_value(binder(), pos, value, size); } void bind(size_t pos, std::string &val, size_t size) { - binder().bind(pos, val, size); + data_type_traits::bind_value(binder(), pos, val, size); } virtual void reset() = 0; diff --git a/include/matador/sql/types.hpp b/include/matador/sql/types.hpp index 922c155..57924a4 100644 --- a/include/matador/sql/types.hpp +++ b/include/matador/sql/types.hpp @@ -1,12 +1,15 @@ #ifndef QUERY_TYPES_HPP #define QUERY_TYPES_HPP +#include "matador/sql/any_type.hpp" + #include #include namespace matador::sql { class query_result_reader; +class parameter_binder; /** * @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_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 { NONE, @@ -79,146 +62,130 @@ struct data_type_traits; /// @cond MATADOR_DEV template <> struct data_type_traits { -// 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; } static void read_value(query_result_reader &reader, const char *id, size_t index, char &value); -// inline static unsigned long size() { return sizeof(char); } -// inline static const char* name() { return "char"; } + static void bind_value(parameter_binder &binder, size_t index, char &value); + inline static any_type create_value(char &value) { return value; } }; template <> struct data_type_traits { -// 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; } static void read_value(query_result_reader &reader, const char *id, size_t index, short &value); -// inline static unsigned long size() { return sizeof(short); } -// inline static const char* name() { return "short"; } + static void bind_value(parameter_binder &binder, size_t index, short &value); + inline static any_type create_value(short &value) { return value; } }; template <> struct data_type_traits { -// 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; } static void read_value(query_result_reader &reader, const char *id, size_t index, int &value); -// inline static unsigned long size() { return sizeof(int); } -// inline static const char* name() { return "int"; } + static void bind_value(parameter_binder &binder, size_t index, int &value); + inline static any_type create_value(int &value) { return value; } }; template <> struct data_type_traits { -// 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; } static void read_value(query_result_reader &reader, const char *id, size_t index, long &value); -// inline static unsigned long size() { return sizeof(long); } -// inline static const char* name() { return "long"; } + static void bind_value(parameter_binder &binder, size_t index, long &value); + inline static any_type create_value(long &value) { return value; } }; template <> struct data_type_traits { -// 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; } 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); } -// inline static const char* name() { return "long long"; } + static void bind_value(parameter_binder &binder, size_t index, long long &value); + inline static any_type create_value(long long &value) { return value; } }; template <> struct data_type_traits { -// 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; } 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); } -// inline static const char* name() { return "unsigned char"; } + static void bind_value(parameter_binder &binder, size_t index, unsigned char &value); + inline static any_type create_value(unsigned char &value) { return value; } }; template <> struct data_type_traits { -// 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; } 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); } -// inline static const char* name() { return "unsigned short"; } + static void bind_value(parameter_binder &binder, size_t index, unsigned short &value); + inline static any_type create_value(unsigned short &value) { return value; } }; template <> struct data_type_traits { -// 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; } 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); } -// inline static const char* name() { return "unsigned int"; } + static void bind_value(parameter_binder &binder, size_t index, unsigned int &value); + inline static any_type create_value(unsigned int &value) { return value; } }; template <> struct data_type_traits { -// 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; } 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); } -// inline static const char* name() { return "unsigned long"; } + static void bind_value(parameter_binder &binder, size_t index, unsigned long &value); + inline static any_type create_value(unsigned long &value) { return value; } }; template <> struct data_type_traits { -// 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; } 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); } -// inline static const char* name() { return "unsigned long long"; } + static void bind_value(parameter_binder &binder, size_t index, unsigned long long &value); + inline static any_type create_value(unsigned long long &value) { return value; } }; template <> struct data_type_traits { -// 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; } static void read_value(query_result_reader &reader, const char *id, size_t index, bool &value); -// inline static unsigned long size() { return sizeof(bool); } -// inline static const char* name() { return "bool"; } + static void bind_value(parameter_binder &binder, size_t index, bool &value); + inline static any_type create_value(bool &value) { return value; } }; template <> struct data_type_traits { -// 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; } static void read_value(query_result_reader &reader, const char *id, size_t index, float &value); -// inline static unsigned long size() { return sizeof(float); } -// inline static const char* name() { return "float"; } + static void bind_value(parameter_binder &binder, size_t index, float &value); + inline static any_type create_value(float &value) { return value; } }; template <> struct data_type_traits { -// 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; } static void read_value(query_result_reader &reader, const char *id, size_t index, double &value); -// inline static unsigned long size() { return sizeof(double); } -// inline static const char* name() { return "double"; } + static void bind_value(parameter_binder &binder, size_t index, double &value); + inline static any_type create_value(double &value) { return value; } }; template <> struct data_type_traits { -// 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; } 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*); } -// inline static const char* name() { return "const char*"; } + static void bind_value(parameter_binder &binder, size_t index, const char *value, size_t size = 0); + inline static any_type create_value(const char *value) { return value; } }; template <> struct data_type_traits { -// 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; } 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*); } -// inline static const char* name() { return "char*"; } + static void bind_value(parameter_binder &binder, size_t index, char *value, size_t size = 0); + inline static any_type create_value(const char *value) { return value; } }; template <> struct data_type_traits { -// 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; } 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; } -// inline static const char* name() { return "std::string"; } + static void bind_value(parameter_binder &binder, size_t index, std::string &value, size_t size = 0); + inline static any_type create_value(std::string &value) { return value; } }; //template <> struct data_type_traits @@ -240,14 +207,16 @@ template <> struct data_type_traits template < typename EnumType > struct data_type_traits::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; } static void read_value(query_result_reader &reader, const char *id, size_t index, EnumType &value) { data_type_traits::read_value(reader, id, index, reinterpret_cast(value)); } -// inline static unsigned long size() { return sizeof(int); } -// inline static const char* name() { return "int"; } + static void bind_value(parameter_binder &binder, size_t index, EnumType &value) + { + data_type_traits::bind_value(binder, index, (int&)value); + } + inline static any_type create_value(EnumType &value) { return (int)value; } }; /// @endcond diff --git a/include/matador/sql/value_extractor.hpp b/include/matador/sql/value_extractor.hpp index 3efe1cc..6562c30 100644 --- a/include/matador/sql/value_extractor.hpp +++ b/include/matador/sql/value_extractor.hpp @@ -2,6 +2,7 @@ #define QUERY_VALUE_EXTRACTOR_HPP #include "matador/sql/fk_value_extractor.hpp" +#include "matador/sql/types.hpp" #include @@ -56,14 +57,9 @@ public: private: template - void append(Type &value, typename std::enable_if::value>::type* = 0) + void append(Type &value) { - values_.emplace_back(value); - } - template - void append(Type &value, typename std::enable_if::value>::type* = 0) - { - values_.emplace_back((int)value); + values_.emplace_back(data_type_traits::create_value(value)); } private: diff --git a/include/matador/utils/enum_mapper.hpp b/include/matador/utils/enum_mapper.hpp new file mode 100644 index 0000000..b370832 --- /dev/null +++ b/include/matador/utils/enum_mapper.hpp @@ -0,0 +1,50 @@ +#ifndef QUERY_ENUM_MAPPER_HPP +#define QUERY_ENUM_MAPPER_HPP + +#include +#include +#include + +namespace matador::utils { + +template < typename EnumType, class Enable = void > +class enum_mapper; + +template < typename EnumType> +class enum_mapper::value>::type> +{ +public: + using enum_to_string_map = std::unordered_map; + using string_to_enum_map = std::unordered_map; + + 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 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 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2a79995..7feb6f7 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -77,7 +77,8 @@ set(UTILS_HEADER ../include/matador/utils/access.hpp ../include/matador/utils/identifier.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 utils/field_attributes.cpp diff --git a/src/sql/object_binder.cpp b/src/sql/object_binder.cpp index 30aece5..b1549db 100644 --- a/src/sql/object_binder.cpp +++ b/src/sql/object_binder.cpp @@ -3,22 +3,35 @@ namespace matador::sql { -object_binder::object_binder(parameter_binder &binder) +namespace detail { + +fk_binder::fk_binder(parameter_binder &binder) : binder_(binder) {} +void fk_binder::on_primary_key(const char *id, std::string &value, size_t size) +{ + data_type_traits::bind_value(binder_, index_++, value); +} + +} + +object_binder::object_binder(parameter_binder &binder) +: binder_(binder) +, fk_binder_(binder) {} + void object_binder::reset() { 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::bind_value(binder_, index_++, val, size); } void object_binder::on_revision(const char *id, unsigned long long int &rev) { - binder_.bind(index_++, rev); + data_type_traits::bind_value(binder_, index_++, rev); } } \ No newline at end of file diff --git a/src/sql/query_result_impl.cpp b/src/sql/query_result_impl.cpp index 2a86023..1494c5b 100644 --- a/src/sql/query_result_impl.cpp +++ b/src/sql/query_result_impl.cpp @@ -6,8 +6,9 @@ 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); +void detail::pk_reader::on_primary_key(const char *id, std::string &value, size_t size) +{ + data_type_traits::read_value(reader_, id, column_index_++, value, size); } query_result_impl::query_result_impl(std::unique_ptr &&reader, record prototype) diff --git a/src/sql/statement.cpp b/src/sql/statement.cpp index 546b59d..9e251d4 100644 --- a/src/sql/statement.cpp +++ b/src/sql/statement.cpp @@ -8,6 +8,12 @@ statement::statement(std::unique_ptr impl, const utils::logger & , 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_->bind(pos, val, size); diff --git a/src/sql/statement_cache.cpp b/src/sql/statement_cache.cpp index 1a191e5..b249147 100644 --- a/src/sql/statement_cache.cpp +++ b/src/sql/statement_cache.cpp @@ -1,14 +1,16 @@ +#include "matador/sql/connection.hpp" #include "matador/sql/statement_cache.hpp" 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 guard(mutex_); - auto key = hash_(stmt); + auto key = hash_(context.sql); auto it = statement_map_.find(key); 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) { diff --git a/src/sql/types.cpp b/src/sql/types.cpp index 1f4246b..34d436c 100644 --- a/src/sql/types.cpp +++ b/src/sql/types.cpp @@ -1,5 +1,6 @@ #include "matador/sql/types.hpp" +#include "matador/sql/parameter_binder.hpp" #include "matador/sql/query_result_reader.hpp" namespace matador::sql { @@ -9,77 +10,159 @@ void data_type_traits::read_value(query_result_reader &reader, const char reader.read_value(id, index, value); } +void data_type_traits::bind_value(parameter_binder &binder, size_t index, char &value) +{ + binder.bind(index, value); +} + void data_type_traits::read_value(query_result_reader &reader, const char *id, size_t index, short &value) { reader.read_value(id, index, value); } +void data_type_traits::bind_value(parameter_binder &binder, size_t index, short &value) +{ + binder.bind(index, value); +} + void data_type_traits::read_value(query_result_reader &reader, const char *id, size_t index, int &value) { reader.read_value(id, index, value); } +void data_type_traits::bind_value(parameter_binder &binder, size_t index, int &value) +{ + binder.bind(index, value); +} + void data_type_traits::read_value(query_result_reader &reader, const char *id, size_t index, long &value) { reader.read_value(id, index, value); } +void data_type_traits::bind_value(parameter_binder &binder, size_t index, long &value) +{ + binder.bind(index, value); +} + void data_type_traits::read_value(query_result_reader &reader, const char *id, size_t index, long long &value) { reader.read_value(id, index, value); } +void data_type_traits::bind_value(parameter_binder &binder, size_t index, long long int &value) +{ + binder.bind(index, value); +} + void data_type_traits::read_value(query_result_reader &reader, const char *id, size_t index, unsigned char &value) { reader.read_value(id, index, value); } +void data_type_traits::bind_value(parameter_binder &binder, size_t index, unsigned char &value) +{ + binder.bind(index, value); +} + void data_type_traits::read_value(query_result_reader &reader, const char *id, size_t index, unsigned short &value) { reader.read_value(id, index, value); } +void data_type_traits::bind_value(parameter_binder &binder, size_t index, unsigned short &value) +{ + binder.bind(index, value); +} + void data_type_traits::read_value(query_result_reader &reader, const char *id, size_t index, unsigned int &value) { reader.read_value(id, index, value); } +void data_type_traits::bind_value(parameter_binder &binder, size_t index, unsigned int &value) +{ + binder.bind(index, value); +} + void data_type_traits::read_value(query_result_reader &reader, const char *id, size_t index, unsigned long &value) { reader.read_value(id, index, value); } +void data_type_traits::bind_value(parameter_binder &binder, size_t index, unsigned long &value) +{ + binder.bind(index, value); +} + void data_type_traits::read_value(query_result_reader &reader, const char *id, size_t index, unsigned long long &value) { reader.read_value(id, index, value); } +void data_type_traits::bind_value(parameter_binder &binder, size_t index, unsigned long long int &value) +{ + binder.bind(index, value); +} + void data_type_traits::read_value(query_result_reader &reader, const char *id, size_t index, bool &value) { reader.read_value(id, index, value); } + +void data_type_traits::bind_value(parameter_binder &binder, size_t index, bool &value) +{ + binder.bind(index, value); +} + void data_type_traits::read_value(query_result_reader &reader, const char *id, size_t index, float &value) { reader.read_value(id, index, value); } + +void data_type_traits::bind_value(parameter_binder &binder, size_t index, float &value) +{ + binder.bind(index, value); +} + void data_type_traits::read_value(query_result_reader &reader, const char *id, size_t index, double &value) { reader.read_value(id, index, value); } +void data_type_traits::bind_value(parameter_binder &binder, size_t index, double &value) +{ + binder.bind(index, value); +} + void data_type_traits::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(value), size); } +void data_type_traits::bind_value(parameter_binder &binder, size_t index, const char *value, size_t size) +{ + binder.bind(index, value, size); +} + void data_type_traits::read_value(query_result_reader &reader, const char *id, size_t index, char* value, size_t size) { reader.read_value(id, index, value, size); } +void data_type_traits::bind_value(parameter_binder &binder, size_t index, char *value, size_t size) +{ + binder.bind(index, value, size); +} + void data_type_traits::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); } +void data_type_traits::bind_value(parameter_binder &binder, size_t index, std::string &value, size_t size) +{ + binder.bind(index, value, size); +} + } \ No newline at end of file diff --git a/test/StatementCacheTest.cpp b/test/StatementCacheTest.cpp index 3c3cd4e..daeec46 100644 --- a/test/StatementCacheTest.cpp +++ b/test/StatementCacheTest.cpp @@ -7,25 +7,16 @@ 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]") { sql::statement_cache cache; - sql::connection_pool pool("sqlite://sqlite.db", 4); + sql::connection_pool pool("sqlite://sqlite.db", 4); -// sql::session s(pool); -// auto conn = pool.acquire(); + sql::session s(pool); + auto conn = pool.acquire(); std::string sql = R"(SELECT * FROM person WHERE name = 'george')"; -// auto stmt = cache.acquire(sql, conn); +// auto &stmt = cache.acquire(sql, *conn); + + } \ No newline at end of file diff --git a/test/TypeTraitsTest.cpp b/test/TypeTraitsTest.cpp index 24b8113..009dae5 100644 --- a/test/TypeTraitsTest.cpp +++ b/test/TypeTraitsTest.cpp @@ -4,6 +4,8 @@ #include "matador/sql/connection_pool.hpp" #include "matador/sql/session.hpp" +#include "matador/utils/enum_mapper.hpp" + #include "Databases.hpp" #include "models/location.hpp" @@ -19,13 +21,13 @@ class TypeTraitsTestFixture { public: TypeTraitsTestFixture() - : pool_(Type::dns, 4), session_(pool_) + : pool_(Type::dns, 4), session_(pool_) { auto res = session_.create() - .table("location") - .execute(); + .table("location") + .execute(); 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() @@ -41,19 +43,78 @@ private: matador::sql::session session_; }; +static const matador::utils::enum_mapper 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 +{ + inline static data_type_t builtin_type(std::size_t size) + { return data_type_traits::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) { auto &s = TypeTraitsTestFixture::session(); - location loc{1, "center", {1, 2, 3}, Color::Black}; + SECTION("Insert and select with direct execution") { + location loc{1, "center", {1, 2, 3}, Color::Black}; - auto res = s.insert().template into("location").values(loc).execute(); - REQUIRE(res.first == 1); + auto res = s.insert().template into("location").values(loc).execute(); + REQUIRE(res.first == 1); - auto result = s.template select().from("location").template fetch_all(); + auto result = s.template select().from("location"). + template fetch_all(); - for (const auto &l : result) { - REQUIRE(l.name == "center"); + for (const auto &l: result) { + 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").template values().prepare(); + auto res = stmt.bind(loc).execute(); + REQUIRE(res == 1); + + auto result = s.template select().from("location"). + template fetch_all(); + + for (const auto &l: result) { + REQUIRE(l.name == "center"); + } + } } \ No newline at end of file diff --git a/test/models/coordinate.hpp b/test/models/coordinate.hpp index f6d63da..f5d06b6 100644 --- a/test/models/coordinate.hpp +++ b/test/models/coordinate.hpp @@ -23,4 +23,5 @@ void attribute(Operator &op, const char *id, test::coordinate &value, const fiel } } + #endif //QUERY_COORDINATE_HPP