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",
427 "SELECT SUBSTRING(name, 1, 5) FROM users",
428 ],
429 }
430 }
431
432 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
433 Self::extract(args, true)
435 }
436}
437
438impl SubstringMethod {
439 fn extract(args: &[DataValue], one_based: bool) -> Result<DataValue> {
446 if args.len() < 2 || args.len() > 3 {
447 return Err(anyhow!("Substring expects 2 or 3 arguments"));
448 }
449
450 let string = match &args[0] {
451 DataValue::String(s) => s.as_str(),
452 DataValue::InternedString(s) => s.as_str(),
453 DataValue::Null => return Ok(DataValue::Null),
454 _ => return Err(anyhow!("Substring expects a string as first argument")),
455 };
456
457 let raw_start = match &args[1] {
458 DataValue::Integer(i) => *i,
459 _ => return Err(anyhow!("Substring expects integer start position")),
460 };
461
462 let zero_based_start = if one_based { raw_start - 1 } else { raw_start };
464 let skip = zero_based_start.max(0) as usize;
465
466 let result: String = if args.len() == 3 {
467 let length = match &args[2] {
468 DataValue::Integer(i) => *i,
469 _ => return Err(anyhow!("Substring expects integer length")),
470 };
471 let consumed_before = (-zero_based_start).max(0);
474 let take = (length - consumed_before).max(0) as usize;
475 string.chars().skip(skip).take(take).collect()
476 } else {
477 string.chars().skip(skip).collect()
478 };
479
480 Ok(DataValue::String(result))
481 }
482}
483
484impl MethodFunction for SubstringMethod {
485 fn handles_method(&self, method_name: &str) -> bool {
486 method_name.eq_ignore_ascii_case("Substring") || method_name.eq_ignore_ascii_case("Substr")
487 }
488
489 fn method_name(&self) -> &'static str {
490 "Substring"
491 }
492
493 fn evaluate_method(&self, receiver: &DataValue, args: &[DataValue]) -> Result<DataValue> {
494 let mut full_args = vec![receiver.clone()];
496 full_args.extend_from_slice(args);
497 Self::extract(&full_args, false)
498 }
499}
500
501pub struct ReplaceMethod;
503
504impl SqlFunction for ReplaceMethod {
505 fn signature(&self) -> FunctionSignature {
506 FunctionSignature {
507 name: "REPLACE",
508 category: FunctionCategory::String,
509 arg_count: ArgCount::Fixed(3),
510 description: "Replaces all occurrences of a substring",
511 returns: "STRING",
512 examples: vec![
513 "SELECT name.Replace('John', 'Jane') FROM users",
514 "SELECT REPLACE(name, 'John', 'Jane') FROM users",
515 ],
516 }
517 }
518
519 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
520 self.validate_args(args)?;
521
522 let string = match &args[0] {
523 DataValue::String(s) => s.as_str(),
524 DataValue::InternedString(s) => s.as_str(),
525 DataValue::Null => return Ok(DataValue::Null),
526 _ => return Err(anyhow!("Replace expects string arguments")),
527 };
528
529 let from = match &args[1] {
530 DataValue::String(s) => s.as_str(),
531 DataValue::InternedString(s) => s.as_str(),
532 _ => return Err(anyhow!("Replace expects string arguments")),
533 };
534
535 let to = match &args[2] {
536 DataValue::String(s) => s.as_str(),
537 DataValue::InternedString(s) => s.as_str(),
538 _ => return Err(anyhow!("Replace expects string arguments")),
539 };
540
541 Ok(DataValue::String(string.replace(from, to)))
542 }
543}
544
545impl MethodFunction for ReplaceMethod {
546 fn handles_method(&self, method_name: &str) -> bool {
547 method_name.eq_ignore_ascii_case("Replace")
548 }
549
550 fn method_name(&self) -> &'static str {
551 "Replace"
552 }
553}
554
555pub struct MidFunction;
557
558impl SqlFunction for MidFunction {
559 fn signature(&self) -> FunctionSignature {
560 FunctionSignature {
561 name: "MID",
562 category: FunctionCategory::String,
563 arg_count: ArgCount::Fixed(3),
564 description: "Extract substring from text (1-based indexing)",
565 returns: "STRING",
566 examples: vec![
567 "SELECT MID('Hello', 1, 3)", "SELECT MID('World', 2, 3)", "SELECT MID(name, 1, 5) FROM table",
570 ],
571 }
572 }
573
574 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
575 self.validate_args(args)?;
576
577 let text = match &args[0] {
579 DataValue::String(s) => s.clone(),
580 DataValue::InternedString(s) => s.to_string(),
581 DataValue::Integer(n) => n.to_string(),
582 DataValue::Float(f) => f.to_string(),
583 DataValue::Null => String::new(),
584 _ => return Err(anyhow!("MID first argument must be convertible to text")),
585 };
586
587 let start_pos = match &args[1] {
589 DataValue::Integer(n) => *n,
590 DataValue::Float(f) => *f as i64,
591 _ => return Err(anyhow!("MID start position must be a number")),
592 };
593
594 let length = match &args[2] {
596 DataValue::Integer(n) => *n,
597 DataValue::Float(f) => *f as i64,
598 _ => return Err(anyhow!("MID length must be a number")),
599 };
600
601 if start_pos < 1 {
603 return Err(anyhow!("MID start position must be >= 1"));
604 }
605 if length < 0 {
606 return Err(anyhow!("MID length must be >= 0"));
607 }
608
609 let start_idx = (start_pos - 1) as usize;
611 let chars: Vec<char> = text.chars().collect();
612
613 if start_idx >= chars.len() {
615 return Ok(DataValue::String(String::new()));
616 }
617
618 let end_idx = std::cmp::min(start_idx + length as usize, chars.len());
620 let result: String = chars[start_idx..end_idx].iter().collect();
621
622 Ok(DataValue::String(result))
623 }
624}
625
626pub struct UpperFunction;
628
629impl SqlFunction for UpperFunction {
630 fn signature(&self) -> FunctionSignature {
631 FunctionSignature {
632 name: "UPPER",
633 category: FunctionCategory::String,
634 arg_count: ArgCount::Fixed(1),
635 description: "Convert string to uppercase",
636 returns: "STRING",
637 examples: vec![
638 "SELECT UPPER('hello')", "SELECT UPPER(name) FROM table",
640 ],
641 }
642 }
643
644 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
645 self.validate_args(args)?;
646
647 match &args[0] {
648 DataValue::String(s) => Ok(DataValue::String(s.to_uppercase())),
649 DataValue::InternedString(s) => Ok(DataValue::String(s.to_uppercase())),
650 DataValue::Null => Ok(DataValue::Null),
651 _ => Err(anyhow!("UPPER expects a string argument")),
652 }
653 }
654}
655
656pub struct LowerFunction;
658
659impl SqlFunction for LowerFunction {
660 fn signature(&self) -> FunctionSignature {
661 FunctionSignature {
662 name: "LOWER",
663 category: FunctionCategory::String,
664 arg_count: ArgCount::Fixed(1),
665 description: "Convert string to lowercase",
666 returns: "STRING",
667 examples: vec![
668 "SELECT LOWER('HELLO')", "SELECT LOWER(name) FROM table",
670 ],
671 }
672 }
673
674 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
675 self.validate_args(args)?;
676
677 match &args[0] {
678 DataValue::String(s) => Ok(DataValue::String(s.to_lowercase())),
679 DataValue::InternedString(s) => Ok(DataValue::String(s.to_lowercase())),
680 DataValue::Null => Ok(DataValue::Null),
681 _ => Err(anyhow!("LOWER expects a string argument")),
682 }
683 }
684}
685
686pub struct TrimFunction;
688
689impl SqlFunction for TrimFunction {
690 fn signature(&self) -> FunctionSignature {
691 FunctionSignature {
692 name: "TRIM",
693 category: FunctionCategory::String,
694 arg_count: ArgCount::Fixed(1),
695 description: "Remove leading and trailing whitespace",
696 returns: "STRING",
697 examples: vec![
698 "SELECT TRIM(' hello ')", "SELECT TRIM(description) FROM table",
700 ],
701 }
702 }
703
704 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
705 self.validate_args(args)?;
706
707 match &args[0] {
708 DataValue::String(s) => Ok(DataValue::String(s.trim().to_string())),
709 DataValue::InternedString(s) => Ok(DataValue::String(s.trim().to_string())),
710 DataValue::Null => Ok(DataValue::Null),
711 _ => Err(anyhow!("TRIM expects a string argument")),
712 }
713 }
714}
715
716pub struct TextJoinFunction;
718
719impl SqlFunction for TextJoinFunction {
720 fn signature(&self) -> FunctionSignature {
721 FunctionSignature {
722 name: "TEXTJOIN",
723 category: FunctionCategory::String,
724 arg_count: ArgCount::Variadic,
725 description: "Join multiple text values with a delimiter",
726 returns: "STRING",
727 examples: vec![
728 "SELECT TEXTJOIN(',', 1, 'a', 'b', 'c')", "SELECT TEXTJOIN(' - ', 1, name, city) FROM table",
730 "SELECT TEXTJOIN('|', 0, col1, col2, col3) FROM table",
731 ],
732 }
733 }
734
735 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
736 if args.len() < 3 {
737 return Err(anyhow!("TEXTJOIN requires at least 3 arguments: delimiter, ignore_empty, text1, [text2, ...]"));
738 }
739
740 let delimiter = match &args[0] {
742 DataValue::String(s) => s.clone(),
743 DataValue::InternedString(s) => s.to_string(),
744 DataValue::Integer(n) => n.to_string(),
745 DataValue::Float(f) => f.to_string(),
746 DataValue::Boolean(b) => b.to_string(),
747 DataValue::Null => String::new(),
748 _ => String::new(),
749 };
750
751 let ignore_empty = match &args[1] {
753 DataValue::Integer(n) => *n != 0,
754 DataValue::Float(f) => *f != 0.0,
755 DataValue::Boolean(b) => *b,
756 DataValue::String(s) => !s.is_empty() && s != "0" && s.to_lowercase() != "false",
757 DataValue::InternedString(s) => {
758 !s.is_empty() && s.as_str() != "0" && s.to_lowercase() != "false"
759 }
760 DataValue::Null => false,
761 _ => true,
762 };
763
764 let mut values = Vec::new();
766 for i in 2..args.len() {
767 let string_value = match &args[i] {
768 DataValue::String(s) => Some(s.clone()),
769 DataValue::InternedString(s) => Some(s.to_string()),
770 DataValue::Integer(n) => Some(n.to_string()),
771 DataValue::Float(f) => Some(f.to_string()),
772 DataValue::Boolean(b) => Some(b.to_string()),
773 DataValue::DateTime(dt) => Some(dt.clone()),
774 DataValue::Vector(v) => {
775 let components: Vec<String> = v.iter().map(|f| f.to_string()).collect();
776 Some(format!("[{}]", components.join(",")))
777 }
778 DataValue::Null => {
779 if ignore_empty {
780 None
781 } else {
782 Some(String::new())
783 }
784 }
785 };
786
787 if let Some(s) = string_value {
788 if !ignore_empty || !s.is_empty() {
789 values.push(s);
790 }
791 }
792 }
793
794 Ok(DataValue::String(values.join(&delimiter)))
795 }
796}
797
798pub struct EditDistanceFunction;
800
801impl EditDistanceFunction {
802 #[must_use]
804 pub fn calculate_edit_distance(s1: &str, s2: &str) -> usize {
805 let len1 = s1.len();
806 let len2 = s2.len();
807 let mut matrix = vec![vec![0; len2 + 1]; len1 + 1];
808
809 for i in 0..=len1 {
810 matrix[i][0] = i;
811 }
812 for j in 0..=len2 {
813 matrix[0][j] = j;
814 }
815
816 for (i, c1) in s1.chars().enumerate() {
817 for (j, c2) in s2.chars().enumerate() {
818 let cost = usize::from(c1 != c2);
819 matrix[i + 1][j + 1] = std::cmp::min(
820 matrix[i][j + 1] + 1, std::cmp::min(
822 matrix[i + 1][j] + 1, matrix[i][j] + cost, ),
825 );
826 }
827 }
828
829 matrix[len1][len2]
830 }
831}
832
833impl SqlFunction for EditDistanceFunction {
834 fn signature(&self) -> FunctionSignature {
835 FunctionSignature {
836 name: "EDIT_DISTANCE",
837 category: FunctionCategory::String,
838 arg_count: ArgCount::Fixed(2),
839 description: "Calculate the Levenshtein edit distance between two strings",
840 returns: "INTEGER",
841 examples: vec![
842 "SELECT EDIT_DISTANCE('kitten', 'sitting')",
843 "SELECT EDIT_DISTANCE(name, 'John') FROM users",
844 "SELECT * FROM users WHERE EDIT_DISTANCE(name, 'Smith') <= 2",
845 ],
846 }
847 }
848
849 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
850 self.validate_args(args)?;
851
852 let s1 = match &args[0] {
853 DataValue::String(s) => s.clone(),
854 DataValue::InternedString(s) => s.to_string(),
855 DataValue::Null => return Ok(DataValue::Null),
856 _ => return Err(anyhow!("EDIT_DISTANCE expects string arguments")),
857 };
858
859 let s2 = match &args[1] {
860 DataValue::String(s) => s.clone(),
861 DataValue::InternedString(s) => s.to_string(),
862 DataValue::Null => return Ok(DataValue::Null),
863 _ => return Err(anyhow!("EDIT_DISTANCE expects string arguments")),
864 };
865
866 let distance = Self::calculate_edit_distance(&s1, &s2);
867 Ok(DataValue::Integer(distance as i64))
868 }
869}
870
871pub struct FrequencyFunction;
873
874impl SqlFunction for FrequencyFunction {
875 fn signature(&self) -> FunctionSignature {
876 FunctionSignature {
877 name: "FREQUENCY",
878 category: FunctionCategory::String,
879 arg_count: ArgCount::Fixed(2),
880 description: "Count occurrences of a substring within a string",
881 returns: "INTEGER",
882 examples: vec![
883 "SELECT FREQUENCY('hello world', 'o')", "SELECT FREQUENCY('mississippi', 'ss')", "SELECT FREQUENCY(text_column, 'error') FROM logs",
886 "SELECT name, FREQUENCY(name, 'a') as a_count FROM users",
887 ],
888 }
889 }
890
891 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
892 self.validate_args(args)?;
893
894 let text = match &args[0] {
896 DataValue::String(s) => s.clone(),
897 DataValue::InternedString(s) => s.to_string(),
898 DataValue::Null => return Ok(DataValue::Integer(0)),
899 _ => return Err(anyhow!("FREQUENCY expects string as first argument")),
900 };
901
902 let search = match &args[1] {
904 DataValue::String(s) => s.clone(),
905 DataValue::InternedString(s) => s.to_string(),
906 DataValue::Null => return Ok(DataValue::Integer(0)),
907 _ => return Err(anyhow!("FREQUENCY expects string as second argument")),
908 };
909
910 if search.is_empty() {
912 return Ok(DataValue::Integer(0));
913 }
914
915 let count = text.matches(&search).count();
917 Ok(DataValue::Integer(count as i64))
918 }
919}
920
921pub struct IndexOfMethod;
923
924impl SqlFunction for IndexOfMethod {
925 fn signature(&self) -> FunctionSignature {
926 FunctionSignature {
927 name: "INDEXOF",
928 category: FunctionCategory::String,
929 arg_count: ArgCount::Fixed(2),
930 description: "Returns the position of the first occurrence of a substring (0-based)",
931 returns: "INTEGER",
932 examples: vec![
933 "SELECT email.IndexOf('@') FROM users",
934 "SELECT INDEXOF(email, '@') FROM users",
935 ],
936 }
937 }
938
939 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
940 self.validate_args(args)?;
941
942 let string = match &args[0] {
943 DataValue::String(s) => s.as_str(),
944 DataValue::InternedString(s) => s.as_str(),
945 DataValue::Null => return Ok(DataValue::Null),
946 _ => return Err(anyhow!("IndexOf expects string arguments")),
947 };
948
949 let substring = match &args[1] {
950 DataValue::String(s) => s.as_str(),
951 DataValue::InternedString(s) => s.as_str(),
952 DataValue::Null => return Ok(DataValue::Null),
953 _ => return Err(anyhow!("IndexOf expects string arguments")),
954 };
955
956 match string.find(substring) {
957 Some(pos) => Ok(DataValue::Integer(pos as i64)),
958 None => Ok(DataValue::Integer(-1)), }
960 }
961}
962
963impl MethodFunction for IndexOfMethod {
964 fn handles_method(&self, method_name: &str) -> bool {
965 method_name.eq_ignore_ascii_case("IndexOf")
966 }
967
968 fn method_name(&self) -> &'static str {
969 "IndexOf"
970 }
971}
972
973pub struct InstrFunction;
976
977impl SqlFunction for InstrFunction {
978 fn signature(&self) -> FunctionSignature {
979 FunctionSignature {
980 name: "INSTR",
981 category: FunctionCategory::String,
982 arg_count: ArgCount::Fixed(2),
983 description: "Returns the position of the first occurrence of a substring (1-based, SQL standard)",
984 returns: "INTEGER",
985 examples: vec![
986 "SELECT INSTR(email, '@') FROM users",
987 "SELECT SUBSTRING(email, INSTR(email, '@') + 1) FROM users",
988 ],
989 }
990 }
991
992 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
993 self.validate_args(args)?;
994
995 let string = match &args[0] {
996 DataValue::String(s) => s.as_str(),
997 DataValue::InternedString(s) => s.as_str(),
998 DataValue::Null => return Ok(DataValue::Null),
999 _ => return Err(anyhow!("INSTR expects string arguments")),
1000 };
1001
1002 let substring = match &args[1] {
1003 DataValue::String(s) => s.as_str(),
1004 DataValue::InternedString(s) => s.as_str(),
1005 DataValue::Null => return Ok(DataValue::Null),
1006 _ => return Err(anyhow!("INSTR expects string arguments")),
1007 };
1008
1009 match string.find(substring) {
1010 Some(pos) => Ok(DataValue::Integer((pos + 1) as i64)), None => Ok(DataValue::Integer(0)), }
1013 }
1014}
1015
1016pub struct LeftFunction;
1018
1019impl SqlFunction for LeftFunction {
1020 fn signature(&self) -> FunctionSignature {
1021 FunctionSignature {
1022 name: "LEFT",
1023 category: FunctionCategory::String,
1024 arg_count: ArgCount::Fixed(2),
1025 description: "Returns leftmost n characters from string",
1026 returns: "STRING",
1027 examples: vec![
1028 "SELECT LEFT(email, 5) FROM users",
1029 "SELECT LEFT('hello@world', INSTR('hello@world', '@') - 1)",
1030 ],
1031 }
1032 }
1033
1034 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
1035 self.validate_args(args)?;
1036
1037 let string = match &args[0] {
1038 DataValue::String(s) => s.as_str(),
1039 DataValue::InternedString(s) => s.as_str(),
1040 DataValue::Null => return Ok(DataValue::Null),
1041 _ => return Err(anyhow!("LEFT expects a string as first argument")),
1042 };
1043
1044 let length = match &args[1] {
1045 DataValue::Integer(n) => *n as usize,
1046 DataValue::Float(f) => *f as usize,
1047 DataValue::Null => return Ok(DataValue::Null),
1048 _ => return Err(anyhow!("LEFT expects a number as second argument")),
1049 };
1050
1051 let result = if length >= string.len() {
1052 string.to_string()
1053 } else {
1054 string.chars().take(length).collect()
1055 };
1056
1057 Ok(DataValue::String(result))
1058 }
1059}
1060
1061pub struct RightFunction;
1063
1064impl SqlFunction for RightFunction {
1065 fn signature(&self) -> FunctionSignature {
1066 FunctionSignature {
1067 name: "RIGHT",
1068 category: FunctionCategory::String,
1069 arg_count: ArgCount::Fixed(2),
1070 description: "Returns rightmost n characters from string",
1071 returns: "STRING",
1072 examples: vec![
1073 "SELECT RIGHT(filename, 4) FROM files", "SELECT RIGHT(email, LENGTH(email) - INSTR(email, '@'))", ],
1076 }
1077 }
1078
1079 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
1080 self.validate_args(args)?;
1081
1082 let string = match &args[0] {
1083 DataValue::String(s) => s.as_str(),
1084 DataValue::InternedString(s) => s.as_str(),
1085 DataValue::Null => return Ok(DataValue::Null),
1086 _ => return Err(anyhow!("RIGHT expects a string as first argument")),
1087 };
1088
1089 let length = match &args[1] {
1090 DataValue::Integer(n) => *n as usize,
1091 DataValue::Float(f) => *f as usize,
1092 DataValue::Null => return Ok(DataValue::Null),
1093 _ => return Err(anyhow!("RIGHT expects a number as second argument")),
1094 };
1095
1096 let chars: Vec<char> = string.chars().collect();
1097 let start = if length >= chars.len() {
1098 0
1099 } else {
1100 chars.len() - length
1101 };
1102
1103 let result: String = chars[start..].iter().collect();
1104 Ok(DataValue::String(result))
1105 }
1106}
1107
1108pub struct SubstringBeforeFunction;
1110
1111impl SqlFunction for SubstringBeforeFunction {
1112 fn signature(&self) -> FunctionSignature {
1113 FunctionSignature {
1114 name: "SUBSTRING_BEFORE",
1115 category: FunctionCategory::String,
1116 arg_count: ArgCount::Range(2, 3),
1117 description: "Returns substring before the first (or nth) occurrence of delimiter",
1118 returns: "STRING",
1119 examples: vec![
1120 "SELECT SUBSTRING_BEFORE(email, '@') FROM users", "SELECT SUBSTRING_BEFORE('a.b.c.d', '.', 2)", ],
1123 }
1124 }
1125
1126 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
1127 if args.len() < 2 || args.len() > 3 {
1128 return Err(anyhow!("SUBSTRING_BEFORE expects 2 or 3 arguments"));
1129 }
1130
1131 let string = match &args[0] {
1132 DataValue::String(s) => s.as_str(),
1133 DataValue::InternedString(s) => s.as_str(),
1134 DataValue::Null => return Ok(DataValue::Null),
1135 _ => {
1136 return Err(anyhow!(
1137 "SUBSTRING_BEFORE expects a string as first argument"
1138 ))
1139 }
1140 };
1141
1142 let delimiter = match &args[1] {
1143 DataValue::String(s) => s.as_str(),
1144 DataValue::InternedString(s) => s.as_str(),
1145 DataValue::Null => return Ok(DataValue::Null),
1146 _ => return Err(anyhow!("SUBSTRING_BEFORE expects a string delimiter")),
1147 };
1148
1149 let occurrence = if args.len() == 3 {
1150 match &args[2] {
1151 DataValue::Integer(n) => *n as usize,
1152 DataValue::Float(f) => *f as usize,
1153 DataValue::Null => 1,
1154 _ => return Err(anyhow!("SUBSTRING_BEFORE expects a number for occurrence")),
1155 }
1156 } else {
1157 1
1158 };
1159
1160 if occurrence == 0 {
1161 return Ok(DataValue::String(String::new()));
1162 }
1163
1164 let mut count = 0;
1166 for (i, _) in string.match_indices(delimiter) {
1167 count += 1;
1168 if count == occurrence {
1169 return Ok(DataValue::String(string[..i].to_string()));
1170 }
1171 }
1172
1173 Ok(DataValue::String(String::new()))
1175 }
1176}
1177
1178pub struct SubstringAfterFunction;
1180
1181impl SqlFunction for SubstringAfterFunction {
1182 fn signature(&self) -> FunctionSignature {
1183 FunctionSignature {
1184 name: "SUBSTRING_AFTER",
1185 category: FunctionCategory::String,
1186 arg_count: ArgCount::Range(2, 3),
1187 description: "Returns substring after the first (or nth) occurrence of delimiter",
1188 returns: "STRING",
1189 examples: vec![
1190 "SELECT SUBSTRING_AFTER(email, '@') FROM users", "SELECT SUBSTRING_AFTER('a.b.c.d', '.', 2)", ],
1193 }
1194 }
1195
1196 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
1197 if args.len() < 2 || args.len() > 3 {
1198 return Err(anyhow!("SUBSTRING_AFTER expects 2 or 3 arguments"));
1199 }
1200
1201 let string = match &args[0] {
1202 DataValue::String(s) => s.as_str(),
1203 DataValue::InternedString(s) => s.as_str(),
1204 DataValue::Null => return Ok(DataValue::Null),
1205 _ => {
1206 return Err(anyhow!(
1207 "SUBSTRING_AFTER expects a string as first argument"
1208 ))
1209 }
1210 };
1211
1212 let delimiter = match &args[1] {
1213 DataValue::String(s) => s.as_str(),
1214 DataValue::InternedString(s) => s.as_str(),
1215 DataValue::Null => return Ok(DataValue::Null),
1216 _ => return Err(anyhow!("SUBSTRING_AFTER expects a string delimiter")),
1217 };
1218
1219 let occurrence = if args.len() == 3 {
1220 match &args[2] {
1221 DataValue::Integer(n) => *n as usize,
1222 DataValue::Float(f) => *f as usize,
1223 DataValue::Null => 1,
1224 _ => return Err(anyhow!("SUBSTRING_AFTER expects a number for occurrence")),
1225 }
1226 } else {
1227 1
1228 };
1229
1230 if occurrence == 0 {
1231 return Ok(DataValue::String(string.to_string()));
1232 }
1233
1234 let mut count = 0;
1236 for (i, _) in string.match_indices(delimiter) {
1237 count += 1;
1238 if count == occurrence {
1239 let start = i + delimiter.len();
1240 if start < string.len() {
1241 return Ok(DataValue::String(string[start..].to_string()));
1242 } else {
1243 return Ok(DataValue::String(String::new()));
1244 }
1245 }
1246 }
1247
1248 Ok(DataValue::String(String::new()))
1250 }
1251}
1252
1253pub struct SplitPartFunction;
1255
1256impl SqlFunction for SplitPartFunction {
1257 fn signature(&self) -> FunctionSignature {
1258 FunctionSignature {
1259 name: "SPLIT_PART",
1260 category: FunctionCategory::String,
1261 arg_count: ArgCount::Fixed(3),
1262 description: "Returns the nth part of a string split by delimiter (1-based index)",
1263 returns: "STRING",
1264 examples: vec![
1265 "SELECT SPLIT_PART('a.b.c.d', '.', 2)", "SELECT SPLIT_PART(email, '@', 1) FROM users", ],
1268 }
1269 }
1270
1271 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
1272 self.validate_args(args)?;
1273
1274 let string = match &args[0] {
1275 DataValue::String(s) => s.as_str(),
1276 DataValue::InternedString(s) => s.as_str(),
1277 DataValue::Null => return Ok(DataValue::Null),
1278 _ => return Err(anyhow!("SPLIT_PART expects a string as first argument")),
1279 };
1280
1281 let delimiter = match &args[1] {
1282 DataValue::String(s) => s.as_str(),
1283 DataValue::InternedString(s) => s.as_str(),
1284 DataValue::Null => return Ok(DataValue::Null),
1285 _ => return Err(anyhow!("SPLIT_PART expects a string delimiter")),
1286 };
1287
1288 let part_num = match &args[2] {
1289 DataValue::Integer(n) => *n as usize,
1290 DataValue::Float(f) => *f as usize,
1291 DataValue::Null => return Ok(DataValue::Null),
1292 _ => return Err(anyhow!("SPLIT_PART expects a number for part index")),
1293 };
1294
1295 if part_num == 0 {
1296 return Err(anyhow!("SPLIT_PART part index must be >= 1"));
1297 }
1298
1299 let parts: Vec<&str> = string.split(delimiter).collect();
1300
1301 if part_num <= parts.len() {
1302 Ok(DataValue::String(parts[part_num - 1].to_string()))
1303 } else {
1304 Ok(DataValue::String(String::new()))
1305 }
1306 }
1307}
1308
1309pub struct ChrFunction;
1311
1312impl SqlFunction for ChrFunction {
1313 fn signature(&self) -> FunctionSignature {
1314 FunctionSignature {
1315 name: "CHR",
1316 category: FunctionCategory::String,
1317 arg_count: ArgCount::Fixed(1),
1318 description: "Convert ASCII code to character",
1319 returns: "STRING",
1320 examples: vec![
1321 "SELECT CHR(65)", "SELECT CHR(97)", "SELECT CHR(48)", ],
1325 }
1326 }
1327
1328 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
1329 if args.len() != 1 {
1330 return Err(anyhow!("CHR expects exactly 1 argument"));
1331 }
1332
1333 let ascii_code = match &args[0] {
1334 DataValue::Integer(n) => *n,
1335 DataValue::Float(f) => *f as i64,
1336 DataValue::String(s) => s
1337 .parse::<i64>()
1338 .map_err(|_| anyhow!("Invalid number for CHR: {}", s))?,
1339 DataValue::InternedString(s) => s
1340 .parse::<i64>()
1341 .map_err(|_| anyhow!("Invalid number for CHR: {}", s))?,
1342 DataValue::Null => return Ok(DataValue::Null),
1343 _ => return Err(anyhow!("CHR expects a numeric argument")),
1344 };
1345
1346 if ascii_code < 0 || ascii_code > 255 {
1348 return Err(anyhow!(
1349 "CHR argument must be between 0 and 255, got {}",
1350 ascii_code
1351 ));
1352 }
1353
1354 let ch = ascii_code as u8 as char;
1355 Ok(DataValue::String(ch.to_string()))
1356 }
1357}
1358
1359pub struct LoremIpsumFunction;
1361
1362impl SqlFunction for LoremIpsumFunction {
1363 fn signature(&self) -> FunctionSignature {
1364 FunctionSignature {
1365 name: "LOREM_IPSUM",
1366 category: FunctionCategory::String,
1367 arg_count: ArgCount::Range(1, 3),
1368 description: "Generate Lorem Ipsum placeholder text with specified number of words",
1369 returns: "STRING",
1370 examples: vec![
1371 "SELECT LOREM_IPSUM(10)", "SELECT LOREM_IPSUM(50)", "SELECT LOREM_IPSUM(20, 1)", "SELECT LOREM_IPSUM(15, 0, id)", ],
1376 }
1377 }
1378
1379 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
1380 self.validate_args(args)?;
1381
1382 let num_words = match &args[0] {
1383 DataValue::Integer(n) if *n > 0 => *n as usize,
1384 DataValue::Float(f) if *f > 0.0 => *f as usize,
1385 DataValue::Null => return Ok(DataValue::Null),
1386 _ => return Err(anyhow!("LOREM_IPSUM requires a positive number of words")),
1387 };
1388
1389 let start_traditional = if args.len() > 1 {
1391 match &args[1] {
1392 DataValue::Integer(n) => *n != 0,
1393 DataValue::Boolean(b) => *b,
1394 _ => false,
1395 }
1396 } else {
1397 false
1398 };
1399
1400 let seed_value = if args.len() > 2 {
1402 match &args[2] {
1403 DataValue::Integer(n) => *n as u64,
1404 DataValue::Float(f) => *f as u64,
1405 DataValue::String(s) => {
1406 let mut hash = 0u64;
1408 for byte in s.bytes() {
1409 hash = hash.wrapping_mul(31).wrapping_add(byte as u64);
1410 }
1411 hash
1412 }
1413 DataValue::Null => 0,
1414 _ => 0,
1415 }
1416 } else {
1417 0
1418 };
1419
1420 const LOREM_WORDS: &[&str] = &[
1422 "lorem",
1423 "ipsum",
1424 "dolor",
1425 "sit",
1426 "amet",
1427 "consectetur",
1428 "adipiscing",
1429 "elit",
1430 "sed",
1431 "do",
1432 "eiusmod",
1433 "tempor",
1434 "incididunt",
1435 "ut",
1436 "labore",
1437 "et",
1438 "dolore",
1439 "magna",
1440 "aliqua",
1441 "enim",
1442 "ad",
1443 "minim",
1444 "veniam",
1445 "quis",
1446 "nostrud",
1447 "exercitation",
1448 "ullamco",
1449 "laboris",
1450 "nisi",
1451 "aliquip",
1452 "ex",
1453 "ea",
1454 "commodo",
1455 "consequat",
1456 "duis",
1457 "aute",
1458 "irure",
1459 "in",
1460 "reprehenderit",
1461 "voluptate",
1462 "velit",
1463 "esse",
1464 "cillum",
1465 "fugiat",
1466 "nulla",
1467 "pariatur",
1468 "excepteur",
1469 "sint",
1470 "occaecat",
1471 "cupidatat",
1472 "non",
1473 "proident",
1474 "sunt",
1475 "culpa",
1476 "qui",
1477 "officia",
1478 "deserunt",
1479 "mollit",
1480 "anim",
1481 "id",
1482 "est",
1483 "laborum",
1484 "perspiciatis",
1485 "unde",
1486 "omnis",
1487 "iste",
1488 "natus",
1489 "error",
1490 "voluptatem",
1491 "accusantium",
1492 "doloremque",
1493 "laudantium",
1494 "totam",
1495 "rem",
1496 "aperiam",
1497 "eaque",
1498 "ipsa",
1499 "quae",
1500 "ab",
1501 "illo",
1502 "inventore",
1503 "veritatis",
1504 "quasi",
1505 "architecto",
1506 "beatae",
1507 "vitae",
1508 "dicta",
1509 "explicabo",
1510 "nemo",
1511 "enim",
1512 "ipsam",
1513 "quia",
1514 "voluptas",
1515 "aspernatur",
1516 "aut",
1517 "odit",
1518 "fugit",
1519 "consequuntur",
1520 "magni",
1521 "dolores",
1522 "eos",
1523 "ratione",
1524 "sequi",
1525 "nesciunt",
1526 "neque",
1527 "porro",
1528 "quisquam",
1529 "dolorem",
1530 "adipisci",
1531 "numquam",
1532 "eius",
1533 "modi",
1534 "tempora",
1535 "incidunt",
1536 "magnam",
1537 "quaerat",
1538 "etiam",
1539 "minus",
1540 "soluta",
1541 "nobis",
1542 "eligendi",
1543 "optio",
1544 "cumque",
1545 "nihil",
1546 "impedit",
1547 "quo",
1548 "possimus",
1549 "suscipit",
1550 "laboriosam",
1551 "aliquid",
1552 "fuga",
1553 "distinctio",
1554 "libero",
1555 "tempore",
1556 "cum",
1557 "assumenda",
1558 "est",
1559 "omnis",
1560 "dolor",
1561 "repellendus",
1562 "temporibus",
1563 "autem",
1564 "quibusdam",
1565 "officiis",
1566 "debitis",
1567 "rerum",
1568 "necessitatibus",
1569 "saepe",
1570 "eveniet",
1571 "voluptates",
1572 "repudiandae",
1573 "molestiae",
1574 "recusandae",
1575 "itaque",
1576 "earum",
1577 "hic",
1578 "tenetur",
1579 "sapiente",
1580 "delectus",
1581 "reiciendis",
1582 "voluptatibus",
1583 "maiores",
1584 "alias",
1585 "consequatur",
1586 "perferendis",
1587 "doloribus",
1588 "asperiores",
1589 "repellat",
1590 "iusto",
1591 "odio",
1592 "dignissimos",
1593 "ducimus",
1594 "blanditiis",
1595 "praesentium",
1596 "voluptatum",
1597 "deleniti",
1598 "atque",
1599 "corrupti",
1600 "quos",
1601 "quas",
1602 "molestias",
1603 "excepturi",
1604 "occaecati",
1605 "provident",
1606 "similique",
1607 "mollitia",
1608 "animi",
1609 "illum",
1610 "dolorum",
1611 "fuga",
1612 "harum",
1613 "quidem",
1614 "rerum",
1615 "facilis",
1616 "expedita",
1617 "distinctio",
1618 "nam",
1619 "libero",
1620 "tempore",
1621 "cum",
1622 "soluta",
1623 "nobis",
1624 "eligendi",
1625 "optio",
1626 "cumque",
1627 "nihil",
1628 "impedit",
1629 "minus",
1630 "quod",
1631 "maxime",
1632 "placeat",
1633 "facere",
1634 "possimus",
1635 "omnis",
1636 "voluptas",
1637 "assumenda",
1638 ];
1639
1640 let mut result = Vec::with_capacity(num_words);
1641
1642 if start_traditional && num_words > 0 {
1643 let traditional_start = ["lorem", "ipsum", "dolor", "sit", "amet"];
1645 let take_count = num_words.min(traditional_start.len());
1646 for i in 0..take_count {
1647 result.push(traditional_start[i]);
1648 }
1649
1650 let seed = if seed_value != 0 {
1652 seed_value
1653 } else {
1654 use std::time::{SystemTime, UNIX_EPOCH};
1655 SystemTime::now()
1656 .duration_since(UNIX_EPOCH)
1657 .unwrap_or_default()
1658 .as_nanos() as u64
1659 };
1660
1661 let mut rng = seed.wrapping_mul(num_words as u64); for i in take_count..num_words {
1663 rng = (rng.wrapping_mul(1664525).wrapping_add(1013904223)) ^ (i as u64);
1665 let idx = (rng as usize) % LOREM_WORDS.len();
1666 result.push(LOREM_WORDS[idx]);
1667 }
1668 } else {
1669 let seed = if seed_value != 0 {
1671 seed_value
1672 } else {
1673 use std::time::{SystemTime, UNIX_EPOCH};
1674 SystemTime::now()
1675 .duration_since(UNIX_EPOCH)
1676 .unwrap_or_default()
1677 .as_nanos() as u64
1678 };
1679
1680 let mut rng = seed.wrapping_mul(num_words as u64).wrapping_add(12345); for i in 0..num_words {
1682 rng = (rng.wrapping_mul(1664525).wrapping_add(1013904223)) ^ (i as u64);
1684 let idx = (rng as usize) % LOREM_WORDS.len();
1685 result.push(LOREM_WORDS[idx]);
1686 }
1687 }
1688
1689 let mut text = String::new();
1691 for (i, word) in result.iter().enumerate() {
1692 if i == 0 {
1693 text.push_str(&word.chars().next().unwrap().to_uppercase().to_string());
1695 text.push_str(&word[1..]);
1696 } else {
1697 text.push(' ');
1698 if i > 0 && ((i * 7) % 13 == 0) && i < num_words - 1 {
1700 text.pop(); text.push_str(". ");
1702 text.push_str(&word.chars().next().unwrap().to_uppercase().to_string());
1704 text.push_str(&word[1..]);
1705 } else {
1706 text.push_str(word);
1707 }
1708 }
1709 }
1710
1711 if !text.is_empty() {
1713 text.push('.');
1714 }
1715
1716 Ok(DataValue::String(text))
1717 }
1718}
1719
1720pub fn register_string_methods(registry: &mut super::FunctionRegistry) {
1722 use std::sync::Arc;
1723
1724 registry.register(Box::new(MidFunction));
1726 registry.register(Box::new(UpperFunction));
1727 registry.register(Box::new(LowerFunction));
1728 registry.register(Box::new(TrimFunction));
1729 registry.register(Box::new(TextJoinFunction));
1730 registry.register(Box::new(EditDistanceFunction));
1731 registry.register(Box::new(FrequencyFunction));
1732
1733 registry.register(Box::new(LeftFunction));
1735 registry.register(Box::new(RightFunction));
1736 registry.register(Box::new(SubstringBeforeFunction));
1737 registry.register(Box::new(SubstringAfterFunction));
1738 registry.register(Box::new(SplitPartFunction));
1739
1740 let to_upper = Arc::new(ToUpperMethod);
1742 registry.register(Box::new(ToUpperMethod));
1743 registry.register_method(to_upper);
1744
1745 let to_lower = Arc::new(ToLowerMethod);
1747 registry.register(Box::new(ToLowerMethod));
1748 registry.register_method(to_lower);
1749
1750 let trim = Arc::new(TrimMethod);
1752 registry.register(Box::new(TrimMethod));
1753 registry.register_method(trim);
1754
1755 let trim_start = Arc::new(TrimStartMethod);
1757 registry.register(Box::new(TrimStartMethod));
1758 registry.register_method(trim_start);
1759
1760 let trim_end = Arc::new(TrimEndMethod);
1762 registry.register(Box::new(TrimEndMethod));
1763 registry.register_method(trim_end);
1764
1765 let length = Arc::new(LengthMethod);
1767 registry.register(Box::new(LengthMethod));
1768 registry.register_method(length);
1769
1770 let contains = Arc::new(ContainsMethod);
1772 registry.register(Box::new(ContainsMethod));
1773 registry.register_method(contains);
1774
1775 let starts_with = Arc::new(StartsWithMethod);
1777 registry.register(Box::new(StartsWithMethod));
1778 registry.register_method(starts_with);
1779
1780 let ends_with = Arc::new(EndsWithMethod);
1782 registry.register(Box::new(EndsWithMethod));
1783 registry.register_method(ends_with);
1784
1785 let substring = Arc::new(SubstringMethod);
1787 registry.register(Box::new(SubstringMethod));
1788 registry.register_method(substring);
1789
1790 let replace = Arc::new(ReplaceMethod);
1792 registry.register(Box::new(ReplaceMethod));
1793 registry.register_method(replace);
1794
1795 let indexof = Arc::new(IndexOfMethod);
1797 registry.register(Box::new(IndexOfMethod));
1798 registry.register_method(indexof.clone());
1799 registry.register(Box::new(InstrFunction));
1801
1802 registry.register(Box::new(ChrFunction));
1804
1805 registry.register(Box::new(LoremIpsumFunction));
1807}