relx 0.1.0
A Modern C++23 Type-Safe SQL Query Builder
Loading...
Searching...
No Matches
operators.hpp
Go to the documentation of this file.
1#pragma once
2
3#include "../query/condition.hpp"
4#include "../query/date_concepts.hpp"
5#include "../query/function.hpp"
6#include "../query/meta.hpp"
7#include "../query/schema_adapter.hpp"
8#include "../query/value.hpp"
9#include "../schema/column.hpp"
10
11#include <chrono>
12#include <iostream>
13#include <optional>
14#include <string>
15#include <type_traits>
16#include <vector>
17
18namespace relx {
20namespace type_checking {
21
23template <typename T>
25 using type = T;
26 static constexpr bool is_optional = false;
27};
28
29template <typename T>
30struct remove_optional<std::optional<T>> {
31 using type = T;
32 static constexpr bool is_optional = true;
33};
34
35template <typename T>
37
39template <typename T1, typename T2>
40concept StringCompatible = (std::same_as<std::remove_cvref_t<T1>, std::string> ||
41 std::same_as<std::remove_cvref_t<T1>, std::string_view> ||
42 std::same_as<std::remove_cvref_t<T1>, const char*>) &&
43 (std::same_as<std::remove_cvref_t<T2>, std::string> ||
44 std::same_as<std::remove_cvref_t<T2>, std::string_view> ||
45 std::same_as<std::remove_cvref_t<T2>, const char*> ||
46 std::convertible_to<std::remove_cvref_t<T2>, std::string> ||
47 std::convertible_to<std::remove_cvref_t<T2>, std::string_view>);
48
50template <typename ColumnType, typename ValueType>
52 // Optional to non-optional: optional<T> with T
53 (remove_optional<std::remove_cvref_t<ColumnType>>::is_optional &&
54 std::same_as<remove_optional_t<std::remove_cvref_t<ColumnType>>,
55 std::remove_cvref_t<ValueType>>) ||
56 // Non-optional to optional: T with optional<T>
57 (remove_optional<std::remove_cvref_t<ValueType>>::is_optional &&
58 std::same_as<std::remove_cvref_t<ColumnType>,
59 remove_optional_t<std::remove_cvref_t<ValueType>>>) ||
60 // Optional string compatibility: optional<string> with string-like types
61 (remove_optional<std::remove_cvref_t<ColumnType>>::is_optional &&
63 // String-like types with optional<string>
64 (remove_optional<std::remove_cvref_t<ValueType>>::is_optional &&
65 StringCompatible<ColumnType, remove_optional_t<std::remove_cvref_t<ValueType>>>) ||
66 // Both optional: optional<T> with optional<U> where T and U are compatible
67 (remove_optional<std::remove_cvref_t<ColumnType>>::is_optional &&
68 remove_optional<std::remove_cvref_t<ValueType>>::is_optional &&
69 (std::same_as<remove_optional_t<std::remove_cvref_t<ColumnType>>,
70 remove_optional_t<std::remove_cvref_t<ValueType>>> ||
72 remove_optional_t<std::remove_cvref_t<ValueType>>>));
73
75template <typename ColumnType, typename ValueType>
77 // Exact match
78 std::same_as<std::remove_cvref_t<ColumnType>, std::remove_cvref_t<ValueType>> ||
79 // String compatibility
81 // Optional compatibility
83
85inline constexpr std::string_view type_error_message =
86 "Column type and value type are not compatible. "
87 "Column types must match the value types being compared. "
88 "For string columns, you can use std::string, std::string_view, or const char*. "
89 "For optional columns, you can compare with the underlying type or another optional. "
90 "For numeric columns, types must match exactly (use explicit casts if needed).";
91} // namespace type_checking
92
93namespace schema {
94
95// Binary comparison operators for columns
96
97// Equality comparison with direct values
98template <typename TableT, fixed_string Name, typename T, typename... Modifiers, typename ValueType>
99auto operator==(const column<TableT, Name, T, Modifiers...>& col, const ValueType& value) {
101 return col == query::val(value);
102}
103
104// Inequality comparison with direct values
105template <typename TableT, fixed_string Name, typename T, typename... Modifiers, typename ValueType>
106auto operator!=(const column<TableT, Name, T, Modifiers...>& col, const ValueType& value) {
108 return col != query::val(value);
109}
110
111// Greater than comparison with direct values
112template <typename TableT, fixed_string Name, typename T, typename... Modifiers, typename ValueType>
113auto operator>(const column<TableT, Name, T, Modifiers...>& col, const ValueType& value) {
115 return col > query::val(value);
116}
117
118// Less than comparison with direct values
119template <typename TableT, fixed_string Name, typename T, typename... Modifiers, typename ValueType>
120auto operator<(const column<TableT, Name, T, Modifiers...>& col, const ValueType& value) {
122 return col < query::val(value);
123}
124
125// Greater than or equal comparison with direct values
126template <typename TableT, fixed_string Name, typename T, typename... Modifiers, typename ValueType>
127auto operator>=(const column<TableT, Name, T, Modifiers...>& col, const ValueType& value) {
129 return col >= query::val(value);
130}
131
132// Less than or equal comparison with direct values
133template <typename TableT, fixed_string Name, typename T, typename... Modifiers, typename ValueType>
134auto operator<=(const column<TableT, Name, T, Modifiers...>& col, const ValueType& value) {
136 return col <= query::val(value);
137}
138
139// Column to column equality comparison
140template <typename TableT1, fixed_string Name1, typename T1, typename... Modifiers1,
141 typename TableT2, fixed_string Name2, typename T2, typename... Modifiers2>
145 "Column types in comparisons (especially JOIN conditions) must be compatible. "
146 "For example, you cannot join an int column with a string column. "
147 "Both columns must have the same type or be string-compatible types.");
148 auto col1_expr = query::to_expr(col1);
149 auto col2_expr = query::to_expr(col2);
150 return col1_expr == col2_expr;
151}
152
153// Column to column inequality comparison
154template <typename TableT1, fixed_string Name1, typename T1, typename... Modifiers1,
155 typename TableT2, fixed_string Name2, typename T2, typename... Modifiers2>
159 "Column types in comparisons must be compatible. "
160 "Both columns must have the same type or be string-compatible types.");
161 auto col1_expr = query::to_expr(col1);
162 auto col2_expr = query::to_expr(col2);
163 return col1_expr != col2_expr;
164}
165
166// Column to column greater than comparison
167template <typename TableT1, fixed_string Name1, typename T1, typename... Modifiers1,
168 typename TableT2, fixed_string Name2, typename T2, typename... Modifiers2>
172 "Column types in comparisons must be compatible. "
173 "Both columns must have the same type or be string-compatible types.");
174 auto col1_expr = query::to_expr(col1);
175 auto col2_expr = query::to_expr(col2);
176 return col1_expr > col2_expr;
177}
178
179// Column to column less than comparison
180template <typename TableT1, fixed_string Name1, typename T1, typename... Modifiers1,
181 typename TableT2, fixed_string Name2, typename T2, typename... Modifiers2>
185 "Column types in comparisons must be compatible. "
186 "Both columns must have the same type or be string-compatible types.");
187 auto col1_expr = query::to_expr(col1);
188 auto col2_expr = query::to_expr(col2);
189 return col1_expr < col2_expr;
190}
191
192// Column to column greater than or equal comparison
193template <typename TableT1, fixed_string Name1, typename T1, typename... Modifiers1,
194 typename TableT2, fixed_string Name2, typename T2, typename... Modifiers2>
198 "Column types in comparisons must be compatible. "
199 "Both columns must have the same type or be string-compatible types.");
200 auto col1_expr = query::to_expr(col1);
201 auto col2_expr = query::to_expr(col2);
202 return col1_expr >= col2_expr;
203}
204
205// Column to column less than or equal comparison
206template <typename TableT1, fixed_string Name1, typename T1, typename... Modifiers1,
207 typename TableT2, fixed_string Name2, typename T2, typename... Modifiers2>
211 "Column types in comparisons must be compatible. "
212 "Both columns must have the same type or be string-compatible types.");
213 auto col1_expr = query::to_expr(col1);
214 auto col2_expr = query::to_expr(col2);
215 return col1_expr <= col2_expr;
216}
217
218// Specialized operators for common types
219
220// Boolean negation operator
221template <typename TableT, fixed_string Name, typename... Modifiers>
223 auto col_expr = query::to_expr(col);
224 // Using the logical NOT operator
225 return !col_expr;
226}
227
228// Logical AND operator between a column and a query::SqlExpr
229template <typename TableT, fixed_string Name, typename... Modifiers, query::SqlExpr Expr>
230auto operator&&(const column<TableT, Name, bool, Modifiers...>& col, const Expr& expr) {
231 auto col_expr = query::to_expr(col);
232 return col_expr && expr;
233}
234
235// Logical AND operator between a query::SqlExpr and a column (reverse)
236template <query::SqlExpr Expr, typename TableT, fixed_string Name, typename... Modifiers>
237auto operator&&(const Expr& expr, const column<TableT, Name, bool, Modifiers...>& col) {
238 auto col_expr = query::to_expr(col);
239 return expr && col_expr;
240}
241
242// Logical OR operator between a column and a query::SqlExpr
243template <typename TableT, fixed_string Name, typename... Modifiers, query::SqlExpr Expr>
244auto operator||(const column<TableT, Name, bool, Modifiers...>& col, const Expr& expr) {
245 auto col_expr = query::to_expr(col);
246 return col_expr || expr;
247}
248
249// Logical OR operator between a query::SqlExpr and a column (reverse)
250template <query::SqlExpr Expr, typename TableT, fixed_string Name, typename... Modifiers>
251auto operator||(const Expr& expr, const column<TableT, Name, bool, Modifiers...>& col) {
252 auto col_expr = query::to_expr(col);
253 return expr || col_expr;
254}
255
256// Symmetrical operators (value on left, column on right)
257
258// Equality comparison with direct values (reversed)
259template <typename ValueType, typename TableT, fixed_string Name, typename T, typename... Modifiers>
260auto operator==(const ValueType& value, const column<TableT, Name, T, Modifiers...>& col) {
262 return col == value;
263}
264
265// Inequality comparison with direct values (reversed)
266template <typename ValueType, typename TableT, fixed_string Name, typename T, typename... Modifiers>
267auto operator!=(const ValueType& value, const column<TableT, Name, T, Modifiers...>& col) {
269 return col != value;
270}
271
272// Greater than comparison with direct values (reversed)
273template <typename ValueType, typename TableT, fixed_string Name, typename T, typename... Modifiers>
274auto operator>(const ValueType& value, const column<TableT, Name, T, Modifiers...>& col) {
276 return col < value;
277}
278
279// Less than comparison with direct values (reversed)
280template <typename ValueType, typename TableT, fixed_string Name, typename T, typename... Modifiers>
281auto operator<(const ValueType& value, const column<TableT, Name, T, Modifiers...>& col) {
283 return col > value;
284}
285
286// Greater than or equal comparison with direct values (reversed)
287template <typename ValueType, typename TableT, fixed_string Name, typename T, typename... Modifiers>
288auto operator>=(const ValueType& value, const column<TableT, Name, T, Modifiers...>& col) {
290 return col <= value;
291}
292
293// Less than or equal comparison with direct values (reversed)
294template <typename ValueType, typename TableT, fixed_string Name, typename T, typename... Modifiers>
295auto operator<=(const ValueType& value, const column<TableT, Name, T, Modifiers...>& col) {
297 return col >= value;
298}
299
300// Boolean operators for columns with conditions
301
302// Logical AND between column and any condition
303template <typename TableT, fixed_string Name, typename... Modifiers, typename Cond>
304 requires query::SqlExpr<Cond> || (!std::same_as<Cond, bool>)
305auto operator&&(const column<TableT, Name, bool, Modifiers...>& col, const Cond& cond) {
306 auto col_expr = query::to_expr(col);
307 if constexpr (query::SqlExpr<Cond>) {
308 return col_expr && cond;
309 } else {
310 auto val_expr = query::val(cond);
311 return col_expr && val_expr;
312 }
313}
314
315// Logical OR between column and any condition
316template <typename TableT, fixed_string Name, typename... Modifiers, typename Cond>
317 requires query::SqlExpr<Cond> || (!std::same_as<Cond, bool>)
318auto operator||(const column<TableT, Name, bool, Modifiers...>& col, const Cond& cond) {
319 auto col_expr = query::to_expr(col);
320 if constexpr (query::SqlExpr<Cond>) {
321 return col_expr || cond;
322 } else {
323 auto val_expr = query::val(cond);
324 return col_expr || val_expr;
325 }
326}
327
328// Logical AND between condition and column (reversed)
329template <typename Cond, typename TableT, fixed_string Name, typename... Modifiers>
330 requires query::SqlExpr<Cond> || (!std::same_as<Cond, bool>)
331auto operator&&(const Cond& cond, const column<TableT, Name, bool, Modifiers...>& col) {
332 auto col_expr = query::to_expr(col);
333 if constexpr (query::SqlExpr<Cond>) {
334 return cond && col_expr;
335 } else {
336 auto val_expr = query::val(cond);
337 return val_expr && col_expr;
338 }
339}
340
341// Logical OR between condition and column (reversed)
342template <typename Cond, typename TableT, fixed_string Name, typename... Modifiers>
343 requires query::SqlExpr<Cond> || (!std::same_as<Cond, bool>)
344auto operator||(const Cond& cond, const column<TableT, Name, bool, Modifiers...>& col) {
345 auto col_expr = query::to_expr(col);
346 if constexpr (query::SqlExpr<Cond>) {
347 return cond || col_expr;
348 } else {
349 auto val_expr = query::val(cond);
350 return val_expr || col_expr;
351 }
352}
353
354} // namespace schema
355
356namespace query {
357
358// Column to SQL Value comparisons (for _sql literals)
359
360// Define a helper meta trait for checking specializations
361namespace meta {
362template <typename T, template <typename...> class Template>
363struct is_specialization : std::false_type {};
364
365template <template <typename...> class Template, typename... Args>
366struct is_specialization<Template<Args...>, Template> : std::true_type {};
367
368template <typename T, template <typename...> class Template>
370} // namespace meta
371
372// Equality comparison with Value
373template <typename TableT, schema::fixed_string Name, typename T, typename... Modifiers,
374 typename ValueT>
376 const Value<ValueT>& value) {
377 auto col_expr = to_expr(col);
378 return col_expr == value;
379}
380
381// Inequality comparison with Value
382template <typename TableT, schema::fixed_string Name, typename T, typename... Modifiers,
383 typename ValueT>
385 const Value<ValueT>& value) {
386 auto col_expr = to_expr(col);
387 return col_expr != value;
388}
389
390// Greater than comparison with Value
391template <typename TableT, schema::fixed_string Name, typename T, typename... Modifiers,
392 typename ValueT>
394 const Value<ValueT>& value) {
395 auto col_expr = to_expr(col);
396 return col_expr > value;
397}
398
399// Less than comparison with Value
400template <typename TableT, schema::fixed_string Name, typename T, typename... Modifiers,
401 typename ValueT>
403 const Value<ValueT>& value) {
404 auto col_expr = to_expr(col);
405 return col_expr < value;
406}
407
408// Greater than or equal comparison with Value
409template <typename TableT, schema::fixed_string Name, typename T, typename... Modifiers,
410 typename ValueT>
412 const Value<ValueT>& value) {
413 auto col_expr = to_expr(col);
414 return col_expr >= value;
415}
416
417// Less than or equal comparison with Value
418template <typename TableT, schema::fixed_string Name, typename T, typename... Modifiers,
419 typename ValueT>
421 const Value<ValueT>& value) {
422 auto col_expr = to_expr(col);
423 return col_expr <= value;
424}
425
426// Column comparison with direct numeric literals
427// These overloads allow for expressions like col > 42 without needing query::val(42)
428
429// Equality comparison with numeric literal
430template <typename TableT, schema::fixed_string Name, typename T, typename... Modifiers,
431 typename LiteralT>
432 requires std::is_arithmetic_v<std::remove_cvref_t<LiteralT>> &&
433 (!std::is_same_v<LiteralT, bool>) &&
434 (!meta::is_specialization_v<std::remove_cvref_t<LiteralT>, Value>)
435auto operator==(const schema::column<TableT, Name, T, Modifiers...>& col, LiteralT&& literal) {
436 auto col_expr = to_expr(col);
437 auto val_expr = val(std::forward<LiteralT>(literal));
438 return col_expr == val_expr;
439}
440
441// Inequality comparison with numeric literal
442template <typename TableT, schema::fixed_string Name, typename T, typename... Modifiers,
443 typename LiteralT>
444 requires std::is_arithmetic_v<std::remove_cvref_t<LiteralT>> &&
445 (!std::is_same_v<LiteralT, bool>) &&
446 (!meta::is_specialization_v<std::remove_cvref_t<LiteralT>, Value>)
447auto operator!=(const schema::column<TableT, Name, T, Modifiers...>& col, LiteralT&& literal) {
448 auto col_expr = to_expr(col);
449 auto val_expr = val(std::forward<LiteralT>(literal));
450 return col_expr != val_expr;
451}
452
453// Greater than comparison with numeric literal
454template <typename TableT, schema::fixed_string Name, typename T, typename... Modifiers,
455 typename LiteralT>
456 requires std::is_arithmetic_v<std::remove_cvref_t<LiteralT>> &&
457 (!std::is_same_v<LiteralT, bool>) &&
458 (!meta::is_specialization_v<std::remove_cvref_t<LiteralT>, Value>)
459auto operator>(const schema::column<TableT, Name, T, Modifiers...>& col, LiteralT&& literal) {
460 auto col_expr = to_expr(col);
461 auto val_expr = val(std::forward<LiteralT>(literal));
462 return col_expr > val_expr;
463}
464
465// Less than comparison with numeric literal
466template <typename TableT, schema::fixed_string Name, typename T, typename... Modifiers,
467 typename LiteralT>
468 requires std::is_arithmetic_v<std::remove_cvref_t<LiteralT>> &&
469 (!std::is_same_v<LiteralT, bool>) &&
470 (!meta::is_specialization_v<std::remove_cvref_t<LiteralT>, Value>)
471auto operator<(const schema::column<TableT, Name, T, Modifiers...>& col, LiteralT&& literal) {
472 auto col_expr = to_expr(col);
473 auto val_expr = val(std::forward<LiteralT>(literal));
474 return col_expr < val_expr;
475}
476
477// Greater than or equal comparison with numeric literal
478template <typename TableT, schema::fixed_string Name, typename T, typename... Modifiers,
479 typename LiteralT>
480 requires std::is_arithmetic_v<std::remove_cvref_t<LiteralT>> &&
481 (!std::is_same_v<LiteralT, bool>) &&
482 (!meta::is_specialization_v<std::remove_cvref_t<LiteralT>, Value>)
483auto operator>=(const schema::column<TableT, Name, T, Modifiers...>& col, LiteralT&& literal) {
484 auto col_expr = to_expr(col);
485 auto val_expr = val(std::forward<LiteralT>(literal));
486 return col_expr >= val_expr;
487}
488
489// Less than or equal comparison with numeric literal
490template <typename TableT, schema::fixed_string Name, typename T, typename... Modifiers,
491 typename LiteralT>
492 requires std::is_arithmetic_v<std::remove_cvref_t<LiteralT>> &&
493 (!std::is_same_v<LiteralT, bool>) &&
494 (!meta::is_specialization_v<std::remove_cvref_t<LiteralT>, Value>)
495auto operator<=(const schema::column<TableT, Name, T, Modifiers...>& col, LiteralT&& literal) {
496 auto col_expr = to_expr(col);
497 auto val_expr = val(std::forward<LiteralT>(literal));
498 return col_expr <= val_expr;
499}
500
501// Symmetrical operators for numeric literals (literal on left, column on right)
502
503// Equality comparison with numeric literal (reversed)
504template <typename LiteralT, typename TableT, schema::fixed_string Name, typename T,
505 typename... Modifiers>
506 requires std::is_arithmetic_v<std::remove_cvref_t<LiteralT>> &&
507 (!std::is_same_v<LiteralT, bool>) &&
508 (!meta::is_specialization_v<std::remove_cvref_t<LiteralT>, Value>)
509auto operator==(LiteralT&& literal, const schema::column<TableT, Name, T, Modifiers...>& col) {
510 return col == std::forward<LiteralT>(literal);
511}
512
513// Inequality comparison with numeric literal (reversed)
514template <typename LiteralT, typename TableT, schema::fixed_string Name, typename T,
515 typename... Modifiers>
516 requires std::is_arithmetic_v<std::remove_cvref_t<LiteralT>> &&
517 (!std::is_same_v<LiteralT, bool>) &&
518 (!meta::is_specialization_v<std::remove_cvref_t<LiteralT>, Value>)
519auto operator!=(LiteralT&& literal, const schema::column<TableT, Name, T, Modifiers...>& col) {
520 return col != std::forward<LiteralT>(literal);
521}
522
523// Greater than comparison with numeric literal (reversed)
524template <typename LiteralT, typename TableT, schema::fixed_string Name, typename T,
525 typename... Modifiers>
526 requires std::is_arithmetic_v<std::remove_cvref_t<LiteralT>> &&
527 (!std::is_same_v<LiteralT, bool>) &&
528 (!meta::is_specialization_v<std::remove_cvref_t<LiteralT>, Value>)
529auto operator>(LiteralT&& literal, const schema::column<TableT, Name, T, Modifiers...>& col) {
530 return col < std::forward<LiteralT>(literal);
531}
532
533// Less than comparison with numeric literal (reversed)
534template <typename LiteralT, typename TableT, schema::fixed_string Name, typename T,
535 typename... Modifiers>
536 requires std::is_arithmetic_v<std::remove_cvref_t<LiteralT>> &&
537 (!std::is_same_v<LiteralT, bool>) &&
538 (!meta::is_specialization_v<std::remove_cvref_t<LiteralT>, Value>)
539auto operator<(LiteralT&& literal, const schema::column<TableT, Name, T, Modifiers...>& col) {
540 return col > std::forward<LiteralT>(literal);
541}
542
543// Greater than or equal comparison with numeric literal (reversed)
544template <typename LiteralT, typename TableT, schema::fixed_string Name, typename T,
545 typename... Modifiers>
546 requires std::is_arithmetic_v<std::remove_cvref_t<LiteralT>> &&
547 (!std::is_same_v<LiteralT, bool>) &&
548 (!meta::is_specialization_v<std::remove_cvref_t<LiteralT>, Value>)
549auto operator>=(LiteralT&& literal, const schema::column<TableT, Name, T, Modifiers...>& col) {
550 return col <= std::forward<LiteralT>(literal);
551}
552
553// Less than or equal comparison with numeric literal (reversed)
554template <typename LiteralT, typename TableT, schema::fixed_string Name, typename T,
555 typename... Modifiers>
556 requires std::is_arithmetic_v<std::remove_cvref_t<LiteralT>> &&
557 (!std::is_same_v<LiteralT, bool>) &&
558 (!meta::is_specialization_v<std::remove_cvref_t<LiteralT>, Value>)
559auto operator<=(LiteralT&& literal, const schema::column<TableT, Name, T, Modifiers...>& col) {
560 return col >= std::forward<LiteralT>(literal);
561}
562
563// String literal comparison
564// These allow for using string literals directly without query::val
565
566// Equality comparison with string literal
567template <typename TableT, schema::fixed_string Name, typename T, typename... Modifiers>
569 auto col_expr = to_expr(col);
570 auto val_expr = val(str);
571 return col_expr == val_expr;
572}
573
574// Inequality comparison with string literal
575template <typename TableT, schema::fixed_string Name, typename T, typename... Modifiers>
577 auto col_expr = to_expr(col);
578 auto val_expr = val(str);
579 return col_expr != val_expr;
580}
581
582// String literal comparison (reversed)
583template <typename TableT, schema::fixed_string Name, typename T, typename... Modifiers>
585 return col == str;
586}
587
588template <typename TableT, schema::fixed_string Name, typename T, typename... Modifiers>
590 return col != str;
591}
592
593// Additional column operation overloads to avoid to_expr wrappers
594
595// LIKE operator for columns
596template <typename TableT, schema::fixed_string Name, typename T, typename... Modifiers>
597auto like(const schema::column<TableT, Name, T, Modifiers...>& col, std::string pattern) {
598 auto col_expr = to_expr(col);
599 return like(col_expr, std::move(pattern));
600}
601
602// IS NULL operator for columns
603template <typename TableT, schema::fixed_string Name, typename T, typename... Modifiers>
605 auto col_expr = to_expr(col);
606 return is_null(col_expr);
607}
608
609// IS NOT NULL operator for columns
610template <typename TableT, schema::fixed_string Name, typename T, typename... Modifiers>
612 auto col_expr = to_expr(col);
613 return is_not_null(col_expr);
614}
615
616// BETWEEN operator for columns
617template <typename TableT, schema::fixed_string Name, typename T, typename... Modifiers>
619 std::string upper) {
620 auto col_expr = to_expr(col);
621 return between(col_expr, std::move(lower), std::move(upper));
622}
623
624// Column support for case expressions
625
626// When with a column condition
627template <typename TableT, schema::fixed_string Name, typename T, typename... Modifiers,
628 typename ResultT>
630 const query::Value<ResultT>& result) {
631 auto col_expr = to_expr(condition);
632 return when(col_expr, result);
633}
634
635// When with a column result
636template <typename CondT, typename TableT, schema::fixed_string Name, typename T,
637 typename... Modifiers>
638auto when(const CondT& condition, const schema::column<TableT, Name, T, Modifiers...>& result) {
639 auto result_expr = to_expr(result);
640 return when(condition, result_expr);
641}
642
643// Else with a column result
644template <typename TableT, schema::fixed_string Name, typename T, typename... Modifiers>
645// NOLINTNEXTLINE(readability-identifier-naming)
647 auto result_expr = to_expr(result);
648 return else_(result_expr);
649}
650
651// Column support for select expressions
652template <typename TableT, schema::fixed_string Name, typename T, typename... Modifiers,
653 typename... Args>
655 auto col_expr = to_expr(col);
656 return select_expr(col_expr, std::forward<Args>(args)...);
657}
658
659// Adapter to literal comparison operators
660
661// SchemaColumnAdapter comparison with direct literals
662template <typename Column, typename LiteralT>
663 requires std::is_arithmetic_v<std::remove_cvref_t<LiteralT>> &&
664 (!std::is_same_v<LiteralT, bool>) &&
665 (!meta::is_specialization_v<std::remove_cvref_t<LiteralT>, Value>)
666auto operator==(const SchemaColumnAdapter<Column>& col, LiteralT&& literal) {
667 return col == val(std::forward<LiteralT>(literal));
668}
669
670template <typename Column, typename LiteralT>
671 requires std::is_arithmetic_v<std::remove_cvref_t<LiteralT>> &&
672 (!std::is_same_v<LiteralT, bool>) &&
673 (!meta::is_specialization_v<std::remove_cvref_t<LiteralT>, Value>)
674auto operator!=(const SchemaColumnAdapter<Column>& col, LiteralT&& literal) {
675 return col != val(std::forward<LiteralT>(literal));
676}
677
678template <typename Column, typename LiteralT>
679 requires std::is_arithmetic_v<std::remove_cvref_t<LiteralT>> &&
680 (!std::is_same_v<LiteralT, bool>) &&
681 (!meta::is_specialization_v<std::remove_cvref_t<LiteralT>, Value>)
682auto operator>(const SchemaColumnAdapter<Column>& col, LiteralT&& literal) {
683 return col > val(std::forward<LiteralT>(literal));
684}
685
686template <typename Column, typename LiteralT>
687 requires std::is_arithmetic_v<std::remove_cvref_t<LiteralT>> &&
688 (!std::is_same_v<LiteralT, bool>) &&
689 (!meta::is_specialization_v<std::remove_cvref_t<LiteralT>, Value>)
690auto operator<(const SchemaColumnAdapter<Column>& col, LiteralT&& literal) {
691 return col < val(std::forward<LiteralT>(literal));
692}
693
694template <typename Column, typename LiteralT>
695 requires std::is_arithmetic_v<std::remove_cvref_t<LiteralT>> &&
696 (!std::is_same_v<LiteralT, bool>) &&
697 (!meta::is_specialization_v<std::remove_cvref_t<LiteralT>, Value>)
698auto operator>=(const SchemaColumnAdapter<Column>& col, LiteralT&& literal) {
699 return col >= val(std::forward<LiteralT>(literal));
700}
701
702template <typename Column, typename LiteralT>
703 requires std::is_arithmetic_v<std::remove_cvref_t<LiteralT>> &&
704 (!std::is_same_v<LiteralT, bool>) &&
705 (!meta::is_specialization_v<std::remove_cvref_t<LiteralT>, Value>)
706auto operator<=(const SchemaColumnAdapter<Column>& col, LiteralT&& literal) {
707 return col <= val(std::forward<LiteralT>(literal));
708}
709
710// Reversed operators
711template <typename LiteralT, typename Column>
712 requires std::is_arithmetic_v<std::remove_cvref_t<LiteralT>> &&
713 (!std::is_same_v<LiteralT, bool>) &&
714 (!meta::is_specialization_v<std::remove_cvref_t<LiteralT>, Value>)
715auto operator==(LiteralT&& literal, const SchemaColumnAdapter<Column>& col) {
716 return col == std::forward<LiteralT>(literal);
717}
718
719template <typename LiteralT, typename Column>
720 requires std::is_arithmetic_v<std::remove_cvref_t<LiteralT>> &&
721 (!std::is_same_v<LiteralT, bool>) &&
722 (!meta::is_specialization_v<std::remove_cvref_t<LiteralT>, Value>)
723auto operator!=(LiteralT&& literal, const SchemaColumnAdapter<Column>& col) {
724 return col != std::forward<LiteralT>(literal);
725}
726
727template <typename LiteralT, typename Column>
728 requires std::is_arithmetic_v<std::remove_cvref_t<LiteralT>> &&
729 (!std::is_same_v<LiteralT, bool>) &&
730 (!meta::is_specialization_v<std::remove_cvref_t<LiteralT>, Value>)
731auto operator>(LiteralT&& literal, const SchemaColumnAdapter<Column>& col) {
732 return col < std::forward<LiteralT>(literal);
733}
734
735template <typename LiteralT, typename Column>
736 requires std::is_arithmetic_v<std::remove_cvref_t<LiteralT>> &&
737 (!std::is_same_v<LiteralT, bool>) &&
738 (!meta::is_specialization_v<std::remove_cvref_t<LiteralT>, Value>)
739auto operator<(LiteralT&& literal, const SchemaColumnAdapter<Column>& col) {
740 return col > std::forward<LiteralT>(literal);
741}
742
743template <typename LiteralT, typename Column>
744 requires std::is_arithmetic_v<std::remove_cvref_t<LiteralT>> &&
745 (!std::is_same_v<LiteralT, bool>) &&
746 (!meta::is_specialization_v<std::remove_cvref_t<LiteralT>, Value>)
747auto operator>=(LiteralT&& literal, const SchemaColumnAdapter<Column>& col) {
748 return col <= std::forward<LiteralT>(literal);
749}
750
751template <typename LiteralT, typename Column>
752 requires std::is_arithmetic_v<std::remove_cvref_t<LiteralT>> &&
753 (!std::is_same_v<LiteralT, bool>) &&
754 (!meta::is_specialization_v<std::remove_cvref_t<LiteralT>, Value>)
755auto operator<=(LiteralT&& literal, const SchemaColumnAdapter<Column>& col) {
756 return col >= std::forward<LiteralT>(literal);
757}
758
759// String literal comparisons for SchemaColumnAdapter
760template <typename Column>
761auto operator==(const SchemaColumnAdapter<Column>& col, const char* str) {
762 return col == val(str);
763}
764
765template <typename Column>
766auto operator!=(const SchemaColumnAdapter<Column>& col, const char* str) {
767 return col != val(str);
768}
769
770template <typename Column>
771auto operator==(const char* str, const SchemaColumnAdapter<Column>& col) {
772 return col == str;
773}
774
775template <typename Column>
776auto operator!=(const char* str, const SchemaColumnAdapter<Column>& col) {
777 return col != str;
778}
779
780// Additional column operation overloads to avoid to_expr wrappers
781
782// Operators for AliasedColumn to work with literals
783
784// For AliasedColumn == literals
785template <SqlExpr Expr, typename LiteralT>
786 requires std::is_arithmetic_v<std::remove_cvref_t<LiteralT>> ||
787 std::is_convertible_v<std::remove_cvref_t<LiteralT>, std::string>
788auto operator==(const AliasedColumn<Expr>& col, LiteralT&& literal) {
789 auto val_expr = val(std::forward<LiteralT>(literal));
790 return BinaryCondition<AliasedColumn<Expr>, decltype(val_expr)>(col, "=", val_expr);
791}
792
793// For literals == AliasedColumn
794template <SqlExpr Expr, typename LiteralT>
795 requires std::is_arithmetic_v<std::remove_cvref_t<LiteralT>> ||
796 std::is_convertible_v<std::remove_cvref_t<LiteralT>, std::string>
797auto operator==(LiteralT&& literal, const AliasedColumn<Expr>& col) {
798 return col == std::forward<LiteralT>(literal);
799}
800
801// Special case for string literals with AliasedColumn
802template <SqlExpr Expr>
803auto operator==(const AliasedColumn<Expr>& col, const char* str) {
804 auto str_val = val(str);
805 return BinaryCondition<AliasedColumn<Expr>, decltype(str_val)>(col, "=", str_val);
806}
807
808template <SqlExpr Expr>
809auto operator==(const char* str, const AliasedColumn<Expr>& col) {
810 return col == str;
811}
812
813// For AliasedColumn != literals
814template <SqlExpr Expr, typename LiteralT>
815 requires std::is_arithmetic_v<std::remove_cvref_t<LiteralT>> ||
816 std::is_convertible_v<std::remove_cvref_t<LiteralT>, std::string>
817auto operator!=(const AliasedColumn<Expr>& col, LiteralT&& literal) {
818 auto val_expr = val(std::forward<LiteralT>(literal));
819 return BinaryCondition<AliasedColumn<Expr>, decltype(val_expr)>(col, "!=", val_expr);
820}
821
822// For literals != AliasedColumn
823template <SqlExpr Expr, typename LiteralT>
824 requires std::is_arithmetic_v<std::remove_cvref_t<LiteralT>> ||
825 std::is_convertible_v<std::remove_cvref_t<LiteralT>, std::string>
826auto operator!=(LiteralT&& literal, const AliasedColumn<Expr>& col) {
827 return col != std::forward<LiteralT>(literal);
828}
829
830// Special case for string literals with AliasedColumn
831template <SqlExpr Expr>
832auto operator!=(const AliasedColumn<Expr>& col, const char* str) {
833 auto str_val = val(str);
834 return BinaryCondition<AliasedColumn<Expr>, decltype(str_val)>(col, "!=", str_val);
835}
836
837template <SqlExpr Expr>
838auto operator!=(const char* str, const AliasedColumn<Expr>& col) {
839 return col != str;
840}
841
842// For other comparison operators (>, <, >=, <=)
843template <SqlExpr Expr, typename LiteralT>
844 requires std::is_arithmetic_v<std::remove_cvref_t<LiteralT>> ||
845 std::is_convertible_v<std::remove_cvref_t<LiteralT>, std::string>
846auto operator>(const AliasedColumn<Expr>& col, LiteralT&& literal) {
847 auto val_expr = val(std::forward<LiteralT>(literal));
848 return BinaryCondition<AliasedColumn<Expr>, decltype(val_expr)>(col, ">", val_expr);
849}
850
851template <SqlExpr Expr, typename LiteralT>
852 requires std::is_arithmetic_v<std::remove_cvref_t<LiteralT>> ||
853 std::is_convertible_v<std::remove_cvref_t<LiteralT>, std::string>
854auto operator<(const AliasedColumn<Expr>& col, LiteralT&& literal) {
855 auto val_expr = val(std::forward<LiteralT>(literal));
856 return BinaryCondition<AliasedColumn<Expr>, decltype(val_expr)>(col, "<", val_expr);
857}
858
859template <SqlExpr Expr, typename LiteralT>
860 requires std::is_arithmetic_v<std::remove_cvref_t<LiteralT>> ||
861 std::is_convertible_v<std::remove_cvref_t<LiteralT>, std::string>
862auto operator>=(const AliasedColumn<Expr>& col, LiteralT&& literal) {
863 auto val_expr = val(std::forward<LiteralT>(literal));
864 return BinaryCondition<AliasedColumn<Expr>, decltype(val_expr)>(col, ">=", val_expr);
865}
866
867template <SqlExpr Expr, typename LiteralT>
868 requires std::is_arithmetic_v<std::remove_cvref_t<LiteralT>> ||
869 std::is_convertible_v<std::remove_cvref_t<LiteralT>, std::string>
870auto operator<=(const AliasedColumn<Expr>& col, LiteralT&& literal) {
871 auto val_expr = val(std::forward<LiteralT>(literal));
872 return BinaryCondition<AliasedColumn<Expr>, decltype(val_expr)>(col, "<=", val_expr);
873}
874
875// Reversed comparison operators with literals
876template <SqlExpr Expr, typename LiteralT>
877 requires std::is_arithmetic_v<std::remove_cvref_t<LiteralT>> ||
878 std::is_convertible_v<std::remove_cvref_t<LiteralT>, std::string>
879auto operator>(LiteralT&& literal, const AliasedColumn<Expr>& col) {
880 return col < std::forward<LiteralT>(literal);
881}
882
883template <SqlExpr Expr, typename LiteralT>
884 requires std::is_arithmetic_v<std::remove_cvref_t<LiteralT>> ||
885 std::is_convertible_v<std::remove_cvref_t<LiteralT>, std::string>
886auto operator<(LiteralT&& literal, const AliasedColumn<Expr>& col) {
887 return col > std::forward<LiteralT>(literal);
888}
889
890template <SqlExpr Expr, typename LiteralT>
891 requires std::is_arithmetic_v<std::remove_cvref_t<LiteralT>> ||
892 std::is_convertible_v<std::remove_cvref_t<LiteralT>, std::string>
893auto operator>=(LiteralT&& literal, const AliasedColumn<Expr>& col) {
894 return col <= std::forward<LiteralT>(literal);
895}
896
897template <SqlExpr Expr, typename LiteralT>
898 requires std::is_arithmetic_v<std::remove_cvref_t<LiteralT>> ||
899 std::is_convertible_v<std::remove_cvref_t<LiteralT>, std::string>
900auto operator<=(LiteralT&& literal, const AliasedColumn<Expr>& col) {
901 return col >= std::forward<LiteralT>(literal);
902}
903
904// Operators for FunctionExpr to work with literals
905
906// For FunctionExpr == literals
907template <SqlExpr Expr, typename LiteralT>
908 requires std::is_arithmetic_v<std::remove_cvref_t<LiteralT>> ||
909 std::is_convertible_v<std::remove_cvref_t<LiteralT>, std::string>
910auto operator==(const FunctionExpr<Expr>& func, LiteralT&& literal) {
911 auto val_expr = val(std::forward<LiteralT>(literal));
912 return BinaryCondition<FunctionExpr<Expr>, decltype(val_expr)>(func, "=", val_expr);
913}
914
915// For literals == FunctionExpr
916template <SqlExpr Expr, typename LiteralT>
917 requires std::is_arithmetic_v<std::remove_cvref_t<LiteralT>> ||
918 std::is_convertible_v<std::remove_cvref_t<LiteralT>, std::string>
919auto operator==(LiteralT&& literal, const FunctionExpr<Expr>& func) {
920 return func == std::forward<LiteralT>(literal);
921}
922
923// Special case for string literals with FunctionExpr
924template <SqlExpr Expr>
925auto operator==(const FunctionExpr<Expr>& func, const char* str) {
926 auto str_val = val(str);
927 return BinaryCondition<FunctionExpr<Expr>, decltype(str_val)>(func, "=", str_val);
928}
929
930template <SqlExpr Expr>
931auto operator==(const char* str, const FunctionExpr<Expr>& func) {
932 return func == str;
933}
934
935// For FunctionExpr != literals
936template <SqlExpr Expr, typename LiteralT>
937 requires std::is_arithmetic_v<std::remove_cvref_t<LiteralT>> ||
938 std::is_convertible_v<std::remove_cvref_t<LiteralT>, std::string>
939auto operator!=(const FunctionExpr<Expr>& func, LiteralT&& literal) {
940 auto val_expr = val(std::forward<LiteralT>(literal));
941 return BinaryCondition<FunctionExpr<Expr>, decltype(val_expr)>(func, "!=", val_expr);
942}
943
944// For literals != FunctionExpr
945template <SqlExpr Expr, typename LiteralT>
946 requires std::is_arithmetic_v<std::remove_cvref_t<LiteralT>> ||
947 std::is_convertible_v<std::remove_cvref_t<LiteralT>, std::string>
948auto operator!=(LiteralT&& literal, const FunctionExpr<Expr>& func) {
949 return func != std::forward<LiteralT>(literal);
950}
951
952// Special case for string literals with FunctionExpr
953template <SqlExpr Expr>
954auto operator!=(const FunctionExpr<Expr>& func, const char* str) {
955 auto str_val = val(str);
956 return BinaryCondition<FunctionExpr<Expr>, decltype(str_val)>(func, "!=", str_val);
957}
958
959template <SqlExpr Expr>
960auto operator!=(const char* str, const FunctionExpr<Expr>& func) {
961 return func != str;
962}
963
964// For other comparison operators (>, <, >=, <=)
965template <SqlExpr Expr, typename LiteralT>
966 requires std::is_arithmetic_v<std::remove_cvref_t<LiteralT>> ||
967 std::is_convertible_v<std::remove_cvref_t<LiteralT>, std::string>
968auto operator>(const FunctionExpr<Expr>& func, LiteralT&& literal) {
969 auto val_expr = val(std::forward<LiteralT>(literal));
970 return BinaryCondition<FunctionExpr<Expr>, decltype(val_expr)>(func, ">", val_expr);
971}
972
973template <SqlExpr Expr, typename LiteralT>
974 requires std::is_arithmetic_v<std::remove_cvref_t<LiteralT>> ||
975 std::is_convertible_v<std::remove_cvref_t<LiteralT>, std::string>
976auto operator<(const FunctionExpr<Expr>& func, LiteralT&& literal) {
977 auto val_expr = val(std::forward<LiteralT>(literal));
978 return BinaryCondition<FunctionExpr<Expr>, decltype(val_expr)>(func, "<", val_expr);
979}
980
981template <SqlExpr Expr, typename LiteralT>
982 requires std::is_arithmetic_v<std::remove_cvref_t<LiteralT>> ||
983 std::is_convertible_v<std::remove_cvref_t<LiteralT>, std::string>
984auto operator>=(const FunctionExpr<Expr>& func, LiteralT&& literal) {
985 auto val_expr = val(std::forward<LiteralT>(literal));
986 return BinaryCondition<FunctionExpr<Expr>, decltype(val_expr)>(func, ">=", val_expr);
987}
988
989template <SqlExpr Expr, typename LiteralT>
990 requires std::is_arithmetic_v<std::remove_cvref_t<LiteralT>> ||
991 std::is_convertible_v<std::remove_cvref_t<LiteralT>, std::string>
992auto operator<=(const FunctionExpr<Expr>& func, LiteralT&& literal) {
993 auto val_expr = val(std::forward<LiteralT>(literal));
994 return BinaryCondition<FunctionExpr<Expr>, decltype(val_expr)>(func, "<=", val_expr);
995}
996
997// Reversed comparison operators with literals
998template <SqlExpr Expr, typename LiteralT>
999 requires std::is_arithmetic_v<std::remove_cvref_t<LiteralT>> ||
1000 std::is_convertible_v<std::remove_cvref_t<LiteralT>, std::string>
1001auto operator>(LiteralT&& literal, const FunctionExpr<Expr>& func) {
1002 return func < std::forward<LiteralT>(literal);
1003}
1004
1005template <SqlExpr Expr, typename LiteralT>
1006 requires std::is_arithmetic_v<std::remove_cvref_t<LiteralT>> ||
1007 std::is_convertible_v<std::remove_cvref_t<LiteralT>, std::string>
1008auto operator<(LiteralT&& literal, const FunctionExpr<Expr>& func) {
1009 return func > std::forward<LiteralT>(literal);
1010}
1011
1012template <SqlExpr Expr, typename LiteralT>
1013 requires std::is_arithmetic_v<std::remove_cvref_t<LiteralT>> ||
1014 std::is_convertible_v<std::remove_cvref_t<LiteralT>, std::string>
1015auto operator>=(LiteralT&& literal, const FunctionExpr<Expr>& func) {
1016 return func <= std::forward<LiteralT>(literal);
1017}
1018
1019template <SqlExpr Expr, typename LiteralT>
1020 requires std::is_arithmetic_v<std::remove_cvref_t<LiteralT>> ||
1021 std::is_convertible_v<std::remove_cvref_t<LiteralT>, std::string>
1022auto operator<=(LiteralT&& literal, const FunctionExpr<Expr>& func) {
1023 return func >= std::forward<LiteralT>(literal);
1024}
1025
1026// Operators for CoalesceExpr to work with literals
1027
1028// For CoalesceExpr == literals
1029template <SqlExpr First, SqlExpr Second, SqlExpr... Rest, typename LiteralT>
1030 requires std::is_arithmetic_v<std::remove_cvref_t<LiteralT>> ||
1031 std::is_convertible_v<std::remove_cvref_t<LiteralT>, std::string>
1032auto operator==(const CoalesceExpr<First, Second, Rest...>& coalesce, LiteralT&& literal) {
1033 auto val_expr = val(std::forward<LiteralT>(literal));
1034 return BinaryCondition<CoalesceExpr<First, Second, Rest...>, decltype(val_expr)>(coalesce, "=",
1035 val_expr);
1036}
1037
1038// For literals == CoalesceExpr
1039template <SqlExpr First, SqlExpr Second, SqlExpr... Rest, typename LiteralT>
1040 requires std::is_arithmetic_v<std::remove_cvref_t<LiteralT>> ||
1041 std::is_convertible_v<std::remove_cvref_t<LiteralT>, std::string>
1042auto operator==(LiteralT&& literal, const CoalesceExpr<First, Second, Rest...>& coalesce) {
1043 return coalesce == std::forward<LiteralT>(literal);
1044}
1045
1046// Special case for string literals with CoalesceExpr
1047template <SqlExpr First, SqlExpr Second, SqlExpr... Rest>
1048auto operator==(const CoalesceExpr<First, Second, Rest...>& coalesce, const char* str) {
1049 auto str_val = val(str);
1050 return BinaryCondition<CoalesceExpr<First, Second, Rest...>, decltype(str_val)>(coalesce, "=",
1051 str_val);
1052}
1053
1054template <SqlExpr First, SqlExpr Second, SqlExpr... Rest>
1055auto operator==(const char* str, const CoalesceExpr<First, Second, Rest...>& coalesce) {
1056 return coalesce == str;
1057}
1058
1059// For CoalesceExpr != literals
1060template <SqlExpr First, SqlExpr Second, SqlExpr... Rest, typename LiteralT>
1061 requires std::is_arithmetic_v<std::remove_cvref_t<LiteralT>> ||
1062 std::is_convertible_v<std::remove_cvref_t<LiteralT>, std::string>
1063auto operator!=(const CoalesceExpr<First, Second, Rest...>& coalesce, LiteralT&& literal) {
1064 auto val_expr = val(std::forward<LiteralT>(literal));
1065 return BinaryCondition<CoalesceExpr<First, Second, Rest...>, decltype(val_expr)>(coalesce,
1066 "!=", val_expr);
1067}
1068
1069// For literals != CoalesceExpr
1070template <SqlExpr First, SqlExpr Second, SqlExpr... Rest, typename LiteralT>
1071 requires std::is_arithmetic_v<std::remove_cvref_t<LiteralT>> ||
1072 std::is_convertible_v<std::remove_cvref_t<LiteralT>, std::string>
1073auto operator!=(LiteralT&& literal, const CoalesceExpr<First, Second, Rest...>& coalesce) {
1074 return coalesce != std::forward<LiteralT>(literal);
1075}
1076
1077// Special case for string literals with CoalesceExpr
1078template <SqlExpr First, SqlExpr Second, SqlExpr... Rest>
1079auto operator!=(const CoalesceExpr<First, Second, Rest...>& coalesce, const char* str) {
1080 auto str_val = val(str);
1081 return BinaryCondition<CoalesceExpr<First, Second, Rest...>, decltype(str_val)>(coalesce,
1082 "!=", str_val);
1083}
1084
1085template <SqlExpr First, SqlExpr Second, SqlExpr... Rest>
1086auto operator!=(const char* str, const CoalesceExpr<First, Second, Rest...>& coalesce) {
1087 return coalesce != str;
1088}
1089
1090// Operators for CountAllExpr to work with literals
1091template <typename LiteralT>
1092 requires std::is_arithmetic_v<std::remove_cvref_t<LiteralT>> ||
1093 std::is_convertible_v<std::remove_cvref_t<LiteralT>, std::string>
1094auto operator==(const CountAllExpr& expr, LiteralT&& literal) {
1095 auto val_expr = val(std::forward<LiteralT>(literal));
1096 return BinaryCondition<CountAllExpr, decltype(val_expr)>(expr, "=", val_expr);
1097}
1098
1099template <typename LiteralT>
1100 requires std::is_arithmetic_v<std::remove_cvref_t<LiteralT>> ||
1101 std::is_convertible_v<std::remove_cvref_t<LiteralT>, std::string>
1102auto operator==(LiteralT&& literal, const CountAllExpr& expr) {
1103 return expr == std::forward<LiteralT>(literal);
1104}
1105
1106template <typename LiteralT>
1107 requires std::is_arithmetic_v<std::remove_cvref_t<LiteralT>> ||
1108 std::is_convertible_v<std::remove_cvref_t<LiteralT>, std::string>
1109auto operator!=(const CountAllExpr& expr, LiteralT&& literal) {
1110 auto val_expr = val(std::forward<LiteralT>(literal));
1111 return BinaryCondition<CountAllExpr, decltype(val_expr)>(expr, "!=", val_expr);
1112}
1113
1114template <typename LiteralT>
1115 requires std::is_arithmetic_v<std::remove_cvref_t<LiteralT>> ||
1116 std::is_convertible_v<std::remove_cvref_t<LiteralT>, std::string>
1117auto operator!=(LiteralT&& literal, const CountAllExpr& expr) {
1118 return expr != std::forward<LiteralT>(literal);
1119}
1120
1121template <typename LiteralT>
1122 requires std::is_arithmetic_v<std::remove_cvref_t<LiteralT>> ||
1123 std::is_convertible_v<std::remove_cvref_t<LiteralT>, std::string>
1124auto operator>(const CountAllExpr& expr, LiteralT&& literal) {
1125 auto val_expr = val(std::forward<LiteralT>(literal));
1126 return BinaryCondition<CountAllExpr, decltype(val_expr)>(expr, ">", val_expr);
1127}
1128
1129template <typename LiteralT>
1130 requires std::is_arithmetic_v<std::remove_cvref_t<LiteralT>> ||
1131 std::is_convertible_v<std::remove_cvref_t<LiteralT>, std::string>
1132auto operator>(LiteralT&& literal, const CountAllExpr& expr) {
1133 auto val_expr = val(std::forward<LiteralT>(literal));
1134 return BinaryCondition<decltype(val_expr), CountAllExpr>(val_expr, ">", expr);
1135}
1136
1137template <typename LiteralT>
1138 requires std::is_arithmetic_v<std::remove_cvref_t<LiteralT>> ||
1139 std::is_convertible_v<std::remove_cvref_t<LiteralT>, std::string>
1140auto operator<(const CountAllExpr& expr, LiteralT&& literal) {
1141 auto val_expr = val(std::forward<LiteralT>(literal));
1142 return BinaryCondition<CountAllExpr, decltype(val_expr)>(expr, "<", val_expr);
1143}
1144
1145template <typename LiteralT>
1146 requires std::is_arithmetic_v<std::remove_cvref_t<LiteralT>> ||
1147 std::is_convertible_v<std::remove_cvref_t<LiteralT>, std::string>
1148auto operator<(LiteralT&& literal, const CountAllExpr& expr) {
1149 auto val_expr = val(std::forward<LiteralT>(literal));
1150 return BinaryCondition<decltype(val_expr), CountAllExpr>(val_expr, "<", expr);
1151}
1152
1153template <typename LiteralT>
1154 requires std::is_arithmetic_v<std::remove_cvref_t<LiteralT>> ||
1155 std::is_convertible_v<std::remove_cvref_t<LiteralT>, std::string>
1156auto operator>=(const CountAllExpr& expr, LiteralT&& literal) {
1157 auto val_expr = val(std::forward<LiteralT>(literal));
1158 return BinaryCondition<CountAllExpr, decltype(val_expr)>(expr, ">=", val_expr);
1159}
1160
1161template <typename LiteralT>
1162 requires std::is_arithmetic_v<std::remove_cvref_t<LiteralT>> ||
1163 std::is_convertible_v<std::remove_cvref_t<LiteralT>, std::string>
1164auto operator>=(LiteralT&& literal, const CountAllExpr& expr) {
1165 auto val_expr = val(std::forward<LiteralT>(literal));
1166 return BinaryCondition<decltype(val_expr), CountAllExpr>(val_expr, ">=", expr);
1167}
1168
1169template <typename LiteralT>
1170 requires std::is_arithmetic_v<std::remove_cvref_t<LiteralT>> ||
1171 std::is_convertible_v<std::remove_cvref_t<LiteralT>, std::string>
1172auto operator<=(const CountAllExpr& expr, LiteralT&& literal) {
1173 auto val_expr = val(std::forward<LiteralT>(literal));
1174 return BinaryCondition<CountAllExpr, decltype(val_expr)>(expr, "<=", val_expr);
1175}
1176
1177template <typename LiteralT>
1178 requires std::is_arithmetic_v<std::remove_cvref_t<LiteralT>> ||
1179 std::is_convertible_v<std::remove_cvref_t<LiteralT>, std::string>
1180auto operator<=(LiteralT&& literal, const CountAllExpr& expr) {
1181 auto val_expr = val(std::forward<LiteralT>(literal));
1182 return BinaryCondition<decltype(val_expr), CountAllExpr>(val_expr, "<=", expr);
1183}
1184
1185// Forward declaration for date expressions
1186class CurrentDateTimeExpr;
1187template <SqlExpr Expr>
1188class UnaryDateFunctionExpr;
1189template <SqlExpr Left, SqlExpr Right>
1190class BinaryDateFunctionExpr;
1191template <SqlExpr DateExpr, SqlExpr IntervalExpr>
1192class DateArithmeticExpr;
1193
1194// Operators for CurrentDateTimeExpr with date columns
1195template <typename TableT, schema::fixed_string Name, typename T, typename... Modifiers>
1196 requires date_checking::DateTimeType<T>
1199 auto col_expr = to_expr(col);
1201}
1202
1203template <typename TableT, schema::fixed_string Name, typename T, typename... Modifiers>
1204 requires date_checking::DateTimeType<T>
1207 auto col_expr = to_expr(col);
1209}
1210
1211template <typename TableT, schema::fixed_string Name, typename T, typename... Modifiers>
1212 requires date_checking::DateTimeType<T>
1215 auto col_expr = to_expr(col);
1217}
1218
1219template <typename TableT, schema::fixed_string Name, typename T, typename... Modifiers>
1220 requires date_checking::DateTimeType<T>
1223 auto col_expr = to_expr(col);
1225}
1226
1227template <typename TableT, schema::fixed_string Name, typename T, typename... Modifiers>
1228 requires date_checking::DateTimeType<T>
1231 auto col_expr = to_expr(col);
1233}
1234
1235template <typename TableT, schema::fixed_string Name, typename T, typename... Modifiers>
1236 requires date_checking::DateTimeType<T>
1239 auto col_expr = to_expr(col);
1241}
1242
1243// Operators for UnaryDateFunctionExpr with date columns
1244template <SqlExpr Expr, typename TableT, schema::fixed_string Name, typename T,
1245 typename... Modifiers>
1246 requires date_checking::DateTimeType<T>
1249 auto col_expr = to_expr(col);
1250 return BinaryCondition<UnaryDateFunctionExpr<Expr>, decltype(col_expr)>(expr, ">", col_expr);
1251}
1252
1253template <SqlExpr Expr, typename TableT, schema::fixed_string Name, typename T,
1254 typename... Modifiers>
1255 requires date_checking::DateTimeType<T>
1258 auto col_expr = to_expr(col);
1259 return BinaryCondition<UnaryDateFunctionExpr<Expr>, decltype(col_expr)>(expr, "<", col_expr);
1260}
1261
1262template <SqlExpr Expr, typename TableT, schema::fixed_string Name, typename T,
1263 typename... Modifiers>
1264 requires date_checking::DateTimeType<T>
1267 auto col_expr = to_expr(col);
1268 return BinaryCondition<UnaryDateFunctionExpr<Expr>, decltype(col_expr)>(expr, ">=", col_expr);
1269}
1270
1271template <SqlExpr Expr, typename TableT, schema::fixed_string Name, typename T,
1272 typename... Modifiers>
1273 requires date_checking::DateTimeType<T>
1276 auto col_expr = to_expr(col);
1277 return BinaryCondition<UnaryDateFunctionExpr<Expr>, decltype(col_expr)>(expr, "<=", col_expr);
1278}
1279
1280template <SqlExpr Expr, typename TableT, schema::fixed_string Name, typename T,
1281 typename... Modifiers>
1282 requires date_checking::DateTimeType<T>
1285 auto col_expr = to_expr(col);
1286 return BinaryCondition<UnaryDateFunctionExpr<Expr>, decltype(col_expr)>(expr, "=", col_expr);
1287}
1288
1289template <SqlExpr Expr, typename TableT, schema::fixed_string Name, typename T,
1290 typename... Modifiers>
1291 requires date_checking::DateTimeType<T>
1294 auto col_expr = to_expr(col);
1295 return BinaryCondition<UnaryDateFunctionExpr<Expr>, decltype(col_expr)>(expr, "!=", col_expr);
1296}
1297
1298// Operators for BinaryDateFunctionExpr with date columns
1299template <SqlExpr Left, SqlExpr Right, typename TableT, schema::fixed_string Name, typename T,
1300 typename... Modifiers>
1301 requires date_checking::DateTimeType<T>
1304 auto col_expr = to_expr(col);
1305 return BinaryCondition<BinaryDateFunctionExpr<Left, Right>, decltype(col_expr)>(expr, ">",
1306 col_expr);
1307}
1308
1309template <SqlExpr Left, SqlExpr Right, typename TableT, schema::fixed_string Name, typename T,
1310 typename... Modifiers>
1311 requires date_checking::DateTimeType<T>
1314 auto col_expr = to_expr(col);
1315 return BinaryCondition<BinaryDateFunctionExpr<Left, Right>, decltype(col_expr)>(expr, "<",
1316 col_expr);
1317}
1318
1319template <SqlExpr Left, SqlExpr Right, typename TableT, schema::fixed_string Name, typename T,
1320 typename... Modifiers>
1321 requires date_checking::DateTimeType<T>
1324 auto col_expr = to_expr(col);
1325 return BinaryCondition<BinaryDateFunctionExpr<Left, Right>, decltype(col_expr)>(expr,
1326 ">=", col_expr);
1327}
1328
1329template <SqlExpr Left, SqlExpr Right, typename TableT, schema::fixed_string Name, typename T,
1330 typename... Modifiers>
1331 requires date_checking::DateTimeType<T>
1334 auto col_expr = to_expr(col);
1335 return BinaryCondition<BinaryDateFunctionExpr<Left, Right>, decltype(col_expr)>(expr,
1336 "<=", col_expr);
1337}
1338
1339template <SqlExpr Left, SqlExpr Right, typename TableT, schema::fixed_string Name, typename T,
1340 typename... Modifiers>
1341 requires date_checking::DateTimeType<T>
1344 auto col_expr = to_expr(col);
1345 return BinaryCondition<BinaryDateFunctionExpr<Left, Right>, decltype(col_expr)>(expr, "=",
1346 col_expr);
1347}
1348
1349template <SqlExpr Left, SqlExpr Right, typename TableT, schema::fixed_string Name, typename T,
1350 typename... Modifiers>
1351 requires date_checking::DateTimeType<T>
1354 auto col_expr = to_expr(col);
1355 return BinaryCondition<BinaryDateFunctionExpr<Left, Right>, decltype(col_expr)>(expr,
1356 "!=", col_expr);
1357}
1358
1359// Operators for DateArithmeticExpr with date columns
1360template <SqlExpr DateExpr, SqlExpr IntervalExpr, typename TableT, schema::fixed_string Name,
1361 typename T, typename... Modifiers>
1362 requires date_checking::DateTimeType<T>
1365 auto col_expr = to_expr(col);
1366 return BinaryCondition<DateArithmeticExpr<DateExpr, IntervalExpr>, decltype(col_expr)>(expr, ">",
1367 col_expr);
1368}
1369
1370template <SqlExpr DateExpr, SqlExpr IntervalExpr, typename TableT, schema::fixed_string Name,
1371 typename T, typename... Modifiers>
1372 requires date_checking::DateTimeType<T>
1375 auto col_expr = to_expr(col);
1376 return BinaryCondition<DateArithmeticExpr<DateExpr, IntervalExpr>, decltype(col_expr)>(expr, "<",
1377 col_expr);
1378}
1379
1380template <SqlExpr DateExpr, SqlExpr IntervalExpr, typename TableT, schema::fixed_string Name,
1381 typename T, typename... Modifiers>
1382 requires date_checking::DateTimeType<T>
1385 auto col_expr = to_expr(col);
1387 expr, ">=", col_expr);
1388}
1389
1390template <SqlExpr DateExpr, SqlExpr IntervalExpr, typename TableT, schema::fixed_string Name,
1391 typename T, typename... Modifiers>
1392 requires date_checking::DateTimeType<T>
1395 auto col_expr = to_expr(col);
1397 expr, "<=", col_expr);
1398}
1399
1400template <SqlExpr DateExpr, SqlExpr IntervalExpr, typename TableT, schema::fixed_string Name,
1401 typename T, typename... Modifiers>
1402 requires date_checking::DateTimeType<T>
1405 auto col_expr = to_expr(col);
1406 return BinaryCondition<DateArithmeticExpr<DateExpr, IntervalExpr>, decltype(col_expr)>(expr, "=",
1407 col_expr);
1408}
1409
1410template <SqlExpr DateExpr, SqlExpr IntervalExpr, typename TableT, schema::fixed_string Name,
1411 typename T, typename... Modifiers>
1412 requires date_checking::DateTimeType<T>
1415 auto col_expr = to_expr(col);
1417 expr, "!=", col_expr);
1418}
1419
1420} // namespace query
1421
1422} // namespace relx
1423
1424// Implementation of column methods that delegate to query functions
1425namespace relx::schema {
1426
1427// Implementation for non-optional columns
1428template <typename TableT, fixed_string Name, typename T, typename... Modifiers>
1429template <typename PatternType>
1430 requires std::convertible_to<PatternType, std::string>
1431auto column<TableT, Name, T, Modifiers...>::like(PatternType&& pattern) const {
1432 return query::like(*this, std::string(std::forward<PatternType>(pattern)));
1433}
1434
1435template <typename TableT, fixed_string Name, typename T, typename... Modifiers>
1439
1440template <typename TableT, fixed_string Name, typename T, typename... Modifiers>
1444
1445// Implementation for optional columns
1446template <typename TableT, fixed_string Name, typename T, typename... Modifiers>
1447template <typename PatternType>
1448 requires std::convertible_to<PatternType, std::string>
1449auto column<TableT, Name, std::optional<T>, Modifiers...>::like(PatternType&& pattern) const {
1450 return query::like(*this, std::string(std::forward<PatternType>(pattern)));
1451}
1452
1453template <typename TableT, fixed_string Name, typename T, typename... Modifiers>
1454auto column<TableT, Name, std::optional<T>, Modifiers...>::is_null() const {
1455 return query::is_null(*this);
1456}
1457
1458template <typename TableT, fixed_string Name, typename T, typename... Modifiers>
1459auto column<TableT, Name, std::optional<T>, Modifiers...>::is_not_null() const {
1460 return query::is_not_null(*this);
1461}
1462
1463} // namespace relx::schema
Generic binary condition expression.
Definition condition.hpp:16
Binary date function expression (e.g., DATE_DIFF)
Definition date.hpp:23
COALESCE function.
Definition function.hpp:355
Expression representing COUNT(*) in SQL.
Definition function.hpp:59
Current date/time functions (no arguments)
Definition date.hpp:330
Date addition/subtraction expression.
Definition date.hpp:291
Base class for SQL function expressions.
Definition function.hpp:17
Adapter to convert schema::column to a ColumnRef This allows direct use of schema columns in query ex...
Unary date function expression with unit (e.g., EXTRACT)
Definition date.hpp:162
Represents a literal value in a SQL query.
Definition value.hpp:15
Represents a column in a database table.
Definition column.hpp:217
auto like(PatternType &&pattern) const
Create a LIKE condition for this column.
auto is_null() const
Create an IS NULL condition for this column.
auto is_not_null() const
Create an IS NOT NULL condition for this column.
Concept for SQL expression components.
Definition core.hpp:29
Check if optional types are compatible with each other or their underlying types.
Definition operators.hpp:51
Check if two types are string-compatible.
Definition operators.hpp:40
Check if column type is compatible with value type.
Definition operators.hpp:76
constexpr bool is_specialization_v
auto like(Expr expr, std::string pattern)
Create a LIKE condition.
auto operator<=(Left left, Right right)
Less than or equal condition (col <= value)
Definition condition.hpp:72
auto operator>(Left left, Right right)
Greater than condition (col > value)
Definition condition.hpp:54
auto select_expr(const schema::column< TableT, Name, T, Modifiers... > &col, Args &&... args)
auto operator<(Left left, Right right)
Less than condition (col < value)
Definition condition.hpp:60
auto operator>=(Left left, Right right)
Greater than or equal condition (col >= value)
Definition condition.hpp:66
auto to_expr(const C &col, std::string_view table_name="")
Helper to wrap a schema column in a SQL expression.
auto is_null(Expr expr)
Create an IS NULL condition.
auto else_(CaseBuilder &builder, const char *value)
auto between(Expr expr, std::string lower, std::string upper)
Create a BETWEEN condition.
auto value(T val)
Create a value expression.
Definition value.hpp:120
auto coalesce(First first, Second second, Rest... rest)
Create a COALESCE expression.
Definition function.hpp:409
auto lower(Expr expr)
LOWER string function.
Definition function.hpp:275
auto operator==(Left left, Right right)
Equality condition (col = value)
Definition condition.hpp:42
auto val(const char *str)
Helper to create a value expression from a string literal.
Definition value.hpp:127
auto is_not_null(Expr expr)
Create an IS NOT NULL condition.
auto upper(Expr expr)
UPPER string function.
Definition function.hpp:297
auto when(CaseBuilder &builder, const ConditionExpr auto &condition, const char *value)
auto operator!=(Left left, Right right)
Inequality condition (col != value)
Definition condition.hpp:48
auto operator>(const column< TableT, Name, T, Modifiers... > &col, const ValueType &value)
auto operator<(const column< TableT, Name, T, Modifiers... > &col, const ValueType &value)
auto operator>=(const column< TableT, Name, T, Modifiers... > &col, const ValueType &value)
auto operator&&(const column< TableT, Name, bool, Modifiers... > &col, const Expr &expr)
auto operator<=(const column< TableT, Name, T, Modifiers... > &col, const ValueType &value)
auto operator!=(const column< TableT, Name, T, Modifiers... > &col, const ValueType &value)
auto operator!(const column< TableT, Name, bool, Modifiers... > &col)
auto operator==(const column< TableT, Name, T, Modifiers... > &col, const ValueType &value)
Definition operators.hpp:99
auto operator||(const column< TableT, Name, bool, Modifiers... > &col, const Expr &expr)
constexpr std::string_view type_error_message
Constant error message for type mismatches.
Definition operators.hpp:85
typename remove_optional< T >::type remove_optional_t
Definition operators.hpp:36
relx database connection
STL namespace.
Compile-time string type that can be used as template non-type parameter in C++20.
Helper to extract the underlying type from optional.
Definition operators.hpp:24
static constexpr bool is_optional
Definition operators.hpp:26