sqruff_lib/rules/capitalisation/
cp05.rs1use ahash::AHashMap;
2use sqruff_lib_core::dialects::syntax::{SyntaxKind, SyntaxSet};
3
4use super::cp01::handle_segment;
5use crate::core::config::Value;
6use crate::core::rules::base::{Erased, ErasedRule, LintResult, Rule, RuleGroups};
7use crate::core::rules::context::RuleContext;
8use crate::core::rules::crawlers::{Crawler, SegmentSeekerCrawler};
9
10#[derive(Debug, Default, Clone)]
11pub struct RuleCP05 {
12 extended_capitalisation_policy: String,
13}
14
15impl Rule for RuleCP05 {
16 fn load_from_config(&self, config: &AHashMap<String, Value>) -> Result<ErasedRule, String> {
17 Ok(RuleCP05 {
18 extended_capitalisation_policy: config["extended_capitalisation_policy"]
19 .as_string()
20 .unwrap()
21 .to_string(),
22 }
23 .erased())
24 }
25
26 fn name(&self) -> &'static str {
27 "capitalisation.types"
28 }
29
30 fn description(&self) -> &'static str {
31 "Inconsistent capitalisation of datatypes."
32 }
33
34 fn long_description(&self) -> &'static str {
35 r#"
36**Anti-pattern**
37
38In this example, `int` and `unsigned` are in lower-case whereas `VARCHAR` is in upper-case.
39
40```sql
41CREATE TABLE t (
42 a int unsigned,
43 b VARCHAR(15)
44);
45```
46
47**Best practice**
48
49Ensure all datatypes are consistently upper or lower case
50
51```sql
52CREATE TABLE t (
53 a INT UNSIGNED,
54 b VARCHAR(15)
55);
56```
57"#
58 }
59
60 fn groups(&self) -> &'static [RuleGroups] {
61 &[
62 RuleGroups::All,
63 RuleGroups::Core,
64 RuleGroups::Capitalisation,
65 ]
66 }
67
68 fn eval(&self, context: &RuleContext) -> Vec<LintResult> {
69 let mut results = Vec::new();
70
71 if context.segment.is_type(SyntaxKind::PrimitiveType)
72 || context.segment.is_type(SyntaxKind::DatetimeTypeIdentifier)
73 || context.segment.is_type(SyntaxKind::DataType)
74 {
75 for seg in context.segment.segments() {
76 if seg.is_type(SyntaxKind::Symbol)
77 || seg.is_type(SyntaxKind::Identifier)
78 || seg.is_type(SyntaxKind::QuotedLiteral)
79 || !seg.segments().is_empty()
80 {
81 continue;
82 }
83
84 results.push(handle_segment(
85 "Datatypes",
86 &self.extended_capitalisation_policy,
87 "extended_capitalisation_policy",
88 seg.clone(),
89 context,
90 ));
91 }
92 }
93
94 results
95 }
96
97 fn is_fix_compatible(&self) -> bool {
98 true
99 }
100
101 fn crawl_behaviour(&self) -> Crawler {
102 SegmentSeekerCrawler::new(
103 const {
104 SyntaxSet::new(&[
105 SyntaxKind::DataTypeIdentifier,
106 SyntaxKind::PrimitiveType,
107 SyntaxKind::DatetimeTypeIdentifier,
108 SyntaxKind::DataType,
109 ])
110 },
111 )
112 .into()
113 }
114}