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