pgevolve_core/ir/
collation.rs1use serde::{Deserialize, Serialize};
8
9use crate::identifier::{Identifier, QualifiedName};
10use crate::ir::difference::Difference;
11use crate::ir::eq::{Equiv, field_difference};
12
13#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
15pub struct Collation {
16 pub qname: QualifiedName,
18 pub provider: CollationProvider,
20 pub lc_collate: String,
22 pub lc_ctype: String,
24 pub deterministic: bool,
26 pub version: Option<String>,
30 pub owner: Option<Identifier>,
32 pub comment: Option<String>,
34}
35
36impl Equiv for Collation {
37 fn differences(&self, other: &Self) -> Vec<Difference> {
38 let Self {
43 qname: _,
44 provider: _,
45 lc_collate: _,
46 lc_ctype: _,
47 deterministic: _,
48 version: _, owner: _,
50 comment: _,
51 } = self;
52 let mut out = Vec::new();
53 out.extend(field_difference("qname", &self.qname, &other.qname));
54 out.extend(field_difference(
55 "provider",
56 &format!("{:?}", self.provider),
57 &format!("{:?}", other.provider),
58 ));
59 out.extend(field_difference(
60 "lc_collate",
61 &self.lc_collate,
62 &other.lc_collate,
63 ));
64 out.extend(field_difference(
65 "lc_ctype",
66 &self.lc_ctype,
67 &other.lc_ctype,
68 ));
69 out.extend(field_difference(
70 "deterministic",
71 &format!("{:?}", self.deterministic),
72 &format!("{:?}", other.deterministic),
73 ));
74 out.extend(field_difference(
75 "owner",
76 &format!("{:?}", self.owner),
77 &format!("{:?}", other.owner),
78 ));
79 out.extend(field_difference(
80 "comment",
81 &format!("{:?}", self.comment),
82 &format!("{:?}", other.comment),
83 ));
84 out
85 }
86}
87
88#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
91#[serde(rename_all = "snake_case")]
92pub enum CollationProvider {
93 Libc,
95 Icu,
97 Builtin,
99}
100
101pub const BUILTIN_COLLATIONS: &[&str] =
104 &["default", "C", "POSIX", "und-x-icu", "unicode", "ucs_basic"];
105
106impl CollationProvider {
107 #[must_use]
109 pub const fn sql_keyword(self) -> &'static str {
110 match self {
111 Self::Libc => "libc",
112 Self::Icu => "icu",
113 Self::Builtin => "builtin",
114 }
115 }
116}
117
118#[cfg(test)]
119mod tests {
120 use super::*;
121
122 fn id(s: &str) -> Identifier {
123 Identifier::from_unquoted(s).unwrap()
124 }
125 fn qn(s: &str, n: &str) -> QualifiedName {
126 QualifiedName::new(id(s), id(n))
127 }
128
129 #[test]
130 fn collation_serde_round_trip() {
131 let c = Collation {
132 qname: qn("app", "case_insensitive"),
133 provider: CollationProvider::Icu,
134 lc_collate: "und".into(),
135 lc_ctype: "und".into(),
136 deterministic: false,
137 version: None,
138 owner: None,
139 comment: Some("CI collation".into()),
140 };
141 let json = serde_json::to_string(&c).unwrap();
142 let back: Collation = serde_json::from_str(&json).unwrap();
143 assert_eq!(c, back);
144 }
145
146 #[test]
147 fn provider_sql_keywords() {
148 assert_eq!(CollationProvider::Libc.sql_keyword(), "libc");
149 assert_eq!(CollationProvider::Icu.sql_keyword(), "icu");
150 assert_eq!(CollationProvider::Builtin.sql_keyword(), "builtin");
151 }
152}