From 3769f50501e4ec6654b44d5a802cf085f2d85c7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dr=2E=20Patrick=20Urbanke=20=28=E5=8A=89=E8=87=AA=E6=88=90?= =?UTF-8?q?=29?= Date: Tue, 7 Oct 2025 23:51:15 +0200 Subject: [PATCH] Refactor iterators to make sure we can use them for DuckDB (#60) --- docs/reading.md | 2 +- docs/select_from.md | 2 +- include/sqlgen/Range.hpp | 29 ++++++--- include/sqlgen/Session.hpp | 5 +- include/sqlgen/Transaction.hpp | 5 +- include/sqlgen/internal/MockTable.hpp | 15 +++++ include/sqlgen/internal/is_range.hpp | 4 +- include/sqlgen/internal/iterator_t.hpp | 26 ++++++++ include/sqlgen/internal/to_container.hpp | 35 ++++++++++ include/sqlgen/is_connection.hpp | 5 +- include/sqlgen/mysql/Connection.hpp | 12 +++- include/sqlgen/postgres/Connection.hpp | 11 +++- include/sqlgen/read.hpp | 64 ++++++------------- include/sqlgen/select_from.hpp | 22 ++++--- include/sqlgen/sqlite/Connection.hpp | 12 +++- src/sqlgen/mysql/Connection.cpp | 3 +- src/sqlgen/postgres/Connection.cpp | 3 +- src/sqlgen/sqlite/Connection.cpp | 3 +- tests/mysql/test_group_by.cpp | 3 - tests/mysql/test_group_by_with_operations.cpp | 3 - tests/mysql/test_join.cpp | 3 - tests/mysql/test_range.cpp | 3 - tests/mysql/test_range_select_from.cpp | 3 - tests/mysql/test_select_from_with_to.cpp | 3 - tests/postgres/test_group_by.cpp | 3 - .../test_group_by_with_operations.cpp | 3 - tests/postgres/test_join.cpp | 3 - tests/postgres/test_range.cpp | 3 - tests/postgres/test_range_select_from.cpp | 3 - tests/postgres/test_select_from_with_to.cpp | 3 - tests/sqlite/test_range.cpp | 3 - 31 files changed, 180 insertions(+), 117 deletions(-) create mode 100644 include/sqlgen/internal/MockTable.hpp create mode 100644 include/sqlgen/internal/iterator_t.hpp create mode 100644 include/sqlgen/internal/to_container.hpp diff --git a/docs/reading.md b/docs/reading.md index 25dc1f2..73e74d3 100644 --- a/docs/reading.md +++ b/docs/reading.md @@ -109,7 +109,7 @@ for (const sqlgen::Result& person : people_range) { } ``` -`sqlgen::Range` satisfies the `std::ranges::input_range` concept, making it compatible with C++20 ranges and views. This allows for memory-efficient iteration through database results and enables composition with other range operations: +`people_range` satisfies the `std::ranges::input_range` concept, making it compatible with C++20 ranges and views. This allows for memory-efficient iteration through database results and enables composition with other range operations: ```cpp using namespace std::ranges::views; diff --git a/docs/select_from.md b/docs/select_from.md index 7ab31e9..35dd034 100644 --- a/docs/select_from.md +++ b/docs/select_from.md @@ -172,7 +172,7 @@ const auto people_vec = query | to>; const auto person = query | to; // Return as Range (lazy evaluation) -const auto people_range = query; // Returns Range by default +const auto people_range = query; // Returns Range<...> by default ``` ### Automatic Type Deduction diff --git a/include/sqlgen/Range.hpp b/include/sqlgen/Range.hpp index 543a2cc..de7203d 100644 --- a/include/sqlgen/Range.hpp +++ b/include/sqlgen/Range.hpp @@ -9,29 +9,38 @@ namespace sqlgen { +template +class Range; + +/// This exists mainly for user-friendliness: We want people to be able +/// to pass Range to read without having to worry about connector-specific +/// iterators. +template +struct Range { + using value_type = Result; +}; + /// This class is meant to provide a way to iterate through the data in the /// database efficiently that is compatible with std::ranges. -template -class Range { +template + requires std::input_iterator +class Range { public: - using value_type = Result; - - static_assert(std::input_iterator>, - "This must be an input iterator."); + using value_type = typename IteratorType::value_type; struct End {}; - Range(const Ref& _it) : it_(_it) {} + Range(const IteratorType& _it) : it_(_it) {} ~Range() = default; - auto begin() const { return Iterator(it_); } + auto begin() const { return it_; } - auto end() const { return typename Iterator::End{}; } + auto end() const { return typename IteratorType::End{}; } private: /// The underlying database iterator. - Ref it_; + IteratorType it_; }; } // namespace sqlgen diff --git a/include/sqlgen/Session.hpp b/include/sqlgen/Session.hpp index 8be4a5b..6d22dc4 100644 --- a/include/sqlgen/Session.hpp +++ b/include/sqlgen/Session.hpp @@ -62,8 +62,9 @@ class Session { return *this; } - Result> read(const dynamic::SelectFrom& _query) { - return conn_->read(_query); + template + Result read(const dynamic::SelectFrom& _query) { + return conn_->template read(_query); } Result rollback() noexcept { return conn_->rollback(); } diff --git a/include/sqlgen/Transaction.hpp b/include/sqlgen/Transaction.hpp index 7bd51f9..4f0d67e 100644 --- a/include/sqlgen/Transaction.hpp +++ b/include/sqlgen/Transaction.hpp @@ -73,8 +73,9 @@ class Transaction { return *this; } - Result> read(const dynamic::SelectFrom& _query) { - return conn_->read(_query); + template + Result read(const dynamic::SelectFrom& _query) { + return conn_->template read(_query); } Result rollback() noexcept { diff --git a/include/sqlgen/internal/MockTable.hpp b/include/sqlgen/internal/MockTable.hpp new file mode 100644 index 0000000..181170e --- /dev/null +++ b/include/sqlgen/internal/MockTable.hpp @@ -0,0 +1,15 @@ +#ifndef SQLGEN_INTERNAL_MOCKTABLE_HPP_ +#define SQLGEN_INTERNAL_MOCKTABLE_HPP_ + +#include + +namespace sqlgen::internal { + +struct MockTable { + std::string field1; + int field2; +}; + +} // namespace sqlgen::internal + +#endif diff --git a/include/sqlgen/internal/is_range.hpp b/include/sqlgen/internal/is_range.hpp index 727fcba..ecede82 100644 --- a/include/sqlgen/internal/is_range.hpp +++ b/include/sqlgen/internal/is_range.hpp @@ -13,8 +13,8 @@ class is_range; template class is_range : public std::false_type {}; -template -class is_range> : public std::true_type {}; +template +class is_range> : public std::true_type {}; template constexpr bool is_range_v = is_range(); diff --git a/include/sqlgen/internal/iterator_t.hpp b/include/sqlgen/internal/iterator_t.hpp new file mode 100644 index 0000000..9e192f2 --- /dev/null +++ b/include/sqlgen/internal/iterator_t.hpp @@ -0,0 +1,26 @@ +#ifndef SQLGEN_TRANSPILATION_ITERATOR_T_HPP_ +#define SQLGEN_TRANSPILATION_ITERATOR_T_HPP_ + +#include + +#include "../Iterator.hpp" + +namespace sqlgen::internal { + +template +struct IteratorType; + +/// Most database connectors can just use the standard iterator type, but +/// sometimes we need exception, in which case this template can be overridden. +template +struct IteratorType { + using Type = Iterator; +}; + +template +using iterator_t = typename IteratorType, + std::remove_cvref_t>::Type; + +} // namespace sqlgen::internal + +#endif diff --git a/include/sqlgen/internal/to_container.hpp b/include/sqlgen/internal/to_container.hpp new file mode 100644 index 0000000..852ef6f --- /dev/null +++ b/include/sqlgen/internal/to_container.hpp @@ -0,0 +1,35 @@ +#ifndef SQLGEN_INTERNAL_TOCONTAINER_HPP_ +#define SQLGEN_INTERNAL_TOCONTAINER_HPP_ + +#include "../Range.hpp" +#include "../Ref.hpp" +#include "../Result.hpp" +#include "../transpilation/value_t.hpp" +#include "is_range.hpp" + +namespace sqlgen::internal { + +template +auto to_container(const Result& _res) { + if constexpr (internal::is_range_v) { + return _res.transform([](auto&& _it) { return Range(_it); }); + + } else { + return to_container>(_res).and_then( + [](auto range) -> Result { + ContainerType container; + for (auto& res : range) { + if (res) { + container.emplace_back(std::move(*res)); + } else { + return error(res.error().what()); + } + } + return container; + }); + } +} + +} // namespace sqlgen::internal + +#endif diff --git a/include/sqlgen/is_connection.hpp b/include/sqlgen/is_connection.hpp index a3cc0b3..2102b59 100644 --- a/include/sqlgen/is_connection.hpp +++ b/include/sqlgen/is_connection.hpp @@ -12,6 +12,7 @@ #include "dynamic/SelectFrom.hpp" #include "dynamic/Statement.hpp" #include "dynamic/Write.hpp" +#include "internal/MockTable.hpp" namespace sqlgen { @@ -36,7 +37,9 @@ concept is_connection = { c.insert(_insert, _data) } -> std::same_as>; /// Reads the results of a SelectFrom statement. - { c.read(_select_from) } -> std::same_as>>; + { + c.template read>(_select_from) + } -> std::same_as>>; /// Commits a transaction. { c.rollback() } -> std::same_as>; diff --git a/include/sqlgen/mysql/Connection.hpp b/include/sqlgen/mysql/Connection.hpp index 20be988..d66e2d6 100644 --- a/include/sqlgen/mysql/Connection.hpp +++ b/include/sqlgen/mysql/Connection.hpp @@ -8,6 +8,7 @@ #include #include +#include "../Iterator.hpp" #include "../IteratorBase.hpp" #include "../Ref.hpp" #include "../Result.hpp" @@ -15,7 +16,9 @@ #include "../dynamic/Column.hpp" #include "../dynamic/Statement.hpp" #include "../dynamic/Write.hpp" +#include "../internal/to_container.hpp" #include "../is_connection.hpp" +#include "../transpilation/value_t.hpp" #include "Credentials.hpp" #include "exec.hpp" #include "to_sql.hpp" @@ -50,7 +53,12 @@ class Connection { const std::vector>>& _data) noexcept; - Result> read(const dynamic::SelectFrom& _query); + template + auto read(const dynamic::SelectFrom& _query) { + using ValueType = transpilation::value_t; + return internal::to_container(read_impl(_query).transform( + [](auto&& _it) { return Iterator(std::move(_it)); })); + } Result rollback() noexcept { return execute("ROLLBACK;"); } @@ -78,6 +86,8 @@ class Connection { const std::variant& _stmt) const noexcept; + Result> read_impl(const dynamic::SelectFrom& _query); + private: /// A prepared statement - needed for the read and write operations. Note that /// we have declared it before conn_, meaning it will be destroyed first. diff --git a/include/sqlgen/postgres/Connection.hpp b/include/sqlgen/postgres/Connection.hpp index 72ece45..ff91011 100644 --- a/include/sqlgen/postgres/Connection.hpp +++ b/include/sqlgen/postgres/Connection.hpp @@ -15,7 +15,9 @@ #include "../dynamic/Column.hpp" #include "../dynamic/Statement.hpp" #include "../dynamic/Write.hpp" +#include "../internal/to_container.hpp" #include "../is_connection.hpp" +#include "../transpilation/value_t.hpp" #include "Credentials.hpp" #include "exec.hpp" #include "to_sql.hpp" @@ -47,7 +49,12 @@ class Connection { const std::vector>>& _data) noexcept; - Result> read(const dynamic::SelectFrom& _query); + template + auto read(const dynamic::SelectFrom& _query) { + using ValueType = transpilation::value_t; + return internal::to_container(read_impl(_query).transform( + [](auto&& _it) { return Iterator(std::move(_it)); })); + } Result rollback() noexcept; @@ -67,6 +74,8 @@ class Connection { private: static ConnPtr make_conn(const std::string& _conn_str); + Result> read_impl(const dynamic::SelectFrom& _query); + std::string to_buffer( const std::vector>& _line) const noexcept; diff --git a/include/sqlgen/read.hpp b/include/sqlgen/read.hpp index c7c50eb..983ab57 100644 --- a/include/sqlgen/read.hpp +++ b/include/sqlgen/read.hpp @@ -4,7 +4,6 @@ #include #include -#include "Range.hpp" #include "Ref.hpp" #include "Result.hpp" #include "internal/is_range.hpp" @@ -21,42 +20,20 @@ namespace sqlgen { template requires is_connection -Result read_impl(const Ref& _conn, - const WhereType& _where, - const LimitType& _limit) { +auto read_impl(const Ref& _conn, const WhereType& _where, + const LimitType& _limit) { using ValueType = transpilation::value_t; - if constexpr (internal::is_range_v) { - const auto query = - transpilation::read_to_select_from(_where, _limit); - return _conn->read(query).transform( - [](auto&& _it) { return ContainerType(_it); }); - - } else { - const auto to_container = [](auto range) -> Result { - ContainerType container; - for (auto& res : range) { - if (res) { - container.emplace_back(std::move(*res)); - } else { - return error(res.error().what()); - } - } - return container; - }; - - return read_impl, WhereType, OrderByType, LimitType>( - _conn, _where, _limit) - .and_then(to_container); - } + const auto query = + transpilation::read_to_select_from(_where, _limit); + return _conn->template read(query); } template requires is_connection -Result read_impl(const Result>& _res, - const WhereType& _where, - const LimitType& _limit) { +auto read_impl(const Result>& _res, const WhereType& _where, + const LimitType& _limit) { return _res.and_then([&](const auto& _conn) { return read_impl( _conn, _where, _limit); @@ -66,25 +43,24 @@ Result read_impl(const Result>& _res, template struct Read { - Result operator()(const auto& _conn) const { - if constexpr (std::ranges::input_range>) { + auto operator()(const auto& _conn) const { + if constexpr (std::ranges::input_range> || + internal::is_range_v) { return read_impl(_conn, where_, limit_); } else { - const auto extract_result = [](auto&& _vec) -> Result { - if (_vec.size() != 1) { - return error( - "Because the provided type was not a container, the query " - "needs to return exactly one result, but it did return " + - std::to_string(_vec.size()) + " results."); - } - return std::move(_vec[0]); - }; - return read_impl, WhereType, OrderByType, LimitType>( _conn, where_, limit_) - .and_then(extract_result); + .and_then([](auto&& _vec) -> Result { + if (_vec.size() != 1) { + return error( + "Because the provided type was not a container, the query " + "needs to return exactly one result, but it did return " + + std::to_string(_vec.size()) + " results."); + } + return std::move(_vec[0]); + }); } } diff --git a/include/sqlgen/select_from.hpp b/include/sqlgen/select_from.hpp index 9c98f7b..8c145b2 100644 --- a/include/sqlgen/select_from.hpp +++ b/include/sqlgen/select_from.hpp @@ -14,6 +14,7 @@ #include "group_by.hpp" #include "internal/GetColType.hpp" #include "internal/is_range.hpp" +#include "internal/iterator_t.hpp" #include "is_connection.hpp" #include "limit.hpp" #include "order_by.hpp" @@ -46,8 +47,7 @@ auto select_from_impl(const Ref& _conn, const FieldsType& _fields, TableOrQueryType, JoinsType, WhereType, GroupByType, OrderByType, LimitType>( _fields, _table_or_query, _joins, _where, _limit); - return _conn->read(query).transform( - [](auto&& _it) { return ContainerType(_it); }); + return _conn->template read(query); } else { const auto to_container = [](auto range) -> Result { @@ -64,8 +64,11 @@ auto select_from_impl(const Ref& _conn, const FieldsType& _fields, return container; }; - using RangeType = Range< - transpilation::fields_to_named_tuple_t>; + using IteratorType = internal::iterator_t< + transpilation::fields_to_named_tuple_t, + decltype(_conn)>; + + using RangeType = Range; return select_from_impl || std::ranges::input_range>) { - using ContainerType = - std::conditional_t, - Range>, - ToType>; + using IteratorType = internal::iterator_t< + transpilation::fields_to_named_tuple_t, + decltype(_conn)>; + + using ContainerType = std::conditional_t, + Range, ToType>; return select_from_impl< TableTupleType, AliasType, FieldsType, TableOrQueryType, JoinsType, WhereType, GroupByType, OrderByType, LimitType, ContainerType>( diff --git a/include/sqlgen/sqlite/Connection.hpp b/include/sqlgen/sqlite/Connection.hpp index 42a73ad..5734f25 100644 --- a/include/sqlgen/sqlite/Connection.hpp +++ b/include/sqlgen/sqlite/Connection.hpp @@ -14,7 +14,9 @@ #include "../Result.hpp" #include "../Transaction.hpp" #include "../dynamic/Write.hpp" +#include "../internal/to_container.hpp" #include "../is_connection.hpp" +#include "../transpilation/value_t.hpp" #include "to_sql.hpp" namespace sqlgen::sqlite { @@ -42,7 +44,12 @@ class Connection { const std::vector>>& _data) noexcept; - Result> read(const dynamic::SelectFrom& _query); + template + auto read(const dynamic::SelectFrom& _query) { + using ValueType = transpilation::value_t; + return internal::to_container(read_impl(_query).transform( + [](auto&& _it) { return Iterator(std::move(_it)); })); + } Result rollback() noexcept; @@ -70,6 +77,9 @@ class Connection { /// Generates a prepared statment, usually for inserts. Result prepare_statement(const std::string& _sql) const noexcept; + /// Implements the actual read. + Result> read_impl(const dynamic::SelectFrom& _query); + private: /// A prepared statement - needed for the read and write operations. Note that /// we have declared it before conn_, meaning it will be destroyed first. diff --git a/src/sqlgen/mysql/Connection.cpp b/src/sqlgen/mysql/Connection.cpp index d90eb0c..3443cfa 100644 --- a/src/sqlgen/mysql/Connection.cpp +++ b/src/sqlgen/mysql/Connection.cpp @@ -122,7 +122,8 @@ Result Connection::prepare_statement( return stmt_ptr; } -Result> Connection::read(const dynamic::SelectFrom& _query) { +Result> Connection::read_impl( + const dynamic::SelectFrom& _query) { const auto sql = mysql::to_sql_impl(_query); const auto err = mysql_real_query(conn_.get(), sql.c_str(), static_cast(sql.size())); diff --git a/src/sqlgen/postgres/Connection.cpp b/src/sqlgen/postgres/Connection.cpp index a983565..f8c90da 100644 --- a/src/sqlgen/postgres/Connection.cpp +++ b/src/sqlgen/postgres/Connection.cpp @@ -107,7 +107,8 @@ typename Connection::ConnPtr Connection::make_conn( return ConnPtr::make(std::shared_ptr(raw_ptr, &PQfinish)).value(); } -Result> Connection::read(const dynamic::SelectFrom& _query) { +Result> Connection::read_impl( + const dynamic::SelectFrom& _query) { const auto sql = postgres::to_sql_impl(_query); try { return Ref(Ref::make(sql, conn_)); diff --git a/src/sqlgen/sqlite/Connection.cpp b/src/sqlgen/sqlite/Connection.cpp index cea1c6c..7d73e78 100644 --- a/src/sqlgen/sqlite/Connection.cpp +++ b/src/sqlgen/sqlite/Connection.cpp @@ -97,7 +97,8 @@ typename Connection::ConnPtr Connection::make_conn(const std::string& _fname) { return ConnPtr::make(std::shared_ptr(conn, &sqlite3_close)).value(); } -Result> Connection::read(const dynamic::SelectFrom& _query) { +Result> Connection::read_impl( + const dynamic::SelectFrom& _query) { const auto sql = to_sql_impl(_query); sqlite3_stmt* p_stmt = nullptr; diff --git a/tests/mysql/test_group_by.cpp b/tests/mysql/test_group_by.cpp index 86c6ad4..d20fef3 100644 --- a/tests/mysql/test_group_by.cpp +++ b/tests/mysql/test_group_by.cpp @@ -19,9 +19,6 @@ struct Person { }; TEST(mysql, test_group_by) { - static_assert(std::ranges::input_range>, - "Must be an input range."); - const auto people1 = std::vector( {Person{ .id = 0, .first_name = "Homer", .last_name = "Simpson", .age = 45}, diff --git a/tests/mysql/test_group_by_with_operations.cpp b/tests/mysql/test_group_by_with_operations.cpp index a03c67b..1e40308 100644 --- a/tests/mysql/test_group_by_with_operations.cpp +++ b/tests/mysql/test_group_by_with_operations.cpp @@ -19,9 +19,6 @@ struct Person { }; TEST(mysql, test_group_by_with_operations) { - static_assert(std::ranges::input_range>, - "Must be an input range."); - const auto people1 = std::vector( {Person{ .id = 0, .first_name = "Homer", .last_name = "Simpson", .age = 45}, diff --git a/tests/mysql/test_join.cpp b/tests/mysql/test_join.cpp index a3615a9..13fe86d 100644 --- a/tests/mysql/test_join.cpp +++ b/tests/mysql/test_join.cpp @@ -19,9 +19,6 @@ struct Person { }; TEST(mysql, test_join) { - static_assert(std::ranges::input_range>, - "Must be an input range."); - const auto people1 = std::vector( {Person{ .id = 0, .first_name = "Homer", .last_name = "Simpson", .age = 45}, diff --git a/tests/mysql/test_range.cpp b/tests/mysql/test_range.cpp index eedf739..2accd13 100644 --- a/tests/mysql/test_range.cpp +++ b/tests/mysql/test_range.cpp @@ -19,9 +19,6 @@ struct Person { }; TEST(mysql, test_range) { - static_assert(std::ranges::input_range>, - "Must be an input range."); - const auto people1 = std::vector( {Person{ .id = 0, .first_name = "Homer", .last_name = "Simpson", .age = 45}, diff --git a/tests/mysql/test_range_select_from.cpp b/tests/mysql/test_range_select_from.cpp index 102e4d5..5a9e81e 100644 --- a/tests/mysql/test_range_select_from.cpp +++ b/tests/mysql/test_range_select_from.cpp @@ -19,9 +19,6 @@ struct Person { }; TEST(mysql, test_range_select_from) { - static_assert(std::ranges::input_range>, - "Must be an input range."); - const auto people1 = std::vector( {Person{ .id = 0, .first_name = "Homer", .last_name = "Simpson", .age = 45}, diff --git a/tests/mysql/test_select_from_with_to.cpp b/tests/mysql/test_select_from_with_to.cpp index d21f48c..44948c2 100644 --- a/tests/mysql/test_select_from_with_to.cpp +++ b/tests/mysql/test_select_from_with_to.cpp @@ -19,9 +19,6 @@ struct Person { }; TEST(mysql, test_range_select_from) { - static_assert(std::ranges::input_range>, - "Must be an input range."); - const auto people1 = std::vector( {Person{ .id = 0, .first_name = "Homer", .last_name = "Simpson", .age = 45}, diff --git a/tests/postgres/test_group_by.cpp b/tests/postgres/test_group_by.cpp index ed7bf86..2fa440f 100644 --- a/tests/postgres/test_group_by.cpp +++ b/tests/postgres/test_group_by.cpp @@ -19,9 +19,6 @@ struct Person { }; TEST(postgres, test_group_by) { - static_assert(std::ranges::input_range>, - "Must be an input range."); - const auto people1 = std::vector( {Person{ .id = 0, .first_name = "Homer", .last_name = "Simpson", .age = 45}, diff --git a/tests/postgres/test_group_by_with_operations.cpp b/tests/postgres/test_group_by_with_operations.cpp index a1afe21..a670a28 100644 --- a/tests/postgres/test_group_by_with_operations.cpp +++ b/tests/postgres/test_group_by_with_operations.cpp @@ -19,9 +19,6 @@ struct Person { }; TEST(postgres, test_group_by) { - static_assert(std::ranges::input_range>, - "Must be an input range."); - const auto people1 = std::vector( {Person{ .id = 0, .first_name = "Homer", .last_name = "Simpson", .age = 45}, diff --git a/tests/postgres/test_join.cpp b/tests/postgres/test_join.cpp index a2eceb5..df0071b 100644 --- a/tests/postgres/test_join.cpp +++ b/tests/postgres/test_join.cpp @@ -19,9 +19,6 @@ struct Person { }; TEST(postgres, test_join) { - static_assert(std::ranges::input_range>, - "Must be an input range."); - const auto people1 = std::vector( {Person{ .id = 0, .first_name = "Homer", .last_name = "Simpson", .age = 45}, diff --git a/tests/postgres/test_range.cpp b/tests/postgres/test_range.cpp index 735b15a..4d76290 100644 --- a/tests/postgres/test_range.cpp +++ b/tests/postgres/test_range.cpp @@ -19,9 +19,6 @@ struct Person { }; TEST(postgres, test_range) { - static_assert(std::ranges::input_range>, - "Must be an input range."); - const auto people1 = std::vector( {Person{ .id = 0, .first_name = "Homer", .last_name = "Simpson", .age = 45}, diff --git a/tests/postgres/test_range_select_from.cpp b/tests/postgres/test_range_select_from.cpp index 9df60e5..2060598 100644 --- a/tests/postgres/test_range_select_from.cpp +++ b/tests/postgres/test_range_select_from.cpp @@ -19,9 +19,6 @@ struct Person { }; TEST(postgres, test_range_select_from) { - static_assert(std::ranges::input_range>, - "Must be an input range."); - const auto people1 = std::vector( {Person{ .id = 0, .first_name = "Homer", .last_name = "Simpson", .age = 45}, diff --git a/tests/postgres/test_select_from_with_to.cpp b/tests/postgres/test_select_from_with_to.cpp index df10210..9ed1342 100644 --- a/tests/postgres/test_select_from_with_to.cpp +++ b/tests/postgres/test_select_from_with_to.cpp @@ -19,9 +19,6 @@ struct Person { }; TEST(postgres, test_range_select_from) { - static_assert(std::ranges::input_range>, - "Must be an input range."); - const auto people1 = std::vector( {Person{ .id = 0, .first_name = "Homer", .last_name = "Simpson", .age = 45}, diff --git a/tests/sqlite/test_range.cpp b/tests/sqlite/test_range.cpp index b5eaf2a..e528c95 100644 --- a/tests/sqlite/test_range.cpp +++ b/tests/sqlite/test_range.cpp @@ -17,9 +17,6 @@ struct Person { }; TEST(sqlite, test_range) { - static_assert(std::ranges::input_range>, - "Must be an input range."); - using namespace std::ranges::views; const auto people1 = std::vector(