alopex_dataframe/
error.rs1use std::path::PathBuf;
2
3use crate::physical::budget::{ResourceScope, StreamFailureClass};
4
5#[derive(Debug, thiserror::Error)]
7pub enum DataFrameError {
8 #[error("I/O error{path}: {source}", path = path_display(.path))]
10 Io {
11 source: std::io::Error,
12 path: Option<PathBuf>,
13 },
14
15 #[error("schema mismatch: {message}")]
17 SchemaMismatch { message: String },
18
19 #[error(
21 "type mismatch{column}: expected {expected}, got {actual}",
22 column = column_display(.column)
23 )]
24 TypeMismatch {
25 column: Option<String>,
26 expected: String,
27 actual: String,
28 },
29
30 #[error("column not found: {name}")]
32 ColumnNotFound { name: String },
33
34 #[error("invalid operation: {message}")]
36 InvalidOperation { message: String },
37
38 #[error("invalid configuration option '{option}': {message}")]
40 Configuration { option: String, message: String },
41
42 #[error("arrow error: {source}")]
44 Arrow { source: arrow::error::ArrowError },
45
46 #[error("parquet error: {source}")]
48 Parquet {
49 source: parquet::errors::ParquetError,
50 },
51
52 #[error(
54 "resource limit exceeded in {scope}: requested total {observed} bytes exceeds {limit} bytes \\
55 (in-flight batches {observed_batches}/{max_in_flight_batches})",
56 scope = scope.as_str()
57 )]
58 ResourceLimitExceeded {
59 limit: u64,
61 observed: u64,
63 max_in_flight_batches: usize,
65 observed_batches: usize,
67 scope: ResourceScope,
69 },
70
71 #[error("stream is closed")]
73 StreamClosed,
74
75 #[error("stream is cancelled")]
77 StreamCancelled,
78
79 #[error("stream failed: {code} ({classification:?})")]
81 StreamFailed {
82 code: &'static str,
84 classification: StreamFailureClass,
86 },
87
88 #[error("streaming unsupported for {subject}: {reason}")]
90 StreamingUnsupported { subject: String, reason: String },
91
92 #[error("streaming requires materialization for {subject}: {reason}")]
94 StreamingRequiresMaterialization { subject: String, reason: String },
95}
96
97pub type Result<T> = std::result::Result<T, DataFrameError>;
99
100impl DataFrameError {
101 pub fn io(source: std::io::Error) -> Self {
103 Self::Io { source, path: None }
104 }
105
106 pub fn io_with_path(source: std::io::Error, path: impl Into<PathBuf>) -> Self {
108 Self::Io {
109 source,
110 path: Some(path.into()),
111 }
112 }
113
114 pub fn schema_mismatch(message: impl Into<String>) -> Self {
116 Self::SchemaMismatch {
117 message: message.into(),
118 }
119 }
120
121 pub fn type_mismatch(
123 column: impl Into<Option<String>>,
124 expected: impl Into<String>,
125 actual: impl Into<String>,
126 ) -> Self {
127 Self::TypeMismatch {
128 column: column.into(),
129 expected: expected.into(),
130 actual: actual.into(),
131 }
132 }
133
134 pub fn column_not_found(name: impl Into<String>) -> Self {
136 Self::ColumnNotFound { name: name.into() }
137 }
138
139 pub fn invalid_operation(message: impl Into<String>) -> Self {
141 Self::InvalidOperation {
142 message: message.into(),
143 }
144 }
145
146 pub fn configuration(option: impl Into<String>, message: impl Into<String>) -> Self {
148 Self::Configuration {
149 option: option.into(),
150 message: message.into(),
151 }
152 }
153
154 pub fn resource_limit_exceeded(
156 limit: u64,
157 observed: u64,
158 max_in_flight_batches: usize,
159 observed_batches: usize,
160 scope: ResourceScope,
161 ) -> Self {
162 Self::ResourceLimitExceeded {
163 limit,
164 observed,
165 max_in_flight_batches,
166 observed_batches,
167 scope,
168 }
169 }
170
171 pub const fn stream_closed() -> Self {
173 Self::StreamClosed
174 }
175
176 pub const fn stream_cancelled() -> Self {
178 Self::StreamCancelled
179 }
180
181 pub const fn stream_failed(code: &'static str, classification: StreamFailureClass) -> Self {
183 Self::StreamFailed {
184 code,
185 classification,
186 }
187 }
188
189 pub fn streaming_unsupported(subject: impl Into<String>, reason: impl Into<String>) -> Self {
191 Self::StreamingUnsupported {
192 subject: subject.into(),
193 reason: reason.into(),
194 }
195 }
196
197 pub fn streaming_requires_materialization(
199 subject: impl Into<String>,
200 reason: impl Into<String>,
201 ) -> Self {
202 Self::StreamingRequiresMaterialization {
203 subject: subject.into(),
204 reason: reason.into(),
205 }
206 }
207}
208
209fn column_display(column: &Option<String>) -> String {
210 column
211 .as_ref()
212 .map(|c| format!(" for column '{c}'"))
213 .unwrap_or_default()
214}
215
216fn path_display(path: &Option<PathBuf>) -> String {
217 path.as_ref()
218 .map(|p| format!(" for path '{}'", p.display()))
219 .unwrap_or_default()
220}