Skip to main content

rigsql_rules/aliasing/
al01.rs

1use rigsql_core::SegmentType;
2
3use crate::rule::{CrawlType, Rule, RuleContext, RuleGroup};
4use crate::utils::{has_as_keyword, insert_as_keyword_fix, is_false_alias};
5use crate::violation::LintViolation;
6
7/// AL01: Implicit aliasing of table/column is not allowed.
8///
9/// Use explicit `AS` keyword for all aliases.
10#[derive(Debug, Default)]
11pub struct RuleAL01;
12
13impl Rule for RuleAL01 {
14    fn code(&self) -> &'static str {
15        "AL01"
16    }
17    fn name(&self) -> &'static str {
18        "aliasing.table"
19    }
20    fn description(&self) -> &'static str {
21        "Implicit aliasing of table/column is not allowed."
22    }
23    fn explanation(&self) -> &'static str {
24        "Aliases should use the explicit AS keyword for clarity. \
25         'SELECT a alias_name' is harder to read than 'SELECT a AS alias_name'. \
26         Explicit aliasing makes the intent clear and prevents ambiguity."
27    }
28    fn groups(&self) -> &[RuleGroup] {
29        &[RuleGroup::Aliasing]
30    }
31    fn is_fixable(&self) -> bool {
32        true
33    }
34
35    fn crawl_type(&self) -> CrawlType {
36        CrawlType::Segment(vec![SegmentType::AliasExpression])
37    }
38
39    fn eval(&self, ctx: &RuleContext) -> Vec<LintViolation> {
40        let children = ctx.segment.children();
41        if is_false_alias(children) || has_as_keyword(children) {
42            return vec![];
43        }
44
45        vec![LintViolation::with_fix(
46            self.code(),
47            "Implicit aliasing not allowed. Use explicit AS keyword.",
48            ctx.segment.span(),
49            insert_as_keyword_fix(children),
50        )]
51    }
52}
53
54#[cfg(test)]
55mod tests {
56    use super::*;
57    use crate::test_utils::lint_sql;
58
59    #[test]
60    fn test_al01_flags_implicit_alias() {
61        let violations = lint_sql("SELECT a b FROM t", RuleAL01);
62        assert_eq!(violations.len(), 1);
63    }
64
65    #[test]
66    fn test_al01_accepts_explicit_alias() {
67        let violations = lint_sql("SELECT a AS b FROM t", RuleAL01);
68        assert_eq!(violations.len(), 0);
69    }
70
71    #[test]
72    fn test_al01_fix_inserts_as() {
73        let violations = lint_sql("SELECT a b FROM t", RuleAL01);
74        assert_eq!(violations.len(), 1);
75        assert!(!violations[0].fixes.is_empty());
76        assert!(violations[0]
77            .fixes
78            .iter()
79            .any(|f| f.new_text.contains("AS")));
80    }
81}