5#include "../DataBinder/Core.hpp"
6#include "../DataBinder/SqlNullValue.hpp"
7#include "../SqlStatement.hpp"
44template <auto TheReferencedField, auto ColumnNameOverr
ideString = std::nullopt, SqlNullable Nullable = SqlNullable::NotNull>
53 if constexpr (!std::same_as<
decltype(ColumnNameOverrideString), std::nullopt_t>)
54 return std::string_view { ColumnNameOverrideString };
56 return std::string_view {};
59#if defined(LIGHTWEIGHT_CXX26_REFLECTION)
66 static_assert(std::remove_cvref_t<decltype(std::declval<ReferencedRecord>().[:
ReferencedField:])>::IsPrimaryKey,
67 "The referenced field must be a primary key.");
72 static_assert(std::remove_cvref_t<decltype(std::declval<ReferencedRecord>().*
ReferencedField)>::IsPrimaryKey,
73 "The referenced field must be a primary key.");
81 using ValueType = std::conditional_t<Nullable == SqlNullable::Null, std::optional<BaseType>,
BaseType>;
83 static constexpr auto IsOptional = Nullable == SqlNullable::Null;
84 static constexpr auto IsMandatory = !IsOptional;
85 static constexpr auto IsPrimaryKey =
false;
86 static constexpr auto IsAutoIncrementPrimaryKey =
false;
88 template <
typename... S>
89 requires std::constructible_from<
ValueType, S...>
90 constexpr BelongsTo(S&&... value)
noexcept:
91 _referencedFieldValue(std::forward<S>(value)...)
96#if defined(LIGHTWEIGHT_CXX26_REFLECTION)
102 _record { std::make_unique<ReferencedRecord>(other) }
106 constexpr BelongsTo(BelongsTo
const& other)
noexcept:
107 _referencedFieldValue(other._referencedFieldValue),
108 _loader(std::move(other._loader)),
109 _loaded(other._loaded),
110 _modified(other._modified),
111 _record(other._record ? std::make_unique<ReferencedRecord>(*other._record) : nullptr)
115 constexpr BelongsTo(BelongsTo&& other)
noexcept:
116 _referencedFieldValue(std::move(other._referencedFieldValue)),
117 _loader(std::move(other._loader)),
118 _loaded(other._loaded),
119 _modified(other._modified),
120 _record(std::move(other._record))
124 BelongsTo& operator=(SqlNullType )
noexcept
126 if (!_referencedFieldValue)
129 _record = std::nullopt;
130 _referencedFieldValue = {};
137#if defined(LIGHTWEIGHT_CXX26_REFLECTION)
144 _record = std::make_unique<ReferencedRecord>(other);
145#if defined(LIGHTWEIGHT_CXX26_REFLECTION)
154 BelongsTo& operator=(BelongsTo
const& other)
159 _referencedFieldValue = other._referencedFieldValue;
160 _loader = std::move(other._loader);
161 _loaded = other._loaded;
162 _modified = other._modified;
163 _record = other._record ? std::make_unique<ReferencedRecord>(*other._record) : nullptr;
168 BelongsTo& operator=(BelongsTo&& other)
noexcept
172 _referencedFieldValue = std::move(other._referencedFieldValue);
173 _loader = std::move(other._loader);
174 _loaded = other._loaded;
175 _modified = other._modified;
176 _record = std::move(other._record);
177 other._loaded =
false;
181 ~BelongsTo() noexcept = default;
186 LIGHTWEIGHT_FORCE_INLINE constexpr
void SetModified(
bool value) noexcept { _modified = value; }
189 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE
constexpr bool IsModified() const noexcept {
return _modified; }
192 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE
constexpr ValueType const&
Value() const noexcept {
return _referencedFieldValue; }
195 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE
constexpr ValueType&
MutableValue() noexcept {
return _referencedFieldValue; }
201 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE
constexpr ReferencedRecord const&
Record()
const { RequireLoaded();
return *_record; }
204 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE
constexpr bool IsLoaded() const noexcept {
return _loaded; }
207 LIGHTWEIGHT_FORCE_INLINE
void Unload() noexcept { _record =
nullptr; _loaded =
false; }
213 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE
constexpr ReferencedRecord const&
operator*() const noexcept { RequireLoaded();
return *_record; }
222 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE
constexpr bool operator!() const noexcept {
return !_referencedFieldValue; }
225 [[nodiscard]] LIGHTWEIGHT_FORCE_INLINE
constexpr explicit operator bool() const noexcept {
return static_cast<bool>(_referencedFieldValue); }
233 _record = std::make_unique<ReferencedRecord>();
237 LIGHTWEIGHT_FORCE_INLINE
void BindOutputColumn(SQLSMALLINT outputIndex,
SqlStatement& stmt)
239 stmt.BindOutputColumn(outputIndex, &_referencedFieldValue);
242 std::weak_ordering operator<=>(BelongsTo
const& other)
const noexcept
244 return _referencedFieldValue <=> other.Value();
247 template <detail::FieldElementType T, PrimaryKey IsPrimaryKeyValue = PrimaryKey::No>
248 std::weak_ordering operator<=>(Field<T, IsPrimaryKeyValue>
const& other)
const noexcept
250 return _referencedFieldValue <=> other.Value();
253 bool operator==(BelongsTo
const& other)
const noexcept
255 return (_referencedFieldValue <=> other.Value()) == std::weak_ordering::equivalent;
258 bool operator!=(BelongsTo
const& other)
const noexcept
260 return (_referencedFieldValue <=> other.Value()) != std::weak_ordering::equivalent;
263 template <detail::FieldElementType T, PrimaryKey IsPrimaryKeyValue = PrimaryKey::No>
264 bool operator==(Field<T, IsPrimaryKeyValue>
const& other)
const noexcept
266 return (_referencedFieldValue <=> other.Value()) == std::weak_ordering::equivalent;
269 template <detail::FieldElementType T, PrimaryKey IsPrimaryKeyValue = PrimaryKey::No>
270 bool operator!=(Field<T, IsPrimaryKeyValue>
const& other)
const noexcept
272 return (_referencedFieldValue <=> other.Value()) != std::weak_ordering::equivalent;
277 std::function<std::optional<ReferencedRecord>()> loadReference {};
283 _loader = std::move(loader);
292 if (_loader.loadReference)
294 auto value = _loader.loadReference();
297 _record = std::make_unique<ReferencedRecord>(std::move(value.value()));
303 throw SqlRequireLoadedError(Reflection::TypeNameOf<std::remove_cvref_t<
decltype(*
this)>>);
308 bool _loaded =
false;
309 bool _modified =
false;
310 std::unique_ptr<ReferencedRecord> _record {};
313template <auto ReferencedField, auto ColumnNameOverr
ideString, SqlNullable Nullable>
314std::ostream& operator<<(std::ostream& os, BelongsTo<ReferencedField, ColumnNameOverrideString, Nullable>
const& belongsTo)
316 return os << belongsTo.Value();
321 template <
typename T>
322 struct IsBelongsToType: std::false_type
326 template <auto ReferencedField, auto ColumnNameOverr
ideString, SqlNullable Nullable>
327 struct IsBelongsToType<BelongsTo<ReferencedField, ColumnNameOverrideString, Nullable>>: std::true_type
334constexpr bool IsBelongsTo = detail::IsBelongsToType<std::remove_cvref_t<T>>::value;
337concept is_belongs_to = IsBelongsTo<T>;
340constexpr bool IsOptionalBelongsTo =
false;
342template <is_be
longs_to T>
343constexpr bool IsOptionalBelongsTo<T> = T::IsOptional;
345template <auto ReferencedField, auto ColumnNameOverr
ideString, SqlNullable Nullable>
346struct SqlDataBinder<BelongsTo<ReferencedField, ColumnNameOverrideString, Nullable>>
348 using SelfType = BelongsTo<ReferencedField, ColumnNameOverrideString, Nullable>;
349 using InnerType =
typename SelfType::ValueType;
351 static constexpr auto ColumnType = SqlDataBinder<InnerType>::ColumnType;
353 static LIGHTWEIGHT_FORCE_INLINE SQLRETURN InputParameter(SQLHSTMT stmt,
355 SelfType
const& value,
356 SqlDataBinderCallback& cb)
358 return SqlDataBinder<InnerType>::InputParameter(stmt, column, value.Value(), cb);
361 static LIGHTWEIGHT_FORCE_INLINE SQLRETURN
362 OutputColumn(SQLHSTMT stmt, SQLUSMALLINT column, SelfType* result, SQLLEN* indicator, SqlDataBinderCallback& cb)
364 auto const sqlReturn = SqlDataBinder<InnerType>::OutputColumn(stmt, column, &result->MutableValue(), indicator, cb);
365 cb.PlanPostProcessOutputColumn([result]() { result->SetModified(
true); });
369 static LIGHTWEIGHT_FORCE_INLINE SQLRETURN GetColumn(
370 SQLHSTMT stmt, SQLUSMALLINT column, SelfType* result, SQLLEN* indicator, SqlDataBinderCallback
const& cb)
noexcept
372 auto const sqlReturn = SqlDataBinder<InnerType>::GetColumn(stmt, column, &result->MutableValue(), indicator, cb);
373 if (SQL_SUCCEEDED(sqlReturn))
374 result->SetModified(
true);
Represents a one-to-one relationship.
LIGHTWEIGHT_FORCE_INLINE constexpr ReferencedRecord const & operator*() const noexcept
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 constexpr ReferencedRecord const * operator->() const
Retrieves the record from the relationship.
LIGHTWEIGHT_FORCE_INLINE constexpr ReferencedRecord & operator*() noexcept
Retrieves the record from the relationship.
static constexpr auto ReferencedField
The field in the other record that references the current record.
LIGHTWEIGHT_FORCE_INLINE constexpr ReferencedRecord const & Record() const
Retrieves an immutable reference to the record from the relationship.
LIGHTWEIGHT_FORCE_INLINE constexpr bool IsLoaded() const noexcept
Checks if the record is loaded into memory.
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.
LIGHTWEIGHT_FORCE_INLINE constexpr ReferencedRecord * operator->()
Retrieves the record from the relationship.
LIGHTWEIGHT_FORCE_INLINE constexpr ValueType & MutableValue() noexcept
Retrieves the mutable reference to the value of the field.
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.
LIGHTWEIGHT_FORCE_INLINE void Unload() noexcept
Unloads the record from memory.
LIGHTWEIGHT_FORCE_INLINE constexpr void SetModified(bool value) noexcept
Marks the field as modified or unmodified.
std::conditional_t< Nullable==SqlNullable::Null, std::optional< BaseType >, BaseType > ValueType
typename std::remove_cvref_t< decltype(std::declval< ReferencedRecord >().*ReferencedField)>::ValueType BaseType
Represents the base column type of the foreign key, matching the primary key of the other record.
void SetAutoLoader(Loader loader) noexcept
Used internally to configure on-demand loading of the record.
MemberClassType< decltype(TheReferencedField)> ReferencedRecord
Represents the record type of the other field.
static constexpr std::string_view ColumnNameOverride
If not an empty string, this value will be used as the column name in the database.
High level API for (prepared) raw SQL statements.