userver: userver/storages/postgres/io/user_types.hpp Source File
Loading...
Searching...
No Matches
user_types.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/storages/postgres/io/user_types.hpp
4/// @brief User types I/O support
5/// @ingroup userver_postgres_parse_and_format
6
7#include <unordered_map>
8#include <unordered_set>
9
10#include <userver/storages/postgres/exceptions.hpp>
11#include <userver/storages/postgres/io/pg_types.hpp>
12#include <userver/storages/postgres/io/type_mapping.hpp>
13
14USERVER_NAMESPACE_BEGIN
15
16namespace storages::postgres {
17namespace io {
18/// @page pg_user_types uPg: Mapping a C++ type to PostgreSQL user type
19///
20/// In PosgtgreSQL the following kinds of user types are available:
21/// - composite (row) types, see @ref pg_composite_types
22/// - enumerations, see @ref pg_enum
23/// - ranges, see @ref pg_range_types
24/// - domains
25///
26/// Domains are essentially some data types with database constraints applied
27/// to them, they map to their base data types' C++ counterparts.
28///
29/// Other user types can be mapped to C++ types, more information on defining
30/// a mapped C++ type can be found on respective pages. After a C++ type is
31/// defined, it must be mapped to it's PostgreSQL counterpart by specialising
32/// CppToUserPg template for the type. C++ types are mapped to PostgreSQL
33/// types by their names, so the specialization for CppToUserPg template
34/// must have a `static constexpr` member of type DBTypeName named
35/// `postgres_name`.
36///
37/// @par C++ type
38///
39/// @snippet storages/postgres/tests/user_types_pgtest.cpp User type
40///
41/// @par Declaring C++ type to PostgreSQL type mapping
42///
43/// @warning The type mapping specialization **must** be accessible at the
44/// points where parsing/formatting of the C++ type is instantiated. The
45/// header where the C++ type is declared is an appropriate place to do it.
46///
47/// @snippet storages/postgres/tests/user_types_pgtest.cpp User type mapping
48///
49/// A connection gets the data types' definitions after connect and uses the
50/// definitions to map C++ types to PostgreSQL type oids.
51///
52///
53/// ----------
54///
55/// @htmlonly <div class="bottom-nav"> @endhtmlonly
56/// ⇦ @ref pg_topology | @ref pg_composite_types ⇨
57/// @htmlonly </div> @endhtmlonly
58} // namespace io
59
60/// @brief PostgreSQL composite type description
62 public:
64 CompositeTypeDescription(CompositeFieldDefs::const_iterator begin,
65 CompositeFieldDefs::const_iterator end)
66 : attributes_{begin, end} {}
67 std::size_t Size() const { return attributes_.size(); }
68 bool Empty() const { return attributes_.empty(); }
69 const CompositeFieldDef& operator[](std::size_t index) const {
70 if (index >= Size()) {
71 throw FieldIndexOutOfBounds{index};
72 }
73 return attributes_[index];
74 }
75
76 private:
77 CompositeFieldDefs attributes_;
78};
79
80/// @brief Container for connection-specific user data types.
81class UserTypes {
82 public:
84
85 UserTypes() = default;
86 UserTypes(const UserTypes&) = delete;
87 UserTypes(UserTypes&&) noexcept = default;
88
89 UserTypes& operator=(const UserTypes&) = delete;
90 UserTypes& operator=(UserTypes&&) noexcept = default;
91
92 void Reset();
93
94 Oid FindOid(DBTypeName) const;
95 Oid FindArrayOid(DBTypeName) const;
96 /// Find element type oid for an array type.
97 /// Returns invalid oid if the type is not an array or the type is not found
98 Oid FindElementOid(Oid) const;
99 DBTypeName FindName(Oid) const;
100 /// Find name of the base type for a domain or element type for an array.
101 /// For the rest of types returns the name for the oid if found.
103 /// Find base oid for a domain or element type for an array.
104 /// For the rest of types returns the oid itself.
105 Oid FindBaseOid(Oid) const;
106 Oid FindBaseOid(DBTypeName) const;
107 /// Find base oid for a domain.
108 /// For the rest of types returns the oid itself.
109 Oid FindDomainBaseOid(Oid) const;
110
111 bool HasParser(Oid) const;
112 io::BufferCategory GetBufferCategory(Oid) const;
113 const io::TypeBufferCategory& GetTypeBufferCategories() const;
114
115 void AddType(DBTypeDescription&& desc);
116 void AddCompositeFields(CompositeFieldDefs&& defs);
117
118 const CompositeTypeDescription& GetCompositeDescription(Oid) const;
119 /// Get type description by oid.
120 /// May return nullptr if the type was not loaded from the database
122
123 private:
124 using DescriptionSet =
131
132 DescriptionSet types_;
133 MapByOid by_oid_;
134 MapByName by_name_;
135 io::TypeBufferCategory buffer_categories_;
136 CompositeTypes composite_types_;
137};
138
139namespace io::detail {
140
141template <typename T>
142inline constexpr DBTypeName kPgUserTypeName = CppToUserPg<T>::postgres_name;
143
144template <typename T>
145struct CppToUserPgImpl {
146 static_assert(io::traits::CheckParser<T>());
147
148 using Type = T;
149 using Mapping = CppToUserPg<T>;
150 static constexpr DBTypeName postgres_name = kPgUserTypeName<T>;
151 static const detail::RegisterUserTypeParser init_;
152 static Oid GetOid(const UserTypes& user_types) {
153 // TODO Handle oid not found
154 return user_types.FindOid(init_.postgres_name);
155 }
156 static Oid GetArrayOid(const UserTypes& user_types) {
157 // TODO Handle oid not found
158 return user_types.FindArrayOid(init_.postgres_name);
159 }
160};
161
162template <typename T>
163const RegisterUserTypeParser CppToUserPgImpl<T>::init_ =
164 RegisterUserTypeParser::Register(kPgUserTypeName<T>,
165 compiler::GetTypeName<T>());
166} // namespace io::detail
167
168void LogRegisteredTypesOnce();
169
170} // namespace storages::postgres
171
172USERVER_NAMESPACE_END