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