1use std::borrow::Borrow;
2use std::cmp::{Eq, PartialEq};
3use std::error::Error;
4use std::fmt;
5use std::hash::{Hash, Hasher};
6use std::io::prelude::*;
7use std::ops::Deref;
8use std::str::FromStr;
9use diesel::deserialize::{self, FromSql};
10use diesel::serialize::{self, IsNull, Output, ToSql};
11use diesel::pg::Pg;
12use serde::{Serialize, Deserialize};
13use crate::sql_types::*;
14
15#[cfg(feature = "with-actix-web")]
16use actix_web::dev::FromParam;
17
18#[derive(Clone, Debug, Serialize, Deserialize, FromSqlRow, AsExpression)]
22#[sql_type = "Citext"]
23pub struct CiString {
24 value: String,
25}
26
27
28impl CiString {
29 pub fn new() -> Self {
30 CiString {
31 value: String::new(),
32 }
33 }
34}
35
36#[cfg(feature = "with-actix-web")]
39impl FromParam for CiString {
40 type Err = actix_web::error::UrlParseError;
41 fn from_param(s: &str) -> Result<Self, Self::Err> {
42 Ok(CiString {
43 value: s.to_lowercase()
44 })
45 }
46}
47
48impl fmt::Display for CiString {
49 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
50 write!(f, "{}", self.value)
51 }
52}
53
54impl PartialEq for CiString {
55 fn eq(&self, other: &CiString) -> bool {
56 self.value == other.value
57 }
58}
59
60impl PartialEq<String> for CiString {
61 fn eq(&self, other: &String) -> bool {
62 self.value == other.to_lowercase()
63 }
64}
65
66impl PartialEq<&str> for CiString {
67 fn eq(&self, other: &&str) -> bool {
68 self.value == other.to_lowercase()
69 }
70}
71
72impl Eq for CiString {
73
74}
75
76impl Hash for CiString {
77 fn hash<H: Hasher>(&self, hasher: &mut H) {
78 self.value.hash(hasher);
79 }
80}
81
82impl AsRef<str> for CiString {
83 fn as_ref(&self) -> &str {
84 &*self.value
85 }
86}
87
88impl Borrow<str> for CiString {
89 fn borrow(&self) -> &str {
90 &*self.value
91 }
92}
93
94impl Deref for CiString {
95 type Target = String;
96
97 fn deref(&self) -> &String {
98 &self.value
99 }
100}
101
102impl FromStr for CiString {
103 type Err = fmt::Error;
104 fn from_str(s: &str) -> Result<Self, Self::Err> {
105 Ok(CiString { value: s.to_lowercase() })
106 }
107}
108
109impl Into<String> for CiString {
110 fn into(self) -> String {
111 self.value
112 }
113}
114
115impl From<String> for CiString {
116 fn from(value: String) -> Self {
117 CiString {
118 value: value.to_lowercase()
119 }
120 }
121}
122
123impl From<&str> for CiString {
124 fn from(value: &str) -> Self {
125 CiString {
126 value: value.to_lowercase()
127 }
128 }
129}
130
131impl FromSql<Citext, Pg> for CiString {
132 fn from_sql(bytes: Option<&[u8]>) -> deserialize::Result<Self> {
133 use std::str;
134 let string = str::from_utf8(not_none!(bytes))?;
135 Ok(CiString{ value: string.to_lowercase() })
136 }
137}
138
139impl ToSql<Citext, Pg> for CiString {
140 fn to_sql<W: Write>(&self, out: &mut Output<W, Pg>) -> serialize::Result {
141 out.write_all(self.value.as_bytes())
142 .map(|_| IsNull::No)
143 .map_err(|e| Box::new(e) as Box<Error + Send + Sync>)
144 }
145}
146
147impl FromSql<Citext, Pg> for String {
148 fn from_sql(bytes: Option<&[u8]>) -> deserialize::Result<Self> {
149 use std::str;
150 let string = str::from_utf8(not_none!(bytes))?;
151 Ok(string.to_lowercase())
152 }
153}
154
155impl ToSql<Citext, Pg> for String {
156 fn to_sql<W: Write>(&self, out: &mut Output<W, Pg>) -> serialize::Result {
157 out.write_all(self.to_lowercase().as_bytes())
158 .map(|_| IsNull::No)
159 .map_err(|e| Box::new(e) as Box<Error + Send + Sync>)
160 }
161}
162
163impl ToSql<Citext, Pg> for str {
164 fn to_sql<W: Write>(&self, out: &mut Output<W, Pg>) -> serialize::Result {
165 out.write_all(self.to_lowercase().as_bytes())
166 .map(|_| IsNull::No)
167 .map_err(|e| Box::new(e) as Box<Error + Send + Sync>)
168 }
169}
170