diff --git a/crates/squawk_linter/src/rules/prefer_robust_stmts.rs b/crates/squawk_linter/src/rules/prefer_robust_stmts.rs index 9c049f18..f1a1db99 100644 --- a/crates/squawk_linter/src/rules/prefer_robust_stmts.rs +++ b/crates/squawk_linter/src/rules/prefer_robust_stmts.rs @@ -157,6 +157,17 @@ pub(crate) fn prefer_robust_stmts(ctx: &mut Linter, parse: &Parse) { ast::Stmt::CreateTable(create_table) if create_table.if_not_exists().is_none() && !inside_transaction => { + let is_temp = + create_table.temp_token().is_some() || create_table.temporary_token().is_some(); + let on_commit_drop = create_table + .on_commit() + .and_then(|oc| oc.on_commit_action()) + .is_some_and(|action| matches!(action, ast::OnCommitAction::Drop(_))); + + if is_temp && on_commit_drop { + continue; + } + let fix = create_table.table_token().map(|table_token| { let at = table_token.text_range().end(); let edit = Edit::insert(" if not exists", at); @@ -669,4 +680,46 @@ DROP INDEX CONCURRENTLY "email_idx"; assert_ne!(errors.len(), 0); assert_debug_snapshot!(errors); } + + #[test] + fn create_temp_table_on_commit_drop_ok() { + let sql = r#" +select 1; -- so we don't skip checking +CREATE TEMP TABLE test_table (id int) ON COMMIT DROP; + "#; + let errors = lint(sql, Rule::PreferRobustStmts); + assert_eq!(errors.len(), 0); + } + + #[test] + fn create_temporary_table_on_commit_drop_ok() { + let sql = r#" +select 1; -- so we don't skip checking +CREATE TEMPORARY TABLE test_table (id int) ON COMMIT DROP; + "#; + let errors = lint(sql, Rule::PreferRobustStmts); + assert_eq!(errors.len(), 0); + } + + #[test] + fn create_temp_table_without_on_commit_drop_err() { + let sql = r#" +select 1; -- so we don't skip checking +CREATE TEMP TABLE test_table (id int); + "#; + let errors = lint(sql, Rule::PreferRobustStmts); + assert_ne!(errors.len(), 0); + assert_debug_snapshot!(errors); + } + + #[test] + fn create_table_with_on_commit_drop_err() { + let sql = r#" +select 1; -- so we don't skip checking +CREATE TABLE test_table (id int) ON COMMIT DROP; + "#; + let errors = lint(sql, Rule::PreferRobustStmts); + assert_ne!(errors.len(), 0); + assert_debug_snapshot!(errors); + } } diff --git a/crates/squawk_linter/src/rules/snapshots/squawk_linter__rules__prefer_robust_stmts__test__create_table_with_on_commit_drop_err.snap b/crates/squawk_linter/src/rules/snapshots/squawk_linter__rules__prefer_robust_stmts__test__create_table_with_on_commit_drop_err.snap new file mode 100644 index 00000000..56c25a61 --- /dev/null +++ b/crates/squawk_linter/src/rules/snapshots/squawk_linter__rules__prefer_robust_stmts__test__create_table_with_on_commit_drop_err.snap @@ -0,0 +1,25 @@ +--- +source: crates/squawk_linter/src/rules/prefer_robust_stmts.rs +expression: errors +--- +[ + Violation { + code: PreferRobustStmts, + message: "Missing `IF NOT EXISTS`, the migration can't be rerun if it fails part way through.", + text_range: 40..87, + help: None, + fix: Some( + Fix { + title: "Insert `if not exists`", + edits: [ + Edit { + text_range: 52..52, + text: Some( + " if not exists", + ), + }, + ], + }, + ), + }, +] diff --git a/crates/squawk_linter/src/rules/snapshots/squawk_linter__rules__prefer_robust_stmts__test__create_temp_table_without_on_commit_drop_err.snap b/crates/squawk_linter/src/rules/snapshots/squawk_linter__rules__prefer_robust_stmts__test__create_temp_table_without_on_commit_drop_err.snap new file mode 100644 index 00000000..96759523 --- /dev/null +++ b/crates/squawk_linter/src/rules/snapshots/squawk_linter__rules__prefer_robust_stmts__test__create_temp_table_without_on_commit_drop_err.snap @@ -0,0 +1,25 @@ +--- +source: crates/squawk_linter/src/rules/prefer_robust_stmts.rs +expression: errors +--- +[ + Violation { + code: PreferRobustStmts, + message: "Missing `IF NOT EXISTS`, the migration can't be rerun if it fails part way through.", + text_range: 40..77, + help: None, + fix: Some( + Fix { + title: "Insert `if not exists`", + edits: [ + Edit { + text_range: 57..57, + text: Some( + " if not exists", + ), + }, + ], + }, + ), + }, +]