Skip to content

Commit ca95210

Browse files
authored
Merge pull request #1311 from fnc12/iterate_result_set
Iteration of result sets
2 parents 754710e + bc93e50 commit ca95210

21 files changed

+787
-200
lines changed

dev/column_result.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,15 @@ namespace sqlite_orm {
4242
* SFINAE - sfinae argument
4343
*/
4444
template<class DBOs, class T, class SFINAE = void>
45-
struct column_result_t;
45+
struct column_result_t {
46+
#ifdef __FUNCTION__
47+
// produce an error message that reveals `T` and `DBOs`
48+
static constexpr bool reveal() {
49+
static_assert(polyfill::always_false_v<T>, "T not found in DBOs - " __FUNCTION__);
50+
}
51+
static constexpr bool trigger = reveal();
52+
#endif
53+
};
4654

4755
template<class DBOs, class T>
4856
using column_result_of_t = typename column_result_t<DBOs, T>::type;

dev/column_result_proxy.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ namespace sqlite_orm {
3030
struct column_result_proxy<P, match_if<is_table_reference, P>> : decay_table_ref<P> {};
3131

3232
/*
33-
* Unwrap `structure`
33+
* Pass through `structure`
3434
*/
3535
template<class P>
3636
struct column_result_proxy<P, match_specialization_of<P, structure>> : P {};

dev/connection_holder.h

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -48,28 +48,33 @@ namespace sqlite_orm {
4848
};
4949

5050
struct connection_ref {
51-
connection_ref(connection_holder& holder_) : holder(holder_) {
52-
this->holder.retain();
51+
connection_ref(connection_holder& holder) : holder(&holder) {
52+
this->holder->retain();
5353
}
5454

5555
connection_ref(const connection_ref& other) : holder(other.holder) {
56-
this->holder.retain();
56+
this->holder->retain();
5757
}
5858

59-
connection_ref(connection_ref&& other) : holder(other.holder) {
60-
this->holder.retain();
59+
// rebind connection reference
60+
connection_ref operator=(const connection_ref& other) {
61+
if(other.holder != this->holder) {
62+
this->holder->release();
63+
this->holder = other.holder;
64+
this->holder->retain();
65+
}
6166
}
6267

6368
~connection_ref() {
64-
this->holder.release();
69+
this->holder->release();
6570
}
6671

6772
sqlite3* get() const {
68-
return this->holder.get();
73+
return this->holder->get();
6974
}
7075

71-
protected:
72-
connection_holder& holder;
76+
private:
77+
connection_holder* holder = nullptr;
7378
};
7479
}
7580
}

dev/cte_storage.h

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -322,13 +322,5 @@ namespace sqlite_orm {
322322
return make_recursive_cte_db_objects(dbObjects, e.cte, std::index_sequence_for<CTEs...>{});
323323
}
324324
#endif
325-
326-
/**
327-
* Return passed in DBOs.
328-
*/
329-
template<class DBOs, class E, satisfies<is_db_objects, DBOs> = true>
330-
decltype(auto) db_objects_for_expression(DBOs& dbObjects, const E&) {
331-
return dbObjects;
332-
}
333325
}
334326
}

dev/functional/config.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,18 @@
5858
#define SQLITE_ORM_CPP20_RANGES_SUPPORTED
5959
#endif
6060

61+
// C++20 or later (unfortunately there's no feature test macro).
62+
// Stupidly, clang says C++20, but `std::default_sentinel_t` was only implemented in libc++ 13 and libstd++-v3 10
63+
// (the latter is used on Linux).
64+
// gcc got it right and reports C++20 only starting with v10.
65+
// The check here doesn't care and checks the library versions in use.
66+
//
67+
// Another way of detection might be the feature-test macro __cpp_lib_concepts
68+
#if(__cplusplus >= 202002L) && \
69+
((!_LIBCPP_VERSION || _LIBCPP_VERSION >= 13000) && (!_GLIBCXX_RELEASE || _GLIBCXX_RELEASE >= 10))
70+
#define SQLITE_ORM_STL_HAS_DEFAULT_SENTINEL
71+
#endif
72+
6173
#if(defined(SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED) && defined(SQLITE_ORM_INLINE_VARIABLES_SUPPORTED) && \
6274
defined(SQLITE_ORM_CONSTEVAL_SUPPORTED)) && \
6375
(defined(SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED))

dev/functional/cxx_core_features.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@
4141
#define SQLITE_ORM_CONSTEXPR_LAMBDAS_SUPPORTED
4242
#endif
4343

44+
#if __cpp_range_based_for >= 201603L
45+
#define SQLITE_ORM_SENTINEL_BASED_FOR_SUPPORTED
46+
#endif
47+
4448
#if __cpp_if_constexpr >= 201606L
4549
#define SQLITE_ORM_IF_CONSTEXPR_SUPPORTED
4650
#endif

dev/functional/cxx_functional_polyfill.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ namespace sqlite_orm {
1717
// gcc got it right and reports C++20 only starting with v10.
1818
// The check here doesn't care and checks the library versions in use.
1919
//
20-
// Another way of detection would be the constrained algorithms feature macro __cpp_lib_ranges
20+
// Another way of detection would be the constrained algorithms feature-test macro __cpp_lib_ranges
2121
#if(__cplusplus >= 202002L) && \
2222
((!_LIBCPP_VERSION || _LIBCPP_VERSION >= 13000) && (!_GLIBCXX_RELEASE || _GLIBCXX_RELEASE >= 10))
2323
using std::identity;

dev/iterator.h renamed to dev/mapped_iterator.h

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ namespace sqlite_orm {
2121
* (Legacy) Input iterator over a result set for a mapped object.
2222
*/
2323
template<class O, class DBOs>
24-
class iterator_t {
24+
class mapped_iterator {
2525
public:
2626
using db_objects_type = DBOs;
2727

@@ -58,7 +58,7 @@ namespace sqlite_orm {
5858
}
5959

6060
void step() {
61-
perform_step(this->stmt.get(), std::bind(&iterator_t::extract_object, this));
61+
perform_step(this->stmt.get(), std::bind(&mapped_iterator::extract_object, this));
6262
if(!this->current) {
6363
this->stmt.reset();
6464
}
@@ -70,17 +70,17 @@ namespace sqlite_orm {
7070
}
7171

7272
public:
73-
iterator_t() = default;
73+
mapped_iterator() = default;
7474

75-
iterator_t(const db_objects_type& dbObjects, statement_finalizer stmt) :
75+
mapped_iterator(const db_objects_type& dbObjects, statement_finalizer stmt) :
7676
db_objects{&dbObjects}, stmt{std::move(stmt)} {
7777
this->step();
7878
}
7979

80-
iterator_t(const iterator_t&) = default;
81-
iterator_t& operator=(const iterator_t&) = default;
82-
iterator_t(iterator_t&&) = default;
83-
iterator_t& operator=(iterator_t&&) = default;
80+
mapped_iterator(const mapped_iterator&) = default;
81+
mapped_iterator& operator=(const mapped_iterator&) = default;
82+
mapped_iterator(mapped_iterator&&) = default;
83+
mapped_iterator& operator=(mapped_iterator&&) = default;
8484

8585
value_type& operator*() const {
8686
if(!this->stmt)
@@ -95,23 +95,23 @@ namespace sqlite_orm {
9595
return &(this->operator*());
9696
}
9797

98-
iterator_t& operator++() {
98+
mapped_iterator& operator++() {
9999
next();
100100
return *this;
101101
}
102102

103-
iterator_t operator++(int) {
103+
mapped_iterator operator++(int) {
104104
auto tmp = *this;
105105
++*this;
106106
return tmp;
107107
}
108108

109-
friend bool operator==(const iterator_t& lhs, const iterator_t& rhs) {
109+
friend bool operator==(const mapped_iterator& lhs, const mapped_iterator& rhs) {
110110
return lhs.current == rhs.current;
111111
}
112112

113113
#ifndef SQLITE_ORM_DEFAULT_COMPARISONS_SUPPORTED
114-
friend bool operator!=(const iterator_t& lhs, const iterator_t& rhs) {
114+
friend bool operator!=(const mapped_iterator& lhs, const mapped_iterator& rhs) {
115115
return !(lhs == rhs);
116116
}
117117
#endif

dev/view.h renamed to dev/mapped_view.h

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
#include <utility> // std::forward, std::move
55

66
#include "row_extractor.h"
7-
#include "iterator.h"
7+
#include "mapped_iterator.h"
88
#include "ast_iterator.h"
99
#include "prepared_statement.h"
1010
#include "connection_holder.h"
@@ -23,11 +23,11 @@ namespace sqlite_orm {
2323
* - iterator begin()
2424
* All these functions are not right const cause all of them may open SQLite connections.
2525
*
26-
* `view_t` is also a 'borrowed range',
26+
* `mapped_view` is also a 'borrowed range',
2727
* meaning that iterators obtained from it are not tied to the lifetime of the view instance.
2828
*/
2929
template<class T, class S, class... Args>
30-
struct view_t {
30+
struct mapped_view {
3131
using mapped_type = T;
3232
using storage_type = S;
3333
using db_objects_type = typename S::db_objects_type;
@@ -36,7 +36,7 @@ namespace sqlite_orm {
3636
connection_ref connection;
3737
get_all_t<T, void, Args...> expression;
3838

39-
view_t(storage_type& storage, connection_ref conn, Args&&... args) :
39+
mapped_view(storage_type& storage, connection_ref conn, Args&&... args) :
4040
storage(storage), connection(std::move(conn)), expression{std::forward<Args>(args)...} {}
4141

4242
size_t size() const {
@@ -47,7 +47,7 @@ namespace sqlite_orm {
4747
return !this->size();
4848
}
4949

50-
iterator_t<T, db_objects_type> begin() {
50+
mapped_iterator<T, db_objects_type> begin() {
5151
using context_t = serializer_context<db_objects_type>;
5252
auto& dbObjects = obtain_db_objects(this->storage);
5353
context_t context{dbObjects};
@@ -59,7 +59,7 @@ namespace sqlite_orm {
5959
return {dbObjects, std::move(stmt)};
6060
}
6161

62-
iterator_t<T, db_objects_type> end() {
62+
mapped_iterator<T, db_objects_type> end() {
6363
return {};
6464
}
6565
};
@@ -68,5 +68,5 @@ namespace sqlite_orm {
6868

6969
#ifdef SQLITE_ORM_CPP20_RANGES_SUPPORTED
7070
template<class T, class S, class... Args>
71-
inline constexpr bool std::ranges::enable_borrowed_range<sqlite_orm::internal::view_t<T, S, Args...>> = true;
71+
inline constexpr bool std::ranges::enable_borrowed_range<sqlite_orm::internal::mapped_view<T, S, Args...>> = true;
7272
#endif

dev/prepared_statement.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -628,9 +628,9 @@ namespace sqlite_orm {
628628
* T is an object type mapped to a storage.
629629
* Usage: get<User>(5);
630630
*/
631-
template<orm_table_reference auto als, class... Ids>
631+
template<orm_table_reference auto table, class... Ids>
632632
auto get(Ids... ids) {
633-
return get<internal::mapped_type_proxy_t<decltype(als)>>(std::forward<Ids>(ids)...);
633+
return get<internal::mapped_type_proxy_t<decltype(table)>>(std::forward<Ids>(ids)...);
634634
}
635635
#endif
636636

@@ -685,15 +685,15 @@ namespace sqlite_orm {
685685
#ifdef SQLITE_ORM_WITH_CPP20_ALIASES
686686
/**
687687
* Create a get all statement.
688-
* `als` is an explicitly specified table proxy of an object to be extracted.
688+
* `mapped` is an explicitly specified table reference or alias of an object to be extracted.
689689
* `R` is the container return type, which must have a `R::push_back(T&&)` method, and defaults to `std::vector<T>`
690690
* Usage: storage.get_all<sqlite_schema>(...);
691691
*/
692-
template<orm_refers_to_table auto als,
693-
class R = std::vector<internal::mapped_type_proxy_t<decltype(als)>>,
692+
template<orm_refers_to_table auto mapped,
693+
class R = std::vector<internal::mapped_type_proxy_t<decltype(mapped)>>,
694694
class... Args>
695695
auto get_all(Args&&... conditions) {
696-
return get_all<internal::auto_decay_table_ref_t<als>, R>(std::forward<Args>(conditions)...);
696+
return get_all<internal::auto_decay_table_ref_t<mapped>, R>(std::forward<Args>(conditions)...);
697697
}
698698
#endif
699699

dev/result_set_iterator.h

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
#pragma once
2+
3+
#include <sqlite3.h>
4+
#include <utility> // std::move
5+
#include <iterator> // std::input_iterator_tag, std::default_sentinel_t
6+
#include <functional> // std::reference_wrapper
7+
8+
#include "functional/cxx_universal.h" // ::ptrdiff_t
9+
#include "statement_finalizer.h"
10+
#include "row_extractor.h"
11+
#include "column_result_proxy.h"
12+
#include "util.h"
13+
14+
#if defined(SQLITE_ORM_SENTINEL_BASED_FOR_SUPPORTED) && defined(SQLITE_ORM_DEFAULT_COMPARISONS_SUPPORTED)
15+
namespace sqlite_orm::internal {
16+
17+
template<class ColResult, class DBOs>
18+
class result_set_iterator;
19+
20+
#ifdef SQLITE_ORM_STL_HAS_DEFAULT_SENTINEL
21+
using result_set_sentinel_t = std::default_sentinel_t;
22+
#else
23+
// sentinel
24+
template<>
25+
class result_set_iterator<void, void> {};
26+
27+
using result_set_sentinel_t = result_set_iterator<void, void>;
28+
#endif
29+
30+
/*
31+
* Input iterator over a result set for a select statement.
32+
*/
33+
template<class ColResult, class DBOs>
34+
class result_set_iterator {
35+
public:
36+
using db_objects_type = DBOs;
37+
38+
#ifdef SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED
39+
using iterator_concept = std::input_iterator_tag;
40+
#else
41+
using iterator_category = std::input_iterator_tag;
42+
#endif
43+
using difference_type = ptrdiff_t;
44+
using value_type = column_result_proxy_t<ColResult>;
45+
46+
public:
47+
result_set_iterator(const db_objects_type& dbObjects, statement_finalizer stmt) :
48+
db_objects{dbObjects}, stmt{std::move(stmt)} {
49+
this->step();
50+
}
51+
result_set_iterator(result_set_iterator&&) = default;
52+
result_set_iterator& operator=(result_set_iterator&&) = default;
53+
result_set_iterator(const result_set_iterator&) = delete;
54+
result_set_iterator& operator=(const result_set_iterator&) = delete;
55+
56+
/** @pre `*this != std::default_sentinel` */
57+
value_type operator*() const {
58+
return this->extract();
59+
}
60+
61+
result_set_iterator& operator++() {
62+
this->step();
63+
return *this;
64+
}
65+
66+
void operator++(int) {
67+
++*this;
68+
}
69+
70+
friend bool operator==(const result_set_iterator& it, const result_set_sentinel_t&) noexcept {
71+
return sqlite3_data_count(it.stmt.get()) == 0;
72+
}
73+
74+
private:
75+
void step() {
76+
perform_step(this->stmt.get(), [](sqlite3_stmt*) {});
77+
}
78+
79+
value_type extract() const {
80+
const auto rowExtractor = make_row_extractor<ColResult>(this->db_objects.get());
81+
return rowExtractor.extract(this->stmt.get(), 0);
82+
}
83+
84+
private:
85+
std::reference_wrapper<const db_objects_type> db_objects;
86+
statement_finalizer stmt;
87+
};
88+
}
89+
#endif

0 commit comments

Comments
 (0)