squawk_syntax/
identifier.rs

1/// Postgres Identifiers are case insensitive unless they're quoted.
2///
3/// This type handles the casing rules for us to make comparisions easier.
4#[derive(Debug, Clone, PartialEq, Eq, Hash)]
5pub struct Identifier(String);
6
7impl Identifier {
8    // TODO: we need to handle more advanced identifiers like:
9    // U&"d!0061t!+000061" UESCAPE '!'
10    pub fn new(s: &str) -> Self {
11        let normalized = if s.starts_with('"') && s.ends_with('"') {
12            s[1..s.len() - 1].to_string()
13        } else {
14            s.to_lowercase()
15        };
16        Identifier(normalized)
17    }
18}
19
20#[cfg(test)]
21mod test {
22    use crate::identifier::Identifier;
23
24    #[test]
25    fn case_folds_correctly() {
26        // https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS
27        // For example, the identifiers FOO, foo, and "foo" are considered the
28        // same by PostgreSQL, but "Foo" and "FOO" are different from these
29        // three and each other.
30        assert_eq!(Identifier::new("FOO"), Identifier::new("foo"));
31        assert_eq!(Identifier::new(r#""foo""#), Identifier::new("foo"));
32        assert_eq!(Identifier::new(r#""foo""#), Identifier::new("FOO"));
33    }
34}