Lightweight 0.20261105.1
Loading...
Searching...
No Matches
Field.hpp
1// SPDX-License-Identifier: Apache-2.0
2#pragma once
3
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"
11
12#include <reflection-cpp/reflection.hpp>
13
14#include <iomanip>
15#include <optional>
16#include <sstream>
17
18namespace Lightweight
19{
20
21/// @brief Tells the data mapper that this field is a primary key with given semantics, or not a primary key.
22enum class PrimaryKey : uint8_t
23{
24 /// The field is not a primary key.
25 No,
26
27 /// @brief The field is a primary key.
28 ///
29 /// If the field is an auto-incrementable key and not manually set, it is automatically set to the
30 /// next available value on the client side, using a SELECT MAX() query.
31 /// This is happening transparently to the user.
32 ///
33 /// If the field is a GUID, it is automatically set to a new GUID value, if not manually set.
34 ///
35 /// @note If the field is neither auto-incrementable nor a GUID, it must be manually set. For a key
36 /// the mapper must never generate even when it could, use @c Manual.
37 AutoAssign,
38
39 /// The field is an integer primary key, and it is auto-incremented by the database.
40 ServerSideAutoIncrement,
41
42 /// @brief The field is a primary key whose value the caller always supplies.
43 ///
44 /// The data mapper neither generates it nor writes a generated value into it, so this is the
45 /// assignment for every member of a composite primary key: auto-assignment produces one value,
46 /// which a composite key cannot be built from.
47 Manual,
48};
49
50/// @brief Tells the data mapper that this field is a timestamp it maintains automatically, or not.
51///
52/// Pass it in one of a Field's two option slots, alone or together with a column-name override:
53///
54/// @code
55/// struct Article
56/// {
57/// Field<uint64_t, PrimaryKey::ServerSideAutoIncrement> id;
58/// Field<SqlDateTime, FieldTimestamp::CreatedAt> createdAt;
59/// Field<SqlDateTime, FieldTimestamp::UpdatedAt, SqlRealName { "updated_at" }> updatedAt;
60/// };
61/// @endcode
62///
63/// The value is read from the DataMapper's timestamp clock (see DataMapper::SetTimestampClock()), once
64/// per operation, so every timestamp written by one operation carries the same value. A value the
65/// caller set explicitly is never overwritten, which allows importing historical rows.
66///
67/// Only `SqlDateTime` and `std::optional<SqlDateTime>` fields may carry a timestamp marker.
68///
69/// @ingroup DataMapper
70enum class FieldTimestamp : uint8_t
71{
72 /// The field is not maintained by the data mapper.
73 None,
74
75 /// @brief The field holds the time the record was created.
76 ///
77 /// Set when the record is inserted, unless the caller gave it a value. Never changed by an update.
79
80 /// @brief The field holds the time the record was last written.
81 ///
82 /// Set when the record is inserted, unless the caller gave it a value, and again whenever an update
83 /// writes any other column of the record, unless the caller modified this field in that change.
85};
86
87namespace detail
88{
89
90 // clang-format off
91
92template <typename T>
93struct IsStdOptionalType: std::false_type {};
94
95template <typename T>
96struct IsStdOptionalType<std::optional<T>>: std::true_type {};
97
98template <typename T>
99constexpr bool IsStdOptional = IsStdOptionalType<T>::value;
100
101template <typename T>
102concept FieldElementType = SqlInputParameterBinder<T> && SqlOutputColumnBinder<T>;
103
104 // clang-format on
105
106 template <typename TargetType, typename P1, typename P2>
107 consteval auto Choose(TargetType defaultValue, P1 p1, P2 p2) noexcept
108 {
109 // An enum parameter is only ever the target itself: some compilers (MSVC) wrongly accept
110 // `TargetType { p }` for a different scoped enum, which would mis-select the parameter.
111 if constexpr (!std::same_as<P1, std::nullopt_t> && (!std::is_enum_v<P1> || std::same_as<P1, TargetType>)
112 && requires { TargetType { p1 }; })
113 return 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 }; })
116 return p2;
117 else
118 return defaultValue;
119 }
120
121 /// Whether @p T is a value type a @ref FieldTimestamp marker may be attached to.
122 template <typename T>
123 inline constexpr bool IsAutoTimestampValueType = OneOf<T, SqlDateTime, std::optional<SqlDateTime>>;
124
125 /// @brief Whether an auto-maintained timestamp value is unset, i.e. was never given a value.
126 ///
127 /// An optional timestamp is unset when it holds no value; a plain `SqlDateTime` is unset when it
128 /// has no date, as a default-constructed one has (no valid date has a zero month).
129 ///
130 /// @param value The timestamp value to test.
131 /// @return True if the data mapper may fill in the value.
132 template <typename T>
133 requires IsAutoTimestampValueType<T>
134 [[nodiscard]] constexpr bool IsUnsetTimestamp(T const& value) noexcept
135 {
136 if constexpr (IsStdOptional<T>)
137 return !value.has_value();
138 else
139 return value.sqlValue.month == 0;
140 }
141} // namespace detail
142
143/// @brief Represents a single column in a table.
144///
145/// This class is used to represent a single column in a table.
146/// It also keeps track of modified-state of the field.
147///
148/// The column name, index, nullability, and type are known at compile time.
149///
150/// @see DataMapper
151/// @ingroup DataMapper, DataTypes
152template <detail::FieldElementType T, auto P1 = std::nullopt, auto P2 = std::nullopt>
153struct Field
154{
155 /// The underlying value type of this field.
156 using ValueType = T;
157
158 /// The primary key mode for this field.
159 static constexpr auto IsPrimaryKeyValue = detail::Choose<PrimaryKey>(PrimaryKey::No, P1, P2);
160 /// If not empty, overrides the default column name in the database.
161 static constexpr auto ColumnNameOverride = detail::Choose<std::string_view>({}, P1, P2);
162 /// Which timestamp, if any, the data mapper maintains in this field.
163 static constexpr auto TimestampKind = detail::Choose<FieldTimestamp>(FieldTimestamp::None, P1, P2);
164
165 /// Indicates if the data mapper sets this field to the creation time of the record.
167
168 /// Indicates if the data mapper sets this field to the time the record was last written.
170
171 /// Indicates if the data mapper maintains this field as a timestamp of either kind.
173
174 static_assert(!IsAutoTimestamp || detail::IsAutoTimestampValueType<T>,
175 "A FieldTimestamp marker (CreatedAt / UpdatedAt) requires the field's value type to be SqlDateTime "
176 "or std::optional<SqlDateTime>.");
177
178 // clang-format off
179 constexpr Field() noexcept = default;
180 /// Default copy constructor.
181 constexpr Field(Field const&) noexcept = default;
182 /// Default copy assignment operator.
183 constexpr Field& operator=(Field const&) noexcept = default;
184 /// Default move constructor.
185 constexpr Field(Field&&) noexcept = default;
186 /// Default move assignment operator.
187 constexpr Field& operator=(Field&&) noexcept = default;
188 constexpr ~Field() noexcept = default;
189 // clang-format on
190
191 /// Constructs a new field with the given value.
192 template <typename... S>
193 requires std::constructible_from<T, S...>
194 constexpr Field(S&&... value) noexcept;
195
196 /// Assigns a new value to the field.
197 template <typename S>
198 requires std::constructible_from<T, S> && (!std::same_as<std::remove_cvref_t<S>, Field<T, P1, P2>>)
199 // NOLINTNEXTLINE(cppcoreguidelines-c-copy-assignment-signature)
200 constexpr Field& operator=(S&& value) noexcept;
201
202 /// Indicates if the field is optional, i.e., it can be NULL.
203 static constexpr auto IsOptional = detail::IsStdOptional<T>;
204
205 /// Indicates if the field is mandatory, i.e., it cannot be NULL.
206 static constexpr auto IsMandatory = !IsOptional;
207
208 /// Indicates if the field is a primary key.
209 static constexpr auto IsPrimaryKey = IsPrimaryKeyValue != PrimaryKey::No;
210
211 /// Indicates if this is a primary key, it also is auto-assigned by the client.
212 static constexpr auto IsAutoAssignPrimaryKey = IsPrimaryKeyValue == PrimaryKey::AutoAssign;
213
214 /// Indicates if this is a primary key, it also is auto-incremented by the database.
215 static constexpr auto IsAutoIncrementPrimaryKey = IsPrimaryKeyValue == PrimaryKey::ServerSideAutoIncrement;
216
217 /// Three-way comparison operator. The strength of the ordering comes from the underlying
218 /// type `T` — e.g. `Field<int>` is `std::strong_ordering`, `Field<double>` is
219 /// `std::partial_ordering` (because of NaN), `Field<std::string>` is `std::strong_ordering`.
220 /// Defined inline so the deduced return type is available at every call site, and so
221 /// `Field<T>` instantiation does not require `T` to have `operator<=>`.
222 constexpr auto operator<=>(Field const& other) const noexcept
223 requires requires(T const& a, T const& b) { a <=> b; }
224 {
225 return _value <=> other._value;
226 }
227
228 /// Compares the field value with the given value for equality.
229 constexpr bool operator==(Field const& other) const noexcept;
230
231 /// Compares the field value with the given value for inequality.
232 constexpr bool operator!=(Field const& other) const noexcept;
233
234 /// Compares the field value with the given value for equality.
235 template <typename S>
236 requires std::convertible_to<S, T>
237 constexpr bool operator==(S const& value) const noexcept;
238
239 /// Compares the field value with the given value for inequality.
240 template <typename S>
241 requires std::convertible_to<S, T>
242 constexpr bool operator!=(S const& value) const noexcept;
243
244 /// Returns a string representation of the value, suitable for use in debugging and logging.
245 [[nodiscard]] std::string InspectValue() const;
246
247 /// Sets the modified state of the field.
248 constexpr void SetModified(bool value) noexcept;
249
250 /// Checks if the field has been modified.
251 [[nodiscard]] constexpr bool IsModified() const noexcept;
252
253 /// Returns the value of the field.
254 [[nodiscard]] constexpr T const& Value() const noexcept;
255
256 /// When the field type is optional, returns the value or the given default value.
257 [[nodiscard]] constexpr auto ValueOr(auto&& defaultValue) const noexcept
258 requires IsOptional
259 {
260 return _value.value_or(std::forward<typename ValueType::value_type>(defaultValue));
261 }
262
263 /// Returns a mutable reference to the value of the field.
264 ///
265 /// @note If the field value is changed through this method, it will not be automatically marked as modified.
266 [[nodiscard]] constexpr T& MutableValue() noexcept;
267
268 private:
269 ValueType _value {};
270 bool _modified { true };
271};
272
273// clang-format off
274namespace detail
275{
276
277template <typename T>
278struct IsAutoAssignPrimaryKeyField: std::false_type {};
279
280template <typename T, auto P>
281struct IsAutoAssignPrimaryKeyField<Field<T, PrimaryKey::AutoAssign, P>>: std::true_type {};
282
283template <typename T, auto P>
284struct IsAutoAssignPrimaryKeyField<Field<T, P, PrimaryKey::AutoAssign>>: std::true_type {};
285
286template <typename T>
287struct IsAutoIncrementPrimaryKeyField: std::false_type {};
288
289template <typename T, auto P>
290struct IsAutoIncrementPrimaryKeyField<Field<T, PrimaryKey::ServerSideAutoIncrement, P>>: std::true_type {};
291
292template <typename T, auto P>
293struct IsAutoIncrementPrimaryKeyField<Field<T, P, PrimaryKey::ServerSideAutoIncrement>>: std::true_type {};
294
295template <typename T>
296struct IsFieldType: std::false_type {};
297
298template <typename T, auto P1, auto P2>
299struct IsFieldType<Field<T, P1, P2>>: std::true_type {};
300
301} // namespace detail
302// clang-format on
303
304/// Tests if T is a Field<> that is a primary key, of whichever @ref PrimaryKey kind.
305template <typename T>
306constexpr bool IsPrimaryKey = false;
307
308template <typename T, auto P1, auto P2>
309constexpr bool IsPrimaryKey<Field<T, P1, P2>> = Field<T, P1, P2>::IsPrimaryKey;
310
311/// Requires that T satisfies to be a field with storage and is considered a primary key.
312template <typename T>
313constexpr bool IsAutoIncrementPrimaryKey = detail::IsAutoIncrementPrimaryKeyField<T>::value;
314
315template <typename T>
316constexpr bool IsField = detail::IsFieldType<std::remove_cvref_t<T>>::value;
317
318/// The @ref FieldTimestamp kind of @p T: the field's marker if T is a Field<>, otherwise None.
319template <typename T>
320inline constexpr FieldTimestamp FieldTimestampOf = FieldTimestamp::None;
321
322/// The @ref FieldTimestamp kind of a Field<>.
323template <typename T, auto P1, auto P2>
324inline constexpr FieldTimestamp FieldTimestampOf<Field<T, P1, P2>> = Field<T, P1, P2>::TimestampKind;
325
326/// Tests if T is a Field<> whose value the data mapper maintains as a timestamp (CreatedAt or UpdatedAt).
327template <typename T>
328inline constexpr bool IsAutoTimestampField = FieldTimestampOf<std::remove_cvref_t<T>> != FieldTimestamp::None;
329
330/// Constructs a new field with the given value.
331template <detail::FieldElementType T, auto P1, auto P2>
332template <typename... S>
333 requires std::constructible_from<T, S...>
334constexpr LIGHTWEIGHT_FORCE_INLINE Field<T, P1, P2>::Field(S&&... value) noexcept:
335 _value(std::forward<S>(value)...)
336{
337}
338
339/// @copydoc Field::operator=(S&&)
340template <detail::FieldElementType T, auto P1, auto P2>
341template <typename S>
342 requires std::constructible_from<T, S> && (!std::same_as<std::remove_cvref_t<S>, Field<T, P1, P2>>)
343constexpr LIGHTWEIGHT_FORCE_INLINE Field<T, P1, P2>& Field<T, P1, P2>::operator=(S&& value) noexcept
344{
345 _value = std::forward<S>(value);
346 SetModified(true);
347 return *this;
348}
349
350template <detail::FieldElementType T, auto P1, auto P2>
351constexpr bool LIGHTWEIGHT_FORCE_INLINE Field<T, P1, P2>::operator==(Field const& other) const noexcept
352{
353 return _value == other._value;
354}
355
356template <detail::FieldElementType T, auto P1, auto P2>
357constexpr bool LIGHTWEIGHT_FORCE_INLINE Field<T, P1, P2>::operator!=(Field const& other) const noexcept
358{
359 return _value != other._value;
360}
361
362/// Equality comparison operator with a convertible value.
363template <detail::FieldElementType T, auto P1, auto P2>
364template <typename S>
365 requires std::convertible_to<S, T>
366constexpr bool LIGHTWEIGHT_FORCE_INLINE Field<T, P1, P2>::operator==(S const& value) const noexcept
367{
368 return _value == value;
369}
370
371/// Inequality comparison operator with a convertible value.
372template <detail::FieldElementType T, auto P1, auto P2>
373template <typename S>
374 requires std::convertible_to<S, T>
375constexpr bool LIGHTWEIGHT_FORCE_INLINE Field<T, P1, P2>::operator!=(S const& value) const noexcept
376{
377 return _value != value;
378}
379
380template <detail::FieldElementType T, auto P1, auto P2>
381inline LIGHTWEIGHT_FORCE_INLINE std::string Field<T, P1, P2>::InspectValue() const
382{
383 if constexpr (std::is_same_v<T, std::string>)
384 {
385 std::stringstream result;
386 result << std::quoted(_value, '\'');
387 return result.str();
388 }
389 else if constexpr (std::is_same_v<T, SqlText>)
390 {
391 std::stringstream result;
392 result << std::quoted(_value.value, '\'');
393 return result.str();
394 }
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(); })
404 {
405 if (_value.has_value())
406 return std::format("{}", _value.value());
407 else
408 return "NULL";
409 }
410 else
411 return std::format("{}", _value);
412}
413
414// ------------------------------------------------------------------------------------------------
415
416template <detail::FieldElementType T, auto P1, auto P2>
417constexpr LIGHTWEIGHT_FORCE_INLINE void Field<T, P1, P2>::SetModified(bool value) noexcept
418{
419 _modified = value;
420}
421
422template <detail::FieldElementType T, auto P1, auto P2>
423constexpr LIGHTWEIGHT_FORCE_INLINE bool Field<T, P1, P2>::IsModified() const noexcept
424{
425 return _modified;
426}
427
428template <detail::FieldElementType T, auto P1, auto P2>
429constexpr LIGHTWEIGHT_FORCE_INLINE T const& Field<T, P1, P2>::Value() const noexcept
430{
431 return _value;
432}
433
434template <detail::FieldElementType T, auto P1, auto P2>
435constexpr LIGHTWEIGHT_FORCE_INLINE T& Field<T, P1, P2>::MutableValue() noexcept
436{
437 return _value;
438}
439
440template <detail::FieldElementType T, auto P1, auto P2>
441struct SqlDataBinder<Field<T, P1, P2>>
442{
443 using ValueType = Field<T, P1, P2>;
444
445 static constexpr auto ColumnType = SqlDataBinder<T>::ColumnType;
446
447 static LIGHTWEIGHT_FORCE_INLINE SQLRETURN InputParameter(SQLHSTMT stmt,
448 SQLUSMALLINT column,
449 ValueType const& value,
451 {
452 return SqlDataBinder<T>::InputParameter(stmt, column, value.Value(), cb);
453 }
454
455 static LIGHTWEIGHT_FORCE_INLINE SQLRETURN
456 OutputColumn(SQLHSTMT stmt, SQLUSMALLINT column, ValueType* result, SQLLEN* indicator, SqlDataBinderCallback& cb)
457 {
458 return SqlDataBinder<T>::OutputColumn(stmt, column, &result->MutableValue(), indicator, cb);
459 }
460
461 /// @throws Whatever `SqlDataBinder<T>::GetColumn` throws — this forwards to an arbitrary binder
462 /// and cannot promise more than the one it wraps.
463 static LIGHTWEIGHT_FORCE_INLINE SQLRETURN
464 GetColumn(SQLHSTMT stmt, SQLUSMALLINT column, ValueType* result, SQLLEN* indicator, SqlDataBinderCallback const& cb)
465 {
466 return SqlDataBinder<T>::GetColumn(stmt, column, &result->emplace(), indicator, cb);
467 }
468
469 static LIGHTWEIGHT_FORCE_INLINE std::string Inspect(ValueType const& value) noexcept
470 {
471 return value.InspectValue();
472 }
473};
474
475/// @brief Retrieves the type of a member field in a record.
476///
477/// Field must be a member of the record type, and it must be a field type, e.g. `Field<int>` or `BelongsTo<OtherRecord>`.
478///
479/// @code
480/// using MyRecord = Record {
481/// Field<int> value;
482/// Field<std::optional<char>> optionalValue;
483/// };
484///
485/// using MyFieldType = ReferencedFieldTypeOf<&MyRecord::value>; // Retrieves `int`
486/// using MyOptionalFieldType = ReferencedFieldTypeOf<&MyRecord::optionalValue>; // Retrieves `std::optional<char>`
487/// @endcode
488///
489/// @ingroup DataMapper
490template <auto Field>
492#if defined(LIGHTWEIGHT_CXX26_REFLECTION)
493 typename std::remove_cvref_t<typename[:type_of(Field):]>::ValueType;
494#else
495 std::remove_cvref_t<decltype(std::declval<MemberClassType<decltype(Field)>>().*Field)>::ValueType;
496#endif
497
498} // namespace Lightweight
499
500template <Lightweight::detail::FieldElementType T, auto P1, auto P2>
501struct std::formatter<Lightweight::Field<T, P1, P2>>: std::formatter<T>
502{
503 template <typename FormatContext>
504 // NOLINTNEXTLINE(readability-identifier-naming)
505 auto format(Lightweight::Field<T, P1, P2> const& field, FormatContext& ctx) const
506 {
507 return formatter<T>::format(field.Value(), ctx);
508 }
509};
510
511/// Specialization for `Field<std::optional<T>, ...>`: `std::optional` has no
512/// `std::formatter` specialization in the standard library, so we inherit from
513/// the inner `std::formatter<T>` and render `"NULL"` for the empty case.
514template <Lightweight::detail::FieldElementType T, auto P1, auto P2>
515struct std::formatter<Lightweight::Field<std::optional<T>, P1, P2>>: std::formatter<T>
516{
517 template <typename FormatContext>
518 // NOLINTNEXTLINE(readability-identifier-naming)
519 auto format(Lightweight::Field<std::optional<T>, P1, P2> const& field, FormatContext& ctx) const
520 {
521 if (field.Value().has_value())
522 return formatter<T>::format(field.Value().value(), ctx);
523
524 // Fallback for the NULL case — write "NULL" verbatim through the format context.
525 constexpr std::string_view nullText { "NULL" };
526 return std::ranges::copy(nullText, ctx.out()).out;
527 }
528};
FieldTimestamp
Tells the data mapper that this field is a timestamp it maintains automatically, or not.
Definition Field.hpp:71
std::remove_cvref_t< decltype(std::declval< MemberClassType< decltype(Field)> >().*Field)>::ValueType ReferencedFieldTypeOf
Retrieves the type of a member field in a record.
Definition Field.hpp:495
@ 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.
Definition Field.hpp:154
T ValueType
The underlying value type of this field.
Definition Field.hpp:156
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.
Definition Field.hpp:423
constexpr T & MutableValue() noexcept
Definition Field.hpp:435
static constexpr auto TimestampKind
Which timestamp, if any, the data mapper maintains in this field.
Definition Field.hpp:163
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.
Definition Field.hpp:357
static constexpr auto IsAutoTimestamp
Indicates if the data mapper maintains this field as a timestamp of either kind.
Definition Field.hpp:172
constexpr void SetModified(bool value) noexcept
Sets the modified state of the field.
Definition Field.hpp:417
static constexpr auto IsUpdatedAtTimestamp
Indicates if the data mapper sets this field to the time the record was last written.
Definition Field.hpp:169
static constexpr auto IsCreatedAtTimestamp
Indicates if the data mapper sets this field to the creation time of the record.
Definition Field.hpp:166
constexpr T const & Value() const noexcept
Returns the value of the field.
Definition Field.hpp:429
constexpr bool operator==(Field const &other) const noexcept
Compares the field value with the given value for equality.
Definition Field.hpp:351
static constexpr auto IsPrimaryKey
Indicates if the field is a primary key.
Definition Field.hpp:209
static constexpr auto IsMandatory
Indicates if the field is mandatory, i.e., it cannot be NULL.
Definition Field.hpp:206
static constexpr auto IsPrimaryKeyValue
The primary key mode for this field.
Definition Field.hpp:159
constexpr auto ValueOr(auto &&defaultValue) const noexcept
When the field type is optional, returns the value or the given default value.
Definition Field.hpp:257
static constexpr auto IsOptional
Indicates if the field is optional, i.e., it can be NULL.
Definition Field.hpp:203
static constexpr auto IsAutoAssignPrimaryKey
Indicates if this is a primary key, it also is auto-assigned by the client.
Definition Field.hpp:212
std::string InspectValue() const
Returns a string representation of the value, suitable for use in debugging and logging.
Definition Field.hpp:381
static constexpr auto ColumnNameOverride
If not empty, overrides the default column name in the database.
Definition Field.hpp:161
static constexpr auto IsAutoIncrementPrimaryKey
Indicates if this is a primary key, it also is auto-incremented by the database.
Definition Field.hpp:215