9#include <reflection-cpp/reflection.hpp>
20template <
typename ReferencedRecordT,
typename ThroughRecordT>
34 using iterator =
typename ReferencedRecordList::iterator;
35 using const_iterator =
typename ReferencedRecordList::const_iterator;
47 [[nodiscard]] std::
size_t Count() const;
50 [[nodiscard]] std::
size_t IsEmpty() const;
80 [[nodiscard]] iterator begin() noexcept;
81 [[nodiscard]] iterator end() noexcept;
82 [[nodiscard]] const_iterator begin() const noexcept;
83 [[nodiscard]] const_iterator end() const noexcept;
85 std::weak_ordering operator<=>(
HasManyThrough const& other) const noexcept = default;
89 std::function<size_t()> count;
90 std::function<void()> all;
97 _loader = std::move(loader);
103 _count = std::nullopt;
104 _records = std::nullopt;
113 template <
typename Callable>
114 void Each(Callable
const& callable)
116 if (!_records && _loader.each)
118 _loader.each(callable);
122 for (
auto const& record:
All())
141 std::optional<size_t> _count;
142 std::optional<ReferencedRecordList> _records;
146constexpr bool IsHasManyThrough = IsSpecializationOf<HasManyThrough, T>;
148template <
typename ReferencedRecordT,
typename ThroughRecordT>
150 ThroughRecordT>::All()
155 return _records.value();
158template <
typename ReferencedRecordT,
typename ThroughRecordT>
160 ThroughRecordT>::All() noexcept
164 return _records.value();
167template <
typename ReferencedRecordT,
typename ThroughRecordT>
171 _records = { std::move(records) };
172 _count = _records->size();
176template <
typename ReferencedRecordT,
typename ThroughRecordT>
180 return _records->size();
185 return _count.value_or(0);
188template <
typename ReferencedRecordT,
typename ThroughRecordT>
194template <
typename ReferencedRecordT,
typename ThroughRecordT>
197 ThroughRecordT>::At(std::size_t index)
const
199 return *All().at(index);
202template <
typename ReferencedRecordT,
typename ThroughRecordT>
206 return *All().at(index);
209template <
typename ReferencedRecordT,
typename ThroughRecordT>
212 ThroughRecordT>::operator[](std::size_t index)
const
214 return *All()[index];
217template <
typename ReferencedRecordT,
typename ThroughRecordT>
221 return *All()[index];
224template <
typename ReferencedRecordT,
typename ThroughRecordT>
225HasManyThrough<ReferencedRecordT, ThroughRecordT>::iterator
HasManyThrough<ReferencedRecordT,
226 ThroughRecordT>::begin() noexcept
228 return All().begin();
231template <
typename ReferencedRecordT,
typename ThroughRecordT>
237template <
typename ReferencedRecordT,
typename ThroughRecordT>
241 return All().begin();
244template <
typename ReferencedRecordT,
typename ThroughRecordT>
This API represents a many-to-many relationship between two records through a third record.
ReferencedRecordList const & All() const noexcept
Retrieves the list of loaded records.
ReferencedRecordList & Emplace(ReferencedRecordList &&records) noexcept
Emplaces the given list of records into this relationship.
std::size_t Count() const
Retrieves the number of records in this relationship.
ReferencedRecord const & At(std::size_t index) const
Retrieves the record at the given index.
ReferencedRecordT ReferencedRecord
The record type of the "many" side of the relationship.
ThroughRecordT ThroughRecord
The record type of the "through" side of the relationship.
std::size_t IsEmpty() const
Checks if this relationship is empty.
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.
ReferencedRecord const & operator[](std::size_t index) const
Retrieves the record at the given index.
void Reload()
Reloads the records from the database.
void SetAutoLoader(Loader loader) noexcept
Used internally to configure on-demand loading of the records.
Represents an error when a record is required to be loaded but is not.