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("SQLTemplaterError")]
92pub struct SQLTemplaterError;
93
94/// An error which should be fed back to the user.
95#[derive(Debug, Error)]
96#[error("{value}")]
97pub struct SQLFluffUserError {
98    pub value: String,
99}
100
101impl SQLFluffUserError {
102    pub fn new(value: String) -> SQLFluffUserError {
103        SQLFluffUserError { value }
104    }
105}
106
107#[derive(Debug, Error)]
108#[error("{description}")]
109pub struct SQLParseError {
110    pub description: String,
111    pub segment: Option<ErasedSegment>,
112}
113
114impl SQLParseError {
115    pub fn matches(&self, regexp: &str) -> bool {
116        let value = &self.description;
117        let regex = Regex::new(regexp).expect("Invalid regex pattern");
118
119        if let Ok(true) = regex.is_match(value) {
120            true
121        } else {
122            let msg = format!("Regex pattern did not match.\nRegex: {regexp:?}\nInput: {value:?}");
123
124            if regexp == value {
125                panic!("{msg}\nDid you mean to escape the regex?");
126            } else {
127                panic!("{}", msg);
128            }
129        }
130    }
131}
132
133impl From<SQLParseError> for SQLBaseError {
134    fn from(value: SQLParseError) -> Self {
135        let (mut line_no, mut line_pos) = Default::default();
136
137        let pos_marker = value
138            .segment
139            .as_ref()
140            .and_then(|segment| segment.get_position_marker());
141
142        if let Some(pos_marker) = pos_marker {
143            (line_no, line_pos) = pos_marker.source_position();
144        }
145
146        Self::default().config(|this| {
147            this.line_no = line_no;
148            this.line_pos = line_pos;
149            this.description = value.description;
150        })
151    }
152}
153
154#[derive(PartialEq, Eq, Debug, Error)]
155#[error("{message}")]
156pub struct SQLLexError {
157    message: String,
158    position_marker: PositionMarker,
159}
160
161impl SQLLexError {
162    pub fn new(message: String, position_marker: PositionMarker) -> SQLLexError {
163        SQLLexError {
164            message,
165            position_marker,
166        }
167    }
168}
169
170#[derive(Debug, Error)]
171#[error("{value}")]
172pub struct SQLFluffSkipFile {
173    value: String,
174}
175
176impl SQLFluffSkipFile {
177    pub fn new(value: String) -> SQLFluffSkipFile {
178        SQLFluffSkipFile { value }
179    }
180}