5#include "../DataBinder/Core.hpp"
6#include "../DataBinder/SqlNullValue.hpp"
7#include "../SqlStatement.hpp"
8#include "BelongsTo.hpp"
12#include <reflection-cpp/reflection.hpp>
62template <
typename OtherRecord, auto TheInverseSelector = AutoDetectRelation>
66 "The second template argument of HasMany must be a foreign key column name (a SqlRealName) "
67 "or std::nullopt to resolve the relationship automatically.");
83 using iterator = ReferencedRecordList::iterator;
98 template <typename Callable>
99 void Each(Callable const& callable);
105 [[nodiscard]] std::
size_t Count() const noexcept;
108 [[nodiscard]]
bool IsEmpty() const noexcept;
115 [[nodiscard]] OtherRecord const&
At(std::
size_t index) const;
122 [[nodiscard]] OtherRecord&
At(std::
size_t index);
129 [[nodiscard]] OtherRecord const& operator[](std::
size_t index) const;
136 [[nodiscard]] OtherRecord& operator[](std::
size_t index);
148 constexpr std::weak_ordering operator<=>(
HasMany const& other) const noexcept = default;
150 constexpr
bool operator==(
HasMany const& other) const noexcept = default;
152 constexpr
bool operator!=(
HasMany const& other) const noexcept = default;
156 std::function<size_t()> count {};
160 std::weak_ordering
operator<=>(Loader
const& )
const noexcept
162 return std::weak_ordering::equivalent;
170 void RequireLoaded();
173 std::optional<ReferencedRecordList> _records;
174 std::optional<size_t> _count;
179 template <
typename T>
180 struct IsHasManyType: std::false_type
184 template <
typename OtherRecord, auto InverseSelector>
185 struct IsHasManyType<HasMany<OtherRecord, InverseSelector>>: std::true_type
192constexpr bool IsHasMany = detail::IsHasManyType<std::remove_cvref_t<T>>::value;
194template <
typename OtherRecord, auto InverseSelector>
197 _loader = std::move(loader);
200template <
typename OtherRecord, auto InverseSelector>
204 _records = _loader.all();
207template <
typename OtherRecord, auto InverseSelector>
212 _records = { std::move(records) };
216template <
typename OtherRecord, auto InverseSelector>
219 InverseSelector>::All() noexcept
225template <
typename OtherRecord, auto InverseSelector>
226template <
typename Callable>
229 if (!_records && _loader.each)
231 _loader.each(callable);
235 for (
auto const& record: All())
239template <
typename OtherRecord, auto InverseSelector>
242 InverseSelector>::All() const noexcept
244 const_cast<HasMany*
>(
this)->RequireLoaded();
248template <
typename OtherRecord, auto InverseSelector>
252 return _records->size();
254 if (!_count && _loader.count)
257 return _count.value_or(0);
260template <
typename OtherRecord, auto InverseSelector>
266template <
typename OtherRecord, auto InverseSelector>
269 const_cast<HasMany*
>(
this)->RequireLoaded();
270 return *_records->at(index);
273template <
typename OtherRecord, auto InverseSelector>
277 return *_records->at(index);
280template <
typename OtherRecord, auto InverseSelector>
283 const_cast<HasMany*
>(
this)->RequireLoaded();
284 return *(*_records)[index];
287template <
typename OtherRecord, auto InverseSelector>
291 return *(*_records)[index];
294template <
typename OtherRecord, auto InverseSelector>
296 InverseSelector>::begin() noexcept
300 return _records->begin();
305template <
typename OtherRecord, auto InverseSelector>
307 InverseSelector>::end() noexcept
311 return _records->end();
316template <
typename OtherRecord, auto InverseSelector>
318 InverseSelector>::begin()
321 const_cast<HasMany*
>(
this)->RequireLoaded();
323 return _records->
begin();
328template <
typename OtherRecord, auto InverseSelector>
330 InverseSelector>::end()
333 const_cast<HasMany*
>(
this)->RequireLoaded();
335 return _records->
end();
This HasMany<OtherRecord> represents a simple one-to-many relationship between two records.
OtherRecord const & At(std::size_t index) const
Retrieves the record at the given index.
iterator end() noexcept
Returns an iterator to the end of the record list.
iterator begin() noexcept
Returns an iterator to the beginning of the record list.
ReferencedRecordList::iterator iterator
Iterator type for the list of records.
void Each(Callable const &callable)
Iterates over the list of records and calls the given callable for each record.
constexpr std::weak_ordering operator<=>(HasMany const &other) const noexcept=default
Three-way comparison operator.
ReferencedRecordList::const_iterator const_iterator
Const iterator type for the list of records.
OtherRecord ReferencedRecord
The record type of the "many" side of the relationship.
std::size_t Count() const noexcept
Retrieves the number of records in this 1-to-many relationship.
ReferencedRecordList const & All() const noexcept
Retrieves the list of loaded records.
OtherRecord const & operator[](std::size_t index) const
Retrieves the record at the given index.
OtherRecord value_type
Record type of the "many" side of the relationship.
void SetAutoLoader(Loader loader) noexcept
Used internally to configure on-demand loading of the records.
static constexpr auto InverseSelector
Singles out the foreign key of OtherRecord that backs this relationship.
std::vector< std::shared_ptr< OtherRecord > > ReferencedRecordList
The list of records on the "many" side of the relationship.
bool IsEmpty() const noexcept
Checks if this 1-to-many relationship is empty.
ReferencedRecordList & Emplace(ReferencedRecordList &&records) noexcept
Emplaces the given list of records.
Constrains what may be used to single out one of several foreign keys into the same table.