1use anyhow::{anyhow, Result};
2
3use super::{ArgCount, FunctionCategory, FunctionSignature, SqlFunction};
4use crate::data::datatable::DataValue;
5
6pub trait MethodFunction: SqlFunction {
9 fn handles_method(&self, method_name: &str) -> bool;
11
12 fn method_name(&self) -> &'static str;
14
15 fn evaluate_method(&self, receiver: &DataValue, args: &[DataValue]) -> Result<DataValue> {
17 let mut full_args = vec![receiver.clone()];
19 full_args.extend_from_slice(args);
20 self.evaluate(&full_args)
21 }
22}
23
24pub struct ToUpperMethod;
26
27impl SqlFunction for ToUpperMethod {
28 fn signature(&self) -> FunctionSignature {
29 FunctionSignature {
30 name: "TOUPPER",
31 category: FunctionCategory::String,
32 arg_count: ArgCount::Fixed(1),
33 description: "Converts string to uppercase",
34 returns: "STRING",
35 examples: vec![
36 "SELECT name.ToUpper() FROM users",
37 "SELECT TOUPPER(name) FROM users",
38 ],
39 }
40 }
41
42 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
43 self.validate_args(args)?;
44
45 match &args[0] {
46 DataValue::String(s) => Ok(DataValue::String(s.to_uppercase())),
47 DataValue::InternedString(s) => Ok(DataValue::String(s.to_uppercase())),
48 DataValue::Null => Ok(DataValue::Null),
49 _ => Err(anyhow!("ToUpper expects a string argument")),
50 }
51 }
52}
53
54impl MethodFunction for ToUpperMethod {
55 fn handles_method(&self, method_name: &str) -> bool {
56 method_name.eq_ignore_ascii_case("ToUpper")
57 || method_name.eq_ignore_ascii_case("ToUpperCase")
58 }
59
60 fn method_name(&self) -> &'static str {
61 "ToUpper"
62 }
63}
64
65pub struct ToLowerMethod;
67
68impl SqlFunction for ToLowerMethod {
69 fn signature(&self) -> FunctionSignature {
70 FunctionSignature {
71 name: "TOLOWER",
72 category: FunctionCategory::String,
73 arg_count: ArgCount::Fixed(1),
74 description: "Converts string to lowercase",
75 returns: "STRING",
76 examples: vec![
77 "SELECT name.ToLower() FROM users",
78 "SELECT TOLOWER(name) FROM users",
79 ],
80 }
81 }
82
83 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
84 self.validate_args(args)?;
85
86 match &args[0] {
87 DataValue::String(s) => Ok(DataValue::String(s.to_lowercase())),
88 DataValue::InternedString(s) => Ok(DataValue::String(s.to_lowercase())),
89 DataValue::Null => Ok(DataValue::Null),
90 _ => Err(anyhow!("ToLower expects a string argument")),
91 }
92 }
93}
94
95impl MethodFunction for ToLowerMethod {
96 fn handles_method(&self, method_name: &str) -> bool {
97 method_name.eq_ignore_ascii_case("ToLower")
98 || method_name.eq_ignore_ascii_case("ToLowerCase")
99 }
100
101 fn method_name(&self) -> &'static str {
102 "ToLower"
103 }
104}
105
106pub struct TrimMethod;
108
109impl SqlFunction for TrimMethod {
110 fn signature(&self) -> FunctionSignature {
111 FunctionSignature {
112 name: "TRIM",
113 category: FunctionCategory::String,
114 arg_count: ArgCount::Fixed(1),
115 description: "Removes leading and trailing whitespace",
116 returns: "STRING",
117 examples: vec![
118 "SELECT name.Trim() FROM users",
119 "SELECT TRIM(name) FROM users",
120 ],
121 }
122 }
123
124 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
125 self.validate_args(args)?;
126
127 match &args[0] {
128 DataValue::String(s) => Ok(DataValue::String(s.trim().to_string())),
129 DataValue::InternedString(s) => Ok(DataValue::String(s.trim().to_string())),
130 DataValue::Null => Ok(DataValue::Null),
131 _ => Err(anyhow!("Trim expects a string argument")),
132 }
133 }
134}
135
136impl MethodFunction for TrimMethod {
137 fn handles_method(&self, method_name: &str) -> bool {
138 method_name.eq_ignore_ascii_case("Trim")
139 }
140
141 fn method_name(&self) -> &'static str {
142 "Trim"
143 }
144}
145
146pub struct TrimStartMethod;
148
149impl SqlFunction for TrimStartMethod {
150 fn signature(&self) -> FunctionSignature {
151 FunctionSignature {
152 name: "TRIMSTART",
153 category: FunctionCategory::String,
154 arg_count: ArgCount::Fixed(1),
155 description: "Removes leading whitespace",
156 returns: "STRING",
157 examples: vec![
158 "SELECT name.TrimStart() FROM users",
159 "SELECT TRIMSTART(name) FROM users",
160 ],
161 }
162 }
163
164 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
165 self.validate_args(args)?;
166
167 match &args[0] {
168 DataValue::String(s) => Ok(DataValue::String(s.trim_start().to_string())),
169 DataValue::InternedString(s) => Ok(DataValue::String(s.trim_start().to_string())),
170 DataValue::Null => Ok(DataValue::Null),
171 _ => Err(anyhow!("TrimStart expects a string argument")),
172 }
173 }
174}
175
176impl MethodFunction for TrimStartMethod {
177 fn handles_method(&self, method_name: &str) -> bool {
178 method_name.eq_ignore_ascii_case("TrimStart")
179 }
180
181 fn method_name(&self) -> &'static str {
182 "TrimStart"
183 }
184}
185
186pub struct TrimEndMethod;
188
189impl SqlFunction for TrimEndMethod {
190 fn signature(&self) -> FunctionSignature {
191 FunctionSignature {
192 name: "TRIMEND",
193 category: FunctionCategory::String,
194 arg_count: ArgCount::Fixed(1),
195 description: "Removes trailing whitespace",
196 returns: "STRING",
197 examples: vec![
198 "SELECT name.TrimEnd() FROM users",
199 "SELECT TRIMEND(name) FROM users",
200 ],
201 }
202 }
203
204 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
205 self.validate_args(args)?;
206
207 match &args[0] {
208 DataValue::String(s) => Ok(DataValue::String(s.trim_end().to_string())),
209 DataValue::InternedString(s) => Ok(DataValue::String(s.trim_end().to_string())),
210 DataValue::Null => Ok(DataValue::Null),
211 _ => Err(anyhow!("TrimEnd expects a string argument")),
212 }
213 }
214}
215
216impl MethodFunction for TrimEndMethod {
217 fn handles_method(&self, method_name: &str) -> bool {
218 method_name.eq_ignore_ascii_case("TrimEnd")
219 }
220
221 fn method_name(&self) -> &'static str {
222 "TrimEnd"
223 }
224}
225
226pub struct LengthMethod;
228
229impl SqlFunction for LengthMethod {
230 fn signature(&self) -> FunctionSignature {
231 FunctionSignature {
232 name: "LENGTH",
233 category: FunctionCategory::String,
234 arg_count: ArgCount::Fixed(1),
235 description: "Returns the length of a string",
236 returns: "INTEGER",
237 examples: vec![
238 "SELECT name.Length() FROM users",
239 "SELECT LENGTH(name) FROM users",
240 ],
241 }
242 }
243
244 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
245 self.validate_args(args)?;
246
247 match &args[0] {
248 DataValue::String(s) => Ok(DataValue::Integer(s.len() as i64)),
249 DataValue::InternedString(s) => Ok(DataValue::Integer(s.len() as i64)),
250 DataValue::Null => Ok(DataValue::Null),
251 _ => Err(anyhow!("Length expects a string argument")),
252 }
253 }
254}
255
256impl MethodFunction for LengthMethod {
257 fn handles_method(&self, method_name: &str) -> bool {
258 method_name.eq_ignore_ascii_case("Length") || method_name.eq_ignore_ascii_case("Len")
259 }
260
261 fn method_name(&self) -> &'static str {
262 "Length"
263 }
264}
265
266pub struct ContainsMethod;
268
269impl SqlFunction for ContainsMethod {
270 fn signature(&self) -> FunctionSignature {
271 FunctionSignature {
272 name: "CONTAINS",
273 category: FunctionCategory::String,
274 arg_count: ArgCount::Fixed(2),
275 description: "Checks if string contains substring",
276 returns: "BOOLEAN",
277 examples: vec![
278 "SELECT * FROM users WHERE name.Contains('john')",
279 "SELECT CONTAINS(name, 'john') FROM users",
280 ],
281 }
282 }
283
284 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
285 self.validate_args(args)?;
286
287 let haystack = match &args[0] {
288 DataValue::String(s) => s.as_str(),
289 DataValue::InternedString(s) => s.as_str(),
290 DataValue::Null => return Ok(DataValue::Boolean(false)),
291 _ => return Err(anyhow!("Contains expects string arguments")),
292 };
293
294 let needle = match &args[1] {
295 DataValue::String(s) => s.as_str(),
296 DataValue::InternedString(s) => s.as_str(),
297 DataValue::Null => return Ok(DataValue::Boolean(false)),
298 _ => return Err(anyhow!("Contains expects string arguments")),
299 };
300
301 Ok(DataValue::Boolean(haystack.contains(needle)))
302 }
303}
304
305impl MethodFunction for ContainsMethod {
306 fn handles_method(&self, method_name: &str) -> bool {
307 method_name.eq_ignore_ascii_case("Contains")
308 }
309
310 fn method_name(&self) -> &'static str {
311 "Contains"
312 }
313}
314
315pub struct StartsWithMethod;
317
318impl SqlFunction for StartsWithMethod {
319 fn signature(&self) -> FunctionSignature {
320 FunctionSignature {
321 name: "STARTSWITH",
322 category: FunctionCategory::String,
323 arg_count: ArgCount::Fixed(2),
324 description: "Checks if string starts with prefix",
325 returns: "BOOLEAN",
326 examples: vec![
327 "SELECT * FROM users WHERE name.StartsWith('John')",
328 "SELECT STARTSWITH(name, 'John') FROM users",
329 ],
330 }
331 }
332
333 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
334 self.validate_args(args)?;
335
336 let string = match &args[0] {
337 DataValue::String(s) => s.as_str(),
338 DataValue::InternedString(s) => s.as_str(),
339 DataValue::Null => return Ok(DataValue::Boolean(false)),
340 _ => return Err(anyhow!("StartsWith expects string arguments")),
341 };
342
343 let prefix = match &args[1] {
344 DataValue::String(s) => s.as_str(),
345 DataValue::InternedString(s) => s.as_str(),
346 DataValue::Null => return Ok(DataValue::Boolean(false)),
347 _ => return Err(anyhow!("StartsWith expects string arguments")),
348 };
349
350 Ok(DataValue::Boolean(string.starts_with(prefix)))
351 }
352}
353
354impl MethodFunction for StartsWithMethod {
355 fn handles_method(&self, method_name: &str) -> bool {
356 method_name.eq_ignore_ascii_case("StartsWith")
357 }
358
359 fn method_name(&self) -> &'static str {
360 "StartsWith"
361 }
362}
363
364pub struct EndsWithMethod;
366
367impl SqlFunction for EndsWithMethod {
368 fn signature(&self) -> FunctionSignature {
369 FunctionSignature {
370 name: "ENDSWITH",
371 category: FunctionCategory::String,
372 arg_count: ArgCount::Fixed(2),
373 description: "Checks if string ends with suffix",
374 returns: "BOOLEAN",
375 examples: vec![
376 "SELECT * FROM users WHERE email.EndsWith('.com')",
377 "SELECT ENDSWITH(email, '.com') FROM users",
378 ],
379 }
380 }
381
382 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
383 self.validate_args(args)?;
384
385 let string = match &args[0] {
386 DataValue::String(s) => s.as_str(),
387 DataValue::InternedString(s) => s.as_str(),
388 DataValue::Null => return Ok(DataValue::Boolean(false)),
389 _ => return Err(anyhow!("EndsWith expects string arguments")),
390 };
391
392 let suffix = match &args[1] {
393 DataValue::String(s) => s.as_str(),
394 DataValue::InternedString(s) => s.as_str(),
395 DataValue::Null => return Ok(DataValue::Boolean(false)),
396 _ => return Err(anyhow!("EndsWith expects string arguments")),
397 };
398
399 Ok(DataValue::Boolean(string.ends_with(suffix)))
400 }
401}
402
403impl MethodFunction for EndsWithMethod {
404 fn handles_method(&self, method_name: &str) -> bool {
405 method_name.eq_ignore_ascii_case("EndsWith")
406 }
407
408 fn method_name(&self) -> &'static str {
409 "EndsWith"
410 }
411}
412
413pub struct SubstringMethod;
415
416impl SqlFunction for SubstringMethod {
417 fn signature(&self) -> FunctionSignature {
418 FunctionSignature {
419 name: "SUBSTRING",
420 category: FunctionCategory::String,
421 arg_count: ArgCount::Range(2, 3),
422 description: "Extracts substring from string",
423 returns: "STRING",
424 examples: vec![
425 "SELECT name.Substring(0, 5) FROM users",
426 "SELECT SUBSTRING(name, 0, 5) FROM users",
427 ],
428 }
429 }
430
431 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
432 if args.len() < 2 || args.len() > 3 {
433 return Err(anyhow!("Substring expects 2 or 3 arguments"));
434 }
435
436 let string = match &args[0] {
437 DataValue::String(s) => s.as_str(),
438 DataValue::InternedString(s) => s.as_str(),
439 DataValue::Null => return Ok(DataValue::Null),
440 _ => return Err(anyhow!("Substring expects a string as first argument")),
441 };
442
443 let start = match &args[1] {
444 DataValue::Integer(i) => *i as usize,
445 _ => return Err(anyhow!("Substring expects integer start position")),
446 };
447
448 let result = if args.len() == 3 {
449 let length = match &args[2] {
450 DataValue::Integer(i) => *i as usize,
451 _ => return Err(anyhow!("Substring expects integer length")),
452 };
453
454 let end = (start + length).min(string.len());
455 string.chars().skip(start).take(end - start).collect()
456 } else {
457 string.chars().skip(start).collect()
458 };
459
460 Ok(DataValue::String(result))
461 }
462}
463
464impl MethodFunction for SubstringMethod {
465 fn handles_method(&self, method_name: &str) -> bool {
466 method_name.eq_ignore_ascii_case("Substring") || method_name.eq_ignore_ascii_case("Substr")
467 }
468
469 fn method_name(&self) -> &'static str {
470 "Substring"
471 }
472}
473
474pub struct ReplaceMethod;
476
477impl SqlFunction for ReplaceMethod {
478 fn signature(&self) -> FunctionSignature {
479 FunctionSignature {
480 name: "REPLACE",
481 category: FunctionCategory::String,
482 arg_count: ArgCount::Fixed(3),
483 description: "Replaces all occurrences of a substring",
484 returns: "STRING",
485 examples: vec![
486 "SELECT name.Replace('John', 'Jane') FROM users",
487 "SELECT REPLACE(name, 'John', 'Jane') FROM users",
488 ],
489 }
490 }
491
492 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
493 self.validate_args(args)?;
494
495 let string = match &args[0] {
496 DataValue::String(s) => s.as_str(),
497 DataValue::InternedString(s) => s.as_str(),
498 DataValue::Null => return Ok(DataValue::Null),
499 _ => return Err(anyhow!("Replace expects string arguments")),
500 };
501
502 let from = match &args[1] {
503 DataValue::String(s) => s.as_str(),
504 DataValue::InternedString(s) => s.as_str(),
505 _ => return Err(anyhow!("Replace expects string arguments")),
506 };
507
508 let to = match &args[2] {
509 DataValue::String(s) => s.as_str(),
510 DataValue::InternedString(s) => s.as_str(),
511 _ => return Err(anyhow!("Replace expects string arguments")),
512 };
513
514 Ok(DataValue::String(string.replace(from, to)))
515 }
516}
517
518impl MethodFunction for ReplaceMethod {
519 fn handles_method(&self, method_name: &str) -> bool {
520 method_name.eq_ignore_ascii_case("Replace")
521 }
522
523 fn method_name(&self) -> &'static str {
524 "Replace"
525 }
526}
527
528pub struct MidFunction;
530
531impl SqlFunction for MidFunction {
532 fn signature(&self) -> FunctionSignature {
533 FunctionSignature {
534 name: "MID",
535 category: FunctionCategory::String,
536 arg_count: ArgCount::Fixed(3),
537 description: "Extract substring from text (1-based indexing)",
538 returns: "STRING",
539 examples: vec![
540 "SELECT MID('Hello', 1, 3)", "SELECT MID('World', 2, 3)", "SELECT MID(name, 1, 5) FROM table",
543 ],
544 }
545 }
546
547 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
548 self.validate_args(args)?;
549
550 let text = match &args[0] {
552 DataValue::String(s) => s.clone(),
553 DataValue::InternedString(s) => s.to_string(),
554 DataValue::Integer(n) => n.to_string(),
555 DataValue::Float(f) => f.to_string(),
556 DataValue::Null => String::new(),
557 _ => return Err(anyhow!("MID first argument must be convertible to text")),
558 };
559
560 let start_pos = match &args[1] {
562 DataValue::Integer(n) => *n,
563 DataValue::Float(f) => *f as i64,
564 _ => return Err(anyhow!("MID start position must be a number")),
565 };
566
567 let length = match &args[2] {
569 DataValue::Integer(n) => *n,
570 DataValue::Float(f) => *f as i64,
571 _ => return Err(anyhow!("MID length must be a number")),
572 };
573
574 if start_pos < 1 {
576 return Err(anyhow!("MID start position must be >= 1"));
577 }
578 if length < 0 {
579 return Err(anyhow!("MID length must be >= 0"));
580 }
581
582 let start_idx = (start_pos - 1) as usize;
584 let chars: Vec<char> = text.chars().collect();
585
586 if start_idx >= chars.len() {
588 return Ok(DataValue::String(String::new()));
589 }
590
591 let end_idx = std::cmp::min(start_idx + length as usize, chars.len());
593 let result: String = chars[start_idx..end_idx].iter().collect();
594
595 Ok(DataValue::String(result))
596 }
597}
598
599pub struct UpperFunction;
601
602impl SqlFunction for UpperFunction {
603 fn signature(&self) -> FunctionSignature {
604 FunctionSignature {
605 name: "UPPER",
606 category: FunctionCategory::String,
607 arg_count: ArgCount::Fixed(1),
608 description: "Convert string to uppercase",
609 returns: "STRING",
610 examples: vec![
611 "SELECT UPPER('hello')", "SELECT UPPER(name) FROM table",
613 ],
614 }
615 }
616
617 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
618 self.validate_args(args)?;
619
620 match &args[0] {
621 DataValue::String(s) => Ok(DataValue::String(s.to_uppercase())),
622 DataValue::InternedString(s) => Ok(DataValue::String(s.to_uppercase())),
623 DataValue::Null => Ok(DataValue::Null),
624 _ => Err(anyhow!("UPPER expects a string argument")),
625 }
626 }
627}
628
629pub struct LowerFunction;
631
632impl SqlFunction for LowerFunction {
633 fn signature(&self) -> FunctionSignature {
634 FunctionSignature {
635 name: "LOWER",
636 category: FunctionCategory::String,
637 arg_count: ArgCount::Fixed(1),
638 description: "Convert string to lowercase",
639 returns: "STRING",
640 examples: vec![
641 "SELECT LOWER('HELLO')", "SELECT LOWER(name) FROM table",
643 ],
644 }
645 }
646
647 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
648 self.validate_args(args)?;
649
650 match &args[0] {
651 DataValue::String(s) => Ok(DataValue::String(s.to_lowercase())),
652 DataValue::InternedString(s) => Ok(DataValue::String(s.to_lowercase())),
653 DataValue::Null => Ok(DataValue::Null),
654 _ => Err(anyhow!("LOWER expects a string argument")),
655 }
656 }
657}
658
659pub struct TrimFunction;
661
662impl SqlFunction for TrimFunction {
663 fn signature(&self) -> FunctionSignature {
664 FunctionSignature {
665 name: "TRIM",
666 category: FunctionCategory::String,
667 arg_count: ArgCount::Fixed(1),
668 description: "Remove leading and trailing whitespace",
669 returns: "STRING",
670 examples: vec![
671 "SELECT TRIM(' hello ')", "SELECT TRIM(description) FROM table",
673 ],
674 }
675 }
676
677 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
678 self.validate_args(args)?;
679
680 match &args[0] {
681 DataValue::String(s) => Ok(DataValue::String(s.trim().to_string())),
682 DataValue::InternedString(s) => Ok(DataValue::String(s.trim().to_string())),
683 DataValue::Null => Ok(DataValue::Null),
684 _ => Err(anyhow!("TRIM expects a string argument")),
685 }
686 }
687}
688
689pub struct TextJoinFunction;
691
692impl SqlFunction for TextJoinFunction {
693 fn signature(&self) -> FunctionSignature {
694 FunctionSignature {
695 name: "TEXTJOIN",
696 category: FunctionCategory::String,
697 arg_count: ArgCount::Variadic,
698 description: "Join multiple text values with a delimiter",
699 returns: "STRING",
700 examples: vec![
701 "SELECT TEXTJOIN(',', 1, 'a', 'b', 'c')", "SELECT TEXTJOIN(' - ', 1, name, city) FROM table",
703 "SELECT TEXTJOIN('|', 0, col1, col2, col3) FROM table",
704 ],
705 }
706 }
707
708 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
709 if args.len() < 3 {
710 return Err(anyhow!("TEXTJOIN requires at least 3 arguments: delimiter, ignore_empty, text1, [text2, ...]"));
711 }
712
713 let delimiter = match &args[0] {
715 DataValue::String(s) => s.clone(),
716 DataValue::InternedString(s) => s.to_string(),
717 DataValue::Integer(n) => n.to_string(),
718 DataValue::Float(f) => f.to_string(),
719 DataValue::Boolean(b) => b.to_string(),
720 DataValue::Null => String::new(),
721 _ => String::new(),
722 };
723
724 let ignore_empty = match &args[1] {
726 DataValue::Integer(n) => *n != 0,
727 DataValue::Float(f) => *f != 0.0,
728 DataValue::Boolean(b) => *b,
729 DataValue::String(s) => !s.is_empty() && s != "0" && s.to_lowercase() != "false",
730 DataValue::InternedString(s) => {
731 !s.is_empty() && s.as_str() != "0" && s.to_lowercase() != "false"
732 }
733 DataValue::Null => false,
734 _ => true,
735 };
736
737 let mut values = Vec::new();
739 for i in 2..args.len() {
740 let string_value = match &args[i] {
741 DataValue::String(s) => Some(s.clone()),
742 DataValue::InternedString(s) => Some(s.to_string()),
743 DataValue::Integer(n) => Some(n.to_string()),
744 DataValue::Float(f) => Some(f.to_string()),
745 DataValue::Boolean(b) => Some(b.to_string()),
746 DataValue::DateTime(dt) => Some(dt.clone()),
747 DataValue::Null => {
748 if ignore_empty {
749 None
750 } else {
751 Some(String::new())
752 }
753 }
754 };
755
756 if let Some(s) = string_value {
757 if !ignore_empty || !s.is_empty() {
758 values.push(s);
759 }
760 }
761 }
762
763 Ok(DataValue::String(values.join(&delimiter)))
764 }
765}
766
767pub struct EditDistanceFunction;
769
770impl EditDistanceFunction {
771 #[must_use]
773 pub fn calculate_edit_distance(s1: &str, s2: &str) -> usize {
774 let len1 = s1.len();
775 let len2 = s2.len();
776 let mut matrix = vec![vec![0; len2 + 1]; len1 + 1];
777
778 for i in 0..=len1 {
779 matrix[i][0] = i;
780 }
781 for j in 0..=len2 {
782 matrix[0][j] = j;
783 }
784
785 for (i, c1) in s1.chars().enumerate() {
786 for (j, c2) in s2.chars().enumerate() {
787 let cost = usize::from(c1 != c2);
788 matrix[i + 1][j + 1] = std::cmp::min(
789 matrix[i][j + 1] + 1, std::cmp::min(
791 matrix[i + 1][j] + 1, matrix[i][j] + cost, ),
794 );
795 }
796 }
797
798 matrix[len1][len2]
799 }
800}
801
802impl SqlFunction for EditDistanceFunction {
803 fn signature(&self) -> FunctionSignature {
804 FunctionSignature {
805 name: "EDIT_DISTANCE",
806 category: FunctionCategory::String,
807 arg_count: ArgCount::Fixed(2),
808 description: "Calculate the Levenshtein edit distance between two strings",
809 returns: "INTEGER",
810 examples: vec![
811 "SELECT EDIT_DISTANCE('kitten', 'sitting')",
812 "SELECT EDIT_DISTANCE(name, 'John') FROM users",
813 "SELECT * FROM users WHERE EDIT_DISTANCE(name, 'Smith') <= 2",
814 ],
815 }
816 }
817
818 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
819 self.validate_args(args)?;
820
821 let s1 = match &args[0] {
822 DataValue::String(s) => s.clone(),
823 DataValue::InternedString(s) => s.to_string(),
824 DataValue::Null => return Ok(DataValue::Null),
825 _ => return Err(anyhow!("EDIT_DISTANCE expects string arguments")),
826 };
827
828 let s2 = match &args[1] {
829 DataValue::String(s) => s.clone(),
830 DataValue::InternedString(s) => s.to_string(),
831 DataValue::Null => return Ok(DataValue::Null),
832 _ => return Err(anyhow!("EDIT_DISTANCE expects string arguments")),
833 };
834
835 let distance = Self::calculate_edit_distance(&s1, &s2);
836 Ok(DataValue::Integer(distance as i64))
837 }
838}
839
840pub struct FrequencyFunction;
842
843impl SqlFunction for FrequencyFunction {
844 fn signature(&self) -> FunctionSignature {
845 FunctionSignature {
846 name: "FREQUENCY",
847 category: FunctionCategory::String,
848 arg_count: ArgCount::Fixed(2),
849 description: "Count occurrences of a substring within a string",
850 returns: "INTEGER",
851 examples: vec![
852 "SELECT FREQUENCY('hello world', 'o')", "SELECT FREQUENCY('mississippi', 'ss')", "SELECT FREQUENCY(text_column, 'error') FROM logs",
855 "SELECT name, FREQUENCY(name, 'a') as a_count FROM users",
856 ],
857 }
858 }
859
860 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
861 self.validate_args(args)?;
862
863 let text = match &args[0] {
865 DataValue::String(s) => s.clone(),
866 DataValue::InternedString(s) => s.to_string(),
867 DataValue::Null => return Ok(DataValue::Integer(0)),
868 _ => return Err(anyhow!("FREQUENCY expects string as first argument")),
869 };
870
871 let search = match &args[1] {
873 DataValue::String(s) => s.clone(),
874 DataValue::InternedString(s) => s.to_string(),
875 DataValue::Null => return Ok(DataValue::Integer(0)),
876 _ => return Err(anyhow!("FREQUENCY expects string as second argument")),
877 };
878
879 if search.is_empty() {
881 return Ok(DataValue::Integer(0));
882 }
883
884 let count = text.matches(&search).count();
886 Ok(DataValue::Integer(count as i64))
887 }
888}
889
890pub struct IndexOfMethod;
892
893impl SqlFunction for IndexOfMethod {
894 fn signature(&self) -> FunctionSignature {
895 FunctionSignature {
896 name: "INDEXOF",
897 category: FunctionCategory::String,
898 arg_count: ArgCount::Fixed(2),
899 description: "Returns the position of the first occurrence of a substring (0-based)",
900 returns: "INTEGER",
901 examples: vec![
902 "SELECT email.IndexOf('@') FROM users",
903 "SELECT INDEXOF(email, '@') FROM users",
904 ],
905 }
906 }
907
908 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
909 self.validate_args(args)?;
910
911 let string = match &args[0] {
912 DataValue::String(s) => s.as_str(),
913 DataValue::InternedString(s) => s.as_str(),
914 DataValue::Null => return Ok(DataValue::Null),
915 _ => return Err(anyhow!("IndexOf expects string arguments")),
916 };
917
918 let substring = match &args[1] {
919 DataValue::String(s) => s.as_str(),
920 DataValue::InternedString(s) => s.as_str(),
921 DataValue::Null => return Ok(DataValue::Null),
922 _ => return Err(anyhow!("IndexOf expects string arguments")),
923 };
924
925 match string.find(substring) {
926 Some(pos) => Ok(DataValue::Integer(pos as i64)),
927 None => Ok(DataValue::Integer(-1)), }
929 }
930}
931
932impl MethodFunction for IndexOfMethod {
933 fn handles_method(&self, method_name: &str) -> bool {
934 method_name.eq_ignore_ascii_case("IndexOf")
935 }
936
937 fn method_name(&self) -> &'static str {
938 "IndexOf"
939 }
940}
941
942pub struct InstrFunction;
945
946impl SqlFunction for InstrFunction {
947 fn signature(&self) -> FunctionSignature {
948 FunctionSignature {
949 name: "INSTR",
950 category: FunctionCategory::String,
951 arg_count: ArgCount::Fixed(2),
952 description: "Returns the position of the first occurrence of a substring (1-based, SQL standard)",
953 returns: "INTEGER",
954 examples: vec![
955 "SELECT INSTR(email, '@') FROM users",
956 "SELECT SUBSTRING(email, INSTR(email, '@') + 1) FROM users",
957 ],
958 }
959 }
960
961 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
962 self.validate_args(args)?;
963
964 let string = match &args[0] {
965 DataValue::String(s) => s.as_str(),
966 DataValue::InternedString(s) => s.as_str(),
967 DataValue::Null => return Ok(DataValue::Null),
968 _ => return Err(anyhow!("INSTR expects string arguments")),
969 };
970
971 let substring = match &args[1] {
972 DataValue::String(s) => s.as_str(),
973 DataValue::InternedString(s) => s.as_str(),
974 DataValue::Null => return Ok(DataValue::Null),
975 _ => return Err(anyhow!("INSTR expects string arguments")),
976 };
977
978 match string.find(substring) {
979 Some(pos) => Ok(DataValue::Integer((pos + 1) as i64)), None => Ok(DataValue::Integer(0)), }
982 }
983}
984
985pub struct LeftFunction;
987
988impl SqlFunction for LeftFunction {
989 fn signature(&self) -> FunctionSignature {
990 FunctionSignature {
991 name: "LEFT",
992 category: FunctionCategory::String,
993 arg_count: ArgCount::Fixed(2),
994 description: "Returns leftmost n characters from string",
995 returns: "STRING",
996 examples: vec![
997 "SELECT LEFT(email, 5) FROM users",
998 "SELECT LEFT('hello@world', INSTR('hello@world', '@') - 1)",
999 ],
1000 }
1001 }
1002
1003 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
1004 self.validate_args(args)?;
1005
1006 let string = match &args[0] {
1007 DataValue::String(s) => s.as_str(),
1008 DataValue::InternedString(s) => s.as_str(),
1009 DataValue::Null => return Ok(DataValue::Null),
1010 _ => return Err(anyhow!("LEFT expects a string as first argument")),
1011 };
1012
1013 let length = match &args[1] {
1014 DataValue::Integer(n) => *n as usize,
1015 DataValue::Float(f) => *f as usize,
1016 DataValue::Null => return Ok(DataValue::Null),
1017 _ => return Err(anyhow!("LEFT expects a number as second argument")),
1018 };
1019
1020 let result = if length >= string.len() {
1021 string.to_string()
1022 } else {
1023 string.chars().take(length).collect()
1024 };
1025
1026 Ok(DataValue::String(result))
1027 }
1028}
1029
1030pub struct RightFunction;
1032
1033impl SqlFunction for RightFunction {
1034 fn signature(&self) -> FunctionSignature {
1035 FunctionSignature {
1036 name: "RIGHT",
1037 category: FunctionCategory::String,
1038 arg_count: ArgCount::Fixed(2),
1039 description: "Returns rightmost n characters from string",
1040 returns: "STRING",
1041 examples: vec![
1042 "SELECT RIGHT(filename, 4) FROM files", "SELECT RIGHT(email, LENGTH(email) - INSTR(email, '@'))", ],
1045 }
1046 }
1047
1048 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
1049 self.validate_args(args)?;
1050
1051 let string = match &args[0] {
1052 DataValue::String(s) => s.as_str(),
1053 DataValue::InternedString(s) => s.as_str(),
1054 DataValue::Null => return Ok(DataValue::Null),
1055 _ => return Err(anyhow!("RIGHT expects a string as first argument")),
1056 };
1057
1058 let length = match &args[1] {
1059 DataValue::Integer(n) => *n as usize,
1060 DataValue::Float(f) => *f as usize,
1061 DataValue::Null => return Ok(DataValue::Null),
1062 _ => return Err(anyhow!("RIGHT expects a number as second argument")),
1063 };
1064
1065 let chars: Vec<char> = string.chars().collect();
1066 let start = if length >= chars.len() {
1067 0
1068 } else {
1069 chars.len() - length
1070 };
1071
1072 let result: String = chars[start..].iter().collect();
1073 Ok(DataValue::String(result))
1074 }
1075}
1076
1077pub struct SubstringBeforeFunction;
1079
1080impl SqlFunction for SubstringBeforeFunction {
1081 fn signature(&self) -> FunctionSignature {
1082 FunctionSignature {
1083 name: "SUBSTRING_BEFORE",
1084 category: FunctionCategory::String,
1085 arg_count: ArgCount::Range(2, 3),
1086 description: "Returns substring before the first (or nth) occurrence of delimiter",
1087 returns: "STRING",
1088 examples: vec![
1089 "SELECT SUBSTRING_BEFORE(email, '@') FROM users", "SELECT SUBSTRING_BEFORE('a.b.c.d', '.', 2)", ],
1092 }
1093 }
1094
1095 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
1096 if args.len() < 2 || args.len() > 3 {
1097 return Err(anyhow!("SUBSTRING_BEFORE expects 2 or 3 arguments"));
1098 }
1099
1100 let string = match &args[0] {
1101 DataValue::String(s) => s.as_str(),
1102 DataValue::InternedString(s) => s.as_str(),
1103 DataValue::Null => return Ok(DataValue::Null),
1104 _ => {
1105 return Err(anyhow!(
1106 "SUBSTRING_BEFORE expects a string as first argument"
1107 ))
1108 }
1109 };
1110
1111 let delimiter = match &args[1] {
1112 DataValue::String(s) => s.as_str(),
1113 DataValue::InternedString(s) => s.as_str(),
1114 DataValue::Null => return Ok(DataValue::Null),
1115 _ => return Err(anyhow!("SUBSTRING_BEFORE expects a string delimiter")),
1116 };
1117
1118 let occurrence = if args.len() == 3 {
1119 match &args[2] {
1120 DataValue::Integer(n) => *n as usize,
1121 DataValue::Float(f) => *f as usize,
1122 DataValue::Null => 1,
1123 _ => return Err(anyhow!("SUBSTRING_BEFORE expects a number for occurrence")),
1124 }
1125 } else {
1126 1
1127 };
1128
1129 if occurrence == 0 {
1130 return Ok(DataValue::String(String::new()));
1131 }
1132
1133 let mut count = 0;
1135 let mut last_pos = 0;
1136 for (i, _) in string.match_indices(delimiter) {
1137 count += 1;
1138 if count == occurrence {
1139 return Ok(DataValue::String(string[..i].to_string()));
1140 }
1141 last_pos = i;
1142 }
1143
1144 Ok(DataValue::String(String::new()))
1146 }
1147}
1148
1149pub struct SubstringAfterFunction;
1151
1152impl SqlFunction for SubstringAfterFunction {
1153 fn signature(&self) -> FunctionSignature {
1154 FunctionSignature {
1155 name: "SUBSTRING_AFTER",
1156 category: FunctionCategory::String,
1157 arg_count: ArgCount::Range(2, 3),
1158 description: "Returns substring after the first (or nth) occurrence of delimiter",
1159 returns: "STRING",
1160 examples: vec![
1161 "SELECT SUBSTRING_AFTER(email, '@') FROM users", "SELECT SUBSTRING_AFTER('a.b.c.d', '.', 2)", ],
1164 }
1165 }
1166
1167 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
1168 if args.len() < 2 || args.len() > 3 {
1169 return Err(anyhow!("SUBSTRING_AFTER expects 2 or 3 arguments"));
1170 }
1171
1172 let string = match &args[0] {
1173 DataValue::String(s) => s.as_str(),
1174 DataValue::InternedString(s) => s.as_str(),
1175 DataValue::Null => return Ok(DataValue::Null),
1176 _ => {
1177 return Err(anyhow!(
1178 "SUBSTRING_AFTER expects a string as first argument"
1179 ))
1180 }
1181 };
1182
1183 let delimiter = match &args[1] {
1184 DataValue::String(s) => s.as_str(),
1185 DataValue::InternedString(s) => s.as_str(),
1186 DataValue::Null => return Ok(DataValue::Null),
1187 _ => return Err(anyhow!("SUBSTRING_AFTER expects a string delimiter")),
1188 };
1189
1190 let occurrence = if args.len() == 3 {
1191 match &args[2] {
1192 DataValue::Integer(n) => *n as usize,
1193 DataValue::Float(f) => *f as usize,
1194 DataValue::Null => 1,
1195 _ => return Err(anyhow!("SUBSTRING_AFTER expects a number for occurrence")),
1196 }
1197 } else {
1198 1
1199 };
1200
1201 if occurrence == 0 {
1202 return Ok(DataValue::String(string.to_string()));
1203 }
1204
1205 let mut count = 0;
1207 for (i, _) in string.match_indices(delimiter) {
1208 count += 1;
1209 if count == occurrence {
1210 let start = i + delimiter.len();
1211 if start < string.len() {
1212 return Ok(DataValue::String(string[start..].to_string()));
1213 } else {
1214 return Ok(DataValue::String(String::new()));
1215 }
1216 }
1217 }
1218
1219 Ok(DataValue::String(String::new()))
1221 }
1222}
1223
1224pub struct SplitPartFunction;
1226
1227impl SqlFunction for SplitPartFunction {
1228 fn signature(&self) -> FunctionSignature {
1229 FunctionSignature {
1230 name: "SPLIT_PART",
1231 category: FunctionCategory::String,
1232 arg_count: ArgCount::Fixed(3),
1233 description: "Returns the nth part of a string split by delimiter (1-based index)",
1234 returns: "STRING",
1235 examples: vec![
1236 "SELECT SPLIT_PART('a.b.c.d', '.', 2)", "SELECT SPLIT_PART(email, '@', 1) FROM users", ],
1239 }
1240 }
1241
1242 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
1243 self.validate_args(args)?;
1244
1245 let string = match &args[0] {
1246 DataValue::String(s) => s.as_str(),
1247 DataValue::InternedString(s) => s.as_str(),
1248 DataValue::Null => return Ok(DataValue::Null),
1249 _ => return Err(anyhow!("SPLIT_PART expects a string as first argument")),
1250 };
1251
1252 let delimiter = match &args[1] {
1253 DataValue::String(s) => s.as_str(),
1254 DataValue::InternedString(s) => s.as_str(),
1255 DataValue::Null => return Ok(DataValue::Null),
1256 _ => return Err(anyhow!("SPLIT_PART expects a string delimiter")),
1257 };
1258
1259 let part_num = match &args[2] {
1260 DataValue::Integer(n) => *n as usize,
1261 DataValue::Float(f) => *f as usize,
1262 DataValue::Null => return Ok(DataValue::Null),
1263 _ => return Err(anyhow!("SPLIT_PART expects a number for part index")),
1264 };
1265
1266 if part_num == 0 {
1267 return Err(anyhow!("SPLIT_PART part index must be >= 1"));
1268 }
1269
1270 let parts: Vec<&str> = string.split(delimiter).collect();
1271
1272 if part_num <= parts.len() {
1273 Ok(DataValue::String(parts[part_num - 1].to_string()))
1274 } else {
1275 Ok(DataValue::String(String::new()))
1276 }
1277 }
1278}
1279
1280pub fn register_string_methods(registry: &mut super::FunctionRegistry) {
1282 use std::sync::Arc;
1283
1284 registry.register(Box::new(MidFunction));
1286 registry.register(Box::new(UpperFunction));
1287 registry.register(Box::new(LowerFunction));
1288 registry.register(Box::new(TrimFunction));
1289 registry.register(Box::new(TextJoinFunction));
1290 registry.register(Box::new(EditDistanceFunction));
1291 registry.register(Box::new(FrequencyFunction));
1292
1293 registry.register(Box::new(LeftFunction));
1295 registry.register(Box::new(RightFunction));
1296 registry.register(Box::new(SubstringBeforeFunction));
1297 registry.register(Box::new(SubstringAfterFunction));
1298 registry.register(Box::new(SplitPartFunction));
1299
1300 let to_upper = Arc::new(ToUpperMethod);
1302 registry.register(Box::new(ToUpperMethod));
1303 registry.register_method(to_upper);
1304
1305 let to_lower = Arc::new(ToLowerMethod);
1307 registry.register(Box::new(ToLowerMethod));
1308 registry.register_method(to_lower);
1309
1310 let trim = Arc::new(TrimMethod);
1312 registry.register(Box::new(TrimMethod));
1313 registry.register_method(trim);
1314
1315 let trim_start = Arc::new(TrimStartMethod);
1317 registry.register(Box::new(TrimStartMethod));
1318 registry.register_method(trim_start);
1319
1320 let trim_end = Arc::new(TrimEndMethod);
1322 registry.register(Box::new(TrimEndMethod));
1323 registry.register_method(trim_end);
1324
1325 let length = Arc::new(LengthMethod);
1327 registry.register(Box::new(LengthMethod));
1328 registry.register_method(length);
1329
1330 let contains = Arc::new(ContainsMethod);
1332 registry.register(Box::new(ContainsMethod));
1333 registry.register_method(contains);
1334
1335 let starts_with = Arc::new(StartsWithMethod);
1337 registry.register(Box::new(StartsWithMethod));
1338 registry.register_method(starts_with);
1339
1340 let ends_with = Arc::new(EndsWithMethod);
1342 registry.register(Box::new(EndsWithMethod));
1343 registry.register_method(ends_with);
1344
1345 let substring = Arc::new(SubstringMethod);
1347 registry.register(Box::new(SubstringMethod));
1348 registry.register_method(substring);
1349
1350 let replace = Arc::new(ReplaceMethod);
1352 registry.register(Box::new(ReplaceMethod));
1353 registry.register_method(replace);
1354
1355 let indexof = Arc::new(IndexOfMethod);
1357 registry.register(Box::new(IndexOfMethod));
1358 registry.register_method(indexof.clone());
1359 registry.register(Box::new(InstrFunction));
1361}