diff --git a/crates/cli/src/docs.rs b/crates/cli/src/docs.rs index 343c04872..f3d712a9b 100644 --- a/crates/cli/src/docs.rs +++ b/crates/cli/src/docs.rs @@ -39,7 +39,7 @@ struct Rule { pub code: &'static str, pub description: &'static str, pub fixable: bool, - pub long_description: Option<&'static str>, + pub long_description: &'static str, } impl From for Rule { diff --git a/crates/cli/src/docs/generate_rule_docs_template.md b/crates/cli/src/docs/generate_rule_docs_template.md index 68b8794d2..92a9908d6 100644 --- a/crates/cli/src/docs/generate_rule_docs_template.md +++ b/crates/cli/src/docs/generate_rule_docs_template.md @@ -18,5 +18,5 @@ The following rules are available in this create. This list is generated from th **Fixable:** {% if rule.fixable %}Yes{% else %}No{% endif %} -{% if rule.long_description %}{{ rule.long_description }}{% endif %} +{{ rule.long_description }} {% endfor %} diff --git a/crates/lib/benches/depth_map.rs b/crates/lib/benches/depth_map.rs index 2d68f72be..a6dadceb1 100644 --- a/crates/lib/benches/depth_map.rs +++ b/crates/lib/benches/depth_map.rs @@ -70,7 +70,7 @@ SELECT construct_depth_info('uuid-3');"#; fn depth_map(c: &mut Criterion) { let linter = Linter::new(FluffConfig::default(), None, None); - let tree = linter.parse_string(COMPLEX_QUERY.into(), None, None, None).unwrap().tree.unwrap(); + let tree = linter.parse_string(COMPLEX_QUERY, None, None, None).unwrap().tree.unwrap(); c.bench_function("DepthMap::from_parent", |b| { b.iter(|| black_box(DepthMap::from_parent(&tree))); diff --git a/crates/lib/benches/parsing.rs b/crates/lib/benches/parsing.rs index 620a0317f..4a947577f 100644 --- a/crates/lib/benches/parsing.rs +++ b/crates/lib/benches/parsing.rs @@ -98,9 +98,9 @@ fn mk_segments<'a>( config: &FluffConfig, source: &str, ) -> (ParseContext<'a>, std::sync::Arc, Vec) { - let ctx = ParseContext::new(&dialect, <_>::default()); + let ctx = ParseContext::new(dialect, <_>::default()); let segment = dialect.r#ref("FileSegment"); - let mut segments = lex(&config, source); + let mut segments = lex(config, source); if segments.last().unwrap().get_type() == "end_of_file" { segments.pop(); diff --git a/crates/lib/src/cli/formatters.rs b/crates/lib/src/cli/formatters.rs index b4d40e302..3d57bec56 100644 --- a/crates/lib/src/cli/formatters.rs +++ b/crates/lib/src/cli/formatters.rs @@ -375,6 +375,10 @@ mod tests { "" } + fn long_description(&self) -> &'static str { + "Ghost rule for testing purposes" + } + fn code(&self) -> &'static str { "A" } diff --git a/crates/lib/src/core/linter/linter.rs b/crates/lib/src/core/linter/linter.rs index 719dfd3c2..6c83dd2b6 100644 --- a/crates/lib/src/core/linter/linter.rs +++ b/crates/lib/src/core/linter/linter.rs @@ -693,7 +693,7 @@ mod tests { #[test] fn test__linter__empty_file() { let linter = Linter::new(FluffConfig::new(<_>::default(), None, None), None, None); - let parsed = linter.parse_string("".into(), None, None, None).unwrap(); + let parsed = linter.parse_string("", None, None, None).unwrap(); assert!(parsed.violations.is_empty()); } diff --git a/crates/lib/src/core/parser/lexer.rs b/crates/lib/src/core/parser/lexer.rs index 149504969..a75f6fb4c 100644 --- a/crates/lib/src/core/parser/lexer.rs +++ b/crates/lib/src/core/parser/lexer.rs @@ -608,7 +608,7 @@ mod tests { /// particular string or negative matching (that it explicitly) /// doesn't match. fn assert_matches(in_string: &str, matcher: &Matcher, match_string: Option<&str>) { - let res = matcher.matches(&in_string); + let res = matcher.matches(in_string); if let Some(match_string) = match_string { assert_eq!(res.forward_string, &in_string[match_string.len()..]); assert_eq!(res.elements.len(), 1); @@ -663,7 +663,7 @@ mod tests { ]; for (raw, reg, res) in tests { - let matcher = Matcher::regex("test", ®, |_, _| unimplemented!()); + let matcher = Matcher::regex("test", reg, |_, _| unimplemented!()); assert_matches(raw, &matcher, Some(res)); } diff --git a/crates/lib/src/core/parser/parsers.rs b/crates/lib/src/core/parser/parsers.rs index a9d480ea5..e435848d9 100644 --- a/crates/lib/src/core/parser/parsers.rs +++ b/crates/lib/src/core/parser/parsers.rs @@ -391,7 +391,7 @@ mod tests { assert_eq!( parser.simple(&parse_cx, None), - (AHashSet::new(), ["single_quote".into()].into()).into() + (AHashSet::new(), ["single_quote"].into()).into() ); } diff --git a/crates/lib/src/core/rules/base.rs b/crates/lib/src/core/rules/base.rs index 4e85ec391..8aaf9cd54 100644 --- a/crates/lib/src/core/rules/base.rs +++ b/crates/lib/src/core/rules/base.rs @@ -248,16 +248,14 @@ pub trait Rule: CloneRule + dyn_clone::DynClone + Debug + 'static + Send + Sync fn name(&self) -> &'static str; - fn long_description(&self) -> Option<&'static str> { - None - } - fn config_ref(&self) -> &'static str { self.name() } fn description(&self) -> &'static str; + fn long_description(&self) -> &'static str; + fn groups(&self) -> &'static [&'static str] { &["all"] } diff --git a/crates/lib/src/dialects/ansi.rs b/crates/lib/src/dialects/ansi.rs index 27ce2aa17..074456a65 100644 --- a/crates/lib/src/dialects/ansi.rs +++ b/crates/lib/src/dialects/ansi.rs @@ -6662,7 +6662,7 @@ mod tests { } fn parse_sql(linter: &Linter, sql: &str) -> ErasedSegment { - let parsed = linter.parse_string(sql.into(), None, None, None).unwrap(); + let parsed = linter.parse_string(sql, None, None, None).unwrap(); parsed.tree.unwrap() } diff --git a/crates/lib/src/dialects/bigquery.rs b/crates/lib/src/dialects/bigquery.rs index bbd09682f..263368f5c 100644 --- a/crates/lib/src/dialects/bigquery.rs +++ b/crates/lib/src/dialects/bigquery.rs @@ -2840,7 +2840,7 @@ mod tests { use crate::helpers; fn parse_sql(linter: &Linter, sql: &str) -> ErasedSegment { - let parsed = linter.parse_string(sql.into(), None, None, None).unwrap(); + let parsed = linter.parse_string(sql, None, None, None).unwrap(); parsed.tree.unwrap() } diff --git a/crates/lib/src/dialects/clickhouse.rs b/crates/lib/src/dialects/clickhouse.rs index 577b4a0fb..5e2359cda 100644 --- a/crates/lib/src/dialects/clickhouse.rs +++ b/crates/lib/src/dialects/clickhouse.rs @@ -1307,7 +1307,7 @@ mod tests { use crate::helpers; fn parse_sql(linter: &Linter, sql: &str) -> ErasedSegment { - let parsed = linter.parse_string(sql.into(), None, None, None).unwrap(); + let parsed = linter.parse_string(sql, None, None, None).unwrap(); parsed.tree.unwrap() } diff --git a/crates/lib/src/dialects/postgres.rs b/crates/lib/src/dialects/postgres.rs index 42dab104c..0ba6d5a32 100644 --- a/crates/lib/src/dialects/postgres.rs +++ b/crates/lib/src/dialects/postgres.rs @@ -7012,7 +7012,7 @@ mod tests { use crate::helpers; fn parse_sql(linter: &Linter, sql: &str) -> ErasedSegment { - let parsed = linter.parse_string(sql.into(), None, None, None).unwrap(); + let parsed = linter.parse_string(sql, None, None, None).unwrap(); parsed.tree.unwrap() } diff --git a/crates/lib/src/dialects/snowflake.rs b/crates/lib/src/dialects/snowflake.rs index 0a6fd4572..1631e85e0 100644 --- a/crates/lib/src/dialects/snowflake.rs +++ b/crates/lib/src/dialects/snowflake.rs @@ -8616,7 +8616,7 @@ mod tests { use crate::helpers; fn parse_sql(linter: &Linter, sql: &str) -> ErasedSegment { - let parsed = linter.parse_string(sql.into(), None, None, None).unwrap(); + let parsed = linter.parse_string(sql, None, None, None).unwrap(); parsed.tree.unwrap() } diff --git a/crates/lib/src/rules/aliasing/AL01.rs b/crates/lib/src/rules/aliasing/AL01.rs index f64dfd73f..68f490dc3 100644 --- a/crates/lib/src/rules/aliasing/AL01.rs +++ b/crates/lib/src/rules/aliasing/AL01.rs @@ -61,8 +61,28 @@ impl Rule for RuleAL01 { "Implicit/explicit aliasing of table." } - fn is_fix_compatible(&self) -> bool { - true + fn long_description(&self) -> &'static str { + r#" +**Anti-pattern** + +In this example, the alias `voo` is implicit. + +```sql +SELECT + voo.a +FROM foo voo +``` + +**Best practice** + +Add `AS` to make the alias explicit. + +```sql +SELECT + voo.a +FROM foo AS voo +``` +"# } fn eval(&self, rule_cx: RuleContext) -> Vec { @@ -129,33 +149,12 @@ impl Rule for RuleAL01 { Vec::new() } - fn crawl_behaviour(&self) -> Crawler { - SegmentSeekerCrawler::new(["alias_expression"].into()).into() + fn is_fix_compatible(&self) -> bool { + true } - fn long_description(&self) -> Option<&'static str> { - r#" -**Anti-pattern** - -In this example, the alias `voo` is implicit. - -```sql -SELECT - voo.a -FROM foo voo -``` - -**Best practice** - -Add `AS` to make the alias explicit. - -```sql -SELECT - voo.a -FROM foo AS voo -``` -"# - .into() + fn crawl_behaviour(&self) -> Crawler { + SegmentSeekerCrawler::new(["alias_expression"].into()).into() } } diff --git a/crates/lib/src/rules/aliasing/AL02.rs b/crates/lib/src/rules/aliasing/AL02.rs index ed0ffbf12..d565b4e3b 100644 --- a/crates/lib/src/rules/aliasing/AL02.rs +++ b/crates/lib/src/rules/aliasing/AL02.rs @@ -34,7 +34,11 @@ impl Rule for RuleAL02 { "aliasing.column" } - fn long_description(&self) -> Option<&'static str> { + fn description(&self) -> &'static str { + "Implicit/explicit aliasing of columns." + } + + fn long_description(&self) -> &'static str { r#" **Anti-pattern** @@ -56,11 +60,6 @@ SELECT FROM foo ``` "# - .into() - } - - fn description(&self) -> &'static str { - "Implicit/explicit aliasing of columns." } fn eval(&self, context: RuleContext) -> Vec { @@ -103,7 +102,7 @@ mod tests { #[test] fn test_fail_explicit_column_default() { assert_eq!( - fix("select 1 bar from table1 b".into(), vec![RuleAL02::default().erased()]), + fix("select 1 bar from table1 b", vec![RuleAL02::default().erased()]), "select 1 AS bar from table1 b" ); } diff --git a/crates/lib/src/rules/aliasing/AL03.rs b/crates/lib/src/rules/aliasing/AL03.rs index 35c191a9a..7364288aa 100644 --- a/crates/lib/src/rules/aliasing/AL03.rs +++ b/crates/lib/src/rules/aliasing/AL03.rs @@ -20,7 +20,11 @@ impl Rule for RuleAL03 { "aliasing.expression" } - fn long_description(&self) -> Option<&'static str> { + fn description(&self) -> &'static str { + "Column expression without alias. Use explicit `AS` clause." + } + + fn long_description(&self) -> &'static str { r#" **Anti-pattern** @@ -44,11 +48,6 @@ SELECT FROM foo ``` "# - .into() - } - - fn description(&self) -> &'static str { - "Column expression without alias. Use explicit `AS` clause." } fn eval(&self, context: RuleContext) -> Vec { diff --git a/crates/lib/src/rules/aliasing/AL04.rs b/crates/lib/src/rules/aliasing/AL04.rs index 9dde1065d..14de1047d 100644 --- a/crates/lib/src/rules/aliasing/AL04.rs +++ b/crates/lib/src/rules/aliasing/AL04.rs @@ -20,7 +20,11 @@ impl Rule for RuleAL04 { "aliasing.unique.table" } - fn long_description(&self) -> Option<&'static str> { + fn description(&self) -> &'static str { + "Table aliases should be unique within each clause." + } + + fn long_description(&self) -> &'static str { r#" **Anti-pattern** @@ -64,11 +68,6 @@ FROM 2021.foo AS f2 ``` "# - .into() - } - - fn description(&self) -> &'static str { - "Table aliases should be unique within each clause." } fn eval(&self, context: RuleContext) -> Vec { diff --git a/crates/lib/src/rules/aliasing/AL05.rs b/crates/lib/src/rules/aliasing/AL05.rs index d874a9f80..74875b3a4 100644 --- a/crates/lib/src/rules/aliasing/AL05.rs +++ b/crates/lib/src/rules/aliasing/AL05.rs @@ -33,7 +33,11 @@ impl Rule for RuleAL05 { "aliasing.unused" } - fn long_description(&self) -> Option<&'static str> { + fn description(&self) -> &'static str { + "Tables should not be aliased if that alias is not used." + } + + fn long_description(&self) -> &'static str { r#" **Anti-pattern** @@ -60,11 +64,7 @@ SELECT a FROM foo ``` -"#.into() - } - - fn description(&self) -> &'static str { - "Tables should not be aliased if that alias is not used." +"# } fn eval(&self, context: RuleContext) -> Vec { @@ -144,15 +144,15 @@ impl RuleAL05 { fn is_alias_required(from_expression_element: &ErasedSegment) -> bool { for segment in from_expression_element.iter_segments(Some(&["bracketed"]), false) { if segment.is_type("table_expression") { - if segment.child(&["values_clause"]).is_some() { - return false; + return if segment.child(&["values_clause"]).is_some() { + false } else { - return segment.iter_segments(Some(&["bracketed"]), false).iter().any(|seg| { + segment.iter_segments(Some(&["bracketed"]), false).iter().any(|seg| { ["select_statement", "set_expression", "with_compound_statement"] .iter() .any(|it| seg.is_type(it)) - }); - } + }) + }; } } false @@ -198,7 +198,7 @@ mod tests { let fail_str = "SELECT * FROM my_tbl AS foo"; let fix_str = "SELECT * FROM my_tbl"; - let result = fix(fail_str.into(), rules()); + let result = fix(fail_str, rules()); assert_eq!(fix_str, result); } @@ -207,7 +207,7 @@ mod tests { let fail_str = "SELECT * FROM (SELECT * FROM my_tbl AS foo)"; let fix_str = "SELECT * FROM (SELECT * FROM my_tbl)"; - let result = fix(fail_str.into(), rules()); + let result = fix(fail_str, rules()); assert_eq!(fix_str, result); } @@ -295,7 +295,7 @@ mod tests { let fail_str = "SELECT * FROM my_tbl foo"; let fix_str = "SELECT * FROM my_tbl"; - let result = fix(fail_str.into(), rules()); + let result = fix(fail_str, rules()); assert_eq!(fix_str, result); } @@ -304,7 +304,7 @@ mod tests { let fail_str = "SELECT * FROM (SELECT * FROM my_tbl foo)"; let fix_str = "SELECT * FROM (SELECT * FROM my_tbl)"; - let result = fix(fail_str.into(), rules()); + let result = fix(fail_str, rules()); assert_eq!(fix_str, result); } @@ -443,7 +443,7 @@ mod tests { FROM my_table "#; - let result = fix(fail_str.into(), rules()); + let result = fix(fail_str, rules()); assert_eq!(fix_str, result); } diff --git a/crates/lib/src/rules/aliasing/AL06.rs b/crates/lib/src/rules/aliasing/AL06.rs index 5c77285a4..4d1f3586d 100644 --- a/crates/lib/src/rules/aliasing/AL06.rs +++ b/crates/lib/src/rules/aliasing/AL06.rs @@ -78,29 +78,19 @@ impl RuleAL06 { } impl Rule for RuleAL06 { - fn name(&self) -> &'static str { - "aliasing.lenght" - } - - fn description(&self) -> &'static str { - "Identify aliases in from clause and join conditions" - } - fn load_from_config(&self, _config: &ahash::AHashMap) -> ErasedRule { RuleAL06::default().erased() } - fn eval(&self, context: RuleContext) -> Vec { - let children = FunctionalContext::new(context.clone()).segment().children(None); - let from_expression_elements = children.recursive_crawl(&["from_expression_element"], true); - self.lint_aliases(from_expression_elements.base) + fn name(&self) -> &'static str { + "aliasing.lenght" } - fn crawl_behaviour(&self) -> Crawler { - SegmentSeekerCrawler::new(["select_statement"].into()).into() + fn description(&self) -> &'static str { + "Identify aliases in from clause and join conditions" } - fn long_description(&self) -> Option<&'static str> { + fn long_description(&self) -> &'static str { r#" **Anti-pattern** @@ -133,7 +123,16 @@ JOIN ON replacement_orders.id = previous_orders.replacement_id ``` "# - .into() + } + + fn eval(&self, context: RuleContext) -> Vec { + let children = FunctionalContext::new(context.clone()).segment().children(None); + let from_expression_elements = children.recursive_crawl(&["from_expression_element"], true); + self.lint_aliases(from_expression_elements.base) + } + + fn crawl_behaviour(&self) -> Crawler { + SegmentSeekerCrawler::new(["select_statement"].into()).into() } } diff --git a/crates/lib/src/rules/aliasing/AL07.rs b/crates/lib/src/rules/aliasing/AL07.rs index fd4c9465b..e2e348996 100644 --- a/crates/lib/src/rules/aliasing/AL07.rs +++ b/crates/lib/src/rules/aliasing/AL07.rs @@ -188,7 +188,11 @@ impl Rule for RuleAL07 { "aliasing.forbid" } - fn long_description(&self) -> Option<&'static str> { + fn description(&self) -> &'static str { + "Avoid table aliases in from clauses and join conditions." + } + + fn long_description(&self) -> &'static str { r#" **Anti-pattern** @@ -224,11 +228,6 @@ FROM table1.foreign_key = table_alias.foreign_key ``` "# - .into() - } - - fn description(&self) -> &'static str { - "Avoid table aliases in from clauses and join conditions." } fn eval(&self, context: RuleContext) -> Vec { @@ -326,7 +325,7 @@ FROM users JOIN customers on users.id = customers.user_id JOIN orders on users.id = orders.user_id;"; - let actual = fix(fail_str.into(), rules()); + let actual = fix(fail_str, rules()); assert_eq!(actual, fix_str); } @@ -354,7 +353,7 @@ JOIN customers on users.id = customers.user_id JOIN orders on users.id = orders.user_id order by orders.user_id desc;"; - let actual = fix(fail_str.into(), rules()); + let actual = fix(fail_str, rules()); assert_eq!(actual, fix_str); } @@ -382,7 +381,7 @@ JOIN customers on users.id = customers.user_id JOIN orders on users.id = orders.user_id order by o desc;"; // In the fix string, 'o' is intentionally left unchanged assuming it's now clear or a different issue - let actual = fix(fail_str.into(), rules()); + let actual = fix(fail_str, rules()); assert_eq!(actual, fix_str); } @@ -391,7 +390,7 @@ order by o desc;"; // In the fix string, 'o' is intentionally left unchanged ass let fail_str = "select b from tbl as a"; let fix_str = "select b from tbl"; - let actual = fix(fail_str.into(), rules()); + let actual = fix(fail_str, rules()); assert_eq!(actual, fix_str); } @@ -400,7 +399,7 @@ order by o desc;"; // In the fix string, 'o' is intentionally left unchanged ass let fail_str = "select * from tbl as a"; let fix_str = "select * from tbl"; - let actual = fix(fail_str.into(), rules()); + let actual = fix(fail_str, rules()); assert_eq!(actual, fix_str); } @@ -408,7 +407,7 @@ order by o desc;"; // In the fix string, 'o' is intentionally left unchanged ass fn test_select_from_values() { let pass_str = "select *\nfrom values(1, 2, 3)"; - let actual = fix(pass_str.into(), rules()); + let actual = fix(pass_str, rules()); assert_eq!(actual, pass_str); } @@ -444,7 +443,7 @@ from let pass_str = "SELECT aaaaaa.c\nFROM aaaaaa\nJOIN bbbbbb AS b ON b.a = aaaaaa.id\nJOIN \ bbbbbb AS b2 ON b2.other = b.id"; - let actual = fix(pass_str.into(), rules()); + let actual = fix(pass_str, rules()); assert_eq!(actual, pass_str); } @@ -455,7 +454,7 @@ from t2,\n(select * from data\nwhere repl=t2.m and\nrnd>=t1.v\norder by \ rnd\nlimit 1)"; - let actual = fix(pass_str.into(), rules()); + let actual = fix(pass_str, rules()); assert_eq!(actual, pass_str); } @@ -490,7 +489,7 @@ from JOIN customers on users.id = customers.user_id JOIN orders\non users.id = \ orders.user_id;"; - let actual = fix(fail_str.into(), rules()); + let actual = fix(fail_str, rules()); assert_eq!(actual, fix_str); } } diff --git a/crates/lib/src/rules/aliasing/AL08.rs b/crates/lib/src/rules/aliasing/AL08.rs index 2b248653f..d3ddda462 100644 --- a/crates/lib/src/rules/aliasing/AL08.rs +++ b/crates/lib/src/rules/aliasing/AL08.rs @@ -24,7 +24,7 @@ impl Rule for RuleAL08 { "Column aliases should be unique within each clause." } - fn long_description(&self) -> Option<&'static str> { + fn long_description(&self) -> &'static str { r#" **Anti-pattern** @@ -60,7 +60,6 @@ FROM table1.foreign_key = table_alias.foreign_key ``` "# - .into() } fn eval(&self, context: RuleContext) -> Vec { diff --git a/crates/lib/src/rules/aliasing/AL09.rs b/crates/lib/src/rules/aliasing/AL09.rs index b4b9d3da1..123fe9923 100644 --- a/crates/lib/src/rules/aliasing/AL09.rs +++ b/crates/lib/src/rules/aliasing/AL09.rs @@ -8,6 +8,10 @@ use crate::utils::functional::context::FunctionalContext; pub struct RuleAL09 {} impl Rule for RuleAL09 { + fn load_from_config(&self, _config: &ahash::AHashMap) -> ErasedRule { + RuleAL09::default().erased() + } + fn name(&self) -> &'static str { "aliasing.self_alias.column" } @@ -16,8 +20,28 @@ impl Rule for RuleAL09 { "Find self-aliased columns and fix them" } - fn load_from_config(&self, _config: &ahash::AHashMap) -> ErasedRule { - RuleAL09::default().erased() + fn long_description(&self) -> &'static str { + r#" +**Anti-pattern** + +Aliasing the column to itself. + +```sql +SELECT + col AS col +FROM table; +``` + +**Best practice** + +Not to use alias to rename the column to its original name. Self-aliasing leads to redundant code without changing any functionality. + +```sql +SELECT + col +FROM table; +``` +"# } fn eval(&self, context: RuleContext) -> Vec { @@ -126,7 +150,7 @@ mod tests { let fail_str = "select col_a as col_a, col_b as new_col_b from foo"; let fix_str = "select col_a, col_b as new_col_b from foo"; - let result = fix(fail_str.into(), rules()); + let result = fix(fail_str, rules()); assert_eq!(fix_str, result); } @@ -135,7 +159,7 @@ mod tests { let fail_str = "select col_a as COL_A, col_b as new_col_b from foo"; let fix_str = "select col_a, col_b as new_col_b from foo"; - let result = fix(fail_str.into(), rules()); + let result = fix(fail_str, rules()); assert_eq!(fix_str, result); } @@ -144,7 +168,7 @@ mod tests { let fail_str = "select col_a col_a, col_b AS new_col_b from foo"; let fix_str = "select col_a, col_b AS new_col_b from foo"; - let result = fix(fail_str.into(), rules()); + let result = fix(fail_str, rules()); assert_eq!(fix_str, result); } @@ -153,7 +177,7 @@ mod tests { let fail_str = "select a.col_a as col_a, a.col_b as new_col_b from foo as a"; let fix_str = "select a.col_a, a.col_b as new_col_b from foo as a"; - let result = fix(fail_str.into(), rules()); + let result = fix(fail_str, rules()); assert_eq!(fix_str, result); } @@ -162,7 +186,7 @@ mod tests { let fail_str = r#"select "col_a" as "col_a", col_b as new_col_b from foo"#; let fix_str = r#"select "col_a", col_b as new_col_b from foo"#; - let result = fix(fail_str.into(), rules()); + let result = fix(fail_str, rules()); assert_eq!(fix_str, result); } diff --git a/crates/lib/src/rules/ambiguous/AM01.rs b/crates/lib/src/rules/ambiguous/AM01.rs index 1c2b6d071..612c62319 100644 --- a/crates/lib/src/rules/ambiguous/AM01.rs +++ b/crates/lib/src/rules/ambiguous/AM01.rs @@ -18,7 +18,11 @@ impl Rule for RuleAM01 { "ambiguous.distinct" } - fn long_description(&self) -> Option<&'static str> { + fn description(&self) -> &'static str { + "Ambiguous use of 'DISTINCT' in a 'SELECT' statement with 'GROUP BY'." + } + + fn long_description(&self) -> &'static str { r#" **Anti-pattern** @@ -42,11 +46,6 @@ SELECT DISTINCT FROM foo ``` "# - .into() - } - - fn description(&self) -> &'static str { - "Ambiguous use of 'DISTINCT' in a 'SELECT' statement with 'GROUP BY'." } fn eval(&self, context: RuleContext) -> Vec { diff --git a/crates/lib/src/rules/ambiguous/AM02.rs b/crates/lib/src/rules/ambiguous/AM02.rs index bd71d6a68..ad8460b68 100644 --- a/crates/lib/src/rules/ambiguous/AM02.rs +++ b/crates/lib/src/rules/ambiguous/AM02.rs @@ -18,14 +18,11 @@ impl Rule for RuleAM02 { "ambiguous.union" } - fn is_fix_compatible(&self) -> bool { - true - } - fn description(&self) -> &'static str { "Look for UNION keyword not immediately followed by DISTINCT or ALL" } - fn long_description(&self) -> Option<&'static str> { + + fn long_description(&self) -> &'static str { r#" **Anti-pattern** @@ -48,13 +45,7 @@ UNION DISTINCT SELECT a, b FROM table_2 ``` "# - .into() - } - - fn crawl_behaviour(&self) -> Crawler { - SegmentSeekerCrawler::new(["set_operator"].into()).into() } - fn eval(&self, rule_cx: RuleContext) -> Vec { let supported_dialects = ["ansi", "hive", "mysql", "redshift"]; if !supported_dialects.contains(&rule_cx.dialect.name) { @@ -94,6 +85,14 @@ SELECT a, b FROM table_2 Vec::new() } + + fn is_fix_compatible(&self) -> bool { + true + } + + fn crawl_behaviour(&self) -> Crawler { + SegmentSeekerCrawler::new(["set_operator"].into()).into() + } } #[cfg(test)] @@ -149,7 +148,7 @@ mod tests { FROM tbl1 "; - let actual = fix(fail_str.into(), rules()); + let actual = fix(fail_str, rules()); assert_eq!(fix_str, actual); } @@ -224,7 +223,7 @@ mod tests { FROM tbl2 "; - let actual = fix(fail_str.into(), rules()); + let actual = fix(fail_str, rules()); assert_eq!(fix_str, actual); } @@ -263,7 +262,7 @@ mod tests { from tbl2 "; - let actual = fix(fail_str.into(), rules()); + let actual = fix(fail_str, rules()); assert_eq!(fix_str, actual); } diff --git a/crates/lib/src/rules/ambiguous/AM06.rs b/crates/lib/src/rules/ambiguous/AM06.rs index b321ce181..816990e34 100644 --- a/crates/lib/src/rules/ambiguous/AM06.rs +++ b/crates/lib/src/rules/ambiguous/AM06.rs @@ -31,7 +31,7 @@ impl Rule for RuleAM06 { fn description(&self) -> &'static str { "Inconsistent column references in 'GROUP BY/ORDER BY' clauses." } - fn long_description(&self) -> Option<&'static str> { + fn long_description(&self) -> &'static str { r#" **Anti-pattern** @@ -55,7 +55,6 @@ FROM foo ORDER BY a ASC, b DESC ``` "# - .into() } fn eval(&self, context: RuleContext) -> Vec { diff --git a/crates/lib/src/rules/capitalisation/CP01.rs b/crates/lib/src/rules/capitalisation/CP01.rs index 0f99461eb..e656a7b1a 100644 --- a/crates/lib/src/rules/capitalisation/CP01.rs +++ b/crates/lib/src/rules/capitalisation/CP01.rs @@ -49,10 +49,6 @@ impl Rule for RuleCP01 { "post" } - fn is_fix_compatible(&self) -> bool { - true - } - fn name(&self) -> &'static str { "capitalisation.keywords" } @@ -61,7 +57,7 @@ impl Rule for RuleCP01 { "Inconsistent capitalisation of keywords." } - fn long_description(&self) -> Option<&'static str> { + fn long_description(&self) -> &'static str { r#" **Anti-pattern** @@ -89,7 +85,6 @@ select from foo ``` "# - .into() } fn eval(&self, context: RuleContext) -> Vec { @@ -114,6 +109,10 @@ from foo )] } + fn is_fix_compatible(&self) -> bool { + true + } + fn crawl_behaviour(&self) -> Crawler { SegmentSeekerCrawler::new(["keyword", "binary_operator", "date_part"].into()).into() } @@ -259,7 +258,7 @@ mod tests { let fail_str = "SeLeCt 1;"; let fix_str = "SELECT 1;"; - let actual = fix(fail_str.into(), vec![RuleCP01::default().erased()]); + let actual = fix(fail_str, vec![RuleCP01::default().erased()]); assert_eq!(fix_str, actual); } @@ -268,7 +267,7 @@ mod tests { let fail_str = "SeLeCt 1 from blah;"; let fix_str = "SELECT 1 FROM blah;"; - let actual = fix(fail_str.into(), vec![RuleCP01::default().erased()]); + let actual = fix(fail_str, vec![RuleCP01::default().erased()]); assert_eq!(fix_str, actual); } @@ -278,7 +277,7 @@ mod tests { let fix_str = "select * from MOO order by dt desc;"; let actual = fix( - fail_str.into(), + fail_str, vec![RuleCP01 { capitalisation_policy: "lower".into(), ..Default::default() }.erased()], ); assert_eq!(fix_str, actual); @@ -290,7 +289,7 @@ mod tests { let fix_str = "SELECT * FROM MOO ORDER BY dt DESC;"; let actual = fix( - fail_str.into(), + fail_str, vec![RuleCP01 { capitalisation_policy: "upper".into(), ..Default::default() }.erased()], ); @@ -303,7 +302,7 @@ mod tests { let fix_str = "Select * From MOO Order By dt Desc;"; let actual = fix( - fail_str.into(), + fail_str, vec![ RuleCP01 { capitalisation_policy: "capitalise".into(), ..Default::default() } .erased(), @@ -319,7 +318,7 @@ mod tests { let fix_str = "SELECT dt + INTERVAL 2 DAY, INTERVAL 3 HOUR;"; let actual = fix( - fail_str.into(), + fail_str, vec![RuleCP01 { capitalisation_policy: "upper".into(), ..Default::default() }.erased()], ); @@ -332,7 +331,7 @@ mod tests { let fix_str = "select dt + interval 2 day, interval 3 hour;"; let actual = fix( - fail_str.into(), + fail_str, vec![RuleCP01 { capitalisation_policy: "lower".into(), ..Default::default() }.erased()], ); @@ -345,7 +344,7 @@ mod tests { let fix_str = "SELECT dt + INTERVAL 2 DAY, INTERVAL 3 HOUR;"; let actual = fix( - fail_str.into(), + fail_str, vec![RuleCP01 { capitalisation_policy: "upper".into(), ..Default::default() }.erased()], ); @@ -357,7 +356,7 @@ mod tests { let pass_str = "SELECT dt + INTERVAL 2 DAY, INTERVAL 3 HOUR;"; let expected_str = "SELECT dt + INTERVAL 2 DAY, INTERVAL 3 HOUR;"; - let actual = fix(pass_str.into(), vec![RuleCP01::default().erased()]); + let actual = fix(pass_str, vec![RuleCP01::default().erased()]); assert_eq!(expected_str, actual); } @@ -368,7 +367,7 @@ mod tests { let expected_str = "CREATE TABLE table1 (account_id bigint);"; let actual = fix( - pass_str.into(), + pass_str, vec![RuleCP01 { capitalisation_policy: "upper".into(), ..Default::default() }.erased()], ); diff --git a/crates/lib/src/rules/capitalisation/CP02.rs b/crates/lib/src/rules/capitalisation/CP02.rs index 033e8c087..53ba5d5d8 100644 --- a/crates/lib/src/rules/capitalisation/CP02.rs +++ b/crates/lib/src/rules/capitalisation/CP02.rs @@ -40,10 +40,6 @@ impl Rule for RuleCP02 { .erased() } - fn is_fix_compatible(&self) -> bool { - true - } - fn name(&self) -> &'static str { "capitalisation.identifiers" } @@ -52,7 +48,7 @@ impl Rule for RuleCP02 { "Inconsistent capitalisation of unquoted identifiers." } - fn long_description(&self) -> Option<&'static str> { + fn long_description(&self) -> &'static str { r#" **Anti-pattern** @@ -83,7 +79,6 @@ select from foo ``` "# - .into() } fn eval(&self, context: RuleContext) -> Vec { @@ -94,6 +89,10 @@ from foo } } + fn is_fix_compatible(&self) -> bool { + true + } + fn crawl_behaviour(&self) -> Crawler { SegmentSeekerCrawler::new(["naked_identifier", "properties_naked_identifier"].into()).into() } @@ -111,7 +110,7 @@ mod tests { fn test_pass_consistent_capitalisation_1() { let pass_str = "SELECT a, b"; - let actual = fix(pass_str.into(), vec![RuleCP02::default().erased()]); + let actual = fix(pass_str, vec![RuleCP02::default().erased()]); assert_eq!(pass_str, actual); } @@ -119,49 +118,49 @@ mod tests { fn test_pass_consistent_capitalisation_2() { let pass_str = "SELECT A, B"; - let actual = fix(pass_str.into(), vec![RuleCP02::default().erased()]); + let actual = fix(pass_str, vec![RuleCP02::default().erased()]); assert_eq!(pass_str, actual); } #[test] fn test_pass_consistent_capitalisation_with_null() { let pass_str = "SELECT NULL, a"; - let actual = fix(pass_str.into(), vec![RuleCP02::default().erased()]); + let actual = fix(pass_str, vec![RuleCP02::default().erased()]); assert_eq!(pass_str, actual); } #[test] fn test_pass_consistent_capitalisation_with_single_letter_upper() { let pass_str = "SELECT A, Boo"; - let actual = fix(pass_str.into(), vec![RuleCP02::default().erased()]); + let actual = fix(pass_str, vec![RuleCP02::default().erased()]); assert_eq!(pass_str, actual); } #[test] fn test_pass_consistent_capitalisation_with_single_word_snake() { let pass_str = "SELECT Apple, Banana_split"; - let actual = fix(pass_str.into(), vec![RuleCP02::default().erased()]); + let actual = fix(pass_str, vec![RuleCP02::default().erased()]); assert_eq!(pass_str, actual); } #[test] fn test_pass_consistent_capitalisation_with_single_word_pascal() { let pass_str = "SELECT AppleFritter, Banana"; - let actual = fix(pass_str.into(), vec![RuleCP02::default().erased()]); + let actual = fix(pass_str, vec![RuleCP02::default().erased()]); assert_eq!(pass_str, actual); } #[test] fn test_pass_consistent_capitalisation_with_multiple_words_with_numbers() { let pass_str = "SELECT AppleFritter, Apple123fritter, Apple123Fritter"; - let actual = fix(pass_str.into(), vec![RuleCP02::default().erased()]); + let actual = fix(pass_str, vec![RuleCP02::default().erased()]); assert_eq!(pass_str, actual); } #[test] fn test_pass_consistent_capitalisation_with_leading_underscore() { let pass_str = "SELECT _a, b"; - let actual = fix(pass_str.into(), vec![RuleCP02::default().erased()]); + let actual = fix(pass_str, vec![RuleCP02::default().erased()]); assert_eq!(pass_str, actual); } @@ -170,7 +169,7 @@ mod tests { // Test that fixes are consistent let fail_str = "SELECT a, B"; let expected = "SELECT a, b"; - let actual = fix(fail_str.into(), vec![RuleCP02::default().erased()]); + let actual = fix(fail_str, vec![RuleCP02::default().erased()]); assert_eq!(expected, actual); } @@ -179,7 +178,7 @@ mod tests { let fail_str = "SELECT B, a"; let expected = "SELECT B, A"; - let actual = fix(fail_str.into(), vec![RuleCP02::default().erased()]); + let actual = fix(fail_str, vec![RuleCP02::default().erased()]); assert_eq!(expected, actual); } } diff --git a/crates/lib/src/rules/capitalisation/CP03.rs b/crates/lib/src/rules/capitalisation/CP03.rs index 29a742202..8d25a0528 100644 --- a/crates/lib/src/rules/capitalisation/CP03.rs +++ b/crates/lib/src/rules/capitalisation/CP03.rs @@ -37,10 +37,6 @@ impl Rule for RuleCP03 { .erased() } - fn is_fix_compatible(&self) -> bool { - true - } - fn name(&self) -> &'static str { "capitalisation.functions" } @@ -49,7 +45,7 @@ impl Rule for RuleCP03 { "Inconsistent capitalisation of function names." } - fn long_description(&self) -> Option<&'static str> { + fn long_description(&self) -> &'static str { r#" **Anti-pattern** @@ -74,13 +70,16 @@ SELECT FROM foo ``` "# - .into() } fn eval(&self, context: RuleContext) -> Vec { self.base.eval(context) } + fn is_fix_compatible(&self) -> bool { + true + } + fn crawl_behaviour(&self) -> Crawler { SegmentSeekerCrawler::new(["function_name_identifier", "bare_function"].into()).into() } @@ -100,7 +99,7 @@ mod tests { let fail_str = "SELECT MAX(id), min(id) from table;"; let fix_str = "SELECT MAX(id), MIN(id) from table;"; - let actual = fix(fail_str.into(), vec![RuleCP03::default().erased()]); + let actual = fix(fail_str, vec![RuleCP03::default().erased()]); assert_eq!(fix_str, actual); } @@ -110,7 +109,7 @@ mod tests { let fix_str = "SELECT max(id), min(id) from table;"; let actual = fix( - fail_str.into(), + fail_str, vec![ RuleCP03 { base: RuleCP01 { capitalisation_policy: "lower".into(), ..Default::default() }, @@ -128,7 +127,7 @@ mod tests { let fix_str = "SELECT Current_Timestamp, Min(a) from table;"; let actual = fix( - fail_str.into(), + fail_str, vec![ RuleCP03 { base: RuleCP01 { capitalisation_policy: "pascal".into(), ..Default::default() }, @@ -145,7 +144,7 @@ mod tests { let fail_str = "SELECT FLOOR(dt) ,count(*) FROM test;"; let fix_str = "SELECT FLOOR(dt) ,COUNT(*) FROM test;"; - let actual = fix(fail_str.into(), vec![RuleCP03::default().erased()]); + let actual = fix(fail_str, vec![RuleCP03::default().erased()]); assert_eq!(fix_str, actual); } @@ -153,7 +152,7 @@ mod tests { fn test_pass_fully_qualified_function_mixed_functions() { let pass_str = "SELECT COUNT(*), project1.foo(value1) AS value2;"; - let actual = fix(pass_str.into(), vec![RuleCP03::default().erased()]); + let actual = fix(pass_str, vec![RuleCP03::default().erased()]); assert_eq!(pass_str, actual); } @@ -161,7 +160,7 @@ mod tests { fn test_pass_fully_qualified_function_pascal_case() { let pass_str = "SELECT project1.FoO(value1) AS value2"; - let actual = fix(pass_str.into(), vec![RuleCP03::default().erased()]); + let actual = fix(pass_str, vec![RuleCP03::default().erased()]); assert_eq!(pass_str, actual); } } diff --git a/crates/lib/src/rules/capitalisation/CP04.rs b/crates/lib/src/rules/capitalisation/CP04.rs index 813272ddc..100e09dda 100644 --- a/crates/lib/src/rules/capitalisation/CP04.rs +++ b/crates/lib/src/rules/capitalisation/CP04.rs @@ -34,10 +34,6 @@ impl Rule for RuleCP04 { .erased() } - fn is_fix_compatible(&self) -> bool { - true - } - fn name(&self) -> &'static str { "capitalisation.literals" } @@ -45,7 +41,8 @@ impl Rule for RuleCP04 { fn description(&self) -> &'static str { "Inconsistent capitalisation of boolean/null literal." } - fn long_description(&self) -> Option<&'static str> { + + fn long_description(&self) -> &'static str { r#" **Anti-pattern** @@ -82,13 +79,15 @@ select from foo ``` "# - .into() } - fn eval(&self, context: RuleContext) -> Vec { self.base.eval(context) } + fn is_fix_compatible(&self) -> bool { + true + } + fn crawl_behaviour(&self) -> Crawler { SegmentSeekerCrawler::new(["null_literal", "boolean_literal"].into()).into() } @@ -107,7 +106,7 @@ mod tests { let fail_str = "SeLeCt true, FALSE, NULL"; let fix_str = "SeLeCt true, false, null"; - let actual = fix(fail_str.into(), vec![RuleCP04::default().erased()]); + let actual = fix(fail_str, vec![RuleCP04::default().erased()]); assert_eq!(fix_str, actual); } } diff --git a/crates/lib/src/rules/capitalisation/CP05.rs b/crates/lib/src/rules/capitalisation/CP05.rs index 9320c0a0a..309d47575 100644 --- a/crates/lib/src/rules/capitalisation/CP05.rs +++ b/crates/lib/src/rules/capitalisation/CP05.rs @@ -30,7 +30,7 @@ impl Rule for RuleCP05 { "Inconsistent capitalisation of datatypes." } - fn long_description(&self) -> Option<&'static str> { + fn long_description(&self) -> &'static str { r#" **Anti-pattern** @@ -54,11 +54,6 @@ CREATE TABLE t ( ); ``` "# - .into() - } - - fn is_fix_compatible(&self) -> bool { - true } fn eval(&self, context: RuleContext) -> Vec { @@ -87,6 +82,10 @@ CREATE TABLE t ( results } + fn is_fix_compatible(&self) -> bool { + true + } + fn crawl_behaviour(&self) -> Crawler { SegmentSeekerCrawler::new( ["data_type_identifier", "primitive_type", "datetime_type_identifier", "data_type"] @@ -110,7 +109,7 @@ mod tests { let fix_str = "CREATE TABLE table1 (account_id BIGINT);"; let actual = fix( - fail_str.into(), + fail_str, vec![RuleCP05 { extended_capitalisation_policy: "upper".into() }.erased()], ); assert_eq!(fix_str, actual); @@ -122,7 +121,7 @@ mod tests { let fix_str = "CREATE TABLE table1 (account_id bigint);"; let actual = fix( - fail_str.into(), + fail_str, vec![RuleCP05 { extended_capitalisation_policy: "lower".into() }.erased()], ); assert_eq!(fix_str, actual); @@ -134,7 +133,7 @@ mod tests { let fix_str = "CREATE TABLE table1 (account_id Bigint);"; let actual = fix( - fail_str.into(), + fail_str, vec![RuleCP05 { extended_capitalisation_policy: "capitalise".into() }.erased()], ); assert_eq!(fix_str, actual); @@ -146,7 +145,7 @@ mod tests { let fix_str = "CREATE TABLE table1 (account_id bigint);"; let actual = fix( - fail_str.into(), + fail_str, vec![RuleCP05 { extended_capitalisation_policy: "lower".into() }.erased()], ); assert_eq!(fix_str, actual); @@ -158,7 +157,7 @@ mod tests { let fix_str = "CREATE TABLE table1 (account_id bigint, column_two varchar(255));"; let actual = fix( - fail_str.into(), + fail_str, vec![RuleCP05 { extended_capitalisation_policy: "lower".into() }.erased()], ); assert_eq!(fix_str, actual); @@ -170,7 +169,7 @@ mod tests { let fix_str = "CREATE TABLE table1 (account_id BIGINT);"; let actual = fix( - fail_str.into(), + fail_str, vec![RuleCP05 { extended_capitalisation_policy: "upper".into() }.erased()], ); assert_eq!(fix_str, actual); @@ -182,7 +181,7 @@ mod tests { let fix_str = "CREATE TABLE table1 (account_id BIGINT, column_two VARCHAR(255));"; let actual = fix( - fail_str.into(), + fail_str, vec![RuleCP05 { extended_capitalisation_policy: "upper".into() }.erased()], ); assert_eq!(fix_str, actual); @@ -194,7 +193,7 @@ mod tests { let fix_str = "CREATE TABLE table1 (account_id Bigint);"; let actual = fix( - fail_str.into(), + fail_str, vec![RuleCP05 { extended_capitalisation_policy: "capitalise".into() }.erased()], ); assert_eq!(fix_str, actual); @@ -206,7 +205,7 @@ mod tests { let fix_str = "CREATE TABLE table1 (account_id BIGINT, column_two TIMESTAMP);"; let actual = fix( - fail_str.into(), + fail_str, vec![RuleCP05 { extended_capitalisation_policy: "upper".into() }.erased()], ); assert_eq!(fix_str, actual); @@ -220,7 +219,7 @@ mod tests { "CREATE TABLE table1 (account_id BIGINT, column_two TIMESTAMP WITH TIME ZONE);"; let actual = fix( - fail_str.into(), + fail_str, vec![RuleCP05 { extended_capitalisation_policy: "upper".into() }.erased()], ); assert_eq!(fix_str, actual); diff --git a/crates/lib/src/rules/convention/CV02.rs b/crates/lib/src/rules/convention/CV02.rs index 24ee49f70..9e8355bc0 100644 --- a/crates/lib/src/rules/convention/CV02.rs +++ b/crates/lib/src/rules/convention/CV02.rs @@ -49,7 +49,7 @@ impl Rule for RuleCV02 { "Use 'COALESCE' instead of 'IFNULL' or 'NVL'." } - fn long_description(&self) -> Option<&'static str> { + fn long_description(&self) -> &'static str { r#" **Anti-pattern** @@ -72,7 +72,6 @@ SELECT coalesce(foo, 0) AS bar, FROM baz; ``` "# - .into() } fn eval(&self, context: RuleContext) -> Vec { diff --git a/crates/lib/src/rules/convention/CV03.rs b/crates/lib/src/rules/convention/CV03.rs index da1282207..d2442decd 100644 --- a/crates/lib/src/rules/convention/CV03.rs +++ b/crates/lib/src/rules/convention/CV03.rs @@ -37,7 +37,7 @@ impl Rule for RuleCV03 { "Trailing commas within select clause" } - fn long_description(&self) -> Option<&'static str> { + fn long_description(&self) -> &'static str { r#" **Anti-pattern** @@ -61,11 +61,6 @@ SELECT FROM foo ``` "# - .into() - } - - fn crawl_behaviour(&self) -> Crawler { - SegmentSeekerCrawler::new(["select_clause"].into()).into() } fn eval(&self, rule_cx: RuleContext) -> Vec { @@ -127,6 +122,10 @@ FROM foo } Vec::new() } + + fn crawl_behaviour(&self) -> Crawler { + SegmentSeekerCrawler::new(["select_clause"].into()).into() + } } #[cfg(test)] @@ -158,7 +157,7 @@ mod tests { let fail_str = "SELECT a, b FROM foo"; let fix_str = "SELECT a, b, FROM foo"; - let result = fix(fail_str.into(), rules()); + let result = fix(fail_str, rules()); assert_eq!(fix_str, result); } @@ -167,7 +166,7 @@ mod tests { let fail_str = "SELECT a, b FROM foo"; let fix_str = "SELECT a, b, FROM foo"; - let result = fix(fail_str.into(), vec![RuleCV03::default().erased()]); + let result = fix(fail_str, vec![RuleCV03::default().erased()]); assert_eq!(fix_str, result); } @@ -191,7 +190,7 @@ mod tests { let fail_str = "SELECT a, b, FROM foo"; let fix_str = "SELECT a, b FROM foo"; - let result = fix(fail_str.into(), rules_with_config("forbid".to_owned())); + let result = fix(fail_str, rules_with_config("forbid".to_owned())); assert_eq!(fix_str, result); } @@ -212,7 +211,7 @@ mod tests { {% endfor %} FROM tbl"#; - let result = fix(fail_str.into(), rules_with_config("forbid".to_owned())); + let result = fix(fail_str, rules_with_config("forbid".to_owned())); assert_eq!(fix_str, result); } } diff --git a/crates/lib/src/rules/convention/CV04.rs b/crates/lib/src/rules/convention/CV04.rs index 74fd650f6..22e1697ea 100644 --- a/crates/lib/src/rules/convention/CV04.rs +++ b/crates/lib/src/rules/convention/CV04.rs @@ -16,10 +16,6 @@ pub struct RuleCV04 { } impl Rule for RuleCV04 { - fn name(&self) -> &'static str { - "convention.count_rows" - } - fn load_from_config(&self, config: &AHashMap) -> ErasedRule { RuleCV04 { prefer_count_1: config @@ -36,15 +32,15 @@ impl Rule for RuleCV04 { .erased() } - fn crawl_behaviour(&self) -> Crawler { - SegmentSeekerCrawler::new(["function"].into()).into() + fn name(&self) -> &'static str { + "convention.count_rows" } fn description(&self) -> &'static str { "Use consistent syntax to express \"count number of rows\"." } - fn long_description(&self) -> Option<&'static str> { + fn long_description(&self) -> &'static str { r#" **Anti-pattern** @@ -66,7 +62,6 @@ select from table_a ``` "# - .into() } fn eval(&self, context: RuleContext) -> Vec { @@ -147,6 +142,10 @@ from table_a Vec::new() } + + fn crawl_behaviour(&self) -> Crawler { + SegmentSeekerCrawler::new(["function"].into()).into() + } } #[cfg(test)] @@ -211,7 +210,7 @@ mod tests { foo "#; - let actual = fix(fail_str.into(), rules()); + let actual = fix(fail_str, rules()); assert_eq!(fix_str, actual); } @@ -268,7 +267,7 @@ mod tests { foo "#; - let actual = fix(fail_str.into(), rules_with_config(true, true)); + let actual = fix(fail_str, rules_with_config(true, true)); assert_eq!(fix_str, actual); } @@ -291,7 +290,7 @@ mod tests { foo "#; - let actual = fix(fail_str.into(), rules()); + let actual = fix(fail_str, rules()); assert_eq!(fix_str, actual); } @@ -314,7 +313,7 @@ mod tests { foo "#; - let actual = fix(fail_str.into(), rules()); + let actual = fix(fail_str, rules()); assert_eq!(fix_str, actual); } @@ -337,7 +336,7 @@ mod tests { foo "#; - let actual = fix(fail_str.into(), rules_with_config(false, true)); + let actual = fix(fail_str, rules_with_config(false, true)); assert_eq!(fix_str, actual); } @@ -360,7 +359,7 @@ mod tests { foo "#; - let actual = fix(fail_str.into(), rules_with_config(true, false)); + let actual = fix(fail_str, rules_with_config(true, false)); assert_eq!(fix_str, actual); } @@ -383,7 +382,7 @@ mod tests { foo "#; - let actual = fix(fail_str.into(), rules_with_config(false, true)); + let actual = fix(fail_str, rules_with_config(false, true)); assert_eq!(fix_str, actual); } @@ -406,7 +405,7 @@ mod tests { foo "#; - let actual = fix(fail_str.into(), rules_with_config(true, false)); + let actual = fix(fail_str, rules_with_config(true, false)); assert_eq!(fix_str, actual); } @@ -437,7 +436,7 @@ mod tests { foo "#; - let actual = fix(fail_str.into(), rules_with_config(true, false)); + let actual = fix(fail_str, rules_with_config(true, false)); assert_eq!(fix_str, actual); } diff --git a/crates/lib/src/rules/convention/CV05.rs b/crates/lib/src/rules/convention/CV05.rs index 9883d8a37..dd1fb4b56 100644 --- a/crates/lib/src/rules/convention/CV05.rs +++ b/crates/lib/src/rules/convention/CV05.rs @@ -36,6 +36,10 @@ fn create_base_is_null_sequence(is_upper: bool, operator_raw: Cow) -> Corre } impl Rule for RuleCV05 { + fn load_from_config(&self, _config: &ahash::AHashMap) -> ErasedRule { + unimplemented!() + } + fn name(&self) -> &'static str { "convention.is_null" } @@ -44,7 +48,7 @@ impl Rule for RuleCV05 { "Relational operators should not be used to check for NULL values." } - fn long_description(&self) -> Option<&'static str> { + fn long_description(&self) -> &'static str { r#" **Anti-pattern** @@ -68,15 +72,6 @@ FROM foo WHERE a IS NULL ``` "# - .into() - } - - fn crawl_behaviour(&self) -> Crawler { - SegmentSeekerCrawler::new(["comparison_operator"].into()).into() - } - - fn load_from_config(&self, _config: &ahash::AHashMap) -> ErasedRule { - unimplemented!() } fn eval(&self, context: RuleContext) -> Vec { @@ -151,6 +146,10 @@ WHERE a IS NULL vec![LintResult::new(Some(context.segment.clone()), fixes, None, None, None)] } + + fn crawl_behaviour(&self) -> Crawler { + SegmentSeekerCrawler::new(["comparison_operator"].into()).into() + } } #[cfg(test)] @@ -200,7 +199,7 @@ mod test { let fail_str = "SELECT a FROM foo WHERE a <> NULL"; let fix_str = "SELECT a FROM foo WHERE a IS NOT NULL"; - let result = fix(fail_str.into(), vec![RuleCV05::default().erased()]); + let result = fix(fail_str, vec![RuleCV05::default().erased()]); assert_eq!(fix_str, result); } @@ -214,7 +213,7 @@ mod test { FROM foo WHERE a IS NOT NULL AND b IS NOT NULL AND c = 'foo'"#; - let result = fix(fail_str.into(), vec![RuleCV05::default().erased()]); + let result = fix(fail_str, vec![RuleCV05::default().erased()]); assert_eq!(fix_str, result); } @@ -223,7 +222,7 @@ mod test { let fail_str = "SELECT a FROM foo WHERE a <> null"; let fix_str = "SELECT a FROM foo WHERE a is not null"; - let actual = fix(fail_str.into(), vec![RuleCV05::default().erased()]); + let actual = fix(fail_str, vec![RuleCV05::default().erased()]); assert_eq!(fix_str, actual); } @@ -237,7 +236,7 @@ mod test { FROM foo WHERE a IS NULL"#; - let result = fix(fail_str.into(), vec![RuleCV05::default().erased()]); + let result = fix(fail_str, vec![RuleCV05::default().erased()]); assert_eq!(fix_str, result); } @@ -246,7 +245,7 @@ mod test { let fail_str = "SELECT a FROM foo WHERE a=NULL"; let fix_str = "SELECT a FROM foo WHERE a IS NULL"; - let result = fix(fail_str.into(), vec![RuleCV05::default().erased()]); + let result = fix(fail_str, vec![RuleCV05::default().erased()]); assert_eq!(fix_str, result); } @@ -255,7 +254,7 @@ mod test { let fail_str = "SELECT a FROM foo WHERE a = b or (c > d or e = NULL)"; let fix_str = "SELECT a FROM foo WHERE a = b or (c > d or e IS NULL)"; - let actual = fix(fail_str.into(), vec![RuleCV05::default().erased()]); + let actual = fix(fail_str, vec![RuleCV05::default().erased()]); assert_eq!(fix_str, actual); } diff --git a/crates/lib/src/rules/layout/LT01.rs b/crates/lib/src/rules/layout/LT01.rs index 7c2069f54..2ef773c63 100644 --- a/crates/lib/src/rules/layout/LT01.rs +++ b/crates/lib/src/rules/layout/LT01.rs @@ -18,7 +18,11 @@ impl Rule for RuleLT01 { "layout.spacing" } - fn long_description(&self) -> Option<&'static str> { + fn description(&self) -> &'static str { + "Inappropriate Spacing." + } + + fn long_description(&self) -> &'static str { r#" **Anti-pattern** @@ -44,11 +48,6 @@ FROM foo JOIN bar USING (a) ``` "# - .into() - } - - fn description(&self) -> &'static str { - "Inappropriate Spacing." } fn eval(&self, context: RuleContext) -> Vec { @@ -81,7 +80,7 @@ mod tests { #[test] fn test_fail_whitespace_before_comma() { - let sql = fix("SELECT 1 ,4".into(), rules()); + let sql = fix("SELECT 1 ,4", rules()); assert_eq!(sql, "SELECT 1, 4"); } @@ -113,13 +112,13 @@ mod tests { #[ignore = "parser needs further development"] fn test_fail_errors_only_in_non_templated_and_ignore() { // ignore_templated_areas: true - let sql = fix("{{ 'SELECT 1, 4' }}, 5 , 6".into(), rules()); + let sql = fix("{{ 'SELECT 1, 4' }}, 5 , 6", rules()); assert_eq!(sql, "{{ 'SELECT 1, 4' }}, 5, 6"); } #[test] fn test_pass_single_whitespace_after_comma() { - let sql = fix("SELECT 1, 4".into(), rules()); + let sql = fix("SELECT 1, 4", rules()); assert_eq!(sql, "SELECT 1, 4"); } @@ -133,19 +132,19 @@ mod tests { #[test] fn test_fail_multiple_whitespace_after_comma() { - let sql = fix("SELECT 1, 4".into(), rules()); + let sql = fix("SELECT 1, 4", rules()); assert_eq!(sql, "SELECT 1, 4"); } #[test] fn test_fail_no_whitespace_after_comma() { - let sql = fix("SELECT 1,4".into(), rules()); + let sql = fix("SELECT 1,4", rules()); assert_eq!(sql, "SELECT 1, 4"); } #[test] fn test_fail_no_whitespace_after_comma_2() { - let sql = fix("SELECT FLOOR(dt) ,count(*) FROM test".into(), rules()); + let sql = fix("SELECT FLOOR(dt) ,count(*) FROM test", rules()); assert_eq!(sql, "SELECT FLOOR(dt), count(*) FROM test"); } @@ -158,7 +157,7 @@ mod tests { // LT01-missing.yml #[test] fn test_fail_no_space_after_using_clause() { - let sql = fix("select * from a JOIN b USING(x)".into(), rules()); + let sql = fix("select * from a JOIN b USING(x)", rules()); assert_eq!(sql, "select * from a JOIN b USING (x)"); } @@ -173,25 +172,25 @@ mod tests { #[test] fn test_fail_cte_no_space_after_as() { - let sql = fix("WITH a AS(select 1) select * from a".into(), rules()); + let sql = fix("WITH a AS(select 1) select * from a", rules()); assert_eq!(sql, "WITH a AS (select 1) select * from a"); } #[test] fn test_fail_multiple_spaces_after_as() { - let sql = fix("WITH a AS (select 1) select * from a".into(), rules()); + let sql = fix("WITH a AS (select 1) select * from a", rules()); assert_eq!(sql, "WITH a AS (select 1) select * from a"); } #[test] fn test_fail_cte_newline_after_as() { - let sql = fix("WITH a AS\n(select 1)\nselect * from a".into(), rules()); + let sql = fix("WITH a AS\n(select 1)\nselect * from a", rules()); assert_eq!(sql, "WITH a AS (select 1)\nselect * from a"); } #[test] fn test_fail_cte_newline_and_spaces_after_as() { - let sql = fix("WITH a AS\n\n\n(select 1)\nselect * from a".into(), rules()); + let sql = fix("WITH a AS\n\n\n(select 1)\nselect * from a", rules()); assert_eq!(sql, "WITH a AS (select 1)\nselect * from a"); } @@ -206,8 +205,7 @@ mod tests { a AS first_column, b AS second_column, (a + b) / 2 AS third_column - FROM foo" - .into(), + FROM foo", rules(), ); assert_eq!( @@ -233,8 +231,7 @@ mod tests { b AS second_column, (a + b) / 2 AS third_column FROM foo AS bar - " - .into(), + ", rules(), ); assert_eq!( @@ -260,8 +257,7 @@ mod tests { b AS second_column, (a + b) / 2 AS third_column FROM foo - " - .into(), + ", rules(), ); assert_eq!( @@ -285,8 +281,7 @@ mod tests { a , b , (a + b) / 2 - FROM foo" - .into(), + FROM foo", rules(), ); assert_eq!( @@ -312,8 +307,7 @@ mod tests { (a + b) / 2 AS third_column FROM foo AS first_table JOIN my_tbl AS second_table USING(a) - " - .into(), + ", rules(), ); assert_eq!( @@ -338,8 +332,7 @@ mod tests { SELECT a AS first_column, (SELECT b AS c) AS second_column - " - .into(), + ", rules(), ); assert_eq!( @@ -363,7 +356,7 @@ mod tests { // configs: *align_alias #[test] fn test_align_alias_inline_fail() { - let sql = fix("SELECT a AS b , c AS d FROM tbl".into(), rules()); + let sql = fix("SELECT a AS b , c AS d FROM tbl", rules()); assert_eq!(sql, "SELECT a AS b, c AS d FROM tbl"); } @@ -379,8 +372,7 @@ mod tests { foo VARCHAR(25) NOT NULL, barbar INT NULL ) - " - .into(), + ", rules(), ); assert_eq!( @@ -404,8 +396,7 @@ mod tests { foo varchar(25) not null, barbar int not null unique ) - " - .into(), + ", rules(), ); assert_eq!( @@ -451,7 +442,7 @@ mod tests { #[test] fn test_fail_parenthesis_block_not_isolated() { - let sql = fix("SELECT * FROM(SELECT 1 AS C1)AS T1;".into(), rules()); + let sql = fix("SELECT * FROM(SELECT 1 AS C1)AS T1;", rules()); assert_eq!(sql, "SELECT * FROM (SELECT 1 AS C1) AS T1;"); } @@ -459,7 +450,7 @@ mod tests { #[test] #[ignore = "parser needs further development"] fn test_fail_parenthesis_block_not_isolated_templated() { - let sql = fix("{{ 'SELECT * FROM(SELECT 1 AS C1)AS T1;' }}".into(), rules()); + let sql = fix("{{ 'SELECT * FROM(SELECT 1 AS C1)AS T1;' }}", rules()); assert_eq!(sql, "{{ 'SELECT * FROM (SELECT 1 AS C1) AS T1;' }}"); } @@ -486,7 +477,7 @@ mod tests { #[test] fn test_basic_fix() { - let sql = fix("SELECT 1".into(), rules()); + let sql = fix("SELECT 1", rules()); assert_eq!(sql, "SELECT 1"); } @@ -494,7 +485,7 @@ mod tests { #[test] #[ignore = "parser needs further development"] fn test_basic_fail_template() { - let sql = fix("{{ 'SELECT 1' }}".into(), rules()); + let sql = fix("{{ 'SELECT 1' }}", rules()); assert_eq!(sql, "{{ 'SELECT 1' }}"); } @@ -506,8 +497,7 @@ mod tests { select 1 + 2 + 3 + 4 -- Comment from foo - " - .into(), + ", rules(), ); assert_eq!( @@ -538,13 +528,13 @@ mod tests { #[test] fn test_fail_as() { - let sql = fix("SELECT 'foo'AS bar FROM foo".into(), rules()); + let sql = fix("SELECT 'foo'AS bar FROM foo", rules()); assert_eq!(sql, "SELECT 'foo' AS bar FROM foo"); } #[test] fn test_fail_expression() { - let sql = fix("SELECT ('foo'||'bar') as buzz".into(), rules()); + let sql = fix("SELECT ('foo'||'bar') as buzz", rules()); assert_eq!(sql, "SELECT ('foo' || 'bar') as buzz"); } @@ -633,7 +623,7 @@ mod tests { #[test] fn test_fail_ansi_single_quote() { - let sql = fix("SELECT a +'b'+ 'c' FROM tbl;".into(), rules()); + let sql = fix("SELECT a +'b'+ 'c' FROM tbl;", rules()); assert_eq!(sql, "SELECT a + 'b' + 'c' FROM tbl;"); } @@ -672,8 +662,7 @@ mod tests { select field, date(field_1)-date(field_2) as diff - from table" - .into(), + from table", rules(), ); @@ -719,7 +708,7 @@ mod tests { #[test] fn fail_simple() { - let sql = fix("SELECT 1+2".into(), rules()); + let sql = fix("SELECT 1+2", rules()); assert_eq!(sql, "SELECT 1 + 2"); } @@ -742,13 +731,13 @@ mod tests { #[test] fn test_fail_trailing_whitespace() { - let sql = fix("SELECT 1 \n".into(), rules()); + let sql = fix("SELECT 1 \n", rules()); assert_eq!(sql, "SELECT 1\n"); } #[test] fn test_fail_trailing_whitespace_on_initial_blank_line() { - let sql = fix(" \nSELECT 1 \n".into(), rules()); + let sql = fix(" \nSELECT 1 \n", rules()); assert_eq!(sql, "\nSELECT 1\n"); } @@ -776,7 +765,7 @@ mod tests { #[test] #[ignore = "parser needs further development"] fn test_fail_trailing_whitespace_and_whitespace_control() { - let sql = fix("{%- set temp = 'temp' -%}\n\nSELECT\n 1, \n 2,\n".into(), rules()); + let sql = fix("{%- set temp = 'temp' -%}\n\nSELECT\n 1, \n 2,\n", rules()); assert_eq!(sql, "{%- set temp = 'temp' -%}\n\nSELECT\n 1,\n 2,\n"); } diff --git a/crates/lib/src/rules/layout/LT02.rs b/crates/lib/src/rules/layout/LT02.rs index 8edab2282..1571e466e 100644 --- a/crates/lib/src/rules/layout/LT02.rs +++ b/crates/lib/src/rules/layout/LT02.rs @@ -18,7 +18,11 @@ impl Rule for RuleLT02 { "layout.indent" } - fn long_description(&self) -> Option<&'static str> { + fn description(&self) -> &'static str { + "Incorrect Indentation." + } + + fn long_description(&self) -> &'static str { r#" **Anti-pattern** @@ -44,11 +48,6 @@ SELECT FROM foo ``` "# - .into() - } - - fn description(&self) -> &'static str { - "Incorrect Indentation." } fn eval(&self, context: RuleContext) -> Vec { @@ -85,7 +84,7 @@ mod tests { #[test] fn test_fail_reindent_first_line_2() { - let fixed = fix(" select 1 from tbl;".into(), rules()); + let fixed = fix(" select 1 from tbl;", rules()); assert_eq!(fixed, "select 1 from tbl;"); } @@ -186,7 +185,7 @@ from foo"; #[test] fn tabs_fail_default() { - let fixed = fix("SELECT\n\t\t1\n".into(), rules()); + let fixed = fix("SELECT\n\t\t1\n", rules()); assert_eq!(fixed, "SELECT\n 1\n"); } @@ -212,6 +211,6 @@ FROM spam"; let fix_str = "\nSELECT\n a,\t\t\t-- Some comment\n longer_col\t-- A lined up \ comment\nFROM spam"; - assert_eq!(fix(fail_str.into(), rules()), fix_str); + assert_eq!(fix(fail_str, rules()), fix_str); } } diff --git a/crates/lib/src/rules/layout/LT03.rs b/crates/lib/src/rules/layout/LT03.rs index 6cddfe0eb..85a4c15cd 100644 --- a/crates/lib/src/rules/layout/LT03.rs +++ b/crates/lib/src/rules/layout/LT03.rs @@ -19,7 +19,10 @@ impl Rule for RuleLT03 { "layout.operators" } - fn long_description(&self) -> Option<&'static str> { + fn description(&self) -> &'static str { + "Operators should follow a standard for being before/after newlines." + } + fn long_description(&self) -> &'static str { r#" **Anti-pattern** @@ -52,10 +55,6 @@ SELECT FROM foo ``` "# - .into() - } - fn description(&self) -> &'static str { - "Operators should follow a standard for being before/after newlines." } fn eval(&self, context: RuleContext) -> Vec { @@ -183,7 +182,7 @@ select from foo "#; - let result = fix(sql.into(), vec![RuleLT03::default().erased()]); + let result = fix(sql, vec![RuleLT03::default().erased()]); println!("{}", result); } } diff --git a/crates/lib/src/rules/layout/LT04.rs b/crates/lib/src/rules/layout/LT04.rs index ad70b0cdf..df5a11e88 100644 --- a/crates/lib/src/rules/layout/LT04.rs +++ b/crates/lib/src/rules/layout/LT04.rs @@ -23,7 +23,10 @@ impl Rule for RuleLT04 { "layout.commas" } - fn long_description(&self) -> Option<&'static str> { + fn description(&self) -> &'static str { + "Leading/Trailing comma enforcement." + } + fn long_description(&self) -> &'static str { r#" **Anti-pattern** @@ -58,10 +61,6 @@ SELECT FROM foo ``` "# - .into() - } - fn description(&self) -> &'static str { - "Leading/Trailing comma enforcement." } fn eval(&self, context: RuleContext) -> Vec { @@ -119,7 +118,7 @@ SELECT , b FROM c"; - let fix_str = fix(fail_str.into(), rules()); + let fix_str = fix(fail_str, rules()); println!("{fix_str}"); } diff --git a/crates/lib/src/rules/layout/LT05.rs b/crates/lib/src/rules/layout/LT05.rs index f2e1b36db..ca3b2f4ac 100644 --- a/crates/lib/src/rules/layout/LT05.rs +++ b/crates/lib/src/rules/layout/LT05.rs @@ -27,7 +27,11 @@ impl Rule for RuleLT05 { "layout.long_lines" } - fn long_description(&self) -> Option<&'static str> { + fn description(&self) -> &'static str { + "Line is too long." + } + + fn long_description(&self) -> &'static str { r#" **Anti-pattern** @@ -58,11 +62,6 @@ SELECT my_expression_function(col6, col7 + col8, arg4) = col9 + col10 as another_relatively_long_alias FROM my_table"# - .into() - } - - fn description(&self) -> &'static str { - "Line is too long." } fn eval(&self, context: RuleContext) -> Vec { let mut results = @@ -220,7 +219,7 @@ mod tests { let mut linter = Linter::new(cfg, None, None); linter.lint_string_wrapped( - sql.into(), + sql, None, Some(true), rules(options.ignore_comment_lines, options.ignore_comment_clauses), diff --git a/crates/lib/src/rules/layout/LT06.rs b/crates/lib/src/rules/layout/LT06.rs index ad490ae6d..2559c23f4 100644 --- a/crates/lib/src/rules/layout/LT06.rs +++ b/crates/lib/src/rules/layout/LT06.rs @@ -20,7 +20,11 @@ impl Rule for RuleLT06 { "layout.functions" } - fn long_description(&self) -> Option<&'static str> { + fn description(&self) -> &'static str { + "Function name not immediately followed by parenthesis." + } + + fn long_description(&self) -> &'static str { r#" **Anti-pattern** @@ -42,11 +46,6 @@ SELECT FROM foo ``` "# - .into() - } - - fn description(&self) -> &'static str { - "Function name not immediately followed by parenthesis." } fn eval(&self, context: RuleContext) -> Vec { let segment = FunctionalContext::new(context).segment(); diff --git a/crates/lib/src/rules/layout/LT07.rs b/crates/lib/src/rules/layout/LT07.rs index dff4398f7..e21f21bc5 100644 --- a/crates/lib/src/rules/layout/LT07.rs +++ b/crates/lib/src/rules/layout/LT07.rs @@ -19,7 +19,11 @@ impl Rule for RuleLT07 { "layout.cte_bracket" } - fn long_description(&self) -> Option<&'static str> { + fn description(&self) -> &'static str { + "'WITH' clause closing bracket should be on a new line." + } + + fn long_description(&self) -> &'static str { r#" **Anti-pattern** @@ -44,11 +48,6 @@ WITH zoo AS ( SELECT * FROM zoo ``` "# - .into() - } - - fn description(&self) -> &'static str { - "'WITH' clause closing bracket should be on a new line." } fn eval(&self, context: RuleContext) -> Vec { let segments = FunctionalContext::new(context.clone()) @@ -183,7 +182,7 @@ with cte_1 as ( select cte_1.foo from cte_1"; - let fixed = fix(sql.into(), rules()); + let fixed = fix(sql, rules()); assert_eq!( fixed, " diff --git a/crates/lib/src/rules/layout/LT08.rs b/crates/lib/src/rules/layout/LT08.rs index e81adacd5..a49ff73a9 100644 --- a/crates/lib/src/rules/layout/LT08.rs +++ b/crates/lib/src/rules/layout/LT08.rs @@ -22,7 +22,11 @@ impl Rule for RuleLT08 { "layout.cte_newline" } - fn long_description(&self) -> Option<&'static str> { + fn description(&self) -> &'static str { + "Blank line expected but not found after CTE closing bracket." + } + + fn long_description(&self) -> &'static str { r#" **Anti-pattern** @@ -47,11 +51,6 @@ WITH plop AS ( SELECT a FROM plop ``` "# - .into() - } - - fn description(&self) -> &'static str { - "Blank line expected but not found after CTE closing bracket." } fn eval(&self, context: RuleContext) -> Vec { let mut error_buffer = Vec::new(); @@ -263,7 +262,7 @@ other_cte as ( select * from my_cte cross join other_cte"; - let fixed = fix(sql.into(), rules()); + let fixed = fix(sql, rules()); assert_eq!( fixed, " @@ -292,7 +291,7 @@ other_cte as ( select * from my_cte cross join other_cte"; - let fixed = fix(sql.into(), rules()); + let fixed = fix(sql, rules()); assert_eq!( fixed, @@ -321,7 +320,7 @@ WITH mycte AS ( SELECT col FROM mycte"; - let fixed = fix(sql.into(), rules()); + let fixed = fix(sql, rules()); assert_eq!( fixed, @@ -349,7 +348,7 @@ other_cte as ( select 1 ) select * from my_cte cross join other_cte"; - let fixed = fix(sql.into(), rules()); + let fixed = fix(sql, rules()); assert_eq!( fixed, " @@ -376,7 +375,7 @@ with my_cte as ( select 1 ) select * from my_cte cross join other_cte"; - let fixed = fix(fail_str.into(), rules()); + let fixed = fix(fail_str, rules()); assert_eq!( fixed, @@ -398,7 +397,7 @@ select * from my_cte cross join other_cte" let fail_str = " with my_cte as (select 1), other_cte as (select 1) select * from my_cte cross join other_cte"; - let fixed = fix(fail_str.into(), rules()); + let fixed = fix(fail_str, rules()); println!("{fixed}"); } diff --git a/crates/lib/src/rules/layout/LT09.rs b/crates/lib/src/rules/layout/LT09.rs index 2ef57a8de..2f7fbf4cb 100644 --- a/crates/lib/src/rules/layout/LT09.rs +++ b/crates/lib/src/rules/layout/LT09.rs @@ -39,7 +39,11 @@ impl Rule for RuleLT09 { "layout.select_targets" } - fn long_description(&self) -> Option<&'static str> { + fn description(&self) -> &'static str { + "Select targets should be on a new line unless there is only one select target." + } + + fn long_description(&self) -> &'static str { r#" **Anti-pattern** @@ -84,11 +88,6 @@ SELECT FROM test_table; ``` "# - .into() - } - - fn description(&self) -> &'static str { - "Select targets should be on a new line unless there is only one select target." } #[allow(unused_variables)] fn eval(&self, context: RuleContext) -> Vec { @@ -542,8 +541,7 @@ mod tests { " select a -from x" - .into(), +from x", rules(), ); @@ -585,7 +583,7 @@ from x"; select * from x"; - let fixed = fix(fail_str.into(), rules()); + let fixed = fix(fail_str, rules()); assert_eq!( fixed, " @@ -597,14 +595,14 @@ select * #[test] fn test_multiple_select_targets_all_on_the_same_line() { let fail_str = "select a, b, c from x"; - let fixed = fix(fail_str.into(), rules()); + let fixed = fix(fail_str, rules()); assert_eq!(fixed, "select\na,\nb,\nc\nfrom x"); } #[test] fn test_multiple_select_targets_including_wildcard_all_on_the_same_line_plus_from_clause() { let fail_str = "select *, b, c from x"; - let fixed = fix(fail_str.into(), rules()); + let fixed = fix(fail_str, rules()); assert_eq!(fixed, "select\n*,\nb,\nc\nfrom x"); } @@ -615,7 +613,7 @@ select a, b, c from x"; - let fixed = fix(fail_str.into(), rules()); + let fixed = fix(fail_str, rules()); assert_eq!( fixed, " @@ -655,7 +653,7 @@ SELECT user_id FROM safe_user"; - let fixed = fix(fail_str.into(), rules()); + let fixed = fix(fail_str, rules()); assert_eq!( fixed, " @@ -686,7 +684,7 @@ f, g, h from x"; - let fixed = fix(fail_str.into(), rules()); + let fixed = fix(fail_str, rules()); assert_eq!(fixed, expected_fixed_str); } @@ -709,7 +707,7 @@ f, g, h from x"; - let fixed = fix(fail_str.into(), rules()); + let fixed = fix(fail_str, rules()); assert_eq!(fixed, expected_fixed_str); } @@ -737,7 +735,7 @@ cte1 AS ( SELECT 1 FROM cte1"; - let fixed = fix(fail_str.into(), rules()); + let fixed = fix(fail_str, rules()); assert_eq!(fixed, expected_fixed_str); } @@ -748,7 +746,7 @@ SELECT id"; let expected_fixed_str = " SELECT id"; - let fixed = fix(fail_str.into(), rules()); + let fixed = fix(fail_str, rules()); assert_eq!(fixed, expected_fixed_str); } @@ -761,7 +759,7 @@ DISTINCT id"; let expected_fixed_str = " SELECT DISTINCT id"; - let fixed = fix(fail_str.into(), rules()); + let fixed = fix(fail_str, rules()); assert_eq!(fixed, expected_fixed_str); } @@ -779,7 +777,7 @@ b, c FROM my_table"; - let fixed = fix(fail_str.into(), rules()); + let fixed = fix(fail_str, rules()); assert_eq!(fixed, expected_fixed_str); } @@ -805,7 +803,7 @@ FROM my_table"; SELECT distinct a FROM my_table"; - let fixed = fix(fail_str.into(), rules()); + let fixed = fix(fail_str, rules()); assert_eq!(fixed, expected_fixed_str); } @@ -821,7 +819,7 @@ FROM my_table"; SELECT distinct a FROM my_table"; - let fixed = fix(fail_str.into(), rules()); + let fixed = fix(fail_str, rules()); assert_eq!(fixed, expected_fixed_str); } @@ -830,7 +828,7 @@ FROM my_table"; fn test_single_select_with_no_from() { let fail_str = "SELECT\n 10000000\n"; let expected_fixed_str = "SELECT 10000000\n"; - let fixed = fix(fail_str.into(), rules()); + let fixed = fix(fail_str, rules()); assert_eq!(fixed, expected_fixed_str); } @@ -841,7 +839,7 @@ FROM my_table"; let expected_fixed_str = "SELECT 10000000 /* test */\n"; - let fixed = fix(fail_str.into(), rules()); + let fixed = fix(fail_str, rules()); assert_eq!(fixed, expected_fixed_str); } @@ -860,7 +858,7 @@ SELECT 1 FROM my_table"; - let fixed = fix(fail_str.into(), rules()); + let fixed = fix(fail_str, rules()); assert_eq!(fixed, expected_fixed_str); } @@ -879,7 +877,7 @@ SELECT 1 FROM my_table"; - let fixed = fix(fail_str.into(), rules()); + let fixed = fix(fail_str, rules()); assert_eq!(fixed, expected_fixed_str); } @@ -900,7 +898,7 @@ SELECT 1 FROM my_table"; - let fixed = fix(fail_str.into(), rules()); + let fixed = fix(fail_str, rules()); assert_eq!(fixed, expected_fixed_str); } @@ -919,7 +917,7 @@ SELECT 1 FROM my_table"; - let fixed = fix(fail_str.into(), rules()); + let fixed = fix(fail_str, rules()); assert_eq!(fixed, expected_fixed_str); } @@ -941,7 +939,7 @@ SELECT c FROM table1 INNER JOIN table2 ON (table1.id = table2.id);"; - let fixed = fix(fail_str.into(), rules()); + let fixed = fix(fail_str, rules()); assert_eq!(fixed, expected_fixed_str); } diff --git a/crates/lib/src/rules/layout/LT10.rs b/crates/lib/src/rules/layout/LT10.rs index fcc0bb77c..a006e6520 100644 --- a/crates/lib/src/rules/layout/LT10.rs +++ b/crates/lib/src/rules/layout/LT10.rs @@ -22,7 +22,11 @@ impl Rule for RuleLT10 { "layout.select_modifiers" } - fn long_description(&self) -> Option<&'static str> { + fn description(&self) -> &'static str { + "'SELECT' modifiers (e.g. 'DISTINCT') must be on the same line as 'SELECT'." + } + + fn long_description(&self) -> &'static str { r#" **Anti-pattern** @@ -46,11 +50,6 @@ select distinct from x ``` "# - .into() - } - - fn description(&self) -> &'static str { - "'SELECT' modifiers (e.g. 'DISTINCT') must be on the same line as 'SELECT'." } fn eval(&self, context: RuleContext) -> Vec { // Get children of select_clause and the corresponding select keyword. @@ -169,7 +168,7 @@ SELECT FROM safe_user"; - let fix_str = fix(fail_str.into(), rules()); + let fix_str = fix(fail_str, rules()); assert_eq!( fix_str, " @@ -190,7 +189,7 @@ SELECT FROM safe_user"; - let fix_str = fix(fail_str.into(), rules()); + let fix_str = fix(fail_str, rules()); assert_eq!( fix_str, " @@ -211,7 +210,7 @@ distinct def from a;"; - let fix_str = fix(fail_str.into(), rules()); + let fix_str = fix(fail_str, rules()); println!("{}", &fix_str); } } diff --git a/crates/lib/src/rules/layout/LT11.rs b/crates/lib/src/rules/layout/LT11.rs index 8e8077f2a..3d2038dcb 100644 --- a/crates/lib/src/rules/layout/LT11.rs +++ b/crates/lib/src/rules/layout/LT11.rs @@ -18,7 +18,11 @@ impl Rule for RuleLT11 { "layout.set_operators" } - fn long_description(&self) -> Option<&'static str> { + fn description(&self) -> &'static str { + "Set operators should be surrounded by newlines." + } + + fn long_description(&self) -> &'static str { r#" **Anti-pattern** @@ -39,11 +43,6 @@ UNION ALL SELECT 'b' AS col ``` "# - .into() - } - - fn description(&self) -> &'static str { - "Set operators should be surrounded by newlines." } fn eval(&self, context: RuleContext) -> Vec { ReflowSequence::from_around_target( @@ -79,7 +78,7 @@ mod tests { fn test_fail_simple_fix_union_all_before() { let sql = "SELECT 'a' UNION ALL\nSELECT 'b'"; - let result = fix(sql.into(), rules()); + let result = fix(sql, rules()); assert_eq!(result, "SELECT 'a'\nUNION ALL\nSELECT 'b'"); } } diff --git a/crates/lib/src/rules/layout/LT12.rs b/crates/lib/src/rules/layout/LT12.rs index 90e3babd6..d0307efd9 100644 --- a/crates/lib/src/rules/layout/LT12.rs +++ b/crates/lib/src/rules/layout/LT12.rs @@ -53,7 +53,10 @@ impl Rule for RuleLT12 { "layout.end_of_file" } - fn long_description(&self) -> Option<&'static str> { + fn description(&self) -> &'static str { + "Files must end with a single trailing newline." + } + fn long_description(&self) -> &'static str { r#" **Anti-pattern** @@ -119,10 +122,6 @@ Add trailing newline to the end. The $ character represents end of file. $ ``` "# - .into() - } - fn description(&self) -> &'static str { - "Files must end with a single trailing newline." } fn eval(&self, context: RuleContext) -> Vec { @@ -193,13 +192,13 @@ mod tests { #[test] fn test_fail_no_final_newline() { - let fixed = fix("SELECT foo FROM bar".into(), rules()); + let fixed = fix("SELECT foo FROM bar", rules()); assert_eq!(fixed, "SELECT foo FROM bar\n"); } #[test] fn test_fail_multiple_final_newlines() { - let fixed = fix("SELECT foo FROM bar\n\n".into(), rules()); + let fixed = fix("SELECT foo FROM bar\n\n", rules()); assert_eq!(fixed, "SELECT foo FROM bar\n"); } @@ -211,13 +210,13 @@ mod tests { #[test] fn test_fail_templated_plus_raw_newlines() { - let fixed = fix("{{ '\n\n' }}".into(), rules()); + let fixed = fix("{{ '\n\n' }}", rules()); assert_eq!(fixed, "{{ '\n\n' }}\n"); } #[test] fn test_fail_templated_plus_raw_newlines_extra_newline() { - let fixed = fix("{{ '\n\n' }}\n\n".into(), rules()); + let fixed = fix("{{ '\n\n' }}\n\n", rules()); assert_eq!(fixed, "{{ '\n\n' }}\n"); } @@ -232,7 +231,7 @@ mod tests { #[test] fn test_fail_templated_no_newline() { - let fixed = fix("{% if true %}\nSELECT 1 + 1\n{%- endif %}".into(), rules()); + let fixed = fix("{% if true %}\nSELECT 1 + 1\n{%- endif %}", rules()); assert_eq!(fixed, "{% if true %}\nSELECT 1 + 1\n{%- endif %}\n"); } } diff --git a/crates/lib/src/rules/layout/LT13.rs b/crates/lib/src/rules/layout/LT13.rs index 5cab57f17..5926aa91d 100644 --- a/crates/lib/src/rules/layout/LT13.rs +++ b/crates/lib/src/rules/layout/LT13.rs @@ -24,7 +24,11 @@ impl Rule for RuleLT13 { "layout.start_of_file" } - fn long_description(&self) -> Option<&'static str> { + fn description(&self) -> &'static str { + "Files must not begin with newlines or whitespace." + } + + fn long_description(&self) -> &'static str { r#" **Anti-pattern** @@ -74,11 +78,6 @@ Start file on either code or comment. (The ^ represents the beginning of the fil foo ``` "# - .into() - } - - fn description(&self) -> &'static str { - "Files must not begin with newlines or whitespace." } fn eval(&self, context: RuleContext) -> Vec { @@ -210,39 +209,38 @@ mod tests { #[test] fn test_fail_leading_whitespace_statement() { - let fixed = fix("\n SELECT foo FROM bar\n".into(), rules()); + let fixed = fix("\n SELECT foo FROM bar\n", rules()); assert_eq!(fixed, "SELECT foo FROM bar\n"); } #[test] fn test_fail_leading_whitespace_comment() { - let fixed = fix("\n /*I am a comment*/\nSELECT foo FROM bar\n".into(), rules()); + let fixed = fix("\n /*I am a comment*/\nSELECT foo FROM bar\n", rules()); assert_eq!(fixed, "/*I am a comment*/\nSELECT foo FROM bar\n"); } #[test] fn test_fail_leading_whitespace_inline_comment() { - let fixed = fix("\n --I am a comment\nSELECT foo FROM bar\n".into(), rules()); + let fixed = fix("\n --I am a comment\nSELECT foo FROM bar\n", rules()); assert_eq!(fixed, "--I am a comment\nSELECT foo FROM bar\n"); } #[test] fn test_fail_leading_whitespace_jinja_comment() { - let fixed = fix("\n {# I am a comment #}\nSELECT foo FROM bar\n".into(), rules()); + let fixed = fix("\n {# I am a comment #}\nSELECT foo FROM bar\n", rules()); assert_eq!(fixed, "{# I am a comment #}\nSELECT foo FROM bar\n"); } #[test] fn test_fail_leading_whitespace_jinja_if() { - let fixed = fix("\n {% if True %}\nSELECT foo\nFROM bar;\n{% endif %}\n".into(), rules()); + let fixed = fix("\n {% if True %}\nSELECT foo\nFROM bar;\n{% endif %}\n", rules()); assert_eq!(fixed, "{% if True %}\nSELECT foo\nFROM bar;\n{% endif %}\n"); } #[test] fn test_fail_leading_whitespace_jinja_for() { let fixed = fix( - "\n {% for item in range(10) %}\nSELECT foo_{{ item }}\nFROM bar;\n{% endfor %}\n" - .into(), + "\n {% for item in range(10) %}\nSELECT foo_{{ item }}\nFROM bar;\n{% endfor %}\n", rules(), ); assert_eq!( diff --git a/crates/lib/src/rules/references/RF01.rs b/crates/lib/src/rules/references/RF01.rs index c07543292..fcc163fb2 100644 --- a/crates/lib/src/rules/references/RF01.rs +++ b/crates/lib/src/rules/references/RF01.rs @@ -181,7 +181,7 @@ impl Rule for RuleRF01 { "References cannot reference objects not present in 'FROM' clause." } - fn long_description(&self) -> Option<&'static str> { + fn long_description(&self) -> &'static str { r#" **Anti-pattern** @@ -203,7 +203,6 @@ SELECT FROM foo ``` "# - .into() } fn eval(&self, context: RuleContext) -> Vec { diff --git a/crates/lib/src/rules/references/RF03.rs b/crates/lib/src/rules/references/RF03.rs index 8ad202f3d..2433ab72d 100644 --- a/crates/lib/src/rules/references/RF03.rs +++ b/crates/lib/src/rules/references/RF03.rs @@ -285,7 +285,7 @@ impl Rule for RuleRF03 { "References should be consistent in statements with a single table." } - fn long_description(&self) -> Option<&'static str> { + fn long_description(&self) -> &'static str { r#" **Anti-pattern** @@ -316,7 +316,6 @@ SELECT FROM foo ``` "# - .into() } fn eval(&self, context: RuleContext) -> Vec { @@ -368,7 +367,7 @@ mod tests { let fail_str = "SELECT my_tbl.bar, baz FROM my_tbl"; let fix_str = "SELECT my_tbl.bar, my_tbl.baz FROM my_tbl"; - let actual = fix(fail_str.into(), rules()); + let actual = fix(fail_str, rules()); assert_eq!(actual, fix_str); } @@ -408,7 +407,7 @@ mod tests { let fail_str = "SELECT * FROM (SELECT my_tbl.bar, baz FROM my_tbl)"; let fix_str = "SELECT * FROM (SELECT my_tbl.bar, my_tbl.baz FROM my_tbl)"; - let actual = fix(fail_str.into(), rules()); + let actual = fix(fail_str, rules()); assert_eq!(actual, fix_str); } @@ -461,7 +460,7 @@ mod tests { let fail_str = "SELECT my_tbl.bar FROM my_tbl"; let fix_str = "SELECT bar FROM my_tbl"; - let actual = fix(fail_str.into(), rules_unqualified()); + let actual = fix(fail_str, rules_unqualified()); assert_eq!(actual, fix_str); } @@ -470,7 +469,7 @@ mod tests { let fail_str = "SELECT bar FROM my_tbl WHERE foo"; let fix_str = "SELECT my_tbl.bar FROM my_tbl WHERE my_tbl.foo"; - let actual = fix(fail_str.into(), rules_qualified()); + let actual = fix(fail_str, rules_qualified()); assert_eq!(actual, fix_str); } @@ -487,7 +486,7 @@ mod tests { let fail_str = "SELECT a.bar, b FROM my_tbl"; let fix_str = "SELECT a.bar, my_tbl.b FROM my_tbl"; - let actual = fix(fail_str.into(), rules()); + let actual = fix(fail_str, rules()); assert_eq!(actual, fix_str); } @@ -507,7 +506,7 @@ mod tests { "select t.col0, t.col1 + 1 as alias_col1 from table1 as t where alias_col1 > 5"; let fix_str = "select col0, col1 + 1 as alias_col1 from table1 as t where alias_col1 > 5"; - let actual = fix(fail_str.into(), rules_unqualified()); + let actual = fix(fail_str, rules_unqualified()); assert_eq!(actual, fix_str); } diff --git a/crates/lib/src/rules/structure/ST01.rs b/crates/lib/src/rules/structure/ST01.rs index b53b8723b..37786e1ee 100644 --- a/crates/lib/src/rules/structure/ST01.rs +++ b/crates/lib/src/rules/structure/ST01.rs @@ -23,7 +23,7 @@ impl Rule for RuleST01 { "Do not specify 'else null' in a case when statement (redundant)." } - fn long_description(&self) -> Option<&'static str> { + fn long_description(&self) -> &'static str { r#" **Anti-pattern** @@ -45,7 +45,6 @@ SELECT FROM foo ``` "# - .into() } fn eval(&self, context: RuleContext) -> Vec { @@ -109,7 +108,7 @@ mod tests { end from x"; - let fixed = fix(fail_str.into(), rules()); + let fixed = fix(fail_str, rules()); assert_eq!(fix_str, fixed); } @@ -132,7 +131,7 @@ mod tests { end from x"; - let fixed = fix(fail_str.into(), rules()); + let fixed = fix(fail_str, rules()); assert_eq!(fix_str, fixed); } @@ -147,7 +146,7 @@ mod tests { end from x"; - let fixed = fix(pass_str.into(), rules()); + let fixed = fix(pass_str, rules()); assert_eq!(pass_str, fixed); } @@ -162,7 +161,7 @@ mod tests { end from x"; - let fixed = fix(pass_str.into(), rules()); + let fixed = fix(pass_str, rules()); assert_eq!(pass_str, fixed); } } diff --git a/crates/lib/src/rules/structure/ST02.rs b/crates/lib/src/rules/structure/ST02.rs index 3382fcd25..503d998eb 100644 --- a/crates/lib/src/rules/structure/ST02.rs +++ b/crates/lib/src/rules/structure/ST02.rs @@ -29,7 +29,7 @@ impl Rule for RuleST02 { "Unnecessary 'CASE' statement." } - fn long_description(&self) -> Option<&'static str> { + fn long_description(&self) -> &'static str { r#" **Anti-pattern** @@ -85,7 +85,6 @@ select fab as fab_clean from fancy_table ``` "# - .into() } fn eval(&self, context: RuleContext) -> Vec { @@ -514,7 +513,7 @@ select coalesce(fab > 0, false) as is_fab from fancy_table"; - let fixed = fix(fail_str.into(), rules()); + let fixed = fix(fail_str, rules()); assert_eq!(fix_str, fixed); } @@ -531,7 +530,7 @@ select not coalesce(fab > 0, false) as is_fab from fancy_table"; - let fixed = fix(fail_str.into(), rules()); + let fixed = fix(fail_str, rules()); assert_eq!(fix_str, fixed); } @@ -548,7 +547,7 @@ select coalesce(fab > 0 and tot > 0, false) as is_fab from fancy_table"; - let fixed = fix(fail_str.into(), rules()); + let fixed = fix(fail_str, rules()); assert_eq!(fix_str, fixed); } @@ -565,7 +564,7 @@ select not coalesce(fab > 0 and tot > 0, false) as is_fab from fancy_table"; - let fixed = fix(fail_str.into(), rules()); + let fixed = fix(fail_str, rules()); assert_eq!(fix_str, fixed); } @@ -582,7 +581,7 @@ select not coalesce(not fab > 0 or tot > 0, false) as is_fab from fancy_table"; - let fixed = fix(fail_str.into(), rules()); + let fixed = fix(fail_str, rules()); assert_eq!(fix_str, fixed); } @@ -611,7 +610,7 @@ select from subscriptions_xf"; - let fixed = fix(fail_str.into(), rules()); + let fixed = fix(fail_str, rules()); assert_eq!(fix_str, fixed); } @@ -633,7 +632,7 @@ select coalesce(bar, '123') as test from baz;"; - let fixed = fix(fail_str.into(), rules()); + let fixed = fix(fail_str, rules()); assert_eq!(fix_str, fixed); } @@ -657,7 +656,7 @@ from baz;"; from baz; "#; - let fixed = fix(fail_str.into(), rules()); + let fixed = fix(fail_str, rules()); assert_eq!(fix_str.trim(), fixed.trim()); } @@ -679,7 +678,7 @@ select bar as test from baz;"#; - let fixed = fix(fail_str.into(), rules()); + let fixed = fix(fail_str, rules()); assert_eq!(fix_str, fixed); } @@ -703,7 +702,7 @@ from baz;"#; from baz; "#; - let fixed = fix(fail_str.into(), rules()); + let fixed = fix(fail_str, rules()); assert_eq!(fix_str, fixed); } @@ -726,7 +725,7 @@ from baz;"#; from baz; "#; - let fixed = fix(fail_str.into(), rules()); + let fixed = fix(fail_str, rules()); assert_eq!(fix_str, fixed); } diff --git a/crates/lib/src/rules/structure/ST03.rs b/crates/lib/src/rules/structure/ST03.rs index 34ff48eea..628269515 100644 --- a/crates/lib/src/rules/structure/ST03.rs +++ b/crates/lib/src/rules/structure/ST03.rs @@ -25,7 +25,7 @@ impl Rule for RuleST03 { "Query defines a CTE (common-table expression) but does not use it." } - fn long_description(&self) -> Option<&'static str> { + fn long_description(&self) -> &'static str { r#" **Anti-pattern** @@ -59,7 +59,6 @@ SELECT * FROM cte1 ``` "# - .into() } fn eval(&self, context: RuleContext) -> Vec { diff --git a/crates/lib/src/rules/structure/ST08.rs b/crates/lib/src/rules/structure/ST08.rs index 6c8dd9c87..46df3bce6 100644 --- a/crates/lib/src/rules/structure/ST08.rs +++ b/crates/lib/src/rules/structure/ST08.rs @@ -41,23 +41,19 @@ impl RuleST08 { } impl Rule for RuleST08 { - fn name(&self) -> &'static str { - "structure.distinct" - } - fn load_from_config(&self, _config: &AHashMap) -> ErasedRule { RuleST08.erased() } - fn crawl_behaviour(&self) -> Crawler { - SegmentSeekerCrawler::new(["select_clause", "function"].into()).into() + fn name(&self) -> &'static str { + "structure.distinct" } fn description(&self) -> &'static str { "Looking for DISTINCT before a bracket" } - fn long_description(&self) -> Option<&'static str> { + fn long_description(&self) -> &'static str { r#" **Anti-pattern** @@ -75,7 +71,6 @@ Remove parentheses to be clear that the DISTINCT applies to both columns. SELECT DISTINCT a, b FROM foo ``` "# - .into() } fn eval(&self, context: RuleContext) -> Vec { @@ -166,6 +161,10 @@ SELECT DISTINCT a, b FROM foo Vec::new() } + + fn crawl_behaviour(&self) -> Crawler { + SegmentSeekerCrawler::new(["select_clause", "function"].into()).into() + } } #[cfg(test)] @@ -176,7 +175,7 @@ mod tests { use crate::api::simple::{fix, lint}; fn rules() -> Vec { - vec![RuleST08::default().erased()] + vec![RuleST08.erased()] } #[test] @@ -184,7 +183,7 @@ mod tests { let fail_str = "SELECT DISTINCT(a)"; let fix_str = "SELECT DISTINCT a"; - let fixed = fix(fail_str.into(), rules()); + let fixed = fix(fail_str, rules()); assert_eq!(fix_str, fixed); } @@ -193,7 +192,7 @@ mod tests { let fail_str = "SELECT DISTINCT(a + b) * c"; let fix_str = "SELECT DISTINCT (a + b) * c"; - let fixed = fix(fail_str.into(), rules()); + let fixed = fix(fail_str, rules()); assert_eq!(fix_str, fixed); } @@ -202,7 +201,7 @@ mod tests { let fail_str = "SELECT DISTINCT (a)"; let fix_str = "SELECT DISTINCT a"; - let fixed = fix(fail_str.into(), rules()); + let fixed = fix(fail_str, rules()); assert_eq!(fix_str, fixed); } @@ -218,7 +217,7 @@ mod tests { let fail_str = r#"SELECT DISTINCT(field_1) FROM my_table"#; let fix_str = "SELECT DISTINCT field_1 FROM my_table"; - let fixed = fix(fail_str.into(), rules()); + let fixed = fix(fail_str, rules()); assert_eq!(fix_str, fixed); } @@ -227,7 +226,7 @@ mod tests { let fail_str = "SELECT DISTINCT(a), b"; let fix_str = "SELECT DISTINCT a, b"; - let fixed = fix(fail_str.into(), rules()); + let fixed = fix(fail_str, rules()); assert_eq!(fix_str, fixed); } @@ -243,7 +242,7 @@ mod tests { let fail_str = "SELECT COUNT(DISTINCT(unique_key))"; let fix_str = "SELECT COUNT(DISTINCT unique_key)"; - let fixed = fix(fail_str.into(), rules()); + let fixed = fix(fail_str, rules()); assert_eq!(fix_str, fixed); } @@ -252,7 +251,7 @@ mod tests { let fail_str = "SELECT COUNT(DISTINCT(CONCAT(col1, '-', col2, '-', col3)))"; let fix_str = "SELECT COUNT(DISTINCT CONCAT(col1, '-', col2, '-', col3))"; - let fixed = fix(fail_str.into(), rules()); + let fixed = fix(fail_str, rules()); assert_eq!(fix_str, fixed); } } diff --git a/docs/rules.md b/docs/rules.md index 9b4ae014c..1f6c02ae7 100644 --- a/docs/rules.md +++ b/docs/rules.md @@ -365,6 +365,26 @@ Find self-aliased columns and fix them **Fixable:** No +**Anti-pattern** + +Aliasing the column to itself. + +```sql +SELECT + col AS col +FROM table; +``` + +**Best practice** + +Not to use alias to rename the column to its original name. Self-aliasing leads to redundant code without changing any functionality. + +```sql +SELECT + col +FROM table; +``` + ### ambiguous.distinct