Skip to content

Commit 5bbe246

Browse files
committed
Implement all executions with iterators
1 parent a5f9f6e commit 5bbe246

File tree

2 files changed

+101
-93
lines changed

2 files changed

+101
-93
lines changed

hdr/sqlite_modern_cpp.h

Lines changed: 99 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -95,16 +95,7 @@ namespace sqlite {
9595
_stmt(std::move(other._stmt)),
9696
_inx(other._inx), execution_started(other.execution_started) { }
9797

98-
void execute() {
99-
_start_execute();
100-
int hresult;
101-
102-
while((hresult = sqlite3_step(_stmt.get())) == SQLITE_ROW) {}
103-
104-
if(hresult != SQLITE_DONE) {
105-
errors::throw_sqlite_error(hresult, sql());
106-
}
107-
}
98+
void execute();
10899

109100
std::string sql() {
110101
#if SQLITE_VERSION_NUMBER >= 3014000
@@ -148,15 +139,6 @@ namespace sqlite {
148139
}
149140
return ++_inx;
150141
}
151-
void _start_execute() {
152-
_next_index();
153-
_inx = 0;
154-
used(true);
155-
}
156-
157-
void _extract(std::function<void(void)> call_back);
158-
159-
void _extract_single_value(std::function<void(void)> call_back);
160142

161143
#ifdef _MSC_VER
162144
sqlite3_stmt* _prepare(const std::u16string& sql) {
@@ -179,31 +161,6 @@ namespace sqlite {
179161
return tmp;
180162
}
181163

182-
template <typename Type>
183-
struct is_sqlite_value : public std::integral_constant<
184-
bool,
185-
std::is_floating_point<Type>::value
186-
|| std::is_integral<Type>::value
187-
|| std::is_same<std::string, Type>::value
188-
|| std::is_same<std::u16string, Type>::value
189-
|| std::is_same<sqlite_int64, Type>::value
190-
> { };
191-
template <typename Type, typename Allocator>
192-
struct is_sqlite_value< std::vector<Type, Allocator> > : public std::integral_constant<
193-
bool,
194-
std::is_floating_point<Type>::value
195-
|| std::is_integral<Type>::value
196-
|| std::is_same<sqlite_int64, Type>::value
197-
> { };
198-
#ifdef MODERN_SQLITE_STD_VARIANT_SUPPORT
199-
template <typename ...Args>
200-
struct is_sqlite_value< std::variant<Args...> > : public std::integral_constant<
201-
bool,
202-
true
203-
> { };
204-
#endif
205-
206-
207164
/* for vector<T, A> support */
208165
template<typename T, typename A> friend database_binder& operator <<(database_binder& db, const std::vector<T, A>& val);
209166
template<typename T, typename A> friend void get_col_from_db(database_binder& db, int inx, std::vector<T, A>& val);
@@ -263,43 +220,56 @@ namespace sqlite {
263220
}
264221
}
265222

266-
template <typename Result>
267-
typename std::enable_if<is_sqlite_value<Result>::value, void>::type operator>>(
268-
Result& value) {
269-
this->_extract_single_value([&value, this] {
270-
get_col_from_db(*this, 0, value);
271-
});
272-
}
273-
274-
template<typename... Types>
275-
void operator>>(std::tuple<Types...>&& values) {
276-
this->_extract_single_value([&values, this] {
277-
tuple_iterate<std::tuple<Types...>>::iterate(values, *this);
278-
});
279-
}
280-
281-
template <typename Function>
282-
typename std::enable_if<!is_sqlite_value<Function>::value, void>::type operator>>(
283-
Function&& func) {
284-
typedef utility::function_traits<Function> traits;
285-
286-
this->_extract([&func, this]() {
287-
binder<traits::arity>::run(*this, func);
288-
});
289-
}
290223
friend class row_iterator;
291224
};
225+
namespace detail {
226+
template <typename Type>
227+
struct is_sqlite_value : public std::integral_constant<
228+
bool,
229+
std::is_floating_point<Type>::value
230+
|| std::is_integral<Type>::value
231+
|| std::is_same<std::string, Type>::value
232+
|| std::is_same<std::u16string, Type>::value
233+
|| std::is_same<sqlite_int64, Type>::value
234+
> { };
235+
template <typename Type, typename Allocator>
236+
struct is_sqlite_value< std::vector<Type, Allocator> > : public std::integral_constant<
237+
bool,
238+
std::is_floating_point<Type>::value
239+
|| std::is_integral<Type>::value
240+
|| std::is_same<sqlite_int64, Type>::value
241+
> { };
242+
template <typename T>
243+
struct is_sqlite_value< std::unique_ptr<T> > : public is_sqlite_value<T> {};
244+
#ifdef MODERN_SQLITE_STD_VARIANT_SUPPORT
245+
template <typename ...Args>
246+
struct is_sqlite_value< std::variant<Args...> > : public std::integral_constant<
247+
bool,
248+
true
249+
> { };
250+
#endif
251+
#ifdef MODERN_SQLITE_STD_OPTIONAL_SUPPORT
252+
template <typename T>
253+
struct is_sqlite_value< std::optional<T> > : public is_sqlite_value<T> {};
254+
#endif
255+
256+
#ifdef _MODERN_SQLITE_BOOST_OPTIONAL_SUPPORT
257+
template <typename T>
258+
struct is_sqlite_value< boost::optional<T> > : public is_sqlite_value<T> {};
259+
#endif
260+
}
261+
292262
class row_iterator {
293263
public:
294264
class value_type {
295265
public:
296266
value_type(database_binder *_binder): _binder(_binder) {};
297267
template<class T>
298-
typename std::enable_if<database_binder::is_sqlite_value<T>::value, value_type &>::type operator >>(T &result) {
268+
typename std::enable_if<detail::is_sqlite_value<T>::value, value_type &>::type operator >>(T &result) {
299269
get_col_from_db(*_binder, next_index++, result);
300270
return *this;
301271
}
302-
template<class T, typename = typename std::enable_if<database_binder::is_sqlite_value<T>::value, value_type &>::type>
272+
template<class T, typename = typename std::enable_if<detail::is_sqlite_value<T>::value, value_type &>::type>
303273
operator T() {
304274
T result;
305275
*this >> result;
@@ -313,6 +283,10 @@ namespace sqlite {
313283
return *this;
314284
}
315285
template<class ...Types>
286+
value_type &operator >>(std::tuple<Types...>&& values) {
287+
return *this >> values;
288+
}
289+
template<class ...Types>
316290
operator std::tuple<Types...>() {
317291
std::tuple<Types...> value;
318292
*this >> value;
@@ -332,7 +306,9 @@ namespace sqlite {
332306

333307
row_iterator() = default;
334308
explicit row_iterator(database_binder &binder): _binder(&binder) {
335-
_binder->_start_execute();
309+
_binder->_next_index();
310+
_binder->_inx = 0;
311+
_binder->used(true);
336312
++*this;
337313
}
338314

@@ -342,7 +318,6 @@ namespace sqlite {
342318
switch(int result = sqlite3_step(_binder->_stmt.get())) {
343319
case SQLITE_ROW:
344320
value = {_binder};
345-
/* tuple_iterate<value_type>::iterate(_value, *_binder); */
346321
break;
347322
case SQLITE_DONE:
348323
_binder = nullptr;
@@ -374,20 +349,53 @@ namespace sqlite {
374349
inline row_iterator database_binder::end() {
375350
return row_iterator();
376351
}
377-
void database_binder::_extract(std::function<void(void)> call_back) {
378-
for(auto &&row[[maybe_unused]] : *this)
379-
call_back();
352+
353+
namespace detail {
354+
template<class Callback>
355+
void _extract_single_value(database_binder &binder, Callback call_back) {
356+
auto iter = binder.begin();
357+
if(iter == binder.end())
358+
throw errors::no_rows("no rows to extract: exactly 1 row expected", binder.sql(), SQLITE_DONE);
359+
360+
call_back(*iter);
361+
362+
if(++iter != binder.end())
363+
throw errors::more_rows("not all rows extracted", binder.sql(), SQLITE_ROW);
364+
}
365+
}
366+
void database_binder::execute() {
367+
for(auto &&row : *this)
368+
(void)row;
369+
}
370+
namespace detail {
371+
template<class T> using void_t = void;
372+
template<class T, class = void>
373+
struct sqlite_direct_result : std::false_type {};
374+
template<class T>
375+
struct sqlite_direct_result<
376+
T,
377+
void_t<decltype(std::declval<row_iterator::value_type&>().operator>>(std::declval<T&&>()))>
378+
> : std::true_type {};
379+
}
380+
template <typename Result>
381+
inline typename std::enable_if<detail::sqlite_direct_result<Result>::value>::type operator>>(database_binder &binder, Result&& value) {
382+
detail::_extract_single_value(binder, [&value] (row_iterator::value_type &row) {
383+
row >> std::forward<Result>(value);
384+
});
380385
}
381386

382-
void database_binder::_extract_single_value(std::function<void(void)> call_back) {
383-
auto iter = begin();
384-
if(iter == end())
385-
throw errors::no_rows("no rows to extract: exactly 1 row expected", sql(), SQLITE_DONE);
387+
template <typename Function>
388+
inline typename std::enable_if<!detail::sqlite_direct_result<Function>::value>::type operator>>(database_binder &db_binder, Function&& func) {
389+
using traits = utility::function_traits<Function>;
386390

387-
call_back();
391+
for(auto &&row : db_binder) {
392+
binder<traits::arity>::run(row, func);
393+
}
394+
}
388395

389-
if(++iter != end())
390-
throw errors::more_rows("not all rows extracted", sql(), SQLITE_ROW);
396+
template <typename Result>
397+
inline decltype(auto) operator>>(database_binder &&binder, Result&& value) {
398+
return binder >> std::forward<Result>(value);
391399
}
392400

393401
namespace sql_function_binder {
@@ -592,14 +600,13 @@ namespace sqlite {
592600
std::size_t Boundary = Count
593601
>
594602
static typename std::enable_if<(sizeof...(Values) < Boundary), void>::type run(
595-
database_binder& db,
596-
Function&& function,
597-
Values&&... values
603+
row_iterator::value_type& row,
604+
Function&& function,
605+
Values&&... values
598606
) {
599-
typename std::remove_cv<typename std::remove_reference<nth_argument_type<Function, sizeof...(Values)>>::type>::type value{};
600-
get_col_from_db(db, sizeof...(Values), value);
601-
602-
run<Function>(db, function, std::forward<Values>(values)..., std::move(value));
607+
typename std::decay<nth_argument_type<Function, sizeof...(Values)>>::type value;
608+
row >> value;
609+
run<Function>(row, function, std::forward<Values>(values)..., std::move(value));
603610
}
604611

605612
template<
@@ -608,9 +615,9 @@ namespace sqlite {
608615
std::size_t Boundary = Count
609616
>
610617
static typename std::enable_if<(sizeof...(Values) == Boundary), void>::type run(
611-
database_binder&,
612-
Function&& function,
613-
Values&&... values
618+
row_iterator::value_type&,
619+
Function&& function,
620+
Values&&... values
614621
) {
615622
function(std::move(values)...);
616623
}

hdr/sqlite_modern_cpp/utility/function_traits.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,11 @@ namespace sqlite {
4242
> {
4343
typedef ReturnType result_type;
4444

45+
using argument_tuple = std::tuple<Arguments...>;
4546
template <std::size_t Index>
4647
using argument = typename std::tuple_element<
4748
Index,
48-
std::tuple<Arguments...>
49+
argument_tuple
4950
>::type;
5051

5152
static const std::size_t arity = sizeof...(Arguments);

0 commit comments

Comments
 (0)