9#include <reflection-cpp/reflection.hpp>
62template <
typename ReferencedRecordT,
69 "The selector template arguments of HasManyThrough must be foreign key column names "
70 "(a SqlRealName) or std::nullopt to resolve the relationship automatically.");
72 static_assert(!IsThrough<ReferencedRecordT>,
73 "The referenced record of HasManyThrough must not be wrapped in Through<>, "
74 "only the join record is.");
95 using iterator = ReferencedRecordList::iterator;
109 [[nodiscard]] std::
size_t Count() const;
112 [[nodiscard]]
bool IsEmpty() const;
152 std::weak_ordering operator<=>(
HasManyThrough const& other) const noexcept = default;
156 std::function<size_t()> count;
164 _loader = std::move(loader);
170 _count = std::nullopt;
171 _records = std::nullopt;
180 template <
typename Callable>
181 void Each(Callable
const& callable)
183 if (!_records && _loader.each)
185 _loader.each(callable);
189 for (
auto const& record:
All())
200 _records = _loader.all();
208 std::optional<size_t> _count;
209 std::optional<ReferencedRecordList> _records;
214 template <
typename T>
215 struct IsHasManyThroughType: std::false_type
219 template <
typename ReferencedRecordT,
typename ThroughSpec, auto OwnerSelector, auto ReferencedSelector>
220 struct IsHasManyThroughType<HasManyThrough<ReferencedRecordT, ThroughSpec, OwnerSelector, ReferencedSelector>>:
228constexpr bool IsHasManyThrough = detail::IsHasManyThroughType<std::remove_cvref_t<T>>::value;
230template <
typename ReferencedRecordT,
typename ThroughSpec, auto OwnerSelector, auto ReferencedSelector>
236 return _records.value();
239template <
typename ReferencedRecordT,
typename ThroughSpec, auto OwnerSelector, auto ReferencedSelector>
245 return _records.value();
248template <
typename ReferencedRecordT,
typename ThroughSpec, auto OwnerSelector, auto ReferencedSelector>
255 _records = { std::move(records) };
256 _count = _records->size();
260template <
typename ReferencedRecordT,
typename ThroughSpec, auto OwnerSelector, auto ReferencedSelector>
264 return _records->size();
270 return _count.value_or(0);
273template <
typename ReferencedRecordT,
typename ThroughSpec, auto OwnerSelector, auto ReferencedSelector>
279template <
typename ReferencedRecordT,
typename ThroughSpec, auto OwnerSelector, auto ReferencedSelector>
283 return *All().at(index);
286template <
typename ReferencedRecordT,
typename ThroughSpec, auto OwnerSelector, auto ReferencedSelector>
290 return *All().at(index);
293template <
typename ReferencedRecordT,
typename ThroughSpec, auto OwnerSelector, auto ReferencedSelector>
297 return *All()[index];
300template <
typename ReferencedRecordT,
typename ThroughSpec, auto OwnerSelector, auto ReferencedSelector>
304 return *All()[index];
307template <
typename ReferencedRecordT,
typename ThroughSpec, auto OwnerSelector, auto ReferencedSelector>
311 return All().begin();
314template <
typename ReferencedRecordT,
typename ThroughSpec, auto OwnerSelector, auto ReferencedSelector>
321template <
typename ReferencedRecordT,
typename ThroughSpec, auto OwnerSelector, auto ReferencedSelector>
325 return All().begin();
328template <
typename ReferencedRecordT,
typename ThroughSpec, auto OwnerSelector, auto ReferencedSelector>
This API represents a many-to-many relationship between two records through a third record.
ReferencedRecordList & Emplace(ReferencedRecordList &&records) noexcept
Emplaces the given list of records into this relationship.
void SetAutoLoader(Loader loader) noexcept
Used internally to configure on-demand loading of the records.
ReferencedRecordList const & All() const noexcept
Retrieves the list of loaded records.
ThroughRecordOf< ThroughSpec > ThroughRecord
The record type of the "through" side of the relationship.
static constexpr auto OwnerSelector
Singles out the join record's foreign key pointing at the record owning this relationship.
ReferencedRecordList::const_iterator const_iterator
Const iterator type for the list of records.
iterator begin() noexcept
Returns an iterator to the beginning of the record list.
void Each(Callable const &callable)
Iterates over all records in this relationship.
std::vector< std::shared_ptr< ReferencedRecord > > ReferencedRecordList
The list of records on the "many" side of the relationship.
ReferencedRecordT ReferencedRecord
The record type of the "many" side of the relationship.
iterator end() noexcept
Returns an iterator to the end of the record list.
ReferencedRecord const & operator[](std::size_t index) const
Retrieves the record at the given index.
ReferencedRecord const & At(std::size_t index) const
Retrieves the record at the given index.
bool IsEmpty() const
Checks if this relationship is empty.
static constexpr auto ReferencedSelector
Singles out the join record's foreign key pointing at ReferencedRecord.
ReferencedRecord value_type
Value type for range-based iteration.
std::size_t Count() const
Retrieves the number of records in this relationship.
void Reload()
Reloads the records from the database.
ReferencedRecordList::iterator iterator
Iterator type for the list of records.
Represents an error when a record is required to be loaded but is not.
Constrains what may be used to single out one of several foreign keys into the same table.
@ Count
Number of enumerators; not an operation itself.
typename detail::ThroughRecordOfHelper< ThroughSpec >::type ThroughRecordOf
Resolves the join record of a through-relationship from its template argument.
constexpr std::nullopt_t AutoDetectRelation
Selector value meaning "resolve the relationship automatically; the match must be unique".