userver: uPg: Composite user types
Loading...
Searching...
No Matches
uPg: Composite user types

The driver supports user-defined PostgreSQL composite types. The C++ counterpart type must satisfy the same requirements as for the row types, (uPg: Typed PostgreSQL results) and must provide a specialization of CppToUserPg template (uPg: Mapping a C++ type to PostgreSQL user type).

Parsing a composite structure from PostgreSQL buffer will throw an error if the number of fields in the postgres data is different from the number of data members in target C++ type. This is the only sanity control for the composite types. The driver doesn't check the data type oids, it's user's responsibility to provide structures with compatible data members.

Examples from tests
namespace pgtest {
struct FooBar {
int i{};
std::string s;
double d{};
std::vector<int> a;
std::vector<std::string> v;
bool operator==(const FooBar& rhs) const {
return i == rhs.i && s == rhs.s && d == rhs.d && a == rhs.a && v == rhs.v;
}
};
struct FooBarWithOptionalFields {
std::optional<int> i;
std::optional<std::string> s;
std::optional<double> d;
std::vector<int> a;
std::vector<std::string> v;
bool operator==(const FooBarWithOptionalFields& rhs) const {
return i == rhs.i && s == rhs.s && d == rhs.d && a == rhs.a && v == rhs.v;
}
};
using FooBarOpt = std::optional<FooBar>;
class FooClass {
int i{};
std::string s;
double d{};
std::vector<int> a;
std::vector<std::string> v;
public:
FooClass() = default;
explicit FooClass(int x) : i(x), s(std::to_string(x)), d(x), a{i}, v{s} {}
// Only non-const version of Introspect() is used by the uPostgres driver
auto Introspect() { return std::tie(i, s, d, a, v); }
auto GetI() const { return i; }
auto GetS() const { return s; }
auto GetD() const { return d; }
auto GetA() const { return a; }
auto GetV() const { return v; }
};
using FooTuple = std::tuple<int, std::string, double, std::vector<int>,
std::vector<std::string>>;
struct BunchOfFoo {
std::vector<FooBar> foobars;
bool operator==(const BunchOfFoo& rhs) const {
return foobars == rhs.foobars;
}
};
} // namespace pgtest
Warning
The type mapping specialization must be accessible at the points where parsing/formatting of the C++ type is instantiated. The header where the C++ type is declared is an appropriate place to do it.
// This specialization MUST go to the header together with the mapped type
template <>
struct CppToUserPg<pgtest::FooBar> {
static constexpr DBTypeName postgres_name = kCompositeName;
};
// This specialization MUST go to the header together with the mapped type
template <>
struct CppToUserPg<pgtest::FooClass> {
static constexpr DBTypeName postgres_name = kCompositeName;
};
// This specialization MUST go to the header together with the mapped type
template <>
struct CppToUserPg<pgtest::FooTuple> {
static constexpr DBTypeName postgres_name = kCompositeName;
};
template <>
struct CppToUserPg<pgtest::BunchOfFoo> {
static constexpr DBTypeName postgres_name = "__pgtest.foobars";
};
} // namespace storages::postgres::io