12#include <userver/dump/fwd.hpp>
13#include <userver/storages/postgres/io/buffer_io.hpp>
14#include <userver/storages/postgres/io/buffer_io_base.hpp>
15#include <userver/storages/postgres/io/interval.hpp>
16#include <userver/storages/postgres/io/transform_io.hpp>
17#include <userver/storages/postgres/io/type_mapping.hpp>
18#include <userver/utils/strong_typedef.hpp>
20USERVER_NAMESPACE_BEGIN
25struct TimePointTzTag {};
26struct TimePointWithoutTzTag {};
29using ClockType = std::chrono::system_clock;
30using TimePoint = ClockType::time_point;
31using IntervalType = std::chrono::microseconds;
40struct TimePointTz
final
41 :
public USERVER_NAMESPACE::utils::StrongTypedef<
42 detail::TimePointTzTag,
44 USERVER_NAMESPACE::utils::StrongTypedefOps::kCompareTransparent> {
45 using StrongTypedef::StrongTypedef;
47 operator TimePoint()
const {
return GetUnderlying(); }
54std::ostream& operator<<(std::ostream&, TimePointTz);
63struct TimePointWithoutTz
final
64 :
public USERVER_NAMESPACE::utils::StrongTypedef<
65 detail::TimePointWithoutTzTag,
67 USERVER_NAMESPACE::utils::StrongTypedefOps::kCompareTransparent> {
68 using StrongTypedef::StrongTypedef;
70 operator TimePoint()
const {
return GetUnderlying(); }
77std::ostream& operator<<(std::ostream&, TimePointWithoutTz);
107template <
typename Duration,
typename Buffer>
108void DoFormatTimePoint(std::chrono::time_point<ClockType, Duration> value,
const UserTypes& types, Buffer& buf) {
111 WriteBuffer(types, buf, std::numeric_limits<Bigint>::max());
113 WriteBuffer(types, buf, std::numeric_limits<Bigint>::min());
115 const auto tmp = std::chrono::duration_cast<std::chrono::microseconds>(value - kPgEpoch).count();
116 WriteBuffer(types, buf, tmp);
120template <
typename Duration>
121void DoParseTimePoint(std::chrono::time_point<ClockType, Duration>& value,
const FieldBuffer& buffer) {
125 if (usec == std::numeric_limits<Bigint>::max()) {
127 }
else if (usec == std::numeric_limits<Bigint>::min()) {
130 value = kPgEpoch + std::chrono::microseconds{usec};
135struct TimePointStrongTypedefFormatter {
138 explicit TimePointStrongTypedefFormatter(T val)
142 template <
typename Buffer>
143 void operator()(
const UserTypes& types, Buffer& buf)
const {
144 detail::DoFormatTimePoint(value.GetUnderlying(), types, buf);
149struct TimePointStrongTypedefParser : BufferParserBase<T> {
150 using BufferParserBase<T>::BufferParserBase;
152 void operator()(
const FieldBuffer& buffer) { detail::DoParseTimePoint(
this->value.GetUnderlying(), buffer); }
159struct BufferFormatter<TimePointTz> : detail::TimePointStrongTypedefFormatter<TimePointTz> {
160 using TimePointStrongTypedefFormatter::TimePointStrongTypedefFormatter;
165struct BufferFormatter<TimePointWithoutTz> : detail::TimePointStrongTypedefFormatter<TimePointWithoutTz> {
166 using TimePointStrongTypedefFormatter::TimePointStrongTypedefFormatter;
171struct BufferParser<TimePointTz> : detail::TimePointStrongTypedefParser<TimePointTz> {
172 using TimePointStrongTypedefParser::TimePointStrongTypedefParser;
177struct BufferParser<TimePointWithoutTz> : detail::TimePointStrongTypedefParser<TimePointWithoutTz> {
178 using TimePointStrongTypedefParser::TimePointStrongTypedefParser;
186struct BufferFormatter<TimePoint> {
187 using ValueType = TimePoint;
189 const ValueType value;
191 explicit BufferFormatter(ValueType val)
195 template <
typename Buffer>
196 void operator()(
const UserTypes& types, Buffer& buf)
const {
197#if !USERVER_POSTGRES_ENABLE_LEGACY_TIMESTAMP
200 "====================> userver: Writing "
201 "std::chrono::system_clock::time_point is not supported. "
202 "Rewrite using the TimePointWithoutTz or TimePointTz types, "
203 "or define USERVER_POSTGRES_ENABLE_LEGACY_TIMESTAMP to 1."
206 detail::DoFormatTimePoint(value, types, buf);
215struct BufferParser<TimePoint> : detail::BufferParserBase<TimePoint> {
216 using BufferParserBase::BufferParserBase;
218 void operator()(
const FieldBuffer& buffer) { detail::DoParseTimePoint(
this->value, buffer); }
223template <
typename Rep,
typename Period>
224struct DurationIntervalCvt {
225 using UserType = std::chrono::duration<Rep, Period>;
226 UserType operator()(
const Interval& wire_val)
const {
227 return std::chrono::duration_cast<UserType>(wire_val.GetDuration());
229 Interval operator()(
const UserType& user_val)
const {
230 return Interval{std::chrono::duration_cast<IntervalType>(user_val)};
239template <
typename Rep,
typename Period>
240struct Output<std::chrono::duration<Rep, Period>> {
242 std::chrono::duration<Rep, Period>,
243 io::detail::Interval,
244 io::detail::DurationIntervalCvt<Rep, Period>>;
248template <
typename Rep,
typename Period>
249struct Input<std::chrono::duration<Rep, Period>> {
251 std::chrono::duration<Rep, Period>,
252 io::detail::Interval,
253 io::detail::DurationIntervalCvt<Rep, Period>>;
259struct CppToSystemPg<TimePointTz> : PredefinedOid<
PredefinedOids::kTimestamptz> {};
262struct CppToSystemPg<TimePointWithoutTz> : PredefinedOid<
PredefinedOids::kTimestamp> {};
265template <
typename Duration>
266struct CppToSystemPg<std::chrono::time_point<ClockType, Duration>> : PredefinedOid<
PredefinedOids::kTimestamp> {};
268template <
typename Rep,
typename Period>
269struct CppToSystemPg<std::chrono::duration<Rep, Period>> : PredefinedOid<
PredefinedOids::kInterval> {};
293struct std::hash<USERVER_NAMESPACE::storages::
postgres::TimePointTz> {
294 std::size_t operator()(
const USERVER_NAMESPACE::storages::
postgres::TimePointTz& v)
296 return std::hash<USERVER_NAMESPACE::storages::
postgres::TimePoint::duration::rep>{
297 }(v.GetUnderlying().time_since_epoch().count());
303struct std::hash<USERVER_NAMESPACE::storages::
postgres::TimePointWithoutTz> {
304 std::size_t operator()(
const USERVER_NAMESPACE::storages::
postgres::TimePointWithoutTz& v)
306 return std::hash<USERVER_NAMESPACE::storages::
postgres::TimePoint::duration::rep>{
307 }(v.GetUnderlying().time_since_epoch().count());