wick_sql/sqlx/sqlite/
serialize.rs

1use serde::ser::{SerializeMap, SerializeSeq};
2use serde::{Serialize, Serializer};
3use sqlx::sqlite::{SqliteRow, SqliteValueRef};
4use sqlx::{Column, Decode, Row, Sqlite, TypeInfo, Value, ValueRef};
5
6/// Can be used with serialize_with
7pub(crate) fn serialize_value_ref<S>(value: &SqliteValueRef, s: S) -> Result<S::Ok, S::Error>
8where
9  S: Serializer,
10{
11  if value.is_null() {
12    return s.serialize_none();
13  }
14
15  let info = value.type_info();
16  let value = value.to_owned();
17  let value = value.as_ref();
18
19  let name = info.name();
20
21  match name {
22    "NULL" => s.serialize_none(),
23
24    "TEXT" => {
25      let v: String = Decode::<Sqlite>::decode(value).unwrap();
26      s.serialize_str(&v)
27    }
28    "REAL" => {
29      let v: f64 = Decode::<Sqlite>::decode(value).unwrap();
30      s.serialize_f64(v)
31    }
32    "BLOB" => {
33      let v: Vec<u8> = Decode::<Sqlite>::decode(value).unwrap();
34      s.serialize_bytes(&v)
35    }
36    "INTEGER" => {
37      let v: i64 = Decode::<Sqlite>::decode(value).unwrap();
38      s.serialize_i64(v)
39    }
40    "NUMERIC" => {
41      let v: f64 = Decode::<Sqlite>::decode(value).unwrap();
42      s.serialize_f64(v)
43    }
44    "BOOLEAN" => {
45      let v: bool = Decode::<Sqlite>::decode(value).unwrap();
46      s.serialize_bool(v)
47    }
48    "DATE" => {
49      let v: wick_packet::DateTime = Decode::<Sqlite>::decode(value).map_err(serde::ser::Error::custom)?;
50      s.serialize_str(&v.to_rfc3339())
51    }
52    "TIME" => {
53      unimplemented!("TIME not supported");
54    }
55    "DATETIME" => {
56      let v: wick_packet::DateTime = Decode::<Sqlite>::decode(value).map_err(serde::ser::Error::custom)?;
57      s.serialize_str(&v.to_rfc3339())
58    }
59    _ => {
60      warn!(name=%name,"unknown type");
61      let v: String = Decode::<Sqlite>::decode(value).unwrap();
62      s.serialize_str(&v)
63    }
64  }
65}
66
67/// Can be used with serialize_with
68pub(crate) fn serialize_row_as_vec<S>(x: &SqliteRow, s: S) -> Result<S::Ok, S::Error>
69where
70  S: Serializer,
71{
72  let cols = x.columns();
73  let mut seq = s.serialize_seq(Some(cols.len()))?;
74  for c in cols {
75    let c: SqliteValueRef = x.try_get_raw(c.ordinal()).unwrap();
76    let c = SerValueRef(c);
77    seq.serialize_element(&c)?;
78  }
79  seq.end()
80}
81
82/// Can be used with serialize_with
83pub(crate) fn serialize_row_as_map<S>(x: &SqliteRow, s: S) -> Result<S::Ok, S::Error>
84where
85  S: Serializer,
86{
87  let cols = x.columns();
88  let mut map = s.serialize_map(Some(cols.len()))?;
89  for col in cols {
90    let c = x.try_get_raw(col.ordinal()).unwrap();
91    let c = SerValueRef(c);
92    map.serialize_entry(col.name(), &c)?;
93  }
94  map.end()
95}
96
97#[derive(Serialize)]
98pub(crate) struct SerVecRow(#[serde(serialize_with = "serialize_row_as_vec")] SqliteRow);
99
100#[derive(Serialize)]
101pub(crate) struct SerMapRow(#[serde(serialize_with = "serialize_row_as_map")] SqliteRow);
102
103impl From<SqliteRow> for SerMapRow {
104  fn from(row: SqliteRow) -> Self {
105    SerMapRow(row)
106  }
107}
108
109#[derive(Serialize)]
110pub(crate) struct SerValueRef<'r>(#[serde(serialize_with = "serialize_value_ref")] SqliteValueRef<'r>);
111
112impl From<SqliteRow> for SerVecRow {
113  fn from(row: SqliteRow) -> Self {
114    SerVecRow(row)
115  }
116}
117
118#[cfg(test)]
119mod integration_test {
120  use anyhow::Result;
121  use pretty_assertions::assert_eq;
122  use serde_json::Value;
123  use sqlx::{Connection, Executor, SqliteConnection};
124
125  use super::*;
126
127  fn read_row(row: &SqliteRow) -> Vec<Value> {
128    let columns = row.columns();
129    let mut result: Vec<Value> = Vec::with_capacity(columns.len());
130    for c in columns {
131      let value = row.try_get_raw(c.ordinal()).unwrap();
132      let value = SerValueRef(value);
133      let value = serde_json::to_value(&value).unwrap();
134      result.push(value);
135    }
136    result
137  }
138
139  async fn connect() -> SqliteConnection {
140    let db = std::env::var("SQLITE_DB").unwrap();
141    let conn_string = format!("file://{}", db);
142
143    SqliteConnection::connect(&conn_string).await.unwrap()
144  }
145
146  #[test_logger::test(tokio::test)]
147  async fn test_int() -> Result<()> {
148    let mut conn = connect().await;
149    let row = conn.fetch_one("select cast(3 as integer);").await?;
150    let row = read_row(&row);
151    assert_eq!(row[0].as_i64().unwrap(), 3);
152    Ok(())
153  }
154
155  #[test_logger::test(tokio::test)]
156  async fn test_map() -> Result<()> {
157    // use sqlx::types::chrono;
158    let mut conn = connect().await;
159
160    let row = conn
161      .fetch_one("select cast(1 as tinyint) as foo, cast('hello' as nvarchar(50)) as bar")
162      .await?;
163    let row = SerMapRow::from(row);
164    let row = serde_json::to_string(&row).unwrap();
165    assert_eq!(row, r#"{"foo":1,"bar":"hello"}"#);
166    Ok(())
167  }
168}