-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdeferred_range.h++
154 lines (136 loc) · 4.46 KB
/
deferred_range.h++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
#pragma once
#include <tagsql/core/row_type_helper.h++>
#include <tagsql/clauses/all.h++>
#include <tagsql/common/exceptions.h++>
#include <tagsql/core/clause_picker.h++>
#include <tagsql/common/string_algo.h++>
#include <vector>
#include <memory>
#include <pqxx/pqxx>
namespace tagsql
{
template<typename SelectQuery>
struct value_type
{
using type = typename detail::row_type<typename SelectQuery::all_tables, typename SelectQuery::select>::type;
};
template<typename SelectQuery>
using value_type_t = typename value_type<SelectQuery>::type;
template<typename SelectQuery>
class deferred_range : public clause_picker<SelectQuery>
{
public:
using _is_deferred_range = std::true_type;
using select_query_type = SelectQuery;
deferred_range(std::shared_ptr<pqxx::connection> connection, std::string query_without_select)
: _connection(connection), _query_without_select(query_without_select), _executed(false) { }
//begin and end : const and non-const versions
auto begin() //-> iterator
{
return deferred_exec().begin();
}
auto end() //-> iterator
{
return deferred_exec().end();
}
auto begin() const //-> const_iterator
{
return const_cast<deferred_range&>(*this).begin();
}
auto end() const //-> const_iterator
{
return const_cast<deferred_range&>(*this).end();
}
//index-based access : const and non-const versions
auto operator[](int index) -> value_type_t<SelectQuery> &
{
return deferred_exec().at(index);
}
auto operator[](int index) const -> value_type_t<SelectQuery> const &
{
return const_cast<deferred_range&>(*this).deferred_exec().at(index);
}
//friendly upcast
auto defer() -> deferred_range&
{
return *this;
}
auto defer() const -> deferred_range const &
{
return *this;
}
//representations
auto as_vector() const -> std::vector<value_type_t<SelectQuery>> const &
{
return const_cast<deferred_range&>(*this).deferred_exec();
}
auto move_as_vector() const -> std::vector<value_type_t<SelectQuery>>
{
std::vector<value_type_t<SelectQuery>> & items = const_cast<deferred_range&>(*this).deferred_exec();
_executed = false;
return std::move(items);
}
auto query_string() const -> std::string const &
{
typename value_type_t<SelectQuery>::taglist columnlist{};
static_check(columnlist, typename select_query_type::all_tables());
return make_query_string(columnlist);
}
private:
std::vector<value_type_t<SelectQuery>>& deferred_exec()
{
return execute(typename value_type_t<SelectQuery>::indices());
}
template<typename ...Columns, typename Tables>
void static_check(::foam::meta::typelist<Columns...> const &, Tables const &) const
{
using tables = typename ::foam::meta::typelist<typename Columns::table_type...>::template unique_cvr<>::type;
static_assert(tables::template is_sublist_of_cvr<Tables>::value,
"Constraint Violation : at least one column does not belong to any table mentioned in the query.");
}
template<typename ...Columns>
std::string const & make_query_string(::foam::meta::typelist<Columns...>) const
{
static const std::vector<std::string> names { qualify(Columns()) ... };
static const std::string select_clause = "SELECT " + ::tagsql::join(",", names) + " ";
if ( _query.empty() )
_query = select_clause + _query_without_select;
return _query;
}
template<int ... N>
std::vector<value_type_t<SelectQuery>>& execute(foam::meta::seq<N...> const &)
{
static std::vector<value_type_t<SelectQuery>> _results;
if ( _executed )
return _results;
_executed = true;
try
{
auto result = pqxx::work(*_connection).exec(query_string());
for(pqxx::tuple && item : result)
{
_results.emplace_back(construct_from_field, std::move(item[N])...);
}
}
catch(std::exception const & e)
{
throw database_error(query_string(),e);
}
return _results;
}
public:
std::shared_ptr<pqxx::connection> _connection;
std::string _query_without_select;
mutable std::string _query;
protected:
bool _executed;
};
template<typename SelectQuery>
std::ostream& operator<<(std::ostream & out, deferred_range<SelectQuery> const & items)
{
out << items.query_string() << std::endl;
for(auto const & item : items)
out << item << "\n";
return out;
}
} //tagsql