5#include "../DataBinder/Core.hpp"
6#include "../DataBinder/SqlNullValue.hpp"
7#include "../SqlStatement.hpp"
40template <auto TheReferencedField, auto ColumnNameOverr
ideString = std::nullopt>
51 if constexpr (!std::same_as<
decltype(ColumnNameOverrideString), std::nullopt_t>)
52 return std::string_view { ColumnNameOverrideString };
54 return std::string_view {};
60 static_assert(std::remove_cvref_t<decltype(std::declval<ReferencedRecord>().*
ReferencedField)>::IsPrimaryKey,
61 "The referenced field must be a primary key.");
66 static constexpr auto IsOptional =
true;
67 static constexpr auto IsMandatory = !IsOptional;
68 static constexpr auto IsPrimaryKey =
false;
69 static constexpr auto IsAutoIncrementPrimaryKey =
false;
71 template <
typename... S>
72 requires std::constructible_from<
ValueType, S...>
73 constexpr BelongsTo(S&&... value)
noexcept:
74 _referencedFieldValue(std::forward<S>(value)...)
81 _record { std::make_unique<ReferencedRecord>(other) }
85 constexpr BelongsTo(SelfType
const& other)
noexcept:
86 _referencedFieldValue(other._referencedFieldValue),
87 _loader(std::move(other._loader)),
88 _loaded(other._loaded),
89 _modified(other._modified),
90 _record(other._record ? std::make_unique<ReferencedRecord>(*other._record) : nullptr)
94 constexpr BelongsTo(SelfType&& other)
noexcept:
95 _referencedFieldValue(std::move(other._referencedFieldValue)),
96 _loader(std::move(other._loader)),
97 _loaded(other._loaded),
98 _modified(other._modified),
99 _record(std::move(other._record))
101 other._loaded =
false;
106 if (!_referencedFieldValue)
109 _record = std::nullopt;
110 _referencedFieldValue = {};
120 _record = std::make_unique<ReferencedRecord>(other);
126 BelongsTo& operator=(SelfType
const& other)
131 _referencedFieldValue = other._referencedFieldValue;
132 _loader = std::move(other._loader);
133 _loaded = other._loaded;
134 _modified = other._modified;
135 _record = other._record ? std::make_unique<ReferencedRecord>(*other._record) : nullptr;
143 LIGHTWEIGHT_FORCE_INLINE
constexpr void SetModified(
bool value)
noexcept { _modified = value; }
146 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE
constexpr bool IsModified() const noexcept {
return _modified; }
149 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE
constexpr ValueType const&
Value() const noexcept {
return _referencedFieldValue; }
152 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE
constexpr ValueType&
MutableValue() noexcept {
return _referencedFieldValue; }
158 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE
constexpr ReferencedRecord const&
Record()
const { RequireLoaded();
return *_record; }
161 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE
constexpr bool IsLoaded() const noexcept {
return _loaded; }
164 LIGHTWEIGHT_FORCE_INLINE
void Unload() noexcept { _record =
nullptr; _loaded =
false; }
170 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE
constexpr ReferencedRecord const&
operator*() const noexcept { RequireLoaded();
return *_record; }
179 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE
constexpr bool operator!() const noexcept {
return !_referencedFieldValue; }
182 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE
constexpr explicit operator bool() const noexcept {
return static_cast<bool>(_referencedFieldValue); }
190 _record = std::make_unique<ReferencedRecord>();
194 LIGHTWEIGHT_FORCE_INLINE
void BindOutputColumn(SQLSMALLINT outputIndex,
SqlStatement& stmt)
196 stmt.BindOutputColumn(outputIndex, &_referencedFieldValue);
199 template <auto OtherReferencedField>
202 return _referencedFieldValue <=> other.Value();
205 template <detail::FieldElementType T, PrimaryKey IsPrimaryKeyValue = PrimaryKey::No>
208 return _referencedFieldValue <=> other.Value();
211 template <auto OtherReferencedField>
214 return (_referencedFieldValue <=> other.Value()) == std::weak_ordering::equivalent;
217 template <auto OtherReferencedField>
220 return (_referencedFieldValue <=> other.Value()) != std::weak_ordering::equivalent;
223 template <detail::FieldElementType T, PrimaryKey IsPrimaryKeyValue = PrimaryKey::No>
226 return (_referencedFieldValue <=> other.Value()) == std::weak_ordering::equivalent;
229 template <detail::FieldElementType T, PrimaryKey IsPrimaryKeyValue = PrimaryKey::No>
232 return (_referencedFieldValue <=> other.Value()) != std::weak_ordering::equivalent;
237 std::function<void()> loadReference {};
243 _loader = std::move(loader);
252 if (_loader.loadReference)
253 _loader.loadReference();
261 bool _loaded =
false;
262 bool _modified =
false;
263 std::unique_ptr<ReferencedRecord> _record {};
266template <auto ReferencedField>
269 return os << belongsTo.
Value();
275struct IsBelongsToType: std::false_type
279template <auto ReferencedField, auto ColumnNameOverr
ideString>
280struct IsBelongsToType<
BelongsTo<ReferencedField, ColumnNameOverrideString>>: std::true_type
287constexpr bool IsBelongsTo = detail::IsBelongsToType<std::remove_cvref_t<T>>::value;
289template <auto ReferencedField, auto ColumnNameOverr
ideString>
290struct SqlDataBinder<
BelongsTo<ReferencedField, ColumnNameOverrideString>>
293 using InnerType =
typename SelfType::ValueType;
295 static constexpr auto ColumnType = SqlDataBinder<InnerType>::ColumnType;
297 static LIGHTWEIGHT_FORCE_INLINE SQLRETURN InputParameter(SQLHSTMT stmt,
299 SelfType
const& value,
302 return SqlDataBinder<InnerType>::InputParameter(stmt, column, value.Value(), cb);
305 static LIGHTWEIGHT_FORCE_INLINE SQLRETURN
306 OutputColumn(SQLHSTMT stmt, SQLUSMALLINT column, SelfType* result, SQLLEN* indicator,
SqlDataBinderCallback& cb)
308 auto const sqlReturn = SqlDataBinder<InnerType>::OutputColumn(stmt, column, &result->MutableValue(), indicator, cb);
309 cb.PlanPostProcessOutputColumn([result]() { result->SetModified(
true); });
313 static LIGHTWEIGHT_FORCE_INLINE SQLRETURN GetColumn(
314 SQLHSTMT stmt, SQLUSMALLINT column, SelfType* result, SQLLEN* indicator,
SqlDataBinderCallback const& cb)
noexcept
316 auto const sqlReturn = SqlDataBinder<InnerType>::GetColumn(stmt, column, &result->MutableValue(), indicator, cb);
317 if (SQL_SUCCEEDED(sqlReturn))
318 result->SetModified(
true);
Represents a one-to-one relationship.
static constexpr std::string_view ColumnNameOverride
If not an empty string, this value will be used as the column name in the database.
LIGHTWEIGHT_FORCE_INLINE constexpr ValueType & MutableValue() noexcept
Retrieves the mutable reference to the value of the field.
LIGHTWEIGHT_FORCE_INLINE constexpr ReferencedRecord & operator*() noexcept
Retrieves the record from the relationship.
LIGHTWEIGHT_FORCE_INLINE constexpr ReferencedRecord const & Record() const
Retrieves an immutable reference to the record from the relationship.
MemberClassType< decltype(TheReferencedField)> ReferencedRecord
Represents the record type of the other field.
void SetAutoLoader(Loader loader) noexcept
Used internally to configure on-demand loading of the record.
static constexpr auto ReferencedField
The field in the other record that references the current record.
LIGHTWEIGHT_FORCE_INLINE constexpr void SetModified(bool value) noexcept
Marks the field as modified or unmodified.
LIGHTWEIGHT_FORCE_INLINE constexpr ReferencedRecord const * operator->() const
Retrieves the record from the relationship.
LIGHTWEIGHT_FORCE_INLINE constexpr ReferencedRecord * operator->()
Retrieves the record from the relationship.
LIGHTWEIGHT_FORCE_INLINE constexpr ReferencedRecord & EmplaceRecord()
Emplaces a record into the relationship. This will mark the relationship as loaded.
LIGHTWEIGHT_FORCE_INLINE void Unload() noexcept
Unloads the record from memory.
LIGHTWEIGHT_FORCE_INLINE constexpr ReferencedRecord & Record()
Retrieves a record from the relationship.
LIGHTWEIGHT_FORCE_INLINE constexpr ValueType const & Value() const noexcept
Retrieves the reference to the value of the field.
typename std::remove_cvref_t< decltype(std::declval< ReferencedRecord >().*ReferencedField)>::ValueType ValueType
Represents the column type of the foreign key, matching the primary key of the other record.
LIGHTWEIGHT_FORCE_INLINE constexpr bool IsLoaded() const noexcept
Checks if the record is loaded into memory.
LIGHTWEIGHT_FORCE_INLINE constexpr ReferencedRecord const & operator*() const noexcept
Retrieves the record from the relationship.
LIGHTWEIGHT_FORCE_INLINE constexpr bool operator!() const noexcept
Checks if the field value is NULL.
LIGHTWEIGHT_FORCE_INLINE constexpr bool IsModified() const noexcept
Checks if the field is modified.
Represents an error when a record is required to be loaded but is not.
High level API for (prepared) raw SQL statements.
Represents a single column in a table.