1#[cfg(feature = "acl")]
12use crate::acl::OIDMask;
13use crate::{OID, value::Value};
14use sqlx::encode::IsNull;
15use sqlx::error::BoxDynError;
16use sqlx::postgres;
17use sqlx::postgres::PgValueRef;
18use sqlx::sqlite;
19use sqlx::sqlite::SqliteValueRef;
20use sqlx::{Decode, Encode};
21use sqlx::{Postgres, Sqlite, Type};
22use std::borrow::Cow;
23
24type ResultIsNull = Result<IsNull, Box<dyn std::error::Error + Send + Sync + 'static>>;
25
26impl Type<Sqlite> for OID {
27 fn type_info() -> sqlite::SqliteTypeInfo {
28 <str as Type<Sqlite>>::type_info()
29 }
30}
31
32impl Type<Postgres> for OID {
33 fn type_info() -> postgres::PgTypeInfo {
34 <str as Type<Postgres>>::type_info()
35 }
36 fn compatible(ty: &postgres::PgTypeInfo) -> bool {
37 *ty == postgres::PgTypeInfo::with_name("VARCHAR")
38 || *ty == postgres::PgTypeInfo::with_name("TEXT")
39 }
40}
41
42impl postgres::PgHasArrayType for OID {
43 fn array_type_info() -> postgres::PgTypeInfo {
44 postgres::PgTypeInfo::with_name("_TEXT")
45 }
46
47 fn array_compatible(ty: &postgres::PgTypeInfo) -> bool {
48 *ty == postgres::PgTypeInfo::with_name("_TEXT")
49 || *ty == postgres::PgTypeInfo::with_name("_VARCHAR")
50 }
51}
52
53impl<'r> Decode<'r, Sqlite> for OID {
54 fn decode(value: SqliteValueRef<'r>) -> Result<Self, BoxDynError> {
55 let value = <&str as Decode<Sqlite>>::decode(value)?;
56 value.parse().map_err(Into::into)
57 }
58}
59
60impl<'r> Decode<'r, Postgres> for OID {
61 fn decode(value: PgValueRef<'r>) -> Result<Self, BoxDynError> {
62 let value = <&str as Decode<Postgres>>::decode(value)?;
63 value.parse().map_err(Into::into)
64 }
65}
66
67impl<'q> Encode<'q, Sqlite> for OID {
68 fn encode(self, args: &mut Vec<sqlite::SqliteArgumentValue<'q>>) -> ResultIsNull {
69 args.push(sqlite::SqliteArgumentValue::Text(Cow::Owned(
70 self.to_string(),
71 )));
72
73 Ok(IsNull::No)
74 }
75 fn encode_by_ref(&self, args: &mut Vec<sqlite::SqliteArgumentValue<'q>>) -> ResultIsNull {
76 args.push(sqlite::SqliteArgumentValue::Text(Cow::Owned(
77 self.to_string(),
78 )));
79 Ok(IsNull::No)
80 }
81
82 fn size_hint(&self) -> usize {
83 self.as_str().len()
84 }
85}
86
87impl Encode<'_, Postgres> for OID {
88 fn encode_by_ref(&self, buf: &mut postgres::PgArgumentBuffer) -> ResultIsNull {
89 <&str as Encode<Postgres>>::encode(self.as_str(), buf)
90 }
91 fn size_hint(&self) -> usize {
92 self.as_str().len()
93 }
94}
95
96#[cfg(feature = "acl")]
97impl Type<Sqlite> for OIDMask {
98 fn type_info() -> sqlite::SqliteTypeInfo {
99 <str as Type<Sqlite>>::type_info()
100 }
101}
102
103#[cfg(feature = "acl")]
104impl Type<Postgres> for OIDMask {
105 fn type_info() -> postgres::PgTypeInfo {
106 <str as Type<Postgres>>::type_info()
107 }
108 fn compatible(ty: &postgres::PgTypeInfo) -> bool {
109 *ty == postgres::PgTypeInfo::with_name("VARCHAR")
110 || *ty == postgres::PgTypeInfo::with_name("TEXT")
111 }
112}
113
114#[cfg(feature = "acl")]
115impl postgres::PgHasArrayType for OIDMask {
116 fn array_type_info() -> postgres::PgTypeInfo {
117 postgres::PgTypeInfo::with_name("_TEXT")
118 }
119
120 fn array_compatible(ty: &postgres::PgTypeInfo) -> bool {
121 *ty == postgres::PgTypeInfo::with_name("_TEXT")
122 || *ty == postgres::PgTypeInfo::with_name("_VARCHAR")
123 }
124}
125
126#[cfg(feature = "acl")]
127impl<'r> Decode<'r, Sqlite> for OIDMask {
128 fn decode(value: SqliteValueRef<'r>) -> Result<Self, BoxDynError> {
129 let value = <&str as Decode<Sqlite>>::decode(value)?;
130 value.parse().map_err(Into::into)
131 }
132}
133
134#[cfg(feature = "acl")]
135impl<'r> Decode<'r, Postgres> for OIDMask {
136 fn decode(value: PgValueRef<'r>) -> Result<Self, BoxDynError> {
137 let value = <&str as Decode<Postgres>>::decode(value)?;
138 value.parse().map_err(Into::into)
139 }
140}
141
142#[cfg(feature = "acl")]
143impl<'q> Encode<'q, Sqlite> for OIDMask {
144 fn encode(self, args: &mut Vec<sqlite::SqliteArgumentValue<'q>>) -> ResultIsNull {
145 args.push(sqlite::SqliteArgumentValue::Text(Cow::Owned(
146 self.to_string(),
147 )));
148
149 Ok(IsNull::No)
150 }
151 fn encode_by_ref(&self, args: &mut Vec<sqlite::SqliteArgumentValue<'q>>) -> ResultIsNull {
152 args.push(sqlite::SqliteArgumentValue::Text(Cow::Owned(
153 self.to_string(),
154 )));
155 Ok(IsNull::No)
156 }
157}
158
159#[cfg(feature = "acl")]
160impl Encode<'_, Postgres> for OIDMask {
161 #[allow(clippy::needless_borrows_for_generic_args)]
162 fn encode_by_ref(&self, buf: &mut postgres::PgArgumentBuffer) -> ResultIsNull {
163 <&str as Encode<Postgres>>::encode(&self.to_string(), buf)
164 }
165}
166
167impl Type<Sqlite> for Value {
168 fn type_info() -> sqlite::SqliteTypeInfo {
169 <str as Type<Sqlite>>::type_info()
170 }
171
172 fn compatible(ty: &sqlite::SqliteTypeInfo) -> bool {
173 <&str as Type<Sqlite>>::compatible(ty)
174 }
175}
176
177impl Type<Postgres> for Value {
178 fn type_info() -> postgres::PgTypeInfo {
179 postgres::PgTypeInfo::with_name("JSONB")
180 }
181}
182
183impl Encode<'_, Sqlite> for Value {
184 fn encode_by_ref(&self, buf: &mut Vec<sqlite::SqliteArgumentValue<'_>>) -> ResultIsNull {
185 let json_string_value =
186 serde_json::to_string(self).expect("serde_json failed to convert to string");
187 Encode::<Sqlite>::encode(json_string_value, buf)
188 }
189}
190
191impl<'r> Decode<'r, Sqlite> for Value {
192 fn decode(value: sqlite::SqliteValueRef<'r>) -> Result<Self, BoxDynError> {
193 let string_value = <&str as Decode<Sqlite>>::decode(value)?;
194
195 serde_json::from_str(string_value).map_err(Into::into)
196 }
197}
198
199impl Encode<'_, Postgres> for Value {
200 fn encode_by_ref(&self, buf: &mut postgres::PgArgumentBuffer) -> ResultIsNull {
201 buf.push(1);
202 serde_json::to_writer(&mut **buf, &self)
203 .expect("failed to serialize to JSON for encoding on transmission to the database");
204 Ok(IsNull::No)
205 }
206}
207
208impl<'r> Decode<'r, Postgres> for Value {
209 fn decode(value: postgres::PgValueRef<'r>) -> Result<Self, BoxDynError> {
210 let buf = value.as_bytes()?;
211 assert_eq!(buf[0], 1, "unsupported JSONB format version {}", buf[0]);
212 serde_json::from_slice(&buf[1..]).map_err(Into::into)
213 }
214}
215
216#[cfg(feature = "time")]
217mod time_impl {
218 use super::ResultIsNull;
219 use crate::time::Time;
220 use sqlx::postgres::{PgArgumentBuffer, PgTypeInfo, PgValueRef};
221 use sqlx::sqlite::{SqliteArgumentValue, SqliteTypeInfo, SqliteValueRef};
222 use sqlx::{Decode, Encode, Postgres, Sqlite, Type, encode::IsNull, error::BoxDynError};
223
224 const J2000_EPOCH_US: i64 = 946_684_800_000_000;
225
226 impl Type<Sqlite> for Time {
227 fn type_info() -> SqliteTypeInfo {
228 <i64 as Type<Sqlite>>::type_info()
229 }
230
231 fn compatible(ty: &SqliteTypeInfo) -> bool {
232 *ty == <i64 as Type<Sqlite>>::type_info()
233 || *ty == <i32 as Type<Sqlite>>::type_info()
234 || *ty == <i16 as Type<Sqlite>>::type_info()
235 || *ty == <i8 as Type<Sqlite>>::type_info()
236 }
237 }
238
239 impl<'q> Encode<'q, Sqlite> for Time {
240 fn encode_by_ref(&self, args: &mut Vec<SqliteArgumentValue<'q>>) -> ResultIsNull {
241 args.push(SqliteArgumentValue::Int64(
242 i64::try_from(self.timestamp_ns()).expect("timestamp too large"),
243 ));
244
245 Ok(IsNull::No)
246 }
247 }
248
249 impl<'r> Decode<'r, Sqlite> for Time {
250 fn decode(value: SqliteValueRef<'r>) -> Result<Self, BoxDynError> {
251 let value = <i64 as Decode<Sqlite>>::decode(value)?;
252 Ok(Time::from_timestamp_ns(
253 value.try_into().unwrap_or_default(),
254 ))
255 }
256 }
257
258 impl Type<Postgres> for Time {
259 fn type_info() -> PgTypeInfo {
260 PgTypeInfo::with_name("TIMESTAMPTZ")
261 }
262 fn compatible(ty: &PgTypeInfo) -> bool {
263 *ty == PgTypeInfo::with_name("TIMESTAMPTZ") || *ty == PgTypeInfo::with_name("TIMESTAMP")
264 }
265 }
266
267 impl Encode<'_, Postgres> for Time {
268 fn encode_by_ref(&self, buf: &mut PgArgumentBuffer) -> ResultIsNull {
269 let us =
270 i64::try_from(self.timestamp_us()).expect("timestamp too large") - J2000_EPOCH_US;
271 Encode::<Postgres>::encode(us, buf)
272 }
273
274 fn size_hint(&self) -> usize {
275 std::mem::size_of::<i64>()
276 }
277 }
278
279 impl<'r> Decode<'r, Postgres> for Time {
280 fn decode(value: PgValueRef<'r>) -> Result<Self, BoxDynError> {
281 let us: i64 = Decode::<Postgres>::decode(value)?;
282 Ok(Time::from_timestamp_us(
283 (us + J2000_EPOCH_US).try_into().unwrap_or_default(),
284 ))
285 }
286 }
287}