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
109 if constexpr (!std::same_as<P1, std::nullopt_t> &&
requires { TargetType { p1 }; })
111 else if constexpr (!std::same_as<P2, std::nullopt_t> &&
requires { TargetType { p2 }; })
118 template <
typename T>
119 inline constexpr bool IsAutoTimestampValueType = OneOf<T, SqlDateTime, std::optional<SqlDateTime>>;
128 template <
typename T>
129 requires IsAutoTimestampValueType<T>
130 [[nodiscard]]
constexpr bool IsUnsetTimestamp(T
const& value)
noexcept
132 if constexpr (IsStdOptional<T>)
133 return !value.has_value();
135 return value.sqlValue.month == 0;
148template <detail::FieldElementType T, auto P1 = std::nullopt, auto P2 = std::nullopt>
171 "A FieldTimestamp marker (CreatedAt / UpdatedAt) requires the field's value type to be SqlDateTime "
172 "or std::optional<SqlDateTime>.");
175 constexpr Field() noexcept = default;
184 constexpr ~
Field() noexcept = default;
188 template <typename... S>
189 requires std::constructible_from<T, S...>
190 constexpr
Field(S&&... value) noexcept;
193 template <typename S>
194 requires std::constructible_from<T, S> && (!std::same_as<std::remove_cvref_t<S>,
Field<T, P1, P2>>)
196 constexpr
Field& operator=(S&& value) noexcept;
218 constexpr auto operator<=>(
Field const& other) const noexcept
219 requires requires(T const& a, T const& b) { a <=> b; }
221 return _value <=> other._value;
231 template <
typename S>
232 requires std::convertible_to<S, T>
236 template <
typename S>
237 requires std::convertible_to<S, T>
250 [[nodiscard]] constexpr T const&
Value() const noexcept;
253 [[nodiscard]] constexpr auto
ValueOr(auto&& defaultValue) const noexcept
256 return _value.value_or(std::forward<typename ValueType::value_type>(defaultValue));
266 bool _modified {
true };
274struct IsAutoAssignPrimaryKeyField: std::false_type {};
276template <
typename T, auto P>
277struct IsAutoAssignPrimaryKeyField<Field<T, PrimaryKey::AutoAssign, P>>: std::true_type {};
279template <
typename T, auto P>
280struct IsAutoAssignPrimaryKeyField<Field<T, P, PrimaryKey::AutoAssign>>: std::true_type {};
283struct IsAutoIncrementPrimaryKeyField: std::false_type {};
285template <
typename T, auto P>
286struct IsAutoIncrementPrimaryKeyField<Field<T, PrimaryKey::ServerSideAutoIncrement, P>>: std::true_type {};
288template <
typename T, auto P>
289struct IsAutoIncrementPrimaryKeyField<Field<T, P, PrimaryKey::ServerSideAutoIncrement>>: std::true_type {};
292struct IsFieldType: std::false_type {};
294template <
typename T, auto P1, auto P2>
295struct IsFieldType<Field<T, P1, P2>>: std::true_type {};
302constexpr bool IsPrimaryKey =
false;
304template <
typename T, auto P1, auto P2>
309constexpr bool IsAutoIncrementPrimaryKey = detail::IsAutoIncrementPrimaryKeyField<T>::value;
312constexpr bool IsField = detail::IsFieldType<std::remove_cvref_t<T>>::value;
319template <
typename T, auto P1, auto P2>
324inline constexpr bool IsAutoTimestampField = FieldTimestampOf<std::remove_cvref_t<T>> !=
FieldTimestamp::None;
327template <detail::FieldElementType T, auto P1, auto P2>
328template <
typename... S>
329 requires std::constructible_from<T, S...>
331 _value(std::forward<S>(value)...)
336template <detail::FieldElementType T, auto P1, auto P2>
338 requires std::constructible_from<T, S> && (!std::same_as<std::remove_cvref_t<S>,
Field<T, P1, P2>>)
341 _value = std::forward<S>(value);
346template <detail::FieldElementType T, auto P1, auto P2>
349 return _value == other._value;
352template <detail::FieldElementType T, auto P1, auto P2>
355 return _value != other._value;
359template <detail::FieldElementType T, auto P1, auto P2>
361 requires std::convertible_to<S, T>
364 return _value == value;
368template <detail::FieldElementType T, auto P1, auto P2>
370 requires std::convertible_to<S, T>
373 return _value != value;
376template <detail::FieldElementType T, auto P1, auto P2>
379 if constexpr (std::is_same_v<T, std::string>)
381 std::stringstream result;
382 result << std::quoted(_value,
'\'');
385 else if constexpr (std::is_same_v<T, SqlText>)
387 std::stringstream result;
388 result << std::quoted(_value.value,
'\'');
391 else if constexpr (std::is_same_v<T, SqlDate>)
392 return std::format(
"\'{}\'", _value.value());
393 else if constexpr (std::is_same_v<T, SqlTime>)
394 return std::format(
"\'{}\'", _value.value());
395 else if constexpr (std::is_same_v<T, SqlDateTime>)
396 return std::format(
"\'{}\'", _value.value());
397 else if constexpr (SqlNumericType<T>)
398 return std::format(
"{}", _value.ToString());
399 else if constexpr (
requires { _value.has_value(); })
401 if (_value.has_value())
402 return std::format(
"{}", _value.value());
407 return std::format(
"{}", _value);
412template <detail::FieldElementType T, auto P1, auto P2>
418template <detail::FieldElementType T, auto P1, auto P2>
424template <detail::FieldElementType T, auto P1, auto P2>
430template <detail::FieldElementType T, auto P1, auto P2>
436template <detail::FieldElementType T, auto P1, auto P2>
437struct SqlDataBinder<
Field<T, P1, P2>>
441 static constexpr auto ColumnType = SqlDataBinder<T>::ColumnType;
443 static LIGHTWEIGHT_FORCE_INLINE SQLRETURN InputParameter(SQLHSTMT stmt,
445 ValueType
const& value,
448 return SqlDataBinder<T>::InputParameter(stmt, column, value.Value(), cb);
451 static LIGHTWEIGHT_FORCE_INLINE SQLRETURN
452 OutputColumn(SQLHSTMT stmt, SQLUSMALLINT column, ValueType* result, SQLLEN* indicator, SqlDataBinderCallback& cb)
454 return SqlDataBinder<T>::OutputColumn(stmt, column, &result->MutableValue(), indicator, cb);
459 static LIGHTWEIGHT_FORCE_INLINE SQLRETURN
460 GetColumn(SQLHSTMT stmt, SQLUSMALLINT column, ValueType* result, SQLLEN* indicator, SqlDataBinderCallback
const& cb)
462 return SqlDataBinder<T>::GetColumn(stmt, column, &result->emplace(), indicator, cb);
465 static LIGHTWEIGHT_FORCE_INLINE std::string Inspect(ValueType
const& value)
noexcept
467 return value.InspectValue();
488#if defined(LIGHTWEIGHT_CXX26_REFLECTION)
489 typename std::remove_cvref_t<
typename[:type_of(
Field):]>::ValueType;
491 std::remove_cvref_t<
decltype(std::declval<MemberClassType<
decltype(
Field)>>().*
Field)>::ValueType;
496template <Lightweight::detail::FieldElementType T, auto P1, auto P2>
497struct std::formatter<Lightweight::Field<T, P1, P2>>: std::formatter<T>
499 template <
typename FormatContext>
503 return formatter<T>::format(field.
Value(), ctx);
510template <Lightweight::detail::FieldElementType T, auto P1, auto P2>
511struct std::formatter<Lightweight::Field<std::optional<T>, P1, P2>>: std::formatter<T>
513 template <
typename FormatContext>
515 auto format(
Lightweight::Field<std::optional<T>, P1, P2>
const& field, FormatContext& ctx)
const
517 if (field.Value().has_value())
518 return formatter<T>::format(field.Value().value(), ctx);
521 constexpr std::string_view nullText {
"NULL" };
522 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.