rigsql_rules/aliasing/
al01.rs1use rigsql_core::SegmentType;
2
3use crate::rule::{CrawlType, Rule, RuleContext, RuleGroup};
4use crate::utils::{has_as_keyword, is_false_alias};
5use crate::violation::{LintViolation, SourceEdit};
6
7#[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 if is_false_alias(ctx.segment.children()) {
42 return vec![];
43 }
44 if !has_as_keyword(ctx.segment.children()) {
45 let children = ctx.segment.children();
46 let fix = children
47 .iter()
48 .rev()
49 .find(|c| !c.segment_type().is_trivia())
50 .map(|alias| SourceEdit::insert(alias.span().start, "AS "));
51
52 return vec![LintViolation::with_fix(
53 self.code(),
54 "Implicit aliasing not allowed. Use explicit AS keyword.",
55 ctx.segment.span(),
56 fix.into_iter().collect(),
57 )];
58 }
59
60 vec![]
61 }
62}