Skip to main content

reifydb_engine/vm/volcano/
variable.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (c) 2026 ReifyDB
3
4use std::sync::Arc;
5
6use reifydb_core::value::column::{columns::Columns, headers::ColumnHeaders};
7use reifydb_evaluate::{error::EvaluateError, stack::Variable};
8use reifydb_rql::expression::VariableExpression;
9use reifydb_transaction::transaction::Transaction;
10use reifydb_value::reifydb_assertions;
11use tracing::instrument;
12
13use crate::{
14	Result,
15	vm::volcano::query::{QueryContext, QueryNode},
16};
17
18pub(crate) struct VariableNode {
19	variable_expr: VariableExpression,
20	context: Option<Arc<QueryContext>>,
21	executed: bool,
22}
23
24impl VariableNode {
25	pub fn new(variable_expr: VariableExpression) -> Self {
26		Self {
27			variable_expr,
28			context: None,
29			executed: false,
30		}
31	}
32}
33
34impl QueryNode for VariableNode {
35	#[instrument(level = "trace", skip_all, name = "volcano::variable::initialize")]
36	fn initialize<'a>(&mut self, _rx: &mut Transaction<'a>, ctx: &QueryContext) -> Result<()> {
37		self.context = Some(Arc::new(ctx.clone()));
38		Ok(())
39	}
40
41	#[instrument(level = "trace", skip_all, name = "volcano::variable::next")]
42	fn next<'a>(&mut self, _rx: &mut Transaction<'a>, ctx: &mut QueryContext) -> Result<Option<Columns>> {
43		reifydb_assertions! {
44			assert!(self.context.is_some(), "VariableNode::next() called before initialize()");
45		}
46
47		if self.executed {
48			return Ok(None);
49		}
50
51		let variable_name = self.variable_expr.name();
52
53		match ctx.symbols.get(variable_name) {
54			Some(Variable::Columns {
55				columns,
56			}) => {
57				self.executed = true;
58				Ok(Some(columns.clone()))
59			}
60			Some(Variable::ForIterator {
61				columns,
62				..
63			}) => {
64				self.executed = true;
65
66				Ok(Some(columns.clone()))
67			}
68			Some(Variable::Closure(_)) => Err(EvaluateError::VariableNotFound {
69				name: variable_name.to_string(),
70			}
71			.into()),
72			None => Err(EvaluateError::VariableNotFound {
73				name: variable_name.to_string(),
74			}
75			.into()),
76		}
77	}
78
79	fn headers(&self) -> Option<ColumnHeaders> {
80		None
81	}
82}