agentic/port_squawk_rules.md
The goal is to port all missing rules from Squawk to our analyser.
Our analyser lives in the pgls_analyser crate. There is a CONTRIBUTING.md guide in that crate which explains how to add new rules. Please also read existing rules to see how it all works.
Then, I want you to check the rules in the squawk project which I copied here for convenience. The rules are in squawk/linter/src/rules. The implementation should be very similar to what we have, and porting them straightforward. Here a few things to watch out for though:
libpg_query to parse the SQL, the bindings can be different. Ours is in the pgls_query crate of you need a reference. The protobuf.rs file contains the full thing.pub struct RuleContext<'a, R: Rule> {
// the ast of the target statement
stmt: &'a pgls_query::NodeEnum,
// options for that specific rule
options: &'a R::Options,
// the schema cache - also includes the postgres version
schema_cache: Option<&'a SchemaCache>,
// the file context which contains other statements in that file in case you need them
file_context: &'a AnalysedFileContext,
}
pub struct AnalysedFileContext<'a> {
// all statements in this file
pub stmts: &'a Vec<pgls_query::NodeEnum>,
pos: usize,
}
impl<'a> AnalysedFileContext<'a> {
pub fn new(stmts: &'a Vec<pgls_query::NodeEnum>) -> Self {
Self { stmts, pos: 0 }
}
// all statements before the currently analysed one
pub fn previous_stmts(&self) -> &[pgls_query::NodeEnum] {
&self.stmts[0..self.pos]
}
// total count of statements in this file
pub fn stmt_count(&self) -> usize {
self.stmts.len()
}
}
In squawk, you will see:
// all statements of that file -> our analyser goes statement by statement but has access to the files content via `file_context`
tree: &[RawStmt],
// the postgres version -> we store it in the schema cache
_pg_version: Option<Version>,
// for us, this is always true
_assume_in_transaction: bool,
Please always write idiomatic code! Only add comments to explain WHY the code is doing something. DO NOT write comments to explain WHAT the code is doing.
If you learn something new that might help in porting all the rules, please update this document.
LEARNINGS:
cargo clippy to check your code after writing itjust new-lintrule command expects severity to be "info", "warn", or "error" (not "warning")detail(span, msg) takes two parameters, note(msg) takes only one parameterctx.schema_cache().is_some_and(|sc| sc.version.major_version) which gives e.g. 17just gen-lint after creating a new rule to generate all necessary filesPlease update the list below with the rules that we need to migrate, and the ones that are already migrated. Keep the list up-to-date.
NEEDS FEATURES:
TODO:
DONE: