Skip to main content

alopex_dataframe/
error.rs

1use std::path::PathBuf;
2
3/// Errors returned by `alopex-dataframe` operations.
4#[derive(Debug, thiserror::Error)]
5pub enum DataFrameError {
6    /// OS-level I/O error (optionally associated with a path).
7    #[error("I/O error{path}: {source}", path = path_display(.path))]
8    Io {
9        source: std::io::Error,
10        path: Option<PathBuf>,
11    },
12
13    /// Arrow schema-related mismatch (e.g. different schema across batches).
14    #[error("schema mismatch: {message}")]
15    SchemaMismatch { message: String },
16
17    /// Data type mismatch (e.g. non-numeric aggregation or incompatible dtypes).
18    #[error(
19        "type mismatch{column}: expected {expected}, got {actual}",
20        column = column_display(.column)
21    )]
22    TypeMismatch {
23        column: Option<String>,
24        expected: String,
25        actual: String,
26    },
27
28    /// Referenced column does not exist.
29    #[error("column not found: {name}")]
30    ColumnNotFound { name: String },
31
32    /// Operation is not supported or invalid for the current inputs.
33    #[error("invalid operation: {message}")]
34    InvalidOperation { message: String },
35
36    /// Invalid configuration option was provided.
37    #[error("invalid configuration option '{option}': {message}")]
38    Configuration { option: String, message: String },
39
40    /// Error originating from Arrow compute / record batch APIs.
41    #[error("arrow error: {source}")]
42    Arrow { source: arrow::error::ArrowError },
43
44    /// Error originating from Parquet APIs.
45    #[error("parquet error: {source}")]
46    Parquet {
47        source: parquet::errors::ParquetError,
48    },
49}
50
51/// Result type used throughout this crate.
52pub type Result<T> = std::result::Result<T, DataFrameError>;
53
54impl DataFrameError {
55    /// Create an I/O error without a path.
56    pub fn io(source: std::io::Error) -> Self {
57        Self::Io { source, path: None }
58    }
59
60    /// Create an I/O error associated with a path.
61    pub fn io_with_path(source: std::io::Error, path: impl Into<PathBuf>) -> Self {
62        Self::Io {
63            source,
64            path: Some(path.into()),
65        }
66    }
67
68    /// Create a schema mismatch error with a message.
69    pub fn schema_mismatch(message: impl Into<String>) -> Self {
70        Self::SchemaMismatch {
71            message: message.into(),
72        }
73    }
74
75    /// Create a type mismatch error with optional column context.
76    pub fn type_mismatch(
77        column: impl Into<Option<String>>,
78        expected: impl Into<String>,
79        actual: impl Into<String>,
80    ) -> Self {
81        Self::TypeMismatch {
82            column: column.into(),
83            expected: expected.into(),
84            actual: actual.into(),
85        }
86    }
87
88    /// Create a missing column error.
89    pub fn column_not_found(name: impl Into<String>) -> Self {
90        Self::ColumnNotFound { name: name.into() }
91    }
92
93    /// Create an invalid operation error.
94    pub fn invalid_operation(message: impl Into<String>) -> Self {
95        Self::InvalidOperation {
96            message: message.into(),
97        }
98    }
99
100    /// Create an invalid configuration error.
101    pub fn configuration(option: impl Into<String>, message: impl Into<String>) -> Self {
102        Self::Configuration {
103            option: option.into(),
104            message: message.into(),
105        }
106    }
107}
108
109fn column_display(column: &Option<String>) -> String {
110    column
111        .as_ref()
112        .map(|c| format!(" for column '{c}'"))
113        .unwrap_or_default()
114}
115
116fn path_display(path: &Option<PathBuf>) -> String {
117    path.as_ref()
118        .map(|p| format!(" for path '{}'", p.display()))
119        .unwrap_or_default()
120}