userver: userver/storages/postgres/io/bytea.hpp Source File
⚠️ This is the documentation for an old userver version. Click here to switch to the latest version.
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
bytea.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/storages/postgres/io/bytea.hpp
4/// @brief storages::postgres::Bytea I/O support
5/// @ingroup userver_postgres_parse_and_format
6
7#include <string>
8#include <string_view>
9#include <vector>
10
11#include <userver/storages/postgres/exceptions.hpp>
12#include <userver/storages/postgres/io/buffer_io.hpp>
13#include <userver/storages/postgres/io/buffer_io_base.hpp>
14#include <userver/storages/postgres/io/type_mapping.hpp>
15
16USERVER_NAMESPACE_BEGIN
17
18namespace storages::postgres {
19
20/**
21 * @page pg_bytea uPg bytea support
22 *
23 * The driver allows reading and writing raw binary data from/to PostgreSQL
24 * `bytea` type.
25 *
26 * Reading and writing to PostgreSQL is implemented for `std::string`,
27 * `std::string_view` and `std::vector` of `char` or `unsigned char`.
28 *
29 * @warning When reading to `std::string_view` the value MUST NOT be used after
30 * the PostgreSQL result set is destroyed.
31 *
32 * @code
33 * namespace pg = storages::postgres;
34 * using namespace std::string_literals;
35 * std::string s = "\0\xff\x0afoobar"s;
36 * trx.Execute("select $1", pg::Bytea(tp));
37 * @endcode
38 *
39 * ----------
40 *
41 * @htmlonly <div class="bottom-nav"> @endhtmlonly
42 * ⇦ @ref pg_arrays | @ref scripts/docs/en/userver/mongodb.md ⇨
43 * @htmlonly </div> @endhtmlonly
44 */
45
46namespace io::traits {
47
48template <typename T>
49struct IsByteaCompatible : std::false_type {};
50
51template <>
52struct IsByteaCompatible<std::string> : std::true_type {};
53template <>
55template <typename... VectorArgs>
56struct IsByteaCompatible<std::vector<char, VectorArgs...>> : std::true_type {};
57template <typename... VectorArgs>
58struct IsByteaCompatible<std::vector<unsigned char, VectorArgs...>>
59 : std::true_type {};
60
61template <typename T>
62inline constexpr bool kIsByteaCompatible = IsByteaCompatible<T>::value;
63
64template <typename T>
66
67} // namespace io::traits
68
69namespace detail {
70
71template <typename ByteContainerRef>
72struct ByteaRefWrapper {
73 static_assert(std::is_reference<ByteContainerRef>::value,
74 "The container must be passed by reference");
75
76 using BytesType = std::decay_t<ByteContainerRef>;
77 static_assert(
78 io::traits::kIsByteaCompatible<BytesType>,
79 "This C++ type cannot be used with PostgreSQL `bytea` data type");
80
81 ByteContainerRef bytes;
82};
83
84} // namespace detail
85
86/// Helper function for writing binary data
87template <typename ByteContainer>
88detail::ByteaRefWrapper<const ByteContainer&> Bytea(
89 const ByteContainer& bytes) {
90 return {bytes};
91}
92
93/// Helper function for reading binary data
94template <typename ByteContainer>
95detail::ByteaRefWrapper<ByteContainer&> Bytea(ByteContainer& bytes) {
96 return {bytes};
97}
98
99/// Wrapper for binary data container
100template <typename ByteContainer>
103
104 static_assert(
106 "This C++ type cannot be used with PostgreSQL `bytea` data type");
107
108 ByteContainer bytes;
109};
110
111namespace io {
112
113template <typename ByteContainer>
114struct BufferParser<
121 using BaseType::BaseType;
123
124 void operator()(const FieldBuffer& buffer) {
125 if constexpr (std::is_same<typename ByteaType::BytesType,
126 std::string_view>{}) {
127 this->value.bytes = std::string_view{
128 reinterpret_cast<const char*>(buffer.buffer), buffer.length};
129 } else {
132 this->value.bytes.begin());
133 }
134 }
135};
136
137template <typename ByteContainer>
142 using BaseType =
144 using BaseType::BaseType;
145
146 void operator()(const FieldBuffer& buffer) {
148 }
149};
150
151template <typename ByteContainer>
152struct BufferFormatter<
159 using BaseType::BaseType;
160
161 template <typename Buffer>
162 void operator()(const UserTypes&, Buffer& buf) const {
163 buf.reserve(buf.size() + this->value.bytes.size());
164 buf.insert(buf.end(), this->value.bytes.begin(), this->value.bytes.end());
165 }
166};
167
168template <typename ByteContainer>
173 using BaseType =
175 using BaseType::BaseType;
176
177 template <typename Buffer>
178 void operator()(const UserTypes& types, Buffer& buffer) const {
180 }
181};
182
183template <typename ByteContainer>
184struct CppToSystemPg<postgres::detail::ByteaRefWrapper<ByteContainer>>
185 : PredefinedOid<PredefinedOids::kBytea> {};
186template <typename ByteContainer>
187struct CppToSystemPg<postgres::ByteaWrapper<ByteContainer>>
188 : PredefinedOid<PredefinedOids::kBytea> {};
189
190} // namespace io
191} // namespace storages::postgres
192
193USERVER_NAMESPACE_END