Lightweight 0.20260213.0
Loading...
Searching...
No Matches
HasOneThrough.hpp
1// SPDX-License-Identifier: Apache-2.0
2
3#pragma once
4
5#include "../SqlStatement.hpp"
6#include "../Utils.hpp"
7#include "Error.hpp"
8
9#include <compare>
10#include <memory>
11#include <type_traits>
12
13namespace Lightweight
14{
15
16/// @brief Represents a one-to-one relationship through a join table.
17///
18/// The `OtherField` parameter is the field in the join table that references the other record.
19/// The `ThroughField` parameter is the field in the join table that references the current record.
20///
21/// @ingroup DataMapper
22template <typename OtherTable, typename ThroughTable>
24{
25 public:
26 /// The record type of the "through" side of the relationship.
27 using ThroughRecord = ThroughTable;
28
29 /// The record type of the "Other" side of the relationship.
30 using ReferencedRecord = OtherTable;
31
32 // clang-format off
33
34 /// Emplaces the given record into this relationship.
35 LIGHTWEIGHT_FORCE_INLINE constexpr void EmplaceRecord(std::shared_ptr<ReferencedRecord> record) { _record = std::move(record); }
36
37 /// Retrieves the record in this relationship.
38 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE constexpr ReferencedRecord& Record() noexcept { RequireLoaded(); return *_record.get(); }
39
40 /// Retrieves the record in this relationship.
41 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE constexpr ReferencedRecord const& Record() const noexcept { RequireLoaded(); return *_record.get(); }
42
43 /// Checks if the record is loaded.
44 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE constexpr bool IsLoaded() const noexcept { return _record.get() != nullptr; }
45
46 /// Unloads the record from memory.
47 LIGHTWEIGHT_FORCE_INLINE void Unload() noexcept { _record = std::nullopt; }
48
49 /// @brief Retrieves the record in this relationship.
50 /// @note On-demand loads the record if it is not already loaded.
51 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE constexpr ReferencedRecord& operator*() noexcept { RequireLoaded(); return *_record; }
52
53 /// @brief Retrieves the record in this relationship.
54 /// @note On-demand loads the record if it is not already loaded.
55 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE constexpr ReferencedRecord const& operator*() const noexcept { RequireLoaded(); return *_record; }
56
57 /// @brief Retrieves the record in this relationship.
58 /// @note On-demand loads the record if it is not already loaded.
59 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE constexpr ReferencedRecord* operator->() noexcept { RequireLoaded(); return &_record.get(); }
60
61 /// @brief Retrieves the record in this relationship.
62 /// @note On-demand loads the record if it is not already loaded.
63 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE constexpr ReferencedRecord const* operator->() const noexcept { RequireLoaded(); return &_record.get(); }
64 // clang-format on
65
66 /// Default three-way comparison operator.
67 std::weak_ordering operator<=>(HasOneThrough const& other) const noexcept = default;
68
69 struct Loader
70 {
71 std::function<void()> loadReference {};
72 };
73
74 /// Used internally to configure on-demand loading of the record.
75 void SetAutoLoader(Loader loader)
76 {
77 _loader = std::move(loader);
78 }
79
80 private:
81 void RequireLoaded() const
82 {
83 if (IsLoaded())
84 return;
85
86 if (_loader.loadReference)
87 _loader.loadReference();
88
89 if (!IsLoaded())
90 throw SqlRequireLoadedError { Reflection::TypeNameOf<std::remove_cvref_t<decltype(*this)>> };
91 }
92
93 Loader _loader {};
94
95 // We use shared_ptr to not require ReferencedRecord to be declared before HasOneThrough.
96 std::shared_ptr<ReferencedRecord> _record {};
97};
98
99namespace detail
100{
101 template <typename T>
102 struct IsHasOneThrough: std::false_type
103 {
104 };
105
106 template <typename OtherTable, typename ThroughTable>
107 struct IsHasOneThrough<HasOneThrough<OtherTable, ThroughTable>>: std::true_type
108 {
109 };
110} // namespace detail
111
112template <typename T>
113constexpr bool IsHasOneThrough = detail::IsHasOneThrough<std::remove_cvref_t<T>>::value;
114
115} // namespace Lightweight
Represents a one-to-one relationship through a join table.
LIGHTWEIGHT_FORCE_INLINE constexpr void EmplaceRecord(std::shared_ptr< ReferencedRecord > record)
Emplaces the given record into this relationship.
LIGHTWEIGHT_FORCE_INLINE void Unload() noexcept
Unloads the record from memory.
LIGHTWEIGHT_FORCE_INLINE constexpr ReferencedRecord * operator->() noexcept
Retrieves the record in this relationship.
ThroughTable ThroughRecord
The record type of the "through" side of the relationship.
std::weak_ordering operator<=>(HasOneThrough const &other) const noexcept=default
Default three-way comparison operator.
LIGHTWEIGHT_FORCE_INLINE constexpr ReferencedRecord & operator*() noexcept
Retrieves the record in this relationship.
LIGHTWEIGHT_FORCE_INLINE constexpr ReferencedRecord & Record() noexcept
Retrieves the record in this relationship.
LIGHTWEIGHT_FORCE_INLINE constexpr ReferencedRecord const & operator*() const noexcept
Retrieves the record in this relationship.
LIGHTWEIGHT_FORCE_INLINE constexpr ReferencedRecord const * operator->() const noexcept
Retrieves the record in this relationship.
LIGHTWEIGHT_FORCE_INLINE constexpr bool IsLoaded() const noexcept
Checks if the record is loaded.
OtherTable ReferencedRecord
The record type of the "Other" side of the relationship.
LIGHTWEIGHT_FORCE_INLINE constexpr ReferencedRecord const & Record() const noexcept
Retrieves the record in this relationship.
void SetAutoLoader(Loader loader)
Used internally to configure on-demand loading of the record.
Represents an error when a record is required to be loaded but is not.
Definition Error.hpp:16