oxigdal_query/executor/join/
value.rs1#[derive(Debug, Clone, PartialEq)]
5pub enum JoinValue {
6 Null,
8 Boolean(bool),
10 Integer(i64),
12 Float(f64),
14 String(String),
16}
17
18impl JoinValue {
19 pub fn is_null(&self) -> bool {
21 matches!(self, JoinValue::Null)
22 }
23
24 pub fn to_hash_key(&self) -> String {
26 match self {
27 JoinValue::Null => "__NULL__".to_string(),
28 JoinValue::Boolean(b) => format!("b:{}", b),
29 JoinValue::Integer(i) => format!("i:{}", i),
30 JoinValue::Float(f) => format!("f:{:?}", f),
31 JoinValue::String(s) => format!("s:{}", s),
32 }
33 }
34
35 pub fn equals(&self, other: &JoinValue) -> Option<bool> {
37 if self.is_null() || other.is_null() {
38 return None; }
40
41 match (self, other) {
42 (JoinValue::Boolean(a), JoinValue::Boolean(b)) => Some(a == b),
43 (JoinValue::Integer(a), JoinValue::Integer(b)) => Some(a == b),
44 (JoinValue::Integer(a), JoinValue::Float(b)) => Some((*a as f64) == *b),
45 (JoinValue::Float(a), JoinValue::Integer(b)) => Some(*a == (*b as f64)),
46 (JoinValue::Float(a), JoinValue::Float(b)) => Some(a == b),
47 (JoinValue::String(a), JoinValue::String(b)) => Some(a == b),
48 _ => Some(false), }
50 }
51
52 pub fn compare(&self, other: &JoinValue) -> Option<std::cmp::Ordering> {
54 if self.is_null() || other.is_null() {
55 return None;
56 }
57
58 match (self, other) {
59 (JoinValue::Boolean(a), JoinValue::Boolean(b)) => Some(a.cmp(b)),
60 (JoinValue::Integer(a), JoinValue::Integer(b)) => Some(a.cmp(b)),
61 (JoinValue::Integer(a), JoinValue::Float(b)) => (*a as f64).partial_cmp(b),
62 (JoinValue::Float(a), JoinValue::Integer(b)) => a.partial_cmp(&(*b as f64)),
63 (JoinValue::Float(a), JoinValue::Float(b)) => a.partial_cmp(b),
64 (JoinValue::String(a), JoinValue::String(b)) => Some(a.cmp(b)),
65 _ => None, }
67 }
68
69 pub fn negate(&self) -> Option<JoinValue> {
71 match self {
72 JoinValue::Integer(i) => Some(JoinValue::Integer(-i)),
73 JoinValue::Float(f) => Some(JoinValue::Float(-f)),
74 _ => None,
75 }
76 }
77
78 pub fn not(&self) -> Option<JoinValue> {
80 match self {
81 JoinValue::Boolean(b) => Some(JoinValue::Boolean(!b)),
82 _ => None,
83 }
84 }
85
86 pub fn add(&self, other: &JoinValue) -> Option<JoinValue> {
88 match (self, other) {
89 (JoinValue::Integer(a), JoinValue::Integer(b)) => Some(JoinValue::Integer(a + b)),
90 (JoinValue::Integer(a), JoinValue::Float(b)) => Some(JoinValue::Float(*a as f64 + b)),
91 (JoinValue::Float(a), JoinValue::Integer(b)) => Some(JoinValue::Float(a + *b as f64)),
92 (JoinValue::Float(a), JoinValue::Float(b)) => Some(JoinValue::Float(a + b)),
93 (JoinValue::String(a), JoinValue::String(b)) => {
94 Some(JoinValue::String(format!("{}{}", a, b)))
95 }
96 _ => None,
97 }
98 }
99
100 pub fn subtract(&self, other: &JoinValue) -> Option<JoinValue> {
102 match (self, other) {
103 (JoinValue::Integer(a), JoinValue::Integer(b)) => Some(JoinValue::Integer(a - b)),
104 (JoinValue::Integer(a), JoinValue::Float(b)) => Some(JoinValue::Float(*a as f64 - b)),
105 (JoinValue::Float(a), JoinValue::Integer(b)) => Some(JoinValue::Float(a - *b as f64)),
106 (JoinValue::Float(a), JoinValue::Float(b)) => Some(JoinValue::Float(a - b)),
107 _ => None,
108 }
109 }
110
111 pub fn multiply(&self, other: &JoinValue) -> Option<JoinValue> {
113 match (self, other) {
114 (JoinValue::Integer(a), JoinValue::Integer(b)) => Some(JoinValue::Integer(a * b)),
115 (JoinValue::Integer(a), JoinValue::Float(b)) => Some(JoinValue::Float(*a as f64 * b)),
116 (JoinValue::Float(a), JoinValue::Integer(b)) => Some(JoinValue::Float(a * *b as f64)),
117 (JoinValue::Float(a), JoinValue::Float(b)) => Some(JoinValue::Float(a * b)),
118 _ => None,
119 }
120 }
121
122 pub fn divide(&self, other: &JoinValue) -> Option<JoinValue> {
124 match (self, other) {
125 (JoinValue::Integer(a), JoinValue::Integer(b)) if *b != 0 => {
126 Some(JoinValue::Integer(a / b))
127 }
128 (JoinValue::Integer(a), JoinValue::Float(b)) if *b != 0.0 => {
129 Some(JoinValue::Float(*a as f64 / b))
130 }
131 (JoinValue::Float(a), JoinValue::Integer(b)) if *b != 0 => {
132 Some(JoinValue::Float(a / *b as f64))
133 }
134 (JoinValue::Float(a), JoinValue::Float(b)) if *b != 0.0 => {
135 Some(JoinValue::Float(a / b))
136 }
137 _ => None,
138 }
139 }
140
141 pub fn modulo(&self, other: &JoinValue) -> Option<JoinValue> {
143 match (self, other) {
144 (JoinValue::Integer(a), JoinValue::Integer(b)) if *b != 0 => {
145 Some(JoinValue::Integer(a % b))
146 }
147 (JoinValue::Integer(a), JoinValue::Float(b)) if *b != 0.0 => {
148 Some(JoinValue::Float(*a as f64 % b))
149 }
150 (JoinValue::Float(a), JoinValue::Integer(b)) if *b != 0 => {
151 Some(JoinValue::Float(a % *b as f64))
152 }
153 (JoinValue::Float(a), JoinValue::Float(b)) if *b != 0.0 => {
154 Some(JoinValue::Float(a % b))
155 }
156 _ => None,
157 }
158 }
159
160 pub fn to_bool(&self) -> Option<bool> {
162 match self {
163 JoinValue::Boolean(b) => Some(*b),
164 JoinValue::Null => None,
165 _ => None,
166 }
167 }
168
169 pub fn matches_like(&self, pattern: &JoinValue) -> Option<bool> {
171 match (self, pattern) {
172 (JoinValue::String(s), JoinValue::String(p)) => Some(Self::like_match(s, p)),
173 _ => None,
174 }
175 }
176
177 pub fn like_match(text: &str, pattern: &str) -> bool {
179 let text_chars: Vec<char> = text.chars().collect();
180 let pattern_chars: Vec<char> = pattern.chars().collect();
181
182 Self::like_match_recursive(&text_chars, 0, &pattern_chars, 0)
183 }
184
185 fn like_match_recursive(text: &[char], ti: usize, pattern: &[char], pi: usize) -> bool {
186 if pi >= pattern.len() {
187 return ti >= text.len();
188 }
189
190 let pattern_char = pattern[pi];
191
192 match pattern_char {
193 '%' => {
194 for i in ti..=text.len() {
196 if Self::like_match_recursive(text, i, pattern, pi + 1) {
197 return true;
198 }
199 }
200 false
201 }
202 '_' => {
203 if ti < text.len() {
205 Self::like_match_recursive(text, ti + 1, pattern, pi + 1)
206 } else {
207 false
208 }
209 }
210 c => {
211 if ti < text.len() && text[ti].eq_ignore_ascii_case(&c) {
213 Self::like_match_recursive(text, ti + 1, pattern, pi + 1)
214 } else {
215 false
216 }
217 }
218 }
219 }
220}