sqruff_lib/rules/layout/
lt11.rs

1use ahash::AHashMap;
2use sqruff_lib_core::dialects::syntax::{SyntaxKind, SyntaxSet};
3
4use crate::core::config::Value;
5use crate::core::rules::base::{Erased, ErasedRule, LintResult, Rule, RuleGroups};
6use crate::core::rules::context::RuleContext;
7use crate::core::rules::crawlers::{Crawler, SegmentSeekerCrawler};
8use crate::utils::reflow::sequence::{ReflowSequence, TargetSide};
9
10#[derive(Debug, Default, Clone)]
11pub struct RuleLT11;
12
13impl Rule for RuleLT11 {
14    fn load_from_config(&self, _config: &AHashMap<String, Value>) -> Result<ErasedRule, String> {
15        Ok(RuleLT11.erased())
16    }
17    fn name(&self) -> &'static str {
18        "layout.set_operators"
19    }
20
21    fn description(&self) -> &'static str {
22        "Set operators should be surrounded by newlines."
23    }
24
25    fn long_description(&self) -> &'static str {
26        r#"
27**Anti-pattern**
28
29In this example, `UNION ALL` is not on a line itself.
30
31```sql
32SELECT 'a' AS col UNION ALL
33SELECT 'b' AS col
34```
35
36**Best practice**
37
38Place `UNION ALL` on its own line.
39
40```sql
41SELECT 'a' AS col
42UNION ALL
43SELECT 'b' AS col
44```
45"#
46    }
47
48    fn groups(&self) -> &'static [RuleGroups] {
49        &[RuleGroups::All, RuleGroups::Core, RuleGroups::Layout]
50    }
51    fn eval(&self, context: &RuleContext) -> Vec<LintResult> {
52        ReflowSequence::from_around_target(
53            &context.segment,
54            context.parent_stack.first().unwrap().clone(),
55            TargetSide::Both,
56            context.config,
57        )
58        .rebreak(context.tables)
59        .results()
60    }
61
62    fn is_fix_compatible(&self) -> bool {
63        true
64    }
65
66    fn crawl_behaviour(&self) -> Crawler {
67        SegmentSeekerCrawler::new(const { SyntaxSet::new(&[SyntaxKind::SetOperator]) }).into()
68    }
69}