4#include "../DataBinder/Core.hpp"
5#include "../DataBinder/SqlDate.hpp"
6#include "../DataBinder/SqlDateTime.hpp"
7#include "../DataBinder/SqlNumeric.hpp"
8#include "../DataBinder/SqlText.hpp"
9#include "../DataBinder/SqlTime.hpp"
10#include "../Utils.hpp"
12#include <reflection-cpp/reflection.hpp>
22enum class PrimaryKey : uint8_t
40 ServerSideAutoIncrement,
93struct IsStdOptionalType: std::false_type {};
96struct IsStdOptionalType<std::optional<T>>: std::true_type {};
99constexpr bool IsStdOptional = IsStdOptionalType<T>::value;
102concept FieldElementType = SqlInputParameterBinder<T> && SqlOutputColumnBinder<T>;
106 template <
typename TargetType,
typename P1,
typename P2>
107 consteval auto Choose(TargetType defaultValue, P1 p1, P2 p2)
noexcept
111 if constexpr (!std::same_as<P1, std::nullopt_t> && (!std::is_enum_v<P1> || std::same_as<P1, TargetType>)
112 &&
requires { TargetType { p1 }; })
114 else if constexpr (!std::same_as<P2, std::nullopt_t> && (!std::is_enum_v<P2> || std::same_as<P2, TargetType>)
115 &&
requires { TargetType { p2 }; })
122 template <
typename T>
123 inline constexpr bool IsAutoTimestampValueType = OneOf<T, SqlDateTime, std::optional<SqlDateTime>>;
132 template <
typename T>
133 requires IsAutoTimestampValueType<T>
134 [[nodiscard]]
constexpr bool IsUnsetTimestamp(T
const& value)
noexcept
136 if constexpr (IsStdOptional<T>)
137 return !value.has_value();
139 return value.sqlValue.month == 0;
152template <detail::FieldElementType T, auto P1 = std::nullopt, auto P2 = std::nullopt>
175 "A FieldTimestamp marker (CreatedAt / UpdatedAt) requires the field's value type to be SqlDateTime "
176 "or std::optional<SqlDateTime>.");
179 constexpr Field() noexcept = default;
188 constexpr ~
Field() noexcept = default;
192 template <typename... S>
193 requires std::constructible_from<T, S...>
194 constexpr
Field(S&&... value) noexcept;
197 template <typename S>
198 requires std::constructible_from<T, S> && (!std::same_as<std::remove_cvref_t<S>,
Field<T, P1, P2>>)
200 constexpr
Field& operator=(S&& value) noexcept;
222 constexpr auto operator<=>(
Field const& other) const noexcept
223 requires requires(T const& a, T const& b) { a <=> b; }
225 return _value <=> other._value;
235 template <
typename S>
236 requires std::convertible_to<S, T>
240 template <
typename S>
241 requires std::convertible_to<S, T>
254 [[nodiscard]] constexpr T const&
Value() const noexcept;
257 [[nodiscard]] constexpr auto
ValueOr(auto&& defaultValue) const noexcept
260 return _value.value_or(std::forward<typename ValueType::value_type>(defaultValue));
270 bool _modified {
true };
278struct IsAutoAssignPrimaryKeyField: std::false_type {};
280template <
typename T, auto P>
281struct IsAutoAssignPrimaryKeyField<Field<T, PrimaryKey::AutoAssign, P>>: std::true_type {};
283template <
typename T, auto P>
284struct IsAutoAssignPrimaryKeyField<Field<T, P, PrimaryKey::AutoAssign>>: std::true_type {};
287struct IsAutoIncrementPrimaryKeyField: std::false_type {};
289template <
typename T, auto P>
290struct IsAutoIncrementPrimaryKeyField<Field<T, PrimaryKey::ServerSideAutoIncrement, P>>: std::true_type {};
292template <
typename T, auto P>
293struct IsAutoIncrementPrimaryKeyField<Field<T, P, PrimaryKey::ServerSideAutoIncrement>>: std::true_type {};
296struct IsFieldType: std::false_type {};
298template <
typename T, auto P1, auto P2>
299struct IsFieldType<Field<T, P1, P2>>: std::true_type {};
306constexpr bool IsPrimaryKey =
false;
308template <
typename T, auto P1, auto P2>
313constexpr bool IsAutoIncrementPrimaryKey = detail::IsAutoIncrementPrimaryKeyField<T>::value;
316constexpr bool IsField = detail::IsFieldType<std::remove_cvref_t<T>>::value;
323template <
typename T, auto P1, auto P2>
328inline constexpr bool IsAutoTimestampField = FieldTimestampOf<std::remove_cvref_t<T>> !=
FieldTimestamp::None;
331template <detail::FieldElementType T, auto P1, auto P2>
332template <
typename... S>
333 requires std::constructible_from<T, S...>
335 _value(std::forward<S>(value)...)
340template <detail::FieldElementType T, auto P1, auto P2>
342 requires std::constructible_from<T, S> && (!std::same_as<std::remove_cvref_t<S>,
Field<T, P1, P2>>)
345 _value = std::forward<S>(value);
350template <detail::FieldElementType T, auto P1, auto P2>
353 return _value == other._value;
356template <detail::FieldElementType T, auto P1, auto P2>
359 return _value != other._value;
363template <detail::FieldElementType T, auto P1, auto P2>
365 requires std::convertible_to<S, T>
368 return _value == value;
372template <detail::FieldElementType T, auto P1, auto P2>
374 requires std::convertible_to<S, T>
377 return _value != value;
380template <detail::FieldElementType T, auto P1, auto P2>
383 if constexpr (std::is_same_v<T, std::string>)
385 std::stringstream result;
386 result << std::quoted(_value,
'\'');
389 else if constexpr (std::is_same_v<T, SqlText>)
391 std::stringstream result;
392 result << std::quoted(_value.value,
'\'');
395 else if constexpr (std::is_same_v<T, SqlDate>)
396 return std::format(
"\'{}\'", _value.value());
397 else if constexpr (std::is_same_v<T, SqlTime>)
398 return std::format(
"\'{}\'", _value.value());
399 else if constexpr (std::is_same_v<T, SqlDateTime>)
400 return std::format(
"\'{}\'", _value.value());
401 else if constexpr (SqlNumericType<T>)
402 return std::format(
"{}", _value.ToString());
403 else if constexpr (
requires { _value.has_value(); })
405 if (_value.has_value())
406 return std::format(
"{}", _value.value());
411 return std::format(
"{}", _value);
416template <detail::FieldElementType T, auto P1, auto P2>
422template <detail::FieldElementType T, auto P1, auto P2>
428template <detail::FieldElementType T, auto P1, auto P2>
434template <detail::FieldElementType T, auto P1, auto P2>
440template <detail::FieldElementType T, auto P1, auto P2>
441struct SqlDataBinder<
Field<T, P1, P2>>
445 static constexpr auto ColumnType = SqlDataBinder<T>::ColumnType;
447 static LIGHTWEIGHT_FORCE_INLINE SQLRETURN InputParameter(SQLHSTMT stmt,
449 ValueType
const& value,
452 return SqlDataBinder<T>::InputParameter(stmt, column, value.Value(), cb);
455 static LIGHTWEIGHT_FORCE_INLINE SQLRETURN
456 OutputColumn(SQLHSTMT stmt, SQLUSMALLINT column, ValueType* result, SQLLEN* indicator, SqlDataBinderCallback& cb)
458 return SqlDataBinder<T>::OutputColumn(stmt, column, &result->MutableValue(), indicator, cb);
463 static LIGHTWEIGHT_FORCE_INLINE SQLRETURN
464 GetColumn(SQLHSTMT stmt, SQLUSMALLINT column, ValueType* result, SQLLEN* indicator, SqlDataBinderCallback
const& cb)
466 return SqlDataBinder<T>::GetColumn(stmt, column, &result->emplace(), indicator, cb);
469 static LIGHTWEIGHT_FORCE_INLINE std::string Inspect(ValueType
const& value)
noexcept
471 return value.InspectValue();
492#if defined(LIGHTWEIGHT_CXX26_REFLECTION)
493 typename std::remove_cvref_t<
typename[:type_of(
Field):]>::ValueType;
495 std::remove_cvref_t<
decltype(std::declval<MemberClassType<
decltype(
Field)>>().*
Field)>::ValueType;
500template <Lightweight::detail::FieldElementType T, auto P1, auto P2>
501struct std::formatter<Lightweight::Field<T, P1, P2>>: std::formatter<T>
503 template <
typename FormatContext>
507 return formatter<T>::format(field.
Value(), ctx);
514template <Lightweight::detail::FieldElementType T, auto P1, auto P2>
515struct std::formatter<Lightweight::Field<std::optional<T>, P1, P2>>: std::formatter<T>
517 template <
typename FormatContext>
519 auto format(
Lightweight::Field<std::optional<T>, P1, P2>
const& field, FormatContext& ctx)
const
521 if (field.Value().has_value())
522 return formatter<T>::format(field.Value().value(), ctx);
525 constexpr std::string_view nullText {
"NULL" };
526 return std::ranges::copy(nullText, ctx.out()).out;
FieldTimestamp
Tells the data mapper that this field is a timestamp it maintains automatically, or not.
std::remove_cvref_t< decltype(std::declval< MemberClassType< decltype(Field)> >().*Field)>::ValueType ReferencedFieldTypeOf
Retrieves the type of a member field in a record.
@ UpdatedAt
The field holds the time the record was last written.
@ CreatedAt
The field holds the time the record was created.
@ None
The field is not maintained by the data mapper.
Represents a single column in a table.
T ValueType
The underlying value type of this field.
constexpr bool operator==(S const &value) const noexcept
Compares the field value with the given value for equality.
constexpr bool IsModified() const noexcept
Checks if the field has been modified.
constexpr T & MutableValue() noexcept
static constexpr auto TimestampKind
Which timestamp, if any, the data mapper maintains in this field.
constexpr bool operator!=(S const &value) const noexcept
Compares the field value with the given value for inequality.
constexpr bool operator!=(Field const &other) const noexcept
Compares the field value with the given value for inequality.
static constexpr auto IsAutoTimestamp
Indicates if the data mapper maintains this field as a timestamp of either kind.
constexpr void SetModified(bool value) noexcept
Sets the modified state of the field.
static constexpr auto IsUpdatedAtTimestamp
Indicates if the data mapper sets this field to the time the record was last written.
static constexpr auto IsCreatedAtTimestamp
Indicates if the data mapper sets this field to the creation time of the record.
constexpr T const & Value() const noexcept
Returns the value of the field.
constexpr bool operator==(Field const &other) const noexcept
Compares the field value with the given value for equality.
static constexpr auto IsPrimaryKey
Indicates if the field is a primary key.
static constexpr auto IsMandatory
Indicates if the field is mandatory, i.e., it cannot be NULL.
static constexpr auto IsPrimaryKeyValue
The primary key mode for this field.
constexpr auto ValueOr(auto &&defaultValue) const noexcept
When the field type is optional, returns the value or the given default value.
static constexpr auto IsOptional
Indicates if the field is optional, i.e., it can be NULL.
static constexpr auto IsAutoAssignPrimaryKey
Indicates if this is a primary key, it also is auto-assigned by the client.
std::string InspectValue() const
Returns a string representation of the value, suitable for use in debugging and logging.
static constexpr auto ColumnNameOverride
If not empty, overrides the default column name in the database.
static constexpr auto IsAutoIncrementPrimaryKey
Indicates if this is a primary key, it also is auto-incremented by the database.