1use crate::data::datatable::DataValue;
2use crate::sql::functions::{ArgCount, FunctionCategory, FunctionSignature, SqlFunction};
3use anyhow::{anyhow, Result};
4
5const ANSI_RESET: &str = "\x1b[0m";
7
8fn get_color_code(color_name: &str) -> Option<&'static str> {
10 match color_name.to_lowercase().as_str() {
11 "black" => Some("\x1b[30m"),
13 "red" => Some("\x1b[31m"),
14 "green" => Some("\x1b[32m"),
15 "yellow" => Some("\x1b[33m"),
16 "blue" => Some("\x1b[34m"),
17 "magenta" | "purple" => Some("\x1b[35m"),
18 "cyan" => Some("\x1b[36m"),
19 "white" => Some("\x1b[37m"),
20 "bright_black" | "gray" | "grey" => Some("\x1b[90m"),
22 "bright_red" => Some("\x1b[91m"),
23 "bright_green" => Some("\x1b[92m"),
24 "bright_yellow" => Some("\x1b[93m"),
25 "bright_blue" => Some("\x1b[94m"),
26 "bright_magenta" | "bright_purple" => Some("\x1b[95m"),
27 "bright_cyan" => Some("\x1b[96m"),
28 "bright_white" => Some("\x1b[97m"),
29 _ => None,
30 }
31}
32
33fn get_bg_color_code(color_name: &str) -> Option<&'static str> {
35 match color_name.to_lowercase().as_str() {
36 "black" => Some("\x1b[40m"),
38 "red" => Some("\x1b[41m"),
39 "green" => Some("\x1b[42m"),
40 "yellow" => Some("\x1b[43m"),
41 "blue" => Some("\x1b[44m"),
42 "magenta" | "purple" => Some("\x1b[45m"),
43 "cyan" => Some("\x1b[46m"),
44 "white" => Some("\x1b[47m"),
45 "bright_black" | "gray" | "grey" => Some("\x1b[100m"),
47 "bright_red" => Some("\x1b[101m"),
48 "bright_green" => Some("\x1b[102m"),
49 "bright_yellow" => Some("\x1b[103m"),
50 "bright_blue" => Some("\x1b[104m"),
51 "bright_magenta" | "bright_purple" => Some("\x1b[105m"),
52 "bright_cyan" => Some("\x1b[106m"),
53 "bright_white" => Some("\x1b[107m"),
54 _ => None,
55 }
56}
57
58pub struct AnsiColorFunction;
60
61impl SqlFunction for AnsiColorFunction {
62 fn signature(&self) -> FunctionSignature {
63 FunctionSignature {
64 name: "ANSI_COLOR",
65 category: FunctionCategory::Terminal,
66 arg_count: ArgCount::Fixed(2),
67 description: "Apply ANSI foreground color to text",
68 returns: "Colored text with ANSI escape codes",
69 examples: vec![
70 "SELECT ANSI_COLOR('red', 'ERROR')",
71 "SELECT ANSI_COLOR('green', 'SUCCESS')",
72 "SELECT ANSI_COLOR('yellow', amount) FROM sales",
73 "SELECT ANSI_COLOR('bright_blue', order_id) FROM orders",
74 ],
75 }
76 }
77
78 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
79 self.validate_args(args)?;
80
81 let color_name = match &args[0] {
82 DataValue::String(s) => s.as_str(),
83 DataValue::InternedString(s) => s.as_str(),
84 DataValue::Null => return Ok(args[1].clone()),
85 _ => return Err(anyhow!("ANSI_COLOR: first argument must be a color name")),
86 };
87
88 let text = match &args[1] {
89 DataValue::String(s) => s.clone(),
90 DataValue::InternedString(s) => s.to_string(),
91 DataValue::Integer(n) => n.to_string(),
92 DataValue::Float(f) => f.to_string(),
93 DataValue::Null => return Ok(DataValue::Null),
94 _ => args[1].to_string(),
95 };
96
97 let color_code = get_color_code(color_name).ok_or_else(|| {
98 anyhow!(
99 "ANSI_COLOR: unknown color '{}'. Available: black, red, green, yellow, blue, magenta, cyan, white, bright_* variants",
100 color_name
101 )
102 })?;
103
104 Ok(DataValue::String(format!(
105 "{}{}{}",
106 color_code, text, ANSI_RESET
107 )))
108 }
109}
110
111pub struct AnsiBgFunction;
113
114impl SqlFunction for AnsiBgFunction {
115 fn signature(&self) -> FunctionSignature {
116 FunctionSignature {
117 name: "ANSI_BG",
118 category: FunctionCategory::Terminal,
119 arg_count: ArgCount::Fixed(2),
120 description: "Apply ANSI background color to text",
121 returns: "Text with colored background using ANSI escape codes",
122 examples: vec![
123 "SELECT ANSI_BG('red', 'CRITICAL')",
124 "SELECT ANSI_BG('green', 'ACTIVE')",
125 "SELECT ANSI_BG('yellow', 'WARNING')",
126 ],
127 }
128 }
129
130 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
131 self.validate_args(args)?;
132
133 let color_name = match &args[0] {
134 DataValue::String(s) => s.as_str(),
135 DataValue::InternedString(s) => s.as_str(),
136 DataValue::Null => return Ok(args[1].clone()),
137 _ => return Err(anyhow!("ANSI_BG: first argument must be a color name")),
138 };
139
140 let text = match &args[1] {
141 DataValue::String(s) => s.clone(),
142 DataValue::InternedString(s) => s.to_string(),
143 DataValue::Integer(n) => n.to_string(),
144 DataValue::Float(f) => f.to_string(),
145 DataValue::Null => return Ok(DataValue::Null),
146 _ => args[1].to_string(),
147 };
148
149 let color_code = get_bg_color_code(color_name).ok_or_else(|| {
150 anyhow!(
151 "ANSI_BG: unknown color '{}'. Available: black, red, green, yellow, blue, magenta, cyan, white, bright_* variants",
152 color_name
153 )
154 })?;
155
156 Ok(DataValue::String(format!(
157 "{}{}{}",
158 color_code, text, ANSI_RESET
159 )))
160 }
161}
162
163pub struct AnsiRgbFunction;
165
166impl SqlFunction for AnsiRgbFunction {
167 fn signature(&self) -> FunctionSignature {
168 FunctionSignature {
169 name: "ANSI_RGB",
170 category: FunctionCategory::Terminal,
171 arg_count: ArgCount::Fixed(4),
172 description: "Apply RGB foreground color to text (0-255 for each component)",
173 returns: "Text colored with RGB value using ANSI escape codes",
174 examples: vec![
175 "SELECT ANSI_RGB(255, 0, 0, 'Bright Red')",
176 "SELECT ANSI_RGB(0, 255, 0, 'Bright Green')",
177 "SELECT ANSI_RGB(255, 165, 0, 'Orange')",
178 "SELECT ANSI_RGB(138, 43, 226, 'Blue Violet')",
179 ],
180 }
181 }
182
183 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
184 self.validate_args(args)?;
185
186 let r = match &args[0] {
187 DataValue::Integer(n) => {
188 if *n < 0 || *n > 255 {
189 return Err(anyhow!("ANSI_RGB: red value must be 0-255, got {}", n));
190 }
191 *n as u8
192 }
193 _ => return Err(anyhow!("ANSI_RGB: red value must be an integer")),
194 };
195
196 let g = match &args[1] {
197 DataValue::Integer(n) => {
198 if *n < 0 || *n > 255 {
199 return Err(anyhow!("ANSI_RGB: green value must be 0-255, got {}", n));
200 }
201 *n as u8
202 }
203 _ => return Err(anyhow!("ANSI_RGB: green value must be an integer")),
204 };
205
206 let b = match &args[2] {
207 DataValue::Integer(n) => {
208 if *n < 0 || *n > 255 {
209 return Err(anyhow!("ANSI_RGB: blue value must be 0-255, got {}", n));
210 }
211 *n as u8
212 }
213 _ => return Err(anyhow!("ANSI_RGB: blue value must be an integer")),
214 };
215
216 let text = match &args[3] {
217 DataValue::String(s) => s.clone(),
218 DataValue::InternedString(s) => s.to_string(),
219 DataValue::Integer(n) => n.to_string(),
220 DataValue::Float(f) => f.to_string(),
221 DataValue::Null => return Ok(DataValue::Null),
222 _ => args[3].to_string(),
223 };
224
225 Ok(DataValue::String(format!(
227 "\x1b[38;2;{};{};{}m{}{}",
228 r, g, b, text, ANSI_RESET
229 )))
230 }
231}
232
233pub struct AnsiRgbBgFunction;
235
236impl SqlFunction for AnsiRgbBgFunction {
237 fn signature(&self) -> FunctionSignature {
238 FunctionSignature {
239 name: "ANSI_RGB_BG",
240 category: FunctionCategory::Terminal,
241 arg_count: ArgCount::Fixed(4),
242 description: "Apply RGB background color to text (0-255 for each component)",
243 returns: "Text with RGB background using ANSI escape codes",
244 examples: vec![
245 "SELECT ANSI_RGB_BG(255, 0, 0, 'Red Background')",
246 "SELECT ANSI_RGB_BG(0, 128, 0, 'Dark Green BG')",
247 ],
248 }
249 }
250
251 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
252 self.validate_args(args)?;
253
254 let r = match &args[0] {
255 DataValue::Integer(n) => {
256 if *n < 0 || *n > 255 {
257 return Err(anyhow!("ANSI_RGB_BG: red value must be 0-255, got {}", n));
258 }
259 *n as u8
260 }
261 _ => return Err(anyhow!("ANSI_RGB_BG: red value must be an integer")),
262 };
263
264 let g = match &args[1] {
265 DataValue::Integer(n) => {
266 if *n < 0 || *n > 255 {
267 return Err(anyhow!("ANSI_RGB_BG: green value must be 0-255, got {}", n));
268 }
269 *n as u8
270 }
271 _ => return Err(anyhow!("ANSI_RGB_BG: green value must be an integer")),
272 };
273
274 let b = match &args[2] {
275 DataValue::Integer(n) => {
276 if *n < 0 || *n > 255 {
277 return Err(anyhow!("ANSI_RGB_BG: blue value must be 0-255, got {}", n));
278 }
279 *n as u8
280 }
281 _ => return Err(anyhow!("ANSI_RGB_BG: blue value must be an integer")),
282 };
283
284 let text = match &args[3] {
285 DataValue::String(s) => s.clone(),
286 DataValue::InternedString(s) => s.to_string(),
287 DataValue::Integer(n) => n.to_string(),
288 DataValue::Float(f) => f.to_string(),
289 DataValue::Null => return Ok(DataValue::Null),
290 _ => args[3].to_string(),
291 };
292
293 Ok(DataValue::String(format!(
295 "\x1b[48;2;{};{};{}m{}{}",
296 r, g, b, text, ANSI_RESET
297 )))
298 }
299}
300
301pub struct AnsiBoldFunction;
303
304impl SqlFunction for AnsiBoldFunction {
305 fn signature(&self) -> FunctionSignature {
306 FunctionSignature {
307 name: "ANSI_BOLD",
308 category: FunctionCategory::Terminal,
309 arg_count: ArgCount::Fixed(1),
310 description: "Make text bold using ANSI escape codes",
311 returns: "Bold text",
312 examples: vec![
313 "SELECT ANSI_BOLD('Important')",
314 "SELECT ANSI_BOLD(total) FROM sales",
315 ],
316 }
317 }
318
319 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
320 self.validate_args(args)?;
321
322 let text = match &args[0] {
323 DataValue::String(s) => s.clone(),
324 DataValue::InternedString(s) => s.to_string(),
325 DataValue::Integer(n) => n.to_string(),
326 DataValue::Float(f) => f.to_string(),
327 DataValue::Null => return Ok(DataValue::Null),
328 _ => args[0].to_string(),
329 };
330
331 Ok(DataValue::String(format!("\x1b[1m{}{}", text, ANSI_RESET)))
332 }
333}
334
335pub struct AnsiItalicFunction;
337
338impl SqlFunction for AnsiItalicFunction {
339 fn signature(&self) -> FunctionSignature {
340 FunctionSignature {
341 name: "ANSI_ITALIC",
342 category: FunctionCategory::Terminal,
343 arg_count: ArgCount::Fixed(1),
344 description: "Make text italic using ANSI escape codes",
345 returns: "Italic text",
346 examples: vec!["SELECT ANSI_ITALIC('Emphasized')"],
347 }
348 }
349
350 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
351 self.validate_args(args)?;
352
353 let text = match &args[0] {
354 DataValue::String(s) => s.clone(),
355 DataValue::InternedString(s) => s.to_string(),
356 DataValue::Integer(n) => n.to_string(),
357 DataValue::Float(f) => f.to_string(),
358 DataValue::Null => return Ok(DataValue::Null),
359 _ => args[0].to_string(),
360 };
361
362 Ok(DataValue::String(format!("\x1b[3m{}{}", text, ANSI_RESET)))
363 }
364}
365
366pub struct AnsiUnderlineFunction;
368
369impl SqlFunction for AnsiUnderlineFunction {
370 fn signature(&self) -> FunctionSignature {
371 FunctionSignature {
372 name: "ANSI_UNDERLINE",
373 category: FunctionCategory::Terminal,
374 arg_count: ArgCount::Fixed(1),
375 description: "Underline text using ANSI escape codes",
376 returns: "Underlined text",
377 examples: vec!["SELECT ANSI_UNDERLINE('Important')"],
378 }
379 }
380
381 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
382 self.validate_args(args)?;
383
384 let text = match &args[0] {
385 DataValue::String(s) => s.clone(),
386 DataValue::InternedString(s) => s.to_string(),
387 DataValue::Integer(n) => n.to_string(),
388 DataValue::Float(f) => f.to_string(),
389 DataValue::Null => return Ok(DataValue::Null),
390 _ => args[0].to_string(),
391 };
392
393 Ok(DataValue::String(format!("\x1b[4m{}{}", text, ANSI_RESET)))
394 }
395}
396
397pub struct AnsiBlinkFunction;
399
400impl SqlFunction for AnsiBlinkFunction {
401 fn signature(&self) -> FunctionSignature {
402 FunctionSignature {
403 name: "ANSI_BLINK",
404 category: FunctionCategory::Terminal,
405 arg_count: ArgCount::Fixed(1),
406 description: "Make text blink using ANSI escape codes",
407 returns: "Blinking text",
408 examples: vec!["SELECT ANSI_BLINK('ALERT')"],
409 }
410 }
411
412 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
413 self.validate_args(args)?;
414
415 let text = match &args[0] {
416 DataValue::String(s) => s.clone(),
417 DataValue::InternedString(s) => s.to_string(),
418 DataValue::Integer(n) => n.to_string(),
419 DataValue::Float(f) => f.to_string(),
420 DataValue::Null => return Ok(DataValue::Null),
421 _ => args[0].to_string(),
422 };
423
424 Ok(DataValue::String(format!("\x1b[5m{}{}", text, ANSI_RESET)))
425 }
426}
427
428pub struct AnsiReverseFunction;
430
431impl SqlFunction for AnsiReverseFunction {
432 fn signature(&self) -> FunctionSignature {
433 FunctionSignature {
434 name: "ANSI_REVERSE",
435 category: FunctionCategory::Terminal,
436 arg_count: ArgCount::Fixed(1),
437 description: "Reverse video (swap foreground and background colors)",
438 returns: "Text with reversed colors",
439 examples: vec!["SELECT ANSI_REVERSE('Highlighted')"],
440 }
441 }
442
443 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
444 self.validate_args(args)?;
445
446 let text = match &args[0] {
447 DataValue::String(s) => s.clone(),
448 DataValue::InternedString(s) => s.to_string(),
449 DataValue::Integer(n) => n.to_string(),
450 DataValue::Float(f) => f.to_string(),
451 DataValue::Null => return Ok(DataValue::Null),
452 _ => args[0].to_string(),
453 };
454
455 Ok(DataValue::String(format!("\x1b[7m{}{}", text, ANSI_RESET)))
456 }
457}
458
459pub struct AnsiStrikethroughFunction;
461
462impl SqlFunction for AnsiStrikethroughFunction {
463 fn signature(&self) -> FunctionSignature {
464 FunctionSignature {
465 name: "ANSI_STRIKETHROUGH",
466 category: FunctionCategory::Terminal,
467 arg_count: ArgCount::Fixed(1),
468 description: "Add strikethrough to text using ANSI escape codes",
469 returns: "Strikethrough text",
470 examples: vec!["SELECT ANSI_STRIKETHROUGH('Deprecated')"],
471 }
472 }
473
474 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
475 self.validate_args(args)?;
476
477 let text = match &args[0] {
478 DataValue::String(s) => s.clone(),
479 DataValue::InternedString(s) => s.to_string(),
480 DataValue::Integer(n) => n.to_string(),
481 DataValue::Float(f) => f.to_string(),
482 DataValue::Null => return Ok(DataValue::Null),
483 _ => args[0].to_string(),
484 };
485
486 Ok(DataValue::String(format!("\x1b[9m{}{}", text, ANSI_RESET)))
487 }
488}