summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Goodliffe <dan@randomdan.homeip.net>2015-11-07 23:56:14 +0000
committerDan Goodliffe <dan@randomdan.homeip.net>2015-11-07 23:56:14 +0000
commit45c23ec13e3a7322cb446207e6994ae0d932bb94 (patch)
tree3eb29c0fe803d67dcfac8e830b8fe0e07dbed6bf
parentAdd typedefs for commands and connection smart pointers (diff)
downloadlibdbpp-45c23ec13e3a7322cb446207e6994ae0d932bb94.tar.bz2
libdbpp-45c23ec13e3a7322cb446207e6994ae0d932bb94.tar.xz
libdbpp-45c23ec13e3a7322cb446207e6994ae0d932bb94.zip
Add utility function for passing each row of a result set to a function accepting one parameter per column
-rw-r--r--libdbpp/selectcommand.h4
-rw-r--r--libdbpp/selectcommandUtil.impl.h35
-rw-r--r--libdbpp/unittests/Jamfile.jam14
-rw-r--r--libdbpp/unittests/testUtils.cpp37
-rw-r--r--libdbpp/unittests/util.sql8
5 files changed, 98 insertions, 0 deletions
diff --git a/libdbpp/selectcommand.h b/libdbpp/selectcommand.h
index 31ef9ca..1586357 100644
--- a/libdbpp/selectcommand.h
+++ b/libdbpp/selectcommand.h
@@ -7,6 +7,7 @@
#include <boost/multi_index/indexed_by.hpp>
#include <boost/multi_index/ordered_index_fwd.hpp>
#include <boost/multi_index/member.hpp>
+#include <boost/function/function_fwd.hpp>
#include <boost/shared_ptr.hpp>
#include <visibility.h>
@@ -31,6 +32,9 @@ namespace DB {
unsigned int columnCount() const;
/// Get the index of a column by name.
unsigned int getOrdinal(const Glib::ustring &) const;
+ /// Push each row through a function accepting one value per column
+ template<typename ... Fn, typename Func = boost::function<void(Fn...)>>
+ void forEachRow(const Func & func);
protected:
/// Helper function so clients need not know about boost::multi_index_container.
diff --git a/libdbpp/selectcommandUtil.impl.h b/libdbpp/selectcommandUtil.impl.h
new file mode 100644
index 0000000..26ff1b7
--- /dev/null
+++ b/libdbpp/selectcommandUtil.impl.h
@@ -0,0 +1,35 @@
+#ifndef DB_SELECTCOMMANDUTIL_IMPL_H
+#define DB_SELECTCOMMANDUTIL_IMPL_H
+
+#include "selectcommand.h"
+#include <boost/function.hpp>
+#include <boost/utility/enable_if.hpp>
+
+namespace DB {
+ template<typename Fields, typename Func, unsigned int field, typename ... Fn>
+ inline typename boost::disable_if_c<field < std::tuple_size<Fields>::value>::type
+ forEachField(DB::SelectCommand *, const Func & func, const Fn & ... args)
+ {
+ func(args...);
+ }
+
+ template<typename Fields, typename Func, unsigned int field, typename ... Fn, typename ... Args>
+ inline typename boost::enable_if_c<field < std::tuple_size<Fields>::value>::type
+ forEachField(DB::SelectCommand * sel, const Func & func, const Args & ... args)
+ {
+ typename std::tuple_element<field, Fields>::type a;
+ (*sel)[field] >> a;
+ forEachField<Fields, Func, field + 1, Fn...>(sel, func, args..., a);
+ }
+
+ template<typename ... Fn, typename Func>
+ inline void SelectCommand::forEachRow(const Func & func)
+ {
+ while (fetch()) {
+ forEachField<std::tuple<Fn...>, Func, 0>(this, func);
+ }
+ }
+}
+
+#endif
+
diff --git a/libdbpp/unittests/Jamfile.jam b/libdbpp/unittests/Jamfile.jam
index 0739af1..ad90ec6 100644
--- a/libdbpp/unittests/Jamfile.jam
+++ b/libdbpp/unittests/Jamfile.jam
@@ -17,3 +17,17 @@ run
testConnection
;
+run
+ testUtils.cpp
+ : : :
+ <define>ROOT=\"$(me)\"
+ <define>BOOST_TEST_DYN_LINK
+ <library>..//dbppcore
+ <library>..//adhocutil
+ <library>../../libpqpp//dbpp-postgresql
+ <library>boost_utf
+ <dependency>util.sql
+ :
+ testUtils
+ ;
+
diff --git a/libdbpp/unittests/testUtils.cpp b/libdbpp/unittests/testUtils.cpp
new file mode 100644
index 0000000..79506cf
--- /dev/null
+++ b/libdbpp/unittests/testUtils.cpp
@@ -0,0 +1,37 @@
+#define BOOST_TEST_MODULE DbUtil
+#include <boost/test/unit_test.hpp>
+
+#include <factory.h>
+#include <connection.h>
+#include <selectcommand.h>
+#include <selectcommandUtil.impl.h>
+#include <definedDirs.h>
+#include <fstream>
+#include <vector>
+#include <mock.h>
+#include <boost/date_time/posix_time/posix_time_io.hpp>
+
+class StandardMockDatabase : public PQ::Mock {
+ public:
+ StandardMockDatabase() : PQ::Mock("user=postgres dbname=postgres", "pqmock", {
+ rootDir / "util.sql" })
+ {
+ }
+};
+
+BOOST_GLOBAL_FIXTURE( StandardMockDatabase );
+
+BOOST_AUTO_TEST_CASE( forEachRow )
+{
+ auto db = DB::ConnectionPtr(DB::MockDatabase::openConnectionTo("pqmock"));
+ auto sel = DB::SelectCommandPtr(db->newSelectCommand("SELECT a, b, c, d, e FROM forEachRow ORDER BY a LIMIT 1"));
+ sel->forEachRow<int64_t, double, std::string, boost::posix_time::ptime, boost::posix_time::time_duration>(
+ [](auto a, auto b, auto c, auto d, auto e) {
+ BOOST_REQUIRE_EQUAL(1, a);
+ BOOST_REQUIRE_EQUAL(2.3, b);
+ BOOST_REQUIRE_EQUAL("Some text", c);
+ BOOST_REQUIRE_EQUAL(boost::posix_time::ptime_from_tm({ 17, 39, 13, 7, 10, 115, 0, 0, 0, 0, 0}), d);
+ BOOST_REQUIRE_EQUAL(boost::posix_time::time_duration(4, 3, 2), e);
+ });
+}
+
diff --git a/libdbpp/unittests/util.sql b/libdbpp/unittests/util.sql
new file mode 100644
index 0000000..a3c5ac8
--- /dev/null
+++ b/libdbpp/unittests/util.sql
@@ -0,0 +1,8 @@
+CREATE TABLE foreachrow (
+ a int,
+ b numeric(4,2),
+ c text,
+ d timestamp without time zone,
+ e interval);
+INSERT INTO foreachrow(a, b, c, d, e) VALUES(1, 2.3, 'Some text', '2015-11-07 13:39:17', '04:03:02');
+