userver: userver/storages/postgres/io/json_types.hpp Source File
Loading...
Searching...
No Matches
json_types.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/storages/postgres/io/json_types.hpp
4/// @brief JSON I/O support
5/// @ingroup userver_postgres_parse_and_format
6
7#include <type_traits>
8
9#include <userver/storages/postgres/exceptions.hpp>
10#include <userver/storages/postgres/io/buffer_io_base.hpp>
11#include <userver/storages/postgres/io/field_buffer.hpp>
12#include <userver/storages/postgres/io/traits.hpp>
13#include <userver/storages/postgres/io/type_mapping.hpp>
14#include <userver/storages/postgres/io/type_traits.hpp>
15#include <userver/storages/postgres/io/user_types.hpp>
16
17#include <userver/formats/json/raw_string.hpp>
18#include <userver/formats/json/value.hpp>
19#include <userver/utils/strong_typedef.hpp>
20
21// TODO: remove this include
22#include <userver/formats/json.hpp>
23
24USERVER_NAMESPACE_BEGIN
25
26namespace storages::postgres {
27
28using PlainJson = USERVER_NAMESPACE::utils::StrongTypedef<
29 struct PlainJsonTag,
30 formats::json::Value,
31 USERVER_NAMESPACE::utils::StrongTypedefOps::kCompareTransparent>;
32
33namespace io {
34namespace detail {
35
36inline constexpr char kJsonbVersion = 1;
37
38struct JsonParser : BufferParserBase<formats::json::Value> {
39 using BaseType = BufferParserBase<formats::json::Value>;
40 using BaseType::BaseType;
41
42 void operator()(const FieldBuffer& buffer);
43};
44
45struct JsonRawStringParser : BufferParserBase<formats::json::RawString> {
46 using BaseType = BufferParserBase<formats::json::RawString>;
47 using BaseType::BaseType;
48
49 void operator()(const FieldBuffer& buffer);
50};
51
52void JsonValueToBuffer(const formats::json::Value& value, std::vector<char>& buffer);
53
54void JsonValueToBuffer(const formats::json::Value& value, std::string& buffer);
55
56template <typename JsonValue>
57struct JsonFormatter : BufferFormatterBase<JsonValue> {
58 using BaseType = BufferFormatterBase<JsonValue>;
59 using BaseType::BaseType;
60
61 template <typename Buffer>
62 void operator()(const UserTypes&, Buffer& buffer) const {
63 if constexpr (!std::is_same_v<PlainJson, JsonValue>) {
64 buffer.push_back(kJsonbVersion);
65 }
66
67 detail::JsonValueToBuffer(static_cast<const formats::json::Value&>(this->value), buffer);
68 }
69};
70
71struct JsonRawStringFormatter : BufferFormatterBase<formats::json::RawString> {
72 using BaseType = BufferFormatterBase<formats::json::RawString>;
73 using BaseType::BaseType;
74
75 template <typename Buffer>
76 void operator()(const UserTypes&, Buffer& buffer) const {
77 WriteAsJsonb(buffer);
78 }
79
80 template <typename Buffer>
81 void operator()(const UserTypes&, Buffer& buffer, Oid replace_oid) const {
82 if (replace_oid == static_cast<Oid>(PredefinedOids::kJson)) {
84 "formats::json::RawString binds as jsonb and cannot be written to a PostgreSQL json "
85 "field; explicitly cast to the expected type in SQL query (e.g. `$1::json`)"
86 };
87 }
88 WriteAsJsonb(buffer);
89 }
90
91private:
92 template <typename Buffer>
93 void WriteAsJsonb(Buffer& buffer) const {
94 const auto view = this->value.GetView();
95 if constexpr (traits::CanReserve<Buffer>) {
96 buffer.reserve(buffer.size() + 1 + view.size());
97 }
98 buffer.push_back(kJsonbVersion);
99 buffer.insert(buffer.end(), view.begin(), view.end());
100 }
101};
102
103} // namespace detail
104
105namespace traits {
106
107template <>
108struct Input<formats::json::Value> {
109 using type = io::detail::JsonParser;
110};
111
112template <>
113struct Input<formats::json::RawString> {
114 using type = io::detail::JsonRawStringParser;
115};
116
117template <>
118struct ParserBufferCategory<io::detail::JsonParser>
119 : std::integral_constant<BufferCategory, BufferCategory::kPlainBuffer> {};
120
121template <>
122struct ParserBufferCategory<io::detail::JsonRawStringParser>
123 : std::integral_constant<BufferCategory, BufferCategory::kPlainBuffer> {};
124
125template <>
126struct Output<formats::json::Value> {
127 using type = io::detail::JsonFormatter<formats::json::Value>;
128};
129
130template <>
131struct Output<PlainJson> {
132 using type = io::detail::JsonFormatter<PlainJson>;
133};
134
135template <>
136struct Output<formats::json::RawString> {
137 using type = io::detail::JsonRawStringFormatter;
138};
139
140} // namespace traits
141
142template <>
143struct CppToSystemPg<formats::json::Value> : PredefinedOid<PredefinedOids::kJsonb> {};
144
145template <>
146struct CppToSystemPg<formats::json::RawString> : PredefinedOid<PredefinedOids::kJsonb> {};
147
148template <>
149struct CppToSystemPg<PlainJson> : PredefinedOid<PredefinedOids::kJson> {};
150
151} // namespace io
152} // namespace storages::postgres
153
154USERVER_NAMESPACE_END