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}