1use crate::{
20 Result,
21 stmt::{
22 BinaryOp, ConstInput, Expr, ExprArg, ExprSet, Input, InputResolve, Limit, Projection,
23 Statement, Value,
24 },
25};
26use std::cmp::Ordering;
27
28enum ScopeStack<'a> {
29 Root,
30 Scope {
31 args: &'a [Value],
32 parent: &'a ScopeStack<'a>,
33 },
34}
35
36impl Statement {
37 pub fn eval(&self, mut input: impl Input) -> Result<Value> {
45 self.eval_ref(&ScopeStack::Root, &mut input)
46 }
47
48 pub fn eval_const(&self) -> Result<Value> {
50 self.eval(ConstInput::new())
51 }
52
53 fn eval_ref(&self, scope: &ScopeStack<'_>, input: &mut impl Input) -> Result<Value> {
54 match self {
55 Statement::Query(query) => {
56 if query.with.is_some() {
57 return Err(crate::Error::expression_evaluation_failed(
58 "cannot evaluate statement with WITH clause",
59 ));
60 }
61
62 if query.order_by.is_some() {
63 return Err(crate::Error::expression_evaluation_failed(
64 "cannot evaluate statement with ORDER BY clause",
65 ));
66 }
67
68 let mut result = query.body.eval_ref(scope, input)?;
69
70 if let Some(limit) = &query.limit {
71 limit.eval_ref(&mut result, scope, input)?;
72 }
73
74 if query.single {
75 let Value::List(mut items) = result else {
76 return Err(crate::Error::expression_evaluation_failed(
77 "single-row query requires body to evaluate to a list",
78 ));
79 };
80 if items.len() != 1 {
81 return Err(crate::Error::expression_evaluation_failed(
82 "single-row query did not return exactly one row",
83 ));
84 }
85 return Ok(items.remove(0));
86 }
87
88 Ok(result)
89 }
90 _ => Err(crate::Error::expression_evaluation_failed(
91 "can only evaluate Query statements",
92 )),
93 }
94 }
95}
96
97impl Limit {
98 fn eval_ref(
99 &self,
100 value: &mut Value,
101 scope: &ScopeStack<'_>,
102 input: &mut impl Input,
103 ) -> Result<()> {
104 let Value::List(items) = value else {
105 return Err(crate::Error::expression_evaluation_failed(
106 "LIMIT requires body to evaluate to a list",
107 ));
108 };
109
110 match self {
111 Limit::Cursor(_) => {
112 return Err(crate::Error::expression_evaluation_failed(
113 "cursor-based pagination cannot be evaluated client-side",
114 ));
115 }
116 Limit::Offset(limit_offset) => {
117 if let Some(offset_expr) = &limit_offset.offset {
118 let skip = offset_expr.eval_ref_usize(scope, input)?;
119 if skip >= items.len() {
120 items.clear();
121 } else {
122 items.drain(..skip);
123 }
124 }
125
126 let n = limit_offset.limit.eval_ref_usize(scope, input)?;
127 items.truncate(n);
128 }
129 }
130 Ok(())
131 }
132}
133
134impl ExprSet {
135 fn eval_ref(&self, scope: &ScopeStack<'_>, input: &mut impl Input) -> Result<Value> {
136 let ExprSet::Values(values) = self else {
137 return Err(crate::Error::expression_evaluation_failed(
138 "can only evaluate Values expressions",
139 ));
140 };
141
142 let mut ret = vec![];
143
144 for row in &values.rows {
145 ret.push(row.eval_ref(scope, input)?);
146 }
147
148 Ok(Value::List(ret))
149 }
150}
151
152impl Expr {
153 pub fn eval(&self, mut input: impl Input) -> Result<Value> {
156 self.eval_ref(&ScopeStack::Root, &mut input)
157 }
158
159 pub fn eval_bool(&self, mut input: impl Input) -> Result<bool> {
165 self.eval_ref_bool(&ScopeStack::Root, &mut input)
166 }
167
168 pub fn eval_const(&self) -> Result<Value> {
170 self.eval(ConstInput::new())
171 }
172
173 fn eval_ref(&self, scope: &ScopeStack<'_>, input: &mut impl Input) -> Result<Value> {
174 match self {
175 Expr::And(expr_and) => {
176 debug_assert!(!expr_and.operands.is_empty());
177
178 for operand in &expr_and.operands {
179 if !operand.eval_ref_bool(scope, input)? {
180 return Ok(false.into());
181 }
182 }
183
184 Ok(true.into())
185 }
186 Expr::Arg(expr_arg) => {
187 let Some(expr) = scope.resolve_arg(expr_arg, &Projection::identity(), input) else {
188 return Err(crate::Error::expression_evaluation_failed(
189 "failed to resolve argument",
190 ));
191 };
192 expr.eval_ref(scope, input)
193 }
194 Expr::BinaryOp(expr_binary_op) => {
195 let lhs = expr_binary_op.lhs.eval_ref(scope, input)?;
196 let rhs = expr_binary_op.rhs.eval_ref(scope, input)?;
197
198 match expr_binary_op.op {
199 BinaryOp::Eq => Ok((lhs == rhs).into()),
200 BinaryOp::Ne => Ok((lhs != rhs).into()),
201 BinaryOp::Ge => Ok((cmp_ordered(&lhs, &rhs)? != Ordering::Less).into()),
202 BinaryOp::Gt => Ok((cmp_ordered(&lhs, &rhs)? == Ordering::Greater).into()),
203 BinaryOp::Le => Ok((cmp_ordered(&lhs, &rhs)? != Ordering::Greater).into()),
204 BinaryOp::Lt => Ok((cmp_ordered(&lhs, &rhs)? == Ordering::Less).into()),
205 BinaryOp::Add => lhs.checked_add(&rhs).ok_or_else(|| {
206 crate::Error::expression_evaluation_failed(
207 "arithmetic overflow or type mismatch in `+`",
208 )
209 }),
210 BinaryOp::Sub => lhs.checked_sub(&rhs).ok_or_else(|| {
211 crate::Error::expression_evaluation_failed(
212 "arithmetic overflow or type mismatch in `-`",
213 )
214 }),
215 }
216 }
217 Expr::Cast(expr_cast) => {
218 let value = expr_cast.expr.eval_ref(scope, input)?;
219 expr_cast
220 .ty
221 .cast_from(&InputResolve(&*input), expr_cast.from.as_ref(), value)
222 }
223 Expr::Default => Err(crate::Error::expression_evaluation_failed(
224 "DEFAULT can only be evaluated by the database",
225 )),
226 Expr::Error(expr_error) => Err(crate::Error::expression_evaluation_failed(
227 &expr_error.message,
228 )),
229 Expr::IsNull(expr_is_null) => {
230 let value = expr_is_null.expr.eval_ref(scope, input)?;
231 Ok(value.is_null().into())
232 }
233 Expr::IsVariant(_) => Err(crate::Error::expression_evaluation_failed(
234 "IsVariant must be lowered before evaluation",
235 )),
236 Expr::Let(expr_let) => {
237 let args: Vec<_> = expr_let
238 .bindings
239 .iter()
240 .map(|b| b.eval_ref(scope, input))
241 .collect::<Result<_, _>>()?;
242 let scope = scope.scope(&args);
243 expr_let.body.eval_ref(&scope, input)
244 }
245 Expr::Not(expr_not) => {
246 let value = expr_not.expr.eval_ref_bool(scope, input)?;
247 Ok((!value).into())
248 }
249 Expr::List(exprs) => {
250 let mut ret = vec![];
251
252 for expr in &exprs.items {
253 ret.push(expr.eval_ref(scope, input)?);
254 }
255
256 Ok(Value::List(ret))
257 }
258 Expr::Map(expr_map) => {
259 let mut base = expr_map.base.eval_ref(scope, input)?;
260
261 let Value::List(items) = &mut base else {
262 return Err(crate::Error::expression_evaluation_failed(
263 "Map base must evaluate to a list",
264 ));
265 };
266
267 for item in items.iter_mut() {
268 let args = [item.take()];
269 let scope = scope.scope(&args);
270 *item = expr_map.map.eval_ref(&scope, input)?;
271 }
272
273 Ok(base)
274 }
275 Expr::Project(expr_project) => match &*expr_project.base {
276 Expr::Arg(expr_arg) => {
277 let Some(expr) = scope.resolve_arg(expr_arg, &expr_project.projection, input)
278 else {
279 return Err(crate::Error::expression_evaluation_failed(
280 "failed to resolve argument",
281 ));
282 };
283
284 expr.eval_ref(scope, input)
285 }
286 Expr::Reference(expr_reference) => {
287 let Some(expr) = input.resolve_ref(expr_reference, &expr_project.projection)
288 else {
289 return Err(crate::Error::expression_evaluation_failed(
290 "failed to resolve reference",
291 ));
292 };
293
294 expr.eval_ref(scope, input)
295 }
296 _ => {
297 let base = expr_project.base.eval_ref(scope, input)?;
298 Ok(base.entry(&expr_project.projection).to_value())
299 }
300 },
301 Expr::Record(expr_record) => {
302 let mut ret = Vec::with_capacity(expr_record.len());
303
304 for expr in &expr_record.fields {
305 ret.push(expr.eval_ref(scope, input)?);
306 }
307
308 Ok(Value::record_from_vec(ret))
309 }
310 Expr::Reference(expr_reference) => {
311 let Some(expr) = input.resolve_ref(expr_reference, &Projection::identity()) else {
312 return Err(crate::Error::expression_evaluation_failed(
313 "failed to resolve reference",
314 ));
315 };
316
317 expr.eval_ref(scope, input)
318 }
319 Expr::Or(expr_or) => {
320 debug_assert!(!expr_or.operands.is_empty());
321
322 for operand in &expr_or.operands {
323 if operand.eval_ref_bool(scope, input)? {
324 return Ok(true.into());
325 }
326 }
327
328 Ok(false.into())
329 }
330 Expr::Any(expr_any) => {
331 let list = expr_any.expr.eval_ref(scope, input)?;
332
333 let Value::List(items) = list else {
334 return Err(crate::Error::expression_evaluation_failed(
335 "Any expression must evaluate to a list",
336 ));
337 };
338
339 for item in &items {
340 match item {
341 Value::Bool(true) => return Ok(true.into()),
342 Value::Bool(false) => {}
343 _ => {
344 return Err(crate::Error::expression_evaluation_failed(
345 "Any expression items must evaluate to bool",
346 ));
347 }
348 }
349 }
350
351 Ok(false.into())
352 }
353 Expr::InList(expr_in_list) => {
354 let needle = expr_in_list.expr.eval_ref(scope, input)?;
355 let list = expr_in_list.list.eval_ref(scope, input)?;
356
357 let Value::List(items) = list else {
358 return Err(crate::Error::expression_evaluation_failed(
359 "InList right-hand side must evaluate to a list",
360 ));
361 };
362
363 Ok(items.iter().any(|item| item == &needle).into())
364 }
365 Expr::AnyOp(e) => {
366 let lhs = e.lhs.eval_ref(scope, input)?;
367 let rhs = e.rhs.eval_ref(scope, input)?;
368 let Value::List(items) = rhs else {
369 return Err(crate::Error::expression_evaluation_failed(
370 "ANY right-hand side must evaluate to a list",
371 ));
372 };
373 Ok(any_all_compare(&lhs, &items, e.op, false)?.into())
374 }
375 Expr::AllOp(e) => {
376 let lhs = e.lhs.eval_ref(scope, input)?;
377 let rhs = e.rhs.eval_ref(scope, input)?;
378 let Value::List(items) = rhs else {
379 return Err(crate::Error::expression_evaluation_failed(
380 "ALL right-hand side must evaluate to a list",
381 ));
382 };
383 Ok(any_all_compare(&lhs, &items, e.op, true)?.into())
384 }
385 Expr::Match(expr_match) => {
386 let subject = expr_match.subject.eval_ref(scope, input)?;
387 for arm in &expr_match.arms {
388 if subject == arm.pattern {
389 return arm.expr.eval_ref(scope, input);
390 }
391 }
392 expr_match.else_expr.eval_ref(scope, input)
393 }
394 Expr::Exists(expr_exists) => {
395 match &expr_exists.subquery.body {
399 ExprSet::Values(values) => {
400 for row in &values.rows {
401 let val = row.eval_ref(scope, input)?;
402 match val {
403 Value::List(items) if items.is_empty() => {}
405 Value::Null => {}
407 _ => return Ok(true.into()),
409 }
410 }
411 Ok(false.into())
412 }
413 _ => todo!("ExprExists with non-Values body"),
414 }
415 }
416 Expr::Value(value) => Ok(value.clone()),
417 Expr::Func(super::ExprFunc::JsonExtract(func)) => {
423 let mut value = func.base.eval_ref(scope, input)?;
424 for key in &func.path {
425 value = match value {
426 Value::Object(mut object) => {
427 match object.entries.iter().position(|(k, _)| k == key) {
428 Some(index) => object.entries.swap_remove(index).1,
429 None => return Ok(Value::Null),
430 }
431 }
432 Value::Null => return Ok(Value::Null),
433 other => {
434 return Err(crate::Error::expression_evaluation_failed(format!(
435 "document path step `{key}` into non-object value {other:?}"
436 )));
437 }
438 };
439 }
440 func.ty.cast(&InputResolve(&*input), value)
441 }
442 Expr::Func(_) => Err(crate::Error::expression_evaluation_failed(
443 "database functions cannot be evaluated client-side",
444 )),
445 _ => todo!("expr={self:#?}"),
446 }
447 }
448
449 fn eval_ref_bool(&self, scope: &ScopeStack<'_>, input: &mut impl Input) -> Result<bool> {
450 match self.eval_ref(scope, input)? {
451 Value::Bool(ret) => Ok(ret),
452 _ => Err(crate::Error::expression_evaluation_failed(
453 "expected boolean value",
454 )),
455 }
456 }
457
458 fn eval_ref_usize(&self, scope: &ScopeStack<'_>, input: &mut impl Input) -> Result<usize> {
459 match self.eval_ref(scope, input)? {
460 Value::I64(n) if n >= 0 => Ok(n as usize),
461 _ => Err(crate::Error::expression_evaluation_failed(
462 "expected non-negative integer",
463 )),
464 }
465 }
466}
467
468impl ScopeStack<'_> {
469 fn resolve_arg(
470 &self,
471 expr_arg: &ExprArg,
472 projection: &Projection,
473 input: &mut impl Input,
474 ) -> Option<Expr> {
475 let mut nesting = expr_arg.nesting;
476 let mut scope = self;
477
478 while nesting > 0 {
479 nesting -= 1;
480
481 scope = match scope {
482 ScopeStack::Root => return None,
483 ScopeStack::Scope { parent, .. } => parent,
484 };
485 }
486
487 match scope {
488 ScopeStack::Root => input.resolve_arg(expr_arg, projection),
489 &ScopeStack::Scope { mut args, .. } => args.resolve_arg(expr_arg, projection),
490 }
491 }
492
493 fn scope<'child>(&'child self, args: &'child [Value]) -> ScopeStack<'child> {
494 ScopeStack::Scope { args, parent: self }
495 }
496}
497
498fn cmp_ordered(lhs: &Value, rhs: &Value) -> Result<Ordering> {
499 if lhs.is_null() || rhs.is_null() {
500 return Err(crate::Error::expression_evaluation_failed(
501 "ordered comparison with NULL is undefined",
502 ));
503 }
504 lhs.partial_cmp(rhs).ok_or_else(|| {
505 crate::Error::expression_evaluation_failed("ordered comparison between incompatible types")
506 })
507}
508
509fn any_all_compare(lhs: &Value, items: &[Value], op: BinaryOp, all: bool) -> Result<bool> {
510 for item in items {
511 let matches = match op {
512 BinaryOp::Eq => lhs == item,
513 BinaryOp::Ne => lhs != item,
514 BinaryOp::Ge => cmp_ordered(lhs, item)? != Ordering::Less,
515 BinaryOp::Gt => cmp_ordered(lhs, item)? == Ordering::Greater,
516 BinaryOp::Le => cmp_ordered(lhs, item)? != Ordering::Greater,
517 BinaryOp::Lt => cmp_ordered(lhs, item)? == Ordering::Less,
518 BinaryOp::Add | BinaryOp::Sub => {
519 return Err(crate::Error::expression_evaluation_failed(
520 "ANY/ALL only supports comparison operators",
521 ));
522 }
523 };
524 if all {
525 if !matches {
526 return Ok(false);
527 }
528 } else if matches {
529 return Ok(true);
530 }
531 }
532 Ok(all)
534}