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
3 changes: 2 additions & 1 deletion crates/pglt_analyser/src/lint/safety.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@
use pglt_analyse::declare_lint_group;
pub mod ban_drop_column;
pub mod ban_drop_not_null;
declare_lint_group! { pub Safety { name : "safety" , rules : [self :: ban_drop_column :: BanDropColumn , self :: ban_drop_not_null :: BanDropNotNull ,] } }
pub mod ban_drop_table;
declare_lint_group! { pub Safety { name : "safety" , rules : [self :: ban_drop_column :: BanDropColumn , self :: ban_drop_not_null :: BanDropNotNull , self :: ban_drop_table :: BanDropTable ,] } }
52 changes: 52 additions & 0 deletions crates/pglt_analyser/src/lint/safety/ban_drop_table.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
use pglt_analyse::{context::RuleContext, declare_lint_rule, Rule, RuleDiagnostic, RuleSource};
use pglt_console::markup;

declare_lint_rule! {
/// Dropping a table may break existing clients.
///
/// Update your application code to no longer read or write the table.
///
/// Once the table is no longer needed, you can delete it by running the command "DROP TABLE mytable;".
///
/// This command will permanently remove the table from the database and all its contents.
/// Be sure to back up the table before deleting it, just in case you need to restore it in the future.
///
/// ## Examples
/// ```sql,expect_diagnostic
/// drop table some_table;
/// ```
pub BanDropTable {
version: "next",
name: "banDropTable",
recommended: true,
sources: &[RuleSource::Squawk("ban-drop-table")],
}
}

impl Rule for BanDropTable {
type Options = ();

fn run(ctx: &RuleContext<Self>) -> Vec<RuleDiagnostic> {
let mut diagnostics = vec![];

if let pglt_query_ext::NodeEnum::DropStmt(stmt) = &ctx.stmt() {
if stmt.remove_type() == pglt_query_ext::protobuf::ObjectType::ObjectTable {
diagnostics.push(
RuleDiagnostic::new(
rule_category!(),
None,
markup! {
"Dropping a table may break existing clients."
},
)
.detail(
None,
"Update your application code to no longer read or write the table, and only then delete the table. Be sure to create a backup.",
),
);
}
}

diagnostics
}
}
1 change: 1 addition & 0 deletions crates/pglt_analyser/src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ pub type BanDropColumn =
<lint::safety::ban_drop_column::BanDropColumn as pglt_analyse::Rule>::Options;
pub type BanDropNotNull =
<lint::safety::ban_drop_not_null::BanDropNotNull as pglt_analyse::Rule>::Options;
pub type BanDropTable = <lint::safety::ban_drop_table::BanDropTable as pglt_analyse::Rule>::Options;
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-- expect_only_lint/safety/banDropTable
drop table test;
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
---
source: crates/pglt_analyser/tests/rules_tests.rs
expression: snapshot
---
# Input
```
-- expect_only_lint/safety/banDropTable
drop table test;
```

# Diagnostics
lint/safety/banDropTable ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

× Dropping a table may break existing clients.

i Update your application code to no longer read or write the table, and only then delete the table. Be sure to create a backup.
25 changes: 23 additions & 2 deletions crates/pglt_configuration/src/analyser/linter/rules.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,18 +149,25 @@ pub struct Safety {
#[doc = "Dropping a NOT NULL constraint may break existing clients."]
#[serde(skip_serializing_if = "Option::is_none")]
pub ban_drop_not_null: Option<RuleConfiguration<pglt_analyser::options::BanDropNotNull>>,
#[doc = "Dropping a table may break existing clients."]
#[serde(skip_serializing_if = "Option::is_none")]
pub ban_drop_table: Option<RuleConfiguration<pglt_analyser::options::BanDropTable>>,
}
impl Safety {
const GROUP_NAME: &'static str = "safety";
pub(crate) const GROUP_RULES: &'static [&'static str] = &["banDropColumn", "banDropNotNull"];
const RECOMMENDED_RULES: &'static [&'static str] = &["banDropColumn", "banDropNotNull"];
pub(crate) const GROUP_RULES: &'static [&'static str] =
&["banDropColumn", "banDropNotNull", "banDropTable"];
const RECOMMENDED_RULES: &'static [&'static str] =
&["banDropColumn", "banDropNotNull", "banDropTable"];
const RECOMMENDED_RULES_AS_FILTERS: &'static [RuleFilter<'static>] = &[
RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[0]),
RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[1]),
RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[2]),
];
const ALL_RULES_AS_FILTERS: &'static [RuleFilter<'static>] = &[
RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[0]),
RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[1]),
RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[2]),
];
#[doc = r" Retrieves the recommended rules"]
pub(crate) fn is_recommended_true(&self) -> bool {
Expand All @@ -187,6 +194,11 @@ impl Safety {
index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[1]));
}
}
if let Some(rule) = self.ban_drop_table.as_ref() {
if rule.is_enabled() {
index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[2]));
}
}
index_set
}
pub(crate) fn get_disabled_rules(&self) -> FxHashSet<RuleFilter<'static>> {
Expand All @@ -201,6 +213,11 @@ impl Safety {
index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[1]));
}
}
if let Some(rule) = self.ban_drop_table.as_ref() {
if rule.is_disabled() {
index_set.insert(RuleFilter::Rule(Self::GROUP_NAME, Self::GROUP_RULES[2]));
}
}
index_set
}
#[doc = r" Checks if, given a rule name, matches one of the rules contained in this category"]
Expand Down Expand Up @@ -245,6 +262,10 @@ impl Safety {
.ban_drop_not_null
.as_ref()
.map(|conf| (conf.level(), conf.get_options())),
"banDropTable" => self
.ban_drop_table
.as_ref()
.map(|conf| (conf.level(), conf.get_options())),
_ => None,
}
}
Expand Down
1 change: 1 addition & 0 deletions crates/pglt_diagnostics_categories/src/categories.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
define_categories! {
"lint/safety/banDropColumn": "https://pglt.dev/linter/rules/ban-drop-column",
"lint/safety/banDropNotNull": "https://pglt.dev/linter/rules/ban-drop-not-null",
"lint/safety/banDropTable": "https://pglt.dev/linter/rules/ban-drop-table",
// end lint rules
;
// General categories
Expand Down