From d3a9db040df0bfd31f94acef3d269d41333fe256 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20Kr=C3=BCger?= Date: Tue, 28 Mar 2017 07:56:41 +0200 Subject: [PATCH 1/3] Stop returning l-Value references to temporaries --- hdr/sqlite_modern_cpp.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hdr/sqlite_modern_cpp.h b/hdr/sqlite_modern_cpp.h index 12c8f718..ebd4b0bf 100644 --- a/hdr/sqlite_modern_cpp.h +++ b/hdr/sqlite_modern_cpp.h @@ -852,7 +852,7 @@ namespace sqlite { #ifdef MODERN_SQLITE_STD_OPTIONAL_SUPPORT template inline database_binder& operator <<(database_binder& db, const std::optional& 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) { @@ -893,7 +893,7 @@ namespace sqlite { #ifdef _MODERN_SQLITE_BOOST_OPTIONAL_SUPPORT template inline database_binder& operator <<(database_binder& db, const boost::optional& 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) { @@ -956,7 +956,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 database_binder& operator << (database_binder&& db, const T& val) { return db << val; } + template database_binder&& operator << (database_binder&& db, const T& val) { db << val; return std::move(db); } namespace sql_function_binder { template From b4d3c0c233d8ce498a4db74c58d3583f14e594e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20Kr=C3=BCger?= Date: Tue, 28 Mar 2017 08:03:59 +0200 Subject: [PATCH 2/3] Added Iterator interface --- hdr/sqlite_modern_cpp.h | 76 +++++++++++++++++++++++++++++++++++++++++ tests/readme_example.cc | 5 +++ 2 files changed, 81 insertions(+) diff --git a/hdr/sqlite_modern_cpp.h b/hdr/sqlite_modern_cpp.h index ebd4b0bf..b4d67ced 100644 --- a/hdr/sqlite_modern_cpp.h +++ b/hdr/sqlite_modern_cpp.h @@ -198,6 +198,57 @@ namespace sqlite { } bool used() const { return execution_started; } + template + class row_iterator { + public: + using difference_type = std::ptrdiff_t; + using value_type = std::tuple; + 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::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 + inline auto as() &; + template + inline auto as() &&; + private: std::shared_ptr _db; std::unique_ptr _stmt; @@ -372,6 +423,31 @@ namespace sqlite { } }; + template + class owning_row_view + { + public: + owning_row_view(database_binder &&binder): _binder(std::move(binder)) {} + auto begin() { return database_binder::row_iterator(_binder); } + auto end() { return database_binder::row_iterator(); } + private: + database_binder _binder; + }; + template + class row_view + { + public: + row_view(database_binder &binder): _binder(&binder) {} + auto begin() { return database_binder::row_iterator(*_binder); } + auto end() { return database_binder::row_iterator(); } + private: + database_binder *_binder; + }; + template + auto database_binder::as() & { return row_view(*this); } + template + auto database_binder::as() && { return owning_row_view(std::move(*this)); } + namespace sql_function_binder { template< typename ContextType, diff --git a/tests/readme_example.cc b/tests/readme_example.cc index e903a85f..1def5d24 100644 --- a/tests/readme_example.cc +++ b/tests/readme_example.cc @@ -49,6 +49,11 @@ 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()) { + 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 From 6835def37ee351a293f1a94f4d0986b3e6cdd7c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20Kr=C3=BCger?= Date: Tue, 28 Mar 2017 08:16:48 +0200 Subject: [PATCH 3/3] Alternative interface --- hdr/sqlite_modern_cpp.h | 5 +++++ tests/readme_example.cc | 6 ++++++ 2 files changed, 11 insertions(+) diff --git a/hdr/sqlite_modern_cpp.h b/hdr/sqlite_modern_cpp.h index b4d67ced..3fc46235 100644 --- a/hdr/sqlite_modern_cpp.h +++ b/hdr/sqlite_modern_cpp.h @@ -1174,4 +1174,9 @@ namespace sqlite { } } } + + template + auto as(database_binder &binder) { return row_view(binder); } + template + auto as(database_binder&&binder) { return owning_row_view(std::move(binder)); } } diff --git a/tests/readme_example.cc b/tests/readme_example.cc index 1def5d24..89083de8 100644 --- a/tests/readme_example.cc +++ b/tests/readme_example.cc @@ -55,6 +55,12 @@ int main() { cout << _age << ' ' << _name << ' ' << _weight << endl; } + for(auto &&[_age, _name, _weight] : as(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 int count = 0;