From 20f3972ce08dd71cf309ad34e6a8d00dbdc69209 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Mon, 18 Feb 2019 20:39:31 +0000 Subject: Add traits based generic bindParam function --- libdbpp/command.h | 55 +++++++++++++++++++++++++++++++++++++++++ libdbpp/unittests/testUtils.cpp | 48 +++++++++++++++++++++++++++++++++++ 2 files changed, 103 insertions(+) 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 + inline auto bindParam(unsigned int i, const O & o) + { + if constexpr (std::is_null_pointer::value) { + bindNull(i); + } + else if constexpr (std::is_same::value) { + bindNull(i); + } + else if constexpr (std::is_same::value) { + bindParamB(i, o); + } + else if constexpr (std::is_floating_point::value) { + bindParamF(i, o); + } + else if constexpr (std::is_same::value) { + bindParamT(i, o); + } + else if constexpr (std::is_same::value) { + bindParamT(i, o); + } + else if constexpr (std::is_same::value) { + bindParamBLOB(i, o); + } + else if constexpr (std::is_integral::value && !std::is_pointer::value) { + bindParamI(i, o); + } + else if constexpr (std::is_convertible::value && std::is_pointer::value) { + if (o) { + bindParamS(i, o); + } + else { + bindNull(i); + } + } + else if constexpr (std::is_same::value) { + bindParamS(i, o); + } + else if constexpr (std::is_convertible::value) { + bindParamS(i, o); + } + else if constexpr (std::is_constructible::value) { + if (o) { + bindParam(i, *o); + } + else { + bindNull(i); + } + } + else { + static_assert(!&o, "No suitable trait"); + } + } + #define OPTWRAPPER(func) \ template \ 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()) { + 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(testInt), false, "43"); + check(__LINE__, std::unique_ptr(), true, ""); + check(__LINE__, (unsigned int)testInt, false, "43"); + check(__LINE__, &testInt, false, "43"); + check(__LINE__, testDouble, false, "3.14"); + check(__LINE__, std::make_shared(testDouble), false, "3.14"); + check(__LINE__, std::shared_ptr(), 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(4), false, "4"); + check(__LINE__, std::optional(), true, ""); +} + BOOST_AUTO_TEST_CASE( testBlobRaw ) { DB::Blob ptr(this, 1); -- cgit v1.2.3