1use crate::args::Args;
4use crate::flavor::Flavor;
5use crate::macros::{IntoStrings, collect_into_strings};
6use crate::modifiers::{Arg, Builder};
7use crate::string_builder::{StringBuilder, filter_empty_strings};
8use std::cell::RefCell;
9use std::rc::Rc;
10
11const MIN_INDEX_BASE: usize = 256;
12
13pub type ArgsRef = Rc<RefCell<Args>>;
14
15#[derive(Debug, Clone)]
17pub struct Cond {
18 pub(crate) args: ArgsRef,
19}
20
21impl Cond {
22 pub fn new() -> Self {
24 let a = Args {
25 index_base: MIN_INDEX_BASE,
26 ..Args::default()
27 };
28 Self {
29 args: Rc::new(RefCell::new(a)),
30 }
31 }
32
33 pub(crate) fn with_args(args: ArgsRef) -> Self {
34 Self { args }
35 }
36
37 pub fn var(&self, value: impl Into<Arg>) -> String {
39 self.args.borrow_mut().add(value)
40 }
41
42 fn expr_builder(&self, f: impl Fn(Flavor, &[Arg]) -> (String, Vec<Arg>) + 'static) -> String {
43 self.var(Arg::Builder(Box::new(CondDynBuilder::new(f))))
44 }
45
46 pub fn equal(&self, field: &str, value: impl Into<Arg>) -> String {
47 if field.is_empty() {
48 return String::new();
49 }
50 let field = field.to_string();
51 let value: Arg = value.into();
52 self.expr_builder(move |flavor, initial| {
53 let mut a = Args {
54 flavor,
55 ..Args::default()
56 };
57 let v = a.add(value.clone());
58 let fmt = format!("{field} = {v}");
59 a.compile_with_flavor(&fmt, flavor, initial)
60 })
61 }
62 pub fn e(&self, field: &str, value: impl Into<Arg>) -> String {
63 self.equal(field, value)
64 }
65 pub fn eq(&self, field: &str, value: impl Into<Arg>) -> String {
66 self.equal(field, value)
67 }
68
69 pub fn not_equal(&self, field: &str, value: impl Into<Arg>) -> String {
70 if field.is_empty() {
71 return String::new();
72 }
73 let field = field.to_string();
74 let value: Arg = value.into();
75 self.expr_builder(move |flavor, initial| {
76 let mut a = Args {
77 flavor,
78 ..Args::default()
79 };
80 let v = a.add(value.clone());
81 let fmt = format!("{field} <> {v}");
82 a.compile_with_flavor(&fmt, flavor, initial)
83 })
84 }
85 pub fn ne(&self, field: &str, value: impl Into<Arg>) -> String {
86 self.not_equal(field, value)
87 }
88 pub fn neq(&self, field: &str, value: impl Into<Arg>) -> String {
89 self.not_equal(field, value)
90 }
91
92 pub fn greater_than(&self, field: &str, value: impl Into<Arg>) -> String {
93 if field.is_empty() {
94 return String::new();
95 }
96 let field = field.to_string();
97 let value: Arg = value.into();
98 self.expr_builder(move |flavor, initial| {
99 let mut a = Args {
100 flavor,
101 ..Args::default()
102 };
103 let v = a.add(value.clone());
104 let fmt = format!("{field} > {v}");
105 a.compile_with_flavor(&fmt, flavor, initial)
106 })
107 }
108 pub fn g(&self, field: &str, value: impl Into<Arg>) -> String {
109 self.greater_than(field, value)
110 }
111 pub fn gt(&self, field: &str, value: impl Into<Arg>) -> String {
112 self.greater_than(field, value)
113 }
114
115 pub fn greater_equal_than(&self, field: &str, value: impl Into<Arg>) -> String {
116 if field.is_empty() {
117 return String::new();
118 }
119 let field = field.to_string();
120 let value: Arg = value.into();
121 self.expr_builder(move |flavor, initial| {
122 let mut a = Args {
123 flavor,
124 ..Args::default()
125 };
126 let v = a.add(value.clone());
127 let fmt = format!("{field} >= {v}");
128 a.compile_with_flavor(&fmt, flavor, initial)
129 })
130 }
131 pub fn ge(&self, field: &str, value: impl Into<Arg>) -> String {
132 self.greater_equal_than(field, value)
133 }
134 pub fn gte(&self, field: &str, value: impl Into<Arg>) -> String {
135 self.greater_equal_than(field, value)
136 }
137
138 pub fn less_than(&self, field: &str, value: impl Into<Arg>) -> String {
139 if field.is_empty() {
140 return String::new();
141 }
142 let field = field.to_string();
143 let value: Arg = value.into();
144 self.expr_builder(move |flavor, initial| {
145 let mut a = Args {
146 flavor,
147 ..Args::default()
148 };
149 let v = a.add(value.clone());
150 let fmt = format!("{field} < {v}");
151 a.compile_with_flavor(&fmt, flavor, initial)
152 })
153 }
154 pub fn l(&self, field: &str, value: impl Into<Arg>) -> String {
155 self.less_than(field, value)
156 }
157 pub fn lt(&self, field: &str, value: impl Into<Arg>) -> String {
158 self.less_than(field, value)
159 }
160
161 pub fn less_equal_than(&self, field: &str, value: impl Into<Arg>) -> String {
162 if field.is_empty() {
163 return String::new();
164 }
165 let field = field.to_string();
166 let value: Arg = value.into();
167 self.expr_builder(move |flavor, initial| {
168 let mut a = Args {
169 flavor,
170 ..Args::default()
171 };
172 let v = a.add(value.clone());
173 let fmt = format!("{field} <= {v}");
174 a.compile_with_flavor(&fmt, flavor, initial)
175 })
176 }
177 pub fn le(&self, field: &str, value: impl Into<Arg>) -> String {
178 self.less_equal_than(field, value)
179 }
180 pub fn lte(&self, field: &str, value: impl Into<Arg>) -> String {
181 self.less_equal_than(field, value)
182 }
183
184 pub fn like(&self, field: &str, value: impl Into<Arg>) -> String {
185 if field.is_empty() {
186 return String::new();
187 }
188 let field = field.to_string();
189 let value: Arg = value.into();
190 self.expr_builder(move |flavor, initial| {
191 let mut a = Args {
192 flavor,
193 ..Args::default()
194 };
195 let v = a.add(value.clone());
196 let fmt = format!("{field} LIKE {v}");
197 a.compile_with_flavor(&fmt, flavor, initial)
198 })
199 }
200
201 pub fn ilike(&self, field: &str, value: impl Into<Arg>) -> String {
202 if field.is_empty() {
203 return String::new();
204 }
205
206 let field = field.to_string();
207 let value: Arg = value.into();
208
209 let b = CondDynBuilder::new(move |flavor, initial| {
211 let mut a = Args {
212 flavor,
213 ..Args::default()
214 };
215 let v = a.add(value.clone());
216 let fmt = match flavor {
217 Flavor::PostgreSQL | Flavor::SQLite => format!("{} ILIKE {v}", field),
218 _ => format!("LOWER({}) LIKE LOWER({v})", field),
219 };
220 a.compile_with_flavor(&fmt, flavor, initial)
221 });
222 self.var(Arg::Builder(Box::new(b)))
223 }
224
225 pub fn not_like(&self, field: &str, value: impl Into<Arg>) -> String {
226 if field.is_empty() {
227 return String::new();
228 }
229 let field = field.to_string();
230 let value: Arg = value.into();
231 self.expr_builder(move |flavor, initial| {
232 let mut a = Args {
233 flavor,
234 ..Args::default()
235 };
236 let v = a.add(value.clone());
237 let fmt = format!("{field} NOT LIKE {v}");
238 a.compile_with_flavor(&fmt, flavor, initial)
239 })
240 }
241
242 pub fn not_ilike(&self, field: &str, value: impl Into<Arg>) -> String {
243 if field.is_empty() {
244 return String::new();
245 }
246
247 let field = field.to_string();
248 let value: Arg = value.into();
249
250 let b = CondDynBuilder::new(move |flavor, initial| {
251 let mut a = Args {
252 flavor,
253 ..Args::default()
254 };
255 let v = a.add(value.clone());
256 let fmt = match flavor {
257 Flavor::PostgreSQL | Flavor::SQLite => format!("{} NOT ILIKE {v}", field),
258 _ => format!("LOWER({}) NOT LIKE LOWER({v})", field),
259 };
260 a.compile_with_flavor(&fmt, flavor, initial)
261 });
262 self.var(Arg::Builder(Box::new(b)))
263 }
264
265 pub fn is_null(&self, field: &str) -> String {
266 if field.is_empty() {
267 return String::new();
268 }
269 let field = field.to_string();
270 self.expr_builder(move |_flavor, initial| (format!("{field} IS NULL"), initial.to_vec()))
271 }
272
273 pub fn is_not_null(&self, field: &str) -> String {
274 if field.is_empty() {
275 return String::new();
276 }
277 let field = field.to_string();
278 self.expr_builder(move |_flavor, initial| {
279 (format!("{field} IS NOT NULL"), initial.to_vec())
280 })
281 }
282
283 pub fn between(&self, field: &str, lower: impl Into<Arg>, upper: impl Into<Arg>) -> String {
284 if field.is_empty() {
285 return String::new();
286 }
287 let field = field.to_string();
288 let lower: Arg = lower.into();
289 let upper: Arg = upper.into();
290 self.expr_builder(move |flavor, initial| {
291 let mut a = Args {
292 flavor,
293 ..Args::default()
294 };
295 let l = a.add(lower.clone());
296 let u = a.add(upper.clone());
297 let fmt = format!("{field} BETWEEN {l} AND {u}");
298 a.compile_with_flavor(&fmt, flavor, initial)
299 })
300 }
301
302 pub fn not_between(&self, field: &str, lower: impl Into<Arg>, upper: impl Into<Arg>) -> String {
303 if field.is_empty() {
304 return String::new();
305 }
306 let field = field.to_string();
307 let lower: Arg = lower.into();
308 let upper: Arg = upper.into();
309 self.expr_builder(move |flavor, initial| {
310 let mut a = Args {
311 flavor,
312 ..Args::default()
313 };
314 let l = a.add(lower.clone());
315 let u = a.add(upper.clone());
316 let fmt = format!("{field} NOT BETWEEN {l} AND {u}");
317 a.compile_with_flavor(&fmt, flavor, initial)
318 })
319 }
320
321 pub fn in_(&self, field: &str, values: impl IntoIterator<Item = impl Into<Arg>>) -> String {
322 if field.is_empty() {
323 return String::new();
324 }
325 let values: Vec<Arg> = values.into_iter().map(|v| v.into()).collect();
326 if values.is_empty() {
327 return "0 = 1".to_string();
328 }
329 let field = field.to_string();
330 self.expr_builder(move |flavor, initial| {
331 let mut a = Args {
332 flavor,
333 ..Args::default()
334 };
335 let vals: Vec<String> = values.iter().cloned().map(|v| a.add(v)).collect();
336 let fmt = format!("{field} IN ({})", vals.join(", "));
337 a.compile_with_flavor(&fmt, flavor, initial)
338 })
339 }
340
341 pub fn not_in(&self, field: &str, values: impl IntoIterator<Item = impl Into<Arg>>) -> String {
342 if field.is_empty() {
343 return String::new();
344 }
345 let values: Vec<Arg> = values.into_iter().map(|v| v.into()).collect();
346 if values.is_empty() {
347 return "0 = 0".to_string();
348 }
349 let field = field.to_string();
350 self.expr_builder(move |flavor, initial| {
351 let mut a = Args {
352 flavor,
353 ..Args::default()
354 };
355 let vals: Vec<String> = values.iter().cloned().map(|v| a.add(v)).collect();
356 let fmt = format!("{field} NOT IN ({})", vals.join(", "));
357 a.compile_with_flavor(&fmt, flavor, initial)
358 })
359 }
360
361 pub fn or<T>(&self, exprs: T) -> String
362 where
363 T: IntoStrings,
364 {
365 let exprs = filter_empty_strings(collect_into_strings(exprs));
366 if exprs.is_empty() {
367 return String::new();
368 }
369 let mut buf = StringBuilder::new();
370 buf.write_str("(");
371 buf.write_strings(&exprs, " OR ");
372 buf.write_str(")");
373 buf.into_string()
374 }
375
376 pub fn and<T>(&self, exprs: T) -> String
377 where
378 T: IntoStrings,
379 {
380 let exprs = filter_empty_strings(collect_into_strings(exprs));
381 if exprs.is_empty() {
382 return String::new();
383 }
384 let mut buf = StringBuilder::new();
385 buf.write_str("(");
386 buf.write_strings(&exprs, " AND ");
387 buf.write_str(")");
388 buf.into_string()
389 }
390
391 pub fn not(&self, expr: impl Into<String>) -> String {
392 let expr = expr.into();
393 if expr.is_empty() {
394 return String::new();
395 }
396 format!("NOT {expr}")
397 }
398
399 pub fn exists(&self, subquery: impl Into<Arg>) -> String {
400 let subquery: Arg = subquery.into();
401 self.expr_builder(move |flavor, initial| {
402 let mut a = Args {
403 flavor,
404 ..Args::default()
405 };
406 let v = a.add(subquery.clone());
407 let fmt = format!("EXISTS ({v})");
408 a.compile_with_flavor(&fmt, flavor, initial)
409 })
410 }
411
412 pub fn not_exists(&self, subquery: impl Into<Arg>) -> String {
413 let subquery: Arg = subquery.into();
414 self.expr_builder(move |flavor, initial| {
415 let mut a = Args {
416 flavor,
417 ..Args::default()
418 };
419 let v = a.add(subquery.clone());
420 let fmt = format!("NOT EXISTS ({v})");
421 a.compile_with_flavor(&fmt, flavor, initial)
422 })
423 }
424
425 pub fn any(
426 &self,
427 field: &str,
428 op: &str,
429 values: impl IntoIterator<Item = impl Into<Arg>>,
430 ) -> String {
431 if field.is_empty() || op.is_empty() {
432 return String::new();
433 }
434 let values: Vec<Arg> = values.into_iter().map(|v| v.into()).collect();
435 if values.is_empty() {
436 return "0 = 1".to_string();
437 }
438 let field = field.to_string();
439 let op = op.to_string();
440 self.expr_builder(move |flavor, initial| {
441 let mut a = Args {
442 flavor,
443 ..Args::default()
444 };
445 let vals: Vec<String> = values.iter().cloned().map(|v| a.add(v)).collect();
446 let fmt = format!("{field} {op} ANY ({})", vals.join(", "));
447 a.compile_with_flavor(&fmt, flavor, initial)
448 })
449 }
450
451 pub fn all(
452 &self,
453 field: &str,
454 op: &str,
455 values: impl IntoIterator<Item = impl Into<Arg>>,
456 ) -> String {
457 if field.is_empty() || op.is_empty() {
458 return String::new();
459 }
460 let values: Vec<Arg> = values.into_iter().map(|v| v.into()).collect();
461 if values.is_empty() {
462 return "0 = 1".to_string();
463 }
464 let field = field.to_string();
465 let op = op.to_string();
466 self.expr_builder(move |flavor, initial| {
467 let mut a = Args {
468 flavor,
469 ..Args::default()
470 };
471 let vals: Vec<String> = values.iter().cloned().map(|v| a.add(v)).collect();
472 let fmt = format!("{field} {op} ALL ({})", vals.join(", "));
473 a.compile_with_flavor(&fmt, flavor, initial)
474 })
475 }
476
477 pub fn some(
478 &self,
479 field: &str,
480 op: &str,
481 values: impl IntoIterator<Item = impl Into<Arg>>,
482 ) -> String {
483 if field.is_empty() || op.is_empty() {
484 return String::new();
485 }
486 let values: Vec<Arg> = values.into_iter().map(|v| v.into()).collect();
487 if values.is_empty() {
488 return "0 = 1".to_string();
489 }
490 let field = field.to_string();
491 let op = op.to_string();
492 self.expr_builder(move |flavor, initial| {
493 let mut a = Args {
494 flavor,
495 ..Args::default()
496 };
497 let vals: Vec<String> = values.iter().cloned().map(|v| a.add(v)).collect();
498 let fmt = format!("{field} {op} SOME ({})", vals.join(", "));
499 a.compile_with_flavor(&fmt, flavor, initial)
500 })
501 }
502
503 pub fn is_distinct_from(&self, field: &str, value: impl Into<Arg>) -> String {
504 if field.is_empty() {
505 return String::new();
506 }
507
508 let field = field.to_string();
509 let value: Arg = value.into();
510
511 let b = CondDynBuilder::new(move |flavor, initial| {
512 let mut a = Args {
513 flavor,
514 ..Args::default()
515 };
516 let fmt = match flavor {
517 Flavor::PostgreSQL | Flavor::SQLite | Flavor::SQLServer => {
518 let v = a.add(value.clone());
519 format!("{field} IS DISTINCT FROM {v}")
520 }
521 Flavor::MySQL => {
522 let v = a.add(value.clone());
523 format!("NOT {field} <=> {v}")
524 }
525 _ => {
526 let v1 = a.add(value.clone());
532 let v2 = a.add(value.clone());
533 let v3 = a.add(value.clone());
534 format!(
535 "CASE WHEN {field} IS NULL AND {v1} IS NULL THEN 0 WHEN {field} IS NOT NULL AND {v2} IS NOT NULL AND {field} = {v3} THEN 0 ELSE 1 END = 1"
536 )
537 }
538 };
539 a.compile_with_flavor(&fmt, flavor, initial)
540 });
541 self.var(Arg::Builder(Box::new(b)))
542 }
543
544 pub fn is_not_distinct_from(&self, field: &str, value: impl Into<Arg>) -> String {
545 if field.is_empty() {
546 return String::new();
547 }
548
549 let field = field.to_string();
550 let value: Arg = value.into();
551
552 let b = CondDynBuilder::new(move |flavor, initial| {
553 let mut a = Args {
554 flavor,
555 ..Args::default()
556 };
557 let fmt = match flavor {
558 Flavor::PostgreSQL | Flavor::SQLite | Flavor::SQLServer => {
559 let v = a.add(value.clone());
560 format!("{field} IS NOT DISTINCT FROM {v}")
561 }
562 Flavor::MySQL => {
563 let v = a.add(value.clone());
564 format!("{field} <=> {v}")
565 }
566 _ => {
567 let v1 = a.add(value.clone());
573 let v2 = a.add(value.clone());
574 let v3 = a.add(value.clone());
575 format!(
576 "CASE WHEN {field} IS NULL AND {v1} IS NULL THEN 1 WHEN {field} IS NOT NULL AND {v2} IS NOT NULL AND {field} = {v3} THEN 1 ELSE 0 END = 1"
577 )
578 }
579 };
580 a.compile_with_flavor(&fmt, flavor, initial)
581 });
582 self.var(Arg::Builder(Box::new(b)))
583 }
584}
585
586#[derive(Clone)]
588struct CondDynBuilder {
589 f: Rc<CondBuildFn>,
590}
591
592type CondBuildFn = dyn Fn(Flavor, &[Arg]) -> (String, Vec<Arg>);
593
594impl CondDynBuilder {
595 fn new(f: impl Fn(Flavor, &[Arg]) -> (String, Vec<Arg>) + 'static) -> Self {
596 Self { f: Rc::new(f) }
597 }
598}
599
600impl Default for Cond {
601 fn default() -> Self {
602 Self::new()
603 }
604}
605
606impl Builder for CondDynBuilder {
607 fn build_with_flavor(&self, flavor: Flavor, initial_arg: &[Arg]) -> (String, Vec<Arg>) {
608 (self.f)(flavor, initial_arg)
609 }
610
611 fn flavor(&self) -> Flavor {
612 Flavor::default()
613 }
614}