Skip to main content

reifydb_column/
error.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (c) 2025 ReifyDB
3
4use reifydb_type::{
5	error::{Diagnostic, Error, IntoDiagnostic},
6	fragment::Fragment,
7	value::r#type::Type,
8};
9
10#[derive(Debug, thiserror::Error)]
11pub enum ColumnError {
12	#[error("{operation}: column '{name}' not in schema")]
13	ColumnNotInSchema {
14		operation: &'static str,
15		name: String,
16	},
17
18	#[error("{operation}: only FixedArray storage supported in v1")]
19	FixedArrayRequired {
20		operation: &'static str,
21	},
22
23	#[error("take: indices must be a fixed-width integer array")]
24	TakeIndicesNotFixed,
25
26	#[error("take: indices must be U8/U16/U32/U64 or I32/I64")]
27	TakeIndicesWrongWidth,
28
29	#[error("Canonical::from_column_buffer: {variant} not yet supported")]
30	FromColumnDataUnsupported {
31		variant: &'static str,
32	},
33
34	#[error("Canonical::to_column_buffer: unexpected VarLen type {ty}")]
35	ToColumnDataUnexpectedVarLen {
36		ty: Type,
37	},
38
39	#[error("Canonical::to_column_buffer: unexpected BigNum type {ty}")]
40	ToColumnDataUnexpectedBigNum {
41		ty: Type,
42	},
43
44	#[error("Canonical::to_column_buffer: invalid UTF-8: {reason}")]
45	ToColumnDataInvalidUtf8 {
46		reason: String,
47	},
48
49	#[error("compare: column storage `{storage}` requires rhs `{expected}`")]
50	CompareRhsTypeMismatch {
51		storage: &'static str,
52		expected: &'static str,
53	},
54
55	#[error("compare: BigNum comparison not yet implemented")]
56	CompareBigNumUnsupported,
57
58	#[error("predicate::evaluate: compare did not return a bool array")]
59	PredicateCompareNotBool,
60
61	#[error("search_sorted: storage/needle type mismatch or unsupported")]
62	SearchSortedTypeMismatch,
63
64	#[error("min_max: empty array has no min/max")]
65	MinMaxEmpty,
66
67	#[error("min_max: all rows are None")]
68	MinMaxAllNone,
69
70	#[error("min_max: float min/max not yet implemented (NaN handling)")]
71	MinMaxFloatUnsupported,
72}
73
74impl From<ColumnError> for Error {
75	fn from(err: ColumnError) -> Self {
76		Error(Box::new(err.into_diagnostic()))
77	}
78}
79
80impl IntoDiagnostic for ColumnError {
81	fn into_diagnostic(self) -> Diagnostic {
82		match self {
83			ColumnError::ColumnNotInSchema {
84				operation,
85				name,
86			} => Diagnostic {
87				code: "COL_003".to_string(),
88				rql: None,
89				message: format!("{operation}: column '{name}' not in schema"),
90				column: None,
91				fragment: Fragment::None,
92				label: Some("column not found".to_string()),
93				help: Some("Verify the column name matches the block's schema".to_string()),
94				notes: vec![],
95				cause: None,
96				operator_chain: None,
97			},
98
99			ColumnError::FixedArrayRequired {
100				operation,
101			} => Diagnostic {
102				code: "COL_004".to_string(),
103				rql: None,
104				message: format!("{operation}: only FixedArray storage supported in v1"),
105				column: None,
106				fragment: Fragment::None,
107				label: None,
108				help: None,
109				notes: vec![],
110				cause: None,
111				operator_chain: None,
112			},
113
114			ColumnError::TakeIndicesNotFixed => Diagnostic {
115				code: "COL_005".to_string(),
116				rql: None,
117				message: "take: indices must be a fixed-width integer array".to_string(),
118				column: None,
119				fragment: Fragment::None,
120				label: None,
121				help: None,
122				notes: vec![],
123				cause: None,
124				operator_chain: None,
125			},
126
127			ColumnError::TakeIndicesWrongWidth => Diagnostic {
128				code: "COL_006".to_string(),
129				rql: None,
130				message: "take: indices must be U8/U16/U32/U64 or I32/I64".to_string(),
131				column: None,
132				fragment: Fragment::None,
133				label: None,
134				help: None,
135				notes: vec![],
136				cause: None,
137				operator_chain: None,
138			},
139
140			ColumnError::FromColumnDataUnsupported {
141				variant,
142			} => Diagnostic {
143				code: "COL_007".to_string(),
144				rql: None,
145				message: format!("Canonical::from_column_buffer: {variant} not yet supported"),
146				column: None,
147				fragment: Fragment::None,
148				label: Some(format!("{variant} column")),
149				help: None,
150				notes: vec![],
151				cause: None,
152				operator_chain: None,
153			},
154
155			ColumnError::ToColumnDataUnexpectedVarLen {
156				ty,
157			} => Diagnostic {
158				code: "COL_008".to_string(),
159				rql: None,
160				message: format!("Canonical::to_column_buffer: unexpected VarLen type {ty}"),
161				column: None,
162				fragment: Fragment::None,
163				label: None,
164				help: None,
165				notes: vec![],
166				cause: None,
167				operator_chain: None,
168			},
169
170			ColumnError::ToColumnDataUnexpectedBigNum {
171				ty,
172			} => Diagnostic {
173				code: "COL_009".to_string(),
174				rql: None,
175				message: format!("Canonical::to_column_buffer: unexpected BigNum type {ty}"),
176				column: None,
177				fragment: Fragment::None,
178				label: None,
179				help: None,
180				notes: vec![],
181				cause: None,
182				operator_chain: None,
183			},
184
185			ColumnError::ToColumnDataInvalidUtf8 {
186				reason,
187			} => Diagnostic {
188				code: "COL_010".to_string(),
189				rql: None,
190				message: format!("Canonical::to_column_buffer: invalid UTF-8: {reason}"),
191				column: None,
192				fragment: Fragment::None,
193				label: None,
194				help: None,
195				notes: vec![],
196				cause: None,
197				operator_chain: None,
198			},
199
200			ColumnError::CompareRhsTypeMismatch {
201				storage,
202				expected,
203			} => Diagnostic {
204				code: "COL_011".to_string(),
205				rql: None,
206				message: format!("compare: column storage `{storage}` requires rhs `{expected}`"),
207				column: None,
208				fragment: Fragment::None,
209				label: Some("rhs type mismatch".to_string()),
210				help: None,
211				notes: vec![],
212				cause: None,
213				operator_chain: None,
214			},
215
216			ColumnError::CompareBigNumUnsupported => Diagnostic {
217				code: "COL_012".to_string(),
218				rql: None,
219				message: "compare: BigNum comparison not yet implemented".to_string(),
220				column: None,
221				fragment: Fragment::None,
222				label: None,
223				help: None,
224				notes: vec![],
225				cause: None,
226				operator_chain: None,
227			},
228
229			ColumnError::PredicateCompareNotBool => Diagnostic {
230				code: "COL_013".to_string(),
231				rql: None,
232				message: "predicate::evaluate: compare did not return a bool array".to_string(),
233				column: None,
234				fragment: Fragment::None,
235				label: None,
236				help: None,
237				notes: vec![],
238				cause: None,
239				operator_chain: None,
240			},
241
242			ColumnError::SearchSortedTypeMismatch => Diagnostic {
243				code: "COL_014".to_string(),
244				rql: None,
245				message: "search_sorted: storage/needle type mismatch or unsupported".to_string(),
246				column: None,
247				fragment: Fragment::None,
248				label: None,
249				help: None,
250				notes: vec![],
251				cause: None,
252				operator_chain: None,
253			},
254
255			ColumnError::MinMaxEmpty => Diagnostic {
256				code: "COL_015".to_string(),
257				rql: None,
258				message: "min_max: empty array has no min/max".to_string(),
259				column: None,
260				fragment: Fragment::None,
261				label: None,
262				help: None,
263				notes: vec![],
264				cause: None,
265				operator_chain: None,
266			},
267
268			ColumnError::MinMaxAllNone => Diagnostic {
269				code: "COL_016".to_string(),
270				rql: None,
271				message: "min_max: all rows are None".to_string(),
272				column: None,
273				fragment: Fragment::None,
274				label: None,
275				help: None,
276				notes: vec![],
277				cause: None,
278				operator_chain: None,
279			},
280
281			ColumnError::MinMaxFloatUnsupported => Diagnostic {
282				code: "COL_017".to_string(),
283				rql: None,
284				message: "min_max: float min/max not yet implemented (NaN handling)".to_string(),
285				column: None,
286				fragment: Fragment::None,
287				label: None,
288				help: None,
289				notes: vec![],
290				cause: None,
291				operator_chain: None,
292			},
293		}
294	}
295}