Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions crates/squawk_linter/src/rules/ban_drop_column.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ use crate::{Linter, Rule, Violation};
pub(crate) fn ban_drop_column(ctx: &mut Linter, parse: &Parse<SourceFile>) {
let file = parse.tree();
for stmt in file.stmts() {
let actions: Vec<_> = match stmt {
ast::Stmt::AlterTable(table) => table.actions().collect(),
ast::Stmt::AlterForeignTable(table) => table.actions().collect(),
let actions = match stmt {
ast::Stmt::AlterTable(table) => table.actions(),
ast::Stmt::AlterForeignTable(table) => table.actions(),
ast::Stmt::AlterType(ty) => {
if let Some(ast::AlterTypeAction::AlterTypeAttributeActionList(list)) = ty.action()
{
Expand All @@ -24,9 +24,9 @@ pub(crate) fn ban_drop_column(ctx: &mut Linter, parse: &Parse<SourceFile>) {
}
}
}
Vec::new()
continue;
}
_ => Vec::new(),
_ => continue,
};
for action in actions {
if let ast::AlterTableAction::DropColumn(drop_column) = action {
Expand Down
10 changes: 5 additions & 5 deletions crates/squawk_linter/src/rules/ban_drop_constraint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ use squawk_syntax::{

pub(crate) fn ban_drop_constraint(ctx: &mut Linter, parse: &Parse<SourceFile>) {
for stmt in parse.tree().stmts() {
let actions: Vec<_> = match &stmt {
ast::Stmt::AlterTable(table) => table.actions().collect(),
ast::Stmt::AlterForeignTable(table) => table.actions().collect(),
_ => Vec::new(),
let actions = match &stmt {
ast::Stmt::AlterTable(table) => Some(table.actions()),
ast::Stmt::AlterForeignTable(table) => Some(table.actions()),
_ => None,
};
for action in actions {
for action in actions.into_iter().flatten() {
match action {
ast::AlterTableAction::DropConstraint(node) => ctx.report(Violation::for_node(
Rule::BanDropConstraint,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -167,11 +167,10 @@ fn check_set_clause(ctx: &mut Linter, set_clause: &ast::SetClause) {
let Some(set_column_list) = set_clause.set_column_list() else {
return;
};
let set_columns = set_column_list.set_columns().collect::<Vec<_>>();
let mut assigned_columns: FxHashMap<Name, Vec<Assignment>> = FxHashMap::default();

for set_column in &set_columns {
match set_column {
for set_column in set_column_list.set_columns() {
match &set_column {
ast::SetColumn::SetMultipleColumns(set_multiple_columns) => {
let Some(column_target_list) = set_multiple_columns.column_target_list() else {
continue;
Expand All @@ -192,7 +191,7 @@ fn check_set_clause(ctx: &mut Linter, set_clause: &ast::SetClause) {
if assignments.len() < 2 || assignments.iter().all(|assignment| assignment.is_partial) {
continue;
}
let mut fix = create_fix(&name, &assignments, &set_columns);
let mut fix = create_fix(&name, &assignments, &set_column_list);
let last_index = assignments.len() - 1;

for (index, assignment) in assignments.iter().enumerate() {
Expand Down Expand Up @@ -232,18 +231,17 @@ fn add_assignment(
fn create_fix(
name: &Name,
assignments: &[Assignment],
set_columns: &[ast::SetColumn],
set_column_list: &ast::SetColumnList,
) -> Option<Fix> {
let mut edits = Vec::with_capacity(assignments.len() - 1);

for assignment in &assignments[..assignments.len() - 1] {
if !matches!(assignment.set_column, ast::SetColumn::SetSingleColumn(_)) {
return None;
}
let index = set_columns
.iter()
.position(|set_column| set_column.syntax() == assignment.set_column.syntax())?;
let next_set_column = set_columns.get(index + 1)?;
let mut set_columns = set_column_list.set_columns();
set_columns.find(|set_column| set_column.syntax() == assignment.set_column.syntax())?;
let next_set_column = set_columns.next()?;
let next_start = next_set_column.syntax().text_range().start();
let mut end = next_start;
let mut seen_comma = false;
Expand Down
10 changes: 5 additions & 5 deletions crates/squawk_linter/src/rules/changing_column_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ use crate::{Linter, Rule, Violation};
pub(crate) fn changing_column_type(ctx: &mut Linter, parse: &Parse<SourceFile>) {
let file = parse.tree();
for stmt in file.stmts() {
let actions: Vec<_> = match stmt {
ast::Stmt::AlterTable(table) => table.actions().collect(),
ast::Stmt::AlterForeignTable(table) => table.actions().collect(),
let actions = match stmt {
ast::Stmt::AlterTable(table) => table.actions(),
ast::Stmt::AlterForeignTable(table) => table.actions(),
ast::Stmt::AlterType(ty) => {
if let Some(ast::AlterTypeAction::AlterTypeAttributeActionList(list)) = ty.action()
{
Expand All @@ -24,9 +24,9 @@ pub(crate) fn changing_column_type(ctx: &mut Linter, parse: &Parse<SourceFile>)
}
}
}
Vec::new()
continue;
}
_ => Vec::new(),
_ => continue,
};
for action in actions {
if let ast::AlterTableAction::AlterColumn(alter_column) = action {
Expand Down
27 changes: 18 additions & 9 deletions crates/squawk_linter/src/rules/prefer_robust_stmts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,18 +22,28 @@ fn is_alembic_version_update(stmt: &ast::Stmt) -> bool {
.is_some_and(|name| name.text().eq_ignore_ascii_case("alembic_version")))
}

fn alembic_version_commit_tx_indices(stmts: &[ast::Stmt]) -> Option<FxHashSet<usize>> {
fn alembic_version_commit_tx_indices(
stmts: impl Iterator<Item = ast::Stmt>,
) -> Option<FxHashSet<usize>> {
let mut indices = FxHashSet::default();
let mut tx_start = None;
for (i, stmt) in stmts.iter().enumerate() {
match stmt {
ast::Stmt::Begin(_) => tx_start = Some(i),
let mut has_alembic_version_update = false;
for (i, stmt) in stmts.enumerate() {
match &stmt {
ast::Stmt::Begin(_) => {
tx_start = Some(i);
has_alembic_version_update = false;
}
ast::Stmt::Commit(_) | ast::Stmt::Rollback(_) => {
if let Some(start) = tx_start.take()
&& stmts[start..=i].iter().any(is_alembic_version_update)
&& has_alembic_version_update
{
indices.extend(start..=i);
}
has_alembic_version_update = false;
}
_ if tx_start.is_some() && is_alembic_version_update(&stmt) => {
has_alembic_version_update = true;
}
_ => {}
}
Expand All @@ -43,25 +53,24 @@ fn alembic_version_commit_tx_indices(stmts: &[ast::Stmt]) -> Option<FxHashSet<us

pub(crate) fn prefer_robust_stmts(ctx: &mut Linter, parse: &Parse<SourceFile>) {
let file = parse.tree();
let stmts: Vec<ast::Stmt> = file.stmts().collect();
let mut inside_transaction = ctx.settings.assume_in_transaction;
let mut constraint_names: FxHashMap<String, Constraint> = FxHashMap::default();

let version_tx_indices = alembic_version_commit_tx_indices(&stmts);
let version_tx_indices = alembic_version_commit_tx_indices(file.stmts());

enum ActionErrorMessage {
IfExists,
IfNotExists,
None,
}

for (i, stmt) in stmts.iter().enumerate() {
for (i, stmt) in file.stmts().enumerate() {
let in_robust_tx = match &version_tx_indices {
Some(set) => ctx.settings.assume_in_transaction || set.contains(&i),
None => inside_transaction,
};

match stmt {
match &stmt {
ast::Stmt::Begin(_) => {
inside_transaction = true;
}
Expand Down
34 changes: 14 additions & 20 deletions crates/squawk_linter/src/rules/require_timeout_settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,18 +62,17 @@ impl LockImpact {
Self(blocks)
}

fn blocked(self) -> Vec<&'static str> {
let mut items = vec![];
for (bit, label) in [
(Self::READS, "reads"),
(Self::WRITES, "writes"),
(Self::SCHEMA_CHANGES, "schema changes"),
] {
if self.0 & bit != 0 {
items.push(label);
}
fn blocked(self) -> &'static str {
match self.0 {
0b001 => "reads",
0b010 => "writes",
0b011 => "reads, writes",
0b100 => "schema changes",
0b101 => "reads, schema changes",
0b110 => "writes, schema changes",
0b111 => "reads, writes, schema changes",
_ => "",
}
items
}
}

Expand Down Expand Up @@ -274,11 +273,10 @@ impl LockKind {
}

fn violation_message(self) -> String {
let name = self.to_string();
if name.is_empty() {
if self == LockKind::Unknown {
"Missing `set lock_timeout` before potentially slow operations".to_string()
} else {
format!("Missing `set lock_timeout` before potentially slow {name} lock operations")
format!("Missing `set lock_timeout` before potentially slow {self} lock operations")
}
}

Expand All @@ -300,19 +298,15 @@ impl LockKind {

fn help(self) -> String {
let help = "Configure a `lock_timeout` before this statement.";
let name = self.to_string();
let Some(impact) = self.impact() else {
return help.to_string();
};

let blocked = impact.blocked();
if blocked.is_empty() {
format!("{help} Statement requires: {name} lock.")
format!("{help} Statement requires: {self} lock.")
} else {
format!(
"{help} Statement requires: {name} lock; blocking: {}.",
blocked.join(", ")
)
format!("{help} Statement requires: {self} lock; blocking: {blocked}.")
}
}
}
Expand Down
Loading