Skip to content

Commit 6205d96

Browse files
committed
Range interface
1 parent 767499e commit 6205d96

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
@@ -62,6 +62,7 @@ namespace sqlite {
6262
static void iterate(Tuple&, database_binder&) {}
6363
};
6464

65+
class row_iterator;
6566
class database_binder {
6667

6768
public:
@@ -109,6 +110,8 @@ namespace sqlite {
109110
execution_started = state;
110111
}
111112
bool used() const { return execution_started; }
113+
row_iterator begin();
114+
row_iterator end();
112115

113116
private:
114117
std::shared_ptr<sqlite3> _db;
@@ -293,7 +296,88 @@ namespace sqlite {
293296
binder<traits::arity>::run(*this, func);
294297
});
295298
}
299+
friend class row_iterator;
296300
};
301+
class row_iterator {
302+
public:
303+
class value_type {
304+
public:
305+
value_type(database_binder *_binder): _binder(_binder) {};
306+
template<class T>
307+
value_type &operator >>(T &result) {
308+
get_col_from_db(*_binder, next_index++, result);
309+
return *this;
310+
}
311+
template<class ...Types>
312+
value_type &operator >>(std::tuple<Types...>& values) {
313+
assert(!next_index);
314+
tuple_iterate<std::tuple<Types...>>::iterate(values, *_binder);
315+
next_index = sizeof...(Types) + 1;
316+
return *this;
317+
}
318+
explicit operator bool() {
319+
return sqlite3_column_count(_binder->_stmt.get()) >= next_index;
320+
}
321+
template<class Type>
322+
operator Type() {
323+
Type value;
324+
*this >> value;
325+
return value;
326+
}
327+
private:
328+
database_binder *_binder;
329+
int next_index = 0;
330+
};
331+
using difference_type = std::ptrdiff_t;
332+
using pointer = value_type*;
333+
using reference = value_type&;
334+
using iterator_category = std::input_iterator_tag;
335+
336+
row_iterator() = default;
337+
explicit row_iterator(database_binder &binder): _binder(&binder) {
338+
_binder->_start_execute();
339+
++*this;
340+
}
341+
342+
reference operator*() const { return value;}
343+
pointer operator->() const { return std::addressof(**this); }
344+
row_iterator &operator++() {
345+
switch(int result = sqlite3_step(_binder->_stmt.get())) {
346+
case SQLITE_ROW:
347+
value = {_binder};
348+
/* tuple_iterate<value_type>::iterate(_value, *_binder); */
349+
break;
350+
case SQLITE_DONE:
351+
_binder = nullptr;
352+
break;
353+
default:
354+
_binder = nullptr;
355+
exceptions::throw_sqlite_error(result, _binder->sql());
356+
}
357+
return *this;
358+
}
359+
360+
// Not well-defined
361+
row_iterator operator++(int);
362+
friend inline bool operator ==(const row_iterator &a, const row_iterator &b) {
363+
return a._binder == b._binder;
364+
}
365+
friend inline bool operator !=(const row_iterator &a, const row_iterator &b) {
366+
return !(a==b);
367+
}
368+
369+
private:
370+
database_binder *_binder = nullptr;
371+
mutable value_type value{_binder}; // mutable, because `changing` the value is just reading it
372+
};
373+
374+
inline row_iterator database_binder::begin() {
375+
return row_iterator(*this);
376+
}
377+
378+
inline row_iterator database_binder::end() {
379+
return row_iterator();
380+
}
297381

298382
namespace sql_function_binder {
299383
template<
@@ -886,7 +970,7 @@ namespace sqlite {
886970
void inline operator++(database_binder& db, int) { db.execute(); }
887971

888972
// 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!)
889-
template<typename T> database_binder&& operator << (database_binder&& db, const T& val) { db << val; return std::move(db); }
973+
template<typename T> database_binder operator << (database_binder&& db, const T& val) { db << val; return std::move(db); }
890974

891975
namespace sql_function_binder {
892976
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)