Skip to main content

reifydb_engine/expression/
context.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (c) 2025 ReifyDB
3
4use std::sync::LazyLock;
5
6use reifydb_core::{
7	interface::{
8		catalog::property::{ColumnPropertyKind, ColumnSaturationStrategy, DEFAULT_COLUMN_SATURATION_STRATEGY},
9		evaluate::TargetColumn,
10	},
11	value::column::columns::Columns,
12};
13use reifydb_extension::transform::context::TransformContext;
14use reifydb_routine::function::registry::Functions;
15use reifydb_runtime::context::{RuntimeContext, clock::Clock};
16use reifydb_type::{params::Params, value::identity::IdentityId};
17
18use crate::{
19	arena::QueryArena,
20	vm::{stack::SymbolTable, volcano::query::QueryContext},
21};
22
23pub struct EvalContext<'a> {
24	pub target: Option<TargetColumn>,
25	pub columns: Columns,
26	pub row_count: usize,
27	pub take: Option<usize>,
28	pub params: &'a Params,
29	pub symbols: &'a SymbolTable,
30	pub is_aggregate_context: bool,
31	pub functions: &'a Functions,
32	pub runtime_context: &'a RuntimeContext,
33	pub arena: Option<&'a QueryArena>,
34	pub identity: IdentityId,
35}
36
37impl<'a> EvalContext<'a> {
38	pub fn testing() -> EvalContext<'static> {
39		static EMPTY_PARAMS: LazyLock<Params> = LazyLock::new(|| Params::None);
40		static EMPTY_SYMBOL_TABLE: LazyLock<SymbolTable> = LazyLock::new(SymbolTable::new);
41		static EMPTY_FUNCTIONS: LazyLock<Functions> = LazyLock::new(Functions::empty);
42		static DEFAULT_RUNTIME_CONTEXT: LazyLock<RuntimeContext> =
43			LazyLock::new(|| RuntimeContext::with_clock(Clock::Real));
44
45		EvalContext {
46			target: None,
47			columns: Columns::empty(),
48			row_count: 1,
49			take: None,
50			params: &EMPTY_PARAMS,
51			symbols: &EMPTY_SYMBOL_TABLE,
52			is_aggregate_context: false,
53			functions: &EMPTY_FUNCTIONS,
54			runtime_context: &DEFAULT_RUNTIME_CONTEXT,
55			arena: None,
56			identity: IdentityId::root(),
57		}
58	}
59
60	/// Sibling context with fresh `columns` / `row_count`, sharing all invariant refs.
61	pub fn with_eval(&self, columns: Columns, row_count: usize) -> EvalContext<'a> {
62		EvalContext {
63			target: None,
64			columns,
65			row_count,
66			take: None,
67			params: self.params,
68			symbols: self.symbols,
69			is_aggregate_context: self.is_aggregate_context,
70			functions: self.functions,
71			runtime_context: self.runtime_context,
72			arena: self.arena,
73			identity: self.identity,
74		}
75	}
76
77	pub fn with_eval_empty(&self) -> EvalContext<'a> {
78		self.with_eval(Columns::empty(), 1)
79	}
80
81	pub fn with_eval_join(&self, columns: Columns) -> EvalContext<'a> {
82		let mut ctx = self.with_eval(columns, 1);
83		ctx.take = Some(1);
84		ctx
85	}
86
87	pub fn from_query(ctx: &'a QueryContext) -> Self {
88		EvalContext {
89			target: None,
90			columns: Columns::empty(),
91			row_count: 1,
92			take: None,
93			params: &ctx.params,
94			symbols: &ctx.symbols,
95			is_aggregate_context: false,
96			functions: &ctx.services.functions,
97			runtime_context: &ctx.services.runtime_context,
98			arena: None,
99			identity: ctx.identity,
100		}
101	}
102
103	pub fn from_transform(ctx: &'a TransformContext, stored: &'a QueryContext) -> Self {
104		EvalContext {
105			target: None,
106			columns: Columns::empty(),
107			row_count: 1,
108			take: None,
109			params: ctx.params,
110			symbols: &stored.symbols,
111			is_aggregate_context: false,
112			functions: ctx.functions,
113			runtime_context: ctx.runtime_context,
114			arena: None,
115			identity: stored.identity,
116		}
117	}
118
119	pub(crate) fn saturation_policy(&self) -> ColumnSaturationStrategy {
120		self.target
121			.as_ref()
122			.and_then(|t| {
123				t.properties()
124					.into_iter()
125					.map(|p| {
126						let ColumnPropertyKind::Saturation(policy) = p;
127						policy
128					})
129					.next()
130			})
131			.unwrap_or(DEFAULT_COLUMN_SATURATION_STRATEGY.clone())
132	}
133}
134
135/// Compile-time context for resolving functions and UDFs.
136pub struct CompileContext<'a> {
137	pub functions: &'a Functions,
138	pub symbols: &'a SymbolTable,
139}