From fae72200e592b03886bbc7407bf626838b931dd7 Mon Sep 17 00:00:00 2001 From: Peter Maatman Date: Sat, 8 Aug 2020 12:23:07 +0200 Subject: [PATCH] sqlite: Add basic json implementation Fixes #608 --- sqlx-core/src/sqlite/types/json.rs | 44 ++++++++++++++++++++++++++++++ sqlx-core/src/sqlite/types/mod.rs | 2 ++ tests/sqlite/types.rs | 40 +++++++++++++++++++++++++++ 3 files changed, 86 insertions(+) create mode 100644 sqlx-core/src/sqlite/types/json.rs diff --git a/sqlx-core/src/sqlite/types/json.rs b/sqlx-core/src/sqlite/types/json.rs new file mode 100644 index 00000000..8f6bf6dc --- /dev/null +++ b/sqlx-core/src/sqlite/types/json.rs @@ -0,0 +1,44 @@ +use serde::{Deserialize, Serialize}; + +use crate::decode::Decode; +use crate::encode::{Encode, IsNull}; +use crate::error::BoxDynError; +use crate::sqlite::{ + type_info::DataType, Sqlite, SqliteArgumentValue, SqliteTypeInfo, SqliteValueRef, +}; +use crate::types::{Json, Type}; + +impl Type for Json { + fn type_info() -> SqliteTypeInfo { + SqliteTypeInfo(DataType::Text) + } + + fn compatible(ty: &SqliteTypeInfo) -> bool { + <&str as Type>::compatible(ty) + } +} + +impl Encode<'_, Sqlite> for Json +where + T: Serialize, +{ + fn encode_by_ref(&self, buf: &mut Vec>) -> IsNull { + let json_string_value = + serde_json::to_string(&self.0).expect("serde_json failed to convert to string"); + + Encode::::encode(json_string_value, buf) + } +} + +impl<'r, T> Decode<'r, Sqlite> for Json +where + T: 'r + Deserialize<'r>, +{ + fn decode(value: SqliteValueRef<'r>) -> Result { + let string_value = <&str as Decode>::decode(value)?; + + serde_json::from_str(&string_value) + .map(Json) + .map_err(Into::into) + } +} diff --git a/sqlx-core/src/sqlite/types/mod.rs b/sqlx-core/src/sqlite/types/mod.rs index 9553d5a2..84ca6154 100644 --- a/sqlx-core/src/sqlite/types/mod.rs +++ b/sqlx-core/src/sqlite/types/mod.rs @@ -35,4 +35,6 @@ mod bytes; mod chrono; mod float; mod int; +#[cfg(feature = "json")] +mod json; mod str; diff --git a/tests/sqlite/types.rs b/tests/sqlite/types.rs index a64572ea..340ce9b9 100644 --- a/tests/sqlite/types.rs +++ b/tests/sqlite/types.rs @@ -32,6 +32,46 @@ test_type!(bytes>(Sqlite, == vec![0_u8, 0, 0, 0, 0x52] )); +#[cfg(feature = "json")] +mod json_tests { + use super::*; + use serde_json::{json, Value as JsonValue}; + use sqlx::types::Json; + use sqlx_test::test_type; + + test_type!(json( + Sqlite, + "'\"Hello, World\"'" == json!("Hello, World"), + "'\"😎\"'" == json!("😎"), + "'\"🙋‍♀️\"'" == json!("🙋‍♀️"), + "'[\"Hello\",\"World!\"]'" == json!(["Hello", "World!"]) + )); + + #[derive(serde::Deserialize, serde::Serialize, Debug, PartialEq)] + struct Friend { + name: String, + age: u32, + } + + test_type!(json_struct>( + Sqlite, + "\'{\"name\":\"Joe\",\"age\":33}\'" == Json(Friend { name: "Joe".to_string(), age: 33 }) + )); + + // NOTE: This is testing recursive (and transparent) usage of the `Json` wrapper. You don't + // need to wrap the Vec in Json<_> to make the example work. + + #[derive(Debug, PartialEq, serde::Serialize, serde::Deserialize)] + struct Customer { + json_column: Json>, + } + + test_type!(json_struct_json_column>( + Sqlite, + "\'{\"json_column\":[1,2]}\'" == Json(Customer { json_column: Json(vec![1, 2]) }) + )); +} + #[cfg(feature = "chrono")] mod chrono { use super::*;