use arrow_schema::ArrowError;
use snafu::{location, Location, Snafu};
type BoxedError = Box<dyn std::error::Error + Send + Sync + 'static>;
pub fn box_error(e: impl std::error::Error + Send + Sync + 'static) -> BoxedError {
Box::new(e)
}
#[derive(Debug, Snafu)]
#[snafu(visibility(pub))]
pub enum Error {
#[snafu(display("Invalid user input: {source}"))]
InvalidInput { source: BoxedError },
#[snafu(display("Dataset already exists: {uri}"))]
DatasetAlreadyExists { uri: String },
#[snafu(display("Append with different schema:"))]
SchemaMismatch {},
#[snafu(display("Dataset at path {path} was not found: {source}"))]
DatasetNotFound { path: String, source: BoxedError },
#[snafu(display("Encountered corrupt file {path}: {source}"))]
CorruptFile {
path: object_store::path::Path,
source: BoxedError,
},
#[snafu(display("Not supported: {source}"))]
NotSupported { source: BoxedError },
#[snafu(display("Commit conflict for version {version}: {source}"))]
CommitConflict { version: u64, source: BoxedError },
#[snafu(display("Encountered internal error. Please file a bug report at https://github.com/lancedb/lance/issues. {message}"))]
Internal { message: String },
#[snafu(display("LanceError(Arrow): {message}"))]
Arrow { message: String },
#[snafu(display("LanceError(Schema): {message}, {location}"))]
Schema { message: String, location: Location },
#[snafu(display("Not found: {uri}, {location}"))]
NotFound { uri: String, location: Location },
#[snafu(display("LanceError(IO): {message}, {location}"))]
IO { message: String, location: Location },
#[snafu(display("LanceError(Index): {message}"))]
Index { message: String },
Stop,
}
impl Error {
pub fn corrupt_file(path: object_store::path::Path, message: impl Into<String>) -> Self {
let message: String = message.into();
Self::CorruptFile {
path,
source: message.into(),
}
}
pub fn invalid_input(message: impl Into<String>) -> Self {
let message: String = message.into();
Self::InvalidInput {
source: message.into(),
}
}
}
pub type Result<T> = std::result::Result<T, Error>;
impl From<ArrowError> for Error {
fn from(e: ArrowError) -> Self {
Self::Arrow {
message: e.to_string(),
}
}
}
impl From<&ArrowError> for Error {
fn from(e: &ArrowError) -> Self {
Self::Arrow {
message: e.to_string(),
}
}
}
impl From<std::io::Error> for Error {
fn from(e: std::io::Error) -> Self {
Self::IO {
message: (e.to_string()),
location: location!(),
}
}
}
impl From<object_store::Error> for Error {
fn from(e: object_store::Error) -> Self {
Self::IO {
message: (e.to_string()),
location: location!(),
}
}
}
impl From<prost::DecodeError> for Error {
fn from(e: prost::DecodeError) -> Self {
Self::IO {
message: (e.to_string()),
location: location!(),
}
}
}
impl From<tokio::task::JoinError> for Error {
fn from(e: tokio::task::JoinError) -> Self {
Self::IO {
message: (e.to_string()),
location: location!(),
}
}
}
impl From<object_store::path::Error> for Error {
fn from(e: object_store::path::Error) -> Self {
Self::IO {
message: (e.to_string()),
location: location!(),
}
}
}
impl From<url::ParseError> for Error {
fn from(e: url::ParseError) -> Self {
Self::IO {
message: (e.to_string()),
location: location!(),
}
}
}
impl From<serde_json::Error> for Error {
fn from(e: serde_json::Error) -> Self {
Self::Arrow {
message: e.to_string(),
}
}
}
fn arrow_io_error_from_msg(message: String) -> ArrowError {
ArrowError::IoError(
message.clone(),
std::io::Error::new(std::io::ErrorKind::Other, message),
)
}
impl From<Error> for ArrowError {
fn from(value: Error) -> Self {
match value {
Error::Arrow { message } => arrow_io_error_from_msg(message), Error::IO { message, .. } => arrow_io_error_from_msg(message),
Error::Schema { message, .. } => Self::SchemaError(message),
Error::Index { message } => arrow_io_error_from_msg(message),
Error::Stop => arrow_io_error_from_msg("early stop".to_string()),
e => arrow_io_error_from_msg(e.to_string()), }
}
}
impl From<datafusion_sql::sqlparser::parser::ParserError> for Error {
fn from(e: datafusion_sql::sqlparser::parser::ParserError) -> Self {
Self::IO {
message: e.to_string(),
location: location!(),
}
}
}
impl From<datafusion_sql::sqlparser::tokenizer::TokenizerError> for Error {
fn from(e: datafusion_sql::sqlparser::tokenizer::TokenizerError) -> Self {
Self::IO {
message: e.to_string(),
location: location!(),
}
}
}
impl From<Error> for datafusion_common::DataFusionError {
fn from(e: Error) -> Self {
Self::Execution(e.to_string())
}
}
impl From<datafusion_common::DataFusionError> for Error {
fn from(e: datafusion_common::DataFusionError) -> Self {
Self::IO {
message: e.to_string(),
location: location!(),
}
}
}
impl From<Error> for object_store::Error {
fn from(err: Error) -> Self {
Self::Generic {
store: "N/A",
source: Box::new(err),
}
}
}