userver: userver/storages/mysql/impl/io/decimal_binder.hpp Source File
Loading...
Searching...
No Matches
decimal_binder.hpp
1#pragma once
2
3#include <userver/decimal64/decimal64.hpp>
4
5#include <userver/storages/mysql/impl/binder_fwd.hpp>
6#include <userver/storages/mysql/impl/io/common_binders.hpp>
7
8USERVER_NAMESPACE_BEGIN
9
10namespace storages::mysql::impl::io {
11
12template <int Prec, typename Policy>
13using Decimal64 = decimal64::Decimal<Prec, Policy>;
14
15template <int Prec, typename Policy>
16using Decimal64Opt = std::optional<Decimal64<Prec, Policy>>;
17
18class DecimalWrapper {
19 public:
20 // For input
21 template <int Prec, typename Policy>
22 DecimalWrapper(const Decimal64<Prec, Policy>& decimal);
23
24 // For output
25 template <int Prec, typename Policy>
26 DecimalWrapper(Decimal64<Prec, Policy>& decimal);
27
28 // For optional output
29 template <int Prec, typename Policy>
30 DecimalWrapper(std::optional<Decimal64<Prec, Policy>>& opt_decimal);
31
32 private:
33 friend class storages::mysql::impl::bindings::OutputBindings;
34 friend class storages::mysql::impl::bindings::InputBindings;
35
36 DecimalWrapper();
37
38 std::string GetValue() const;
39
40 void Restore(std::string_view db_representation) const;
41
42 template <typename T>
43 static void RestoreCb(void* source, std::string_view db_representation) {
44 auto* decimal = static_cast<T*>(source);
45 UASSERT(decimal);
46
47 *decimal = T{db_representation};
48 }
49
50 template <typename T>
51 static void RestoreOptionalCb(void* source,
52 std::string_view db_representation) {
53 auto* optional = static_cast<std::optional<T>*>(source);
54 UASSERT(optional);
55
56 optional->emplace(db_representation);
57 }
58
59 template <typename T>
60 static std::string GetValueCb(void* source) {
61 auto* decimal = static_cast<T*>(source);
62 UASSERT(decimal);
63
64 return ToString(*decimal);
65 }
66
67 void* source_{nullptr};
68 std::string (*get_value_cb_)(void*){nullptr};
69 void (*restore_cb_)(void*, std::string_view){nullptr};
70};
71
72template <int Prec, typename Policy>
73DecimalWrapper::DecimalWrapper(const Decimal64<Prec, Policy>& decimal)
74 // We only ever read from it via ToString()
75 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
76 : source_{const_cast<Decimal64<Prec, Policy>*>(&decimal)},
77 // this constructor takes const reference, that means we are binding
78 // for input
79 get_value_cb_{GetValueCb<Decimal64<Prec, Policy>>} {}
80
81template <int Prec, typename Policy>
82DecimalWrapper::DecimalWrapper(Decimal64<Prec, Policy>& decimal)
83 : source_{&decimal},
84 // this constructor takes non-const reference, that means we are binding
85 // for output
86 restore_cb_{RestoreCb<Decimal64<Prec, Policy>>} {}
87
88template <int Prec, typename Policy>
89DecimalWrapper::DecimalWrapper(
90 std::optional<Decimal64<Prec, Policy>>& opt_decimal)
91 : source_{&opt_decimal},
92 // this constructor takes non-const reference, that means we are binding
93 // for output optional
94 restore_cb_{RestoreOptionalCb<Decimal64<Prec, Policy>>} {}
95
96void FreestandingBind(OutputBindingsFwd& binds, std::size_t pos,
97 io::DecimalWrapper& val);
98void FreestandingBind(OutputBindingsFwd& binds, std::size_t pos,
99 std::optional<io::DecimalWrapper>& val);
100
101void FreestandingBind(InputBindingsFwd& binds, std::size_t pos,
102 const io::DecimalWrapper& val);
103void FreestandingBind(InputBindingsFwd& binds, std::size_t pos,
104 const std::optional<io::DecimalWrapper>& val);
105
106template <int Prec, typename Policy>
107void FreestandingBind(InputBindingsFwd& binds, std::size_t pos,
108 ExplicitCRef<Decimal64<Prec, Policy>> field) {
109 DecimalWrapper wrapper{field.Get()};
110
111 storages::mysql::impl::io::FreestandingBind(binds, pos, wrapper);
112}
113
114template <int Prec, typename Policy>
115void FreestandingBind(InputBindingsFwd& binds, std::size_t pos,
116 ExplicitCRef<Decimal64Opt<Prec, Policy>> field) {
117 const auto wrapper = [&field]() -> std::optional<DecimalWrapper> {
118 if (field.Get().has_value()) {
119 return DecimalWrapper{*field.Get()};
120 } else {
121 return std::nullopt;
122 }
123 }();
124
125 storages::mysql::impl::io::FreestandingBind(binds, pos, wrapper);
126}
127
128template <int Prec, typename Policy>
129void FreestandingBind(OutputBindingsFwd& binds, std::size_t pos,
130 ExplicitRef<Decimal64<Prec, Policy>> field) {
131 DecimalWrapper wrapper{field.Get()};
132
133 storages::mysql::impl::io::FreestandingBind(binds, pos, wrapper);
134}
135
136template <int Prec, typename Policy>
137void FreestandingBind(OutputBindingsFwd& binds, std::size_t pos,
138 ExplicitRef<Decimal64Opt<Prec, Policy>> field) {
139 // This doesn't have to be optional, but it's easier to distinguish this way
140 std::optional<DecimalWrapper> wrapper{field.Get()};
141
142 storages::mysql::impl::io::FreestandingBind(binds, pos, wrapper);
143}
144
145} // namespace storages::mysql::impl::io
146
147USERVER_NAMESPACE_END