1use std::fmt;
2
3#[derive(Debug)]
4pub struct ScytheError {
5 pub code: ErrorCode,
6 pub message: String,
7}
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14#[non_exhaustive]
15pub enum ErrorCode {
16 SyntaxError,
17 UnknownTable,
18 UnknownColumn,
19 UnknownFunction,
20 AmbiguousColumn,
21 TypeMismatch,
22 MissingAnnotation,
23 InvalidAnnotation,
24 ColumnCountMismatch,
25 DuplicateAlias,
26 InvalidRecursion,
27 InvalidConfig,
31 InternalError,
32}
33
34impl fmt::Display for ErrorCode {
35 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
36 match self {
37 ErrorCode::SyntaxError => write!(f, "SYNTAX_ERROR"),
38 ErrorCode::UnknownTable => write!(f, "UNKNOWN_TABLE"),
39 ErrorCode::UnknownColumn => write!(f, "UNKNOWN_COLUMN"),
40 ErrorCode::UnknownFunction => write!(f, "UNKNOWN_FUNCTION"),
41 ErrorCode::AmbiguousColumn => write!(f, "AMBIGUOUS_COLUMN"),
42 ErrorCode::TypeMismatch => write!(f, "TYPE_MISMATCH"),
43 ErrorCode::MissingAnnotation => write!(f, "MISSING_ANNOTATION"),
44 ErrorCode::InvalidAnnotation => write!(f, "INVALID_ANNOTATION"),
45 ErrorCode::ColumnCountMismatch => write!(f, "COLUMN_COUNT_MISMATCH"),
46 ErrorCode::DuplicateAlias => write!(f, "DUPLICATE_ALIAS"),
47 ErrorCode::InvalidRecursion => write!(f, "INVALID_RECURSION"),
48 ErrorCode::InvalidConfig => write!(f, "INVALID_CONFIG"),
49 ErrorCode::InternalError => write!(f, "INTERNAL_ERROR"),
50 }
51 }
52}
53
54impl fmt::Display for ScytheError {
55 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
56 write!(f, "{}: {}", self.code, self.message)
57 }
58}
59
60impl std::error::Error for ScytheError {}
61
62impl ScytheError {
63 pub fn new(code: ErrorCode, message: impl Into<String>) -> Self {
64 Self {
65 code,
66 message: message.into(),
67 }
68 }
69
70 pub fn syntax(msg: impl Into<String>) -> Self {
71 Self::new(ErrorCode::SyntaxError, msg)
72 }
73
74 pub fn unknown_table(name: &str) -> Self {
75 Self::new(ErrorCode::UnknownTable, format!("table \"{name}\" does not exist"))
76 }
77
78 pub fn unknown_column(name: &str) -> Self {
79 Self::new(ErrorCode::UnknownColumn, format!("column \"{name}\" does not exist"))
80 }
81
82 pub fn unknown_function(name: &str) -> Self {
83 Self::new(
84 ErrorCode::UnknownFunction,
85 format!("function \"{name}\" does not exist"),
86 )
87 }
88
89 pub fn ambiguous_column(name: &str) -> Self {
90 Self::new(ErrorCode::AmbiguousColumn, format!("column \"{name}\" is ambiguous"))
91 }
92
93 pub fn type_mismatch(msg: impl Into<String>) -> Self {
94 Self::new(ErrorCode::TypeMismatch, msg)
95 }
96
97 pub fn missing_annotation(what: &str) -> Self {
98 Self::new(ErrorCode::MissingAnnotation, format!("missing @{what} annotation"))
99 }
100
101 pub fn invalid_annotation(msg: impl Into<String>) -> Self {
102 Self::new(ErrorCode::InvalidAnnotation, msg)
103 }
104
105 pub fn column_count_mismatch(left: usize, right: usize) -> Self {
106 Self::new(
107 ErrorCode::ColumnCountMismatch,
108 format!("column count mismatch: {left} vs {right}"),
109 )
110 }
111
112 pub fn duplicate_alias(name: &str) -> Self {
113 Self::new(ErrorCode::DuplicateAlias, format!("duplicate column alias \"{name}\""))
114 }
115
116 pub fn cte_column_alias_mismatch(alias_count: usize, column_count: usize) -> Self {
121 Self::new(
122 ErrorCode::ColumnCountMismatch,
123 format!("CTE column alias list has {alias_count} entries but the CTE body produces {column_count} columns"),
124 )
125 }
126
127 pub fn invalid_recursion(msg: impl Into<String>) -> Self {
128 Self::new(ErrorCode::InvalidRecursion, msg)
129 }
130
131 pub fn invalid_config(msg: impl Into<String>) -> Self {
138 Self::new(ErrorCode::InvalidConfig, msg)
139 }
140}