Skip to main content

safe_migrate/
resolve.rs

1use crate::error::{Result, SafeMigrateError};
2use crate::model::{IndexIdentity, TableIdentity};
3use squawk_syntax::ast::{self, AstNode};
4
5pub fn normalize_ident(ident: &str) -> String {
6    let ident = ident.trim();
7    if ident.starts_with('"') && ident.ends_with('"') && ident.len() >= 2 {
8        ident[1..ident.len() - 1].to_string()
9    } else {
10        ident.to_ascii_lowercase()
11    }
12}
13
14fn extract_segment_text(seg: &ast::PathSegment) -> String {
15    if let Some(name) = seg.name() {
16        if let Some(ident) = name.ident_token() {
17            return ident.text().to_string();
18        }
19    } else if let Some(name_ref) = seg.name_ref()
20        && let Some(ident) = name_ref.ident_token()
21    {
22        return ident.text().to_string();
23    }
24    seg.syntax().text().to_string()
25}
26
27pub fn extract_path_components(path: ast::Path) -> Result<(Option<String>, String)> {
28    let mut segments = Vec::new();
29    let mut current_path = Some(path);
30
31    while let Some(p) = current_path {
32        if let Some(seg) = p.segment() {
33            segments.push(extract_segment_text(&seg));
34        }
35        current_path = p.qualifier();
36    }
37    segments.reverse();
38
39    match segments.as_slice() {
40        [name] => Ok((None, normalize_ident(name))),
41        [schema, name] => Ok((Some(normalize_ident(schema)), normalize_ident(name))),
42        _ => Err(SafeMigrateError::Parse(format!(
43            "Unsupported identifier length (got {}): {}",
44            segments.len(),
45            segments.join(".")
46        ))),
47    }
48}
49
50pub fn extract_table_identity(path: ast::Path) -> Result<TableIdentity> {
51    let (schema, name) = extract_path_components(path)?;
52    Ok(TableIdentity { schema, name })
53}
54
55pub fn extract_index_identity(path: ast::Path) -> Result<IndexIdentity> {
56    let (schema, name) = extract_path_components(path)?;
57    Ok(IndexIdentity { schema, name })
58}
59
60#[cfg(test)]
61mod tests {
62    use super::*;
63
64    #[test]
65    fn test_normalize_ident_standard() {
66        // Standard identifiers should be downcased
67        assert_eq!(normalize_ident("Users"), "users");
68        assert_eq!(normalize_ident("CamelCaseTable"), "camelcasetable");
69    }
70
71    #[test]
72    fn test_normalize_ident_quoted() {
73        // Quoted identifiers should preserve their exact case and strip the quotes
74        assert_eq!(normalize_ident("\"Users\""), "Users");
75        assert_eq!(normalize_ident("\"CamelCaseTable\""), "CamelCaseTable");
76        assert_eq!(
77            normalize_ident("\"weird-table-name!\""),
78            "weird-table-name!"
79        );
80    }
81}