Skip to content

Instantly share code, notes, and snippets.

@egorpugin
Created February 20, 2020 16:39
Show Gist options
  • Save egorpugin/eced222ace1c2782d869c6e713397d91 to your computer and use it in GitHub Desktop.
Save egorpugin/eced222ace1c2782d869c6e713397d91 to your computer and use it in GitHub Desktop.
/*
c++: 17
deps:
- org.sw.demo.jtv.pqxx
- org.sw.demo.apolukhin.magic_get
*/
#include <boost/pfr/precise/core.hpp>
#include <pqxx/pqxx>
struct PqxxFancyResultWrapper
{
using r = typename pqxx::result;
template <class ... Args>
struct Wrapper
{
struct Iterator
{
r::const_iterator i;
Iterator(r::const_iterator i) : i(i) {}
bool operator==(const Iterator &rhs) const { return i == rhs.i; }
bool operator!=(const Iterator &rhs) const { return !operator==(rhs); }
Iterator &operator++() { ++i; return *this; }
auto operator*() const
{
if constexpr (sizeof...(Args) == 1 && std::is_class_v<std::tuple_element_t<0, std::tuple<Args...>>>)
{
std::tuple_element_t<0, std::tuple<Args...>> v;
boost::pfr::for_each_field(
v, [this](auto &field, size_t idx) { field = i[idx].as<std::decay_t<decltype(field)>>(); });
return v;
}
else
{
std::tuple<Args...> t;
assign(t);
return t;
}
}
private:
template<std::size_t I = 0, typename... Tp>
inline typename std::enable_if_t<I == sizeof...(Tp), void>
assign(std::tuple<Tp...>& t) const
{}
template<std::size_t I = 0, typename... Tp>
inline typename std::enable_if_t<I < sizeof...(Tp), void>
assign(std::tuple<Tp...>& t) const
{
std::get<I>(t) = i[(pqxx::row::size_type)I].as<std::decay_t<decltype(std::get<I>(t))>>();
assign<I + 1, Tp...>(t);
}
};
Wrapper(const PqxxFancyResultWrapper &r) : r(r) {}
auto begin() const { return Iterator{ r.get().begin() }; }
auto end() const { return Iterator{ r.get().end() }; }
private:
PqxxFancyResultWrapper r;
};
PqxxFancyResultWrapper(r &&r)
: holder(std::move(r))
{}
PqxxFancyResultWrapper(const r &r)
: pholder(&r)
{}
template <class ... Args>
auto as() const
{
return Wrapper<Args...>(*this);
}
private:
r holder;
const r *pholder = nullptr;
const r &get() const { if (pholder) return *pholder; return holder; }
};
using W = PqxxFancyResultWrapper;
int main()
{
pqxx::connection c("dbname=sw user=webapp password=webapp");
pqxx::work tx(c);
c.prepare("x", "select * from package_version order by package_version_id");
auto r = tx.exec_prepared("x");
for (const auto &row : W(r).as<int>())
{
auto a = std::get<0>(row);
}
for (const auto &[id, pkgver] : W(tx.exec_prepared("x")).as<int, int>())
{
}
struct my_struct { int id, pkgver; };
for (const auto &row : W(r).as<my_struct>())
{
row.id;
row.pkgver;
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment