Skip to content

Commit 37061ca

Browse files
committed
Implement all executions with iterators
1 parent f0ea5b4 commit 37061ca

File tree

2 files changed

+108
-93
lines changed

2 files changed

+108
-93
lines changed

hdr/sqlite_modern_cpp.h

Lines changed: 106 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -76,16 +76,7 @@ namespace sqlite {
7676
_stmt(std::move(other._stmt)),
7777
_inx(other._inx), execution_started(other.execution_started) { }
7878

79-
void execute() {
80-
_start_execute();
81-
int hresult;
82-
83-
while((hresult = sqlite3_step(_stmt.get())) == SQLITE_ROW) {}
84-
85-
if(hresult != SQLITE_DONE) {
86-
errors::throw_sqlite_error(hresult, sql());
87-
}
88-
}
79+
void execute();
8980

9081
std::string sql() {
9182
#if SQLITE_VERSION_NUMBER >= 3014000
@@ -129,15 +120,6 @@ namespace sqlite {
129120
}
130121
return ++_inx;
131122
}
132-
void _start_execute() {
133-
_next_index();
134-
_inx = 0;
135-
used(true);
136-
}
137-
138-
void _extract(std::function<void(void)> call_back);
139-
140-
void _extract_single_value(std::function<void(void)> call_back);
141123

142124
#ifdef _MSC_VER
143125
sqlite3_stmt* _prepare(const std::u16string& sql) {
@@ -160,31 +142,6 @@ namespace sqlite {
160142
return tmp;
161143
}
162144

163-
template <typename Type>
164-
struct is_sqlite_value : public std::integral_constant<
165-
bool,
166-
std::is_floating_point<Type>::value
167-
|| std::is_integral<Type>::value
168-
|| std::is_same<std::string, Type>::value
169-
|| std::is_same<std::u16string, Type>::value
170-
|| std::is_same<sqlite_int64, Type>::value
171-
> { };
172-
template <typename Type, typename Allocator>
173-
struct is_sqlite_value< std::vector<Type, Allocator> > : public std::integral_constant<
174-
bool,
175-
std::is_floating_point<Type>::value
176-
|| std::is_integral<Type>::value
177-
|| std::is_same<sqlite_int64, Type>::value
178-
> { };
179-
#ifdef MODERN_SQLITE_STD_VARIANT_SUPPORT
180-
template <typename ...Args>
181-
struct is_sqlite_value< std::variant<Args...> > : public std::integral_constant<
182-
bool,
183-
true
184-
> { };
185-
#endif
186-
187-
188145
/* for vector<T, A> support */
189146
template<typename T, typename A> friend database_binder& operator <<(database_binder& db, const std::vector<T, A>& val);
190147
template<typename T, typename A> friend void get_col_from_db(database_binder& db, int inx, std::vector<T, A>& val);
@@ -244,43 +201,56 @@ namespace sqlite {
244201
}
245202
}
246203

247-
template <typename Result>
248-
typename std::enable_if<is_sqlite_value<Result>::value, void>::type operator>>(
249-
Result& value) {
250-
this->_extract_single_value([&value, this] {
251-
get_col_from_db(*this, 0, value);
252-
});
253-
}
254-
255-
template<typename... Types>
256-
void operator>>(std::tuple<Types...>&& values) {
257-
this->_extract_single_value([&values, this] {
258-
tuple_iterate<std::tuple<Types...>>::iterate(values, *this);
259-
});
260-
}
261-
262-
template <typename Function>
263-
typename std::enable_if<!is_sqlite_value<Function>::value, void>::type operator>>(
264-
Function&& func) {
265-
typedef utility::function_traits<Function> traits;
266-
267-
this->_extract([&func, this]() {
268-
binder<traits::arity>::run(*this, func);
269-
});
270-
}
271204
friend class row_iterator;
272205
};
206+
namespace detail {
207+
template <typename Type>
208+
struct is_sqlite_value : public std::integral_constant<
209+
bool,
210+
std::is_floating_point<Type>::value
211+
|| std::is_integral<Type>::value
212+
|| std::is_same<std::string, Type>::value
213+
|| std::is_same<std::u16string, Type>::value
214+
|| std::is_same<sqlite_int64, Type>::value
215+
> { };
216+
template <typename Type, typename Allocator>
217+
struct is_sqlite_value< std::vector<Type, Allocator> > : public std::integral_constant<
218+
bool,
219+
std::is_floating_point<Type>::value
220+
|| std::is_integral<Type>::value
221+
|| std::is_same<sqlite_int64, Type>::value
222+
> { };
223+
template <typename T>
224+
struct is_sqlite_value< std::unique_ptr<T> > : public is_sqlite_value<T> {};
225+
#ifdef MODERN_SQLITE_STD_VARIANT_SUPPORT
226+
template <typename ...Args>
227+
struct is_sqlite_value< std::variant<Args...> > : public std::integral_constant<
228+
bool,
229+
true
230+
> { };
231+
#endif
232+
#ifdef MODERN_SQLITE_STD_OPTIONAL_SUPPORT
233+
template <typename T>
234+
struct is_sqlite_value< std::optional<T> > : public is_sqlite_value<T> {};
235+
#endif
236+
237+
#ifdef _MODERN_SQLITE_BOOST_OPTIONAL_SUPPORT
238+
template <typename T>
239+
struct is_sqlite_value< boost::optional<T> > : public is_sqlite_value<T> {};
240+
#endif
241+
}
242+
273243
class row_iterator {
274244
public:
275245
class value_type {
276246
public:
277247
value_type(database_binder *_binder): _binder(_binder) {};
278248
template<class T>
279-
typename std::enable_if<database_binder::is_sqlite_value<T>::value, value_type &>::type operator >>(T &result) {
249+
typename std::enable_if<detail::is_sqlite_value<T>::value, value_type &>::type operator >>(T &result) {
280250
get_col_from_db(*_binder, next_index++, result);
281251
return *this;
282252
}
283-
template<class T, typename = typename std::enable_if<database_binder::is_sqlite_value<T>::value, value_type &>::type>
253+
template<class T, typename = typename std::enable_if<detail::is_sqlite_value<T>::value, value_type &>::type>
284254
operator T() {
285255
T result;
286256
*this >> result;
@@ -294,6 +264,10 @@ namespace sqlite {
294264
return *this;
295265
}
296266
template<class ...Types>
267+
value_type &operator >>(std::tuple<Types...>&& values) {
268+
return *this >> values;
269+
}
270+
template<class ...Types>
297271
operator std::tuple<Types...>() {
298272
std::tuple<Types...> value;
299273
*this >> value;
@@ -313,7 +287,9 @@ namespace sqlite {
313287

314288
row_iterator() = default;
315289
explicit row_iterator(database_binder &binder): _binder(&binder) {
316-
_binder->_start_execute();
290+
_binder->_next_index();
291+
_binder->_inx = 0;
292+
_binder->used(true);
317293
++*this;
318294
}
319295

@@ -323,7 +299,6 @@ namespace sqlite {
323299
switch(int result = sqlite3_step(_binder->_stmt.get())) {
324300
case SQLITE_ROW:
325301
value = {_binder};
326-
/* tuple_iterate<value_type>::iterate(_value, *_binder); */
327302
break;
328303
case SQLITE_DONE:
329304
_binder = nullptr;
@@ -355,20 +330,60 @@ namespace sqlite {
355330
inline row_iterator database_binder::end() {
356331
return row_iterator();
357332
}
358-
void database_binder::_extract(std::function<void(void)> call_back) {
359-
for(auto &&row[[maybe_unused]] : *this)
360-
call_back();
333+
334+
namespace detail {
335+
template<class Callback>
336+
void _extract_single_value(database_binder &binder, Callback call_back) {
337+
auto iter = binder.begin();
338+
if(iter == binder.end())
339+
throw errors::no_rows("no rows to extract: exactly 1 row expected", binder.sql(), SQLITE_DONE);
340+
341+
call_back(*iter);
342+
343+
if(++iter != binder.end())
344+
throw errors::more_rows("not all rows extracted", binder.sql(), SQLITE_ROW);
345+
}
346+
}
347+
void database_binder::execute() {
348+
for(auto &&row : *this)
349+
(void)row;
350+
}
351+
namespace detail {
352+
template<class T> using void_t = void;
353+
template<class T, class = void>
354+
struct sqlite_direct_result : std::false_type {};
355+
template<class T>
356+
struct sqlite_direct_result<
357+
T,
358+
void_t<decltype(std::declval<row_iterator::value_type&>().operator>>(std::declval<T&&>()))>
359+
> : std::true_type {};
360+
}
361+
template <typename Result>
362+
inline typename std::enable_if<detail::sqlite_direct_result<Result>::value>::type operator>>(database_binder &binder, Result&& value) {
363+
detail::_extract_single_value(binder, [&value] (row_iterator::value_type &row) {
364+
row >> std::forward<Result>(value);
365+
});
361366
}
362367

363-
void database_binder::_extract_single_value(std::function<void(void)> call_back) {
364-
auto iter = begin();
365-
if(iter == end())
366-
throw errors::no_rows("no rows to extract: exactly 1 row expected", sql(), SQLITE_DONE);
368+
/* template<typename... Types> */
369+
/* inline void operator>>(database_binder &binder, std::tuple<Types...>&& values) { */
370+
/* detail::_extract_single_value(binder, [&values] (row_iterator::value_type &row) { */
371+
/* row >> std::move(values); */
372+
/* }); */
373+
/* } */
367374

368-
call_back();
375+
template <typename Function>
376+
inline typename std::enable_if<!detail::sqlite_direct_result<Function>::value>::type operator>>(database_binder &db_binder, Function&& func) {
377+
using traits = utility::function_traits<Function>;
369378

370-
if(++iter != end())
371-
throw errors::more_rows("not all rows extracted", sql(), SQLITE_ROW);
379+
for(auto &&row : db_binder) {
380+
binder<traits::arity>::run(row, func);
381+
}
382+
}
383+
384+
template <typename Result>
385+
inline decltype(auto) operator>>(database_binder &&binder, Result&& value) {
386+
return binder >> std::forward<Result>(value);
372387
}
373388

374389
namespace sql_function_binder {
@@ -573,14 +588,13 @@ namespace sqlite {
573588
std::size_t Boundary = Count
574589
>
575590
static typename std::enable_if<(sizeof...(Values) < Boundary), void>::type run(
576-
database_binder& db,
577-
Function&& function,
578-
Values&&... values
591+
row_iterator::value_type& row,
592+
Function&& function,
593+
Values&&... values
579594
) {
580-
typename std::remove_cv<typename std::remove_reference<nth_argument_type<Function, sizeof...(Values)>>::type>::type value{};
581-
get_col_from_db(db, sizeof...(Values), value);
582-
583-
run<Function>(db, function, std::forward<Values>(values)..., std::move(value));
595+
typename std::decay<nth_argument_type<Function, sizeof...(Values)>>::type value;
596+
row >> value;
597+
run<Function>(row, function, std::forward<Values>(values)..., std::move(value));
584598
}
585599

586600
template<
@@ -589,9 +603,9 @@ namespace sqlite {
589603
std::size_t Boundary = Count
590604
>
591605
static typename std::enable_if<(sizeof...(Values) == Boundary), void>::type run(
592-
database_binder&,
593-
Function&& function,
594-
Values&&... values
606+
row_iterator::value_type&,
607+
Function&& function,
608+
Values&&... values
595609
) {
596610
function(std::move(values)...);
597611
}

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)