1#[derive(Debug, Clone, PartialEq)]
4pub enum Value {
5 Null,
6 Integer(i64),
7 Real(f64),
8 Text(String),
9 Blob(Vec<u8>),
10}
11
12impl From<&str> for Value {
13 fn from(s: &str) -> Self {
14 Value::Text(s.to_owned())
15 }
16}
17
18impl From<String> for Value {
19 fn from(s: String) -> Self {
20 Value::Text(s)
21 }
22}
23
24impl From<i32> for Value {
25 fn from(n: i32) -> Self {
26 Value::Integer(i64::from(n))
27 }
28}
29
30impl From<i64> for Value {
31 fn from(n: i64) -> Self {
32 Value::Integer(n)
33 }
34}
35
36impl From<f64> for Value {
37 fn from(f: f64) -> Self {
38 Value::Real(f)
39 }
40}
41
42impl From<bool> for Value {
43 fn from(b: bool) -> Self {
44 Value::Integer(if b { 1 } else { 0 })
45 }
46}
47
48impl From<Vec<u8>> for Value {
49 fn from(b: Vec<u8>) -> Self {
50 Value::Blob(b)
51 }
52}
53
54impl<T: Into<Value>> From<Option<T>> for Value {
55 fn from(opt: Option<T>) -> Self {
56 match opt {
57 Some(v) => v.into(),
58 None => Value::Null,
59 }
60 }
61}
62
63#[cfg(feature = "libsql")]
64impl From<Value> for libsql::Value {
65 fn from(v: Value) -> Self {
66 match v {
67 Value::Null => libsql::Value::Null,
68 Value::Integer(n) => libsql::Value::Integer(n),
69 Value::Real(f) => libsql::Value::Real(f),
70 Value::Text(s) => libsql::Value::Text(s),
71 Value::Blob(b) => libsql::Value::Blob(b),
72 }
73 }
74}
75
76#[cfg(feature = "libsql")]
77impl From<libsql::Value> for Value {
78 fn from(v: libsql::Value) -> Self {
79 match v {
80 libsql::Value::Null => Value::Null,
81 libsql::Value::Integer(n) => Value::Integer(n),
82 libsql::Value::Real(f) => Value::Real(f),
83 libsql::Value::Text(s) => Value::Text(s),
84 libsql::Value::Blob(b) => Value::Blob(b),
85 }
86 }
87}
88
89#[cfg(feature = "rusqlite")]
90impl rusqlite::types::ToSql for Value {
91 fn to_sql(&self) -> rusqlite::Result<rusqlite::types::ToSqlOutput<'_>> {
92 match self {
93 Value::Null => Ok(rusqlite::types::ToSqlOutput::Owned(
94 rusqlite::types::Value::Null,
95 )),
96 Value::Integer(n) => Ok(rusqlite::types::ToSqlOutput::Owned(
97 rusqlite::types::Value::Integer(*n),
98 )),
99 Value::Real(f) => Ok(rusqlite::types::ToSqlOutput::Owned(
100 rusqlite::types::Value::Real(*f),
101 )),
102 Value::Text(s) => Ok(rusqlite::types::ToSqlOutput::Owned(
103 rusqlite::types::Value::Text(s.clone()),
104 )),
105 Value::Blob(b) => Ok(rusqlite::types::ToSqlOutput::Owned(
106 rusqlite::types::Value::Blob(b.clone()),
107 )),
108 }
109 }
110}
111
112#[cfg(feature = "postgres")]
113mod pg_conversions {
114 use postgres_types::ToSql;
115
116 use super::Value;
117
118 #[derive(Debug)]
120 struct PgNull;
121
122 impl postgres_types::ToSql for PgNull {
123 fn to_sql(
124 &self,
125 _ty: &postgres_types::Type,
126 _out: &mut bytes::BytesMut,
127 ) -> Result<postgres_types::IsNull, Box<dyn std::error::Error + Send + Sync>> {
128 Ok(postgres_types::IsNull::Yes)
129 }
130
131 fn accepts(_ty: &postgres_types::Type) -> bool {
132 true
133 }
134
135 postgres_types::to_sql_checked!();
136 }
137
138 #[derive(Debug)]
143 struct FlexibleText(String);
144
145 impl postgres_types::ToSql for FlexibleText {
146 fn to_sql(
147 &self,
148 ty: &postgres_types::Type,
149 out: &mut bytes::BytesMut,
150 ) -> Result<postgres_types::IsNull, Box<dyn std::error::Error + Send + Sync>> {
151 if *ty == postgres_types::Type::UUID {
152 let uuid: uuid::Uuid = self.0.parse()?;
153 uuid.to_sql(ty, out)
154 } else {
155 self.0.to_sql(ty, out)
156 }
157 }
158
159 fn accepts(ty: &postgres_types::Type) -> bool {
160 *ty == postgres_types::Type::UUID || <String as postgres_types::ToSql>::accepts(ty)
161 }
162
163 postgres_types::to_sql_checked!();
164 }
165
166 pub fn to_pg_params(params: &[Value]) -> Vec<Box<dyn ToSql + Sync + Send>> {
169 params
170 .iter()
171 .map(|v| -> Box<dyn ToSql + Sync + Send> {
172 match v {
173 Value::Null => Box::new(PgNull),
174 Value::Integer(n) => Box::new(*n),
175 Value::Real(f) => Box::new(*f),
176 Value::Text(s) => Box::new(FlexibleText(s.clone())),
177 Value::Blob(b) => Box::new(b.clone()),
178 }
179 })
180 .collect()
181 }
182}
183
184#[cfg(feature = "postgres")]
185pub use pg_conversions::to_pg_params;