1use anyhow::{anyhow, Result};
2
3use crate::data::datatable::DataValue;
4use crate::sql::functions::{ArgCount, FunctionCategory, FunctionSignature, SqlFunction};
5
6pub struct SinFunction;
8
9impl SqlFunction for SinFunction {
10 fn signature(&self) -> FunctionSignature {
11 FunctionSignature {
12 name: "SIN",
13 category: FunctionCategory::Mathematical,
14 arg_count: ArgCount::Fixed(1),
15 description: "Returns the sine of an angle in radians",
16 returns: "FLOAT",
17 examples: vec![
18 "SELECT SIN(0)", "SELECT SIN(PI()/2)", "SELECT SIN(RADIANS(30))", ],
22 }
23 }
24
25 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
26 self.validate_args(args)?;
27
28 let radians = match &args[0] {
29 DataValue::Integer(n) => *n as f64,
30 DataValue::Float(f) => *f,
31 DataValue::Null => return Ok(DataValue::Null),
32 _ => return Err(anyhow!("SIN requires a numeric argument")),
33 };
34
35 Ok(DataValue::Float(radians.sin()))
36 }
37}
38
39pub struct CosFunction;
41
42impl SqlFunction for CosFunction {
43 fn signature(&self) -> FunctionSignature {
44 FunctionSignature {
45 name: "COS",
46 category: FunctionCategory::Mathematical,
47 arg_count: ArgCount::Fixed(1),
48 description: "Returns the cosine of an angle in radians",
49 returns: "FLOAT",
50 examples: vec![
51 "SELECT COS(0)", "SELECT COS(PI())", "SELECT COS(RADIANS(60))", ],
55 }
56 }
57
58 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
59 self.validate_args(args)?;
60
61 let radians = match &args[0] {
62 DataValue::Integer(n) => *n as f64,
63 DataValue::Float(f) => *f,
64 DataValue::Null => return Ok(DataValue::Null),
65 _ => return Err(anyhow!("COS requires a numeric argument")),
66 };
67
68 Ok(DataValue::Float(radians.cos()))
69 }
70}
71
72pub struct TanFunction;
74
75impl SqlFunction for TanFunction {
76 fn signature(&self) -> FunctionSignature {
77 FunctionSignature {
78 name: "TAN",
79 category: FunctionCategory::Mathematical,
80 arg_count: ArgCount::Fixed(1),
81 description: "Returns the tangent of an angle in radians",
82 returns: "FLOAT",
83 examples: vec![
84 "SELECT TAN(0)", "SELECT TAN(PI()/4)", "SELECT TAN(RADIANS(45))", ],
88 }
89 }
90
91 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
92 self.validate_args(args)?;
93
94 let radians = match &args[0] {
95 DataValue::Integer(n) => *n as f64,
96 DataValue::Float(f) => *f,
97 DataValue::Null => return Ok(DataValue::Null),
98 _ => return Err(anyhow!("TAN requires a numeric argument")),
99 };
100
101 Ok(DataValue::Float(radians.tan()))
102 }
103}
104
105pub struct AsinFunction;
107
108impl SqlFunction for AsinFunction {
109 fn signature(&self) -> FunctionSignature {
110 FunctionSignature {
111 name: "ASIN",
112 category: FunctionCategory::Mathematical,
113 arg_count: ArgCount::Fixed(1),
114 description:
115 "Returns the arcsine (inverse sine) in radians. Input must be between -1 and 1",
116 returns: "FLOAT",
117 examples: vec![
118 "SELECT ASIN(0)", "SELECT ASIN(1)", "SELECT DEGREES(ASIN(0.5))", ],
122 }
123 }
124
125 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
126 self.validate_args(args)?;
127
128 let value = match &args[0] {
129 DataValue::Integer(n) => *n as f64,
130 DataValue::Float(f) => *f,
131 DataValue::Null => return Ok(DataValue::Null),
132 _ => return Err(anyhow!("ASIN requires a numeric argument")),
133 };
134
135 if value < -1.0 || value > 1.0 {
136 return Err(anyhow!(
137 "ASIN input must be between -1 and 1, got {}",
138 value
139 ));
140 }
141
142 Ok(DataValue::Float(value.asin()))
143 }
144}
145
146pub struct AcosFunction;
148
149impl SqlFunction for AcosFunction {
150 fn signature(&self) -> FunctionSignature {
151 FunctionSignature {
152 name: "ACOS",
153 category: FunctionCategory::Mathematical,
154 arg_count: ArgCount::Fixed(1),
155 description:
156 "Returns the arccosine (inverse cosine) in radians. Input must be between -1 and 1",
157 returns: "FLOAT",
158 examples: vec![
159 "SELECT ACOS(1)", "SELECT ACOS(0)", "SELECT DEGREES(ACOS(0.5))", ],
163 }
164 }
165
166 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
167 self.validate_args(args)?;
168
169 let value = match &args[0] {
170 DataValue::Integer(n) => *n as f64,
171 DataValue::Float(f) => *f,
172 DataValue::Null => return Ok(DataValue::Null),
173 _ => return Err(anyhow!("ACOS requires a numeric argument")),
174 };
175
176 if value < -1.0 || value > 1.0 {
177 return Err(anyhow!(
178 "ACOS input must be between -1 and 1, got {}",
179 value
180 ));
181 }
182
183 Ok(DataValue::Float(value.acos()))
184 }
185}
186
187pub struct AtanFunction;
189
190impl SqlFunction for AtanFunction {
191 fn signature(&self) -> FunctionSignature {
192 FunctionSignature {
193 name: "ATAN",
194 category: FunctionCategory::Mathematical,
195 arg_count: ArgCount::Fixed(1),
196 description: "Returns the arctangent (inverse tangent) in radians",
197 returns: "FLOAT",
198 examples: vec![
199 "SELECT ATAN(0)", "SELECT ATAN(1)", "SELECT DEGREES(ATAN(1))", ],
203 }
204 }
205
206 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
207 self.validate_args(args)?;
208
209 let value = match &args[0] {
210 DataValue::Integer(n) => *n as f64,
211 DataValue::Float(f) => *f,
212 DataValue::Null => return Ok(DataValue::Null),
213 _ => return Err(anyhow!("ATAN requires a numeric argument")),
214 };
215
216 Ok(DataValue::Float(value.atan()))
217 }
218}
219
220pub struct Atan2Function;
222
223impl SqlFunction for Atan2Function {
224 fn signature(&self) -> FunctionSignature {
225 FunctionSignature {
226 name: "ATAN2",
227 category: FunctionCategory::Mathematical,
228 arg_count: ArgCount::Fixed(2),
229 description:
230 "Returns the arctangent of y/x in radians, using signs to determine quadrant",
231 returns: "FLOAT",
232 examples: vec![
233 "SELECT ATAN2(1, 1)", "SELECT ATAN2(1, 0)", "SELECT DEGREES(ATAN2(-1, -1))", ],
237 }
238 }
239
240 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
241 self.validate_args(args)?;
242
243 let y = match &args[0] {
244 DataValue::Integer(n) => *n as f64,
245 DataValue::Float(f) => *f,
246 DataValue::Null => return Ok(DataValue::Null),
247 _ => return Err(anyhow!("ATAN2 first argument must be numeric")),
248 };
249
250 let x = match &args[1] {
251 DataValue::Integer(n) => *n as f64,
252 DataValue::Float(f) => *f,
253 DataValue::Null => return Ok(DataValue::Null),
254 _ => return Err(anyhow!("ATAN2 second argument must be numeric")),
255 };
256
257 Ok(DataValue::Float(y.atan2(x)))
258 }
259}
260
261pub struct CotFunction;
263
264impl SqlFunction for CotFunction {
265 fn signature(&self) -> FunctionSignature {
266 FunctionSignature {
267 name: "COT",
268 category: FunctionCategory::Mathematical,
269 arg_count: ArgCount::Fixed(1),
270 description: "Returns the cotangent of an angle in radians (1/tan)",
271 returns: "FLOAT",
272 examples: vec![
273 "SELECT COT(PI()/4)", "SELECT COT(PI()/2)", "SELECT COT(RADIANS(45))", ],
277 }
278 }
279
280 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
281 self.validate_args(args)?;
282
283 let radians = match &args[0] {
284 DataValue::Integer(n) => *n as f64,
285 DataValue::Float(f) => *f,
286 DataValue::Null => return Ok(DataValue::Null),
287 _ => return Err(anyhow!("COT requires a numeric argument")),
288 };
289
290 let tan_val = radians.tan();
291 if tan_val == 0.0 {
292 return Err(anyhow!("COT undefined when tangent is zero"));
293 }
294
295 Ok(DataValue::Float(1.0 / tan_val))
296 }
297}
298
299pub struct SinhFunction;
301
302impl SqlFunction for SinhFunction {
303 fn signature(&self) -> FunctionSignature {
304 FunctionSignature {
305 name: "SINH",
306 category: FunctionCategory::Mathematical,
307 arg_count: ArgCount::Fixed(1),
308 description: "Returns the hyperbolic sine of a number",
309 returns: "FLOAT",
310 examples: vec![
311 "SELECT SINH(0)", "SELECT SINH(1)", "SELECT SINH(-1)", ],
315 }
316 }
317
318 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
319 self.validate_args(args)?;
320
321 let value = match &args[0] {
322 DataValue::Integer(n) => *n as f64,
323 DataValue::Float(f) => *f,
324 DataValue::Null => return Ok(DataValue::Null),
325 _ => return Err(anyhow!("SINH requires a numeric argument")),
326 };
327
328 Ok(DataValue::Float(value.sinh()))
329 }
330}
331
332pub struct CoshFunction;
334
335impl SqlFunction for CoshFunction {
336 fn signature(&self) -> FunctionSignature {
337 FunctionSignature {
338 name: "COSH",
339 category: FunctionCategory::Mathematical,
340 arg_count: ArgCount::Fixed(1),
341 description: "Returns the hyperbolic cosine of a number",
342 returns: "FLOAT",
343 examples: vec![
344 "SELECT COSH(0)", "SELECT COSH(1)", "SELECT COSH(-1)", ],
348 }
349 }
350
351 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
352 self.validate_args(args)?;
353
354 let value = match &args[0] {
355 DataValue::Integer(n) => *n as f64,
356 DataValue::Float(f) => *f,
357 DataValue::Null => return Ok(DataValue::Null),
358 _ => return Err(anyhow!("COSH requires a numeric argument")),
359 };
360
361 Ok(DataValue::Float(value.cosh()))
362 }
363}
364
365pub struct TanhFunction;
367
368impl SqlFunction for TanhFunction {
369 fn signature(&self) -> FunctionSignature {
370 FunctionSignature {
371 name: "TANH",
372 category: FunctionCategory::Mathematical,
373 arg_count: ArgCount::Fixed(1),
374 description: "Returns the hyperbolic tangent of a number",
375 returns: "FLOAT",
376 examples: vec![
377 "SELECT TANH(0)", "SELECT TANH(1)", "SELECT TANH(-1)", ],
381 }
382 }
383
384 fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
385 self.validate_args(args)?;
386
387 let value = match &args[0] {
388 DataValue::Integer(n) => *n as f64,
389 DataValue::Float(f) => *f,
390 DataValue::Null => return Ok(DataValue::Null),
391 _ => return Err(anyhow!("TANH requires a numeric argument")),
392 };
393
394 Ok(DataValue::Float(value.tanh()))
395 }
396}
397
398#[cfg(test)]
399mod tests {
400 use super::*;
401 use std::f64::consts::PI;
402
403 #[test]
404 fn test_sin() {
405 let func = SinFunction;
406
407 let result = func.evaluate(&[DataValue::Integer(0)]).unwrap();
409 assert_eq!(result, DataValue::Float(0.0));
410
411 let result = func.evaluate(&[DataValue::Float(PI / 2.0)]).unwrap();
413 if let DataValue::Float(val) = result {
414 assert!((val - 1.0).abs() < 1e-10);
415 } else {
416 panic!("Expected Float result");
417 }
418
419 let result = func.evaluate(&[DataValue::Float(PI)]).unwrap();
421 if let DataValue::Float(val) = result {
422 assert!(val.abs() < 1e-10);
423 } else {
424 panic!("Expected Float result");
425 }
426 }
427
428 #[test]
429 fn test_cos() {
430 let func = CosFunction;
431
432 let result = func.evaluate(&[DataValue::Integer(0)]).unwrap();
434 assert_eq!(result, DataValue::Float(1.0));
435
436 let result = func.evaluate(&[DataValue::Float(PI / 2.0)]).unwrap();
438 if let DataValue::Float(val) = result {
439 assert!(val.abs() < 1e-10);
440 } else {
441 panic!("Expected Float result");
442 }
443
444 let result = func.evaluate(&[DataValue::Float(PI)]).unwrap();
446 if let DataValue::Float(val) = result {
447 assert!((val + 1.0).abs() < 1e-10);
448 } else {
449 panic!("Expected Float result");
450 }
451 }
452
453 #[test]
454 fn test_tan() {
455 let func = TanFunction;
456
457 let result = func.evaluate(&[DataValue::Integer(0)]).unwrap();
459 assert_eq!(result, DataValue::Float(0.0));
460
461 let result = func.evaluate(&[DataValue::Float(PI / 4.0)]).unwrap();
463 if let DataValue::Float(val) = result {
464 assert!((val - 1.0).abs() < 1e-10);
465 } else {
466 panic!("Expected Float result");
467 }
468 }
469
470 #[test]
471 fn test_asin() {
472 let func = AsinFunction;
473
474 let result = func.evaluate(&[DataValue::Integer(0)]).unwrap();
476 assert_eq!(result, DataValue::Float(0.0));
477
478 let result = func.evaluate(&[DataValue::Integer(1)]).unwrap();
480 if let DataValue::Float(val) = result {
481 assert!((val - PI / 2.0).abs() < 1e-10);
482 } else {
483 panic!("Expected Float result");
484 }
485
486 assert!(func.evaluate(&[DataValue::Float(1.5)]).is_err());
488 }
489
490 #[test]
491 fn test_atan2() {
492 let func = Atan2Function;
493
494 let result = func
496 .evaluate(&[DataValue::Integer(1), DataValue::Integer(1)])
497 .unwrap();
498 if let DataValue::Float(val) = result {
499 assert!((val - PI / 4.0).abs() < 1e-10);
500 } else {
501 panic!("Expected Float result");
502 }
503
504 let result = func
506 .evaluate(&[DataValue::Integer(1), DataValue::Integer(0)])
507 .unwrap();
508 if let DataValue::Float(val) = result {
509 assert!((val - PI / 2.0).abs() < 1e-10);
510 } else {
511 panic!("Expected Float result");
512 }
513 }
514}