Closed trueqbit closed 1 week ago
What is the appropriate syntax for using iterate? iterate seems to need a Table type but that does not work for general selects!
auto rows = storage.iterate(select(columns(&Doctor::id, &Doctor::name, &Visit::patientName, &Visit::vdate),
left_join<Visit>(on(c(&Doctor::id) == &Visit::doctorId))));
for( auto& row : rows)
{
auto id = get<0>(row); // does not work!!
}
@trueqbit, maybe a discussion for another place. But I'm trying to create a wrapper around result_set_view
so I'm only exposing STL types/don't need to include the ORM code everywhere (type erasure). I'm running into the issue that result_set_iterator
doesn't seem to implement the !=
operator. Am I doing this wrong? Basically, my goal is to have some type, let's call it Iterator
where I can do the following:
std::ranges::view auto SomeQuery() const
{
auto result = storage.iterate<MarvelHero>(where(length(&MarvelHero::name) < 6)));
return Iterator<MarvelHero>(result.begin(), result.end());
}
The error is: binary '!=': no operator found which takes a left-hand operand of type 'const TIterator' (or there is no acceptable conversion) with TIterator=sqlite_orm::internal::result_set_sentinel_t
Any thoughts?
std::ranges::view auto SomeQuery() const { auto result = storage.iterate<MarvelHero>(where(length(&MarvelHero::name) < 6))); return Iterator<MarvelHero>(result.begin(), result.end()); }
The error is:
binary '!=': no operator found which takes a left-hand operand of type 'const TIterator' (or there is no acceptable conversion) with TIterator=sqlite_orm::internal::result_set_sentinel_t
Any thoughts?
The specific query you posted here does not return a view on a result set of a select statement, but a view on "mapped objects", so there is a mismatch between the error you described and the iterator method you used.
The "mapped objects" view returns the same iterator type for start and end.
The view on a result set returns a sentinel as the end of the range (which is std::default_sentinel_t
). Since a result set iterator is a single-pass input iterator, you can only compare it to the sentinel.
Of course, I have no insight into the specifics of your application. However, nowadays there is a very nice way of type erasure that usually saves me from writing view or iterator adapters: range generators.
You can have a function that returns a range generator of MarvelHeroS:
std::generator<MarvelHero> query_heroes() {
for (MarvelHero hero : storage.iterate</*...*/>(/*...*/)) {
co_yield hero;
}
}
I use the reference implementation of the C++ WG21 proposal P2168, which is available on Lewis' Repository. There are probably improved implementations since the C++ WG21 proposal P2502.
This PR introduces iteration over result sets of select statements (possibly with common table expressions).
Technically speaking, the feature consists of:
internal::result_set_view
.std::ranges::view
,std::ranges::borrowed_range
.internal::result_set_iterator
.std::input_iterator
.std::default_sentinel_t
is taken as a range sentinel.The feature currently requires a C++20 compiler, but can also be used with implementations of the C++14 standard library.
Additional changes:
internal::view_t
tointernal::mapped_view
internal::iterator_t
tointernal::mapped_iterator