diff options
-rw-r--r-- | libdbpp/selectcommand.cpp | 17 | ||||
-rw-r--r-- | libdbpp/selectcommand.h | 55 | ||||
-rw-r--r-- | libdbpp/selectcommandUtil.impl.h | 69 | ||||
-rw-r--r-- | libdbpp/unittests/testUtils.cpp | 20 |
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")); |