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 :
public USERVER_NAMESPACE::utils::StrongTypedef<
41 detail::TimePointTzTag,
43 USERVER_NAMESPACE::utils::StrongTypedefOps::kCompareTransparent> {
44 using StrongTypedef::StrongTypedef;
46 operator TimePoint()
const {
return GetUnderlying(); }
53std::ostream& operator<<(std::ostream&, TimePointTz);
62struct TimePointWithoutTz
final :
public USERVER_NAMESPACE::utils::StrongTypedef<
63 detail::TimePointWithoutTzTag,
65 USERVER_NAMESPACE::utils::StrongTypedefOps::kCompareTransparent> {
66 using StrongTypedef::StrongTypedef;
68 operator TimePoint()
const {
return GetUnderlying(); }
75std::ostream& operator<<(std::ostream&, TimePointWithoutTz);
105template <
typename Duration,
typename Buffer>
106void DoFormatTimePoint(std::chrono::time_point<ClockType, Duration> value,
const UserTypes& types, Buffer& buf) {
107 static const auto pg_epoch = std::chrono::time_point_cast<Duration>(PostgresEpochTimePoint());
108 if (value == kTimestampPositiveInfinity) {
109 WriteBuffer(types, buf, std::numeric_limits<Bigint>::max());
110 }
else if (value == kTimestampNegativeInfinity) {
111 WriteBuffer(types, buf, std::numeric_limits<Bigint>::min());
113 const auto tmp = std::chrono::duration_cast<std::chrono::microseconds>(value - pg_epoch).count();
114 WriteBuffer(types, buf, tmp);
118template <
typename Duration>
119void DoParseTimePoint(std::chrono::time_point<ClockType, Duration>& value,
const FieldBuffer& buffer) {
120 static const auto pg_epoch = std::chrono::time_point_cast<Duration>(PostgresEpochTimePoint());
122 ReadBuffer(buffer, usec);
123 if (usec == std::numeric_limits<Bigint>::max()) {
124 value = kTimestampPositiveInfinity;
125 }
else if (usec == std::numeric_limits<Bigint>::min()) {
126 value = kTimestampNegativeInfinity;
128 value = pg_epoch + std::chrono::microseconds{usec};
133struct TimePointStrongTypedefFormatter {
136 explicit TimePointStrongTypedefFormatter(T val) : value{val} {}
138 template <
typename Buffer>
139 void operator()(
const UserTypes& types, Buffer& buf)
const {
140 detail::DoFormatTimePoint(value.GetUnderlying(), types, buf);
145struct TimePointStrongTypedefParser : BufferParserBase<T> {
146 using BufferParserBase<T>::BufferParserBase;
148 void operator()(
const FieldBuffer& buffer) { detail::DoParseTimePoint(
this->value.GetUnderlying(), buffer); }
155struct BufferFormatter<TimePointTz> : detail::TimePointStrongTypedefFormatter<TimePointTz> {
156 using TimePointStrongTypedefFormatter::TimePointStrongTypedefFormatter;
161struct BufferFormatter<TimePointWithoutTz> : detail::TimePointStrongTypedefFormatter<TimePointWithoutTz> {
162 using TimePointStrongTypedefFormatter::TimePointStrongTypedefFormatter;
167struct BufferParser<TimePointTz> : detail::TimePointStrongTypedefParser<TimePointTz> {
168 using TimePointStrongTypedefParser::TimePointStrongTypedefParser;
173struct BufferParser<TimePointWithoutTz> : detail::TimePointStrongTypedefParser<TimePointWithoutTz> {
174 using TimePointStrongTypedefParser::TimePointStrongTypedefParser;
182struct BufferFormatter<TimePoint> {
183 using ValueType = TimePoint;
185 const ValueType value;
187 explicit BufferFormatter(ValueType val) : value{val} {}
189 template <
typename Buffer>
190 void operator()(
const UserTypes& types, Buffer& buf)
const {
191#if !USERVER_POSTGRES_ENABLE_LEGACY_TIMESTAMP
194 "====================> userver: Writing "
195 "std::chrono::system_clock::time_point is not supported. "
196 "Rewrite using the TimePointWithoutTz or TimePointTz types, "
197 "or define USERVER_POSTGRES_ENABLE_LEGACY_TIMESTAMP to 1."
200 detail::DoFormatTimePoint(value, types, buf);
209struct BufferParser<TimePoint> : detail::BufferParserBase<TimePoint> {
210 using BufferParserBase::BufferParserBase;
212 void operator()(
const FieldBuffer& buffer) { detail::DoParseTimePoint(
this->value, buffer); }
217template <
typename Rep,
typename Period>
218struct DurationIntervalCvt {
219 using UserType = std::chrono::duration<Rep, Period>;
220 UserType operator()(
const Interval& wire_val)
const {
221 return std::chrono::duration_cast<UserType>(wire_val.GetDuration());
223 Interval operator()(
const UserType& user_val)
const {
224 return Interval{std::chrono::duration_cast<IntervalType>(user_val)};
253struct CppToSystemPg<TimePointTz> : PredefinedOid<PredefinedOids::kTimestamptz> {};
256struct CppToSystemPg<TimePointWithoutTz> : PredefinedOid<PredefinedOids::kTimestamp> {};
259template <
typename Duration>
260struct CppToSystemPg<std::chrono::time_point<ClockType, Duration>> : PredefinedOid<PredefinedOids::kTimestamp> {};
262template <
typename Rep,
typename Period>
263struct CppToSystemPg<std::chrono::duration<Rep, Period>> : PredefinedOid<PredefinedOids::kInterval> {};
287struct std::hash<USERVER_NAMESPACE::storages::
postgres::TimePointTz> {
288 std::size_t operator()(
const USERVER_NAMESPACE::storages::
postgres::TimePointTz& v)
290 return std::hash<USERVER_NAMESPACE::storages::postgres::TimePoint::duration::rep>{}(
291 v.GetUnderlying().time_since_epoch().count()
298struct std::hash<USERVER_NAMESPACE::storages::
postgres::TimePointWithoutTz> {
299 std::size_t operator()(
const USERVER_NAMESPACE::storages::
postgres::TimePointWithoutTz& v)
301 return std::hash<USERVER_NAMESPACE::storages::postgres::TimePoint::duration::rep>{}(
302 v.GetUnderlying().time_since_epoch().count()