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 {
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 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#[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#[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}