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
155
|
#pragma once
#include "Query.h"
#include "QueryResult.h"
#include <tuple>
#include <sqlite3.h>
#include <memory>
#include <vector>
namespace Database
{
template<typename ...ReturnTypes>
class QueryExecuter
{
public:
/*
Creates a prepared statement and initializes the query.
*/
explicit QueryExecuter(sqlite3* db) : database(db) {}
/*
Sets the query this executer will execute.
*/
QueryExecuter<ReturnTypes...>& setQuery(Query<ReturnTypes...> query)
{
this->query = std::make_unique<Query<ReturnTypes...>>(query);
this->query->prepare(database);
return *this;
}
/*
Binds the given name-value pairs to the statement.
Recursive case.
*/
template<typename BindType>
QueryExecuter<ReturnTypes...>& bindParams(BindType locationValuePair, int depth = 1)
{
query->template bind<BindType>(locationValuePair, depth);
return *this;
}
/*
Binds the given name-value pairs to the statement.
Recursive case.
*/
template<typename BindType, typename ...BindTypes>
QueryExecuter<ReturnTypes...>& bindParams(BindType locationValuePair, BindTypes... locationValuePairs, int depth = 1)
{
query->template bind<BindType>(locationValuePair, depth);
bindParams<BindTypes...>(locationValuePairs..., depth + 1);
return *this;
}
/*
Executes the query and returns a tuple with an entry for each type. Use this to recieve only the first result.
Multiple calls, or calls when there are no rows in the db, can lead to exceptions.
This is functionally equivalent to stepping and then calling getResult
*/
QueryResult<ReturnTypes...> executeOnce()
{
query->step();
return QueryResult<ReturnTypes...>(getResult<ReturnTypes...>());
}
/*
Steps the query.
*/
bool step()
{
return query->step();
}
/*
Returns the result.
*/
QueryResult<ReturnTypes...> result()
{
return QueryResult<ReturnTypes...>(getResult<ReturnTypes...>());
}
/*
Executes the query and returns a vector of tuples for each result.
*/
std::vector<QueryResult<ReturnTypes...>> execute(int limit = 0)
{
std::vector<QueryResult<ReturnTypes...>> result;
// Return code
bool more;
int limiter = 0;
do
{
// Execution of the statement
more = query->step();
if (!more || (limiter >= limit && limit > 0))
break;
limiter++;
std::tuple<ReturnTypes...> row = getResult<ReturnTypes...>();
result.emplace_back(row);
} while (more);
return result;
}
/*
Resets the sqlite3 query object.
*/
QueryExecuter<ReturnTypes...>& reset()
{
query->reset();
return *this;
}
private:
/*
Returns the results after executing the query.
Base case.
*/
template<typename ReturnType>
std::tuple<ReturnType> getResult(int depth = 0)
{
return std::tuple<ReturnType>(query->template getResult<ReturnType>(depth));
}
/*
Returns the results after executing the query.
Recursive Case.
*/
template<typename FirstReturnType, typename SecondReturnType, typename ...OtherReturnTypes>
std::tuple<FirstReturnType, SecondReturnType, OtherReturnTypes...> getResult(int depth = 0)
{
std::tuple<FirstReturnType> first = std::tuple<FirstReturnType>(query->template getResult<FirstReturnType>(depth));
std::tuple<SecondReturnType, OtherReturnTypes...> rest = getResult<SecondReturnType, OtherReturnTypes...>(depth + 1);
return std::tuple_cat(first, rest);
}
/*
Returns an empty tuple for when there are no return values.
*/
template<typename ...NoTypes>
std::tuple<> getResult(int depth = 0) const
{
return std::tuple<>();
}
std::unique_ptr<Query<ReturnTypes...>> query;
sqlite3* database;
};
}
|