Skip to main content

laminar_connectors/schema/error/
mod.rs

1//! Schema error types.
2//!
3//! Provides [`SchemaError`] for schema inference, resolution, and evolution
4//! operations, plus a convenience [`SchemaResult`] alias.
5
6use thiserror::Error;
7
8use crate::error::ConnectorError;
9
10/// Result alias for schema operations.
11pub type SchemaResult<T> = Result<T, SchemaError>;
12
13/// Errors that can occur during schema operations.
14#[derive(Debug, Error)]
15pub enum SchemaError {
16    /// Schema inference failed (e.g., not enough samples, conflicting types).
17    #[error("inference failed: {0}")]
18    InferenceFailed(String),
19
20    /// Two schemas are incompatible and cannot be merged.
21    #[error("incompatible schemas: {0}")]
22    Incompatible(String),
23
24    /// Error communicating with a schema registry.
25    #[error("registry error: {0}")]
26    RegistryError(String),
27
28    /// Error decoding raw data into Arrow records.
29    #[error("decode error: {0}")]
30    DecodeError(String),
31
32    /// A proposed schema evolution was rejected by compatibility rules.
33    #[error("evolution rejected: {0}")]
34    EvolutionRejected(String),
35
36    /// A required configuration key is missing.
37    #[error("missing config: {0}")]
38    MissingConfig(String),
39
40    /// A configuration value is invalid.
41    #[error("invalid config key '{key}': {message}")]
42    InvalidConfig {
43        /// The configuration key.
44        key: String,
45        /// What was wrong with the value.
46        message: String,
47    },
48
49    /// Duplicate wildcard `*` in the column list.
50    #[error("duplicate wildcard: only one `*` is allowed in the column list")]
51    DuplicateWildcard,
52
53    /// Wildcard `*` used without a connector that provides schema resolution.
54    #[error(
55        "wildcard without resolution: `*` requires a connector with a schema provider or registry"
56    )]
57    WildcardWithoutResolution,
58
59    /// A wildcard-prefixed column name collides with a declared column.
60    #[error("wildcard prefix collision: prefixed column '{0}' collides with a declared column")]
61    WildcardPrefixCollision(String),
62
63    /// Wildcard expanded to zero new columns (all source columns were
64    /// already declared).
65    #[error("wildcard expanded to zero new columns: all source columns are already declared")]
66    WildcardNoNewFields,
67
68    /// An Arrow error propagated from schema operations.
69    #[error("arrow error: {0}")]
70    Arrow(#[from] arrow_schema::ArrowError),
71
72    /// Catch-all for wrapped external errors.
73    #[error(transparent)]
74    Other(Box<dyn std::error::Error + Send + Sync>),
75}
76
77impl From<ConnectorError> for SchemaError {
78    fn from(err: ConnectorError) -> Self {
79        match err {
80            // `ConnectorError::MissingConfig` folded into
81            // `ConfigurationError` — both land in `InvalidConfig` now.
82            ConnectorError::ConfigurationError(msg) => SchemaError::InvalidConfig {
83                key: String::new(),
84                message: msg,
85            },
86            ConnectorError::SchemaMismatch(msg) => SchemaError::Incompatible(msg),
87            other => SchemaError::Other(Box::new(other)),
88        }
89    }
90}
91
92impl From<SchemaError> for ConnectorError {
93    fn from(err: SchemaError) -> Self {
94        match err {
95            SchemaError::MissingConfig(msg) => ConnectorError::missing_config(msg),
96            SchemaError::InvalidConfig { key, message } => {
97                ConnectorError::ConfigurationError(format!("invalid config key '{key}': {message}"))
98            }
99            SchemaError::Incompatible(msg) => ConnectorError::SchemaMismatch(msg),
100            SchemaError::DecodeError(msg) => ConnectorError::ReadError(msg),
101            other => ConnectorError::Internal(other.to_string()),
102        }
103    }
104}
105
106#[cfg(test)]
107mod tests;