1use std::borrow::Cow;
15
16use core::fmt::{Display, Formatter};
17use core::str::FromStr;
18
19pub const MAX_LENGTH: usize = 63;
21
22const fn validate(input: &str) -> Option<ParseError> {
24 if input.is_empty() {
25 return Some(ParseError::Empty);
26 }
27
28 if input.len() > MAX_LENGTH {
29 return Some(ParseError::TooLong);
30 }
31
32 let bytes = input.as_bytes();
33 let mut index = 0;
34
35 while index < bytes.len() {
36 if bytes[index] == 0 {
37 return Some(ParseError::ContainsNul);
38 }
39 index += 1;
40 }
41
42 None
43}
44
45#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, serde::Serialize, serde::Deserialize)]
50#[serde(try_from = "String")]
51struct Identifier(Cow<'static, str>);
52
53impl TryFrom<String> for Identifier {
54 type Error = ParseError;
55
56 fn try_from(value: String) -> Result<Self, Self::Error> {
57 value.parse()
58 }
59}
60
61impl Identifier {
62 #[must_use]
68 const fn from_static_or_panic(input: &'static str) -> Self {
69 match validate(input) {
70 Some(error) => panic!("{}", error.message()),
71 None => Self(Cow::Borrowed(input)),
72 }
73 }
74
75 #[must_use]
77 fn as_str(&self) -> &str {
78 &self.0
79 }
80}
81
82impl Display for Identifier {
83 fn fmt(&self, formatter: &mut Formatter<'_>) -> core::fmt::Result {
84 write!(formatter, "{}", self.0)
85 }
86}
87
88impl AsRef<str> for Identifier {
89 fn as_ref(&self) -> &str {
90 &self.0
91 }
92}
93
94impl FromStr for Identifier {
95 type Err = ParseError;
96
97 fn from_str(input: &str) -> Result<Self, Self::Err> {
98 match validate(input) {
99 Some(error) => Err(error),
100 None => Ok(Self(Cow::Owned(input.to_owned()))),
101 }
102 }
103}
104
105#[derive(Debug, Clone, Copy, PartialEq, Eq)]
107pub enum ParseError {
108 Empty,
110
111 TooLong,
113
114 ContainsNul,
116}
117
118impl ParseError {
119 #[must_use]
121 pub const fn message(&self) -> &'static str {
122 match self {
123 Self::Empty => "identifier cannot be empty",
124 Self::TooLong => "identifier exceeds maximum length",
125 Self::ContainsNul => "identifier cannot contain NUL bytes",
126 }
127 }
128}
129
130impl Display for ParseError {
131 fn fmt(&self, formatter: &mut Formatter<'_>) -> core::fmt::Result {
132 write!(formatter, "{}", self.message())
133 }
134}
135
136impl std::error::Error for ParseError {}
137
138macro_rules! define_identifier_type {
140 ($(#[$meta:meta])* $name:ident, $test_mod:ident) => {
141 $(#[$meta])*
142 #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, serde::Serialize, serde::Deserialize)]
143 #[serde(try_from = "String")]
144 pub struct $name(Identifier);
145
146 impl TryFrom<String> for $name {
147 type Error = ParseError;
148
149 fn try_from(value: String) -> Result<Self, Self::Error> {
150 value.parse()
151 }
152 }
153
154 impl $name {
155 #[must_use]
161 pub const fn from_static_or_panic(input: &'static str) -> Self {
162 Self(Identifier::from_static_or_panic(input))
163 }
164
165 #[must_use]
167 pub fn as_str(&self) -> &str {
168 self.0.as_str()
169 }
170 }
171
172 impl Display for $name {
173 fn fmt(&self, formatter: &mut Formatter<'_>) -> core::fmt::Result {
174 write!(formatter, "{}", self.0)
175 }
176 }
177
178 impl AsRef<str> for $name {
179 fn as_ref(&self) -> &str {
180 self.0.as_ref()
181 }
182 }
183
184 impl FromStr for $name {
185 type Err = ParseError;
186
187 fn from_str(input: &str) -> Result<Self, Self::Err> {
188 Identifier::from_str(input).map(Self)
189 }
190 }
191
192 #[cfg(test)]
193 mod $test_mod {
194 use super::*;
195
196 #[test]
197 fn parse_valid() {
198 let value: $name = "test".parse().unwrap();
199 assert_eq!(value.to_string(), "test");
200 }
201
202 #[test]
203 fn parse_valid_with_space() {
204 let value: $name = "test value".parse().unwrap();
205 assert_eq!(value.to_string(), "test value");
206 }
207
208 #[test]
209 fn parse_empty_fails() {
210 let result: Result<$name, _> = "".parse();
211 assert!(matches!(result, Err(ParseError::Empty)));
212 }
213
214 #[test]
215 fn parse_contains_nul_fails() {
216 let result: Result<$name, _> = "test\0value".parse();
217 assert!(matches!(result, Err(ParseError::ContainsNul)));
218 }
219
220 #[test]
221 fn parse_too_long_fails() {
222 let input = "a".repeat(MAX_LENGTH + 1);
223 let result: Result<$name, _> = input.parse();
224 assert!(matches!(result, Err(ParseError::TooLong)));
225 }
226 }
227 };
228}
229
230define_identifier_type!(
231 Table,
233 table
234);
235
236define_identifier_type!(
237 Schema,
239 schema
240);
241
242impl Schema {
243 pub const PUBLIC: Self = Self::from_static_or_panic("public");
245}
246
247#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, serde::Serialize, serde::Deserialize)]
249pub struct QualifiedTable {
250 pub schema: Schema,
252 pub table: Table,
254}
255
256impl Display for QualifiedTable {
257 fn fmt(&self, formatter: &mut Formatter<'_>) -> core::fmt::Result {
258 write!(formatter, "{}.{}", self.schema, self.table)
259 }
260}
261
262define_identifier_type!(
263 Column,
265 column
266);
267
268define_identifier_type!(
269 Index,
271 index
272);
273
274define_identifier_type!(
275 Constraint,
279 constraint
280);
281
282define_identifier_type!(
283 Extension,
285 extension
286);
287
288define_identifier_type!(
289 Sequence,
291 sequence
292);
293
294define_identifier_type!(
295 Function,
297 function
298);
299
300define_identifier_type!(
301 Trigger,
303 trigger
304);
305
306define_identifier_type!(
307 Domain,
309 domain
310);
311
312define_identifier_type!(
313 Type,
317 r#type
318);
319
320define_identifier_type!(
321 View,
323 view
324);
325
326define_identifier_type!(
327 Relation,
332 relation
333);
334
335impl From<Table> for Relation {
336 fn from(table: Table) -> Self {
337 Self(table.0)
338 }
339}
340
341impl From<View> for Relation {
342 fn from(view: View) -> Self {
343 Self(view.0)
344 }
345}
346
347define_identifier_type!(
348 MaterializedView,
350 materialized_view
351);
352
353impl From<MaterializedView> for Relation {
354 fn from(materialized_view: MaterializedView) -> Self {
355 Self(materialized_view.0)
356 }
357}
358
359define_identifier_type!(
360 Operator,
362 operator
363);
364
365define_identifier_type!(
366 Aggregate,
368 aggregate
369);
370
371define_identifier_type!(
372 Collation,
374 collation
375);
376
377define_identifier_type!(
378 Tablespace,
380 tablespace
381);
382
383define_identifier_type!(
384 Policy,
386 policy
387);
388
389define_identifier_type!(
390 Rule,
392 rule
393);
394
395define_identifier_type!(
396 Publication,
398 publication
399);
400
401define_identifier_type!(
402 Subscription,
404 subscription
405);
406
407define_identifier_type!(
408 ForeignServer,
410 foreign_server
411);
412
413define_identifier_type!(
414 ForeignDataWrapper,
416 foreign_data_wrapper
417);
418
419define_identifier_type!(
420 ForeignTable,
422 foreign_table
423);
424
425define_identifier_type!(
426 EventTrigger,
428 event_trigger
429);
430
431define_identifier_type!(
432 Language,
434 language
435);
436
437define_identifier_type!(
438 TextSearchConfiguration,
440 text_search_configuration
441);
442
443define_identifier_type!(
444 TextSearchDictionary,
446 text_search_dictionary
447);
448
449define_identifier_type!(
450 Conversion,
452 conversion
453);
454
455define_identifier_type!(
456 OperatorClass,
458 operator_class
459);
460
461define_identifier_type!(
462 OperatorFamily,
464 operator_family
465);
466
467define_identifier_type!(
468 AccessMethod,
470 access_method
471);
472
473define_identifier_type!(
474 StatisticsObject,
476 statistics_object
477);
478
479define_identifier_type!(
480 Database,
482 database
483);
484
485impl Database {
486 pub const POSTGRES: Self = Self::from_static_or_panic("postgres");
488}
489
490define_identifier_type!(
491 Role,
495 role
496);
497
498impl Role {
499 pub const POSTGRES: Self = Self::from_static_or_panic("postgres");
501}
502
503pub type User = Role;
507
508#[cfg(test)]
509mod tests {
510 use super::*;
511
512 mod identifier {
513 use super::*;
514
515 #[test]
516 fn parse_valid_simple() {
517 let identifier: Identifier = "users".parse().unwrap();
518 assert_eq!(identifier.to_string(), "users");
519 }
520
521 #[test]
522 fn parse_valid_with_space() {
523 let identifier: Identifier = "my table".parse().unwrap();
524 assert_eq!(identifier.to_string(), "my table");
525 }
526
527 #[test]
528 fn parse_valid_with_special_chars() {
529 let identifier: Identifier = "my-table.name".parse().unwrap();
530 assert_eq!(identifier.to_string(), "my-table.name");
531 }
532
533 #[test]
534 fn parse_valid_starting_with_digit() {
535 let identifier: Identifier = "1table".parse().unwrap();
536 assert_eq!(identifier.to_string(), "1table");
537 }
538
539 #[test]
540 fn parse_valid_max_length() {
541 let input = "a".repeat(MAX_LENGTH);
542 let identifier: Identifier = input.parse().unwrap();
543 assert_eq!(identifier.to_string(), input);
544 }
545
546 #[test]
547 fn parse_empty_fails() {
548 let result: Result<Identifier, _> = "".parse();
549 assert_eq!(result, Err(ParseError::Empty));
550 }
551
552 #[test]
553 fn parse_too_long_fails() {
554 let input = "a".repeat(MAX_LENGTH + 1);
555 let result: Result<Identifier, _> = input.parse();
556 assert_eq!(result, Err(ParseError::TooLong));
557 }
558
559 #[test]
560 fn parse_contains_nul_fails() {
561 let result: Result<Identifier, _> = "my\0table".parse();
562 assert_eq!(result, Err(ParseError::ContainsNul));
563 }
564 }
565}