sql_cli/sql/generators/
literal_generators.rs

1use crate::data::datatable::{DataColumn, DataRow, DataTable, DataType, DataValue};
2use crate::sql::generators::TableGenerator;
3use anyhow::{anyhow, Result};
4use std::collections::HashMap;
5use std::sync::Arc;
6
7/// VALUES - Create a table from literal values
8/// This generator allows creating a table from a list of literal values
9/// Example: SELECT * FROM VALUES(1, 20, 30, 50)
10pub struct Values;
11
12impl TableGenerator for Values {
13    fn name(&self) -> &str {
14        "VALUES"
15    }
16
17    fn columns(&self) -> Vec<DataColumn> {
18        vec![DataColumn {
19            name: "value".to_string(),
20            data_type: DataType::Float, // Use Float to handle both integers and decimals
21            nullable: false,
22            unique_values: Some(0),
23            null_count: 0,
24            metadata: HashMap::new(),
25            qualified_name: None,
26            source_table: None,
27        }]
28    }
29
30    fn generate(&self, args: Vec<DataValue>) -> Result<Arc<DataTable>> {
31        if args.is_empty() {
32            return Err(anyhow!("VALUES expects at least one argument"));
33        }
34
35        let mut table = DataTable::new("values");
36        table.add_column(DataColumn::new("value"));
37
38        // Add each argument as a row in the table
39        for (i, arg) in args.iter().enumerate() {
40            let value = match arg {
41                DataValue::Integer(n) => DataValue::Integer(*n),
42                DataValue::Float(f) => DataValue::Float(*f),
43                DataValue::String(s) => {
44                    // Try to parse string as number
45                    if let Ok(n) = s.parse::<i64>() {
46                        DataValue::Integer(n)
47                    } else if let Ok(f) = s.parse::<f64>() {
48                        DataValue::Float(f)
49                    } else {
50                        return Err(anyhow!(
51                            "VALUES argument {} ('{}') cannot be converted to a number",
52                            i + 1,
53                            s
54                        ));
55                    }
56                }
57                DataValue::Null => DataValue::Null,
58                _ => {
59                    return Err(anyhow!(
60                        "VALUES expects numeric arguments, got {:?} at position {}",
61                        arg,
62                        i + 1
63                    ))
64                }
65            };
66
67            table
68                .add_row(DataRow::new(vec![value]))
69                .map_err(|e| anyhow!(e))?;
70        }
71
72        Ok(Arc::new(table))
73    }
74
75    fn description(&self) -> &str {
76        "Generate a table from literal values"
77    }
78
79    fn arg_count(&self) -> usize {
80        0 // Variable number of arguments
81    }
82}
83
84/// ARRAY - Alternative name for VALUES generator
85/// This provides a more intuitive name for creating arrays as tables
86pub struct Array;
87
88impl TableGenerator for Array {
89    fn name(&self) -> &str {
90        "ARRAY"
91    }
92
93    fn columns(&self) -> Vec<DataColumn> {
94        vec![
95            DataColumn {
96                name: "index".to_string(),
97                data_type: DataType::Integer,
98                nullable: false,
99                unique_values: Some(0),
100                null_count: 0,
101                metadata: HashMap::new(),
102                qualified_name: None,
103                source_table: None,
104            },
105            DataColumn {
106                name: "value".to_string(),
107                data_type: DataType::Float,
108                nullable: false,
109                unique_values: Some(0),
110                null_count: 0,
111                metadata: HashMap::new(),
112                qualified_name: None,
113                source_table: None,
114            },
115        ]
116    }
117
118    fn generate(&self, args: Vec<DataValue>) -> Result<Arc<DataTable>> {
119        if args.is_empty() {
120            return Err(anyhow!("ARRAY expects at least one argument"));
121        }
122
123        let mut table = DataTable::new("array");
124        table.add_column(DataColumn::new("index"));
125        table.add_column(DataColumn::new("value"));
126
127        // Add each argument as a row with index
128        for (i, arg) in args.iter().enumerate() {
129            let value = match arg {
130                DataValue::Integer(n) => DataValue::Integer(*n),
131                DataValue::Float(f) => DataValue::Float(*f),
132                DataValue::String(s) => {
133                    // Try to parse string as number
134                    if let Ok(n) = s.parse::<i64>() {
135                        DataValue::Integer(n)
136                    } else if let Ok(f) = s.parse::<f64>() {
137                        DataValue::Float(f)
138                    } else {
139                        return Err(anyhow!(
140                            "ARRAY argument {} ('{}') cannot be converted to a number",
141                            i + 1,
142                            s
143                        ));
144                    }
145                }
146                DataValue::Null => DataValue::Null,
147                _ => {
148                    return Err(anyhow!(
149                        "ARRAY expects numeric arguments, got {:?} at position {}",
150                        arg,
151                        i + 1
152                    ))
153                }
154            };
155
156            table
157                .add_row(DataRow::new(vec![DataValue::Integer(i as i64), value]))
158                .map_err(|e| anyhow!(e))?;
159        }
160
161        Ok(Arc::new(table))
162    }
163
164    fn description(&self) -> &str {
165        "Generate a table from an array of literal values with index"
166    }
167
168    fn arg_count(&self) -> usize {
169        0 // Variable number of arguments
170    }
171}