squawk-linter 2.50.0

Linter for Postgres migrations & SQL
Documentation
use rowan::TextRange;
use squawk_syntax::{
    Parse, SourceFile,
    ast::{self, AstNode},
};

use crate::{Linter, Rule, Violation};

pub(crate) fn ban_create_domain_with_constraint(ctx: &mut Linter, parse: &Parse<SourceFile>) {
    let file = parse.tree();
    for stmt in file.stmts() {
        if let ast::Stmt::CreateDomain(domain) = stmt {
            let range =
                domain
                    .constraints()
                    .map(|c| c.syntax().text_range())
                    .fold(None, |prev, cur| match prev {
                        None => Some(cur),
                        Some(prev) => {
                            let new_start = prev.start().min(cur.start());
                            let new_end = prev.end().max(cur.end());
                            Some(TextRange::new(new_start, new_end))
                        }
                    });
            if let Some(range) = range {
                ctx.report(Violation::for_range(
                Rule::BanCreateDomainWithConstraint,
                    "Domains with constraints have poor support for online migrations. Use table and column constraints instead.".into(),
                    range,
                ))
            }
        }
    }
}

#[cfg(test)]
mod test {
    use insta::assert_snapshot;

    use crate::Rule;
    use crate::test_utils::{lint_errors, lint_ok};

    #[test]
    fn err() {
        let sql = r#"
CREATE DOMAIN domain_name_3 AS NUMERIC(15,5) CHECK (value > 0);
        "#;
        assert_snapshot!(lint_errors(sql, Rule::BanCreateDomainWithConstraint));
    }

    #[test]
    fn err_with_multiple_constraints() {
        // checking that we highlight all the constraints in our range
        let sql = r#"
create domain d as t check (value > 0) not null;
        "#;
        assert_snapshot!(lint_errors(sql, Rule::BanCreateDomainWithConstraint));
    }

    #[test]
    fn ok() {
        // creating without a constraint is okay
        let sql = r#"
CREATE DOMAIN domain_name_1 AS TEXT;
CREATE DOMAIN domain_name_2 AS CHARACTER VARYING;
        "#;
        lint_ok(sql, Rule::BanCreateDomainWithConstraint);
    }
}