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;
133 constexpr std::weak_ordering operator<=>(
Field const& other) const noexcept;
136 constexpr
bool operator==(
Field const& other) const noexcept;
139 constexpr
bool operator!=(
Field const& other) const noexcept;
142 template <typename S>
143 requires std::convertible_to<S, T>
144 constexpr
bool operator==(S const& value) const noexcept;
147 template <typename S>
148 requires std::convertible_to<S, T>
149 constexpr
bool operator!=(S const& value) const noexcept;
161 [[nodiscard]] constexpr T const&
Value() const noexcept;
164 [[nodiscard]] constexpr auto
ValueOr(auto&& defaultValue) const noexcept
167 return _value.value_or(std::forward<typename ValueType::value_type>(defaultValue));
177 bool _modified {
true };
185struct IsAutoAssignPrimaryKeyField: std::false_type {};
187template <
typename T, auto P>
188struct IsAutoAssignPrimaryKeyField<Field<T, PrimaryKey::AutoAssign, P>>: std::true_type {};
190template <
typename T, auto P>
191struct IsAutoAssignPrimaryKeyField<Field<T, P, PrimaryKey::AutoAssign>>: std::true_type {};
194struct IsAutoIncrementPrimaryKeyField: std::false_type {};
196template <
typename T, auto P>
197struct IsAutoIncrementPrimaryKeyField<Field<T, PrimaryKey::ServerSideAutoIncrement, P>>: std::true_type {};
199template <
typename T, auto P>
200struct IsAutoIncrementPrimaryKeyField<Field<T, P, PrimaryKey::ServerSideAutoIncrement>>: std::true_type {};
203struct IsFieldType: std::false_type {};
205template <
typename T, auto P1, auto P2>
206struct IsFieldType<Field<T, P1, P2>>: std::true_type {};
213constexpr bool IsPrimaryKey =
214 detail::IsAutoAssignPrimaryKeyField<T>::value || detail::IsAutoIncrementPrimaryKeyField<T>::value;
218constexpr bool IsAutoIncrementPrimaryKey = detail::IsAutoIncrementPrimaryKeyField<T>::value;
221constexpr bool IsField = detail::IsFieldType<std::remove_cvref_t<T>>::value;
224template <detail::FieldElementType T, auto P1, auto P2>
225template <
typename... S>
226 requires std::constructible_from<T, S...>
228 _value(std::forward<S>(value)...)
233template <detail::FieldElementType T, auto P1, auto P2>
235 requires std::constructible_from<T, S> && (!std::same_as<std::remove_cvref_t<S>,
Field<T, P1, P2>>)
238 _value = std::forward<S>(value);
243template <detail::FieldElementType T, auto P1, auto P2>
246 return _value <=> other._value;
249template <detail::FieldElementType T, auto P1, auto P2>
252 return _value == other._value;
255template <detail::FieldElementType T, auto P1, auto P2>
258 return _value != other._value;
262template <detail::FieldElementType T, auto P1, auto P2>
264 requires std::convertible_to<S, T>
267 return _value == value;
271template <detail::FieldElementType T, auto P1, auto P2>
273 requires std::convertible_to<S, T>
276 return _value != value;
279template <detail::FieldElementType T, auto P1, auto P2>
282 if constexpr (std::is_same_v<T, std::string>)
284 std::stringstream result;
285 result << std::quoted(_value,
'\'');
288 else if constexpr (std::is_same_v<T, SqlText>)
290 std::stringstream result;
291 result << std::quoted(_value.value,
'\'');
294 else if constexpr (std::is_same_v<T, SqlDate>)
295 return std::format(
"\'{}\'", _value.value);
296 else if constexpr (std::is_same_v<T, SqlTime>)
297 return std::format(
"\'{}\'", _value.value);
298 else if constexpr (std::is_same_v<T, SqlDateTime>)
299 return std::format(
"\'{}\'", _value.value());
300 else if constexpr (SqlNumericType<T>)
301 return std::format(
"{}", _value.ToString());
302 else if constexpr (
requires { _value.has_value(); })
304 if (_value.has_value())
305 return std::format(
"{}", _value.value());
310 return std::format(
"{}", _value);
315template <detail::FieldElementType T, auto P1, auto P2>
321template <detail::FieldElementType T, auto P1, auto P2>
327template <detail::FieldElementType T, auto P1, auto P2>
333template <detail::FieldElementType T, auto P1, auto P2>
339template <detail::FieldElementType T, auto P1, auto P2>
340struct SqlDataBinder<
Field<T, P1, P2>>
344 static constexpr auto ColumnType = SqlDataBinder<T>::ColumnType;
346 static LIGHTWEIGHT_FORCE_INLINE SQLRETURN InputParameter(SQLHSTMT stmt,
348 ValueType
const& value,
351 return SqlDataBinder<T>::InputParameter(stmt, column, value.Value(), cb);
354 static LIGHTWEIGHT_FORCE_INLINE SQLRETURN
355 OutputColumn(SQLHSTMT stmt, SQLUSMALLINT column, ValueType* result, SQLLEN* indicator, SqlDataBinderCallback& cb)
357 return SqlDataBinder<T>::OutputColumn(stmt, column, &result->MutableValue(), indicator, cb);
360 static LIGHTWEIGHT_FORCE_INLINE SQLRETURN GetColumn(
361 SQLHSTMT stmt, SQLUSMALLINT column, ValueType* result, SQLLEN* indicator, SqlDataBinderCallback
const& cb)
noexcept
363 return SqlDataBinder<T>::GetColumn(stmt, column, &result->emplace(), indicator, cb);
366 static LIGHTWEIGHT_FORCE_INLINE std::string Inspect(ValueType
const& value)
noexcept
368 return value.InspectValue();
389#if defined(LIGHTWEIGHT_CXX26_REFLECTION)
390 typename std::remove_cvref_t<
typename[:type_of(
Field):]>::ValueType;
392 std::remove_cvref_t<
decltype(std::declval<MemberClassType<
decltype(
Field)>>().*
Field)>::ValueType;
397template <Lightweight::detail::FieldElementType T, auto P1, auto P2>
398struct std::formatter<Lightweight::Field<T, P1, P2>>: std::formatter<T>
400 template <
typename FormatContext>
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 IsModified() const noexcept
Checks if the field has been modified.
constexpr T & MutableValue() noexcept
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.
constexpr std::weak_ordering operator<=>(Field const &other) const noexcept
Compares two fields for equality.
static constexpr auto IsAutoIncrementPrimaryKey
Indicates if this is a primary key, it also is auto-incremented by the database.