diff --git a/crates/squawk_linter/src/ignore.rs b/crates/squawk_linter/src/ignore.rs index 691140d3..821df8db 100644 --- a/crates/squawk_linter/src/ignore.rs +++ b/crates/squawk_linter/src/ignore.rs @@ -102,7 +102,6 @@ pub(crate) fn find_ignores(ctx: &mut Linter, file: &SyntaxNode) { Rule::UnusedIgnore, format!("unknown name {trimmed}"), range, - None, )); } diff --git a/crates/squawk_linter/src/lib.rs b/crates/squawk_linter/src/lib.rs index 7909b599..24840ec4 100644 --- a/crates/squawk_linter/src/lib.rs +++ b/crates/squawk_linter/src/lib.rs @@ -219,16 +219,6 @@ impl fmt::Display for Rule { } } -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct Violation { - // TODO: should this be String instead? - pub code: Rule, - pub message: String, - pub text_range: TextRange, - pub help: Option, - pub fix: Option, -} - #[derive(Debug, Clone, PartialEq, Eq)] pub struct Fix { pub title: String, @@ -258,14 +248,19 @@ impl Edit { } } +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Violation { + // TODO: should this be String instead? + pub code: Rule, + pub message: String, + pub text_range: TextRange, + pub help: Option, + pub fix: Option, +} + impl Violation { #[must_use] - pub fn for_node( - code: Rule, - message: String, - node: &SyntaxNode, - help: impl Into>, - ) -> Self { + pub fn for_node(code: Rule, message: String, node: &SyntaxNode) -> Self { let range = node.text_range(); let start = node @@ -280,31 +275,30 @@ impl Violation { code, text_range: TextRange::new(start, range.end()), message, - help: help.into(), + help: None, fix: None, } } #[must_use] - pub fn for_range( - code: Rule, - message: String, - text_range: TextRange, - help: impl Into>, - ) -> Self { + pub fn for_range(code: Rule, message: String, text_range: TextRange) -> Self { Self { code, text_range, message, - help: help.into(), + help: None, fix: None, } } - fn with_fix(mut self, fix: Option) -> Violation { + fn fix(mut self, fix: Option) -> Violation { self.fix = fix; self } + fn help(mut self, help: impl Into) -> Violation { + self.help = Some(help.into()); + self + } } #[derive(Default)] diff --git a/crates/squawk_linter/src/rules/adding_field_with_default.rs b/crates/squawk_linter/src/rules/adding_field_with_default.rs index 90ab5454..230a3bac 100644 --- a/crates/squawk_linter/src/rules/adding_field_with_default.rs +++ b/crates/squawk_linter/src/rules/adding_field_with_default.rs @@ -73,20 +73,24 @@ pub(crate) fn adding_field_with_default(ctx: &mut Linter, parse: &Parse { - ctx.report(Violation::for_node( - Rule::AddingFieldWithDefault, - message.into(), - generated.syntax(), - help.to_string(), - )); + ctx.report( + Violation::for_node( + Rule::AddingFieldWithDefault, + message.into(), + generated.syntax(), + ) + .help(help), + ); } _ => (), } diff --git a/crates/squawk_linter/src/rules/adding_foreign_key_constraint.rs b/crates/squawk_linter/src/rules/adding_foreign_key_constraint.rs index 8a2f36fe..cb3106fe 100644 --- a/crates/squawk_linter/src/rules/adding_foreign_key_constraint.rs +++ b/crates/squawk_linter/src/rules/adding_foreign_key_constraint.rs @@ -25,12 +25,14 @@ pub(crate) fn adding_foreign_key_constraint(ctx: &mut Linter, parse: &Parse) "Setting a column `NOT NULL` blocks reads while the table is scanned." .into(), option.syntax(), - "Make the field nullable and use a `CHECK` constraint instead." - .to_string(), - )); + ).help("Make the field nullable and use a `CHECK` constraint instead.")); } } } diff --git a/crates/squawk_linter/src/rules/adding_primary_key_constraint.rs b/crates/squawk_linter/src/rules/adding_primary_key_constraint.rs index 37da152f..caf289c4 100644 --- a/crates/squawk_linter/src/rules/adding_primary_key_constraint.rs +++ b/crates/squawk_linter/src/rules/adding_primary_key_constraint.rs @@ -18,12 +18,14 @@ pub(crate) fn adding_primary_key_constraint(ctx: &mut Linter, parse: &Parse) Rule::AddingRequiredField, "Adding a new column that is `NOT NULL` and has no default value to an existing table effectively makes it required.".into(), add_column.syntax(), - "Make the field nullable or add a non-VOLATILE DEFAULT".to_string(), - )); + ).help("Make the field nullable or add a non-VOLATILE DEFAULT")); } } } diff --git a/crates/squawk_linter/src/rules/ban_alter_domain_with_add_constraint.rs b/crates/squawk_linter/src/rules/ban_alter_domain_with_add_constraint.rs index 6238576e..e15cd29b 100644 --- a/crates/squawk_linter/src/rules/ban_alter_domain_with_add_constraint.rs +++ b/crates/squawk_linter/src/rules/ban_alter_domain_with_add_constraint.rs @@ -16,7 +16,6 @@ pub(crate) fn ban_alter_domain_with_add_constraint(ctx: &mut Linter, parse: &Par Rule::BanAlterDomainWithAddConstraint, "Domains with constraints have poor support for online migrations. Use table and column constraints instead.".into(), add_constraint.syntax(), - None, )) } } diff --git a/crates/squawk_linter/src/rules/ban_char_field.rs b/crates/squawk_linter/src/rules/ban_char_field.rs index 69cb7425..45f69cf3 100644 --- a/crates/squawk_linter/src/rules/ban_char_field.rs +++ b/crates/squawk_linter/src/rules/ban_char_field.rs @@ -24,7 +24,6 @@ fn check_path_type(ctx: &mut Linter, path_type: ast::PathType) { Rule::BanCharField, "Using `character` is likely a mistake and should almost always be replaced by `text` or `varchar`.".into(), path_type.syntax(), - None, )); } } @@ -36,7 +35,6 @@ fn check_char_type(ctx: &mut Linter, char_type: ast::CharType) { Rule::BanCharField, "Using `character` is likey a mistake and should almost always be replaced by `text` or `varchar`.".into(), char_type.syntax(), - None, )); } } diff --git a/crates/squawk_linter/src/rules/ban_concurrent_index_creation_in_transaction.rs b/crates/squawk_linter/src/rules/ban_concurrent_index_creation_in_transaction.rs index 909a0d14..aea8caea 100644 --- a/crates/squawk_linter/src/rules/ban_concurrent_index_creation_in_transaction.rs +++ b/crates/squawk_linter/src/rules/ban_concurrent_index_creation_in_transaction.rs @@ -26,8 +26,7 @@ pub(crate) fn ban_concurrent_index_creation_in_transaction( Rule::BanConcurrentIndexCreationInTransaction, "While regular index creation can happen inside a transaction, this is not allowed when the `CONCURRENTLY` option is used.".into(), concurrently.text_range(), - "Build the index outside any transactions.".to_string(), - )); + ).help("Build the index outside any transactions.")); } } } @@ -45,7 +44,10 @@ pub(crate) fn ban_concurrent_index_creation_in_transaction( mod test { use insta::assert_debug_snapshot; - use crate::{Rule, test_utils::{lint, lint_with_assume_in_transaction}}; + use crate::{ + Rule, + test_utils::{lint, lint_with_assume_in_transaction}, + }; #[test] fn ban_concurrent_index_creation_in_transaction_err() { @@ -77,7 +79,8 @@ mod test { CREATE UNIQUE INDEX CONCURRENTLY "field_name_idx" ON "table_name" ("field_name"); ALTER TABLE "table_name" ADD CONSTRAINT "field_name_id" UNIQUE USING INDEX "field_name_idx"; "#; - let errors = lint_with_assume_in_transaction(sql, Rule::BanConcurrentIndexCreationInTransaction); + let errors = + lint_with_assume_in_transaction(sql, Rule::BanConcurrentIndexCreationInTransaction); assert_ne!(errors.len(), 0); assert_debug_snapshot!(errors); } @@ -88,7 +91,8 @@ mod test { -- run index creation in a standalone migration CREATE UNIQUE INDEX CONCURRENTLY "field_name_idx" ON "table_name" ("field_name"); "#; - let errors = lint_with_assume_in_transaction(sql, Rule::BanConcurrentIndexCreationInTransaction); + let errors = + lint_with_assume_in_transaction(sql, Rule::BanConcurrentIndexCreationInTransaction); assert_eq!(errors.len(), 0); } @@ -101,7 +105,8 @@ mod test { BEGIN; ALTER TABLE "table_name" ADD CONSTRAINT "field_name_id" UNIQUE USING INDEX "field_name_idx"; "#; - let errors = lint_with_assume_in_transaction(sql, Rule::BanConcurrentIndexCreationInTransaction); + let errors = + lint_with_assume_in_transaction(sql, Rule::BanConcurrentIndexCreationInTransaction); assert_eq!(errors.len(), 0); } } diff --git a/crates/squawk_linter/src/rules/ban_create_domain_with_constraint.rs b/crates/squawk_linter/src/rules/ban_create_domain_with_constraint.rs index 2eac4dc9..144999b6 100644 --- a/crates/squawk_linter/src/rules/ban_create_domain_with_constraint.rs +++ b/crates/squawk_linter/src/rules/ban_create_domain_with_constraint.rs @@ -27,7 +27,6 @@ pub(crate) fn ban_create_domain_with_constraint(ctx: &mut Linter, parse: &Parse< Rule::BanCreateDomainWithConstraint, "Domains with constraints have poor support for online migrations. Use table and column constraints instead.".into(), range, - None, )) } } diff --git a/crates/squawk_linter/src/rules/ban_drop_column.rs b/crates/squawk_linter/src/rules/ban_drop_column.rs index e4f8c27f..12619e16 100644 --- a/crates/squawk_linter/src/rules/ban_drop_column.rs +++ b/crates/squawk_linter/src/rules/ban_drop_column.rs @@ -15,7 +15,6 @@ pub(crate) fn ban_drop_column(ctx: &mut Linter, parse: &Parse) { Rule::BanDropColumn, "Dropping a column may break existing clients.".into(), drop_column.syntax(), - None, )); } } diff --git a/crates/squawk_linter/src/rules/ban_drop_database.rs b/crates/squawk_linter/src/rules/ban_drop_database.rs index 3d94b386..5b6b78a4 100644 --- a/crates/squawk_linter/src/rules/ban_drop_database.rs +++ b/crates/squawk_linter/src/rules/ban_drop_database.rs @@ -14,7 +14,6 @@ pub(crate) fn ban_drop_database(ctx: &mut Linter, parse: &Parse) { Rule::BanDropDatabase, "Dropping a database may break existing clients.".into(), drop_database.syntax(), - None, )); } } diff --git a/crates/squawk_linter/src/rules/ban_drop_not_null.rs b/crates/squawk_linter/src/rules/ban_drop_not_null.rs index 98b9f6d6..941ba119 100644 --- a/crates/squawk_linter/src/rules/ban_drop_not_null.rs +++ b/crates/squawk_linter/src/rules/ban_drop_not_null.rs @@ -18,7 +18,6 @@ pub(crate) fn ban_drop_not_null(ctx: &mut Linter, parse: &Parse) { Rule::BanDropNotNull, "Dropping a `NOT NULL` constraint may break existing clients.".into(), drop_not_null.syntax(), - None, )); } } diff --git a/crates/squawk_linter/src/rules/ban_drop_table.rs b/crates/squawk_linter/src/rules/ban_drop_table.rs index 4a70a39a..de06b167 100644 --- a/crates/squawk_linter/src/rules/ban_drop_table.rs +++ b/crates/squawk_linter/src/rules/ban_drop_table.rs @@ -13,7 +13,6 @@ pub(crate) fn ban_drop_table(ctx: &mut Linter, parse: &Parse) { Rule::BanDropTable, "Dropping a table may break existing clients.".into(), drop_table.syntax(), - None, )); } } diff --git a/crates/squawk_linter/src/rules/ban_truncate_cascade.rs b/crates/squawk_linter/src/rules/ban_truncate_cascade.rs index a242bce5..44ce1976 100644 --- a/crates/squawk_linter/src/rules/ban_truncate_cascade.rs +++ b/crates/squawk_linter/src/rules/ban_truncate_cascade.rs @@ -14,8 +14,7 @@ pub(crate) fn ban_truncate_cascade(ctx: &mut Linter, parse: &Parse) Rule::BanTruncateCascade, "Using `CASCADE` will recursively truncate any tables that foreign key to the referenced tables! So if you had foreign keys setup as `a <- b <- c` and truncated `a`, then `b` & `c` would also be truncated!".to_string(), cascade.text_range(), - "Remove the `CASCADE` and specify exactly which tables you want to truncate.".to_string(), - )); + ).help("Remove the `CASCADE` and specify exactly which tables you want to truncate.")); } } } diff --git a/crates/squawk_linter/src/rules/changing_column_type.rs b/crates/squawk_linter/src/rules/changing_column_type.rs index 67f67119..faba2d61 100644 --- a/crates/squawk_linter/src/rules/changing_column_type.rs +++ b/crates/squawk_linter/src/rules/changing_column_type.rs @@ -16,7 +16,6 @@ pub(crate) fn changing_column_type(ctx: &mut Linter, parse: &Parse) Rule::ChangingColumnType, "Changing a column type requires an `ACCESS EXCLUSIVE` lock on the table which blocks reads and writes while the table is rewritten. Changing the type of the column may also break other clients reading from the table.".into(), set_type.syntax(), - None, )); } } diff --git a/crates/squawk_linter/src/rules/constraint_missing_not_valid.rs b/crates/squawk_linter/src/rules/constraint_missing_not_valid.rs index dca23316..1a77e3d1 100644 --- a/crates/squawk_linter/src/rules/constraint_missing_not_valid.rs +++ b/crates/squawk_linter/src/rules/constraint_missing_not_valid.rs @@ -61,8 +61,7 @@ fn not_valid_validate_in_transaction( Rule::ConstraintMissingNotValid, "Using `NOT VALID` and `VALIDATE CONSTRAINT` in the same transaction will block all reads while the constraint is validated.".into(), validate_constraint.syntax(), - "Add constraint as `NOT VALID` in one transaction and `VALIDATE CONSTRAINT` in a separate transaction.".to_string(), - )) + ).help("Add constraint as `NOT VALID` in one transaction and `VALIDATE CONSTRAINT` in a separate transaction.")) } } } @@ -131,8 +130,7 @@ pub(crate) fn constraint_missing_not_valid(ctx: &mut Linter, parse: &Parse) { if let Some(ty) = ty { if is_not_valid_int_type(&ty, &INT_TYPES) { - ctx.report(Violation::for_node( - Rule::PreferBigintOverInt, - "Using 32-bit integer fields can result in hitting the max `int` limit.".into(), - ty.syntax(), - "Use 64-bit integer values instead to prevent hitting this limit.".to_string(), - )); + ctx.report( + Violation::for_node( + Rule::PreferBigintOverInt, + "Using 32-bit integer fields can result in hitting the max `int` limit.".into(), + ty.syntax(), + ) + .help("Use 64-bit integer values instead to prevent hitting this limit."), + ); }; } } diff --git a/crates/squawk_linter/src/rules/prefer_bigint_over_smallint.rs b/crates/squawk_linter/src/rules/prefer_bigint_over_smallint.rs index 6251c421..c1903718 100644 --- a/crates/squawk_linter/src/rules/prefer_bigint_over_smallint.rs +++ b/crates/squawk_linter/src/rules/prefer_bigint_over_smallint.rs @@ -23,12 +23,14 @@ lazy_static! { fn check_ty_for_small_int(ctx: &mut Linter, ty: Option) { if let Some(ty) = ty { if is_not_valid_int_type(&ty, &SMALL_INT_TYPES) { - ctx.report(Violation::for_node( - Rule::PreferBigintOverSmallint, - "Using 16-bit integer fields can result in hitting the max `int` limit.".into(), - ty.syntax(), - "Use 64-bit integer values instead to prevent hitting this limit.".to_string(), - )); + ctx.report( + Violation::for_node( + Rule::PreferBigintOverSmallint, + "Using 16-bit integer fields can result in hitting the max `int` limit.".into(), + ty.syntax(), + ) + .help("Use 64-bit integer values instead to prevent hitting this limit."), + ); }; } } diff --git a/crates/squawk_linter/src/rules/prefer_identity.rs b/crates/squawk_linter/src/rules/prefer_identity.rs index 73e2bcb0..606bf56d 100644 --- a/crates/squawk_linter/src/rules/prefer_identity.rs +++ b/crates/squawk_linter/src/rules/prefer_identity.rs @@ -25,12 +25,15 @@ lazy_static! { fn check_ty_for_serial(ctx: &mut Linter, ty: Option) { if let Some(ty) = ty { if is_not_valid_int_type(&ty, &SERIAL_TYPES) { - ctx.report(Violation::for_node( - Rule::PreferIdentity, - "Serial types make schema, dependency, and permission management difficult.".into(), - ty.syntax(), - "Use an `IDENTITY` column instead.".to_string(), - )); + ctx.report( + Violation::for_node( + Rule::PreferIdentity, + "Serial types make schema, dependency, and permission management difficult." + .into(), + ty.syntax(), + ) + .help("Use an `IDENTITY` column instead."), + ); }; } } diff --git a/crates/squawk_linter/src/rules/prefer_robust_stmts.rs b/crates/squawk_linter/src/rules/prefer_robust_stmts.rs index 4ea16c69..b9ff48eb 100644 --- a/crates/squawk_linter/src/rules/prefer_robust_stmts.rs +++ b/crates/squawk_linter/src/rules/prefer_robust_stmts.rs @@ -142,13 +142,8 @@ pub(crate) fn prefer_robust_stmts(ctx: &mut Linter, parse: &Parse) { }; ctx.report( - Violation::for_node( - Rule::PreferRobustStmts, - message, - action.syntax(), - None, - ) - .with_fix(fix), + Violation::for_node(Rule::PreferRobustStmts, message, action.syntax()) + .fix(fix), ); } } @@ -168,8 +163,7 @@ pub(crate) fn prefer_robust_stmts(ctx: &mut Linter, parse: &Parse) { Rule::PreferRobustStmts, "Missing `IF NOT EXISTS`, the migration can't be rerun if it fails part way through.".into(), create_index.syntax(), - "Use an explicit name for a concurrently created index".to_string(), - ).with_fix(fix)); + ).help("Use an explicit name for a concurrently created index").fix(fix)); } ast::Stmt::CreateTable(create_table) if create_table.if_not_exists().is_none() && !inside_transaction => @@ -186,8 +180,7 @@ pub(crate) fn prefer_robust_stmts(ctx: &mut Linter, parse: &Parse) { Rule::PreferRobustStmts, "Missing `IF NOT EXISTS`, the migration can't be rerun if it fails part way through.".into(), create_table.syntax(), - None, - ).with_fix(fix)); + ).fix(fix)); } ast::Stmt::DropIndex(drop_index) if drop_index.if_exists().is_none() && !inside_transaction => @@ -204,8 +197,7 @@ pub(crate) fn prefer_robust_stmts(ctx: &mut Linter, parse: &Parse) { Rule::PreferRobustStmts, "Missing `IF EXISTS`, the migration can't be rerun if it fails part way through.".into(), drop_index.syntax(), - None, - ).with_fix(fix)); + ).fix(fix)); } ast::Stmt::DropTable(drop_table) if drop_table.if_exists().is_none() && !inside_transaction => @@ -221,8 +213,7 @@ pub(crate) fn prefer_robust_stmts(ctx: &mut Linter, parse: &Parse) { Rule::PreferRobustStmts, "Missing `IF EXISTS`, the migration can't be rerun if it fails part way through.".into(), drop_table.syntax(), - None, - ).with_fix(fix)); + ).fix(fix)); } ast::Stmt::DropType(drop_type) if drop_type.if_exists().is_none() && !inside_transaction => @@ -239,8 +230,7 @@ pub(crate) fn prefer_robust_stmts(ctx: &mut Linter, parse: &Parse) { Rule::PreferRobustStmts, "Missing `IF EXISTS`, the migration can't be rerun if it fails part way through.".into(), drop_type.syntax(), - None, - ).with_fix(fix)); + ).fix(fix)); } _ => (), } @@ -251,7 +241,10 @@ pub(crate) fn prefer_robust_stmts(ctx: &mut Linter, parse: &Parse) { mod test { use insta::{assert_debug_snapshot, assert_snapshot}; - use crate::{Edit, Linter, Rule, test_utils::{lint, lint_with_assume_in_transaction}}; + use crate::{ + Edit, Linter, Rule, + test_utils::{lint, lint_with_assume_in_transaction}, + }; fn fix(sql: &str) -> String { let file = squawk_syntax::SourceFile::parse(sql); diff --git a/crates/squawk_linter/src/rules/prefer_text_field.rs b/crates/squawk_linter/src/rules/prefer_text_field.rs index bd94cdbe..c90ede25 100644 --- a/crates/squawk_linter/src/rules/prefer_text_field.rs +++ b/crates/squawk_linter/src/rules/prefer_text_field.rs @@ -56,8 +56,7 @@ fn check_ty_for_varchar(ctx: &mut Linter, ty: Option) { Rule::PreferTextField, "Changing the size of a `varchar` field requires an `ACCESS EXCLUSIVE` lock, that will prevent all reads and writes to the table.".to_string(), ty.syntax(), - "Use a `TEXT` field with a `CHECK` constraint.".to_string(), - )); + ).help("Use a `TEXT` field with a `CHECK` constraint.")); }; } } diff --git a/crates/squawk_linter/src/rules/prefer_timestamptz.rs b/crates/squawk_linter/src/rules/prefer_timestamptz.rs index 8b8ad2ad..e13aabdc 100644 --- a/crates/squawk_linter/src/rules/prefer_timestamptz.rs +++ b/crates/squawk_linter/src/rules/prefer_timestamptz.rs @@ -51,8 +51,7 @@ fn check_ty_for_timestamp(ctx: &mut Linter, ty: Option) { Rule::PreferTimestampTz, "When Postgres stores a datetime in a `timestamp` field, Postgres drops the UTC offset. This means 2019-10-11 21:11:24+02 and 2019-10-11 21:11:24-06 will both be stored as 2019-10-11 21:11:24 in the database, even though they are eight hours apart in time.".into(), ty.syntax(), - "Use timestamptz instead of timestamp for your column type.".to_string(), - )); + ).help("Use timestamptz instead of timestamp for your column type.")); }; } } diff --git a/crates/squawk_linter/src/rules/renaming_column.rs b/crates/squawk_linter/src/rules/renaming_column.rs index e1d80410..49a58ee8 100644 --- a/crates/squawk_linter/src/rules/renaming_column.rs +++ b/crates/squawk_linter/src/rules/renaming_column.rs @@ -15,7 +15,6 @@ pub(crate) fn renaming_column(ctx: &mut Linter, parse: &Parse) { Rule::RenamingColumn, "Renaming a column may break existing clients.".into(), rename_column.syntax(), - None, )); } } diff --git a/crates/squawk_linter/src/rules/renaming_table.rs b/crates/squawk_linter/src/rules/renaming_table.rs index 2fc2e1da..df3785a1 100644 --- a/crates/squawk_linter/src/rules/renaming_table.rs +++ b/crates/squawk_linter/src/rules/renaming_table.rs @@ -15,7 +15,6 @@ pub(crate) fn renaming_table(ctx: &mut Linter, parse: &Parse) { Rule::RenamingTable, "Renaming a table may break existing clients.".into(), rename_table.syntax(), - None, )); } } diff --git a/crates/squawk_linter/src/rules/require_concurrent_index_creation.rs b/crates/squawk_linter/src/rules/require_concurrent_index_creation.rs index 89444d81..03cea33e 100644 --- a/crates/squawk_linter/src/rules/require_concurrent_index_creation.rs +++ b/crates/squawk_linter/src/rules/require_concurrent_index_creation.rs @@ -25,8 +25,7 @@ pub(crate) fn require_concurrent_index_creation(ctx: &mut Linter, parse: &Parse< Rule::RequireConcurrentIndexCreation, "During normal index creation, table updates are blocked, but reads are still allowed.".into(), create_index.syntax(), - "Use `CONCURRENTLY` to avoid blocking writes.".to_string(), - )); + ).help("Use `CONCURRENTLY` to avoid blocking writes.")); } } } @@ -37,7 +36,10 @@ pub(crate) fn require_concurrent_index_creation(ctx: &mut Linter, parse: &Parse< mod test { use insta::assert_debug_snapshot; - use crate::{Rule, test_utils::{lint, lint_with_assume_in_transaction}}; + use crate::{ + Rule, + test_utils::{lint, lint_with_assume_in_transaction}, + }; /// ```sql /// -- instead of diff --git a/crates/squawk_linter/src/rules/require_concurrent_index_deletion.rs b/crates/squawk_linter/src/rules/require_concurrent_index_deletion.rs index 40cdb4a8..01d8dd41 100644 --- a/crates/squawk_linter/src/rules/require_concurrent_index_deletion.rs +++ b/crates/squawk_linter/src/rules/require_concurrent_index_deletion.rs @@ -14,8 +14,7 @@ pub(crate) fn require_concurrent_index_deletion(ctx: &mut Linter, parse: &Parse< Rule::RequireConcurrentIndexDeletion, "A normal `DROP INDEX` acquires an `ACCESS EXCLUSIVE` lock on the table, blocking other accesses until the index drop can complete.".into(), drop_index.syntax(), - "Drop the index `CONCURRENTLY`.".to_string(), - )); + ).help("Drop the index `CONCURRENTLY`.")); } } } diff --git a/crates/squawk_linter/src/rules/transaction_nesting.rs b/crates/squawk_linter/src/rules/transaction_nesting.rs index bbd1f794..26c412a4 100644 --- a/crates/squawk_linter/src/rules/transaction_nesting.rs +++ b/crates/squawk_linter/src/rules/transaction_nesting.rs @@ -18,15 +18,16 @@ pub(crate) fn transaction_nesting(ctx: &mut Linter, parse: &Parse) { Rule::TransactionNesting, "There is an existing transaction already in progress, managed by your migration tool.".to_string(), stmt.syntax(), - assume_in_transaction_help.to_string() - )); + ).help(assume_in_transaction_help)); } else if in_explicit_transaction { - ctx.report(Violation::for_node( - Rule::TransactionNesting, - "There is an existing transaction already in progress.".to_string(), - stmt.syntax(), - assume_in_transaction_help.to_string(), - )); + ctx.report( + Violation::for_node( + Rule::TransactionNesting, + "There is an existing transaction already in progress.".to_string(), + stmt.syntax(), + ) + .help(assume_in_transaction_help), + ); } in_explicit_transaction = true; } @@ -37,15 +38,13 @@ pub(crate) fn transaction_nesting(ctx: &mut Linter, parse: &Parse) { "Attempting to end the transaction that is managed by your migration tool" .to_string(), stmt.syntax(), - assume_in_transaction_help.to_string(), - )); + ).help(assume_in_transaction_help)); } else if !in_explicit_transaction { ctx.report(Violation::for_node( Rule::TransactionNesting, "There is no transaction to `COMMIT` or `ROLLBACK`.".to_string(), stmt.syntax(), - "`BEGIN` a transaction at an earlier point in the migration or remove this statement.".to_string() - )); + ).help("`BEGIN` a transaction at an earlier point in the migration or remove this statement.")); } in_explicit_transaction = false; }