sqruff_lib_core/
errors.rs

1use 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    /// Get a tuple representing this error. Mostly for testing.
18    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/// An error which should be fed back to the user.
161#[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// Not from SQLFluff but translates Python value error
179#[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}