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 {
25	/// Fully resolved column with complete source information
26	Resolved(ResolvedColumn),
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 TargetColumn {
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(
62		&self,
63	) -> Option<reifydb_type::diagnostic::number::NumberOfRangeColumnDescriptor<'_>> {
64		use reifydb_core::interface::resolved::resolved_column_to_number_descriptor;
65		use reifydb_type::diagnostic::number::NumberOfRangeColumnDescriptor;
66
67		match self {
68			Self::Resolved(col) => Some(resolved_column_to_number_descriptor(col)),
69			Self::Partial {
70				column_type,
71				source_name,
72				column_name,
73				..
74			} => {
75				// Only create descriptor if we have at least some name information
76				if source_name.is_some() || column_name.is_some() {
77					Some(NumberOfRangeColumnDescriptor {
78						namespace: None,
79						table: source_name.as_deref(),
80						column: column_name.as_deref(),
81						column_type: Some(*column_type),
82					})
83				} else {
84					None
85				}
86			}
87		}
88	}
89}
90
91#[derive(Debug)]
92pub struct ColumnEvaluationContext<'a> {
93	pub target: Option<TargetColumn>,
94	pub columns: Columns,
95	pub row_count: usize,
96	pub take: Option<usize>,
97	pub params: &'a Params,
98	pub stack: &'a Stack,
99	// TODO: This is a temporary hack to support aggregate functions in StandardColumnEvaluator
100	// Should be replaced with proper function detection or separate aggregation methods
101	pub is_aggregate_context: bool,
102}
103
104impl<'a> ColumnEvaluationContext<'a> {
105	pub fn testing() -> Self {
106		use std::sync::LazyLock;
107		static EMPTY_PARAMS: LazyLock<Params> = LazyLock::new(|| Params::None);
108		static EMPTY_STACK: LazyLock<Stack> = LazyLock::new(|| Stack::new());
109		Self {
110			target: None,
111			columns: Columns::empty(),
112			row_count: 1,
113			take: None,
114			params: &EMPTY_PARAMS,
115			stack: &EMPTY_STACK,
116			is_aggregate_context: false,
117		}
118	}
119
120	pub(crate) fn saturation_policy(&self) -> ColumnSaturationPolicy {
121		self.target
122			.as_ref()
123			.and_then(|t| {
124				t.policies().into_iter().find_map(|p| match p {
125					ColumnPolicyKind::Saturation(policy) => Some(policy),
126				})
127			})
128			.unwrap_or(DEFAULT_COLUMN_SATURATION_POLICY.clone())
129	}
130
131	#[inline]
132	pub fn pooled(&self, target: Type, capacity: usize) -> ColumnData {
133		ColumnData::with_capacity(target, capacity)
134	}
135}
136
137pub struct RowEvaluationContext<'a> {
138	pub row: Row,
139	pub target: Option<TargetColumn>,
140	pub params: &'a Params,
141}