1use crate::{
20 Result,
21 stmt::{
22 BinaryOp, ConstInput, Expr, ExprArg, ExprSet, Input, Limit, Offset, Projection, Statement,
23 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 if let Some(offset) = &self.offset {
111 match offset {
112 Offset::Count(offset_expr) => {
113 let skip = offset_expr.eval_ref_usize(scope, input)?;
114 if skip >= items.len() {
115 items.clear();
116 } else {
117 items.drain(..skip);
118 }
119 }
120 Offset::After(_) => {
121 return Err(crate::Error::expression_evaluation_failed(
122 "keyset-based OFFSET cannot be evaluated client-side",
123 ));
124 }
125 }
126 }
127
128 let n = self.limit.eval_ref_usize(scope, input)?;
129 items.truncate(n);
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 }
206 }
207 Expr::Cast(expr_cast) => expr_cast.ty.cast(expr_cast.expr.eval_ref(scope, input)?),
208 Expr::Default => Err(crate::Error::expression_evaluation_failed(
209 "DEFAULT can only be evaluated by the database",
210 )),
211 Expr::Error(expr_error) => Err(crate::Error::expression_evaluation_failed(
212 &expr_error.message,
213 )),
214 Expr::IsNull(expr_is_null) => {
215 let value = expr_is_null.expr.eval_ref(scope, input)?;
216 Ok(value.is_null().into())
217 }
218 Expr::IsVariant(_) => Err(crate::Error::expression_evaluation_failed(
219 "IsVariant must be lowered before evaluation",
220 )),
221 Expr::Let(expr_let) => {
222 let args: Vec<_> = expr_let
223 .bindings
224 .iter()
225 .map(|b| b.eval_ref(scope, input))
226 .collect::<Result<_, _>>()?;
227 let scope = scope.scope(&args);
228 expr_let.body.eval_ref(&scope, input)
229 }
230 Expr::Not(expr_not) => {
231 let value = expr_not.expr.eval_ref_bool(scope, input)?;
232 Ok((!value).into())
233 }
234 Expr::List(exprs) => {
235 let mut ret = vec![];
236
237 for expr in &exprs.items {
238 ret.push(expr.eval_ref(scope, input)?);
239 }
240
241 Ok(Value::List(ret))
242 }
243 Expr::Map(expr_map) => {
244 let mut base = expr_map.base.eval_ref(scope, input)?;
245
246 let Value::List(items) = &mut base else {
247 return Err(crate::Error::expression_evaluation_failed(
248 "Map base must evaluate to a list",
249 ));
250 };
251
252 for item in items.iter_mut() {
253 let args = [item.take()];
254 let scope = scope.scope(&args);
255 *item = expr_map.map.eval_ref(&scope, input)?;
256 }
257
258 Ok(base)
259 }
260 Expr::Project(expr_project) => match &*expr_project.base {
261 Expr::Arg(expr_arg) => {
262 let Some(expr) = scope.resolve_arg(expr_arg, &expr_project.projection, input)
263 else {
264 return Err(crate::Error::expression_evaluation_failed(
265 "failed to resolve argument",
266 ));
267 };
268
269 expr.eval_ref(scope, input)
270 }
271 Expr::Reference(expr_reference) => {
272 let Some(expr) = input.resolve_ref(expr_reference, &expr_project.projection)
273 else {
274 return Err(crate::Error::expression_evaluation_failed(
275 "failed to resolve reference",
276 ));
277 };
278
279 expr.eval_ref(scope, input)
280 }
281 _ => {
282 let base = expr_project.base.eval_ref(scope, input)?;
283 Ok(base.entry(&expr_project.projection).to_value())
284 }
285 },
286 Expr::Record(expr_record) => {
287 let mut ret = Vec::with_capacity(expr_record.len());
288
289 for expr in &expr_record.fields {
290 ret.push(expr.eval_ref(scope, input)?);
291 }
292
293 Ok(Value::record_from_vec(ret))
294 }
295 Expr::Reference(expr_reference) => {
296 let Some(expr) = input.resolve_ref(expr_reference, &Projection::identity()) else {
297 return Err(crate::Error::expression_evaluation_failed(
298 "failed to resolve reference",
299 ));
300 };
301
302 expr.eval_ref(scope, input)
303 }
304 Expr::Or(expr_or) => {
305 debug_assert!(!expr_or.operands.is_empty());
306
307 for operand in &expr_or.operands {
308 if operand.eval_ref_bool(scope, input)? {
309 return Ok(true.into());
310 }
311 }
312
313 Ok(false.into())
314 }
315 Expr::Any(expr_any) => {
316 let list = expr_any.expr.eval_ref(scope, input)?;
317
318 let Value::List(items) = list else {
319 return Err(crate::Error::expression_evaluation_failed(
320 "Any expression must evaluate to a list",
321 ));
322 };
323
324 for item in &items {
325 match item {
326 Value::Bool(true) => return Ok(true.into()),
327 Value::Bool(false) => {}
328 _ => {
329 return Err(crate::Error::expression_evaluation_failed(
330 "Any expression items must evaluate to bool",
331 ));
332 }
333 }
334 }
335
336 Ok(false.into())
337 }
338 Expr::InList(expr_in_list) => {
339 let needle = expr_in_list.expr.eval_ref(scope, input)?;
340 let list = expr_in_list.list.eval_ref(scope, input)?;
341
342 let Value::List(items) = list else {
343 return Err(crate::Error::expression_evaluation_failed(
344 "InList right-hand side must evaluate to a list",
345 ));
346 };
347
348 Ok(items.iter().any(|item| item == &needle).into())
349 }
350 Expr::Match(expr_match) => {
351 let subject = expr_match.subject.eval_ref(scope, input)?;
352 for arm in &expr_match.arms {
353 if subject == arm.pattern {
354 return arm.expr.eval_ref(scope, input);
355 }
356 }
357 expr_match.else_expr.eval_ref(scope, input)
358 }
359 Expr::Exists(expr_exists) => {
360 match &expr_exists.subquery.body {
364 ExprSet::Values(values) => {
365 for row in &values.rows {
366 let val = row.eval_ref(scope, input)?;
367 match val {
368 Value::List(items) if items.is_empty() => {}
370 Value::Null => {}
372 _ => return Ok(true.into()),
374 }
375 }
376 Ok(false.into())
377 }
378 _ => todo!("ExprExists with non-Values body"),
379 }
380 }
381 Expr::Value(value) => Ok(value.clone()),
382 Expr::Func(_) => Err(crate::Error::expression_evaluation_failed(
383 "database functions cannot be evaluated client-side",
384 )),
385 _ => todo!("expr={self:#?}"),
386 }
387 }
388
389 fn eval_ref_bool(&self, scope: &ScopeStack<'_>, input: &mut impl Input) -> Result<bool> {
390 match self.eval_ref(scope, input)? {
391 Value::Bool(ret) => Ok(ret),
392 _ => Err(crate::Error::expression_evaluation_failed(
393 "expected boolean value",
394 )),
395 }
396 }
397
398 fn eval_ref_usize(&self, scope: &ScopeStack<'_>, input: &mut impl Input) -> Result<usize> {
399 match self.eval_ref(scope, input)? {
400 Value::I64(n) if n >= 0 => Ok(n as usize),
401 _ => Err(crate::Error::expression_evaluation_failed(
402 "expected non-negative integer",
403 )),
404 }
405 }
406}
407
408impl ScopeStack<'_> {
409 fn resolve_arg(
410 &self,
411 expr_arg: &ExprArg,
412 projection: &Projection,
413 input: &mut impl Input,
414 ) -> Option<Expr> {
415 let mut nesting = expr_arg.nesting;
416 let mut scope = self;
417
418 while nesting > 0 {
419 nesting -= 1;
420
421 scope = match scope {
422 ScopeStack::Root => return None,
423 ScopeStack::Scope { parent, .. } => parent,
424 };
425 }
426
427 match scope {
428 ScopeStack::Root => input.resolve_arg(expr_arg, projection),
429 &ScopeStack::Scope { mut args, .. } => args.resolve_arg(expr_arg, projection),
430 }
431 }
432
433 fn scope<'child>(&'child self, args: &'child [Value]) -> ScopeStack<'child> {
434 ScopeStack::Scope { args, parent: self }
435 }
436}
437
438fn cmp_ordered(lhs: &Value, rhs: &Value) -> Result<Ordering> {
439 if lhs.is_null() || rhs.is_null() {
440 return Err(crate::Error::expression_evaluation_failed(
441 "ordered comparison with NULL is undefined",
442 ));
443 }
444 lhs.partial_cmp(rhs).ok_or_else(|| {
445 crate::Error::expression_evaluation_failed("ordered comparison between incompatible types")
446 })
447}