-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
187 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"rust-analyzer.cargo.features": "all" | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
use scylla::cql_to_rust::{FromCqlVal, FromCqlValError}; | ||
use scylla::frame::response::result::CqlValue; | ||
use serde::{Deserialize, Serialize}; | ||
|
||
/// An implementation of a JSON type for ScyllaDB. | ||
/// | ||
/// Also implements `From<Json>` for `prost_types::Struct` and vice versa. | ||
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)] | ||
pub struct Json(pub serde_json::Map<String, serde_json::Value>); | ||
|
||
impl std::fmt::Debug for Json { | ||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||
self.0.fmt(f) | ||
} | ||
} | ||
|
||
impl scylla::frame::value::Value for Json { | ||
fn serialize(&self, buf: &mut Vec<u8>) -> Result<(), scylla::frame::value::ValueTooBig> { | ||
let data = serde_json::to_vec(&self.0).unwrap(); | ||
<Vec<u8> as scylla::frame::value::Value>::serialize(&data, buf) | ||
} | ||
} | ||
|
||
impl FromCqlVal<CqlValue> for Json { | ||
fn from_cql(cql_val: CqlValue) -> Result<Self, FromCqlValError> { | ||
let data = <String as FromCqlVal<CqlValue>>::from_cql(cql_val)?; | ||
|
||
serde_json::from_str(&data) | ||
.map(Json) | ||
.ok() | ||
.ok_or(FromCqlValError::BadCqlType) | ||
} | ||
} | ||
|
||
#[cfg(feature = "grpc")] | ||
impl From<Json> for prost_types::Struct { | ||
fn from(json: Json) -> Self { | ||
fn to_struct(json: serde_json::Map<String, serde_json::Value>) -> prost_types::Struct { | ||
prost_types::Struct { | ||
fields: json | ||
.into_iter() | ||
.map(|(k, v)| (k, serde_json_to_prost(v))) | ||
.collect(), | ||
} | ||
} | ||
|
||
fn serde_json_to_prost(json: serde_json::Value) -> prost_types::Value { | ||
use prost_types::value::Kind; | ||
use serde_json::Value; | ||
|
||
prost_types::Value { | ||
kind: Some(match json { | ||
Value::Null => Kind::NullValue(0 /* wot? */), | ||
Value::Bool(v) => Kind::BoolValue(v), | ||
Value::Number(n) => Kind::NumberValue(n.as_f64().expect("Non-f64-representable number")), | ||
Value::String(s) => Kind::StringValue(s), | ||
Value::Array(v) => Kind::ListValue(prost_types::ListValue { | ||
values: v.into_iter().map(serde_json_to_prost).collect(), | ||
}), | ||
Value::Object(v) => Kind::StructValue(to_struct(v)), | ||
}), | ||
} | ||
} | ||
|
||
to_struct(json.0) | ||
} | ||
} | ||
|
||
#[cfg(feature = "grpc")] | ||
impl From<prost_types::Struct> for Json { | ||
fn from(value: prost_types::Struct) -> Self { | ||
fn from_struct(struct_: prost_types::Struct) -> serde_json::Map<String, serde_json::Value> { | ||
struct_ | ||
.fields | ||
.into_iter() | ||
.map(|(k, v)| (k, prost_to_serde_json(v))) | ||
.collect() | ||
} | ||
|
||
fn prost_to_serde_json(value: prost_types::Value) -> serde_json::Value { | ||
use prost_types::value::Kind; | ||
use serde_json::Value; | ||
|
||
match value.kind.unwrap() { | ||
Kind::NullValue(_) => Value::Null, | ||
Kind::BoolValue(v) => Value::Bool(v), | ||
Kind::NumberValue(n) => { | ||
Value::Number(serde_json::Number::from_f64(n).expect("Non-f64-representable number")) | ||
} | ||
Kind::StringValue(s) => Value::String(s), | ||
Kind::ListValue(v) => Value::Array(v.values.into_iter().map(prost_to_serde_json).collect()), | ||
Kind::StructValue(v) => Value::Object(from_struct(v)), | ||
} | ||
} | ||
|
||
Json(from_struct(value)) | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use super::*; | ||
use serde_json::json; | ||
|
||
fn create_map() -> serde_json::Map<String, serde_json::Value> { | ||
let mut map = serde_json::Map::new(); | ||
map.insert("a".to_string(), json!(1)); | ||
map.insert("b".to_string(), json!("2")); | ||
map.insert("c".to_string(), json!([1, 2, 3])); | ||
map.insert("d".to_string(), json!({"e": "f"})); | ||
map | ||
} | ||
|
||
#[test] | ||
fn test_json() { | ||
let json = Json(create_map()); | ||
let data = serde_json::to_string(&json).unwrap(); | ||
assert_eq!(data, r#"{"a":1,"b":"2","c":[1,2,3],"d":{"e":"f"}}"#); | ||
} | ||
|
||
#[test] | ||
fn test_json_from_cql() { | ||
let json = Json(create_map()); | ||
let cql_val = CqlValue::Text(serde_json::to_string(&json).unwrap()); | ||
let json2 = Json::from_cql(cql_val).unwrap(); | ||
assert_eq!(json, json2); | ||
} | ||
|
||
#[test] | ||
fn test_json_from_cql_bad_type() { | ||
let cql_val = CqlValue::Int(1); | ||
let json = Json::from_cql(cql_val); | ||
assert!(json.is_err()); | ||
} | ||
|
||
#[test] | ||
fn test_json_from_cql_bad_json() { | ||
let cql_val = CqlValue::Text("bad json".to_string()); | ||
let json = Json::from_cql(cql_val); | ||
assert!(json.is_err()); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters