summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Goodliffe <dan@randomdan.homeip.net>2016-06-17 01:41:21 +0100
committerDan Goodliffe <dan@randomdan.homeip.net>2016-06-17 01:41:21 +0100
commit3c9ae28cf54f02c41310ad40a7085be0209e733a (patch)
tree66145b9b22ca2efe2b370cddbdc9503dec274612
parentAdd doxygen exclude markers (diff)
downloadlibdbpp-3c9ae28cf54f02c41310ad40a7085be0209e733a.tar.bz2
libdbpp-3c9ae28cf54f02c41310ad40a7085be0209e733a.tar.xz
libdbpp-3c9ae28cf54f02c41310ad40a7085be0209e733a.zip
Add RowRange and supporting classes for use with for loop over a selected rowset
-rw-r--r--libdbpp/selectcommand.cpp17
-rw-r--r--libdbpp/selectcommand.h55
-rw-r--r--libdbpp/selectcommandUtil.impl.h69
-rw-r--r--libdbpp/unittests/testUtils.cpp20
4 files changed, 161 insertions, 0 deletions
diff --git a/libdbpp/selectcommand.cpp b/libdbpp/selectcommand.cpp
index 7106fb6..6f36aa5 100644
--- a/libdbpp/selectcommand.cpp
+++ b/libdbpp/selectcommand.cpp
@@ -71,3 +71,20 @@ DB::SelectCommand::insertColumn(ColumnPtr col)
return *columns->insert(col).first;
}
+DB::RowBase::RowBase(SelectCommand * s) :
+ sel(s)
+{
+}
+
+const DB::Column&
+DB::RowBase::operator[](const Glib::ustring & n) const
+{
+ return sel->operator[](n);
+}
+
+const DB::Column&
+DB::RowBase::operator[](unsigned int col) const
+{
+ return sel->operator[](col);
+}
+
diff --git a/libdbpp/selectcommand.h b/libdbpp/selectcommand.h
index c29084a..5e48f4d 100644
--- a/libdbpp/selectcommand.h
+++ b/libdbpp/selectcommand.h
@@ -16,6 +16,58 @@
namespace DB {
class Column;
+ class SelectCommand;
+
+ /// @cond
+ class DLL_PUBLIC RowBase {
+ public:
+ RowBase(SelectCommand *);
+
+ /// Get a column reference by index.
+ const Column & operator[](unsigned int col) const;
+ /// Get a column reference by name.
+ const Column & operator[](const Glib::ustring &) const;
+
+ protected:
+ SelectCommand * sel;
+ };
+
+ template<typename ... Fn>
+ class Row : public RowBase {
+ public:
+ Row(SelectCommand *);
+
+ /// Get value of column C in current row.
+ template<unsigned int C>
+ typename std::tuple_element<C, std::tuple<Fn...>>::type value() const;
+ };
+
+ template<typename ... Fn>
+ class RowRangeIterator {
+ public:
+ RowRangeIterator(SelectCommand *);
+
+ bool operator!=(const RowRangeIterator &) const;
+ void operator++();
+ Row<Fn...> operator*() const;
+
+ private:
+ SelectCommand * sel;
+ bool validRow;
+ };
+
+ template<typename ... Fn>
+ class RowRange {
+ public:
+ RowRange(SelectCommand *);
+
+ RowRangeIterator<Fn...> begin() const;
+ RowRangeIterator<Fn...> end() const;
+
+ private:
+ SelectCommand * sel;
+ };
+ /// @endcond
/// Exception thrown when the requested column is outside the range of the result set.
class DLL_PUBLIC ColumnIndexOutOfRange : public AdHoc::Exception<Error> {
@@ -67,6 +119,9 @@ namespace DB {
/// 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);
+ /// Support for a C++ row range for
+ template<typename ... Fn>
+ RowRange<Fn...> as();
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
index 26e9635..4c0e035 100644
--- a/libdbpp/selectcommandUtil.impl.h
+++ b/libdbpp/selectcommandUtil.impl.h
@@ -30,6 +30,75 @@ namespace DB {
forEachField<std::tuple<Fn...>, Func, 0>(this, func);
}
}
+
+ template<typename ... Fn>
+ inline RowRange<Fn...> SelectCommand::as()
+ {
+ return RowRange<Fn...>(this);
+ }
+
+ template<typename ... Fn>
+ inline RowRange<Fn...>::RowRange(SelectCommand * s) :
+ sel(s)
+ {
+ }
+
+ template<typename ... Fn>
+ inline RowRangeIterator<Fn...> RowRange<Fn...>::begin() const
+ {
+ return RowRangeIterator<Fn...>(sel);
+ }
+
+ template<typename ... Fn>
+ inline RowRangeIterator<Fn...> RowRange<Fn...>::end() const
+ {
+ return RowRangeIterator<Fn...>(nullptr);
+ }
+
+ template<typename ... Fn>
+ inline RowRangeIterator<Fn...>::RowRangeIterator(SelectCommand * s) :
+ sel(s)
+ {
+ if (sel) {
+ validRow = sel->fetch();
+ }
+ else {
+ validRow = false;
+ }
+ }
+
+ template<typename ... Fn>
+ inline bool RowRangeIterator<Fn...>::operator!=(const RowRangeIterator &) const
+ {
+ return validRow;
+ }
+
+ template<typename ... Fn>
+ inline void RowRangeIterator<Fn...>::operator++()
+ {
+ validRow = sel->fetch();
+ }
+
+ template<typename ... Fn>
+ inline Row<Fn...> RowRangeIterator<Fn...>::operator*() const
+ {
+ return Row<Fn...>(sel);
+ }
+
+ template<typename ... Fn>
+ inline Row<Fn...>::Row(SelectCommand * s) :
+ RowBase(s)
+ {
+ }
+
+ template<typename ... Fn>
+ template<unsigned int C>
+ inline typename std::tuple_element<C, std::tuple<Fn...>>::type Row<Fn...>::value() const
+ {
+ typename std::tuple_element<C, std::tuple<Fn...>>::type a;
+ sel->operator[](C) >> a;
+ return a;
+ }
}
/// @endcond
diff --git a/libdbpp/unittests/testUtils.cpp b/libdbpp/unittests/testUtils.cpp
index 4c269e9..ac9b7c1 100644
--- a/libdbpp/unittests/testUtils.cpp
+++ b/libdbpp/unittests/testUtils.cpp
@@ -50,6 +50,26 @@ BOOST_AUTO_TEST_CASE( forEachRowNulls )
});
}
+BOOST_AUTO_TEST_CASE( stdforOverRows )
+{
+ auto db = DB::ConnectionPtr(DB::MockDatabase::openConnectionTo("pqmock"));
+ unsigned int count = 0;
+ int64_t totalOfa = 0;
+ std::string totalOfc;
+ auto sel = db->select("SELECT a, c FROM forEachRow ORDER BY a DESC");
+ for (const auto & row : sel->as<int64_t, std::string>()) {
+ count += 1;
+ BOOST_REQUIRE_EQUAL("a", row[0].name);
+ BOOST_REQUIRE_EQUAL(1, row["c"].colNo);
+ int64_t a = row.value<0>();
+ totalOfa += a;
+ totalOfc += row.value<1>();
+ }
+ BOOST_REQUIRE_EQUAL(count, 2);
+ BOOST_REQUIRE_EQUAL(totalOfa, 3);
+ BOOST_REQUIRE_EQUAL(totalOfc, "Some textSome text");
+}
+
BOOST_AUTO_TEST_CASE( execute )
{
auto db = DB::ConnectionPtr(DB::MockDatabase::openConnectionTo("pqmock"));