userver: userver/storages/mysql/impl/io/decimal_binder.hpp Source File
⚠️ This is the documentation for an old userver version. Click here to switch to the latest version.
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Concepts
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