diff options
-rw-r--r-- | libdbpp/command.h | 55 | ||||
-rw-r--r-- | libdbpp/unittests/testUtils.cpp | 48 |
2 files changed, 103 insertions, 0 deletions
diff --git a/libdbpp/command.h b/libdbpp/command.h index 6f66559..09377a9 100644 --- a/libdbpp/command.h +++ b/libdbpp/command.h @@ -103,6 +103,61 @@ namespace DB { /// The SQL statement. const std::string sql; + /// Bind a parameter by type based on C++ traits to parameter i. + template<typename O> + inline auto bindParam(unsigned int i, const O & o) + { + if constexpr (std::is_null_pointer<O>::value) { + bindNull(i); + } + else if constexpr (std::is_same<O, std::nullopt_t>::value) { + bindNull(i); + } + else if constexpr (std::is_same<O, bool>::value) { + bindParamB(i, o); + } + else if constexpr (std::is_floating_point<O>::value) { + bindParamF(i, o); + } + else if constexpr (std::is_same<O, boost::posix_time::time_duration>::value) { + bindParamT(i, o); + } + else if constexpr (std::is_same<O, boost::posix_time::ptime>::value) { + bindParamT(i, o); + } + else if constexpr (std::is_same<O, Blob>::value) { + bindParamBLOB(i, o); + } + else if constexpr (std::is_integral<O>::value && !std::is_pointer<O>::value) { + bindParamI(i, o); + } + else if constexpr (std::is_convertible<O, std::string_view>::value && std::is_pointer<O>::value) { + if (o) { + bindParamS(i, o); + } + else { + bindNull(i); + } + } + else if constexpr (std::is_same<O, Glib::ustring>::value) { + bindParamS(i, o); + } + else if constexpr (std::is_convertible<O, std::string_view>::value) { + bindParamS(i, o); + } + else if constexpr (std::is_constructible<bool, const O &>::value) { + if (o) { + bindParam(i, *o); + } + else { + bindNull(i); + } + } + else { + static_assert(!&o, "No suitable trait"); + } + } + #define OPTWRAPPER(func) \ template<typename O> \ inline auto \ diff --git a/libdbpp/unittests/testUtils.cpp b/libdbpp/unittests/testUtils.cpp index 0e90a94..67c1751 100644 --- a/libdbpp/unittests/testUtils.cpp +++ b/libdbpp/unittests/testUtils.cpp @@ -302,6 +302,54 @@ BOOST_AUTO_TEST_CASE( bindIntPtr ) BOOST_REQUIRE_EQUAL(159, total); } +BOOST_FIXTURE_TEST_CASE( traits_bind, DB::TestCore ) +{ + auto db = DB::ConnectionPtr(DB::MockDatabase::openConnectionTo("pqmock")); + auto cmd = db->select("select x is null, format('%s', x) from (select ? x) d"); + auto check = [cmd](int line, const auto & v, bool isNull, const auto & strval) { + BOOST_TEST_CONTEXT("line " << line) { + cmd->bindParam(0, v); + for (const auto & [null, str] : cmd->as<bool, std::string_view>()) { + BOOST_CHECK_EQUAL(null, isNull); + BOOST_CHECK_EQUAL(str, strval); + } + } + }; + check(__LINE__, std::nullopt, true, ""); + check(__LINE__, nullptr, true, ""); + check(__LINE__, testInt, false, "43"); + check(__LINE__, std::make_unique<short>(testInt), false, "43"); + check(__LINE__, std::unique_ptr<short>(), true, ""); + check(__LINE__, (unsigned int)testInt, false, "43"); + check(__LINE__, &testInt, false, "43"); + check(__LINE__, testDouble, false, "3.14"); + check(__LINE__, std::make_shared<float>(testDouble), false, "3.14"); + check(__LINE__, std::shared_ptr<float>(), true, ""); + check(__LINE__, (float)testDouble, false, "3.14"); + check(__LINE__, &testDouble, false, "3.14"); + check(__LINE__, testString, false, testString); + check(__LINE__, &testString, false, testString); + check(__LINE__, "str", false, "str"); + check(__LINE__, "", false, ""); + const char * const nullstr = nullptr; + check(__LINE__, nullstr, true, ""); + const char * const str = "str"; + check(__LINE__, str, false, "str"); + check(__LINE__, std::string(), false, ""); + check(__LINE__, std::string_view(), false, ""); + check(__LINE__, Glib::ustring(), false, ""); + check(__LINE__, Glib::ustring("foo"), false, "foo"); + check(__LINE__, testDateTime, false, "2015-05-02T01:36:33"); + check(__LINE__, testInterval, false, "01:02:03"); + check(__LINE__, &testInterval, false, "01:02:03"); + decltype(testInterval) * nullInterval = nullptr; + check(__LINE__, nullInterval, true, ""); + check(__LINE__, true, false, "1"); + check(__LINE__, false, false, "0"); + check(__LINE__, std::optional<int>(4), false, "4"); + check(__LINE__, std::optional<int>(), true, ""); +} + BOOST_AUTO_TEST_CASE( testBlobRaw ) { DB::Blob ptr(this, 1); |