fraiseql_core/db/identifier.rs
1//! Database identifier quoting utilities.
2//!
3//! This module provides database-specific identifier quoting functions that handle
4//! schema-qualified identifiers (e.g., `schema.table`, `catalog.schema.table`).
5//!
6//! Each function splits on `.` and quotes each component with the appropriate syntax
7//! for the target database.
8
9/// Quote a PostgreSQL identifier.
10///
11/// PostgreSQL uses double quotes for identifiers. Schema-qualified names
12/// (e.g., `schema.table`) are split and quoted per component.
13///
14/// # Examples
15///
16/// ```ignore
17/// assert_eq!(quote_postgres_identifier("v_user"), "\"v_user\"");
18/// assert_eq!(quote_postgres_identifier("benchmark.v_user"), "\"benchmark\".\"v_user\"");
19/// assert_eq!(
20/// quote_postgres_identifier("catalog.schema.table"),
21/// "\"catalog\".\"schema\".\"table\""
22/// );
23/// ```
24#[inline]
25#[must_use]
26pub fn quote_postgres_identifier(identifier: &str) -> String {
27 identifier
28 .split('.')
29 .map(|part| format!("\"{}\"", part))
30 .collect::<Vec<_>>()
31 .join(".")
32}
33
34/// Quote a MySQL identifier.
35///
36/// MySQL uses backticks for identifiers. Schema-qualified names
37/// (e.g., `database.table`) are split and quoted per component.
38///
39/// # Examples
40///
41/// ```ignore
42/// assert_eq!(quote_mysql_identifier("v_user"), "`v_user`");
43/// assert_eq!(quote_mysql_identifier("mydb.v_user"), "`mydb`.`v_user`");
44/// assert_eq!(
45/// quote_mysql_identifier("catalog.schema.table"),
46/// "`catalog`.`schema`.`table`"
47/// );
48/// ```
49#[inline]
50#[must_use]
51pub fn quote_mysql_identifier(identifier: &str) -> String {
52 identifier
53 .split('.')
54 .map(|part| format!("`{}`", part))
55 .collect::<Vec<_>>()
56 .join(".")
57}
58
59/// Quote a SQLite identifier.
60///
61/// SQLite uses double quotes for identifiers. Schema-qualified names
62/// (e.g., `schema.table`) are split and quoted per component.
63///
64/// # Examples
65///
66/// ```ignore
67/// assert_eq!(quote_sqlite_identifier("v_user"), "\"v_user\"");
68/// assert_eq!(quote_sqlite_identifier("main.v_user"), "\"main\".\"v_user\"");
69/// assert_eq!(
70/// quote_sqlite_identifier("catalog.schema.table"),
71/// "\"catalog\".\"schema\".\"table\""
72/// );
73/// ```
74#[inline]
75#[must_use]
76pub fn quote_sqlite_identifier(identifier: &str) -> String {
77 identifier
78 .split('.')
79 .map(|part| format!("\"{}\"", part))
80 .collect::<Vec<_>>()
81 .join(".")
82}
83
84/// Quote a SQL Server identifier.
85///
86/// SQL Server uses square brackets for identifiers. Schema-qualified names
87/// (e.g., `schema.table`) are split and quoted per component.
88///
89/// # Examples
90///
91/// ```ignore
92/// assert_eq!(quote_sqlserver_identifier("v_user"), "[v_user]");
93/// assert_eq!(quote_sqlserver_identifier("dbo.v_user"), "[dbo].[v_user]");
94/// assert_eq!(
95/// quote_sqlserver_identifier("catalog.schema.table"),
96/// "[catalog].[schema].[table]"
97/// );
98/// ```
99#[inline]
100#[must_use]
101pub fn quote_sqlserver_identifier(identifier: &str) -> String {
102 identifier
103 .split('.')
104 .map(|part| format!("[{}]", part))
105 .collect::<Vec<_>>()
106 .join(".")
107}
108
109#[cfg(test)]
110mod tests {
111 use super::*;
112
113 #[test]
114 fn test_postgres_simple_identifier() {
115 assert_eq!(quote_postgres_identifier("v_user"), "\"v_user\"");
116 }
117
118 #[test]
119 fn test_postgres_schema_qualified() {
120 assert_eq!(quote_postgres_identifier("benchmark.v_user"), "\"benchmark\".\"v_user\"");
121 }
122
123 #[test]
124 fn test_postgres_three_part_name() {
125 assert_eq!(
126 quote_postgres_identifier("catalog.schema.table"),
127 "\"catalog\".\"schema\".\"table\""
128 );
129 }
130
131 #[test]
132 fn test_mysql_simple_identifier() {
133 assert_eq!(quote_mysql_identifier("v_user"), "`v_user`");
134 }
135
136 #[test]
137 fn test_mysql_schema_qualified() {
138 assert_eq!(quote_mysql_identifier("mydb.v_user"), "`mydb`.`v_user`");
139 }
140
141 #[test]
142 fn test_mysql_three_part_name() {
143 assert_eq!(quote_mysql_identifier("catalog.schema.table"), "`catalog`.`schema`.`table`");
144 }
145
146 #[test]
147 fn test_sqlite_simple_identifier() {
148 assert_eq!(quote_sqlite_identifier("v_user"), "\"v_user\"");
149 }
150
151 #[test]
152 fn test_sqlite_schema_qualified() {
153 assert_eq!(quote_sqlite_identifier("main.v_user"), "\"main\".\"v_user\"");
154 }
155
156 #[test]
157 fn test_sqlite_three_part_name() {
158 assert_eq!(
159 quote_sqlite_identifier("catalog.schema.table"),
160 "\"catalog\".\"schema\".\"table\""
161 );
162 }
163
164 #[test]
165 fn test_sqlserver_simple_identifier() {
166 assert_eq!(quote_sqlserver_identifier("v_user"), "[v_user]");
167 }
168
169 #[test]
170 fn test_sqlserver_schema_qualified() {
171 assert_eq!(quote_sqlserver_identifier("dbo.v_user"), "[dbo].[v_user]");
172 }
173
174 #[test]
175 fn test_sqlserver_three_part_name() {
176 assert_eq!(
177 quote_sqlserver_identifier("catalog.schema.table"),
178 "[catalog].[schema].[table]"
179 );
180 }
181}