qraft_core/expression/
like.rs1use std::borrow::Cow;
4
5use super::Operator;
6use crate::{
7 Bool, Likeable, LowerCompatible,
8 expression::Expression,
9 lower::{Instructions, LowerCtx},
10};
11
12#[derive(Debug)]
14pub struct Like<L, R> {
15 pub case_sensitive: bool,
16 pub negated: bool,
17 pub left: L,
18 pub right: R,
19}
20
21pub fn prepare_sqlite_glob<'a>(value: &'a str) -> Cow<'a, str> {
23 let mut first_special = None;
24 for (i, ch) in value.char_indices() {
25 match ch {
26 '*' | '?' | '%' | '_' => {
27 first_special = Some(i);
28 break;
29 }
30 _ => {}
31 }
32 }
33
34 let Some(idx) = first_special else {
35 return Cow::Borrowed(value);
36 };
37
38 let mut out = String::with_capacity(value.len());
39 out.push_str(&value[..idx]);
40
41 for ch in value[idx..].chars() {
42 match ch {
43 '*' => {
44 out.push('[');
45 out.push('*');
46 out.push(']');
47 }
48 '?' => {
49 out.push('[');
50 out.push('?');
51 out.push(']');
52 }
53 '%' => out.push('*'),
54 '_' => out.push('?'),
55 _ => out.push(ch),
56 }
57 }
58
59 Cow::Owned(out)
60}
61
62#[qraft_expression_macro::as_expression]
63impl<L, R, T> Expression for Like<L, R>
64where
65 T: Likeable,
66 L: Expression<Type = T>,
67 R: LowerCompatible<T>,
68{
69 type Type = Bool;
70
71 fn lower(&self, ctx: &mut LowerCtx) -> usize {
72 let lhs = self.left.lower(ctx);
73 let rhs = self.right.lower_compatible(ctx);
74 ctx.instrs.push_binary(
75 Operator::Like {
76 sensitive: self.case_sensitive,
77 negated: self.negated,
78 },
79 lhs,
80 rhs,
81 );
82 lhs + rhs + 1
83 }
84}
85
86impl<L, R> Like<L, R> {
87 pub fn case_sensitive(mut self) -> Self {
89 self.case_sensitive = true;
90 self
91 }
92}
93
94pub trait LikeExt<T: Likeable>: Sized + Expression {
96 fn like<E>(self, other: E) -> Like<Self, E>
97 where
98 E: LowerCompatible<T>,
99 {
100 Like {
101 left: self,
102 right: other,
103 case_sensitive: false,
104 negated: false,
105 }
106 }
107
108 fn not_like<E>(self, other: E) -> Like<Self, E>
109 where
110 E: LowerCompatible<T>,
111 {
112 Like {
113 left: self,
114 right: other,
115 case_sensitive: false,
116 negated: true,
117 }
118 }
119}
120
121impl<T: Likeable, V> LikeExt<T> for V where V: Expression<Type = T> {}