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
39 ServerSideAutoIncrement,
48struct IsStdOptionalType: std::false_type {};
51struct IsStdOptionalType<std::optional<T>>: std::true_type {};
54constexpr bool IsStdOptional = IsStdOptionalType<T>::value;
57concept FieldElementType = SqlInputParameterBinder<T> && SqlOutputColumnBinder<T>;
61 template <
typename TargetType,
typename P1,
typename P2>
62 consteval auto Choose(TargetType defaultValue, P1 p1, P2 p2)
noexcept
64 if constexpr (!std::same_as<P1, std::nullopt_t> &&
requires { TargetType { p1 }; })
66 else if constexpr (!std::same_as<P2, std::nullopt_t> &&
requires { TargetType { p2 }; })
82template <detail::FieldElementType T, auto P1 = std::nullopt, auto P2 = std::nullopt>
89 static constexpr auto IsPrimaryKeyValue = detail::Choose<PrimaryKey>(PrimaryKey::No, P1, P2);
94 constexpr Field() noexcept = default;
98 constexpr
Field& operator=(
Field const&) noexcept = default;
103 constexpr ~
Field() noexcept = default;
107 template <typename... S>
108 requires std::constructible_from<T, S...>
109 constexpr
Field(S&&... value) noexcept;
112 template <typename S>
113 requires std::constructible_from<T, S> && (!std::same_as<std::remove_cvref_t<S>,
Field<T, P1, P2>>)
115 constexpr
Field& operator=(S&& value) noexcept;
137 constexpr auto operator<=>(
Field const& other) const noexcept
138 requires requires(T const& a, T const& b) { a <=> b; }
140 return _value <=> other._value;
150 template <
typename S>
151 requires std::convertible_to<S, T>
155 template <
typename S>
156 requires std::convertible_to<S, T>
169 [[nodiscard]] constexpr T const&
Value() const noexcept;
172 [[nodiscard]] constexpr auto
ValueOr(auto&& defaultValue) const noexcept
175 return _value.value_or(std::forward<typename ValueType::value_type>(defaultValue));
185 bool _modified {
true };
193struct IsAutoAssignPrimaryKeyField: std::false_type {};
195template <
typename T, auto P>
196struct IsAutoAssignPrimaryKeyField<Field<T, PrimaryKey::AutoAssign, P>>: std::true_type {};
198template <
typename T, auto P>
199struct IsAutoAssignPrimaryKeyField<Field<T, P, PrimaryKey::AutoAssign>>: std::true_type {};
202struct IsAutoIncrementPrimaryKeyField: std::false_type {};
204template <
typename T, auto P>
205struct IsAutoIncrementPrimaryKeyField<Field<T, PrimaryKey::ServerSideAutoIncrement, P>>: std::true_type {};
207template <
typename T, auto P>
208struct IsAutoIncrementPrimaryKeyField<Field<T, P, PrimaryKey::ServerSideAutoIncrement>>: std::true_type {};
211struct IsFieldType: std::false_type {};
213template <
typename T, auto P1, auto P2>
214struct IsFieldType<Field<T, P1, P2>>: std::true_type {};
221constexpr bool IsPrimaryKey =
222 detail::IsAutoAssignPrimaryKeyField<T>::value || detail::IsAutoIncrementPrimaryKeyField<T>::value;
226constexpr bool IsAutoIncrementPrimaryKey = detail::IsAutoIncrementPrimaryKeyField<T>::value;
229constexpr bool IsField = detail::IsFieldType<std::remove_cvref_t<T>>::value;
232template <detail::FieldElementType T, auto P1, auto P2>
233template <
typename... S>
234 requires std::constructible_from<T, S...>
236 _value(std::forward<S>(value)...)
241template <detail::FieldElementType T, auto P1, auto P2>
243 requires std::constructible_from<T, S> && (!std::same_as<std::remove_cvref_t<S>,
Field<T, P1, P2>>)
246 _value = std::forward<S>(value);
251template <detail::FieldElementType T, auto P1, auto P2>
254 return _value == other._value;
257template <detail::FieldElementType T, auto P1, auto P2>
260 return _value != other._value;
264template <detail::FieldElementType T, auto P1, auto P2>
266 requires std::convertible_to<S, T>
269 return _value == value;
273template <detail::FieldElementType T, auto P1, auto P2>
275 requires std::convertible_to<S, T>
278 return _value != value;
281template <detail::FieldElementType T, auto P1, auto P2>
284 if constexpr (std::is_same_v<T, std::string>)
286 std::stringstream result;
287 result << std::quoted(_value,
'\'');
290 else if constexpr (std::is_same_v<T, SqlText>)
292 std::stringstream result;
293 result << std::quoted(_value.value,
'\'');
296 else if constexpr (std::is_same_v<T, SqlDate>)
297 return std::format(
"\'{}\'", _value.value());
298 else if constexpr (std::is_same_v<T, SqlTime>)
299 return std::format(
"\'{}\'", _value.value());
300 else if constexpr (std::is_same_v<T, SqlDateTime>)
301 return std::format(
"\'{}\'", _value.value());
302 else if constexpr (SqlNumericType<T>)
303 return std::format(
"{}", _value.ToString());
304 else if constexpr (
requires { _value.has_value(); })
306 if (_value.has_value())
307 return std::format(
"{}", _value.value());
312 return std::format(
"{}", _value);
317template <detail::FieldElementType T, auto P1, auto P2>
323template <detail::FieldElementType T, auto P1, auto P2>
329template <detail::FieldElementType T, auto P1, auto P2>
335template <detail::FieldElementType T, auto P1, auto P2>
341template <detail::FieldElementType T, auto P1, auto P2>
342struct SqlDataBinder<
Field<T, P1, P2>>
346 static constexpr auto ColumnType = SqlDataBinder<T>::ColumnType;
348 static LIGHTWEIGHT_FORCE_INLINE SQLRETURN InputParameter(SQLHSTMT stmt,
350 ValueType
const& value,
353 return SqlDataBinder<T>::InputParameter(stmt, column, value.Value(), cb);
356 static LIGHTWEIGHT_FORCE_INLINE SQLRETURN
357 OutputColumn(SQLHSTMT stmt, SQLUSMALLINT column, ValueType* result, SQLLEN* indicator, SqlDataBinderCallback& cb)
359 return SqlDataBinder<T>::OutputColumn(stmt, column, &result->MutableValue(), indicator, cb);
362 static LIGHTWEIGHT_FORCE_INLINE SQLRETURN GetColumn(
363 SQLHSTMT stmt, SQLUSMALLINT column, ValueType* result, SQLLEN* indicator, SqlDataBinderCallback
const& cb)
noexcept
365 return SqlDataBinder<T>::GetColumn(stmt, column, &result->emplace(), indicator, cb);
368 static LIGHTWEIGHT_FORCE_INLINE std::string Inspect(ValueType
const& value)
noexcept
370 return value.InspectValue();
391#if defined(LIGHTWEIGHT_CXX26_REFLECTION)
392 typename std::remove_cvref_t<
typename[:type_of(
Field):]>::ValueType;
394 std::remove_cvref_t<
decltype(std::declval<MemberClassType<
decltype(
Field)>>().*
Field)>::ValueType;
399template <Lightweight::detail::FieldElementType T, auto P1, auto P2>
400struct std::formatter<Lightweight::Field<T, P1, P2>>: std::formatter<T>
402 template <
typename FormatContext>
406 return formatter<T>::format(field.
Value(), ctx);
413template <Lightweight::detail::FieldElementType T, auto P1, auto P2>
414struct std::formatter<Lightweight::Field<std::optional<T>, P1, P2>>: std::formatter<T>
416 template <
typename FormatContext>
418 auto format(
Lightweight::Field<std::optional<T>, P1, P2>
const& field, FormatContext& ctx)
const
420 if (field.Value().has_value())
421 return formatter<T>::format(field.Value().value(), ctx);
424 constexpr std::string_view nullText {
"NULL" };
425 return std::ranges::copy(nullText, ctx.out()).out;
std::remove_cvref_t< decltype(std::declval< MemberClassType< decltype(Field)> >().*Field)>::ValueType ReferencedFieldTypeOf
Retrieves the type of a member field in a record.
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
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.
constexpr void SetModified(bool value) noexcept
Sets the modified state of the field.
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.