Skip to main content

sqruff_lib_core/
errors.rs

1use std::ops::{Deref, DerefMut, Range};
2
3use fancy_regex::Regex;
4use thiserror::Error;
5
6use super::parser::segments::ErasedSegment;
7use crate::helpers::Config;
8use crate::parser::markers::PositionMarker;
9
10#[derive(Debug, PartialEq, Clone, Default, Error)]
11#[error("{description}")]
12pub struct SQLBaseError {
13    pub fixable: bool,
14    pub line_no: usize,
15    pub line_pos: usize,
16    pub description: String,
17    pub rule: Option<ErrorStructRule>,
18    pub source_slice: Range<usize>,
19}
20
21#[derive(Debug, PartialEq, Clone, Default)]
22pub struct ErrorStructRule {
23    pub name: &'static str,
24    pub code: &'static str,
25}
26
27impl SQLBaseError {
28    pub fn rule_code(&self) -> &'static str {
29        self.rule.as_ref().map_or("????", |rule| rule.code)
30    }
31
32    pub fn set_position_marker(&mut self, position_marker: PositionMarker) {
33        let (line_no, line_pos) = position_marker.source_position();
34
35        self.line_no = line_no;
36        self.line_pos = line_pos;
37
38        self.source_slice = position_marker.source_slice.clone();
39    }
40
41    pub fn desc(&self) -> &str {
42        &self.description
43    }
44}
45
46#[derive(Debug, Clone, Error)]
47#[error(transparent)]
48pub struct SQLLintError {
49    base: SQLBaseError,
50}
51
52impl SQLLintError {
53    pub fn new(description: &str, segment: ErasedSegment, fixable: bool) -> Self {
54        Self {
55            base: SQLBaseError::default().config(|this| {
56                this.description = description.into();
57                this.set_position_marker(segment.get_position_marker().unwrap().clone());
58                this.fixable = fixable;
59            }),
60        }
61    }
62}
63
64impl Deref for SQLLintError {
65    type Target = SQLBaseError;
66
67    fn deref(&self) -> &Self::Target {
68        &self.base
69    }
70}
71
72impl DerefMut for SQLLintError {
73    fn deref_mut(&mut self) -> &mut Self::Target {
74        &mut self.base
75    }
76}
77
78impl From<SQLLintError> for SQLBaseError {
79    fn from(value: SQLLintError) -> Self {
80        value.base
81    }
82}
83
84impl From<SQLBaseError> for SQLLintError {
85    fn from(value: SQLBaseError) -> Self {
86        Self { base: value }
87    }
88}
89
90#[derive(Debug, PartialEq, Clone, Error)]
91#[error("{message}")]
92pub struct SQLTemplaterError {
93    pub message: String,
94}
95
96impl SQLTemplaterError {
97    pub fn new(message: String) -> Self {
98        Self { message }
99    }
100}
101
102impl From<SQLTemplaterError> for SQLBaseError {
103    fn from(value: SQLTemplaterError) -> Self {
104        Self {
105            description: value.message,
106            rule: Some(ErrorStructRule {
107                name: "templater",
108                code: "TMP",
109            }),
110            ..Default::default()
111        }
112    }
113}
114
115/// An error which should be fed back to the user.
116#[derive(Debug, Error)]
117#[error("{value}")]
118pub struct SQLFluffUserError {
119    pub value: String,
120}
121
122impl SQLFluffUserError {
123    pub fn new(value: String) -> SQLFluffUserError {
124        SQLFluffUserError { value }
125    }
126}
127
128#[derive(Debug, Error)]
129#[error("{description}")]
130pub struct SQLParseError {
131    pub description: String,
132    pub segment: Option<ErasedSegment>,
133}
134
135impl SQLParseError {
136    pub fn matches(&self, regexp: &str) -> bool {
137        let value = &self.description;
138        let regex = Regex::new(regexp).expect("Invalid regex pattern");
139
140        if let Ok(true) = regex.is_match(value) {
141            true
142        } else {
143            let msg = format!("Regex pattern did not match.\nRegex: {regexp:?}\nInput: {value:?}");
144
145            if regexp == value {
146                panic!("{msg}\nDid you mean to escape the regex?");
147            } else {
148                panic!("{}", msg);
149            }
150        }
151    }
152}
153
154impl From<SQLParseError> for SQLBaseError {
155    fn from(value: SQLParseError) -> Self {
156        let (mut line_no, mut line_pos) = Default::default();
157
158        let pos_marker = value
159            .segment
160            .as_ref()
161            .and_then(|segment| segment.get_position_marker());
162
163        if let Some(pos_marker) = pos_marker {
164            (line_no, line_pos) = pos_marker.source_position();
165        }
166
167        Self::default().config(|this| {
168            this.line_no = line_no;
169            this.line_pos = line_pos;
170            this.description = value.description;
171        })
172    }
173}
174
175#[derive(PartialEq, Eq, Debug, Error)]
176#[error("{message}")]
177pub struct SQLLexError {
178    message: String,
179    position_marker: PositionMarker,
180}
181
182impl SQLLexError {
183    pub fn new(message: String, position_marker: PositionMarker) -> SQLLexError {
184        SQLLexError {
185            message,
186            position_marker,
187        }
188    }
189}
190
191#[derive(Debug, Error)]
192#[error("{value}")]
193pub struct SQLFluffSkipFile {
194    value: String,
195}
196
197impl SQLFluffSkipFile {
198    pub fn new(value: String) -> SQLFluffSkipFile {
199        SQLFluffSkipFile { value }
200    }
201}