diff options
-rw-r--r-- | lib/dbTypes.h | 74 | ||||
-rw-r--r-- | lib/input/mysqlConn.cpp | 1 | ||||
-rw-r--r-- | lib/input/mysqlConn.h | 4 | ||||
-rw-r--r-- | lib/input/mysqlStmt.h | 4 | ||||
-rw-r--r-- | lib/output/dumpToConsole.cpp | 1 | ||||
-rw-r--r-- | lib/output/pq/pqConn.cpp | 1 | ||||
-rw-r--r-- | lib/output/pq/pqConn.h | 4 | ||||
-rw-r--r-- | lib/output/pq/pqStmt.h | 4 | ||||
-rw-r--r-- | test/test-misc.cpp | 78 |
9 files changed, 164 insertions, 7 deletions
diff --git a/lib/dbTypes.h b/lib/dbTypes.h index 068d642..332b896 100644 --- a/lib/dbTypes.h +++ b/lib/dbTypes.h @@ -2,6 +2,7 @@ #define MYGRATE_DBTYPES_H #include "bitset.h" +#include <boost/numeric/conversion/cast.hpp> #include <cstdint> #include <span> #include <string_view> @@ -36,6 +37,60 @@ namespace MyGrate { using DbValueV = std::variant<std::nullptr_t, double, float, int8_t, uint8_t, int16_t, uint16_t, int32_t, uint32_t, int64_t, uint64_t, timespec, Date, Time, DateTime, std::string_view, BitSet, Blob>; + namespace detail { + template<typename I> + concept HasToString = requires + { + std::to_string(I {}); + }; + + template<typename T> struct is_false { + static constexpr bool value {false}; + }; + + template<typename R, template<typename> typename ConceptT> struct SafeExtract { + R + operator()(const R & i) const + { + return i; + } + + template<typename I> + R + operator()(const I & i) const + { + if constexpr (ConceptT<I>::value) { + return boost::numeric_cast<R>(i); + } + else { + throw std::logic_error("Unreasonable conversion requested"); + } + } + }; + + struct ToString { + std::string + operator()(const std::string_view & i) const + { + return std::string {i}; + } + + template<HasToString I> + std::string + operator()(const I & i) const + { + return std::to_string(i); + } + + template<typename I> + std::string + operator()(const I &) const + { + throw std::logic_error("Unreasonable to_string requested"); + } + }; + } + class DbValue : public DbValueV { public: using DbValueV::DbValueV; @@ -54,6 +109,25 @@ namespace MyGrate { { return std::get<T>(static_cast<const DbValueV &>(*this)); } + + template<typename R> operator R() const + { + if constexpr (std::is_integral_v<R>) { + return visit(detail::SafeExtract<R, std::is_integral> {}); + } + else if constexpr (std::is_floating_point_v<R>) { + return visit(detail::SafeExtract<R, std::is_floating_point> {}); + } + else if constexpr (std::is_same_v<std::string_view, R>) { + return get<std::string_view>(); + } + else if constexpr (std::is_same_v<std::string, R>) { + return visit(detail::ToString {}); + } + else { + static_assert(detail::is_false<R>::value, "Cannot extract one of these"); + } + } }; } diff --git a/lib/input/mysqlConn.cpp b/lib/input/mysqlConn.cpp index 46ed7c6..4899deb 100644 --- a/lib/input/mysqlConn.cpp +++ b/lib/input/mysqlConn.cpp @@ -4,7 +4,6 @@ #include <cstddef> #include <cstring> #include <dbConn.h> -#include <dbTypes.h> #include <helpers.h> #include <memory> #include <mysql.h> diff --git a/lib/input/mysqlConn.h b/lib/input/mysqlConn.h index 29a34db..db30ff0 100644 --- a/lib/input/mysqlConn.h +++ b/lib/input/mysqlConn.h @@ -3,10 +3,12 @@ #include <cstddef> #include <dbConn.h> -#include <dbTypes.h> #include <initializer_list> #include <mysql.h> +namespace MyGrate { + class DbValue; +} namespace MyGrate::Input { class MySQLConn : public MYSQL, public DbConn { public: diff --git a/lib/input/mysqlStmt.h b/lib/input/mysqlStmt.h index a42e0db..69e62d4 100644 --- a/lib/input/mysqlStmt.h +++ b/lib/input/mysqlStmt.h @@ -3,12 +3,14 @@ #include "dbConn.h" #include "dbRecordSet.h" -#include "dbTypes.h" #include <cstddef> #include <initializer_list> #include <memory> #include <mysql.h> +namespace MyGrate { + class DbValue; +} namespace MyGrate::Input { using StmtPtr = std::unique_ptr<MYSQL_STMT, decltype(&mysql_stmt_close)>; diff --git a/lib/output/dumpToConsole.cpp b/lib/output/dumpToConsole.cpp index 96850f3..949c16f 100644 --- a/lib/output/dumpToConsole.cpp +++ b/lib/output/dumpToConsole.cpp @@ -10,7 +10,6 @@ #include <row.h> #include <streamSupport.h> #include <utility> -#include <variant> namespace MyGrate::Output { void diff --git a/lib/output/pq/pqConn.cpp b/lib/output/pq/pqConn.cpp index 81d9610..b3a6ca6 100644 --- a/lib/output/pq/pqConn.cpp +++ b/lib/output/pq/pqConn.cpp @@ -2,7 +2,6 @@ #include "pqBindings.h" #include "pqStmt.h" #include <dbConn.h> -#include <dbTypes.h> #include <helpers.h> #include <libpq-fe.h> #include <memory> diff --git a/lib/output/pq/pqConn.h b/lib/output/pq/pqConn.h index ae5fc9a..5c9effb 100644 --- a/lib/output/pq/pqConn.h +++ b/lib/output/pq/pqConn.h @@ -3,7 +3,6 @@ #include <cstddef> #include <dbConn.h> -#include <dbTypes.h> #include <functional> #include <initializer_list> #include <libpq-fe.h> @@ -11,6 +10,9 @@ #include <memory> #include <string> +namespace MyGrate { + class DbValue; +} namespace MyGrate::Output::Pq { class PqConn : public DbConn { public: diff --git a/lib/output/pq/pqStmt.h b/lib/output/pq/pqStmt.h index b806617..6531180 100644 --- a/lib/output/pq/pqStmt.h +++ b/lib/output/pq/pqStmt.h @@ -3,13 +3,15 @@ #include "dbConn.h" #include "dbRecordSet.h" -#include "dbTypes.h" #include <cstddef> #include <initializer_list> #include <libpq-fe.h> #include <memory> #include <string> +namespace MyGrate { + class DbValue; +} namespace MyGrate::Output::Pq { class PqConn; diff --git a/test/test-misc.cpp b/test/test-misc.cpp index cc9154a..3f45927 100644 --- a/test/test-misc.cpp +++ b/test/test-misc.cpp @@ -1,8 +1,22 @@ #define BOOST_TEST_MODULE BitSet #include <boost/test/unit_test.hpp> +#include <cstddef> +#include <cstdint> +#include <dbTypes.h> #include <helpers.h> #include <stdexcept> +#include <string> +#include <string_view> +#include <tuple> +#include <variant> +namespace MyGrate { + class BitSet; +} +namespace boost::numeric { + class bad_numeric_cast; +} +struct timespec; BOOST_AUTO_TEST_CASE(verify) { @@ -10,3 +24,67 @@ BOOST_AUTO_TEST_CASE(verify) BOOST_CHECK_THROW(MyGrate::verify<std::runtime_error>(false, "throw re"), std::runtime_error); BOOST_CHECK_THROW(MyGrate::verify<std::logic_error>(false, "throw le"), std::logic_error); } + +using Ints = std::tuple<int8_t, uint8_t, int16_t, uint16_t, int32_t, uint32_t, int64_t, uint64_t>; +using Floats = std::tuple<float, double>; +using Times = std::tuple<timespec, MyGrate::Date, MyGrate::Time, MyGrate::DateTime>; +using Str = std::tuple<std::string_view>; +using Others = std::tuple<std::nullptr_t, MyGrate::BitSet, MyGrate::Blob>; +using TinyInts = std::tuple<int8_t, uint8_t>; +using SmallInts = std::tuple<int8_t, uint8_t, int16_t, uint16_t>; + +BOOST_AUTO_TEST_CASE_TEMPLATE(DbValueConvIntToInts, I, Ints) +{ + MyGrate::DbValue v {123}; + I out {v}; + BOOST_CHECK_EQUAL(123, out); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(DbValueConvIntToTinyInts, I, TinyInts) +{ + MyGrate::DbValue v {1234}; + BOOST_CHECK_THROW([[maybe_unused]] I out {v}, boost::bad_numeric_cast); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(DbValueConvIntToSmallInts, I, SmallInts) +{ + MyGrate::DbValue v {123400}; + BOOST_CHECK_THROW([[maybe_unused]] I out {v}, boost::bad_numeric_cast); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(DbValueConvIntToFloats, F, Floats) +{ + MyGrate::DbValue v {123400}; + BOOST_CHECK_THROW([[maybe_unused]] F out {v}, std::logic_error); +} + +BOOST_AUTO_TEST_CASE(DbValueConvIntToStringView) +{ + MyGrate::DbValue v {123}; + BOOST_CHECK_THROW([[maybe_unused]] std::string_view out {v}, std::bad_variant_access); +} + +BOOST_AUTO_TEST_CASE(DbValueConvStrViewToStringView) +{ + using namespace std::literals; + MyGrate::DbValue v {"str"}; + BOOST_CHECK_EQUAL((std::string_view)v, "str"sv); + BOOST_CHECK_EQUAL((std::string)v, "str"s); +} + +static_assert(MyGrate::detail::HasToString<int>); +static_assert(!MyGrate::detail::HasToString<MyGrate::Date>); + +BOOST_AUTO_TEST_CASE_TEMPLATE(DbValueConvIntToString, I, Ints) +{ + using namespace std::literals; + MyGrate::DbValue v {I {123}}; + BOOST_CHECK_EQUAL((std::string)v, "123"s); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(DbValueConvFloatToString, F, Floats) +{ + using namespace std::literals; + MyGrate::DbValue v {F {123}}; + BOOST_CHECK_EQUAL((std::string)v, "123.000000"s); +} |