1use crate::arguments::XuguArgumentValue;
2use crate::protocol::text::{ColumnFlags, ColumnType};
3use crate::{Xugu, XuguTypeInfo, XuguValueRef};
4
5use sqlx_core::decode::Decode;
6use sqlx_core::encode::{Encode, IsNull};
7use sqlx_core::error::BoxDynError;
8use sqlx_core::types::Type;
9use sqlx_core::value::ValueRef;
10use std::borrow::Cow;
11
12impl Type<Xugu> for str {
13 fn type_info() -> XuguTypeInfo {
14 XuguTypeInfo {
15 r#type: ColumnType::CHAR,
16 flags: ColumnFlags::empty(),
17 }
18 }
19
20 fn compatible(ty: &XuguTypeInfo) -> bool {
21 matches!(
22 ty.r#type,
23 ColumnType::BLOB
24 | ColumnType::BLOB_I
25 | ColumnType::BLOB_M
26 | ColumnType::BLOB_OM
27 | ColumnType::BLOB_S
28 | ColumnType::CLOB
29 | ColumnType::BINARY
30 | ColumnType::NUMERIC
31 | ColumnType::TINYINT
32 | ColumnType::SMALLINT
33 | ColumnType::INTEGER
34 | ColumnType::BIGINT
35 | ColumnType::BOOLEAN
36 | ColumnType::CHAR
37 | ColumnType::NCHAR
38 | ColumnType::GUID
39 | ColumnType::ROWID
40 | ColumnType::ROWVERSION
41 | ColumnType::ARRAY
42 | ColumnType::VECTOR
43 | ColumnType::HALFVEC
44 | ColumnType::SPARSEVEC
45
46 | ColumnType::POINT
48 | ColumnType::LSEG
49 | ColumnType::PATH
50 | ColumnType::BOX
51 | ColumnType::POLYGON
52 | ColumnType::LINE
53 | ColumnType::CIRCLE
54 | ColumnType::GEOMETRY
55 | ColumnType::GEOGRAPHY
56 | ColumnType::BOX2D
57 | ColumnType::BOX3D
58 | ColumnType::SPHEROID
59 | ColumnType::RASTER
60 )
61 }
62}
63
64impl<'q> Encode<'q, Xugu> for &'q str {
65 fn encode_by_ref(&self, args: &mut Vec<XuguArgumentValue<'q>>) -> Result<IsNull, BoxDynError> {
66 if self.is_empty() {
67 args.push(XuguArgumentValue::Str(Cow::Borrowed("\0")));
68 } else {
69 args.push(XuguArgumentValue::Str(Cow::Borrowed(*self)));
70 }
71
72 Ok(IsNull::No)
73 }
74}
75
76impl<'q> Decode<'q, Xugu> for &'q str {
77 fn decode(value: XuguValueRef<'q>) -> Result<Self, BoxDynError> {
78 value.as_str().map(map_empty)
79 }
80}
81
82impl Type<Xugu> for Box<str> {
83 fn type_info() -> XuguTypeInfo {
84 <&str as Type<Xugu>>::type_info()
85 }
86
87 fn compatible(ty: &XuguTypeInfo) -> bool {
88 <&str as Type<Xugu>>::compatible(ty)
89 }
90}
91
92impl Encode<'_, Xugu> for Box<str> {
93 fn encode(self, args: &mut Vec<XuguArgumentValue<'_>>) -> Result<IsNull, BoxDynError> {
94 if self.is_empty() {
95 args.push(XuguArgumentValue::Str(Cow::Borrowed("\0")));
96 } else {
97 args.push(XuguArgumentValue::Str(Cow::Owned(self.into_string())));
98 }
99
100 Ok(IsNull::No)
101 }
102
103 fn encode_by_ref(&self, args: &mut Vec<XuguArgumentValue<'_>>) -> Result<IsNull, BoxDynError> {
104 if self.is_empty() {
105 args.push(XuguArgumentValue::Str(Cow::Borrowed("\0")));
106 } else {
107 args.push(XuguArgumentValue::Str(Cow::Owned(
108 self.clone().into_string(),
109 )));
110 }
111
112 Ok(IsNull::No)
113 }
114}
115
116impl<'r> Decode<'r, Xugu> for Box<str> {
117 fn decode(value: XuguValueRef<'r>) -> Result<Self, BoxDynError> {
118 let ty = value.type_info().r#type;
119 if matches!(
120 ty,
121 ColumnType::TINYINT | ColumnType::SMALLINT | ColumnType::INTEGER | ColumnType::BIGINT
122 ) {
123 let num = <i64 as Decode<Xugu>>::decode(value)?;
124 return Ok(Box::from(num.to_string()));
125 }
126
127 value.as_str().map(map_empty).map(Box::from)
128 }
129}
130
131impl Type<Xugu> for String {
132 fn type_info() -> XuguTypeInfo {
133 <str as Type<Xugu>>::type_info()
134 }
135
136 fn compatible(ty: &XuguTypeInfo) -> bool {
137 <str as Type<Xugu>>::compatible(ty)
138 }
139}
140
141impl Encode<'_, Xugu> for String {
142 fn encode(self, args: &mut Vec<XuguArgumentValue<'_>>) -> Result<IsNull, BoxDynError> {
143 if self.is_empty() {
144 args.push(XuguArgumentValue::Str(Cow::Borrowed("\0")));
145 } else {
146 args.push(XuguArgumentValue::Str(Cow::Owned(self)));
147 }
148
149 Ok(IsNull::No)
150 }
151
152 fn encode_by_ref(&self, args: &mut Vec<XuguArgumentValue<'_>>) -> Result<IsNull, BoxDynError> {
153 if self.is_empty() {
154 args.push(XuguArgumentValue::Str(Cow::Borrowed("\0")));
155 } else {
156 args.push(XuguArgumentValue::Str(Cow::Owned(self.clone())));
157 }
158
159 Ok(IsNull::No)
160 }
161}
162
163impl Decode<'_, Xugu> for String {
164 fn decode(value: XuguValueRef<'_>) -> Result<Self, BoxDynError> {
165 let ty = value.type_info().r#type;
166 if matches!(
167 ty,
168 ColumnType::TINYINT | ColumnType::SMALLINT | ColumnType::INTEGER | ColumnType::BIGINT
169 ) {
170 let num = <i64 as Decode<Xugu>>::decode(value)?;
171 return Ok(num.to_string());
172 }
173
174 value.as_str().map(map_empty).map(ToOwned::to_owned)
175 }
176}
177
178impl Type<Xugu> for Cow<'_, str> {
179 fn type_info() -> XuguTypeInfo {
180 <&str as Type<Xugu>>::type_info()
181 }
182
183 fn compatible(ty: &XuguTypeInfo) -> bool {
184 <&str as Type<Xugu>>::compatible(ty)
185 }
186}
187
188impl<'q> Encode<'q, Xugu> for Cow<'q, str> {
189 fn encode(self, args: &mut Vec<XuguArgumentValue<'q>>) -> Result<IsNull, BoxDynError> {
190 if self.is_empty() {
191 args.push(XuguArgumentValue::Str(Cow::Borrowed("\0")));
192 } else {
193 args.push(XuguArgumentValue::Str(self));
194 }
195
196 Ok(IsNull::No)
197 }
198
199 fn encode_by_ref(&self, args: &mut Vec<XuguArgumentValue<'q>>) -> Result<IsNull, BoxDynError> {
200 if self.is_empty() {
201 args.push(XuguArgumentValue::Str(Cow::Borrowed("\0")));
202 } else {
203 args.push(XuguArgumentValue::Str(self.clone()));
204 }
205
206 Ok(IsNull::No)
207 }
208}
209
210impl<'r> Decode<'r, Xugu> for Cow<'r, str> {
211 fn decode(value: XuguValueRef<'r>) -> Result<Self, BoxDynError> {
212 let ty = value.type_info().r#type;
213 if matches!(
214 ty,
215 ColumnType::TINYINT | ColumnType::SMALLINT | ColumnType::INTEGER | ColumnType::BIGINT
216 ) {
217 let num = <i64 as Decode<Xugu>>::decode(value)?;
218 return Ok(Cow::Owned(num.to_string()));
219 }
220
221 value.as_str().map(map_empty).map(Cow::Borrowed)
222 }
223}
224
225fn map_empty(s: &str) -> &str {
227 if s == "\0" {
228 return "";
229 }
230 s
231}