Skip to main content

rigsql_rules/rigsql/
rg03.rs

1use rigsql_core::SegmentType;
2
3use crate::rule::{CrawlType, Rule, RuleContext, RuleGroup};
4use crate::violation::LintViolation;
5
6/// RG03: Use of BETWEEN operator.
7///
8/// The BETWEEN operator can be confusing, especially with date ranges,
9/// because it is inclusive on both ends. Prefer explicit >= AND <= comparisons.
10#[derive(Debug, Default)]
11pub struct RuleRG03;
12
13impl Rule for RuleRG03 {
14    fn code(&self) -> &'static str {
15        "RG03"
16    }
17    fn name(&self) -> &'static str {
18        "rigsql.no_between"
19    }
20    fn description(&self) -> &'static str {
21        "Use of BETWEEN operator."
22    }
23    fn explanation(&self) -> &'static str {
24        "The BETWEEN operator is inclusive on both ends and can lead to subtle bugs, \
25         especially with date/time ranges. For example, 'BETWEEN '2024-01-01' AND '2024-01-31'' \
26         may miss times on the 31st after midnight. Prefer explicit '>= ... AND <= ...' for clarity."
27    }
28    fn groups(&self) -> &[RuleGroup] {
29        &[RuleGroup::Convention]
30    }
31    fn is_fixable(&self) -> bool {
32        false
33    }
34
35    fn crawl_type(&self) -> CrawlType {
36        CrawlType::Segment(vec![SegmentType::BetweenExpression])
37    }
38
39    fn eval(&self, ctx: &RuleContext) -> Vec<LintViolation> {
40        vec![LintViolation::with_msg_key(
41            self.code(),
42            "Use of BETWEEN. Consider using >= and <= for explicit range boundaries.",
43            ctx.segment.span(),
44            "rules.RG03.msg",
45            vec![],
46        )]
47    }
48}
49
50#[cfg(test)]
51mod tests {
52    use super::*;
53    use crate::test_utils::lint_sql;
54
55    #[test]
56    fn test_rg03_flags_between() {
57        let violations = lint_sql("SELECT * FROM t WHERE x BETWEEN 1 AND 10", RuleRG03);
58        assert_eq!(violations.len(), 1);
59    }
60
61    #[test]
62    fn test_rg03_accepts_comparison() {
63        let violations = lint_sql("SELECT * FROM t WHERE x >= 1", RuleRG03);
64        assert_eq!(violations.len(), 0);
65    }
66}