userver: userver/storages/postgres/io/bytea.hpp Source File
Loading...
Searching...
No Matches
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