summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/dbTypes.h74
-rw-r--r--lib/input/mysqlConn.cpp1
-rw-r--r--lib/input/mysqlConn.h4
-rw-r--r--lib/input/mysqlStmt.h4
-rw-r--r--lib/output/dumpToConsole.cpp1
-rw-r--r--lib/output/pq/pqConn.cpp1
-rw-r--r--lib/output/pq/pqConn.h4
-rw-r--r--lib/output/pq/pqStmt.h4
-rw-r--r--test/test-misc.cpp78
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);
+}