Skip to main content

drasi_core/evaluation/functions/text/
text.rs

1// Copyright 2024 The Drasi Authors.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use crate::evaluation::variable_value::VariableValue;
16use async_trait::async_trait;
17use drasi_query_ast::ast;
18
19use crate::evaluation::functions::ScalarFunction;
20use crate::evaluation::{ExpressionEvaluationContext, FunctionError, FunctionEvaluationError};
21
22#[derive(Debug, PartialEq)]
23pub struct ToUpper {}
24
25#[async_trait]
26impl ScalarFunction for ToUpper {
27    async fn call(
28        &self,
29        _context: &ExpressionEvaluationContext,
30        expression: &ast::FunctionExpression,
31        args: Vec<VariableValue>,
32    ) -> Result<VariableValue, FunctionError> {
33        if args.len() != 1 {
34            return Err(FunctionError {
35                function_name: expression.name.to_string(),
36                error: FunctionEvaluationError::InvalidArgumentCount,
37            });
38        }
39        match &args[0] {
40            VariableValue::String(s) => Ok(VariableValue::String(s.to_uppercase())),
41            VariableValue::Null => Ok(VariableValue::Null),
42            _ => Err(FunctionError {
43                function_name: expression.name.to_string(),
44                error: FunctionEvaluationError::InvalidArgument(0),
45            }),
46        }
47    }
48}
49
50#[derive(Debug)]
51pub struct ToLower {}
52
53#[async_trait]
54impl ScalarFunction for ToLower {
55    async fn call(
56        &self,
57        _context: &ExpressionEvaluationContext,
58        expression: &ast::FunctionExpression,
59        args: Vec<VariableValue>,
60    ) -> Result<VariableValue, FunctionError> {
61        if args.len() != 1 {
62            return Err(FunctionError {
63                function_name: expression.name.to_string(),
64                error: FunctionEvaluationError::InvalidArgumentCount,
65            });
66        }
67        match &args[0] {
68            VariableValue::String(s) => Ok(VariableValue::String(s.to_lowercase())),
69            VariableValue::Null => Ok(VariableValue::Null),
70            _ => Err(FunctionError {
71                function_name: expression.name.to_string(),
72                error: FunctionEvaluationError::InvalidArgument(0),
73            }),
74        }
75    }
76}
77
78#[derive(Debug)]
79pub struct Trim {}
80
81#[async_trait]
82impl ScalarFunction for Trim {
83    async fn call(
84        &self,
85        _context: &ExpressionEvaluationContext,
86        expression: &ast::FunctionExpression,
87        args: Vec<VariableValue>,
88    ) -> Result<VariableValue, FunctionError> {
89        if args.len() != 1 {
90            return Err(FunctionError {
91                function_name: expression.name.to_string(),
92                error: FunctionEvaluationError::InvalidArgumentCount,
93            });
94        }
95        match &args[0] {
96            VariableValue::String(s) => Ok(VariableValue::String(s.trim().to_string())),
97            VariableValue::Null => Ok(VariableValue::Null),
98            _ => Err(FunctionError {
99                function_name: expression.name.to_string(),
100                error: FunctionEvaluationError::InvalidArgument(0),
101            }),
102        }
103    }
104}
105
106#[derive(Debug)]
107pub struct LTrim {}
108
109#[async_trait]
110impl ScalarFunction for LTrim {
111    async fn call(
112        &self,
113        _context: &ExpressionEvaluationContext,
114        expression: &ast::FunctionExpression,
115        args: Vec<VariableValue>,
116    ) -> Result<VariableValue, FunctionError> {
117        if args.len() != 1 {
118            return Err(FunctionError {
119                function_name: expression.name.to_string(),
120                error: FunctionEvaluationError::InvalidArgumentCount,
121            });
122        }
123        match &args[0] {
124            VariableValue::String(s) => Ok(VariableValue::String(s.trim_start().to_string())),
125            VariableValue::Null => Ok(VariableValue::Null),
126            _ => Err(FunctionError {
127                function_name: expression.name.to_string(),
128                error: FunctionEvaluationError::InvalidArgument(0),
129            }),
130        }
131    }
132}
133
134#[derive(Debug)]
135pub struct RTrim {}
136
137#[async_trait]
138impl ScalarFunction for RTrim {
139    async fn call(
140        &self,
141        _context: &ExpressionEvaluationContext,
142        expression: &ast::FunctionExpression,
143        args: Vec<VariableValue>,
144    ) -> Result<VariableValue, FunctionError> {
145        if args.len() != 1 {
146            return Err(FunctionError {
147                function_name: expression.name.to_string(),
148                error: FunctionEvaluationError::InvalidArgumentCount,
149            });
150        }
151        match &args[0] {
152            VariableValue::String(s) => Ok(VariableValue::String(s.trim_end().to_string())),
153            VariableValue::Null => Ok(VariableValue::Null),
154            _ => Err(FunctionError {
155                function_name: expression.name.to_string(),
156                error: FunctionEvaluationError::InvalidArgument(0),
157            }),
158        }
159    }
160}
161
162#[derive(Debug)]
163pub struct Reverse {}
164
165#[async_trait]
166impl ScalarFunction for Reverse {
167    async fn call(
168        &self,
169        _context: &ExpressionEvaluationContext,
170        expression: &ast::FunctionExpression,
171        args: Vec<VariableValue>,
172    ) -> Result<VariableValue, FunctionError> {
173        if args.len() != 1 {
174            return Err(FunctionError {
175                function_name: expression.name.to_string(),
176                error: FunctionEvaluationError::InvalidArgumentCount,
177            });
178        }
179        match &args[0] {
180            VariableValue::String(s) => Ok(VariableValue::String(s.chars().rev().collect())),
181            VariableValue::List(l) => {
182                let mut l = l.clone();
183                l.reverse();
184                Ok(VariableValue::List(l))
185            }
186            VariableValue::Null => Ok(VariableValue::Null),
187            _ => Err(FunctionError {
188                function_name: expression.name.to_string(),
189                error: FunctionEvaluationError::InvalidArgument(0),
190            }),
191        }
192    }
193}
194
195#[derive(Debug)]
196pub struct Left {}
197
198#[async_trait]
199impl ScalarFunction for Left {
200    async fn call(
201        &self,
202        _context: &ExpressionEvaluationContext,
203        expression: &ast::FunctionExpression,
204        args: Vec<VariableValue>,
205    ) -> Result<VariableValue, FunctionError> {
206        if args.len() != 2 {
207            return Err(FunctionError {
208                function_name: expression.name.to_string(),
209                error: FunctionEvaluationError::InvalidArgumentCount,
210            });
211        }
212        match (&args[0], &args[1]) {
213            (VariableValue::Null, VariableValue::Integer(_length)) => Ok(VariableValue::Null),
214            (VariableValue::Null, VariableValue::Null) => Ok(VariableValue::Null),
215            (VariableValue::String(original), VariableValue::Integer(length)) => {
216                let len = match length.as_i64() {
217                    Some(l) => {
218                        if l <= 0 {
219                            return Err(FunctionError {
220                                function_name: expression.name.to_string(),
221                                error: FunctionEvaluationError::OverflowError,
222                            });
223                        }
224                        l as usize
225                    }
226                    None => {
227                        return Err(FunctionError {
228                            function_name: expression.name.to_string(),
229                            error: FunctionEvaluationError::InvalidArgument(1),
230                        })
231                    }
232                };
233                if len > original.len() {
234                    return Ok(VariableValue::String(original.to_string()));
235                }
236                let result = original.chars().take(len).collect::<String>();
237                Ok(VariableValue::String(result))
238            }
239            (VariableValue::String(_original), _) => {
240                return Err(FunctionError {
241                    function_name: expression.name.to_string(),
242                    error: FunctionEvaluationError::InvalidArgument(1),
243                })
244            }
245            _ => Err(FunctionError {
246                function_name: expression.name.to_string(),
247                error: FunctionEvaluationError::InvalidArgument(0),
248            }),
249        }
250    }
251}
252
253#[derive(Debug)]
254pub struct Right {}
255
256#[async_trait]
257impl ScalarFunction for Right {
258    async fn call(
259        &self,
260        _context: &ExpressionEvaluationContext,
261        expression: &ast::FunctionExpression,
262        args: Vec<VariableValue>,
263    ) -> Result<VariableValue, FunctionError> {
264        if args.len() != 2 {
265            return Err(FunctionError {
266                function_name: expression.name.to_string(),
267                error: FunctionEvaluationError::InvalidArgumentCount,
268            });
269        }
270        match (&args[0], &args[1]) {
271            (VariableValue::Null, VariableValue::Integer(_length)) => Ok(VariableValue::Null),
272            (VariableValue::Null, VariableValue::Null) => Ok(VariableValue::Null),
273            (VariableValue::String(original), VariableValue::Integer(length)) => {
274                let len = match length.as_i64() {
275                    Some(l) => {
276                        if l <= 0 {
277                            return Err(FunctionError {
278                                function_name: expression.name.to_string(),
279                                error: FunctionEvaluationError::OverflowError,
280                            });
281                        }
282                        l as usize
283                    }
284                    None => {
285                        return Err(FunctionError {
286                            function_name: expression.name.to_string(),
287                            error: FunctionEvaluationError::InvalidArgument(1),
288                        })
289                    }
290                };
291                if len > original.len() {
292                    return Ok(VariableValue::String(original.to_string()));
293                }
294                let start_index = original.len() - len;
295                let result = original[start_index..].to_string();
296                Ok(VariableValue::String(result))
297            }
298            (VariableValue::String(_), _) => {
299                return Err(FunctionError {
300                    function_name: expression.name.to_string(),
301                    error: FunctionEvaluationError::InvalidArgument(1),
302                })
303            }
304            _ => Err(FunctionError {
305                function_name: expression.name.to_string(),
306                error: FunctionEvaluationError::InvalidArgument(0),
307            }),
308        }
309    }
310}
311
312#[derive(Debug)]
313pub struct Replace {}
314
315#[async_trait]
316impl ScalarFunction for Replace {
317    async fn call(
318        &self,
319        _context: &ExpressionEvaluationContext,
320        expression: &ast::FunctionExpression,
321        args: Vec<VariableValue>,
322    ) -> Result<VariableValue, FunctionError> {
323        if args.len() != 3 {
324            return Err(FunctionError {
325                function_name: expression.name.to_string(),
326                error: FunctionEvaluationError::InvalidArgumentCount,
327            });
328        }
329        match (&args[0], &args[1], &args[2]) {
330            (
331                VariableValue::String(original),
332                VariableValue::String(search),
333                VariableValue::String(replace),
334            ) => {
335                if search.is_empty() {
336                    return Ok(VariableValue::String(original.to_string()));
337                }
338                let result = original.replace(search, replace);
339                return Ok(VariableValue::String(result));
340            }
341
342            (VariableValue::Null, _, _) => Ok(VariableValue::Null),
343            (_, VariableValue::Null, _) => Ok(VariableValue::Null),
344            (_, _, VariableValue::Null) => Ok(VariableValue::Null),
345            (VariableValue::String(_), VariableValue::String(_), _) => Err(FunctionError {
346                function_name: expression.name.to_string(),
347                error: FunctionEvaluationError::InvalidArgument(2),
348            }),
349            (_, VariableValue::String(_), _) => Err(FunctionError {
350                function_name: expression.name.to_string(),
351                error: FunctionEvaluationError::InvalidArgument(0),
352            }),
353            _ => Err(FunctionError {
354                function_name: expression.name.to_string(),
355                error: FunctionEvaluationError::InvalidArgument(0),
356            }),
357        }
358    }
359}
360
361#[derive(Debug)]
362pub struct Split {}
363
364#[async_trait]
365impl ScalarFunction for Split {
366    async fn call(
367        &self,
368        _context: &ExpressionEvaluationContext,
369        expression: &ast::FunctionExpression,
370        args: Vec<VariableValue>,
371    ) -> Result<VariableValue, FunctionError> {
372        if args.len() != 2 {
373            return Err(FunctionError {
374                function_name: expression.name.to_string(),
375                error: FunctionEvaluationError::InvalidArgumentCount,
376            });
377        }
378        match (&args[0], &args[1]) {
379            (VariableValue::Null, _) => Ok(VariableValue::Null),
380            (_, VariableValue::Null) => Ok(VariableValue::Null),
381            (VariableValue::String(original), VariableValue::String(separator)) => {
382                if separator.is_empty() {
383                    return Err(FunctionError {
384                        function_name: expression.name.to_string(),
385                        error: FunctionEvaluationError::InvalidArgument(1),
386                    });
387                }
388                let result = original
389                    .split(separator)
390                    .map(|s| VariableValue::String(s.to_string()))
391                    .collect::<Vec<VariableValue>>();
392                return Ok(VariableValue::List(result));
393            }
394            (VariableValue::String(original), VariableValue::List(delimiters)) => {
395                // An array of delimiters
396                let mut delimiters_vector = Vec::new();
397                let mut result = Vec::new();
398                let mut current_word = String::new();
399
400                for delimiter in delimiters {
401                    match delimiter {
402                        VariableValue::String(s) => delimiters_vector.push(s),
403                        _ => {
404                            return Err(FunctionError {
405                                function_name: expression.name.to_string(),
406                                error: FunctionEvaluationError::InvalidArgument(1),
407                            })
408                        }
409                    }
410                }
411                for c in original.chars() {
412                    if delimiters_vector.iter().any(|d| d.contains(c)) {
413                        if !current_word.is_empty() {
414                            result.push(VariableValue::String(current_word.clone()));
415                            current_word.clear();
416                        }
417                    } else {
418                        current_word.push(c);
419                    }
420                }
421                if !current_word.is_empty() {
422                    result.push(VariableValue::String(current_word));
423                }
424                return Ok(VariableValue::List(result));
425            }
426            _ => Err(FunctionError {
427                function_name: expression.name.to_string(),
428                error: FunctionEvaluationError::InvalidArgument(0),
429            }),
430        }
431    }
432}
433
434#[derive(Debug)]
435pub struct Substring {}
436
437#[async_trait]
438impl ScalarFunction for Substring {
439    async fn call(
440        &self,
441        _context: &ExpressionEvaluationContext,
442        expression: &ast::FunctionExpression,
443        args: Vec<VariableValue>,
444    ) -> Result<VariableValue, FunctionError> {
445        if args.len() < 2 || args.len() > 3 {
446            return Err(FunctionError {
447                function_name: expression.name.to_string(),
448                error: FunctionEvaluationError::InvalidArgumentCount,
449            });
450        }
451        match (&args[0], &args[1], &args.get(2)) {
452            (VariableValue::Null, _, _) => Ok(VariableValue::Null),
453            (_, VariableValue::Null, _) => Err(FunctionError {
454                function_name: expression.name.to_string(),
455                error: FunctionEvaluationError::InvalidArgument(1),
456            }),
457            (_, _, Some(VariableValue::Null)) => Err(FunctionError {
458                function_name: expression.name.to_string(),
459                error: FunctionEvaluationError::InvalidArgument(2),
460            }),
461            (VariableValue::String(original), VariableValue::Integer(start), None) => {
462                // Handle case with two arguments
463                let start_index = match start.as_i64() {
464                    Some(s) => {
465                        if s < 0 {
466                            return Err(FunctionError {
467                                function_name: expression.name.to_string(),
468                                error: FunctionEvaluationError::InvalidType {
469                                    expected: "positive integer".to_string(),
470                                },
471                            });
472                        }
473                        s as usize
474                    }
475                    None => {
476                        return Err(FunctionError {
477                            function_name: expression.name.to_string(),
478                            error: FunctionEvaluationError::InvalidArgument(1),
479                        })
480                    }
481                };
482                if start_index > original.len() {
483                    return Err(FunctionError {
484                        function_name: expression.name.to_string(),
485                        error: FunctionEvaluationError::InvalidArgument(1),
486                    });
487                }
488                return Ok(VariableValue::String(original[start_index..].to_string()));
489            }
490            (VariableValue::String(_), _, None) => {
491                return Err(FunctionError {
492                    function_name: expression.name.to_string(),
493                    error: FunctionEvaluationError::InvalidArgument(1),
494                });
495            }
496            (
497                VariableValue::String(original),
498                VariableValue::Integer(start),
499                Some(VariableValue::Integer(length)),
500            ) => {
501                let start_index = match start.as_i64() {
502                    Some(s) => {
503                        if s < 0 {
504                            return Err(FunctionError {
505                                function_name: expression.name.to_string(),
506                                error: FunctionEvaluationError::InvalidType {
507                                    expected: "positive integer".to_string(),
508                                },
509                            });
510                        }
511                        s as usize
512                    }
513                    None => {
514                        return Err(FunctionError {
515                            function_name: expression.name.to_string(),
516                            error: FunctionEvaluationError::InvalidArgument(1),
517                        })
518                    }
519                };
520
521                let len = match length.as_i64() {
522                    Some(l) => {
523                        if l < 0 {
524                            return Err(FunctionError {
525                                function_name: expression.name.to_string(),
526                                error: FunctionEvaluationError::InvalidType {
527                                    expected: "positive integer".to_string(),
528                                },
529                            });
530                        }
531                        l as usize
532                    }
533                    None => {
534                        return Err(FunctionError {
535                            function_name: expression.name.to_string(),
536                            error: FunctionEvaluationError::InvalidArgument(2),
537                        })
538                    }
539                };
540                if start_index > original.len() || start_index + len - start_index > original.len()
541                {
542                    return Err(FunctionError {
543                        function_name: expression.name.to_string(),
544                        error: FunctionEvaluationError::InvalidType {
545                            expected: "Valid index or length".to_string(),
546                        },
547                    });
548                }
549                return Ok(VariableValue::String(
550                    original[start_index..start_index + len].to_string(),
551                ));
552            }
553            (VariableValue::String(_), VariableValue::Integer(_), _) => {
554                return Err(FunctionError {
555                    function_name: expression.name.to_string(),
556                    error: FunctionEvaluationError::InvalidArgument(2),
557                });
558            }
559            _ => {
560                return Err(FunctionError {
561                    function_name: expression.name.to_string(),
562                    error: FunctionEvaluationError::InvalidArgument(0),
563                })
564            }
565        }
566    }
567}
568
569pub struct ToString {}
570
571#[async_trait]
572impl ScalarFunction for ToString {
573    async fn call(
574        &self,
575        _context: &ExpressionEvaluationContext,
576        expression: &ast::FunctionExpression,
577        args: Vec<VariableValue>,
578    ) -> Result<VariableValue, FunctionError> {
579        if args.len() != 1 {
580            return Err(FunctionError {
581                function_name: expression.name.to_string(),
582                error: FunctionEvaluationError::InvalidArgumentCount,
583            });
584        }
585        match &args[0] {
586            VariableValue::Integer(n) => return Ok(VariableValue::String(n.to_string())),
587            VariableValue::Float(n) => return Ok(VariableValue::String(n.to_string())),
588            VariableValue::String(s) => return Ok(VariableValue::String(s.to_string())),
589            VariableValue::Bool(b) => return Ok(VariableValue::String(b.to_string())),
590            VariableValue::List(a) => {
591                let mut result = String::new();
592                result.push('[');
593                for v in a {
594                    result.push_str(&v.to_string());
595                    result.push_str(", ");
596                }
597                result.truncate(result.len() - 2);
598                result.push(']');
599                return Ok(VariableValue::String(result));
600            }
601            VariableValue::Null => return Ok(VariableValue::Null),
602            _ => {
603                return Err(FunctionError {
604                    function_name: expression.name.to_string(),
605                    error: FunctionEvaluationError::InvalidArgument(0),
606                })
607            }
608        }
609    }
610}
611
612pub struct ToStringOrNull {}
613
614#[async_trait]
615impl ScalarFunction for ToStringOrNull {
616    async fn call(
617        &self,
618        _context: &ExpressionEvaluationContext,
619        expression: &ast::FunctionExpression,
620        args: Vec<VariableValue>,
621    ) -> Result<VariableValue, FunctionError> {
622        if args.len() != 1 {
623            return Err(FunctionError {
624                function_name: expression.name.to_string(),
625                error: FunctionEvaluationError::InvalidArgumentCount,
626            });
627        }
628        match &args[0] {
629            VariableValue::Null => return Ok(VariableValue::Null),
630            VariableValue::Integer(n) => return Ok(VariableValue::String(n.to_string())),
631            VariableValue::Float(n) => return Ok(VariableValue::String(n.to_string())),
632            VariableValue::String(s) => return Ok(VariableValue::String(s.to_string())),
633            VariableValue::List(a) => {
634                let mut result = String::new();
635                result.push('[');
636                for v in a {
637                    result.push_str(&v.to_string());
638                    result.push_str(", ");
639                }
640                result.truncate(result.len() - 2);
641                result.push(']');
642                return Ok(VariableValue::String(result));
643            }
644            VariableValue::Object(_o) => {
645                // For objects should return null
646                return Ok(VariableValue::Null);
647            }
648            _ => {
649                return Err(FunctionError {
650                    function_name: expression.name.to_string(),
651                    error: FunctionEvaluationError::InvalidArgument(0),
652                })
653            }
654        }
655    }
656}
657
658#[derive(Debug)]
659pub struct RandomUUID {}
660
661#[async_trait]
662impl ScalarFunction for RandomUUID {
663    async fn call(
664        &self,
665        _context: &ExpressionEvaluationContext,
666        expression: &ast::FunctionExpression,
667        args: Vec<VariableValue>,
668    ) -> Result<VariableValue, FunctionError> {
669        if !args.is_empty() {
670            return Err(FunctionError {
671                function_name: expression.name.to_string(),
672                error: FunctionEvaluationError::InvalidArgumentCount,
673            });
674        }
675        Ok(VariableValue::String(uuid::Uuid::new_v4().to_string()))
676    }
677}