From 3c9ae28cf54f02c41310ad40a7085be0209e733a Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Fri, 17 Jun 2016 01:41:21 +0100 Subject: Add RowRange and supporting classes for use with for loop over a selected rowset --- libdbpp/selectcommand.cpp | 17 ++++++++++ libdbpp/selectcommand.h | 55 ++++++++++++++++++++++++++++++++ libdbpp/selectcommandUtil.impl.h | 69 ++++++++++++++++++++++++++++++++++++++++ libdbpp/unittests/testUtils.cpp | 20 ++++++++++++ 4 files changed, 161 insertions(+) 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 + class Row : public RowBase { + public: + Row(SelectCommand *); + + /// Get value of column C in current row. + template + typename std::tuple_element>::type value() const; + }; + + template + class RowRangeIterator { + public: + RowRangeIterator(SelectCommand *); + + bool operator!=(const RowRangeIterator &) const; + void operator++(); + Row operator*() const; + + private: + SelectCommand * sel; + bool validRow; + }; + + template + class RowRange { + public: + RowRange(SelectCommand *); + + RowRangeIterator begin() const; + RowRangeIterator 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 { @@ -67,6 +119,9 @@ namespace DB { /// Push each row through a function accepting one value per column template> void forEachRow(const Func & func); + /// Support for a C++ row range for + template + RowRange 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, Func, 0>(this, func); } } + + template + inline RowRange SelectCommand::as() + { + return RowRange(this); + } + + template + inline RowRange::RowRange(SelectCommand * s) : + sel(s) + { + } + + template + inline RowRangeIterator RowRange::begin() const + { + return RowRangeIterator(sel); + } + + template + inline RowRangeIterator RowRange::end() const + { + return RowRangeIterator(nullptr); + } + + template + inline RowRangeIterator::RowRangeIterator(SelectCommand * s) : + sel(s) + { + if (sel) { + validRow = sel->fetch(); + } + else { + validRow = false; + } + } + + template + inline bool RowRangeIterator::operator!=(const RowRangeIterator &) const + { + return validRow; + } + + template + inline void RowRangeIterator::operator++() + { + validRow = sel->fetch(); + } + + template + inline Row RowRangeIterator::operator*() const + { + return Row(sel); + } + + template + inline Row::Row(SelectCommand * s) : + RowBase(s) + { + } + + template + template + inline typename std::tuple_element>::type Row::value() const + { + typename std::tuple_element>::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()) { + 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")); -- cgit v1.2.3