1use gitql_ast::types::boolean::BoolType;
2use gitql_ast::types::integer::IntType;
3use gitql_ast::types::text::TextType;
4use gitql_core::signature::Signature;
5use gitql_core::signature::StandardFunction;
6use gitql_core::values::boolean::BoolValue;
7use gitql_core::values::integer::IntValue;
8use gitql_core::values::text::TextValue;
9use gitql_core::values::Value;
10
11use std::collections::HashMap;
12
13use regex::Regex;
14
15#[inline(always)]
16pub fn register_std_regex_functions(map: &mut HashMap<&'static str, StandardFunction>) {
17 map.insert("regexp_instr", regexp_instr);
18 map.insert("regexp_like", regexp_like);
19 map.insert("regexp_replace", regexp_replace);
20 map.insert("regexp_substr", regexp_substr);
21}
22
23#[inline(always)]
24pub fn register_std_regex_function_signatures(map: &mut HashMap<&'static str, Signature>) {
25 map.insert(
26 "regexp_instr",
27 Signature {
28 parameters: vec![Box::new(TextType), Box::new(TextType)],
29 return_type: Box::new(IntType),
30 },
31 );
32 map.insert(
33 "regexp_like",
34 Signature {
35 parameters: vec![Box::new(TextType), Box::new(TextType)],
36 return_type: Box::new(BoolType),
37 },
38 );
39 map.insert(
40 "regexp_replace",
41 Signature {
42 parameters: vec![Box::new(TextType), Box::new(TextType), Box::new(TextType)],
43 return_type: Box::new(TextType),
44 },
45 );
46 map.insert(
47 "regexp_substr",
48 Signature {
49 parameters: vec![Box::new(TextType), Box::new(TextType)],
50 return_type: Box::new(TextType),
51 },
52 );
53}
54
55pub fn regexp_instr(inputs: &[Box<dyn Value>]) -> Box<dyn Value> {
59 let input = inputs[0].as_text().unwrap();
60 let pattern = inputs[1].as_text().unwrap();
61 if let Ok(regex) = Regex::new(&pattern) {
62 if let Some(match_result) = regex.find(&input) {
63 let value = (match_result.start() + 1) as i64;
64 return Box::new(IntValue { value });
65 }
66 }
67 Box::new(IntValue { value: -1 })
68}
69
70pub fn regexp_like(inputs: &[Box<dyn Value>]) -> Box<dyn Value> {
72 let input = inputs[0].as_text().unwrap();
73 let pattern = inputs[1].as_text().unwrap();
74 if let Ok(regex) = Regex::new(&pattern) {
75 return Box::new(BoolValue {
76 value: regex.is_match(&input),
77 });
78 }
79 Box::new(BoolValue { value: false })
80}
81
82pub fn regexp_replace(inputs: &[Box<dyn Value>]) -> Box<dyn Value> {
85 let input = inputs[0].as_text().unwrap();
86 let pattern = inputs[1].as_text().unwrap();
87 let replacement = inputs[2].as_text().unwrap();
88 if let Ok(regex) = Regex::new(&pattern) {
89 let value = regex.replace_all(&input, replacement).to_string();
90 return Box::new(TextValue { value });
91 }
92 Box::new(TextValue { value: input })
93}
94
95pub fn regexp_substr(inputs: &[Box<dyn Value>]) -> Box<dyn Value> {
97 let input = inputs[0].as_text().unwrap();
98 let pattern = inputs[1].as_text().unwrap();
99 if let Ok(regex) = Regex::new(&pattern) {
100 if let Some(mat) = regex.find(&input) {
101 return Box::new(TextValue {
102 value: mat.as_str().to_string(),
103 });
104 }
105 }
106 Box::new(TextValue {
107 value: "".to_string(),
108 })
109}