Skip to content

Commit cc5ee48

Browse files
authored
cli: fix parsing of rule name aliases i.e., prefer-timestamptz (#668)
#667
1 parent 85d2874 commit cc5ee48

File tree

4 files changed

+93
-2
lines changed

4 files changed

+93
-2
lines changed

PLAN.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,18 @@ parse and warn, helps with copy pasting examples
5151

5252
support Trino, BigQuery, Aurora DSLQ, etc.
5353

54+
### Check `format()` calls
55+
56+
https://www.postgresql.org/docs/18/functions-string.html#FUNCTIONS-STRING-FORMAT
57+
58+
```sql
59+
SELECT format('Hello %s', 'World');
60+
-- ok
61+
62+
SELECT format('Hello %s %s', 'World');
63+
-- error ^^
64+
```
65+
5466
### Formatter
5567

5668
```shell
@@ -387,6 +399,24 @@ select count(*) from t where t.name in ('1 month', '2 month')
387399
-- type checks!
388400
```
389401

402+
### Rule: no-unncesssary-parens
403+
404+
```sql
405+
select (((x * 2)));
406+
-- becomes
407+
select x * 2;
408+
```
409+
410+
```sql
411+
-- ok, indexes on expressions require extra parens
412+
create index foo on t((1));
413+
414+
-- ok
415+
select (x * 2) + 4;
416+
```
417+
418+
related: https://eslint.style/rules/no-extra-parens
419+
390420
### Rule: dialect: now() to dest
391421

392422
should support various fixes so people can write in one dialect of SQL and have it easily convert to the other one

crates/squawk/src/config.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,4 +137,14 @@ fail_on_violations = true
137137
fs::write(&squawk_toml, file).expect("Unable to write file");
138138
assert_debug_snapshot!(Config::parse(Some(squawk_toml.path().to_path_buf())));
139139
}
140+
#[test]
141+
fn load_excluded_rules_with_alias() {
142+
let squawk_toml = NamedTempFile::new().expect("generate tempFile");
143+
let file = r#"
144+
excluded_rules = ["prefer-timestamp-tz", "prefer-timestamptz"]
145+
146+
"#;
147+
fs::write(&squawk_toml, file).expect("Unable to write file");
148+
assert_debug_snapshot!(Config::parse(Some(squawk_toml.path().to_path_buf())));
149+
}
140150
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
---
2+
source: crates/squawk/src/config.rs
3+
expression: "Config::parse(Some(squawk_toml.path().to_path_buf()))"
4+
---
5+
Ok(
6+
Some(
7+
Config {
8+
excluded_paths: [],
9+
excluded_rules: [
10+
PreferTimestampTz,
11+
PreferTimestampTz,
12+
],
13+
pg_version: None,
14+
assume_in_transaction: None,
15+
upload_to_github: UploadToGitHubConfig {
16+
fail_on_violations: None,
17+
},
18+
},
19+
),
20+
)

crates/squawk_linter/src/lib.rs

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ use rules::require_concurrent_index_deletion;
5454
use rules::transaction_nesting;
5555
// xtask:new-rule:rule-import
5656

57-
#[derive(Debug, PartialEq, Clone, Copy, Serialize, Hash, Eq, Deserialize, Sequence)]
57+
#[derive(Debug, PartialEq, Clone, Copy, Serialize, Hash, Eq, Sequence)]
5858
pub enum Rule {
5959
#[serde(rename = "require-concurrent-index-creation")]
6060
RequireConcurrentIndexCreation,
@@ -176,7 +176,7 @@ impl std::error::Error for UnknownRuleName {}
176176
impl std::str::FromStr for Rule {
177177
type Err = UnknownRuleName;
178178
fn from_str(s: &str) -> Result<Self, Self::Err> {
179-
serde_plain::from_str(s).map_err(|_| UnknownRuleName { val: s.to_string() })
179+
Rule::try_from(s).map_err(|_| UnknownRuleName { val: s.to_string() })
180180
}
181181
}
182182

@@ -220,6 +220,16 @@ impl fmt::Display for Rule {
220220
}
221221
}
222222

223+
impl<'de> Deserialize<'de> for Rule {
224+
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
225+
where
226+
D: serde::Deserializer<'de>,
227+
{
228+
let s = String::deserialize(deserializer)?;
229+
s.parse().map_err(serde::de::Error::custom)
230+
}
231+
}
232+
223233
#[derive(Debug, Clone, PartialEq, Eq)]
224234
pub struct Fix {
225235
pub title: String,
@@ -470,3 +480,24 @@ impl Linter {
470480
}
471481
}
472482
}
483+
484+
#[cfg(test)]
485+
mod tests {
486+
use insta::assert_debug_snapshot;
487+
488+
use super::*;
489+
490+
#[test]
491+
fn prefer_timestamp_aliases() {
492+
let rule1: Rule = "prefer-timestamp-tz".parse().unwrap();
493+
let rule2: Rule = "prefer-timestamptz".parse().unwrap();
494+
assert_eq!(rule1, rule2);
495+
assert_debug_snapshot!(rule1, @"PreferTimestampTz");
496+
}
497+
498+
#[test]
499+
fn invalid_rule_name() {
500+
let result: Result<Rule, _> = "invalid-rule-name".parse();
501+
assert!(result.is_err());
502+
}
503+
}

0 commit comments

Comments
 (0)