use std::collections::BTreeMap;
use arrow::{datatypes::DataType, error::ArrowError};
use chrono::{DateTime, Utc};
use parquet::errors::ParquetError;
use snafu::prelude::*;
use crate::{
coverage::io::CoverageError,
formats::parquet::{SegmentCoverageError, SegmentEntityIdentityError},
metadata::schema_compat::SchemaCompatibilityError,
storage::StorageError,
transaction_log::{CommitError, TableKind, TimeBucket, segments::SegmentError},
};
#[derive(Debug, Snafu)]
#[snafu(visibility(pub(crate)))]
pub enum TableError {
#[snafu(display("Transaction log error: {source}"))]
TransactionLog {
#[snafu(source, backtrace)]
source: CommitError,
},
#[snafu(display("Cannot open table with no commits (CURRENT version is 0)"))]
EmptyTable,
#[snafu(display("Table kind is {kind:?}, expected TableKind::TimeSeries"))]
NotTimeSeries {
kind: TableKind,
},
#[snafu(display("Unsupported table format version: expected {expected}, found {found}"))]
UnsupportedFormatVersion {
expected: u32,
found: u32,
},
#[snafu(display("Table already exists; current transaction log version is {current_version}"))]
AlreadyExists {
current_version: u64,
},
#[snafu(display("Segment metadata error while appending: {source}"))]
SegmentMeta {
#[snafu(source, backtrace)]
source: SegmentError,
},
#[snafu(display("Schema compatibility error: {source}"))]
SchemaCompatibility {
#[snafu(source)]
source: SchemaCompatibilityError,
},
#[snafu(display("Table has no logical_schema at version {version}; cannot append in v0.1"))]
MissingCanonicalSchema {
version: u64,
},
#[snafu(display("Storage error while accessing table data: {source}"))]
Storage {
source: StorageError,
},
#[snafu(display("Invalid scan range: start={start}, end={end} (expect start < end)"))]
InvalidRange {
start: DateTime<Utc>,
end: DateTime<Utc>,
},
#[snafu(display("Parquet read error: {source}"))]
ParquetRead {
source: ParquetError,
},
#[snafu(display("Arrow error while filtering batch: {source}"))]
Arrow {
source: ArrowError,
},
#[snafu(display("Missing time column {column} in segment"))]
MissingTimeColumn {
column: String,
},
#[snafu(display("Unsupported time column {column} with type {datatype:?}"))]
UnsupportedTimeType {
column: String,
datatype: DataType,
},
#[snafu(display("Timestamp conversion overflow for column {column} (value: {timestamp})"))]
TimeConversionOverflow {
column: String,
timestamp: DateTime<Utc>,
},
#[snafu(display("Segment coverage error: {source}"))]
SegmentCoverage {
#[snafu(source, backtrace)]
source: SegmentCoverageError,
},
#[snafu(display(
"Table coverage bucket spec mismatch: expected {expected:?}, found {actual:?} (from coverage version {pointer_version})"
))]
TableCoverageBucketMismatch {
expected: TimeBucket,
actual: TimeBucket,
pointer_version: u64,
},
#[snafu(display("Coverage sidecar error: {source}"))]
CoverageSidecar {
#[snafu(source, backtrace)]
source: CoverageError,
},
#[snafu(display(
"Coverage overlap while appending {segment_path}: {overlap_count} overlapping buckets (example={example_bucket:?})"
))]
CoverageOverlap {
segment_path: String,
overlap_count: u64,
example_bucket: Option<u32>,
},
#[snafu(display("Segment path is already live: {path}"))]
DuplicateSegmentPath {
path: String,
},
#[snafu(display(
"Cannot append because existing segment {path} is missing coverage_path (required for coverage tracking)"
))]
ExistingSegmentMissingCoverage {
path: String,
},
#[snafu(display(
"Cannot recover table coverage: failed to read segment coverage sidecar for {path} at {coverage_path}: {source}"
))]
SegmentCoverageSidecarRead {
path: String,
coverage_path: String,
#[snafu(source(from(CoverageError, Box::new)), backtrace)]
source: Box<CoverageError>,
},
#[snafu(display(
"Expected bucket domain overflows u32: last_bucket_id={last_bucket_id} (max={max})"
))]
BucketDomainOverflow {
last_bucket_id: u64,
max: u32,
},
#[snafu(display(
"Cannot append because table has segments but no table coverage snapshot pointer in state"
))]
MissingTableCoveragePointer,
#[snafu(display("Segment entity identity error: {source}"))]
SegmentEntityIdentity {
#[snafu(source, backtrace)]
source: SegmentEntityIdentityError,
},
#[snafu(display(
"Entity mismatch while appending {segment_path}: expected={expected:?}, found={found:?}"
))]
EntityMismatch {
segment_path: String,
expected: BTreeMap<String, String>,
found: BTreeMap<String, String>,
},
}