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