Cppgres
Build Postgres extensions in C++
Loading...
Searching...
No Matches
datum.hpp
Go to the documentation of this file.
1
4#pragma once
5
6#include "utils/utils.hpp"
7
8#include "imports.h"
9#include "memory.hpp"
10
11#include <cstdint>
12#include <optional>
13#include <string>
14
15namespace cppgres {
16
17struct oid {
18 oid(::Oid oid) : oid_(oid) {}
19 oid(oid &oid) : oid_(oid.oid_) {}
20
21 bool operator==(const oid &rhs) const { return oid_ == rhs.oid_; }
22 bool operator!=(const oid &rhs) const { return !(rhs == *this); }
23
24 bool operator==(const ::Oid &rhs) const { return oid_ == rhs; }
25 bool operator!=(const ::Oid &rhs) const { return oid_ != rhs; }
26
27 operator ::Oid() const { return oid_; }
28 operator ::Oid &() { return oid_; }
29
30private:
31 ::Oid oid_;
32};
33static_assert(sizeof(::Oid) == sizeof(oid));
34
35struct datum {
36 template <typename T, typename> friend struct datum_conversion;
37
38 operator const ::Datum &() const { return _datum; }
39
40 operator Pointer() const { return reinterpret_cast<Pointer>(_datum); }
41
42 datum() : _datum(0) {}
43 explicit datum(::Datum datum) : _datum(datum) {}
44
45 bool operator==(const datum &other) const { return _datum == other._datum; }
46
47private:
48 ::Datum _datum;
49 friend struct nullable_datum;
50};
51
52class null_datum_exception : public std::exception {
53 const char *what() const noexcept override { return "passed datum is null"; }
54};
55
57
58 bool is_null() const noexcept { return _ndatum.isnull; }
59
60 operator struct datum &() {
61 if (_ndatum.isnull) {
63 }
64 return _datum;
65 }
66
67 operator const ::Datum &() {
68 if (_ndatum.isnull) {
70 }
71 return _datum.operator const ::Datum &();
72 }
73
74 operator const struct datum &() const {
75 if (_ndatum.isnull) {
77 }
78 return _datum;
79 }
80
81 explicit nullable_datum(::NullableDatum d) : _ndatum(d) {}
82
83 explicit nullable_datum() : _ndatum({.isnull = true}) {}
84
85 explicit nullable_datum(::Datum d) : _ndatum({.value = d, .isnull = false}) {}
86 explicit nullable_datum(datum d) : _ndatum({.value = d._datum, .isnull = false}) {}
87
88 bool operator==(const nullable_datum &other) const {
89 if (is_null()) {
90 return other.is_null();
91 }
92 if (other.is_null()) {
93 return is_null();
94 }
95 return _datum.operator==(other._datum);
96 }
97
98private:
99 union {
100 ::NullableDatum _ndatum;
101 datum _datum;
102 };
103};
104
110template <typename T, typename = void> struct datum_conversion {
111
118 static T from_nullable_datum(const nullable_datum &d, const oid oid,
119 std::optional<memory_context> context = std::nullopt) = delete;
120
127 static T from_datum(const datum &, const oid,
128 std::optional<memory_context> context = std::nullopt) = delete;
134 static datum into_datum(const T &d) = delete;
135};
136
137template <typename T, typename R = T> struct default_datum_conversion {
144 static R from_nullable_datum(const nullable_datum &d, const oid oid,
145 std::optional<memory_context> context = std::nullopt) {
146 if (d.is_null()) {
147 throw std::runtime_error(cppgres::fmt::format("datum is null and can't be coerced into {}",
148 utils::type_name<T>()));
149 }
150 return datum_conversion<T>::from_datum(d, oid, context);
151 }
152};
153
154template <typename T>
155concept convertible_into_datum = requires(T t) {
156 { datum_conversion<T, void>::into_datum(std::declval<T>()) } -> std::same_as<datum>;
157};
158
159template <typename T>
160concept convertible_from_datum = requires(datum d, oid oid, std::optional<memory_context> context) {
161 { datum_conversion<T, void>::from_datum(d, oid, context) } -> std::same_as<T>;
162};
163
164template <typename T> struct unsupported_type {};
165
166template <typename T>
168T from_nullable_datum(const nullable_datum &d, const oid oid,
169 std::optional<memory_context> context = std::nullopt) {
170 return datum_conversion<std::remove_cv_t<T>>::from_nullable_datum(d, oid, context);
171}
172
173template <typename T> nullable_datum into_nullable_datum(const std::optional<T> &v) {
174 if (v.has_value()) {
175 return nullable_datum(datum_conversion<T>::into_datum(v.value()));
176 } else {
177 return nullable_datum();
178 }
179}
180
181template <typename T> nullable_datum into_nullable_datum(const T &v) {
182 if constexpr (std::same_as<nullable_datum, T>) {
183 return v;
184 }
185 return nullable_datum(datum_conversion<T>::into_datum(v));
186}
187
188template <typename T>
190 {
191 cppgres::from_nullable_datum<T>(std::declval<nullable_datum>(), std::declval<oid>(),
192 std::declval<std::optional<memory_context>>())
193 } -> std::same_as<T>;
194};
195
196template <typename T>
198 { cppgres::into_nullable_datum(std::declval<T>()) } -> std::same_as<nullable_datum>;
199};
200
201template <typename T> struct all_from_nullable_datum {
202private:
203 static constexpr std::size_t N = utils::tuple_size_v<T>;
204
205 template <std::size_t... I> static constexpr bool impl(std::index_sequence<I...>) {
206 return (
207 ... &&
208 convertible_from_nullable_datum<utils::remove_optional_t<utils::tuple_element_t<I, T>>>);
209 }
210
211public:
212 static constexpr bool value = impl(std::make_index_sequence<N>{});
213};
214
215} // namespace cppgres
Definition: datum.hpp:52
Definition: datum.hpp:160
Definition: datum.hpp:155
Definition: datum.hpp:201
A trait to convert from and into a cppgres::datum.
Definition: datum.hpp:110
static T from_datum(const datum &, const oid, std::optional< memory_context > context=std::nullopt)=delete
Convert from a datum.
static T from_nullable_datum(const nullable_datum &d, const oid oid, std::optional< memory_context > context=std::nullopt)=delete
Convert from a nullable datum.
static datum into_datum(const T &d)=delete
Convert datum into a type.
Definition: datum.hpp:35
Definition: datum.hpp:137
static R from_nullable_datum(const nullable_datum &d, const oid oid, std::optional< memory_context > context=std::nullopt)
Convert from a nullable datum.
Definition: datum.hpp:144
Definition: datum.hpp:56
Definition: datum.hpp:17
Definition: datum.hpp:164
Definition: value.hpp:8