userver: userver/storages/postgres/io/user_types.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
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