Skip to content

Commit

Permalink
Derived Type, ParseFromJSON and IntoJSON for prost_wkt_types Struct a…
Browse files Browse the repository at this point in the history
…nd Value
  • Loading branch information
Nahuel-M committed Nov 12, 2023
1 parent a2e8b98 commit 6ca1479
Show file tree
Hide file tree
Showing 5 changed files with 241 additions and 0 deletions.
1 change: 1 addition & 0 deletions poem-openapi/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ bson = { version = "2.0.0", optional = true }
rust_decimal = { version = "1.22.0", optional = true }
humantime = { version = "2.1.0", optional = true }
ipnet = { version = "2.7.1", optional = true }
prost-wkt-types = { version = "0.5.0", optional = true}

[dev-dependencies]
tokio = { workspace = true, features = ["macros", "rt-multi-thread"] }
Expand Down
2 changes: 2 additions & 0 deletions poem-openapi/src/types/external/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,5 @@ mod url;
#[cfg(feature = "uuid")]
mod uuid;
mod vec;
#[cfg(feature = "prost-wkt-types")]
mod prost_wkt_types;
2 changes: 2 additions & 0 deletions poem-openapi/src/types/external/prost_wkt_types/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
mod r#struct;
mod value;
109 changes: 109 additions & 0 deletions poem-openapi/src/types/external/prost_wkt_types/struct.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
use crate::registry::{MetaSchema, MetaSchemaRef};
use crate::types::{ParseError, ParseFromJSON, ParseResult, ToJSON, Type};
use std::borrow::Cow;
use prost_wkt_types::Value;

impl Type for prost_wkt_types::Struct {
const IS_REQUIRED: bool = true;

type RawValueType = Self;

type RawElementValueType = <Value as Type>::RawValueType;

fn name() -> Cow<'static, str> {
"Protobuf Struct".into()
}

fn schema_ref() -> MetaSchemaRef {
MetaSchemaRef::Inline(Box::new(MetaSchema {
additional_properties: Some(Box::new(Value::schema_ref())),
..MetaSchema::new("object")
}))
}

fn as_raw_value(&self) -> Option<&Self::RawValueType> {
Some(self)
}

fn raw_element_iter<'a>(
&'a self,
) -> Box<dyn Iterator<Item = &'a Self::RawElementValueType> + 'a> {
self.fields.raw_element_iter()
}

fn is_empty(&self) -> bool {
self.fields.is_empty()
}
}

impl ParseFromJSON for prost_wkt_types::Struct {
fn parse_from_json(value: Option<serde_json::Value>) -> ParseResult<Self> {
let value = value.unwrap_or_default();
if let serde_json::Value::Object(_) = &value {
serde_json::from_value::<prost_wkt_types::Struct>(value)
.map_err(|e| ParseError::custom(e.to_string()))
} else {
Err(ParseError::expected_type(value))
}
}
}

impl ToJSON for prost_wkt_types::Struct {
fn to_json(&self) -> Option<serde_json::Value> {
serde_json::to_value(self).ok()
}
}

#[cfg(test)]
mod tests {
use std::collections::HashMap;
use prost_wkt_types::Value;
use serde_json::json;
use super::*;

#[test]
fn parse_from_parameters() {
let prost_struct = prost_wkt_types::Struct::parse_from_json(Some(json!(
{
"f1":10_f64,
"f2":"Hi",
"f3":true,
"f4":null,
"f5": {"fa": "Hello"},
"f6": [1,2,3]
}
)))
.unwrap();

assert_eq!(
prost_struct.fields.get("f1").unwrap(),
&Value::number(10_f64)
);
assert_eq!(
prost_struct.fields.get("f2").unwrap(),
&Value::string("Hi".to_string())
);
assert_eq!(
prost_struct.fields.get("f3").unwrap(),
&Value::bool(true)
);
assert_eq!(
prost_struct.fields.get("f4").unwrap(),
&Value::null()
);
assert_eq!(
prost_struct.fields.get("f5").unwrap(),
&Value::pb_struct(
HashMap::from([("fa".into(), Value::string("Hello".into()))])
)
);
assert_eq!(
prost_struct.fields.get("f6").unwrap(),
&Value::pb_list(
vec![Value::number(1_f64),
Value::number(2_f64),
Value::number(3_f64)]
)
);
}
}
127 changes: 127 additions & 0 deletions poem-openapi/src/types/external/prost_wkt_types/value.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
use std::borrow::Cow;
use crate::registry::{MetaSchema, MetaSchemaRef};
use prost_wkt_types::value::Kind;
use crate::types::{ParseError, ParseFromJSON, ParseResult, ToJSON, Type};

impl Type for prost_wkt_types::Value {
const IS_REQUIRED: bool = true;

type RawValueType = prost_wkt_types::Value;

type RawElementValueType = prost_wkt_types::Value;

fn name() -> Cow<'static, str> {
"Protobuf Value".into()
}

fn schema_ref() -> MetaSchemaRef {
MetaSchemaRef::Inline(Box::new(MetaSchema::ANY))
}

fn as_raw_value(&self) -> Option<&Self::RawValueType> {
Some(self)
}

fn raw_element_iter<'a>(
&'a self,
) -> Box<dyn Iterator<Item = &'a Self::RawElementValueType> + 'a> {
Box::new(self.as_raw_value().into_iter())
}
fn is_empty(&self) -> bool {
matches!(self.kind, Some(Kind::NullValue(_)) | None)
}
}


impl ParseFromJSON for prost_wkt_types::Value{
fn parse_from_json(value: Option<serde_json::Value>) -> ParseResult<Self> {
let value = value.unwrap_or_default();
serde_json::from_value(value).map_err(|e| ParseError::custom(e.to_string()))
}
}

impl ToJSON for prost_wkt_types::Value{
fn to_json(&self) -> Option<serde_json::Value> {
serde_json::to_value(self).ok()
}
}

#[cfg(test)]
mod tests {
use std::collections::HashMap;
use prost_wkt_types::Value;
use serde_json::json;
use super::*;

#[test]
fn parse_from_number() {
let value = Value::parse_from_json(Some(
json!(10_f64)
)).unwrap();
assert_eq!(
value,
Value::number(10_f64)
);
}

#[test]
fn parse_from_string() {
let value = Value::parse_from_json(Some(
json!("Hi")
)).unwrap();
assert_eq!(
value,
Value::string("Hi".into())
);
}

#[test]
fn parse_from_bool() {
let value = Value::parse_from_json(Some(
json!(true)
)).unwrap();
assert_eq!(
value,
Value::bool(true)
);
}

#[test]
fn parse_from_null() {
let value = Value::parse_from_json(Some(
json!(null)
)).unwrap();
assert_eq!(
value,
Value::null()
);
}

#[test]
fn parse_from_struct() {
let value = Value::parse_from_json(Some(
json!({"f1": "Hello"})
)).unwrap();
assert_eq!(
value,
Value::pb_struct(
HashMap::from([("f1".into(), Value::string("Hello".into()))])
)
);
}

#[test]
fn parse_from_list() {
let value = Value::parse_from_json(Some(
json!([1,2,3])
)).unwrap();
assert_eq!(
value,
Value::pb_list(
vec![Value::number(1_f64),
Value::number(2_f64),
Value::number(3_f64)]
)
);
}
}

0 comments on commit 6ca1479

Please sign in to comment.