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