relx 0.1.0
A Modern C++23 Type-Safe SQL Query Builder
Loading...
Searching...
No Matches
condition.hpp
Go to the documentation of this file.
1#pragma once
2
4#include "core.hpp"
5#include "schema_adapter.hpp"
6
7#include <memory>
8#include <sstream>
9#include <string>
10#include <vector>
11
12namespace relx::query {
13
15template <SqlExpr Left, SqlExpr Right>
17public:
18 BinaryCondition(Left left, std::string op, Right right)
19 : left_(std::move(left)), op_(std::move(op)), right_(std::move(right)) {}
20
21 std::string to_sql() const override {
22 std::stringstream ss;
23 ss << "(" << left_.to_sql() << " " << op_ << " " << right_.to_sql() << ")";
24 return ss.str();
25 }
26
27 std::vector<std::string> bind_params() const override {
28 auto left_params = left_.bind_params();
29 auto right_params = right_.bind_params();
30 left_params.insert(left_params.end(), right_params.begin(), right_params.end());
31 return left_params;
32 }
33
34private:
35 Left left_;
36 std::string op_;
37 Right right_;
38};
39
41template <SqlExpr Left, SqlExpr Right>
42auto operator==(Left left, Right right) {
43 return BinaryCondition<Left, Right>(std::move(left), "=", std::move(right));
44}
45
47template <SqlExpr Left, SqlExpr Right>
48auto operator!=(Left left, Right right) {
49 return BinaryCondition<Left, Right>(std::move(left), "!=", std::move(right));
50}
51
53template <SqlExpr Left, SqlExpr Right>
54auto operator>(Left left, Right right) {
55 return BinaryCondition<Left, Right>(std::move(left), ">", std::move(right));
56}
57
59template <SqlExpr Left, SqlExpr Right>
60auto operator<(Left left, Right right) {
61 return BinaryCondition<Left, Right>(std::move(left), "<", std::move(right));
62}
63
65template <SqlExpr Left, SqlExpr Right>
66auto operator>=(Left left, Right right) {
67 return BinaryCondition<Left, Right>(std::move(left), ">=", std::move(right));
68}
69
71template <SqlExpr Left, SqlExpr Right>
72auto operator<=(Left left, Right right) {
73 return BinaryCondition<Left, Right>(std::move(left), "<=", std::move(right));
74}
75
77template <SqlExpr Left, SqlExpr Right>
78auto operator&&(Left left, Right right) {
79 return BinaryCondition<Left, Right>(std::move(left), "AND", std::move(right));
80}
81
83template <SqlExpr Left, SqlExpr Right>
84auto operator||(Left left, Right right) {
85 return BinaryCondition<Left, Right>(std::move(left), "OR", std::move(right));
86}
87
89template <SqlExpr Expr, std::ranges::range Range>
90 requires std::convertible_to<std::ranges::range_value_t<Range>, std::string>
92public:
93 TypedInCondition(Expr expr, Range values) : expr_(std::move(expr)), values_(std::move(values)) {}
94
95 std::string to_sql() const override {
96 std::stringstream ss;
97 ss << expr_.to_sql() << " IN (";
98 bool first = true;
99 for (const auto& _ : values_) {
100 if (!first) {
101 ss << ", ";
102 }
103 ss << "?";
104 first = false;
105 }
106 ss << ")";
107 return ss.str();
108 }
109
110 std::vector<std::string> bind_params() const override {
111 auto params = expr_.bind_params();
112 for (const auto& value : values_) {
113 params.push_back(value);
114 }
115 return params;
116 }
117
118private:
119 Expr expr_;
120 Range values_;
121};
122
129template <typename TableT, schema::fixed_string Name, typename T, typename... Modifiers,
130 std::ranges::range Range>
131 requires std::convertible_to<std::ranges::range_value_t<Range>, std::string>
132auto in(const schema::column<TableT, Name, T, Modifiers...>& col, Range values) {
133 using ValueType = std::ranges::range_value_t<Range>;
134
135 // Type check for IN operations - ensure the values are compatible with the column type
136 if constexpr (std::same_as<T, std::string> || std::same_as<T, std::string_view>) {
137 static_assert(std::convertible_to<ValueType, std::string>,
138 "IN operation with string column requires string-convertible values");
139 } else if constexpr (std::is_arithmetic_v<T>) {
140 static_assert(std::convertible_to<ValueType, std::string>,
141 "IN operation values must be convertible to string for parameter binding");
142 }
143
144 auto col_expr = to_expr(col);
145 return TypedInCondition<decltype(col_expr), Range>(std::move(col_expr), std::move(values));
146}
147
149template <SqlExpr Expr, std::ranges::range Range>
150 requires std::convertible_to<std::ranges::range_value_t<Range>, std::string>
152public:
153 InCondition(Expr expr, Range values) : expr_(std::move(expr)), values_(std::move(values)) {}
154
155 std::string to_sql() const override {
156 std::stringstream ss;
157 ss << expr_.to_sql() << " IN (";
158 bool first = true;
159 for (const auto& _ : values_) {
160 if (!first) {
161 ss << ", ";
162 }
163 ss << "?";
164 first = false;
165 }
166 ss << ")";
167 return ss.str();
168 }
169
170 std::vector<std::string> bind_params() const override {
171 auto params = expr_.bind_params();
172 for (const auto& value : values_) {
173 params.push_back(value);
174 }
175 return params;
176 }
177
178private:
179 Expr expr_;
180 Range values_;
181};
182
189template <SqlExpr Expr, std::ranges::range Range>
190 requires std::convertible_to<std::ranges::range_value_t<Range>, std::string>
191auto in(Expr expr, Range values) {
192 return InCondition<Expr, Range>(std::move(expr), std::move(values));
193}
194
196template <SqlExpr Expr>
198public:
199 LikeCondition(Expr expr, std::string pattern)
200 : expr_(std::move(expr)), pattern_(std::move(pattern)) {}
201
202 std::string to_sql() const override { return expr_.to_sql() + " LIKE ?"; }
203
204 std::vector<std::string> bind_params() const override {
205 auto params = expr_.bind_params();
206 params.push_back(pattern_);
207 return params;
208 }
209
210private:
211 Expr expr_;
212 std::string pattern_;
213};
214
220template <SqlExpr Expr>
221auto like(Expr expr, std::string pattern) {
222 return LikeCondition<Expr>(std::move(expr), std::move(pattern));
223}
224
226template <SqlExpr Expr>
228public:
229 BetweenCondition(Expr expr, std::string lower, std::string upper)
230 : expr_(std::move(expr)), lower_(std::move(lower)), upper_(std::move(upper)) {}
231
232 std::string to_sql() const override { return expr_.to_sql() + " BETWEEN ? AND ?"; }
233
234 std::vector<std::string> bind_params() const override {
235 auto params = expr_.bind_params();
236 params.push_back(lower_);
237 params.push_back(upper_);
238 return params;
239 }
240
241private:
242 Expr expr_;
243 std::string lower_;
244 std::string upper_;
245};
246
253template <SqlExpr Expr>
254auto between(Expr expr, std::string lower, std::string upper) {
255 return BetweenCondition<Expr>(std::move(expr), std::move(lower), std::move(upper));
256}
257
259template <SqlExpr Expr>
261public:
262 explicit IsNullCondition(Expr expr) : expr_(std::move(expr)) {}
263
264 std::string to_sql() const override { return expr_.to_sql() + " IS NULL"; }
265
266 std::vector<std::string> bind_params() const override { return expr_.bind_params(); }
267
268private:
269 Expr expr_;
270};
271
276template <SqlExpr Expr>
277auto is_null(Expr expr) {
278 return IsNullCondition<Expr>(std::move(expr));
279}
280
282template <SqlExpr Expr>
284public:
285 explicit IsNotNullCondition(Expr expr) : expr_(std::move(expr)) {}
286
287 std::string to_sql() const override { return expr_.to_sql() + " IS NOT NULL"; }
288
289 std::vector<std::string> bind_params() const override { return expr_.bind_params(); }
290
291private:
292 Expr expr_;
293};
294
299template <SqlExpr Expr>
300auto is_not_null(Expr expr) {
301 return IsNotNullCondition<Expr>(std::move(expr));
302}
303
305template <SqlExpr Expr>
307public:
308 explicit NotCondition(Expr expr) : expr_(std::move(expr)) {}
309
310 std::string to_sql() const override { return "(NOT " + expr_.to_sql() + ")"; }
311
312 std::vector<std::string> bind_params() const override { return expr_.bind_params(); }
313
314private:
315 Expr expr_;
316};
317
319template <SqlExpr Expr>
320auto operator!(Expr expr) {
321 return NotCondition<Expr>(std::move(expr));
322}
323
324} // namespace relx::query
BETWEEN condition (col BETWEEN lower AND upper)
std::vector< std::string > bind_params() const override
std::string to_sql() const override
BetweenCondition(Expr expr, std::string lower, std::string upper)
Generic binary condition expression.
Definition condition.hpp:16
BinaryCondition(Left left, std::string op, Right right)
Definition condition.hpp:18
std::string to_sql() const override
Definition condition.hpp:21
std::vector< std::string > bind_params() const override
Definition condition.hpp:27
Original IN condition for backward compatibility.
std::string to_sql() const override
InCondition(Expr expr, Range values)
std::vector< std::string > bind_params() const override
IS NOT NULL condition.
std::string to_sql() const override
std::vector< std::string > bind_params() const override
std::string to_sql() const override
std::vector< std::string > bind_params() const override
LIKE condition (col LIKE pattern)
LikeCondition(Expr expr, std::string pattern)
std::string to_sql() const override
std::vector< std::string > bind_params() const override
Negation condition (NOT expr)
std::vector< std::string > bind_params() const override
std::string to_sql() const override
IN condition (col IN (values)) with type checking.
Definition condition.hpp:91
std::string to_sql() const override
Definition condition.hpp:95
TypedInCondition(Expr expr, Range values)
Definition condition.hpp:93
std::vector< std::string > bind_params() const override
Represents a column in a database table.
Definition column.hpp:217
auto like(Expr expr, std::string pattern)
Create a LIKE condition.
auto operator||(Left left, Right right)
Logical OR condition.
Definition condition.hpp:84
auto operator<=(Left left, Right right)
Less than or equal condition (col <= value)
Definition condition.hpp:72
auto in(const schema::column< TableT, Name, T, Modifiers... > &col, Range values)
Create an IN condition with type checking for columns.
auto operator>(Left left, Right right)
Greater than condition (col > value)
Definition condition.hpp:54
auto operator&&(Left left, Right right)
Logical AND condition.
Definition condition.hpp:78
auto operator!(Expr expr)
Logical NOT operator.
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 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 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 is_not_null(Expr expr)
Create an IS NOT NULL condition.
auto upper(Expr expr)
UPPER string function.
Definition function.hpp:297
auto operator!=(Left left, Right right)
Inequality condition (col != value)
Definition condition.hpp:48
STL namespace.
Base class for SQL expressions.
Definition core.hpp:61
Compile-time string type that can be used as template non-type parameter in C++20.