sqruff_lib/rules/layout/
lt11.rs1use 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}