@@ -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 }
0 commit comments