Skip to main content

safe_migrate/ast/
identifiers.rs

1// FILE: ./src/ast/identifiers.rs
2
3use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
6pub struct Ident {
7    pub text: String,
8    pub quoted: bool,
9}
10
11impl Ident {
12    pub fn new(text: impl Into<String>, quoted: bool) -> Self {
13        Self {
14            text: text.into(),
15            quoted,
16        }
17    }
18
19    /// Resolves the identifier exactly as PostgreSQL would:
20    /// Quoted identifiers preserve exact casing; unquoted identifiers are case-folded to lowercase.
21    pub fn resolve(&self) -> String {
22        if self.quoted {
23            self.text.clone()
24        } else {
25            self.text.to_lowercase()
26        }
27    }
28}
29
30#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
31pub struct QualifiedName {
32    pub schema: Option<Ident>,
33    pub name: Ident,
34}
35
36impl QualifiedName {
37    pub fn new(schema: Option<Ident>, name: Ident) -> Self {
38        Self { schema, name }
39    }
40}
41
42/// ObjectId represents a fully resolved, state-machine tracked database object.
43/// By the time an ObjectId is constructed, its schema and name must already be properly case-folded.
44#[derive(Debug, Clone, Serialize, Deserialize)]
45pub struct ObjectId {
46    pub schema: String,
47    pub name: String,
48    #[serde(default)]
49    pub inferred_schema: bool,
50}
51
52impl PartialEq for ObjectId {
53    fn eq(&self, other: &Self) -> bool {
54        self.schema == other.schema && self.name == other.name
55    }
56}
57
58impl Eq for ObjectId {}
59
60impl std::hash::Hash for ObjectId {
61    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
62        self.schema.hash(state);
63        self.name.hash(state);
64    }
65}
66
67impl ObjectId {
68    pub fn new(schema: impl Into<String>, name: impl Into<String>) -> Self {
69        Self {
70            schema: schema.into(),
71            name: name.into(),
72            inferred_schema: false,
73        }
74    }
75}
76
77impl std::fmt::Display for ObjectId {
78    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
79        if self.inferred_schema {
80            write!(f, "{}.{} (inferred)", self.schema, self.name)
81        } else {
82            write!(f, "{}.{}", self.schema, self.name)
83        }
84    }
85}