sqruff_lib_core/
errors.rs1use 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 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#[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#[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}