pub mod arrow;
pub mod csv;
pub mod parallel;
pub mod parquet;
pub mod source;
pub use arrow::{
import_from_arrow_ipc, import_from_record_batch, import_from_record_batches,
ArrowImportOptions, ArrowToCsvWriter, CsvWriterOptions,
};
pub use csv::{
import_from_callback, import_from_file, import_from_files, import_from_iter,
import_from_stream, CsvImportOptions, DataPipeSender,
};
pub use parquet::{
import_from_parquet, import_from_parquet_files, import_from_parquet_stream,
ParquetImportOptions,
};
pub use crate::types::ColumnNameMode;
pub use parallel::{ImportFileEntry, ParallelTransportPool};
pub use source::IntoFileSources;
use thiserror::Error;
#[derive(Error, Debug)]
pub enum ImportError {
#[error("IO error: {0}")]
IoError(#[from] std::io::Error),
#[error("Parquet error: {0}")]
ParquetError(String),
#[error("Arrow error: {0}")]
ArrowError(String),
#[error("Transport error: {0}")]
TransportError(#[from] crate::error::TransportError),
#[error("Query error: {0}")]
QueryError(String),
#[error("Conversion error: {0}")]
ConversionError(String),
#[error("Invalid configuration: {0}")]
InvalidConfig(String),
#[error("CSV write error: {0}")]
CsvWriteError(String),
#[error("Arrow IPC error: {0}")]
ArrowIpcError(String),
#[error("SQL execution failed: {0}")]
SqlError(String),
#[error("HTTP transport failed: {0}")]
HttpTransportError(String),
#[error("Data streaming error: {0}")]
StreamError(String),
#[error("Compression error: {0}")]
CompressionError(String),
#[error("Invalid session state: {0}")]
InvalidSessionState(String),
#[error("Channel error: {0}")]
ChannelError(String),
#[error("Parallel import error: {0}")]
ParallelImportError(String),
#[error("Schema inference failed: {0}")]
SchemaInferenceError(String),
#[error("Schema mismatch between files: {0}")]
SchemaMismatchError(String),
}
impl From<::arrow::error::ArrowError> for ImportError {
fn from(err: ::arrow::error::ArrowError) -> Self {
ImportError::ArrowError(err.to_string())
}
}
impl From<::parquet::errors::ParquetError> for ImportError {
fn from(err: ::parquet::errors::ParquetError) -> Self {
ImportError::ParquetError(err.to_string())
}
}
#[cfg(test)]
mod tests {
use super::ImportError;
#[test]
fn test_import_error_from_arrow_error_keeps_the_arrow_message() {
let arrow_error =
::arrow::error::ArrowError::SchemaError("column NAME missing".to_string());
let arrow_message = arrow_error.to_string();
let err: ImportError = arrow_error.into();
assert!(matches!(err, ImportError::ArrowError(_)));
assert_eq!(err.to_string(), format!("Arrow error: {}", arrow_message));
}
#[test]
fn test_import_error_from_parquet_error_keeps_the_parquet_message() {
let parquet_error = ::parquet::errors::ParquetError::General("bad footer".to_string());
let parquet_message = parquet_error.to_string();
let err: ImportError = parquet_error.into();
assert!(matches!(err, ImportError::ParquetError(_)));
assert_eq!(
err.to_string(),
format!("Parquet error: {}", parquet_message)
);
}
#[test]
fn test_import_error_from_io_error_keeps_the_io_message() {
let io_error = std::io::Error::new(std::io::ErrorKind::NotFound, "data.csv");
let err: ImportError = io_error.into();
assert!(matches!(err, ImportError::IoError(_)));
assert_eq!(err.to_string(), "IO error: data.csv");
}
#[test]
fn test_import_error_from_transport_error_keeps_the_transport_message() {
let transport_error = crate::error::TransportError::IoError("socket closed".to_string());
let err: ImportError = transport_error.into();
assert!(matches!(err, ImportError::TransportError(_)));
assert_eq!(
err.to_string(),
"Transport error: Network I/O error: socket closed"
);
}
#[test]
fn test_every_import_error_variant_renders_its_context() {
let cases: Vec<(ImportError, &str)> = vec![
(
ImportError::ParquetError("bad footer".to_string()),
"Parquet error: bad footer",
),
(
ImportError::ArrowError("schema".to_string()),
"Arrow error: schema",
),
(
ImportError::QueryError("IMPORT rejected".to_string()),
"Query error: IMPORT rejected",
),
(
ImportError::ConversionError("i128 overflow".to_string()),
"Conversion error: i128 overflow",
),
(
ImportError::InvalidConfig("no columns".to_string()),
"Invalid configuration: no columns",
),
(
ImportError::CsvWriteError("disk full".to_string()),
"CSV write error: disk full",
),
(
ImportError::ArrowIpcError("truncated".to_string()),
"Arrow IPC error: truncated",
),
(
ImportError::SqlError("syntax".to_string()),
"SQL execution failed: syntax",
),
(
ImportError::HttpTransportError("bind failed".to_string()),
"HTTP transport failed: bind failed",
),
(
ImportError::StreamError("reset".to_string()),
"Data streaming error: reset",
),
(
ImportError::CompressionError("gzip".to_string()),
"Compression error: gzip",
),
(
ImportError::InvalidSessionState("not connected".to_string()),
"Invalid session state: not connected",
),
(
ImportError::ChannelError("receiver dropped".to_string()),
"Channel error: receiver dropped",
),
(
ImportError::ParallelImportError("worker 2 failed".to_string()),
"Parallel import error: worker 2 failed",
),
(
ImportError::SchemaInferenceError("no metadata".to_string()),
"Schema inference failed: no metadata",
),
(
ImportError::SchemaMismatchError("file 2 differs".to_string()),
"Schema mismatch between files: file 2 differs",
),
];
for (err, expected) in cases {
assert_eq!(err.to_string(), expected);
}
}
}