sql_cli/sql/functions/
random.rs

1use anyhow::{anyhow, Result};
2use rand::Rng;
3
4use crate::data::datatable::DataValue;
5use crate::sql::functions::{ArgCount, FunctionCategory, FunctionSignature, SqlFunction};
6
7/// RAND_RANGE function - Generate random numbers within a range
8pub struct RandRangeFunction;
9
10impl SqlFunction for RandRangeFunction {
11    fn signature(&self) -> FunctionSignature {
12        FunctionSignature {
13            name: "RAND_RANGE",
14            category: FunctionCategory::Mathematical,
15            arg_count: ArgCount::Fixed(3),
16            description: "Generate N random numbers between lower and upper bounds",
17            returns: "TABLE",
18            examples: vec![
19                "SELECT * FROM RAND_RANGE(10, 1, 100)", // 10 random numbers between 1 and 100
20                "SELECT * FROM RAND_RANGE(5, 0.0, 1.0)", // 5 random floats between 0.0 and 1.0
21                "SELECT AVG(value) FROM RAND_RANGE(1000, 1, 6)", // Average of 1000 dice rolls
22            ],
23        }
24    }
25
26    fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
27        self.validate_args(args)?;
28
29        let count = match &args[0] {
30            DataValue::Integer(n) if *n > 0 => *n as usize,
31            DataValue::Float(f) if *f > 0.0 => *f as usize,
32            _ => return Err(anyhow!("RAND_RANGE count must be a positive number")),
33        };
34
35        let (lower, upper, use_float) = match (&args[1], &args[2]) {
36            (DataValue::Integer(l), DataValue::Integer(u)) => (*l as f64, *u as f64, false),
37            (DataValue::Float(l), DataValue::Float(u)) => (*l, *u, true),
38            (DataValue::Integer(l), DataValue::Float(u)) => (*l as f64, *u, true),
39            (DataValue::Float(l), DataValue::Integer(u)) => (*l, *u as f64, true),
40            _ => return Err(anyhow!("RAND_RANGE bounds must be numeric")),
41        };
42
43        if lower > upper {
44            return Err(anyhow!("RAND_RANGE lower bound must be <= upper bound"));
45        }
46
47        // Generate random values
48        let mut rng = rand::thread_rng();
49        let mut values = Vec::with_capacity(count);
50
51        for _ in 0..count {
52            if use_float {
53                let value = rng.gen_range(lower..=upper);
54                values.push(DataValue::Float(value));
55            } else {
56                let value = rng.gen_range(lower as i64..=upper as i64);
57                values.push(DataValue::Integer(value));
58            }
59        }
60
61        // For now, return the first value (we'll enhance this when table functions are fully supported)
62        // In the future, this should return a proper table
63        if values.is_empty() {
64            Ok(DataValue::Null)
65        } else {
66            Ok(values[0].clone())
67        }
68    }
69}
70
71/// RANDOM function - Generate a single random number between 0 and 1
72pub struct RandomFunction;
73
74impl SqlFunction for RandomFunction {
75    fn signature(&self) -> FunctionSignature {
76        FunctionSignature {
77            name: "RANDOM",
78            category: FunctionCategory::Mathematical,
79            arg_count: ArgCount::Fixed(0),
80            description: "Generate a random float between 0 and 1",
81            returns: "FLOAT",
82            examples: vec![
83                "SELECT RANDOM()",
84                "SELECT ROUND(RANDOM() * 100, 0)", // Random integer 0-100
85            ],
86        }
87    }
88
89    fn evaluate(&self, _args: &[DataValue]) -> Result<DataValue> {
90        let mut rng = rand::thread_rng();
91        Ok(DataValue::Float(rng.gen_range(0.0..1.0)))
92    }
93}
94
95/// RAND_INT function - Generate a random integer between bounds
96pub struct RandIntFunction;
97
98impl SqlFunction for RandIntFunction {
99    fn signature(&self) -> FunctionSignature {
100        FunctionSignature {
101            name: "RAND_INT",
102            category: FunctionCategory::Mathematical,
103            arg_count: ArgCount::Fixed(2),
104            description: "Generate a random integer between lower and upper bounds (inclusive)",
105            returns: "INTEGER",
106            examples: vec![
107                "SELECT RAND_INT(1, 6)",   // Dice roll
108                "SELECT RAND_INT(1, 100)", // Random percentage
109                "SELECT RAND_INT(0, 255)", // Random byte value
110            ],
111        }
112    }
113
114    fn evaluate(&self, args: &[DataValue]) -> Result<DataValue> {
115        self.validate_args(args)?;
116
117        let lower = match &args[0] {
118            DataValue::Integer(n) => *n,
119            DataValue::Float(f) => *f as i64,
120            _ => return Err(anyhow!("RAND_INT lower bound must be numeric")),
121        };
122
123        let upper = match &args[1] {
124            DataValue::Integer(n) => *n,
125            DataValue::Float(f) => *f as i64,
126            _ => return Err(anyhow!("RAND_INT upper bound must be numeric")),
127        };
128
129        if lower > upper {
130            return Err(anyhow!("RAND_INT lower bound must be <= upper bound"));
131        }
132
133        let mut rng = rand::thread_rng();
134        Ok(DataValue::Integer(rng.gen_range(lower..=upper)))
135    }
136}