8#include <reflection-cpp/reflection.hpp>
19template <
size_t... Ints>
26 struct IsSqlElements: std::false_type
30 template <
size_t... Ints>
31 struct IsSqlElements<
SqlElements<Ints...>>: std::true_type
38concept NotSqlElements = !detail::IsSqlElements<T>::value;
46template <
typename Record>
49template <
typename... Records>
55 template <std::
size_t I,
typename Record>
56 constexpr std::optional<size_t> FindPrimaryKeyIndex()
59 if constexpr (I < Reflection::CountMembers<Record>)
61 if constexpr (IsPrimaryKey<Reflection::MemberTypeOf<I, Record>>)
64 return FindPrimaryKeyIndex<I + 1, Record>();
72template <
typename Record>
73constexpr size_t RecordPrimaryKeyIndex =
74 detail::FindPrimaryKeyIndex<0, Record>().value_or((std::numeric_limits<size_t>::max)());
77template <
typename Record>
78decltype(
auto) RecordPrimaryKeyOf(Record&& record)
82 return Reflection::GetMemberAt<RecordPrimaryKeyIndex<std::remove_cvref_t<Record>>>(std::forward<Record>(record));
88 template <
typename Record>
89 struct RecordPrimaryKeyTypeHelper
94 template <
typename Record>
95 requires(RecordPrimaryKeyIndex<Record> < Reflection::CountMembers<Record>)
96 struct RecordPrimaryKeyTypeHelper<Record>
98 using type =
typename Reflection::MemberTypeOf<RecordPrimaryKeyIndex<Record>, Record>::ValueType;
104template <
typename Record>
105using RecordPrimaryKeyType =
typename details::RecordPrimaryKeyTypeHelper<Record>::type;
108template <
typename Record,
typename TargetMappable>
109void MapFromRecordFields(Record&& record, TargetMappable& target)
111 Reflection::EnumerateMembers(std::forward<Record>(record), [&]<std::size_t I>(
auto const& field) {
112 using MemberType = Reflection::MemberTypeOf<I, Record>;
113 static_assert(IsField<MemberType>,
"Record member must be a Field<> type");
114 static_assert(std::is_assignable_v<
decltype(target[I]),
decltype(field.Value())>,
115 "Target must support operator[] with the field type");
116 target[I] = field.Value();
126 { field.Value() } -> std::convertible_to<typename T::ValueType const&>;
127 { mutableField.MutableValue() } -> std::convertible_to<typename T::ValueType&>;
128 { field.IsModified() } -> std::convertible_to<bool>;
129 { mutableField.SetModified(
bool {}) } -> std::convertible_to<void>;
136template <
typename Record>
138 Reflection::FoldMembers<Record>(
size_t { 0 }, []<
size_t I,
typename Field>(
size_t const accum)
constexpr {
139 if constexpr (FieldWithStorage<Field>)
145template <
typename Record>
146concept RecordWithStorageFields = (RecordStorageFieldCount<Record> > 0);
151 template <auto Test,
typename T>
152 constexpr bool CheckFieldProperty = Reflection::FoldMembers<T>(
false, []<
size_t I,
typename Field>(
bool const accum) {
153 if constexpr (Test.template operator()<Field>())
165constexpr bool HasPrimaryKey = detail::CheckFieldProperty<[]<typename Field>() {
return IsPrimaryKey<Field>; }, T>;
172 detail::CheckFieldProperty<[]<typename Field>() {
return IsAutoIncrementPrimaryKey<Field>; }, T>;
177template <
typename Record>
178inline LIGHTWEIGHT_FORCE_INLINE RecordPrimaryKeyType<Record>
GetPrimaryKeyField(Record
const& record)
noexcept
181 static_assert(HasPrimaryKey<Record>,
"Record must have a primary key");
183 auto result = RecordPrimaryKeyType<Record> {};
184 Reflection::EnumerateMembers(record, [&]<
size_t I,
typename FieldType>(FieldType
const& field) {
185 if constexpr (IsPrimaryKey<FieldType> && std::same_as<FieldType, RecordPrimaryKeyType<Record>>)
Represents a record type that can be used with the DataMapper.
LIGHTWEIGHT_FORCE_INLINE RecordPrimaryKeyType< Record > GetPrimaryKeyField(Record const &record) noexcept
constexpr bool HasAutoIncrementPrimaryKey
Tests if the given record type does contain an auto increment primary key.
std::integer_sequence< size_t, Ints... > SqlElements
Represents a sequence of indexes that can be used alongside Query() to retrieve only part of the reco...
constexpr size_t RecordStorageFieldCount
constexpr bool HasPrimaryKey
Tests if the given record type does contain a primary key.