sqruff_lib/rules/aliasing/
al02.rs

1use ahash::AHashMap;
2use sqruff_lib_core::dialects::syntax::{SyntaxKind, SyntaxSet};
3
4use super::al01::{Aliasing, RuleAL01};
5use crate::core::config::Value;
6use crate::core::rules::context::RuleContext;
7use crate::core::rules::crawlers::{Crawler, SegmentSeekerCrawler};
8use crate::core::rules::{Erased, ErasedRule, LintResult, Rule, RuleGroups};
9
10#[derive(Debug, Clone)]
11pub struct RuleAL02 {
12    base: RuleAL01,
13}
14
15impl Default for RuleAL02 {
16    fn default() -> Self {
17        Self {
18            base: RuleAL01::default()
19                .target_parent_types(const { SyntaxSet::new(&[SyntaxKind::SelectClauseElement]) }),
20        }
21    }
22}
23
24impl RuleAL02 {
25    pub fn aliasing(mut self, aliasing: Aliasing) -> Self {
26        self.base = self.base.aliasing(aliasing);
27        self
28    }
29}
30
31impl Rule for RuleAL02 {
32    fn load_from_config(&self, config: &AHashMap<String, Value>) -> Result<ErasedRule, String> {
33        let aliasing = match config.get("aliasing").unwrap().as_string().unwrap() {
34            "explicit" => Aliasing::Explicit,
35            "implicit" => Aliasing::Implicit,
36            _ => unreachable!(),
37        };
38
39        let mut rule = RuleAL02::default();
40        rule.base = rule.base.aliasing(aliasing);
41
42        Ok(rule.erased())
43    }
44
45    fn is_fix_compatible(&self) -> bool {
46        true
47    }
48
49    fn name(&self) -> &'static str {
50        "aliasing.column"
51    }
52
53    fn description(&self) -> &'static str {
54        "Implicit/explicit aliasing of columns."
55    }
56
57    fn long_description(&self) -> &'static str {
58        r#"
59**Anti-pattern**
60
61In this example, the alias for column `a` is implicit.
62
63```sql
64SELECT
65  a alias_col
66FROM foo
67```
68
69**Best practice**
70
71Add the `AS` keyword to make the alias explicit.
72
73```sql
74SELECT
75    a AS alias_col
76FROM foo
77```
78"#
79    }
80
81    fn groups(&self) -> &'static [RuleGroups] {
82        &[RuleGroups::All, RuleGroups::Core, RuleGroups::Aliasing]
83    }
84
85    fn eval(&self, context: &RuleContext) -> Vec<LintResult> {
86        if matches!(
87            context.segment
88                .child(&SyntaxSet::new(&[SyntaxKind::AliasOperator])),
89            Some(alias_operator) if alias_operator.raw() == "="
90        ) {
91            return Vec::new();
92        }
93
94        self.base.eval(context)
95    }
96
97    fn crawl_behaviour(&self) -> Crawler {
98        SegmentSeekerCrawler::new(const { SyntaxSet::new(&[SyntaxKind::AliasExpression]) }).into()
99    }
100}