sqruff_lib_core/
errors.rs1use std::fmt::Display;
2use std::ops::{Deref, DerefMut, Range};
3
4use fancy_regex::Regex;
5
6use super::parser::segments::ErasedSegment;
7use crate::helpers::Config;
8use crate::lint_fix::LintFix;
9use crate::parser::markers::PositionMarker;
10
11type CheckTuple = (&'static str, usize, usize);
12
13pub trait SqlError: Display {
14 fn fixable(&self) -> bool;
15 fn rule_code(&self) -> Option<&'static str>;
16 fn identifier(&self) -> &'static str;
17 fn check_tuple(&self) -> CheckTuple;
19}
20
21#[derive(Debug, PartialEq, Clone, Default)]
22pub struct SQLBaseError {
23 pub fixable: bool,
24 pub line_no: usize,
25 pub line_pos: usize,
26 pub description: String,
27 pub rule: Option<ErrorStructRule>,
28 pub source_slice: Range<usize>,
29}
30
31#[derive(Debug, PartialEq, Clone, Default)]
32pub struct ErrorStructRule {
33 pub name: &'static str,
34 pub code: &'static str,
35}
36
37impl SQLBaseError {
38 pub fn rule_code(&self) -> &'static str {
39 self.rule.as_ref().map_or("????", |rule| rule.code)
40 }
41
42 pub fn set_position_marker(&mut self, position_marker: PositionMarker) {
43 let (line_no, line_pos) = position_marker.source_position();
44
45 self.line_no = line_no;
46 self.line_pos = line_pos;
47
48 self.source_slice = position_marker.source_slice.clone();
49 }
50
51 pub fn desc(&self) -> &str {
52 &self.description
53 }
54}
55
56impl Display for SQLBaseError {
57 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
58 write!(f, "{}", self.description)
59 }
60}
61
62impl SqlError for SQLBaseError {
63 fn fixable(&self) -> bool {
64 self.fixable
65 }
66
67 fn rule_code(&self) -> Option<&'static str> {
68 None
69 }
70
71 fn identifier(&self) -> &'static str {
72 "base"
73 }
74
75 fn check_tuple(&self) -> CheckTuple {
76 ("", self.line_no, self.line_pos)
77 }
78}
79
80#[derive(Debug, Clone)]
81pub struct SQLLintError {
82 base: SQLBaseError,
83 pub fixes: Vec<LintFix>,
84}
85
86impl SQLLintError {
87 pub fn new(
88 description: &str,
89 segment: ErasedSegment,
90 fixable: bool,
91 fixes: Vec<LintFix>,
92 ) -> Self {
93 Self {
94 base: SQLBaseError::default().config(|this| {
95 this.description = description.into();
96 this.set_position_marker(segment.get_position_marker().unwrap().clone());
97 this.fixable = fixable;
98 }),
99 fixes,
100 }
101 }
102}
103
104impl Deref for SQLLintError {
105 type Target = SQLBaseError;
106
107 fn deref(&self) -> &Self::Target {
108 &self.base
109 }
110}
111
112impl DerefMut for SQLLintError {
113 fn deref_mut(&mut self) -> &mut Self::Target {
114 &mut self.base
115 }
116}
117
118impl From<SQLLintError> for SQLBaseError {
119 fn from(value: SQLLintError) -> Self {
120 value.base
121 }
122}
123
124impl From<SQLBaseError> for SQLLintError {
125 fn from(value: SQLBaseError) -> Self {
126 Self {
127 base: value,
128 fixes: vec![],
129 }
130 }
131}
132
133#[derive(Debug, PartialEq, Clone)]
134pub struct SQLTemplaterError {}
135
136impl Display for SQLTemplaterError {
137 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
138 write!(f, "SQLTemplaterError")
139 }
140}
141
142impl SqlError for SQLTemplaterError {
143 fn fixable(&self) -> bool {
144 false
145 }
146
147 fn rule_code(&self) -> Option<&'static str> {
148 None
149 }
150
151 fn identifier(&self) -> &'static str {
152 "templater"
153 }
154
155 fn check_tuple(&self) -> CheckTuple {
156 ("", 0, 0)
157 }
158}
159
160#[derive(Debug)]
162pub struct SQLFluffUserError {
163 pub value: String,
164}
165
166impl SQLFluffUserError {
167 pub fn new(value: String) -> SQLFluffUserError {
168 SQLFluffUserError { value }
169 }
170}
171
172impl Display for SQLFluffUserError {
173 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
174 f.write_str(&self.value)
175 }
176}
177
178#[derive(Debug)]
180pub struct ValueError {
181 #[allow(dead_code)]
182 value: String,
183}
184
185impl ValueError {
186 pub fn new(value: String) -> ValueError {
187 ValueError { value }
188 }
189}
190
191#[derive(Debug)]
192pub struct SQLParseError {
193 pub description: String,
194 pub segment: Option<ErasedSegment>,
195}
196
197impl SQLParseError {
198 pub fn matches(&self, regexp: &str) -> bool {
199 let value = &self.description;
200 let regex = Regex::new(regexp).expect("Invalid regex pattern");
201
202 if let Ok(true) = regex.is_match(value) {
203 true
204 } else {
205 let msg = format!(
206 "Regex pattern did not match.\nRegex: {:?}\nInput: {:?}",
207 regexp, value
208 );
209
210 if regexp == value {
211 panic!("{}\nDid you mean to escape the regex?", msg);
212 } else {
213 panic!("{}", msg);
214 }
215 }
216 }
217}
218
219impl From<SQLParseError> for SQLBaseError {
220 fn from(value: SQLParseError) -> Self {
221 let (mut line_no, mut line_pos) = Default::default();
222
223 let pos_marker = value
224 .segment
225 .as_ref()
226 .and_then(|segment| segment.get_position_marker());
227
228 if let Some(pos_marker) = pos_marker {
229 (line_no, line_pos) = pos_marker.source_position();
230 }
231
232 Self::default().config(|this| {
233 this.line_no = line_no;
234 this.line_pos = line_pos;
235 this.description = value.description;
236 })
237 }
238}
239
240#[derive(PartialEq, Eq, Debug)]
241pub struct SQLLexError {
242 message: String,
243 position_marker: PositionMarker,
244}
245
246impl SQLLexError {
247 pub fn new(message: String, position_marker: PositionMarker) -> SQLLexError {
248 SQLLexError {
249 message,
250 position_marker,
251 }
252 }
253}
254
255#[derive(Debug)]
256pub struct SQLFluffSkipFile {
257 #[allow(dead_code)]
258 value: String,
259}
260
261impl SQLFluffSkipFile {
262 pub fn new(value: String) -> SQLFluffSkipFile {
263 SQLFluffSkipFile { value }
264 }
265}