userver
C++ Async Framework
Toggle main menu visibility
Loading...
Searching...
No Matches
field.hpp
Go to the documentation of this file.
1
#
pragma
once
2
3
/// @file
4
/// @brief Result field accessors
5
6
#
include
<
cstddef
>
7
#
include
<
type_traits
>
8
#
include
<
utility
>
9
10
#
include
<
userver
/
storages
/
postgres
/
exceptions
.
hpp
>
11
#
include
<
userver
/
storages
/
postgres
/
io
/
supported_types
.
hpp
>
12
13
#
include
<
userver
/
storages
/
postgres
/
detail
/
const_data_iterator
.
hpp
>
14
15
USERVER_NAMESPACE_BEGIN
16
17
namespace
storages::
postgres
{
18
19
struct
FieldDescription
{
20
/// Index of the field in the result set
21
std::size_t
index
;
22
/// @brief The object ID of the field's data type.
23
Oid
type_oid
;
24
/// @brief The field name.
25
// TODO string_view
26
std::string
name
;
27
/// @brief If the field can be identified as a column of a specific table,
28
/// the object ID of the table; otherwise zero.
29
Oid
table_oid
;
30
/// @brief If the field can be identified as a column of a specific table,
31
/// the attribute number of the column; otherwise zero.
32
Integer
table_column
;
33
/// @brief The data type size (see pg_type.typlen). Note that negative
34
/// values denote variable-width types.
35
Integer
type_size
;
36
/// @brief The type modifier (see pg_attribute.atttypmod). The meaning of
37
/// the modifier is type-specific.
38
Integer
type_modifier
;
39
};
40
41
class
FieldView
final
{
42
public
:
43
using
size_type = std::size_t;
44
45
FieldView(
const
detail::ResultWrapper& res, size_type row_index, size_type field_index)
46
: res_{res},
47
row_index_{row_index},
48
field_index_{field_index}
49
{}
50
51
template
<
typename
T>
52
size_type To(T&& val)
const
{
53
using
ValueType = std::remove_cvref_t<T>;
54
auto
fb = GetBuffer();
55
return
ReadNullable(fb, std::forward<T>(val),
io
::
traits
::
IsNullable
<ValueType>{});
56
}
57
58
private
:
59
io
::
FieldBuffer
GetBuffer()
const
;
60
std::string_view Name()
const
;
61
Oid
GetTypeOid()
const
;
62
const
io
::TypeBufferCategory& GetTypeBufferCategories()
const
;
63
64
template
<
typename
T>
65
size_type ReadNullable(
const
io
::
FieldBuffer
& fb, T&& val, std::true_type)
const
{
66
using
ValueType = std::remove_cvref_t<T>;
67
using
NullSetter =
io
::
traits
::
GetSetNull
<ValueType>;
68
if
(fb.is_null) {
69
NullSetter::SetNull(val);
70
}
else
{
71
Read(fb, std::forward<T>(val));
72
}
73
return
fb.length;
74
}
75
76
template
<
typename
T>
77
size_type ReadNullable(
const
io
::
FieldBuffer
& buffer, T&& val, std::false_type)
const
{
78
if
(buffer.is_null) {
79
throw
FieldValueIsNull
{field_index_, Name(), val};
80
}
else
{
81
Read(buffer, std::forward<T>(val));
82
}
83
return
buffer.length;
84
}
85
86
template
<
typename
T>
87
void
Read(
const
io
::
FieldBuffer
& buffer, T&& val)
const
{
88
using
ValueType = std::remove_cvref_t<T>;
89
io
::
traits
::CheckParser<ValueType>();
90
try
{
91
io
::ReadBuffer(buffer, std::forward<T>(val), GetTypeBufferCategories());
92
}
catch
(
InvalidInputBufferSize
& ex) {
93
// InvalidInputBufferSize is not descriptive. Enriching with OID information and C++ types info
94
ex.AddMsgPrefix(
fmt
::format(
95
"Error while reading field #{0} '{1}' which database type {2} as a C++ type '{3}'. Refer to "
96
"the 'Supported data types' in the documentation to make sure that the database type is actually "
97
"representable as a C++ type '{3}'. Error details: "
,
98
field_index_,
99
Name(),
100
impl::OidPrettyPrint(GetTypeOid()),
101
compiler
::GetTypeName<T>()
102
));
103
UASSERT_MSG
(
false
, ex.what());
104
throw
;
105
}
catch
(
ResultSetError
& ex) {
106
ex.AddMsgSuffix(
fmt
::format(
" (ResultSet error while reading field #{} name `{}`)"
, field_index_, Name()));
107
throw
;
108
}
109
}
110
111
const
detail::ResultWrapper& res_;
112
const
size_type row_index_;
113
const
size_type field_index_;
114
};
115
116
/// @brief Accessor to a single field in a result set's row
117
class
Field
{
118
public
:
119
using
size_type = std::size_t;
120
121
size_type RowIndex()
const
{
return
row_index_; }
122
size_type FieldIndex()
const
{
return
field_index_; }
123
124
//@{
125
/** @name Field metadata */
126
/// Field name as named in query
127
std::string_view
Name
()
const
;
128
FieldDescription
Description()
const
;
129
130
Oid
GetTypeOid()
const
;
131
//@}
132
133
//@{
134
/** @name Data access */
135
bool
IsNull()
const
;
136
137
size_type Length()
const
;
138
139
/// Read the field's buffer into user-provided variable.
140
/// @throws FieldValueIsNull If the field is null and the C++ type is
141
/// not nullable.
142
template
<
typename
T>
143
size_type
To
(T&& val)
const
{
144
return
FieldView{*res_, row_index_, field_index_}.To(std::forward<T>(val));
145
}
146
147
/// Read the field's buffer into user-provided variable.
148
/// If the field is null, set the variable to the default value.
149
template
<
typename
T>
150
void
Coalesce
(T& val,
const
T& default_val)
const
{
151
if
(!IsNull()) {
152
To(val);
153
}
else
{
154
val = default_val;
155
}
156
}
157
158
/// Convert the field's buffer into a C++ type.
159
/// @throws FieldValueIsNull If the field is null and the C++ type is
160
/// not nullable.
161
template
<
typename
T>
162
typename
std::decay<T>::
type
As
()
const
{
163
T val{};
164
To(val);
165
return
val;
166
}
167
168
/// Convert the field's buffer into a C++ type.
169
/// If the field is null, return default value.
170
template
<
typename
T>
171
typename
std::decay<T>::
type
Coalesce
(
const
T& default_val)
const
{
172
if
(IsNull()) {
173
return
default_val;
174
}
175
return
As<T>();
176
}
177
//@}
178
const
io
::TypeBufferCategory& GetTypeBufferCategories()
const
;
179
180
protected
:
181
friend
class
Row
;
182
183
Field() =
default
;
184
185
Field(detail::ResultWrapperPtr res, size_type row, size_type col)
186
: res_{std::move(res)},
187
row_index_{row},
188
field_index_{col}
189
{}
190
191
//@{
192
/** @name Iteration support */
193
bool
IsValid()
const
;
194
int
Compare(
const
Field
& rhs)
const
;
195
std::ptrdiff_t Distance(
const
Field
& rhs)
const
;
196
Field
& Advance(std::ptrdiff_t);
197
//@}
198
199
private
:
200
detail::ResultWrapperPtr res_;
201
size_type row_index_{0};
202
size_type field_index_{0};
203
};
204
205
/// @brief Iterator over fields in a result set's row
206
class
ConstFieldIterator
207
:
public
detail::ConstDataIterator<
ConstFieldIterator
,
Field
, detail::IteratorDirection::kForward> {
208
public
:
209
ConstFieldIterator() =
default
;
210
211
private
:
212
friend
class
Row
;
213
214
ConstFieldIterator(detail::ResultWrapperPtr res, size_type row, size_type col)
215
: ConstDataIterator(std::move(res), row, col)
216
{}
217
};
218
219
/// @brief Reverse iterator over fields in a result set's row
220
class
ReverseConstFieldIterator
221
:
public
detail::ConstDataIterator<
ReverseConstFieldIterator
,
Field
, detail::IteratorDirection::kReverse> {
222
public
:
223
ReverseConstFieldIterator() =
default
;
224
225
private
:
226
friend
class
Row
;
227
228
ReverseConstFieldIterator(detail::ResultWrapperPtr res, size_type row, size_type col)
229
: ConstDataIterator(std::move(res), row, col)
230
{}
231
};
232
233
}
// namespace storages::postgres
234
235
USERVER_NAMESPACE_END
userver
storages
postgres
field.hpp
Generated on
for userver by
Doxygen
1.17.0