reifydb_engine/evaluate/
mod.rs

1// Copyright (c) reifydb.com 2025
2// This file is licensed under the AGPL-3.0-or-later, see license.md file
3
4mod arith;
5pub mod column;
6pub mod convert;
7pub mod row;
8
9// Copyright (c) reifydb.com 2025
10// This file is licensed under the AGPL-3.0-or-later, see license.md file
11
12use reifydb_core::{
13	Row,
14	interface::{ColumnPolicyKind, ColumnSaturationPolicy, DEFAULT_COLUMN_SATURATION_POLICY, ResolvedColumn},
15	value::column::{ColumnData, Columns},
16};
17use reifydb_type::{Params, Type};
18
19use crate::stack::Stack;
20// FIXME this should not be part of core - engine should be sufficient now
21
22/// Represents target column information for evaluation
23#[derive(Debug, Clone)]
24pub enum TargetColumn<'a> {
25	/// Fully resolved column with complete source information
26	Resolved(ResolvedColumn<'a>),
27	/// Partial column information with type, policies, and optional names for error reporting
28	Partial {
29		source_name: Option<String>,
30		column_name: Option<String>,
31		column_type: Type,
32		policies: Vec<ColumnPolicyKind>,
33	},
34}
35
36impl<'a> TargetColumn<'a> {
37	/// Get the column type
38	pub fn column_type(&self) -> Type {
39		match self {
40			Self::Resolved(col) => col.column_type(),
41			Self::Partial {
42				column_type,
43				..
44			} => *column_type,
45		}
46	}
47
48	/// Get the column policies
49	pub fn policies(&self) -> Vec<ColumnPolicyKind> {
50		match self {
51			Self::Resolved(col) => col.policies(),
52			Self::Partial {
53				policies,
54				..
55			} => policies.clone(),
56		}
57	}
58
59	// FIXME remove this
60	/// Convert to NumberOfRangeColumnDescriptor for error reporting
61	pub fn to_number_descriptor(&self) -> Option<reifydb_type::diagnostic::number::NumberOfRangeColumnDescriptor> {
62		use reifydb_core::interface::resolved::resolved_column_to_number_descriptor;
63		use reifydb_type::diagnostic::number::NumberOfRangeColumnDescriptor;
64
65		match self {
66			Self::Resolved(col) => Some(resolved_column_to_number_descriptor(col)),
67			Self::Partial {
68				column_type,
69				source_name,
70				column_name,
71				..
72			} => {
73				// Only create descriptor if we have at least some name information
74				if source_name.is_some() || column_name.is_some() {
75					Some(NumberOfRangeColumnDescriptor {
76						namespace: None,
77						table: source_name.as_deref(),
78						column: column_name.as_deref(),
79						column_type: Some(*column_type),
80					})
81				} else {
82					None
83				}
84			}
85		}
86	}
87}
88
89#[derive(Debug)]
90pub struct ColumnEvaluationContext<'a> {
91	pub target: Option<TargetColumn<'a>>,
92	pub columns: Columns<'a>,
93	pub row_count: usize,
94	pub take: Option<usize>,
95	pub params: &'a Params,
96	pub stack: &'a Stack,
97	// TODO: This is a temporary hack to support aggregate functions in StandardColumnEvaluator
98	// Should be replaced with proper function detection or separate aggregation methods
99	pub is_aggregate_context: bool,
100}
101
102impl<'a> ColumnEvaluationContext<'a> {
103	pub fn testing() -> Self {
104		use std::sync::LazyLock;
105		static EMPTY_PARAMS: LazyLock<Params> = LazyLock::new(|| Params::None);
106		static EMPTY_STACK: LazyLock<Stack> = LazyLock::new(|| Stack::new());
107		Self {
108			target: None,
109			columns: Columns::empty(),
110			row_count: 1,
111			take: None,
112			params: &EMPTY_PARAMS,
113			stack: &EMPTY_STACK,
114			is_aggregate_context: false,
115		}
116	}
117
118	pub(crate) fn saturation_policy(&self) -> ColumnSaturationPolicy {
119		self.target
120			.as_ref()
121			.and_then(|t| {
122				t.policies().into_iter().find_map(|p| match p {
123					ColumnPolicyKind::Saturation(policy) => Some(policy),
124				})
125			})
126			.unwrap_or(DEFAULT_COLUMN_SATURATION_POLICY.clone())
127	}
128
129	#[inline]
130	pub fn pooled(&self, target: Type, capacity: usize) -> ColumnData {
131		ColumnData::with_capacity(target, capacity)
132	}
133}
134
135pub struct RowEvaluationContext<'a> {
136	pub row: Row,
137	pub target: Option<TargetColumn<'a>>,
138	pub params: &'a Params,
139}