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