Lightweight 0.20250904.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 std::weak_ordering operator<=>(HasOneThrough const& other) const noexcept = default;
67
68 struct Loader
69 {
70 std::function<void()> loadReference {};
71 };
72
73 /// Used internally to configure on-demand loading of the record.
74 void SetAutoLoader(Loader loader)
75 {
76 _loader = std::move(loader);
77 }
78
79 private:
80 void RequireLoaded() const
81 {
82 if (IsLoaded())
83 return;
84
85 if (_loader.loadReference)
86 _loader.loadReference();
87
88 if (!IsLoaded())
89 throw SqlRequireLoadedError { Reflection::TypeNameOf<std::remove_cvref_t<decltype(*this)>> };
90 }
91
92 Loader _loader {};
93
94 // We use shared_ptr to not require ReferencedRecord to be declared before HasOneThrough.
95 std::shared_ptr<ReferencedRecord> _record {};
96};
97
98namespace detail
99{
100 template <typename T>
101 struct IsHasOneThrough: std::false_type
102 {
103 };
104
105 template <typename OtherTable, typename ThroughTable>
106 struct IsHasOneThrough<HasOneThrough<OtherTable, ThroughTable>>: std::true_type
107 {
108 };
109} // namespace detail
110
111template <typename T>
112constexpr bool IsHasOneThrough = detail::IsHasOneThrough<std::remove_cvref_t<T>>::value;
113
114} // 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.
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