1use std::{collections::BTreeMap, sync::LazyLock};
5
6use reifydb_core::value::column::columns::Columns;
7use reifydb_engine::{
8 expression::{
9 compile::compile_expression,
10 context::{CompileContext, EvalContext},
11 },
12 vm::stack::SymbolTable,
13};
14use reifydb_function::registry::Functions;
15use reifydb_rql::expression::Expression;
16use reifydb_runtime::clock::Clock;
17use reifydb_type::{
18 Result,
19 params::Params,
20 value::{Value, identity::IdentityId},
21};
22
23static EMPTY_PARAMS: Params = Params::None;
24static EMPTY_SYMBOL_TABLE: LazyLock<SymbolTable> = LazyLock::new(|| SymbolTable::new());
25
26pub fn evaluate_operator_config(
44 expressions: &[Expression],
45 functions: &Functions,
46 clock: &Clock,
47) -> Result<BTreeMap<String, Value>> {
48 let mut result = BTreeMap::new();
49
50 let compile_ctx = CompileContext {
51 functions,
52 symbol_table: &EMPTY_SYMBOL_TABLE,
53 };
54
55 let empty_columns = Columns::empty();
56
57 let exec_ctx = EvalContext {
58 target: None,
59 columns: empty_columns,
60 row_count: 1, take: None,
62 params: &EMPTY_PARAMS,
63 symbol_table: &EMPTY_SYMBOL_TABLE,
64 is_aggregate_context: false,
65 functions,
66 clock,
67 arena: None,
68 identity: IdentityId::root(),
69 };
70
71 for expr in expressions {
72 match expr {
73 Expression::Alias(alias_expr) => {
74 let key = alias_expr.alias.name().to_string();
75
76 let expr = compile_expression(&compile_ctx, &alias_expr.expression)?;
77 let column = expr.execute(&exec_ctx)?;
78
79 let value = if column.data().len() > 0 {
80 column.data().get_value(0)
81 } else {
82 Value::none()
83 };
84 result.insert(key, value);
85 }
86 _ => {}
87 }
88 }
89
90 Ok(result)
91}
92
93#[cfg(test)]
94pub mod tests {
95 use reifydb_function::registry::Functions;
96 use reifydb_rql::expression::{AliasExpression, ConstantExpression, Expression, IdentExpression};
97 use reifydb_runtime::clock::Clock;
98 use reifydb_type::{fragment::Fragment, value::Value};
99
100 use super::evaluate_operator_config;
101
102 fn create_alias_expression(alias_name: &str, inner_expression: Expression) -> Expression {
103 Expression::Alias(AliasExpression {
104 alias: IdentExpression(Fragment::internal(alias_name.to_string())),
105 expression: Box::new(inner_expression),
106 fragment: Fragment::testing_empty(),
107 })
108 }
109
110 fn create_constant_text(text: &str) -> Expression {
111 Expression::Constant(ConstantExpression::Text {
112 fragment: Fragment::internal(text.to_string()),
113 })
114 }
115
116 fn create_constant_number(num: i64) -> Expression {
117 Expression::Constant(ConstantExpression::Number {
118 fragment: Fragment::internal(num.to_string()),
119 })
120 }
121
122 fn create_constant_bool(value: bool) -> Expression {
123 Expression::Constant(ConstantExpression::Bool {
124 fragment: Fragment::internal(value.to_string()),
125 })
126 }
127
128 fn create_constant_undefined() -> Expression {
129 Expression::Constant(ConstantExpression::None {
130 fragment: Fragment::internal("none".to_string()),
131 })
132 }
133
134 #[test]
135 fn test_empty_expressions() {
136 let functions = Functions::builder().build();
137 let clock = Clock::default();
138 let expressions: Vec<Expression> = vec![];
139
140 let result = evaluate_operator_config(&expressions, &functions, &clock).unwrap();
141
142 assert!(result.is_empty());
143 }
144
145 #[test]
146 fn test_single_alias_string() {
147 let functions = Functions::builder().build();
148 let clock = Clock::default();
149 let expressions = vec![create_alias_expression("key1", create_constant_text("value1"))];
150
151 let result = evaluate_operator_config(&expressions, &functions, &clock).unwrap();
152
153 assert_eq!(result.len(), 1);
154 assert_eq!(result.get("key1"), Some(&Value::Utf8("value1".into())));
155 }
156
157 #[test]
158 fn test_single_alias_number() {
159 let functions = Functions::builder().build();
160 let clock = Clock::default();
161 let expressions = vec![create_alias_expression("count", create_constant_number(42))];
162
163 let result = evaluate_operator_config(&expressions, &functions, &clock).unwrap();
164
165 assert_eq!(result.len(), 1);
166 assert_eq!(result.get("count"), Some(&Value::Int1(42)));
167 }
168
169 #[test]
170 fn test_single_alias_bool() {
171 let functions = Functions::builder().build();
172 let clock = Clock::default();
173 let expressions = vec![create_alias_expression("enabled", create_constant_bool(true))];
174
175 let result = evaluate_operator_config(&expressions, &functions, &clock).unwrap();
176
177 assert_eq!(result.len(), 1);
178 assert_eq!(result.get("enabled"), Some(&Value::Boolean(true)));
179 }
180
181 #[test]
182 fn test_single_alias_undefined() {
183 let functions = Functions::builder().build();
184 let clock = Clock::default();
185 let expressions = vec![create_alias_expression("optional", create_constant_undefined())];
186
187 let result = evaluate_operator_config(&expressions, &functions, &clock).unwrap();
188
189 assert_eq!(result.len(), 1);
190 assert_eq!(result.get("optional"), Some(&Value::none()));
191 }
192
193 #[test]
194 fn test_multiple_aliases() {
195 let functions = Functions::builder().build();
196 let clock = Clock::default();
197 let expressions = vec![
198 create_alias_expression("key1", create_constant_text("value1")),
199 create_alias_expression("key2", create_constant_number(100)),
200 create_alias_expression("key3", create_constant_bool(false)),
201 ];
202
203 let result = evaluate_operator_config(&expressions, &functions, &clock).unwrap();
204
205 assert_eq!(result.len(), 3);
206 assert_eq!(result.get("key1"), Some(&Value::Utf8("value1".into())));
207 assert_eq!(result.get("key2"), Some(&Value::Int1(100)));
208 assert_eq!(result.get("key3"), Some(&Value::Boolean(false)));
209 }
210
211 #[test]
214 fn test_non_alias_expressions_skipped() {
215 let functions = Functions::builder().build();
216 let clock = Clock::default();
217 let expressions = vec![
218 create_alias_expression("valid", create_constant_text("included")),
219 create_constant_text("standalone"), create_constant_number(999), ];
222
223 let result = evaluate_operator_config(&expressions, &functions, &clock).unwrap();
224
225 assert_eq!(result.len(), 1);
226 assert_eq!(result.get("valid"), Some(&Value::Utf8("included".into())));
227 }
228
229 #[test]
230 fn test_only_non_alias_expressions() {
231 let functions = Functions::builder().build();
232 let clock = Clock::default();
233 let expressions =
234 vec![create_constant_text("text"), create_constant_number(42), create_constant_bool(true)];
235
236 let result = evaluate_operator_config(&expressions, &functions, &clock).unwrap();
237
238 assert!(result.is_empty());
239 }
240
241 #[test]
244 fn test_all_basic_value_types() {
245 let functions = Functions::builder().build();
246 let clock = Clock::default();
247 let expressions = vec![
248 create_alias_expression("text_val", create_constant_text("hello")),
249 create_alias_expression("num_val", create_constant_number(-42)),
250 create_alias_expression("bool_true", create_constant_bool(true)),
251 create_alias_expression("bool_false", create_constant_bool(false)),
252 create_alias_expression("undef_val", create_constant_undefined()),
253 ];
254
255 let result = evaluate_operator_config(&expressions, &functions, &clock).unwrap();
256
257 assert_eq!(result.len(), 5);
258 assert_eq!(result.get("text_val"), Some(&Value::Utf8("hello".into())));
259 assert_eq!(result.get("num_val"), Some(&Value::Int1(-42)));
260 assert_eq!(result.get("bool_true"), Some(&Value::Boolean(true)));
261 assert_eq!(result.get("bool_false"), Some(&Value::Boolean(false)));
262 assert_eq!(result.get("undef_val"), Some(&Value::none()));
263 }
264
265 #[test]
266 fn test_duplicate_alias_names_last_wins() {
267 let functions = Functions::builder().build();
268 let clock = Clock::default();
269 let expressions = vec![
270 create_alias_expression("key", create_constant_text("first")),
271 create_alias_expression("key", create_constant_text("second")),
272 create_alias_expression("key", create_constant_number(42)),
273 ];
274
275 let result = evaluate_operator_config(&expressions, &functions, &clock).unwrap();
276
277 assert_eq!(result.len(), 1);
278 assert_eq!(result.get("key"), Some(&Value::Int1(42)));
279 }
280
281 #[test]
282 fn test_empty_string_value() {
283 let functions = Functions::builder().build();
284 let clock = Clock::default();
285 let expressions = vec![create_alias_expression("empty", create_constant_text(""))];
286
287 let result = evaluate_operator_config(&expressions, &functions, &clock).unwrap();
288
289 assert_eq!(result.len(), 1);
290 assert_eq!(result.get("empty"), Some(&Value::Utf8("".into())));
291 }
292
293 #[test]
294 fn test_special_characters_in_alias_name() {
295 let functions = Functions::builder().build();
296 let clock = Clock::default();
297 let expressions = vec![
298 create_alias_expression("key_with_underscore", create_constant_number(1)),
299 create_alias_expression("keyWithCamelCase", create_constant_number(2)),
300 create_alias_expression("key123", create_constant_number(3)),
301 ];
302
303 let result = evaluate_operator_config(&expressions, &functions, &clock).unwrap();
304
305 assert_eq!(result.len(), 3);
306 assert_eq!(result.get("key_with_underscore"), Some(&Value::Int1(1)));
307 assert_eq!(result.get("keyWithCamelCase"), Some(&Value::Int1(2)));
308 assert_eq!(result.get("key123"), Some(&Value::Int1(3)));
309 }
310
311 #[test]
312 fn test_large_number_values() {
313 let functions = Functions::builder().build();
314 let clock = Clock::default();
315 let expressions = vec![
316 create_alias_expression("small", create_constant_number(0)),
317 create_alias_expression("large_positive", create_constant_number(i64::MAX)),
318 create_alias_expression("large_negative", create_constant_number(i64::MIN)),
319 ];
320
321 let result = evaluate_operator_config(&expressions, &functions, &clock).unwrap();
322
323 assert_eq!(result.len(), 3);
324 assert_eq!(result.get("small"), Some(&Value::Int1(0)));
325 assert_eq!(result.get("large_positive"), Some(&Value::Int8(i64::MAX)));
326 assert_eq!(result.get("large_negative"), Some(&Value::Int8(i64::MIN)));
327 }
328}