summaryrefslogtreecommitdiff
path: root/libdbpp/command.h
blob: 48205691d460a687ff1ce016fbea913fa99dc26e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
#ifndef DB_COMMAND_H
#define DB_COMMAND_H

#include "command_fwd.h"
#include <glibmm/ustring.h>
#include <boost/date_time/posix_time/posix_time_types.hpp>
#include <memory>
#include <boost/lexical_cast.hpp>
#include <visibility.h>
#include <factory.h>
#include <type_traits>
#include "dbTypes.h"
#include "error.h"
#include <c++11Helpers.h>

namespace DB {
	/// Exception thrown when binding a parameter of type the connector doesn't support.
	class DLL_PUBLIC ParameterTypeNotSupported : public Error {
	};

	/// Exception thrown when binding a parameter out of range of those defined in the command.
	class DLL_PUBLIC ParameterOutOfRange : public Error {
	};

	/// Represents the basic options that can be passed when creating new commands.
	class DLL_PUBLIC CommandOptions {
		public:
			CommandOptions() = default;
			/// Constructor which populates the hash value only.
			explicit CommandOptions(std::size_t hash, const CommandOptionsMap & = CommandOptionsMap());
			virtual ~CommandOptions() = default;
			/// Standard special members
			SPECIAL_MEMBERS_DEFAULT(CommandOptions);

			/// An (optional) hash of the SQL statement.
			std::optional<std::size_t> hash;

		protected:
			/// Helper function to extract values from a CommandOptionsMap
			template<typename X, typename Y>
			static X get(const CommandOptionsMap & map, const Y & key, const X & def)
			{
				if (auto i = map.find(key); i != map.end()) {
					if constexpr (std::is_convertible<CommandOptionsMap::mapped_type, X>::value) {
						return i->second;
					}
					else {
						return boost::lexical_cast<X>(i->second);
					}
				}
				return def;
			}
			/// Helper function to test if a value is set in a CommandOptionsMap
			static bool isSet(const CommandOptionsMap & map, const std::string & key);
	};

	/// Represents the basics of any command to be executed against a database.
	class DLL_PUBLIC Command {
		public:
			/// Creates a new command from the given SQL.
			explicit Command(std::string sql);
			virtual ~Command() = 0;

			/// Standard special members
			SPECIAL_MEMBERS_COPY_RO(Command);

			/// Bind an integer to parameter i.
			virtual void	bindParamI(unsigned int i, int val) = 0;
			/// Bind an integer to parameter i.
			virtual void	bindParamI(unsigned int i, long val) = 0;
			/// Bind an integer to parameter i.
			virtual void	bindParamI(unsigned int i, long long val) = 0;
			/// Bind an integer to parameter i.
			virtual void	bindParamI(unsigned int i, unsigned int val) = 0;
			/// Bind an integer to parameter i.
			virtual void	bindParamI(unsigned int i, unsigned long int val) = 0;
			/// Bind an integer to parameter i.
			virtual void	bindParamI(unsigned int i, unsigned long long int val) = 0;

			/// Bind a boolean to parameter i.
			virtual void	bindParamB(unsigned int i, bool val) = 0;

			/// Bind a floating point number to parameter i.
			virtual void	bindParamF(unsigned int i, double val) = 0;
			/// Bind a floating point number to parameter i.
			virtual void	bindParamF(unsigned int i, float val) = 0;

			/// Bind a string to parameter i.
			virtual void	bindParamS(unsigned int i, const Glib::ustring &) = 0;
			/// Bind a string_view to parameter i.
			virtual void	bindParamS(unsigned int i, const std::string_view &) = 0;
			/// Bind a string to parameter i (wraps string_view).
			inline void bindParamS(unsigned int i, const std::string & v)
			{
				bindParamS(i, std::string_view(v));
			}

			/// Bind a duration to parameter i.
			virtual void	bindParamT(unsigned int i, const boost::posix_time::time_duration &) = 0;
			/// Bind a date time to parameter i.
			virtual void	bindParamT(unsigned int i, const boost::posix_time::ptime &) = 0;

			/// Bind a BLOB to parameter i.
			virtual void	bindParamBLOB(unsigned int i, const Blob &);

			/// Bind null to parameter i.
			virtual void	bindNull(unsigned int i) = 0;

			/// The SQL statement.
			const std::string sql;

			/// Bind a parameter by type based on C++ traits to parameter i.
			template<typename O>
			inline void bindParam(unsigned int i, const O & o)
			{
				if constexpr (std::is_null_pointer<O>::value ||
						std::is_same<O, std::nullopt_t>::value) {
					bindNull(i);
				}
				else if constexpr (std::is_same<O, bool>::value) {
					bindParamB(i, o);
				}
				else if constexpr (std::is_floating_point<O>::value) {
					bindParamF(i, o);
				}
				else if constexpr (std::is_same<O, boost::posix_time::time_duration>::value ||
						std::is_same<O, boost::posix_time::ptime>::value) {
					bindParamT(i, o);
				}
				else if constexpr (std::is_same<O, Blob>::value || std::is_convertible<O, Blob>::value) {
					bindParamBLOB(i, o);
				}
				else if constexpr (std::is_integral<O>::value && !std::is_pointer<O>::value) {
					bindParamI(i, o);
				}
				else if constexpr (std::is_convertible<O, std::string_view>::value &&
						std::is_pointer<O>::value) {
					if (o) {
						bindParamS(i, o);
					}
					else {
						bindNull(i);
					}
				}
				else if constexpr (std::is_same<O, Glib::ustring>::value ||
						std::is_convertible<O, std::string_view>::value) {
					// NOLINTNEXTLINE(hicpp-no-array-decay)
					bindParamS(i, o);
				}
				else if constexpr (std::is_constructible<bool, const O &>::value) {
					if (o) {
						bindParam(i, *o);
					}
					else {
						bindNull(i);
					}
				}
				else {
					static_assert(std::is_void_v<O>, "No suitable trait");
				}
			}

#define OPTWRAPPER(func) \
			template<typename O> \
			inline auto \
			func(unsigned int i, const O & o) -> typename std::enable_if< \
					std::is_constructible_v<bool, const O &> \
					&& !std::is_void_v<decltype(*o)> \
					>::type\
			{ \
				bool nn(o); \
				if (nn) \
					func(i, *o); \
				else \
					bindNull(i); \
			}
			/// @cond
			OPTWRAPPER(bindParamI);
			OPTWRAPPER(bindParamF);
			// NOLINTNEXTLINE(hicpp-no-array-decay)
			OPTWRAPPER(bindParamS);
			OPTWRAPPER(bindParamB);
			OPTWRAPPER(bindParamT);
			/// @endcond
#undef OPTWRAPPER
			/// Bind a (possibly null) c-string to parameter i.
			void bindParamS(unsigned int, const char * const);
			/// Bind a (possibly null) c-string to parameter i.
			void bindParamS(unsigned int, char * const);
	};
	using CommandOptionsFactory = AdHoc::Factory<CommandOptions, std::size_t, const CommandOptionsMap &>;
}

#endif