SQLon test coverage


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 99.7% 734 / 0 / 736
Functions: 100.0% 208 / 0 / 208
Branches: 77.4% 376 / 0 / 486

include/sqlon/expression.h
Line Branch Exec Source
1 /******************************************************************************
2 **
3 ** Copyright (C) 2026 Ivan Pinezhaninov <ivan.pinezhaninov@gmail.com>
4 **
5 ** This file is part of the SQLon - which can be found at
6 ** https://github.com/IvanPinezhaninov/sqlon/.
7 **
8 ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
9 ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
10 ** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
11 ** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
12 ** DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
13 ** OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
14 ** THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 **
16 ******************************************************************************/
17
18 #ifndef SQLON_EXPRESSION_H
19 #define SQLON_EXPRESSION_H
20
21 #include <sqlon/detail/nodes.h>
22 #include <sqlon/error.h>
23 #include <sqlon/export.h>
24
25 #include <cstddef>
26 #include <initializer_list>
27 #include <memory>
28 #include <string>
29 #include <string_view>
30 #include <type_traits>
31 #include <utility>
32 #include <vector>
33
34 namespace sqlon {
35
36 /** @brief Typed SQL value expression. */
37 template<typename T>
38 class expression;
39
40 /** @brief Typed reusable parameter slot for prepared queries. */
41 template<typename T>
42 class parameter_slot;
43
44 class query;
45 class select_query;
46 class ordering;
47 class window_spec;
48
49 namespace detail {
50
51 template<typename T>
52 struct normalized_type {
53 using decayed_type = std::decay_t<T>;
54 using type = std::conditional_t<std::is_same_v<decayed_type, const char*> || std::is_same_v<decayed_type, char*>,
55 std::string, parameter_expression_type_t<decayed_type>>;
56 };
57
58 template<std::size_t N>
59 struct normalized_type<const char (&)[N]> {
60 using type = std::string;
61 };
62
63 template<std::size_t N>
64 struct normalized_type<char (&)[N]> {
65 using type = std::string;
66 };
67
68 template<typename T>
69 using normalized_type_t = typename normalized_type<T>::type;
70
71 template<typename T>
72 struct is_expression : std::false_type {};
73
74 template<typename T>
75 struct is_expression<expression<T>> : std::true_type {};
76
77 template<typename T, typename = void>
78 struct is_expression_like : std::false_type {};
79
80 template<typename T>
81 struct is_expression_like<T, std::void_t<typename std::decay_t<T>::value_type>>
82 : std::is_base_of<expression<typename std::decay_t<T>::value_type>, std::decay_t<T>> {};
83
84 template<typename T, bool = is_expression_like<T>::value>
85 struct expression_value_type {
86 using type = normalized_type_t<T>;
87 };
88
89 template<typename T>
90 struct expression_value_type<T, true> {
91 using type = typename std::decay_t<T>::value_type;
92 };
93
94 template<typename T>
95 using expression_value_type_t = typename expression_value_type<T>::type;
96
97 template<typename... Values>
98 using are_non_query_values = std::conjunction<std::negation<std::is_base_of<query, std::decay_t<Values>>>...>;
99
100 template<typename Left, typename Right>
101 inline constexpr bool compatible_expression_types =
102 std::is_same_v<normalized_type_t<Left>, normalized_type_t<Right>> ||
103 (std::is_arithmetic_v<normalized_type_t<Left>> && std::is_arithmetic_v<normalized_type_t<Right>> &&
104 !std::is_same_v<normalized_type_t<Left>, bool> && !std::is_same_v<normalized_type_t<Right>, bool>) ||
105 std::is_same_v<normalized_type_t<Right>, std::nullptr_t>;
106
107 SQLON_API detail::expression_ptr make_expression_node(detail::expression_kind kind, std::string text = {},
108 std::vector<detail::expression_ptr> operands = {});
109
110 SQLON_API detail::expression_ptr make_binary_node(std::string operation, detail::expression_ptr left,
111 detail::expression_ptr right);
112
113 SQLON_API detail::expression_ptr make_raw_expression_node(std::string sql,
114 std::vector<detail::expression_ptr> operands);
115
116 SQLON_API std::size_t next_parameter_identity();
117
118 SQLON_API bool valid_function_name(std::string_view name) noexcept;
119
120 struct expression_access;
121
122 } // namespace detail
123
124 /** @brief Typed, reusable handle to a SQL expression. */
125 template<typename T>
126 class expression {
127 public:
128 /** @brief C++ value type represented by the expression. */
129 using value_type = T;
130
131 protected:
132 /** @brief Creates an expression from an internal node. */
133 1101 explicit expression(detail::expression_ptr node)
134 1101 : m_node(std::move(node))
135 1101 {}
136
137 public:
138 /** @brief Returns this expression with a SQL alias. */
139 14 expression<T> as(std::string alias) const
140 {
141
4/9
sqlon::expression<int>::as(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >) const:
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
✓ Branch 5 taken 1 time.
sqlon::expression<long>::as(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >) const:
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✗ Branch 5 not taken.
sqlon::expression<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::as(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >) const:
✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
✗ Branch 5 not taken.
14 if (alias.empty()) throw invalid_query{"an expression alias cannot be empty"};
142
8/18
sqlon::expression<int>::as(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >) const:
✗ Branch 1 not taken.
✗ Branch 6 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
sqlon::expression<long>::as(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >) const:
✓ Branch 1 taken 12 times.
✓ Branch 6 taken 12 times.
✓ Branch 12 taken 12 times.
✓ Branch 13 taken 12 times.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
sqlon::expression<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::as(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >) const:
✓ Branch 1 taken 1 time.
✓ Branch 6 taken 1 time.
✓ Branch 12 taken 1 time.
✓ Branch 13 taken 1 time.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
39 return expression<T>{detail::make_expression_node(detail::expression_kind::alias, std::move(alias), {m_node})};
143 13 }
144
145 /** @brief Creates an IS NULL predicate. */
146 1 expression<bool> is_null() const
147 {
148
5/7
✓ Branch 1 taken 1 time.
✓ Branch 4 taken 1 time.
✓ Branch 7 taken 1 time.
✓ Branch 13 taken 1 time.
✓ Branch 14 taken 1 time.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
5 return expression<bool>{detail::make_expression_node(detail::expression_kind::unary, "is_null", {m_node})};
149 1 }
150
151 /** @brief Creates an IS NOT NULL predicate. */
152 3 expression<bool> is_not_null() const
153 {
154
10/14
sqlon::expression<long>::is_not_null() const:
✓ Branch 1 taken 1 time.
✓ Branch 4 taken 1 time.
✓ Branch 7 taken 1 time.
✓ Branch 13 taken 1 time.
✓ Branch 14 taken 1 time.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
sqlon::expression<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::is_not_null() const:
✓ Branch 1 taken 2 times.
✓ Branch 4 taken 2 times.
✓ Branch 7 taken 2 times.
✓ Branch 13 taken 2 times.
✓ Branch 14 taken 2 times.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
15 return expression<bool>{detail::make_expression_node(detail::expression_kind::unary, "is_not_null", {m_node})};
155 3 }
156
157 /** @brief Creates an IS NULL predicate. */
158 1 expression<bool> operator==(std::nullptr_t) const
159 {
160 1 return is_null();
161 }
162
163 /** @brief Creates an IS NOT NULL predicate. */
164 1 expression<bool> operator!=(std::nullptr_t) const
165 {
166 1 return is_not_null();
167 }
168
169 /** @brief Creates an equality predicate with a compatible expression or value. */
170 template<typename Right>
171 expression<bool> operator==(Right&& right) const;
172
173 /** @brief Creates an inequality predicate with a compatible expression or value. */
174 template<typename Right>
175 expression<bool> operator!=(Right&& right) const;
176
177 /** @brief Creates a less-than predicate with a compatible expression or value. */
178 template<typename Right>
179 expression<bool> operator<(Right&& right) const;
180
181 /** @brief Creates a less-than-or-equal predicate with a compatible expression or value. */
182 template<typename Right>
183 expression<bool> operator<=(Right&& right) const;
184
185 /** @brief Creates a greater-than predicate with a compatible expression or value. */
186 template<typename Right>
187 expression<bool> operator>(Right&& right) const;
188
189 /** @brief Creates a greater-than-or-equal predicate with a compatible expression or value. */
190 template<typename Right>
191 expression<bool> operator>=(Right&& right) const;
192
193 /** @brief Named alias for the equality operator. */
194 template<typename Right>
195 4 expression<bool> eq(Right&& right) const
196 {
197 4 return operator==(std::forward<Right>(right));
198 }
199
200 /** @brief Named alias for the inequality operator. */
201 template<typename Right>
202 1 expression<bool> ne(Right&& right) const
203 {
204 1 return operator!=(std::forward<Right>(right));
205 }
206
207 /** @brief Named alias for the less-than operator. */
208 template<typename Right>
209 1 expression<bool> lt(Right&& right) const
210 {
211 1 return operator<(std::forward<Right>(right));
212 }
213
214 /** @brief Named alias for the less-than-or-equal operator. */
215 template<typename Right>
216 1 expression<bool> le(Right&& right) const
217 {
218 1 return operator<=(std::forward<Right>(right));
219 }
220
221 /** @brief Named alias for the greater-than operator. */
222 template<typename Right>
223 1 expression<bool> gt(Right&& right) const
224 {
225 1 return operator>(std::forward<Right>(right));
226 }
227
228 /** @brief Named alias for the greater-than-or-equal operator. */
229 template<typename Right>
230 1 expression<bool> ge(Right&& right) const
231 {
232 1 return operator>=(std::forward<Right>(right));
233 }
234
235 /** @brief Creates a numeric addition expression. */
236 template<typename Right, typename U = T, std::enable_if_t<std::is_arithmetic_v<U>, int> = 0>
237 expression<std::common_type_t<T, detail::expression_value_type_t<Right>>> operator+(Right&& right) const;
238
239 /** @brief Creates a numeric subtraction expression. */
240 template<typename Right, typename U = T, std::enable_if_t<std::is_arithmetic_v<U>, int> = 0>
241 expression<std::common_type_t<T, detail::expression_value_type_t<Right>>> operator-(Right&& right) const;
242
243 /** @brief Creates a numeric multiplication expression. */
244 template<typename Right, typename U = T, std::enable_if_t<std::is_arithmetic_v<U>, int> = 0>
245 expression<std::common_type_t<T, detail::expression_value_type_t<Right>>> operator*(Right&& right) const;
246
247 /** @brief Creates a numeric division expression. */
248 template<typename Right, typename U = T, std::enable_if_t<std::is_arithmetic_v<U>, int> = 0>
249 expression<std::common_type_t<T, detail::expression_value_type_t<Right>>> operator/(Right&& right) const;
250
251 /** @brief Named alias for numeric addition. */
252 template<typename Right, typename U = T, std::enable_if_t<std::is_arithmetic_v<U>, int> = 0>
253 1 expression<std::common_type_t<T, detail::expression_value_type_t<Right>>> add(Right&& right) const
254 {
255 1 return operator+(std::forward<Right>(right));
256 }
257
258 /** @brief Named alias for numeric subtraction. */
259 template<typename Right, typename U = T, std::enable_if_t<std::is_arithmetic_v<U>, int> = 0>
260 1 expression<std::common_type_t<T, detail::expression_value_type_t<Right>>> sub(Right&& right) const
261 {
262 1 return operator-(std::forward<Right>(right));
263 }
264
265 /** @brief Named alias for numeric multiplication. */
266 template<typename Right, typename U = T, std::enable_if_t<std::is_arithmetic_v<U>, int> = 0>
267 1 expression<std::common_type_t<T, detail::expression_value_type_t<Right>>> mul(Right&& right) const
268 {
269 1 return operator*(std::forward<Right>(right));
270 }
271
272 /** @brief Named alias for numeric division. */
273 template<typename Right, typename U = T, std::enable_if_t<std::is_arithmetic_v<U>, int> = 0>
274 1 expression<std::common_type_t<T, detail::expression_value_type_t<Right>>> div(Right&& right) const
275 {
276 1 return operator/(std::forward<Right>(right));
277 }
278
279 /** @brief Creates an ascending ordering for this expression. */
280 ordering asc() const;
281
282 /** @brief Creates a descending ordering for this expression. */
283 ordering desc() const;
284
285 /** @brief Creates an IN predicate from compatible values. */
286 template<typename... Values, std::enable_if_t<detail::are_non_query_values<Values...>::value, int> = 0>
287 expression<bool> in(Values&&... values) const;
288
289 /** @brief Creates an IN predicate from a subquery. */
290 expression<bool> in(const select_query& value) const;
291
292 /** @brief Creates a NOT IN predicate from compatible values. */
293 template<typename... Values, std::enable_if_t<detail::are_non_query_values<Values...>::value, int> = 0>
294 expression<bool> not_in(Values&&... values) const;
295
296 /** @brief Creates a NOT IN predicate from a subquery. */
297 expression<bool> not_in(const select_query& value) const;
298
299 /** @brief Creates a BETWEEN predicate with compatible bounds. */
300 template<typename Lower, typename Upper>
301 expression<bool> between(Lower&& lower, Upper&& upper) const;
302
303 /** @brief Creates a LIKE predicate for a string expression. */
304 template<typename Pattern>
305 expression<bool> like(Pattern&& pattern) const;
306
307 /** @brief Creates a NOT LIKE predicate for a string expression. */
308 template<typename Pattern>
309 expression<bool> not_like(Pattern&& pattern) const;
310
311 /** @brief Applies a window specification to this expression. */
312 expression<T> over(const window_spec& window) const;
313
314 private:
315 template<typename>
316 friend class expression;
317 friend struct detail::expression_access;
318
319 detail::expression_ptr m_node;
320 };
321
322 namespace detail {
323
324 struct expression_access final {
325 template<typename T>
326 446 static expression<T> make(expression_ptr node)
327 {
328 446 return expression<T>{std::move(node)};
329 }
330
331 template<typename T>
332 965 static const expression_ptr& node(const expression<T>& value) noexcept
333 {
334 965 return value.m_node;
335 }
336 };
337
338 } // namespace detail
339
340 /** @brief Converts an expression-like value to its base expression handle. */
341 template<typename T, std::enable_if_t<detail::is_expression_like<T>::value, int> = 0>
342 443 expression<typename std::decay_t<T>::value_type> to_expression(T&& value)
343 {
344 using value_type = typename std::decay_t<T>::value_type;
345 443 return static_cast<const expression<value_type>&>(value);
346 }
347
348 /** @brief Converts an ordinary C++ value to a bound parameter expression. */
349 template<typename T, std::enable_if_t<!detail::is_expression_like<T>::value, int> = 0>
350 262 expression<detail::normalized_type_t<T>> to_expression(T&& value)
351 {
352 using value_type = detail::normalized_type_t<T>;
353
15/15
sqlon::expression<sqlon::detail::normalized_type<ClientId>::type> sqlon::to_expression<ClientId, 0>(ClientId&&):
✓ Branch 1 taken 1 time.
sqlon::expression<sqlon::detail::normalized_type<ClientUuid const&>::type> sqlon::to_expression<ClientUuid const&, 0>(ClientUuid const&):
✓ Branch 1 taken 1 time.
sqlon::expression<sqlon::detail::normalized_type<bool>::type> sqlon::to_expression<bool, 0>(bool&&):
✓ Branch 1 taken 41 times.
sqlon::expression<sqlon::detail::normalized_type<char const (&) [4]>::type> sqlon::to_expression<char const (&) [4], 0>(char const (&) [4]):
✓ Branch 1 taken 11 times.
sqlon::expression<sqlon::detail::normalized_type<char const (&) [6]>::type> sqlon::to_expression<char const (&) [6], 0>(char const (&) [6]):
✓ Branch 1 taken 40 times.
sqlon::expression<sqlon::detail::normalized_type<char const (&) [7]>::type> sqlon::to_expression<char const (&) [7], 0>(char const (&) [7]):
✓ Branch 1 taken 3 times.
sqlon::expression<sqlon::detail::normalized_type<char const (&) [8]>::type> sqlon::to_expression<char const (&) [8], 0>(char const (&) [8]):
✓ Branch 1 taken 1 time.
sqlon::expression<sqlon::detail::normalized_type<decltype(nullptr)>::type> sqlon::to_expression<decltype(nullptr), 0>(decltype(nullptr)&&):
✓ Branch 1 taken 1 time.
sqlon::expression<sqlon::detail::normalized_type<double>::type> sqlon::to_expression<double, 0>(double&&):
✓ Branch 1 taken 2 times.
sqlon::expression<sqlon::detail::normalized_type<int>::type> sqlon::to_expression<int, 0>(int&&):
✓ Branch 1 taken 117 times.
sqlon::expression<sqlon::detail::normalized_type<long>::type> sqlon::to_expression<long, 0>(long&&):
✓ Branch 1 taken 5 times.
sqlon::expression<sqlon::detail::normalized_type<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::type> sqlon::to_expression<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, 0>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&&):
✓ Branch 1 taken 36 times.
sqlon::expression<sqlon::detail::normalized_type<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&>::type> sqlon::to_expression<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, 0>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&):
✓ Branch 1 taken 1 time.
sqlon::expression<sqlon::detail::normalized_type<std::vector<std::byte, std::allocator<std::byte> > const&>::type> sqlon::to_expression<std::vector<std::byte, std::allocator<std::byte> > const&, 0>(std::vector<std::byte, std::allocator<std::byte> > const&):
✓ Branch 1 taken 1 time.
sqlon::expression<sqlon::detail::normalized_type<unsigned long>::type> sqlon::to_expression<unsigned long, 0>(unsigned long&&):
✓ Branch 1 taken 1 time.
262 std::shared_ptr<detail::expression_node> node = std::make_shared<detail::expression_node>();
354 262 node->kind = detail::expression_kind::parameter;
355
22/22
sqlon::expression<sqlon::detail::normalized_type<ClientId>::type> sqlon::to_expression<ClientId, 0>(ClientId&&):
✓ Branch 4 taken 1 time.
sqlon::expression<sqlon::detail::normalized_type<ClientUuid const&>::type> sqlon::to_expression<ClientUuid const&, 0>(ClientUuid const&):
✓ Branch 3 taken 1 time.
✓ Branch 6 taken 1 time.
sqlon::expression<sqlon::detail::normalized_type<bool>::type> sqlon::to_expression<bool, 0>(bool&&):
✓ Branch 4 taken 41 times.
sqlon::expression<sqlon::detail::normalized_type<char const (&) [4]>::type> sqlon::to_expression<char const (&) [4], 0>(char const (&) [4]):
✓ Branch 3 taken 11 times.
✓ Branch 6 taken 11 times.
sqlon::expression<sqlon::detail::normalized_type<char const (&) [6]>::type> sqlon::to_expression<char const (&) [6], 0>(char const (&) [6]):
✓ Branch 3 taken 40 times.
✓ Branch 6 taken 40 times.
sqlon::expression<sqlon::detail::normalized_type<char const (&) [7]>::type> sqlon::to_expression<char const (&) [7], 0>(char const (&) [7]):
✓ Branch 3 taken 3 times.
✓ Branch 6 taken 3 times.
sqlon::expression<sqlon::detail::normalized_type<char const (&) [8]>::type> sqlon::to_expression<char const (&) [8], 0>(char const (&) [8]):
✓ Branch 3 taken 1 time.
✓ Branch 6 taken 1 time.
sqlon::expression<sqlon::detail::normalized_type<decltype(nullptr)>::type> sqlon::to_expression<decltype(nullptr), 0>(decltype(nullptr)&&):
✓ Branch 4 taken 1 time.
sqlon::expression<sqlon::detail::normalized_type<double>::type> sqlon::to_expression<double, 0>(double&&):
✓ Branch 4 taken 2 times.
sqlon::expression<sqlon::detail::normalized_type<int>::type> sqlon::to_expression<int, 0>(int&&):
✓ Branch 4 taken 117 times.
sqlon::expression<sqlon::detail::normalized_type<long>::type> sqlon::to_expression<long, 0>(long&&):
✓ Branch 4 taken 5 times.
sqlon::expression<sqlon::detail::normalized_type<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::type> sqlon::to_expression<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, 0>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&&):
✓ Branch 4 taken 36 times.
sqlon::expression<sqlon::detail::normalized_type<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&>::type> sqlon::to_expression<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, 0>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&):
✓ Branch 3 taken 1 time.
✓ Branch 6 taken 1 time.
sqlon::expression<sqlon::detail::normalized_type<std::vector<std::byte, std::allocator<std::byte> > const&>::type> sqlon::to_expression<std::vector<std::byte, std::allocator<std::byte> > const&, 0>(std::vector<std::byte, std::allocator<std::byte> > const&):
✓ Branch 3 taken 1 time.
✓ Branch 6 taken 1 time.
sqlon::expression<sqlon::detail::normalized_type<unsigned long>::type> sqlon::to_expression<unsigned long, 0>(unsigned long&&):
✓ Branch 4 taken 1 time.
262 node->bound_parameter.emplace(detail::make_parameter_value(std::forward<T>(value)));
356
5/6
sqlon::expression<sqlon::detail::normalized_type<bool>::type> sqlon::to_expression<bool, 0>(bool&&):
✗ Branch 3 not taken.
sqlon::expression<sqlon::detail::normalized_type<decltype(nullptr)>::type> sqlon::to_expression<decltype(nullptr), 0>(decltype(nullptr)&&):
✓ Branch 3 taken 1 time.
sqlon::expression<sqlon::detail::normalized_type<double>::type> sqlon::to_expression<double, 0>(double&&):
✓ Branch 3 taken 2 times.
sqlon::expression<sqlon::detail::normalized_type<int>::type> sqlon::to_expression<int, 0>(int&&):
✓ Branch 3 taken 117 times.
sqlon::expression<sqlon::detail::normalized_type<std::vector<std::byte, std::allocator<std::byte> > const&>::type> sqlon::to_expression<std::vector<std::byte, std::allocator<std::byte> > const&, 0>(std::vector<std::byte, std::allocator<std::byte> > const&):
✓ Branch 3 taken 1 time.
sqlon::expression<sqlon::detail::normalized_type<unsigned long>::type> sqlon::to_expression<unsigned long, 0>(unsigned long&&):
✓ Branch 3 taken 1 time.
524 return detail::expression_access::make<value_type>(std::move(node));
357 262 }
358
359 /** @brief Creates an explicit SQL literal expression. */
360 template<typename T>
361 43 expression<detail::normalized_type_t<T>> literal(T&& value)
362 {
363 using value_type = detail::normalized_type_t<T>;
364
12/12
sqlon::expression<sqlon::detail::normalized_type<PreparedDate>::type> sqlon::literal<PreparedDate>(PreparedDate&&):
✓ Branch 1 taken 1 time.
sqlon::expression<sqlon::detail::normalized_type<bool>::type> sqlon::literal<bool>(bool&&):
✓ Branch 1 taken 2 times.
sqlon::expression<sqlon::detail::normalized_type<char const (&) [9]>::type> sqlon::literal<char const (&) [9]>(char const (&) [9]):
✓ Branch 1 taken 2 times.
sqlon::expression<sqlon::detail::normalized_type<decltype(nullptr)>::type> sqlon::literal<decltype(nullptr)>(decltype(nullptr)&&):
✓ Branch 1 taken 1 time.
sqlon::expression<sqlon::detail::normalized_type<double>::type> sqlon::literal<double>(double&&):
✓ Branch 1 taken 2 times.
sqlon::expression<sqlon::detail::normalized_type<int>::type> sqlon::literal<int>(int&&):
✓ Branch 1 taken 28 times.
sqlon::expression<sqlon::detail::normalized_type<long>::type> sqlon::literal<long>(long&&):
✓ Branch 1 taken 1 time.
sqlon::expression<sqlon::detail::normalized_type<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::type> sqlon::literal<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&&):
✓ Branch 1 taken 2 times.
sqlon::expression<sqlon::detail::normalized_type<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&>::type> sqlon::literal<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&):
✓ Branch 1 taken 1 time.
sqlon::expression<sqlon::detail::normalized_type<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&>::type> sqlon::literal<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&):
✓ Branch 1 taken 1 time.
sqlon::expression<sqlon::detail::normalized_type<std::vector<std::byte, std::allocator<std::byte> > >::type> sqlon::literal<std::vector<std::byte, std::allocator<std::byte> > >(std::vector<std::byte, std::allocator<std::byte> >&&):
✓ Branch 1 taken 1 time.
sqlon::expression<sqlon::detail::normalized_type<unsigned long>::type> sqlon::literal<unsigned long>(unsigned long&&):
✓ Branch 1 taken 1 time.
43 std::shared_ptr<detail::expression_node> node = std::make_shared<detail::expression_node>();
365 43 node->kind = detail::expression_kind::literal;
366
16/16
sqlon::expression<sqlon::detail::normalized_type<PreparedDate>::type> sqlon::literal<PreparedDate>(PreparedDate&&):
✓ Branch 3 taken 1 time.
✓ Branch 6 taken 1 time.
sqlon::expression<sqlon::detail::normalized_type<bool>::type> sqlon::literal<bool>(bool&&):
✓ Branch 4 taken 2 times.
sqlon::expression<sqlon::detail::normalized_type<char const (&) [9]>::type> sqlon::literal<char const (&) [9]>(char const (&) [9]):
✓ Branch 3 taken 2 times.
✓ Branch 6 taken 2 times.
sqlon::expression<sqlon::detail::normalized_type<decltype(nullptr)>::type> sqlon::literal<decltype(nullptr)>(decltype(nullptr)&&):
✓ Branch 4 taken 1 time.
sqlon::expression<sqlon::detail::normalized_type<double>::type> sqlon::literal<double>(double&&):
✓ Branch 4 taken 2 times.
sqlon::expression<sqlon::detail::normalized_type<int>::type> sqlon::literal<int>(int&&):
✓ Branch 4 taken 28 times.
sqlon::expression<sqlon::detail::normalized_type<long>::type> sqlon::literal<long>(long&&):
✓ Branch 4 taken 1 time.
sqlon::expression<sqlon::detail::normalized_type<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::type> sqlon::literal<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&&):
✓ Branch 4 taken 2 times.
sqlon::expression<sqlon::detail::normalized_type<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&>::type> sqlon::literal<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&):
✓ Branch 3 taken 1 time.
✓ Branch 6 taken 1 time.
sqlon::expression<sqlon::detail::normalized_type<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&>::type> sqlon::literal<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&):
✓ Branch 3 taken 1 time.
✓ Branch 6 taken 1 time.
sqlon::expression<sqlon::detail::normalized_type<std::vector<std::byte, std::allocator<std::byte> > >::type> sqlon::literal<std::vector<std::byte, std::allocator<std::byte> > >(std::vector<std::byte, std::allocator<std::byte> >&&):
✓ Branch 4 taken 1 time.
sqlon::expression<sqlon::detail::normalized_type<unsigned long>::type> sqlon::literal<unsigned long>(unsigned long&&):
✓ Branch 4 taken 1 time.
43 node->bound_parameter.emplace(detail::make_parameter_value(std::forward<T>(value)));
367
6/6
sqlon::expression<sqlon::detail::normalized_type<PreparedDate>::type> sqlon::literal<PreparedDate>(PreparedDate&&):
✓ Branch 3 taken 1 time.
sqlon::expression<sqlon::detail::normalized_type<decltype(nullptr)>::type> sqlon::literal<decltype(nullptr)>(decltype(nullptr)&&):
✓ Branch 3 taken 1 time.
sqlon::expression<sqlon::detail::normalized_type<double>::type> sqlon::literal<double>(double&&):
✓ Branch 3 taken 2 times.
sqlon::expression<sqlon::detail::normalized_type<int>::type> sqlon::literal<int>(int&&):
✓ Branch 3 taken 28 times.
sqlon::expression<sqlon::detail::normalized_type<std::vector<std::byte, std::allocator<std::byte> > >::type> sqlon::literal<std::vector<std::byte, std::allocator<std::byte> > >(std::vector<std::byte, std::allocator<std::byte> >&&):
✓ Branch 3 taken 1 time.
sqlon::expression<sqlon::detail::normalized_type<unsigned long>::type> sqlon::literal<unsigned long>(unsigned long&&):
✓ Branch 3 taken 1 time.
86 return detail::expression_access::make<value_type>(std::move(node));
368 43 }
369
370 /** @brief Creates a bound parameter with a logical name. */
371 template<typename T>
372 19 expression<detail::normalized_type_t<T>> param(std::string name, T&& value)
373 {
374
7/15
sqlon::expression<sqlon::detail::normalized_type<ClientUuid const&>::type> sqlon::param<ClientUuid const&>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, ClientUuid const&):
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 5 not taken.
sqlon::expression<sqlon::detail::normalized_type<int>::type> sqlon::param<int>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int&&):
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 5 times.
✓ Branch 5 taken 1 time.
sqlon::expression<sqlon::detail::normalized_type<long>::type> sqlon::param<long>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, long&&):
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✗ Branch 5 not taken.
sqlon::expression<sqlon::detail::normalized_type<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::type> sqlon::param<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&&):
✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
✗ Branch 5 not taken.
sqlon::expression<sqlon::detail::normalized_type<std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&>::type> sqlon::param<std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&):
✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
✗ Branch 5 not taken.
19 if (name.empty()) throw invalid_query{"a named parameter requires a non-empty name"};
375 using value_type = detail::normalized_type_t<T>;
376
5/5
sqlon::expression<sqlon::detail::normalized_type<ClientUuid const&>::type> sqlon::param<ClientUuid const&>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, ClientUuid const&):
✓ Branch 1 taken 3 times.
sqlon::expression<sqlon::detail::normalized_type<int>::type> sqlon::param<int>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int&&):
✓ Branch 1 taken 5 times.
sqlon::expression<sqlon::detail::normalized_type<long>::type> sqlon::param<long>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, long&&):
✓ Branch 1 taken 8 times.
sqlon::expression<sqlon::detail::normalized_type<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::type> sqlon::param<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&&):
✓ Branch 1 taken 1 time.
sqlon::expression<sqlon::detail::normalized_type<std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&>::type> sqlon::param<std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&):
✓ Branch 1 taken 1 time.
18 std::shared_ptr<detail::expression_node> node = std::make_shared<detail::expression_node>();
377 18 node->kind = detail::expression_kind::parameter;
378 18 node->text = std::move(name);
379
7/7
sqlon::expression<sqlon::detail::normalized_type<ClientUuid const&>::type> sqlon::param<ClientUuid const&>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, ClientUuid const&):
✓ Branch 3 taken 3 times.
✓ Branch 6 taken 3 times.
sqlon::expression<sqlon::detail::normalized_type<int>::type> sqlon::param<int>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int&&):
✓ Branch 4 taken 5 times.
sqlon::expression<sqlon::detail::normalized_type<long>::type> sqlon::param<long>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, long&&):
✓ Branch 4 taken 8 times.
sqlon::expression<sqlon::detail::normalized_type<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::type> sqlon::param<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&&):
✓ Branch 4 taken 1 time.
sqlon::expression<sqlon::detail::normalized_type<std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&>::type> sqlon::param<std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&):
✓ Branch 3 taken 1 time.
✓ Branch 6 taken 1 time.
18 node->bound_parameter.emplace(detail::make_parameter_value(std::forward<T>(value)));
380
2/2
sqlon::expression<sqlon::detail::normalized_type<int>::type> sqlon::param<int>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, int&&):
✓ Branch 3 taken 5 times.
sqlon::expression<sqlon::detail::normalized_type<std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&>::type> sqlon::param<std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > const&):
✓ Branch 3 taken 1 time.
36 return detail::expression_access::make<value_type>(std::move(node));
381 18 }
382
383 /** @brief Typed assignment produced when binding a prepared parameter handle. */
384 template<typename T>
385 struct parameter_binding final {
386 /** @brief Stable identity of the parameter handle. */
387 std::size_t identity{};
388
389 /** @brief Logical parameter name. */
390 std::string name;
391
392 /** @brief Bound parameter value. */
393 parameter_value value;
394 };
395
396 namespace detail {
397
398 template<typename T>
399 struct is_parameter_binding<parameter_binding<T>> : std::true_type {};
400
401 } // namespace detail
402
403 /** @brief Typed named slot whose value is supplied after preparation. */
404 template<typename T>
405 class parameter_slot final : public expression<detail::parameter_expression_type_t<T>> {
406 public:
407 /** @brief Creates a prepared parameter slot with a logical name. */
408 31 explicit parameter_slot(std::string name)
409 : expression<detail::parameter_expression_type_t<T>>(make_node(name))
410 30 , m_identity(detail::expression_access::node(*this)->parameter_slot->identity)
411
7/7
sqlon::parameter_slot<PreparedUuid>::parameter_slot(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >):
✓ Branch 1 taken 2 times.
sqlon::parameter_slot<bool>::parameter_slot(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >):
✓ Branch 1 taken 4 times.
sqlon::parameter_slot<long>::parameter_slot(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >):
✓ Branch 1 taken 12 times.
sqlon::parameter_slot<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::parameter_slot(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >):
✓ Branch 1 taken 8 times.
sqlon::parameter_slot<std::optional<PreparedUuid> >::parameter_slot(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >):
✓ Branch 1 taken 1 time.
sqlon::parameter_slot<std::optional<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::parameter_slot(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >):
✓ Branch 1 taken 2 times.
sqlon::parameter_slot<unsigned long>::parameter_slot(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >):
✓ Branch 1 taken 1 time.
61 , m_name(std::move(name))
412 30 {}
413
414 /** @brief Creates a typed binding for this slot. */
415 29 parameter_binding<T> operator=(T value) const
416 {
417 29 return {m_identity, m_name, parameter_value{detail::make_parameter_value(std::move(value))}};
418 29 }
419
420 /** @brief Returns the stable parameter identity. */
421 4 std::size_t identity() const noexcept
422 {
423 4 return m_identity;
424 }
425
426 /** @brief Returns the logical parameter name. */
427 3 const std::string& name() const noexcept
428 {
429 3 return m_name;
430 }
431
432 private:
433 31 static detail::expression_ptr make_node(const std::string& name)
434 {
435
9/21
sqlon::parameter_slot<PreparedUuid>::make_node(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&):
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 5 not taken.
sqlon::parameter_slot<bool>::make_node(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&):
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 5 not taken.
sqlon::parameter_slot<long>::make_node(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&):
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 12 times.
✓ Branch 5 taken 1 time.
sqlon::parameter_slot<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::make_node(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&):
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✗ Branch 5 not taken.
sqlon::parameter_slot<std::optional<PreparedUuid> >::make_node(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&):
✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
✗ Branch 5 not taken.
sqlon::parameter_slot<std::optional<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::make_node(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&):
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 5 not taken.
sqlon::parameter_slot<unsigned long>::make_node(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&):
✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
✗ Branch 5 not taken.
31 if (name.empty()) throw invalid_query{"a prepared parameter requires a non-empty name"};
436
7/7
sqlon::parameter_slot<PreparedUuid>::make_node(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&):
✓ Branch 1 taken 2 times.
sqlon::parameter_slot<bool>::make_node(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&):
✓ Branch 1 taken 4 times.
sqlon::parameter_slot<long>::make_node(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&):
✓ Branch 1 taken 12 times.
sqlon::parameter_slot<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::make_node(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&):
✓ Branch 1 taken 8 times.
sqlon::parameter_slot<std::optional<PreparedUuid> >::make_node(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&):
✓ Branch 1 taken 1 time.
sqlon::parameter_slot<std::optional<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >::make_node(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&):
✓ Branch 1 taken 2 times.
sqlon::parameter_slot<unsigned long>::make_node(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&):
✓ Branch 1 taken 1 time.
30 std::shared_ptr<detail::expression_node> node = std::make_shared<detail::expression_node>();
437 30 node->kind = detail::expression_kind::parameter_slot;
438 30 node->parameter_slot =
439 60 detail::parameter_slot_node{detail::next_parameter_identity(), name, detail::parameter_kind_of<T>(),
440 30 detail::is_nullable_parameter_v<T>, detail::custom_parameter_type_id<T>()};
441 60 return node;
442 60 }
443
444 std::size_t m_identity{};
445 std::string m_name;
446 };
447
448 template<typename T>
449 template<typename Right>
450 66 expression<bool> expression<T>::operator==(Right&& right) const
451 {
452
6/6
sqlon::expression<bool> sqlon::expression<ClientUuid>::operator==<ClientUuid const&>(ClientUuid const&) const:
✓ Branch 2 taken 1 time.
sqlon::expression<bool> sqlon::expression<bool>::operator==<bool>(bool&&) const:
✓ Branch 2 taken 15 times.
sqlon::expression<bool> sqlon::expression<long>::operator==<ClientId>(ClientId&&) const:
✓ Branch 2 taken 1 time.
sqlon::expression<bool> sqlon::expression<long>::operator==<int>(int&&) const:
✓ Branch 2 taken 14 times.
sqlon::expression<bool> sqlon::expression<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::operator==<char const (&) [4]>(char const (&) [4]) const:
✓ Branch 2 taken 4 times.
sqlon::expression<bool> sqlon::expression<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::operator==<char const (&) [6]>(char const (&) [6]) const:
✓ Branch 2 taken 4 times.
66 auto rhs = to_expression(std::forward<Right>(right));
453 static_assert(detail::compatible_expression_types<T, typename decltype(rhs)::value_type>,
454 "incompatible SQL comparison types");
455
18/18
sqlon::expression<bool> sqlon::expression<ClientUuid>::operator==<ClientUuid const&>(ClientUuid const&) const:
✓ Branch 4 taken 1 time.
✓ Branch 7 taken 1 time.
sqlon::expression<bool> sqlon::expression<bool>::operator==<bool>(bool&&) const:
✓ Branch 4 taken 15 times.
✓ Branch 7 taken 15 times.
sqlon::expression<bool> sqlon::expression<long>::operator==<ClientId>(ClientId&&) const:
✓ Branch 4 taken 1 time.
✓ Branch 7 taken 1 time.
sqlon::expression<bool> sqlon::expression<long>::operator==<int>(int&&) const:
✓ Branch 4 taken 14 times.
✓ Branch 7 taken 14 times.
sqlon::expression<bool> sqlon::expression<long>::operator==<sqlon::column<long> const&>(sqlon::column<long> const&) const:
✓ Branch 4 taken 18 times.
✓ Branch 7 taken 18 times.
sqlon::expression<bool> sqlon::expression<long>::operator==<sqlon::expression<long> const&>(sqlon::expression<long> const&) const:
✓ Branch 4 taken 1 time.
✓ Branch 7 taken 1 time.
sqlon::expression<bool> sqlon::expression<long>::operator==<sqlon::parameter_slot<long> const&>(sqlon::parameter_slot<long> const&) const:
✓ Branch 4 taken 8 times.
✓ Branch 7 taken 8 times.
sqlon::expression<bool> sqlon::expression<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::operator==<char const (&) [4]>(char const (&) [4]) const:
✓ Branch 4 taken 4 times.
✓ Branch 7 taken 4 times.
sqlon::expression<bool> sqlon::expression<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >::operator==<char const (&) [6]>(char const (&) [6]) const:
✓ Branch 4 taken 4 times.
✓ Branch 7 taken 4 times.
264 return expression<bool>{detail::make_binary_node("=", m_node, detail::expression_access::node(rhs))};
456 66 }
457
458 template<typename T>
459 template<typename Right>
460 1 expression<bool> expression<T>::operator!=(Right&& right) const
461 {
462 1 auto rhs = to_expression(std::forward<Right>(right));
463 static_assert(detail::compatible_expression_types<T, typename decltype(rhs)::value_type>,
464 "incompatible SQL comparison types");
465
2/2
✓ Branch 4 taken 1 time.
✓ Branch 7 taken 1 time.
4 return expression<bool>{detail::make_binary_node("!=", m_node, detail::expression_access::node(rhs))};
466 1 }
467
468 #define SQLON_DEFINE_COMPARISON_OPERATOR(symbol, operation) \
469 template<typename T> \
470 template<typename Right> \
471 expression<bool> expression<T>::operator symbol(Right && right) const \
472 { \
473 auto rhs = to_expression(std::forward<Right>(right)); \
474 static_assert(detail::compatible_expression_types<T, typename decltype(rhs)::value_type>, \
475 "incompatible SQL comparison types"); \
476 return expression<bool>{detail::make_binary_node(operation, m_node, detail::expression_access::node(rhs))}; \
477 }
478
479
5/5
sqlon::expression<bool> sqlon::expression<long>::operator< <int>(int&&) const:
✓ Branch 2 taken 1 time.
✓ Branch 8 taken 1 time.
✓ Branch 11 taken 1 time.
sqlon::expression<bool> sqlon::expression<long>::operator< <sqlon::column<long> const&>(sqlon::column<long> const&) const:
✓ Branch 6 taken 1 time.
✓ Branch 9 taken 1 time.
8 SQLON_DEFINE_COMPARISON_OPERATOR(<, "<")
480
2/2
✓ Branch 6 taken 1 time.
✓ Branch 9 taken 1 time.
4 SQLON_DEFINE_COMPARISON_OPERATOR(<=, "<=")
481
8/8
sqlon::expression<bool> sqlon::expression<long>::operator><int>(int&&) const:
✓ Branch 2 taken 13 times.
✓ Branch 8 taken 13 times.
✓ Branch 11 taken 13 times.
sqlon::expression<bool> sqlon::expression<long>::operator><long>(long&&) const:
✓ Branch 2 taken 1 time.
✓ Branch 8 taken 1 time.
✓ Branch 11 taken 1 time.
sqlon::expression<bool> sqlon::expression<long>::operator><sqlon::column<long> const&>(sqlon::column<long> const&) const:
✓ Branch 6 taken 1 time.
✓ Branch 9 taken 1 time.
60 SQLON_DEFINE_COMPARISON_OPERATOR(>, ">")
482
5/5
sqlon::expression<bool> sqlon::expression<long>::operator>=<int>(int&&) const:
✓ Branch 2 taken 1 time.
✓ Branch 8 taken 1 time.
✓ Branch 11 taken 1 time.
sqlon::expression<bool> sqlon::expression<long>::operator>=<sqlon::column<long> const&>(sqlon::column<long> const&) const:
✓ Branch 6 taken 1 time.
✓ Branch 9 taken 1 time.
8 SQLON_DEFINE_COMPARISON_OPERATOR(>=, ">=")
483
484 #undef SQLON_DEFINE_COMPARISON_OPERATOR
485
486 #define SQLON_DEFINE_ARITHMETIC_OPERATOR(symbol, operation) \
487 template<typename T> \
488 template<typename Right, typename U, std::enable_if_t<std::is_arithmetic_v<U>, int>> \
489 expression<std::common_type_t<T, detail::expression_value_type_t<Right>>> expression<T>::operator symbol( \
490 Right && right) const \
491 { \
492 auto rhs = to_expression(std::forward<Right>(right)); \
493 static_assert(!std::is_same_v<detail::normalized_type_t<T>, bool> && \
494 !std::is_same_v<typename decltype(rhs)::value_type, bool>, \
495 "SQL arithmetic does not accept boolean expressions"); \
496 using result_type = std::common_type_t<T, typename decltype(rhs)::value_type>; \
497 return expression<result_type>{detail::make_binary_node(operation, m_node, detail::expression_access::node(rhs))}; \
498 }
499
500
7/7
sqlon::expression<std::common_type<long, sqlon::detail::expression_value_type<int, sqlon::detail::is_expression_like<int, void>::value>::type>::type> sqlon::expression<long>::operator+<int, long, 0>(int&&) const:
✓ Branch 2 taken 3 times.
✓ Branch 8 taken 3 times.
✓ Branch 11 taken 3 times.
sqlon::expression<std::common_type<long, sqlon::detail::expression_value_type<sqlon::expression<int>, sqlon::detail::is_expression_like<sqlon::expression<int>, void>::value>::type>::type> sqlon::expression<long>::operator+<sqlon::expression<int>, long, 0>(sqlon::expression<int>&&) const:
✓ Branch 6 taken 1 time.
✓ Branch 9 taken 1 time.
sqlon::expression<std::common_type<long, sqlon::detail::expression_value_type<sqlon::parameter_slot<long> const&, sqlon::detail::is_expression_like<sqlon::parameter_slot<long> const&, void>::value>::type>::type> sqlon::expression<long>::operator+<sqlon::parameter_slot<long> const&, long, 0>(sqlon::parameter_slot<long> const&) const:
✓ Branch 6 taken 1 time.
✓ Branch 9 taken 1 time.
20 SQLON_DEFINE_ARITHMETIC_OPERATOR(+, "+")
501
3/3
✓ Branch 2 taken 1 time.
✓ Branch 8 taken 1 time.
✓ Branch 11 taken 1 time.
4 SQLON_DEFINE_ARITHMETIC_OPERATOR(-, "-")
502
6/6
sqlon::expression<std::common_type<long, sqlon::detail::expression_value_type<int, sqlon::detail::is_expression_like<int, void>::value>::type>::type> sqlon::expression<long>::operator*<int, long, 0>(int&&) const:
✓ Branch 2 taken 2 times.
✓ Branch 8 taken 2 times.
✓ Branch 11 taken 2 times.
sqlon::expression<std::common_type<long, sqlon::detail::expression_value_type<long, sqlon::detail::is_expression_like<long, void>::value>::type>::type> sqlon::expression<long>::operator*<long, long, 0>(long&&) const:
✓ Branch 2 taken 1 time.
✓ Branch 8 taken 1 time.
✓ Branch 11 taken 1 time.
12 SQLON_DEFINE_ARITHMETIC_OPERATOR(*, "*")
503
3/3
✓ Branch 2 taken 1 time.
✓ Branch 8 taken 1 time.
✓ Branch 11 taken 1 time.
4 SQLON_DEFINE_ARITHMETIC_OPERATOR(/, "/")
504
505 #undef SQLON_DEFINE_ARITHMETIC_OPERATOR
506
507 template<typename T>
508 template<typename... Values, std::enable_if_t<detail::are_non_query_values<Values...>::value, int>>
509 2 expression<bool> expression<T>::in(Values&&... values) const
510 {
511 static_assert(sizeof...(Values) > 0, "IN requires at least one value");
512 static_assert(
513 (detail::compatible_expression_types<T, typename decltype(to_expression(std::declval<Values>()))::value_type> &&
514 ...),
515 "IN values must be compatible with the tested expression");
516
3/5
✓ Branch 1 taken 2 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 2 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
6 std::vector<detail::expression_ptr> operands{m_node};
517
6/6
✓ Branch 2 taken 2 times.
✓ Branch 6 taken 2 times.
✓ Branch 10 taken 2 times.
✓ Branch 14 taken 2 times.
✓ Branch 18 taken 2 times.
✓ Branch 22 taken 2 times.
2 (operands.push_back(detail::expression_access::node(to_expression(std::forward<Values>(values)))), ...);
518
2/2
✓ Branch 3 taken 2 times.
✓ Branch 6 taken 2 times.
8 return expression<bool>{detail::make_expression_node(detail::expression_kind::function, "in", std::move(operands))};
519 4 }
520
521 template<typename T>
522 template<typename... Values, std::enable_if_t<detail::are_non_query_values<Values...>::value, int>>
523 1 expression<bool> expression<T>::not_in(Values&&... values) const
524 {
525 static_assert(sizeof...(Values) > 0, "NOT IN requires at least one value");
526 static_assert(
527 (detail::compatible_expression_types<T, typename decltype(to_expression(std::declval<Values>()))::value_type> &&
528 ...),
529 "NOT IN values must be compatible with the tested expression");
530
3/5
✓ Branch 1 taken 1 time.
✓ Branch 3 taken 1 time.
✓ Branch 4 taken 1 time.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
3 std::vector<detail::expression_ptr> operands{m_node};
531
6/6
✓ Branch 2 taken 1 time.
✓ Branch 6 taken 1 time.
✓ Branch 10 taken 1 time.
✓ Branch 14 taken 1 time.
✓ Branch 18 taken 1 time.
✓ Branch 22 taken 1 time.
1 (operands.push_back(detail::expression_access::node(to_expression(std::forward<Values>(values)))), ...);
532 return expression<bool>{
533
2/2
✓ Branch 3 taken 1 time.
✓ Branch 6 taken 1 time.
4 detail::make_expression_node(detail::expression_kind::function, "not_in", std::move(operands))};
534 2 }
535
536 template<typename T>
537 template<typename Lower, typename Upper>
538 2 expression<bool> expression<T>::between(Lower&& lower, Upper&& upper) const
539 {
540
1/1
✓ Branch 2 taken 2 times.
2 auto lower_expression = to_expression(std::forward<Lower>(lower));
541
1/1
✓ Branch 2 taken 2 times.
2 auto upper_expression = to_expression(std::forward<Upper>(upper));
542 static_assert(detail::compatible_expression_types<T, typename decltype(lower_expression)::value_type> &&
543 detail::compatible_expression_types<T, typename decltype(upper_expression)::value_type>,
544 "BETWEEN bounds must be compatible with the tested expression");
545 6 return expression<bool>{detail::make_expression_node(
546 detail::expression_kind::function, "between",
547
5/7
✓ Branch 1 taken 2 times.
✓ Branch 4 taken 2 times.
✓ Branch 7 taken 2 times.
✓ Branch 13 taken 6 times.
✓ Branch 14 taken 2 times.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
16 {m_node, detail::expression_access::node(lower_expression), detail::expression_access::node(upper_expression)})};
548 4 }
549
550 template<typename T>
551 template<typename Pattern>
552 1 expression<bool> expression<T>::like(Pattern&& pattern) const
553 {
554 static_assert(std::is_same_v<T, std::string>, "LIKE requires a string expression");
555
1/1
✓ Branch 2 taken 1 time.
1 auto rhs = to_expression(std::forward<Pattern>(pattern));
556 static_assert(std::is_same_v<typename decltype(rhs)::value_type, std::string>,
557 "LIKE patterns must be string expressions");
558
2/2
✓ Branch 4 taken 1 time.
✓ Branch 7 taken 1 time.
4 return expression<bool>{detail::make_binary_node("like", m_node, detail::expression_access::node(rhs))};
559 1 }
560
561 template<typename T>
562 template<typename Pattern>
563 1 expression<bool> expression<T>::not_like(Pattern&& pattern) const
564 {
565 static_assert(std::is_same_v<T, std::string>, "NOT LIKE requires a string expression");
566
1/1
✓ Branch 2 taken 1 time.
1 auto rhs = to_expression(std::forward<Pattern>(pattern));
567 static_assert(std::is_same_v<typename decltype(rhs)::value_type, std::string>,
568 "NOT LIKE patterns must be string expressions");
569
2/2
✓ Branch 4 taken 1 time.
✓ Branch 7 taken 1 time.
4 return expression<bool>{detail::make_binary_node("not_like", m_node, detail::expression_access::node(rhs))};
570 1 }
571
572 /** @brief Creates a logical AND expression. */
573 SQLON_API expression<bool> operator&&(const expression<bool>& left, const expression<bool>& right);
574
575 /** @brief Creates a logical OR expression. */
576 SQLON_API expression<bool> operator||(const expression<bool>& left, const expression<bool>& right);
577
578 /** @brief Creates a logical NOT expression. */
579 SQLON_API expression<bool> operator!(const expression<bool>& value);
580
581 /** @brief Creates an IS NULL predicate. */
582 template<typename T>
583 expression<bool> operator==(std::nullptr_t, const expression<T>& value)
584 {
585 return value.is_null();
586 }
587
588 /** @brief Creates an IS NOT NULL predicate. */
589 template<typename T>
590 expression<bool> operator!=(std::nullptr_t, const expression<T>& value)
591 {
592 return value.is_not_null();
593 }
594
595 /** @brief Creates a COUNT aggregate for an expression. */
596 template<typename T>
597 6 expression<std::int64_t> count(const expression<T>& value)
598 {
599 6 return detail::expression_access::make<std::int64_t>(detail::make_expression_node(
600
5/7
✓ Branch 1 taken 6 times.
✓ Branch 4 taken 6 times.
✓ Branch 7 taken 6 times.
✓ Branch 13 taken 6 times.
✓ Branch 14 taken 6 times.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
30 detail::expression_kind::function, "count", {detail::expression_access::node(value)}));
601 6 }
602
603 /** @brief Creates a COUNT(*) aggregate. */
604 SQLON_API expression<std::int64_t> count_all();
605
606 /** @brief Wraps an expression in DISTINCT. */
607 template<typename T>
608 2 expression<T> distinct(const expression<T>& value)
609 {
610 return detail::expression_access::make<T>(
611
4/6
✓ Branch 1 taken 2 times.
✓ Branch 5 taken 2 times.
✓ Branch 11 taken 2 times.
✓ Branch 12 taken 2 times.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
6 detail::make_expression_node(detail::expression_kind::distinct, {}, {detail::expression_access::node(value)}));
612 2 }
613
614 /** @brief Creates a COUNT aggregate over distinct values. */
615 template<typename T>
616 2 expression<std::int64_t> count_distinct(const expression<T>& value)
617 {
618
2/2
✓ Branch 1 taken 2 times.
✓ Branch 4 taken 2 times.
2 return count(distinct(value));
619 }
620
621 /** @brief Creates a MIN aggregate. */
622 template<typename T>
623 1 expression<T> min(const expression<T>& value)
624 {
625 return detail::expression_access::make<T>(
626
5/7
✓ Branch 1 taken 1 time.
✓ Branch 4 taken 1 time.
✓ Branch 7 taken 1 time.
✓ Branch 13 taken 1 time.
✓ Branch 14 taken 1 time.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
5 detail::make_expression_node(detail::expression_kind::function, "min", {detail::expression_access::node(value)}));
627 1 }
628
629 /** @brief Creates a MAX aggregate. */
630 template<typename T>
631 2 expression<T> max(const expression<T>& value)
632 {
633 return detail::expression_access::make<T>(
634
5/7
✓ Branch 1 taken 2 times.
✓ Branch 4 taken 2 times.
✓ Branch 7 taken 2 times.
✓ Branch 13 taken 2 times.
✓ Branch 14 taken 2 times.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
10 detail::make_expression_node(detail::expression_kind::function, "max", {detail::expression_access::node(value)}));
635 2 }
636
637 /** @brief Creates a SUM aggregate for a numeric expression. */
638 template<typename T>
639 4 expression<T> sum(const expression<T>& value)
640 {
641 static_assert(std::is_arithmetic_v<T> && !std::is_same_v<T, bool>, "sum requires a numeric expression");
642 return detail::expression_access::make<T>(
643
5/7
✓ Branch 1 taken 4 times.
✓ Branch 4 taken 4 times.
✓ Branch 7 taken 4 times.
✓ Branch 13 taken 4 times.
✓ Branch 14 taken 4 times.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
20 detail::make_expression_node(detail::expression_kind::function, "sum", {detail::expression_access::node(value)}));
644 4 }
645
646 /** @brief Creates an AVG aggregate for a numeric expression. */
647 template<typename T>
648 1 expression<double> avg(const expression<T>& value)
649 {
650 static_assert(std::is_arithmetic_v<T> && !std::is_same_v<T, bool>, "avg requires a numeric expression");
651 return detail::expression_access::make<double>(
652
6/8
✓ Branch 1 taken 1 time.
✓ Branch 4 taken 1 time.
✓ Branch 7 taken 1 time.
✓ Branch 10 taken 1 time.
✓ Branch 15 taken 1 time.
✓ Branch 16 taken 1 time.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
5 detail::make_expression_node(detail::expression_kind::function, "avg", {detail::expression_access::node(value)}));
653 1 }
654
655 /** @brief Tag type for SQL timestamp expressions. */
656 struct timestamp final {};
657
658 /** @brief Creates the CURRENT_TIMESTAMP expression. */
659 SQLON_API expression<timestamp> current_timestamp();
660
661 /** @brief Creates an explicit SQL NULL expression. */
662 SQLON_API expression<std::nullptr_t> null();
663
664 /** @brief Creates a DEFAULT value expression. */
665 SQLON_API expression<std::nullptr_t> default_value();
666
667 /** @brief Creates a typed SQL function call. */
668 template<typename T, typename... Arguments>
669 17 expression<T> function(std::string name, Arguments&&... arguments)
670 {
671
8/18
sqlon::expression<long> sqlon::function<long, sqlon::column<long> const&>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, sqlon::column<long> const&):
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 2 times.
✓ Branch 6 taken 1 time.
sqlon::expression<long> sqlon::function<long, sqlon::expression<long> const&, int, int>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, sqlon::expression<long> const&, int&&, int&&):
✗ Branch 2 not taken.
✓ Branch 3 taken 1 time.
✗ Branch 6 not taken.
sqlon::expression<long> sqlon::function<long, sqlon::expression<long> const&, sqlon::parameter_slot<unsigned long> const&, sqlon::parameter_slot<long> const&>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, sqlon::expression<long> const&, sqlon::parameter_slot<unsigned long> const&, sqlon::parameter_slot<long> const&):
✗ Branch 2 not taken.
✓ Branch 3 taken 1 time.
✗ Branch 6 not taken.
sqlon::expression<long> sqlon::function<long>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >):
✗ Branch 2 not taken.
✓ Branch 3 taken 10 times.
✗ Branch 6 not taken.
sqlon::expression<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > sqlon::function<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, sqlon::expression<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >&, char const (&) [8]>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, sqlon::expression<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >&, char const (&) [8]):
✗ Branch 2 not taken.
✓ Branch 3 taken 1 time.
✗ Branch 6 not taken.
sqlon::expression<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > sqlon::function<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, sqlon::expression<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >&, sqlon::column<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, sqlon::expression<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >&, sqlon::column<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&):
✗ Branch 2 not taken.
✓ Branch 3 taken 1 time.
✗ Branch 6 not taken.
17 if (!detail::valid_function_name(name)) throw invalid_query{"a SQL function requires an identifier-like name"};
672 12 return detail::expression_access::make<T>(detail::make_expression_node(
673 16 detail::expression_kind::function_call, std::move(name),
674
25/35
sqlon::expression<long> sqlon::function<long, sqlon::column<long> const&>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, sqlon::column<long> const&):
✓ Branch 3 taken 2 times.
✓ Branch 7 taken 2 times.
✓ Branch 13 taken 2 times.
✓ Branch 14 taken 2 times.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
sqlon::expression<long> sqlon::function<long, sqlon::expression<long> const&, int, int>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, sqlon::expression<long> const&, int&&, int&&):
✓ Branch 3 taken 1 time.
✓ Branch 7 taken 1 time.
✓ Branch 11 taken 1 time.
✓ Branch 15 taken 1 time.
✓ Branch 21 taken 3 times.
✓ Branch 22 taken 1 time.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
sqlon::expression<long> sqlon::function<long, sqlon::expression<long> const&, sqlon::parameter_slot<unsigned long> const&, sqlon::parameter_slot<long> const&>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, sqlon::expression<long> const&, sqlon::parameter_slot<unsigned long> const&, sqlon::parameter_slot<long> const&):
✓ Branch 7 taken 1 time.
✓ Branch 11 taken 1 time.
✓ Branch 17 taken 3 times.
✓ Branch 18 taken 1 time.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
sqlon::expression<long> sqlon::function<long>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >):
✓ Branch 3 taken 10 times.
✓ Branch 6 taken 10 times.
sqlon::expression<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > sqlon::function<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, sqlon::expression<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >&, char const (&) [8]>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, sqlon::expression<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >&, char const (&) [8]):
✓ Branch 3 taken 1 time.
✓ Branch 7 taken 1 time.
✓ Branch 11 taken 1 time.
✓ Branch 17 taken 2 times.
✓ Branch 18 taken 1 time.
✗ Branch 23 not taken.
✗ Branch 24 not taken.
sqlon::expression<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > sqlon::function<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, sqlon::expression<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >&, sqlon::column<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, sqlon::expression<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >&, sqlon::column<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&):
✓ Branch 5 taken 1 time.
✓ Branch 9 taken 1 time.
✓ Branch 15 taken 2 times.
✓ Branch 16 taken 1 time.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
62 {detail::expression_access::node(to_expression(std::forward<Arguments>(arguments)))...}));
675 18 }
676
677 /** @brief Creates a COALESCE expression from compatible arguments. */
678 template<typename First, typename... Rest>
679 2 auto coalesce(First&& first, Rest&&... rest)
680 {
681 static_assert(sizeof...(Rest) > 0, "COALESCE requires at least two arguments");
682 2 auto first_expression = to_expression(std::forward<First>(first));
683 using value_type = typename decltype(first_expression)::value_type;
684 static_assert((detail::compatible_expression_types<value_type, detail::expression_value_type_t<Rest>> && ...),
685 "COALESCE arguments must have compatible expression types");
686
4/4
auto sqlon::coalesce<sqlon::column<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&, char const (&) [8]>(sqlon::column<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&, char const (&) [8]):
✓ Branch 2 taken 1 time.
✓ Branch 5 taken 1 time.
auto sqlon::coalesce<sqlon::expression<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, sqlon::column<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&>(sqlon::expression<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >&&, sqlon::column<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&):
✓ Branch 2 taken 1 time.
✓ Branch 5 taken 1 time.
6 return function<value_type>("coalesce", first_expression, std::forward<Rest>(rest)...);
687 2 }
688
689 /**
690 * @brief Creates a grouped raw SQL expression whose operands retain normal SQLon rendering and parameter handling.
691 *
692 * The SQL template is trusted syntax and is not escaped, validated for a database preset, or translated between
693 * dialects. Each `{}` position is replaced by the next operand after that operand passes through `to_expression()`.
694 * Do not put user-controlled text or database placeholders directly in the template.
695 */
696 template<typename Result, typename... Operands>
697 23 expression<Result> raw_expr(std::string sql, Operands&&... operands)
698 {
699
36/60
sqlon::expression<bool> sqlon::raw_expr<bool, sqlon::column<bool> const&, bool>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, sqlon::column<bool> const&, bool&&):
✓ Branch 1 taken 1 time.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 1 time.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
sqlon::expression<bool> sqlon::raw_expr<bool, sqlon::column<bool> const&>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, sqlon::column<bool> const&):
✓ Branch 1 taken 5 times.
✓ Branch 3 taken 5 times.
✓ Branch 4 taken 5 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
sqlon::expression<bool> sqlon::raw_expr<bool, sqlon::column<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&, sqlon::expression<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&, sqlon::column<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&, sqlon::expression<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, sqlon::column<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&, sqlon::expression<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&, sqlon::column<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&, sqlon::expression<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&):
✓ Branch 1 taken 1 time.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 1 time.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
sqlon::expression<bool> sqlon::raw_expr<bool, sqlon::column<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&, sqlon::parameter_slot<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&, sqlon::column<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&, sqlon::parameter_slot<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, sqlon::column<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&, sqlon::parameter_slot<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&, sqlon::column<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&, sqlon::parameter_slot<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&):
✓ Branch 1 taken 1 time.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 1 time.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
sqlon::expression<bool> sqlon::raw_expr<bool, sqlon::column<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, sqlon::column<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&&):
✓ Branch 1 taken 4 times.
✓ Branch 3 taken 8 times.
✓ Branch 4 taken 4 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
sqlon::expression<bool> sqlon::raw_expr<bool, sqlon::expression<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, sqlon::expression<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&):
✓ Branch 1 taken 1 time.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 1 time.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
sqlon::expression<long> sqlon::raw_expr<long, sqlon::column<long> const&, long>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, sqlon::column<long> const&, long&&):
✓ Branch 1 taken 1 time.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 1 time.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
sqlon::expression<long> sqlon::raw_expr<long, sqlon::column<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, sqlon::column<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&):
✓ Branch 1 taken 1 time.
✓ Branch 3 taken 1 time.
✓ Branch 4 taken 1 time.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
sqlon::expression<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > sqlon::raw_expr<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, sqlon::column<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&, sqlon::expression<std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > > const&>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, sqlon::column<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&, sqlon::expression<std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > > const&):
✓ Branch 1 taken 1 time.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 1 time.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
sqlon::expression<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > sqlon::raw_expr<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, sqlon::column<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, sqlon::column<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&):
✓ Branch 1 taken 1 time.
✓ Branch 3 taken 1 time.
✓ Branch 4 taken 1 time.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
sqlon::expression<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > sqlon::raw_expr<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, sqlon::expression<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&, long>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, sqlon::expression<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&, long&&):
✓ Branch 1 taken 1 time.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 1 time.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
sqlon::expression<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > sqlon::raw_expr<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&&):
✓ Branch 1 taken 1 time.
✓ Branch 3 taken 1 time.
✓ Branch 4 taken 1 time.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
76 std::vector<detail::expression_ptr> nodes{
700
6/6
sqlon::expression<bool> sqlon::raw_expr<bool, sqlon::column<bool> const&, bool>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, sqlon::column<bool> const&, bool&&):
✓ Branch 3 taken 1 time.
sqlon::expression<bool> sqlon::raw_expr<bool, sqlon::column<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, sqlon::column<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&&):
✓ Branch 3 taken 4 times.
sqlon::expression<bool> sqlon::raw_expr<bool, sqlon::expression<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, sqlon::expression<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&):
✓ Branch 3 taken 1 time.
sqlon::expression<long> sqlon::raw_expr<long, sqlon::column<long> const&, long>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, sqlon::column<long> const&, long&&):
✓ Branch 3 taken 1 time.
sqlon::expression<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > sqlon::raw_expr<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, sqlon::expression<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&, long>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, sqlon::expression<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&, long&&):
✓ Branch 3 taken 1 time.
sqlon::expression<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > sqlon::raw_expr<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&&):
✓ Branch 1 taken 1 time.
53 detail::expression_access::node(to_expression(std::forward<Operands>(operands)))...};
701
14/20
sqlon::expression<bool> sqlon::raw_expr<bool, sqlon::column<bool> const&, bool>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, sqlon::column<bool> const&, bool&&):
✗ Branch 5 not taken.
✗ Branch 8 not taken.
sqlon::expression<bool> sqlon::raw_expr<bool, sqlon::column<bool> const&>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, sqlon::column<bool> const&):
✗ Branch 5 not taken.
✗ Branch 8 not taken.
sqlon::expression<bool> sqlon::raw_expr<bool, sqlon::column<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&, sqlon::expression<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&, sqlon::column<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&, sqlon::expression<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, sqlon::column<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&, sqlon::expression<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&, sqlon::column<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&, sqlon::expression<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&):
✓ Branch 5 taken 1 time.
✓ Branch 8 taken 1 time.
sqlon::expression<bool> sqlon::raw_expr<bool, sqlon::column<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&, sqlon::parameter_slot<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&, sqlon::column<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&, sqlon::parameter_slot<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, sqlon::column<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&, sqlon::parameter_slot<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&, sqlon::column<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&, sqlon::parameter_slot<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&):
✓ Branch 5 taken 1 time.
✓ Branch 8 taken 1 time.
sqlon::expression<bool> sqlon::raw_expr<bool, sqlon::column<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, sqlon::column<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&&):
✓ Branch 5 taken 4 times.
✓ Branch 8 taken 4 times.
sqlon::expression<bool> sqlon::raw_expr<bool, sqlon::expression<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, sqlon::expression<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&):
✓ Branch 5 taken 1 time.
✓ Branch 8 taken 1 time.
sqlon::expression<bool> sqlon::raw_expr<bool>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >):
✗ Branch 5 not taken.
✗ Branch 8 not taken.
sqlon::expression<long> sqlon::raw_expr<long, sqlon::column<long> const&, long>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, sqlon::column<long> const&, long&&):
✓ Branch 5 taken 1 time.
sqlon::expression<long> sqlon::raw_expr<long, sqlon::column<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, sqlon::column<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&):
✓ Branch 5 taken 1 time.
sqlon::expression<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > sqlon::raw_expr<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, sqlon::column<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&, sqlon::expression<std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > > const&>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, sqlon::column<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&, sqlon::expression<std::vector<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > > const&):
✓ Branch 5 taken 1 time.
sqlon::expression<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > sqlon::raw_expr<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, sqlon::column<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, sqlon::column<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&):
✓ Branch 5 taken 1 time.
sqlon::expression<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > sqlon::raw_expr<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, sqlon::expression<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&, long>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, sqlon::expression<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > const&, long&&):
✓ Branch 5 taken 1 time.
sqlon::expression<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > sqlon::raw_expr<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&&):
✓ Branch 5 taken 1 time.
56 return detail::expression_access::make<Result>(detail::make_raw_expression_node(std::move(sql), std::move(nodes)));
702 76 }
703
704 /**
705 * @brief Creates an opaque raw SQL expression from trusted syntax.
706 *
707 * The SQL text is emitted unchanged and receives no escaping or parameterization. Runtime values and SQLon
708 * expressions must be passed through `raw_expr()` operands instead. Database placeholders written here are not
709 * tracked by SQLon.
710 */
711 template<typename T>
712 2 expression<T> raw_sql(std::string sql)
713 {
714
3/3
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 1 time.
✓ Branch 5 taken 1 time.
2 if (sql.empty()) throw invalid_query{"a raw SQL expression cannot be empty"};
715
1/1
✓ Branch 4 taken 1 time.
1 return detail::expression_access::make<T>(detail::make_expression_node(detail::expression_kind::raw, std::move(sql)));
716 }
717
718 } // namespace sqlon
719
720 #endif // SQLON_EXPRESSION_H
721