Skip to content

Commit d35b6f0

Browse files
committed
Range interface
1 parent 76472db commit d35b6f0

File tree

2 files changed

+100
-1
lines changed

2 files changed

+100
-1
lines changed

hdr/sqlite_modern_cpp.h

Lines changed: 85 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ namespace sqlite {
8181
static void iterate(Tuple&, database_binder&) {}
8282
};
8383

84+
class row_iterator;
8485
class database_binder {
8586

8687
public:
@@ -128,6 +129,8 @@ namespace sqlite {
128129
execution_started = state;
129130
}
130131
bool used() const { return execution_started; }
132+
row_iterator begin();
133+
row_iterator end();
131134

132135
private:
133136
std::shared_ptr<sqlite3> _db;
@@ -312,7 +315,88 @@ namespace sqlite {
312315
binder<traits::arity>::run(*this, func);
313316
});
314317
}
318+
friend class row_iterator;
315319
};
320+
class row_iterator {
321+
public:
322+
class value_type {
323+
public:
324+
value_type(database_binder *_binder): _binder(_binder) {};
325+
template<class T>
326+
value_type &operator >>(T &result) {
327+
get_col_from_db(*_binder, next_index++, result);
328+
return *this;
329+
}
330+
template<class ...Types>
331+
value_type &operator >>(std::tuple<Types...>& values) {
332+
assert(!next_index);
333+
tuple_iterate<std::tuple<Types...>>::iterate(values, *_binder);
334+
next_index = sizeof...(Types) + 1;
335+
return *this;
336+
}
337+
explicit operator bool() {
338+
return sqlite3_column_count(_binder->_stmt.get()) >= next_index;
339+
}
340+
template<class Type>
341+
operator Type() {
342+
Type value;
343+
*this >> value;
344+
return value;
345+
}
346+
private:
347+
database_binder *_binder;
348+
int next_index = 0;
349+
};
350+
using difference_type = std::ptrdiff_t;
351+
using pointer = value_type*;
352+
using reference = value_type&;
353+
using iterator_category = std::input_iterator_tag;
354+
355+
row_iterator() = default;
356+
explicit row_iterator(database_binder &binder): _binder(&binder) {
357+
_binder->_start_execute();
358+
++*this;
359+
}
360+
361+
reference operator*() const { return value;}
362+
pointer operator->() const { return std::addressof(**this); }
363+
row_iterator &operator++() {
364+
switch(int result = sqlite3_step(_binder->_stmt.get())) {
365+
case SQLITE_ROW:
366+
value = {_binder};
367+
/* tuple_iterate<value_type>::iterate(_value, *_binder); */
368+
break;
369+
case SQLITE_DONE:
370+
_binder = nullptr;
371+
break;
372+
default:
373+
_binder = nullptr;
374+
exceptions::throw_sqlite_error(result, _binder->sql());
375+
}
376+
return *this;
377+
}
378+
379+
// Not well-defined
380+
row_iterator operator++(int);
381+
friend inline bool operator ==(const row_iterator &a, const row_iterator &b) {
382+
return a._binder == b._binder;
383+
}
384+
friend inline bool operator !=(const row_iterator &a, const row_iterator &b) {
385+
return !(a==b);
386+
}
387+
388+
private:
389+
database_binder *_binder = nullptr;
390+
mutable value_type value{_binder}; // mutable, because `changing` the value is just reading it
391+
};
392+
393+
inline row_iterator database_binder::begin() {
394+
return row_iterator(*this);
395+
}
396+
397+
inline row_iterator database_binder::end() {
398+
return row_iterator();
399+
}
316400

317401
namespace sql_function_binder {
318402
template<
@@ -913,7 +997,7 @@ namespace sqlite {
913997
void inline operator++(database_binder& db, int) { db.execute(); }
914998

915999
// Convert the rValue binder to a reference and call first op<<, its needed for the call that creates the binder (be carefull of recursion here!)
916-
template<typename T> database_binder&& operator << (database_binder&& db, const T& val) { db << val; return std::move(db); }
1000+
template<typename T> database_binder operator << (database_binder&& db, const T& val) { db << val; return std::move(db); }
9171001

9181002
namespace sql_function_binder {
9191003
template<class T>

tests/readme_example.cc

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,21 @@ int main() {
4949
exit(EXIT_FAILURE);
5050
cout << _age << ' ' << _name << ' ' << _weight << endl;
5151
};
52+
for(auto &&row : db << "select age,name,weight from user where age > ? ;" << 21) {
53+
int _age;
54+
string _name;
55+
double _weight;
56+
row >> _age >> _name >> _weight;
57+
if(_age != age || _name != name)
58+
exit(EXIT_FAILURE);
59+
cout << _age << ' ' << _name << ' ' << _weight << endl;
60+
}
61+
62+
for(std::tuple<int, string, double> row : db << "select age,name,weight from user where age > ? ;" << 21) {
63+
if(std::get<int>(row) != age || std::get<string>(row) != name)
64+
exit(EXIT_FAILURE);
65+
cout << std::get<int>(row) << ' ' << std::get<string>(row) << ' ' << std::get<double>(row) << endl;
66+
}
5267

5368
// selects the count(*) from user table
5469
// note that you can extract a single culumn single row result only to : int,long,long,float,double,string,u16string

0 commit comments

Comments
 (0)