rigsql_rules/aliasing/
al06.rs1use rigsql_core::{Segment, SegmentType};
2
3use crate::rule::{CrawlType, Rule, RuleContext, RuleGroup};
4use crate::violation::LintViolation;
5
6#[derive(Debug, Default)]
11pub struct RuleAL06;
12
13impl Rule for RuleAL06 {
14 fn code(&self) -> &'static str {
15 "AL06"
16 }
17 fn name(&self) -> &'static str {
18 "aliasing.subquery"
19 }
20 fn description(&self) -> &'static str {
21 "Subqueries in FROM clause should have an alias."
22 }
23 fn explanation(&self) -> &'static str {
24 "When a subquery is used as a table source in a FROM or JOIN clause, \
25 it must be given an explicit alias. Without an alias, columns from the \
26 subquery cannot be referenced clearly in the outer query."
27 }
28 fn groups(&self) -> &[RuleGroup] {
29 &[RuleGroup::Aliasing]
30 }
31 fn is_fixable(&self) -> bool {
32 false
33 }
34
35 fn crawl_type(&self) -> CrawlType {
36 CrawlType::Segment(vec![SegmentType::FromClause, SegmentType::JoinClause])
37 }
38
39 fn eval(&self, ctx: &RuleContext) -> Vec<LintViolation> {
40 let mut violations = Vec::new();
41 check_subqueries_have_alias(ctx.segment, &mut violations, self.code());
42 violations
43 }
44}
45
46fn check_subqueries_have_alias(
47 segment: &Segment,
48 violations: &mut Vec<LintViolation>,
49 code: &'static str,
50) {
51 let children = segment.children();
52
53 for child in children {
54 let st = child.segment_type();
55
56 if st == SegmentType::Subquery {
58 violations.push(LintViolation::new(
59 code,
60 "Subquery in FROM/JOIN clause should have an alias.",
61 child.span(),
62 ));
63 continue;
64 }
65
66 if st == SegmentType::AliasExpression {
68 continue;
69 }
70
71 check_subqueries_have_alias(child, violations, code);
73 }
74}