Skip to content

[RFC] Iterator interface #103

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 84 additions & 3 deletions hdr/sqlite_modern_cpp.h
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,57 @@ namespace sqlite {
}
bool used() const { return execution_started; }

template<class ...T>
class row_iterator {
public:
using difference_type = std::ptrdiff_t;
using value_type = std::tuple<T...>;
using pointer = const value_type*;;
using reference = const value_type&;
using iterator_category = std::input_iterator_tag;

row_iterator() = default;
explicit row_iterator(database_binder &binder): _binder(&binder) {
_binder->used(true);
++*this;
}

reference operator*() const { return _value; }
pointer operator->() const { return std::addressof(**this); }
row_iterator &operator++() {

switch(int result = sqlite3_step(_binder->_stmt.get())) {
case SQLITE_ROW:
tuple_iterate<value_type>::iterate(_value, *_binder);
break;
case SQLITE_DONE:
_binder = nullptr;
break;
default:
_binder = nullptr;
exceptions::throw_sqlite_error(result, _binder->sql());
}
return *this;
}

row_iterator operator++(int) const { auto old = *this; ++*this; return old; }
friend inline bool operator ==(const row_iterator &a, const row_iterator &b) {
return a._binder == b._binder;
}
friend inline bool operator !=(const row_iterator &a, const row_iterator &b) {
return !(a==b);
}

private:
database_binder *_binder = nullptr;
value_type _value;
};

template<class ...T>
inline auto as() &;
template<class ...T>
inline auto as() &&;

private:
std::shared_ptr<sqlite3> _db;
std::unique_ptr<sqlite3_stmt, decltype(&sqlite3_finalize)> _stmt;
Expand Down Expand Up @@ -372,6 +423,31 @@ namespace sqlite {
}
};

template<class ...T>
class owning_row_view
{
public:
owning_row_view(database_binder &&binder): _binder(std::move(binder)) {}
auto begin() { return database_binder::row_iterator<T...>(_binder); }
auto end() { return database_binder::row_iterator<T...>(); }
private:
database_binder _binder;
};
template<class ...T>
class row_view
{
public:
row_view(database_binder &binder): _binder(&binder) {}
auto begin() { return database_binder::row_iterator<T...>(*_binder); }
auto end() { return database_binder::row_iterator<T...>(); }
private:
database_binder *_binder;
};
template<class ...T>
auto database_binder::as() & { return row_view<T...>(*this); }
template<class ...T>
auto database_binder::as() && { return owning_row_view<T...>(std::move(*this)); }

namespace sql_function_binder {
template<
typename ContextType,
Expand Down Expand Up @@ -852,7 +928,7 @@ namespace sqlite {
#ifdef MODERN_SQLITE_STD_OPTIONAL_SUPPORT
template <typename OptionalT> inline database_binder& operator <<(database_binder& db, const std::optional<OptionalT>& val) {
if(val) {
return operator << (std::move(db), std::move(*val));
return operator << (db, std::move(*val));
}
int hresult;
if((hresult = sqlite3_bind_null(db._stmt.get(), db._inx)) != SQLITE_OK) {
Expand Down Expand Up @@ -893,7 +969,7 @@ namespace sqlite {
#ifdef _MODERN_SQLITE_BOOST_OPTIONAL_SUPPORT
template <typename BoostOptionalT> inline database_binder& operator <<(database_binder& db, const boost::optional<BoostOptionalT>& val) {
if(val) {
return operator << (std::move(db), std::move(*val));
return operator << (db, std::move(*val));
}
int hresult;
if((hresult = sqlite3_bind_null(db._stmt.get(), db._inx)) != SQLITE_OK) {
Expand Down Expand Up @@ -956,7 +1032,7 @@ namespace sqlite {
void inline operator++(database_binder& db, int) { db.execute(); db.reset(); }

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

namespace sql_function_binder {
template<class T>
Expand Down Expand Up @@ -1098,4 +1174,9 @@ namespace sqlite {
}
}
}

template<class ...T>
auto as(database_binder &binder) { return row_view<T...>(binder); }
template<class ...T>
auto as(database_binder&&binder) { return owning_row_view<T...>(std::move(binder)); }
}
11 changes: 11 additions & 0 deletions tests/readme_example.cc
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,17 @@ int main() {
exit(EXIT_FAILURE);
cout << _age << ' ' << _name << ' ' << _weight << endl;
};
for(auto &&[_age, _name, _weight] : (db << "select age,name,weight from user where age > ? ;" << 21).as<int, string, double>()) {
if(_age != age || _name != name)
exit(EXIT_FAILURE);
cout << _age << ' ' << _name << ' ' << _weight << endl;
}

for(auto &&[_age, _name, _weight] : as<int, string, double>(db << "select age,name,weight from user where age > ? ;" << 21)) {
if(_age != age || _name != name)
exit(EXIT_FAILURE);
cout << _age << ' ' << _name << ' ' << _weight << endl;
}

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