Skip to main content

reifydb_evaluate/expression/
udf_extract.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (c) 2026 ReifyDB
3
4use reifydb_core::{
5	expression::{
6		AddExpression, AliasExpression, AndExpression, BetweenExpression, CallExpression, CastExpression,
7		ColumnExpression, ContainsExpression, DivExpression, ElseIfExpression, EqExpression, Expression,
8		ExtendExpression, FieldAccessExpression, GreaterThanEqExpression, GreaterThanExpression, IfExpression,
9		InExpression, LessThanEqExpression, LessThanExpression, ListExpression, MapExpression, MulExpression,
10		NotEqExpression, OrExpression, PrefixExpression, RecordExpression, RemExpression, SubExpression,
11		TupleExpression, XorExpression,
12	},
13	interface::identifier::{ColumnIdentifier, ColumnObject},
14};
15use reifydb_value::fragment::Fragment;
16
17use crate::stack::{Callable, SymbolTable};
18
19pub struct ExtractedUdf {
20	pub callable: Callable,
21	pub arg_expressions: Vec<Expression>,
22	pub result_column: Fragment,
23	pub name: String,
24	pub fragment: Fragment,
25}
26
27pub fn extract_udf_calls(
28	expr: &Expression,
29	symbols: &SymbolTable,
30	counter: &mut usize,
31) -> (Expression, Vec<ExtractedUdf>) {
32	let mut extracted = Vec::new();
33	let rewritten = rewrite_expr(expr, symbols, counter, &mut extracted);
34	(rewritten, extracted)
35}
36
37fn rw(e: &Expression, s: &SymbolTable, c: &mut usize, x: &mut Vec<ExtractedUdf>) -> Expression {
38	rewrite_expr(e, s, c, x)
39}
40
41fn rw_vec(exprs: &[Expression], s: &SymbolTable, c: &mut usize, x: &mut Vec<ExtractedUdf>) -> Vec<Expression> {
42	exprs.iter().map(|e| rewrite_expr(e, s, c, x)).collect()
43}
44
45fn rewrite_expr(
46	expr: &Expression,
47	symbols: &SymbolTable,
48	counter: &mut usize,
49	extracted: &mut Vec<ExtractedUdf>,
50) -> Expression {
51	match expr {
52		Expression::Call(call) => {
53			let rewritten_args = rw_vec(&call.args, symbols, counter, extracted);
54			let function_name = call.func.0.text();
55
56			if let Some(callable) = symbols.resolve_callable(function_name) {
57				let col_name = Fragment::internal(format!("__udf_{}", counter));
58				*counter += 1;
59
60				extracted.push(ExtractedUdf {
61					callable,
62					arg_expressions: rewritten_args,
63					result_column: col_name.clone(),
64					name: function_name.to_string(),
65					fragment: call.func.0.clone(),
66				});
67
68				Expression::Column(ColumnExpression(ColumnIdentifier {
69					object: ColumnObject::Alias(Fragment::internal("")),
70					name: col_name,
71				}))
72			} else {
73				Expression::Call(CallExpression {
74					func: call.func.clone(),
75					args: rewritten_args,
76					fragment: call.fragment.clone(),
77				})
78			}
79		}
80
81		Expression::Add(e) => Expression::Add(AddExpression {
82			left: Box::new(rw(&e.left, symbols, counter, extracted)),
83			right: Box::new(rw(&e.right, symbols, counter, extracted)),
84			fragment: e.fragment.clone(),
85		}),
86		Expression::Sub(e) => Expression::Sub(SubExpression {
87			left: Box::new(rw(&e.left, symbols, counter, extracted)),
88			right: Box::new(rw(&e.right, symbols, counter, extracted)),
89			fragment: e.fragment.clone(),
90		}),
91		Expression::Mul(e) => Expression::Mul(MulExpression {
92			left: Box::new(rw(&e.left, symbols, counter, extracted)),
93			right: Box::new(rw(&e.right, symbols, counter, extracted)),
94			fragment: e.fragment.clone(),
95		}),
96		Expression::Div(e) => Expression::Div(DivExpression {
97			left: Box::new(rw(&e.left, symbols, counter, extracted)),
98			right: Box::new(rw(&e.right, symbols, counter, extracted)),
99			fragment: e.fragment.clone(),
100		}),
101		Expression::Rem(e) => Expression::Rem(RemExpression {
102			left: Box::new(rw(&e.left, symbols, counter, extracted)),
103			right: Box::new(rw(&e.right, symbols, counter, extracted)),
104			fragment: e.fragment.clone(),
105		}),
106		Expression::GreaterThan(e) => Expression::GreaterThan(GreaterThanExpression {
107			left: Box::new(rw(&e.left, symbols, counter, extracted)),
108			right: Box::new(rw(&e.right, symbols, counter, extracted)),
109			fragment: e.fragment.clone(),
110		}),
111		Expression::GreaterThanEqual(e) => Expression::GreaterThanEqual(GreaterThanEqExpression {
112			left: Box::new(rw(&e.left, symbols, counter, extracted)),
113			right: Box::new(rw(&e.right, symbols, counter, extracted)),
114			fragment: e.fragment.clone(),
115		}),
116		Expression::LessThan(e) => Expression::LessThan(LessThanExpression {
117			left: Box::new(rw(&e.left, symbols, counter, extracted)),
118			right: Box::new(rw(&e.right, symbols, counter, extracted)),
119			fragment: e.fragment.clone(),
120		}),
121		Expression::LessThanEqual(e) => Expression::LessThanEqual(LessThanEqExpression {
122			left: Box::new(rw(&e.left, symbols, counter, extracted)),
123			right: Box::new(rw(&e.right, symbols, counter, extracted)),
124			fragment: e.fragment.clone(),
125		}),
126		Expression::Equal(e) => Expression::Equal(EqExpression {
127			left: Box::new(rw(&e.left, symbols, counter, extracted)),
128			right: Box::new(rw(&e.right, symbols, counter, extracted)),
129			fragment: e.fragment.clone(),
130		}),
131		Expression::NotEqual(e) => Expression::NotEqual(NotEqExpression {
132			left: Box::new(rw(&e.left, symbols, counter, extracted)),
133			right: Box::new(rw(&e.right, symbols, counter, extracted)),
134			fragment: e.fragment.clone(),
135		}),
136		Expression::And(e) => Expression::And(AndExpression {
137			left: Box::new(rw(&e.left, symbols, counter, extracted)),
138			right: Box::new(rw(&e.right, symbols, counter, extracted)),
139			fragment: e.fragment.clone(),
140		}),
141		Expression::Or(e) => Expression::Or(OrExpression {
142			left: Box::new(rw(&e.left, symbols, counter, extracted)),
143			right: Box::new(rw(&e.right, symbols, counter, extracted)),
144			fragment: e.fragment.clone(),
145		}),
146		Expression::Xor(e) => Expression::Xor(XorExpression {
147			left: Box::new(rw(&e.left, symbols, counter, extracted)),
148			right: Box::new(rw(&e.right, symbols, counter, extracted)),
149			fragment: e.fragment.clone(),
150		}),
151
152		Expression::Between(e) => Expression::Between(BetweenExpression {
153			value: Box::new(rw(&e.value, symbols, counter, extracted)),
154			lower: Box::new(rw(&e.lower, symbols, counter, extracted)),
155			upper: Box::new(rw(&e.upper, symbols, counter, extracted)),
156			fragment: e.fragment.clone(),
157		}),
158		Expression::In(e) => Expression::In(InExpression {
159			value: Box::new(rw(&e.value, symbols, counter, extracted)),
160			list: Box::new(rw(&e.list, symbols, counter, extracted)),
161			negated: e.negated,
162			fragment: e.fragment.clone(),
163		}),
164		Expression::Contains(e) => Expression::Contains(ContainsExpression {
165			value: Box::new(rw(&e.value, symbols, counter, extracted)),
166			list: Box::new(rw(&e.list, symbols, counter, extracted)),
167			fragment: e.fragment.clone(),
168		}),
169		Expression::Cast(e) => Expression::Cast(CastExpression {
170			expression: Box::new(rw(&e.expression, symbols, counter, extracted)),
171			to: e.to.clone(),
172			fragment: e.fragment.clone(),
173		}),
174		Expression::Prefix(e) => Expression::Prefix(PrefixExpression {
175			operator: e.operator.clone(),
176			expression: Box::new(rw(&e.expression, symbols, counter, extracted)),
177			fragment: e.fragment.clone(),
178		}),
179		Expression::Alias(e) => Expression::Alias(AliasExpression {
180			alias: e.alias.clone(),
181			expression: Box::new(rw(&e.expression, symbols, counter, extracted)),
182			fragment: e.fragment.clone(),
183		}),
184		Expression::If(e) => Expression::If(IfExpression {
185			condition: Box::new(rw(&e.condition, symbols, counter, extracted)),
186			then_expr: Box::new(rw(&e.then_expr, symbols, counter, extracted)),
187			else_ifs: e
188				.else_ifs
189				.iter()
190				.map(|ei| ElseIfExpression {
191					condition: Box::new(rw(&ei.condition, symbols, counter, extracted)),
192					then_expr: Box::new(rw(&ei.then_expr, symbols, counter, extracted)),
193					fragment: ei.fragment.clone(),
194				})
195				.collect(),
196			else_expr: e.else_expr.as_ref().map(|b| Box::new(rw(b, symbols, counter, extracted))),
197			fragment: e.fragment.clone(),
198		}),
199		Expression::FieldAccess(e) => Expression::FieldAccess(FieldAccessExpression {
200			object: Box::new(rw(&e.object, symbols, counter, extracted)),
201			field: e.field.clone(),
202			fragment: e.fragment.clone(),
203		}),
204
205		Expression::Tuple(e) => Expression::Tuple(TupleExpression {
206			expressions: rw_vec(&e.expressions, symbols, counter, extracted),
207			fragment: e.fragment.clone(),
208		}),
209		Expression::List(e) => Expression::List(ListExpression {
210			expressions: rw_vec(&e.expressions, symbols, counter, extracted),
211			fragment: e.fragment.clone(),
212		}),
213		Expression::Map(e) => Expression::Map(MapExpression {
214			expressions: rw_vec(&e.expressions, symbols, counter, extracted),
215			fragment: e.fragment.clone(),
216		}),
217		Expression::Extend(e) => Expression::Extend(ExtendExpression {
218			expressions: rw_vec(&e.expressions, symbols, counter, extracted),
219			fragment: e.fragment.clone(),
220		}),
221		Expression::Record(e) => Expression::Record(RecordExpression {
222			fields: e
223				.fields
224				.iter()
225				.map(|(name, expression)| {
226					(name.clone(), rewrite_expr(expression, symbols, counter, extracted))
227				})
228				.collect(),
229			fragment: e.fragment.clone(),
230		}),
231
232		Expression::Constant(_)
233		| Expression::Column(_)
234		| Expression::AccessSource(_)
235		| Expression::Parameter(_)
236		| Expression::Variable(_)
237		| Expression::Type(_)
238		| Expression::SumTypeConstructor(_)
239		| Expression::IsVariant(_) => expr.clone(),
240	}
241}