@@ -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,53 @@ 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 Function>
369+ inline typename std::enable_if<!detail::sqlite_direct_result<Function>::value>::type operator >>(database_binder &db_binder, Function&& func) {
370+ using traits = utility::function_traits<Function>;
367371
368- call_back ();
372+ for (auto &&row : db_binder) {
373+ binder<traits::arity>::run (row, func);
374+ }
375+ }
369376
370- if (++iter != end ())
371- throw errors::more_rows (" not all rows extracted" , sql (), SQLITE_ROW);
377+ template <typename Result>
378+ inline decltype (auto ) operator>>(database_binder &&binder, Result&& value) {
379+ return binder >> std::forward<Result>(value);
372380 }
373381
374382 namespace sql_function_binder {
@@ -573,14 +581,13 @@ namespace sqlite {
573581 std::size_t Boundary = Count
574582 >
575583 static typename std::enable_if<(sizeof ...(Values) < Boundary), void >::type run (
576- database_binder& db ,
577- Function&& function,
578- Values&&... values
584+ row_iterator::value_type& row ,
585+ Function&& function,
586+ Values&&... values
579587 ) {
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));
588+ typename std::decay<nth_argument_type<Function, sizeof ...(Values)>>::type value;
589+ row >> value;
590+ run<Function>(row, function, std::forward<Values>(values)..., std::move (value));
584591 }
585592
586593 template <
@@ -589,9 +596,9 @@ namespace sqlite {
589596 std::size_t Boundary = Count
590597 >
591598 static typename std::enable_if<(sizeof ...(Values) == Boundary), void >::type run (
592- database_binder &,
593- Function&& function,
594- Values&&... values
599+ row_iterator::value_type &,
600+ Function&& function,
601+ Values&&... values
595602 ) {
596603 function (std::move (values)...);
597604 }
0 commit comments