1use crate::binder::scope::BinderScope;
11use linkrs_core::types::expr::Expression;
12use linkrs_core::types::operators::{AggregateFunction, BinaryOperator, UnaryOperator};
13use linkrs_core::DataType;
14
15pub struct ExpressionBinder<'a> {
17 scope: &'a BinderScope,
18}
19
20impl<'a> ExpressionBinder<'a> {
21 pub fn new(scope: &'a BinderScope) -> Self {
22 Self { scope }
23 }
24
25 pub fn resolve_type(&self, expr: &Expression) -> DataType {
27 match expr {
28 Expression::Literal(v) => v.data_type(),
29
30 Expression::Variable(name) => self
31 .scope
32 .lookup(name)
33 .and_then(|v| v.properties.values().next().map(|vt| vt.to_data_type()))
34 .unwrap_or(DataType::Unknown),
35
36 Expression::Property { object, property } => {
37 if let Expression::Variable(var_name) = object.as_ref() {
38 self.resolve_property_type(var_name, property)
39 } else {
40 DataType::Unknown
41 }
42 }
43
44 Expression::StructField { base, field } => match self.resolve_type(base) {
45 DataType::Struct(info) => info
46 .fields
47 .iter()
48 .find(|(name, _)| name == field)
49 .map(|(_, field_type)| field_type.clone())
50 .unwrap_or(DataType::Unknown),
51 _ => DataType::Unknown,
52 },
53
54 Expression::Binary { op, left, right } => {
55 let left_type = self.resolve_type(left);
56 let right_type = self.resolve_type(right);
57 match op {
58 BinaryOperator::Equal
59 | BinaryOperator::NotEqual
60 | BinaryOperator::LessThan
61 | BinaryOperator::LessThanOrEqual
62 | BinaryOperator::GreaterThan
63 | BinaryOperator::GreaterThanOrEqual
64 | BinaryOperator::And
65 | BinaryOperator::Or => DataType::Bool,
66 BinaryOperator::StringConcat => DataType::String,
67 BinaryOperator::Add
68 | BinaryOperator::Subtract
69 | BinaryOperator::Multiply
70 | BinaryOperator::Divide
71 | BinaryOperator::Modulo
72 | BinaryOperator::Exponent => {
73 self.deduce_arithmetic_type(&left_type, &right_type)
74 }
75 _ => DataType::Unknown,
76 }
77 }
78
79 Expression::Unary { op, operand } => match op {
80 UnaryOperator::Not => DataType::Bool,
81 UnaryOperator::IsNull | UnaryOperator::IsNotNull => DataType::Bool,
82 UnaryOperator::Plus | UnaryOperator::Minus => self.resolve_type(operand),
83 UnaryOperator::IsEmpty | UnaryOperator::IsNotEmpty => DataType::Bool,
84 },
85
86 Expression::Function { name, args } => {
87 if name.eq_ignore_ascii_case("list_reduce") {
88 for arg in args {
92 if let Expression::Lambda { body, .. } = arg.as_expr() {
93 let body_type = self.resolve_type(body);
94 if body_type != DataType::Unknown {
95 return body_type;
96 }
97 break;
98 }
99 }
100 if let Some(initial) = args.get(2) {
101 let initial_type = self.resolve_type(initial.as_expr());
102 if initial_type != DataType::Unknown {
103 return initial_type;
104 }
105 }
106 return DataType::Unknown;
107 }
108 let arg_types: Vec<DataType> = args
109 .iter()
110 .map(|a| self.resolve_type(a.as_expr()))
111 .collect();
112 self.deduce_function_return_type(name, &arg_types)
113 }
114
115 Expression::Aggregate { func, args, .. } => {
116 let arg_type = args
117 .first()
118 .map(|a| self.resolve_type(a))
119 .unwrap_or(DataType::Unknown);
120 self.deduce_aggregate_return_type(func, &arg_type)
121 }
122
123 Expression::List(items) => {
124 DataType::List(Box::new(self.resolve_container_element(items)))
125 }
126 Expression::Map(entries) => {
127 DataType::Map(Box::new(self.resolve_map_value_type(entries)))
128 }
129
130 Expression::Case {
131 conditions,
132 default,
133 ..
134 } => {
135 for (_, value) in conditions {
136 let t = self.resolve_type(value);
137 if t != DataType::Unknown {
138 return t;
139 }
140 }
141 default
142 .as_ref()
143 .map(|d| self.resolve_type(d))
144 .unwrap_or(DataType::Unknown)
145 }
146
147 Expression::Subscript { collection, .. } => match self.resolve_type(collection) {
148 DataType::List(element) => element.as_ref().clone(),
149 DataType::Map(value) => value.as_ref().clone(),
150 DataType::Set(element) => element.as_ref().clone(),
151 DataType::Array(info) => info.element.as_ref().clone(),
152 DataType::Path => DataType::Vertex,
153 _ => DataType::Unknown,
154 },
155
156 Expression::TypeCast { target_type, .. } => target_type.clone(),
157
158 Expression::ListComprehension { map, .. } => DataType::List(Box::new(
159 map.as_ref()
160 .map(|m| self.resolve_type(m))
161 .unwrap_or(DataType::Unknown),
162 )),
163 Expression::Reduce {
166 initial, mapping, ..
167 } => {
168 let initial_type = self.resolve_type(initial);
169 let mapping_type = self.resolve_type(mapping);
170 if initial_type != DataType::Unknown {
171 initial_type
172 } else if mapping_type != DataType::Unknown {
173 mapping_type
174 } else {
175 DataType::Unknown
176 }
177 }
178 Expression::WindowFunction { name, args, .. } => {
181 let arg_types: Vec<DataType> = args.iter().map(|a| self.resolve_type(a)).collect();
182 self.deduce_function_return_type(name, &arg_types)
183 }
184
185 Expression::Parameter(_) => DataType::Unknown,
186 Expression::SessionVariable(_) => DataType::Unknown,
187 Expression::Vector(v) => DataType::VectorDense(v.len()),
188
189 Expression::Path(_) => DataType::Path,
190 Expression::PathBuild(_) => DataType::Path,
191 Expression::Label(_) => DataType::String,
192 Expression::TagProperty { .. } => DataType::Unknown,
193 Expression::EdgeProperty { .. } => DataType::Unknown,
194 Expression::LabelTagProperty { .. } => DataType::Unknown,
195 Expression::Predicate { .. } => DataType::Bool,
196 Expression::Range { collection, .. } => match self.resolve_type(collection) {
197 DataType::List(element) => DataType::List(element),
198 DataType::Array(info) => DataType::Array(info),
199 _ => DataType::List(Box::new(DataType::Unknown)),
200 },
201 Expression::Exists { .. } => DataType::Bool,
202 Expression::In { .. } => DataType::Bool,
203 Expression::CountSubquery { .. } => DataType::Int,
204 Expression::ScalarSubquery { .. } => DataType::Unknown,
205 Expression::Lambda { .. } => DataType::Unknown,
206 }
207 }
208
209 pub fn resolve_property_type(&self, var_name: &str, property: &str) -> DataType {
211 if let Some(var_info) = self.scope.lookup(var_name) {
212 if let Some(vt) = var_info.properties.get(property) {
213 return vt.to_data_type();
214 }
215 }
216 DataType::Unknown
217 }
218
219 fn resolve_container_element(&self, items: &[Expression]) -> DataType {
222 let mut common = DataType::Unknown;
223 for item in items {
224 let item_type = self.resolve_type(item);
225 common = if common == DataType::Unknown {
226 item_type
227 } else {
228 linkrs_core::type_system::TypeUtils::get_common_type(&common, &item_type)
229 };
230 if common == DataType::Empty {
231 return DataType::Unknown;
232 }
233 }
234 common
235 }
236
237 fn resolve_map_value_type(&self, entries: &[(String, Expression)]) -> DataType {
240 let mut common = DataType::Unknown;
241 for (_, value) in entries {
242 let value_type = self.resolve_type(value);
243 common = if common == DataType::Unknown {
244 value_type
245 } else {
246 linkrs_core::type_system::TypeUtils::get_common_type(&common, &value_type)
247 };
248 if common == DataType::Empty {
249 return DataType::Unknown;
250 }
251 }
252 common
253 }
254
255 pub fn deduce_arithmetic_type(&self, left: &DataType, right: &DataType) -> DataType {
257 let left_is_numeric = matches!(
258 left,
259 DataType::SmallInt
260 | DataType::Int
261 | DataType::BigInt
262 | DataType::Float
263 | DataType::Double
264 );
265 let right_is_numeric = matches!(
266 right,
267 DataType::SmallInt
268 | DataType::Int
269 | DataType::BigInt
270 | DataType::Float
271 | DataType::Double
272 );
273
274 if !left_is_numeric || !right_is_numeric {
275 return DataType::Unknown;
276 }
277
278 let left_is_float = matches!(left, DataType::Float | DataType::Double);
279 let right_is_float = matches!(right, DataType::Float | DataType::Double);
280
281 if left_is_float || right_is_float {
282 DataType::Float
283 } else {
284 DataType::Int
285 }
286 }
287
288 pub fn deduce_function_return_type(&self, name: &str, arg_types: &[DataType]) -> DataType {
290 let lower = name.to_lowercase();
291 match lower.as_str() {
292 "list_reduce" => return DataType::Unknown,
297 "head" | "last" | "coalesce" | "greatest" | "least" | "nullif" | "ifnull"
298 | "first_value" | "last_value" | "nth_value" | "lead" | "lag" | "element_at"
299 | "list_extract" | "struct_extract" | "map_extract" => {
300 return arg_types.first().cloned().unwrap_or(DataType::Unknown);
301 }
302 "date_add" | "date_sub" | "date_trunc" | "last_day" => {
303 return arg_types.first().cloned().unwrap_or(DataType::DateTime);
304 }
305 _ => {}
306 }
307
308 let registry = crate::executor::expression::functions::global_registry_ref();
309 if let Some(return_type) = registry.get_return_type(name) {
310 if *return_type != DataType::Unknown {
311 return return_type.clone();
312 }
313 if !arg_types.is_empty() {
316 let first = &arg_types[0];
317 if *first != DataType::Unknown {
318 return first.clone();
319 }
320 }
321 return return_type.clone();
322 }
323
324 match lower.as_str() {
325 "head" => arg_types.first().cloned().unwrap_or(DataType::Unknown),
326 "last" => arg_types.first().cloned().unwrap_or(DataType::Unknown),
327 "coalesce" => arg_types.first().cloned().unwrap_or(DataType::Unknown),
328 _ => DataType::Unknown,
329 }
330 }
331
332 pub fn deduce_aggregate_return_type(
334 &self,
335 func: &AggregateFunction,
336 arg_type: &DataType,
337 ) -> DataType {
338 match func {
339 AggregateFunction::Count => DataType::Int,
340 AggregateFunction::Sum => DataType::Float,
341 AggregateFunction::Avg => DataType::Float,
342 AggregateFunction::Max | AggregateFunction::Min => arg_type.clone(),
343 AggregateFunction::Collect => DataType::List(Box::new(arg_type.clone())),
344 AggregateFunction::CollectSet => DataType::Set(Box::new(arg_type.clone())),
345 AggregateFunction::Percentile => DataType::Float,
346 AggregateFunction::PercentileCont => DataType::Float,
347 AggregateFunction::Std => DataType::Float,
348 AggregateFunction::StddevPop => DataType::Float,
349 AggregateFunction::StddevSamp => DataType::Float,
350 AggregateFunction::Product => DataType::Float,
351 AggregateFunction::Variance => DataType::Float,
352 AggregateFunction::Median => DataType::Float,
353 AggregateFunction::Mode => arg_type.clone(),
354 AggregateFunction::BitAnd | AggregateFunction::BitOr => DataType::Int,
355 AggregateFunction::BoolAnd | AggregateFunction::BoolOr => DataType::Bool,
356 AggregateFunction::GroupConcat => DataType::String,
357 AggregateFunction::GroupConcatWithOrder => DataType::String,
358 AggregateFunction::VecSum => DataType::Vector,
359 AggregateFunction::VecAvg => DataType::Vector,
360 }
361 }
362}