1use std::fmt;
2
3#[derive(Debug, Clone, PartialEq, Eq)]
5#[non_exhaustive]
6pub enum DataError {
7 UnknownColumn(String),
9 UnsupportedKey(String),
11 UnsupportedColumn(String),
13 LiteralMismatch(String),
16 NotNumeric(String),
19 WindowSpan(String),
22 BucketWidth(String),
26 DuplicateName(String),
28 ColumnCount {
30 expected: usize,
32 found: usize,
34 },
35 ColumnMismatch {
37 column: usize,
39 },
40 NullKey {
42 row: usize,
44 },
45 KeyType,
47 TooManyRows,
49 Arrow(String),
51}
52
53impl fmt::Display for DataError {
54 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
55 match self {
56 Self::UnknownColumn(name) => write!(
57 f,
58 "there is no column named {name:?}: names match exactly, case included \
59 (the table's schema lists them)"
60 ),
61 Self::UnsupportedKey(name) => {
62 write!(f, "key column {name:?} must hold integers or strings")
63 }
64 Self::UnsupportedColumn(name) => {
65 write!(
66 f,
67 "views and groups cannot read column {name:?} of this type: they read \
68 booleans, integers, floats, decimals, text (or dictionaries of text), dates, \
69 times, timestamps and durations"
70 )
71 }
72 Self::LiteralMismatch(name) => {
73 write!(f, "the filter does not fit the type of column {name:?}")
74 }
75 Self::NotNumeric(name) => {
76 write!(
77 f,
78 "column {name:?} is not numeric, so it has no sum or mean: those take \
79 integers, decimals and floats (count takes no column; min and max take any column \
80 views can sort)"
81 )
82 }
83 Self::WindowSpan(name) => {
84 write!(
85 f,
86 "the window's span does not fit the type of column {name:?}: \
87 Window::duration goes with dates, times, timestamps and durations, \
88 Window::span (zero or more) with integers, decimals and floats"
89 )
90 }
91 Self::BucketWidth(name) => {
92 write!(
93 f,
94 "the bucket width does not fit the type of column {name:?}: \
95 group_by_time takes at least one of the column's units for dates, times, \
96 timestamps and durations, group_by_step at least one unit for integers \
97 and decimals, or a finite step above zero for floats"
98 )
99 }
100 Self::DuplicateName(name) => write!(
101 f,
102 "two result columns are named {name:?}: give an aggregate another name with \
103 Aggregate::named"
104 ),
105 Self::ColumnCount { expected, found } => {
106 write!(f, "the batch has {found} columns, the table {expected}")
107 }
108 Self::ColumnMismatch { column } => {
109 write!(
110 f,
111 "column {column} of the batch has another name or data type than the \
112 table's: every batch must have the table's schema (LiveTable::schema)"
113 )
114 }
115 Self::NullKey { row } => write!(f, "row {row} of the batch has a null key"),
116 Self::KeyType => f.write_str(
117 "the keys are not of the key column's kind: give integers for a key column of \
118 integers, strings for one of strings",
119 ),
120 Self::TooManyRows => f.write_str("more than 2^32 live keys, or rows in one batch"),
121 Self::Arrow(message) => write!(f, "Arrow could not build a batch: {message}"),
122 }
123 }
124}
125
126impl std::error::Error for DataError {}
127
128impl DataError {
129 pub(crate) fn arrow(error: arrow_schema::ArrowError) -> Self {
130 Self::Arrow(error.to_string())
131 }
132}