Skip to content
Merged
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
10 changes: 9 additions & 1 deletion dev/column_result.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,15 @@ namespace sqlite_orm {
* SFINAE - sfinae argument
*/
template<class DBOs, class T, class SFINAE = void>
struct column_result_t;
struct column_result_t {
#ifdef __FUNCTION__
// produce an error message that reveals `T` and `DBOs`
static constexpr bool reveal() {
static_assert(polyfill::always_false_v<T>, "T not found in DBOs - " __FUNCTION__);
}
static constexpr bool trigger = reveal();
#endif
};

template<class DBOs, class T>
using column_result_of_t = typename column_result_t<DBOs, T>::type;
Expand Down
2 changes: 1 addition & 1 deletion dev/column_result_proxy.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ namespace sqlite_orm {
struct column_result_proxy<P, match_if<is_table_reference, P>> : decay_table_ref<P> {};

/*
* Unwrap `structure`
* Pass through `structure`
*/
template<class P>
struct column_result_proxy<P, match_specialization_of<P, structure>> : P {};
Expand Down
23 changes: 14 additions & 9 deletions dev/connection_holder.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,28 +48,33 @@ namespace sqlite_orm {
};

struct connection_ref {
connection_ref(connection_holder& holder_) : holder(holder_) {
this->holder.retain();
connection_ref(connection_holder& holder) : holder(&holder) {
this->holder->retain();
}

connection_ref(const connection_ref& other) : holder(other.holder) {
this->holder.retain();
this->holder->retain();
}

connection_ref(connection_ref&& other) : holder(other.holder) {
this->holder.retain();
// rebind connection reference
connection_ref operator=(const connection_ref& other) {
if(other.holder != this->holder) {
this->holder->release();
this->holder = other.holder;
this->holder->retain();
}
}

~connection_ref() {
this->holder.release();
this->holder->release();
}

sqlite3* get() const {
return this->holder.get();
return this->holder->get();
}

protected:
connection_holder& holder;
private:
connection_holder* holder = nullptr;
};
}
}
8 changes: 0 additions & 8 deletions dev/cte_storage.h
Original file line number Diff line number Diff line change
Expand Up @@ -322,13 +322,5 @@ namespace sqlite_orm {
return make_recursive_cte_db_objects(dbObjects, e.cte, std::index_sequence_for<CTEs...>{});
}
#endif

/**
* Return passed in DBOs.
*/
template<class DBOs, class E, satisfies<is_db_objects, DBOs> = true>
decltype(auto) db_objects_for_expression(DBOs& dbObjects, const E&) {
return dbObjects;
}
}
}
12 changes: 12 additions & 0 deletions dev/functional/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,18 @@
#define SQLITE_ORM_CPP20_RANGES_SUPPORTED
#endif

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

#if(defined(SQLITE_ORM_CLASSTYPE_TEMPLATE_ARGS_SUPPORTED) && defined(SQLITE_ORM_INLINE_VARIABLES_SUPPORTED) && \
defined(SQLITE_ORM_CONSTEVAL_SUPPORTED)) && \
(defined(SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED))
Expand Down
4 changes: 4 additions & 0 deletions dev/functional/cxx_core_features.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@
#define SQLITE_ORM_CONSTEXPR_LAMBDAS_SUPPORTED
#endif

#if __cpp_range_based_for >= 201603L
#define SQLITE_ORM_SENTINEL_BASED_FOR_SUPPORTED
#endif

#if __cpp_if_constexpr >= 201606L
#define SQLITE_ORM_IF_CONSTEXPR_SUPPORTED
#endif
Expand Down
2 changes: 1 addition & 1 deletion dev/functional/cxx_functional_polyfill.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ namespace sqlite_orm {
// gcc got it right and reports C++20 only starting with v10.
// The check here doesn't care and checks the library versions in use.
//
// Another way of detection would be the constrained algorithms feature macro __cpp_lib_ranges
// Another way of detection would be the constrained algorithms feature-test macro __cpp_lib_ranges
#if(__cplusplus >= 202002L) && \
((!_LIBCPP_VERSION || _LIBCPP_VERSION >= 13000) && (!_GLIBCXX_RELEASE || _GLIBCXX_RELEASE >= 10))
using std::identity;
Expand Down
24 changes: 12 additions & 12 deletions dev/iterator.h → dev/mapped_iterator.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ namespace sqlite_orm {
* (Legacy) Input iterator over a result set for a mapped object.
*/
template<class O, class DBOs>
class iterator_t {
class mapped_iterator {
public:
using db_objects_type = DBOs;

Expand Down Expand Up @@ -58,7 +58,7 @@ namespace sqlite_orm {
}

void step() {
perform_step(this->stmt.get(), std::bind(&iterator_t::extract_object, this));
perform_step(this->stmt.get(), std::bind(&mapped_iterator::extract_object, this));
if(!this->current) {
this->stmt.reset();
}
Expand All @@ -70,17 +70,17 @@ namespace sqlite_orm {
}

public:
iterator_t() = default;
mapped_iterator() = default;

iterator_t(const db_objects_type& dbObjects, statement_finalizer stmt) :
mapped_iterator(const db_objects_type& dbObjects, statement_finalizer stmt) :
db_objects{&dbObjects}, stmt{std::move(stmt)} {
this->step();
}

iterator_t(const iterator_t&) = default;
iterator_t& operator=(const iterator_t&) = default;
iterator_t(iterator_t&&) = default;
iterator_t& operator=(iterator_t&&) = default;
mapped_iterator(const mapped_iterator&) = default;
mapped_iterator& operator=(const mapped_iterator&) = default;
mapped_iterator(mapped_iterator&&) = default;
mapped_iterator& operator=(mapped_iterator&&) = default;

value_type& operator*() const {
if(!this->stmt)
Expand All @@ -95,23 +95,23 @@ namespace sqlite_orm {
return &(this->operator*());
}

iterator_t& operator++() {
mapped_iterator& operator++() {
next();
return *this;
}

iterator_t operator++(int) {
mapped_iterator operator++(int) {
auto tmp = *this;
++*this;
return tmp;
}

friend bool operator==(const iterator_t& lhs, const iterator_t& rhs) {
friend bool operator==(const mapped_iterator& lhs, const mapped_iterator& rhs) {
return lhs.current == rhs.current;
}

#ifndef SQLITE_ORM_DEFAULT_COMPARISONS_SUPPORTED
friend bool operator!=(const iterator_t& lhs, const iterator_t& rhs) {
friend bool operator!=(const mapped_iterator& lhs, const mapped_iterator& rhs) {
return !(lhs == rhs);
}
#endif
Expand Down
14 changes: 7 additions & 7 deletions dev/view.h → dev/mapped_view.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#include <utility> // std::forward, std::move

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

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

size_t size() const {
Expand All @@ -47,7 +47,7 @@ namespace sqlite_orm {
return !this->size();
}

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

iterator_t<T, db_objects_type> end() {
mapped_iterator<T, db_objects_type> end() {
return {};
}
};
Expand All @@ -68,5 +68,5 @@ namespace sqlite_orm {

#ifdef SQLITE_ORM_CPP20_RANGES_SUPPORTED
template<class T, class S, class... Args>
inline constexpr bool std::ranges::enable_borrowed_range<sqlite_orm::internal::view_t<T, S, Args...>> = true;
inline constexpr bool std::ranges::enable_borrowed_range<sqlite_orm::internal::mapped_view<T, S, Args...>> = true;
#endif
12 changes: 6 additions & 6 deletions dev/prepared_statement.h
Original file line number Diff line number Diff line change
Expand Up @@ -628,9 +628,9 @@ namespace sqlite_orm {
* T is an object type mapped to a storage.
* Usage: get<User>(5);
*/
template<orm_table_reference auto als, class... Ids>
template<orm_table_reference auto table, class... Ids>
auto get(Ids... ids) {
return get<internal::mapped_type_proxy_t<decltype(als)>>(std::forward<Ids>(ids)...);
return get<internal::mapped_type_proxy_t<decltype(table)>>(std::forward<Ids>(ids)...);
}
#endif

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

Expand Down
89 changes: 89 additions & 0 deletions dev/result_set_iterator.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
#pragma once

#include <sqlite3.h>
#include <utility> // std::move
#include <iterator> // std::input_iterator_tag, std::default_sentinel_t
#include <functional> // std::reference_wrapper

#include "functional/cxx_universal.h" // ::ptrdiff_t
#include "statement_finalizer.h"
#include "row_extractor.h"
#include "column_result_proxy.h"
#include "util.h"

#if defined(SQLITE_ORM_SENTINEL_BASED_FOR_SUPPORTED) && defined(SQLITE_ORM_DEFAULT_COMPARISONS_SUPPORTED)
namespace sqlite_orm::internal {

template<class ColResult, class DBOs>
class result_set_iterator;

#ifdef SQLITE_ORM_STL_HAS_DEFAULT_SENTINEL
using result_set_sentinel_t = std::default_sentinel_t;
#else
// sentinel
template<>
class result_set_iterator<void, void> {};

using result_set_sentinel_t = result_set_iterator<void, void>;
#endif

/*
* Input iterator over a result set for a select statement.
*/
template<class ColResult, class DBOs>
class result_set_iterator {
public:
using db_objects_type = DBOs;

#ifdef SQLITE_ORM_CPP20_CONCEPTS_SUPPORTED
using iterator_concept = std::input_iterator_tag;
#else
using iterator_category = std::input_iterator_tag;
#endif
using difference_type = ptrdiff_t;
using value_type = column_result_proxy_t<ColResult>;

public:
result_set_iterator(const db_objects_type& dbObjects, statement_finalizer stmt) :
db_objects{dbObjects}, stmt{std::move(stmt)} {
this->step();
}
result_set_iterator(result_set_iterator&&) = default;
result_set_iterator& operator=(result_set_iterator&&) = default;
result_set_iterator(const result_set_iterator&) = delete;
result_set_iterator& operator=(const result_set_iterator&) = delete;

/** @pre `*this != std::default_sentinel` */
value_type operator*() const {
return this->extract();
}

result_set_iterator& operator++() {
this->step();
return *this;
}

void operator++(int) {
++*this;
}

friend bool operator==(const result_set_iterator& it, const result_set_sentinel_t&) noexcept {
return sqlite3_data_count(it.stmt.get()) == 0;
}

private:
void step() {
perform_step(this->stmt.get(), [](sqlite3_stmt*) {});
}

value_type extract() const {
const auto rowExtractor = make_row_extractor<ColResult>(this->db_objects.get());
return rowExtractor.extract(this->stmt.get(), 0);
}

private:
std::reference_wrapper<const db_objects_type> db_objects;
statement_finalizer stmt;
};
}
#endif
Loading