squawk-syntax 2.50.0

Linter for Postgres migrations & SQL
Documentation
/// Postgres Identifiers are case insensitive unless they're quoted.
///
/// This type handles the casing rules for us to make comparisions easier.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct Identifier(String);

impl Identifier {
    // TODO: we need to handle more advanced identifiers like:
    // U&"d!0061t!+000061" UESCAPE '!'
    pub fn new(s: &str) -> Self {
        let normalized = if s.starts_with('"') && s.ends_with('"') {
            s[1..s.len() - 1].to_string()
        } else {
            s.to_lowercase()
        };
        Identifier(normalized)
    }
}

#[cfg(test)]
mod test {
    use crate::identifier::Identifier;

    #[test]
    fn case_folds_correctly() {
        // https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS
        // For example, the identifiers FOO, foo, and "foo" are considered the
        // same by PostgreSQL, but "Foo" and "FOO" are different from these
        // three and each other.
        assert_eq!(Identifier::new("FOO"), Identifier::new("foo"));
        assert_eq!(Identifier::new(r#""foo""#), Identifier::new("foo"));
        assert_eq!(Identifier::new(r#""foo""#), Identifier::new("FOO"));
    }
}