From b315de338163ffc760e0a522cb9ed65d61bfdf2d Mon Sep 17 00:00:00 2001 From: Alex Kotov Date: Wed, 3 Aug 2022 01:09:53 +0400 Subject: [PATCH] Add struct field Document.errors --- examples/builders.rs | 1 + src/builders/document.rs | 123 +++++++++++++++++++++++++++++++++++---- src/entities/document.rs | 9 ++- src/entities/mod.rs | 40 +++++++++++++ 4 files changed, 162 insertions(+), 11 deletions(-) diff --git a/examples/builders.rs b/examples/builders.rs index 413b77b..70c7a66 100644 --- a/examples/builders.rs +++ b/examples/builders.rs @@ -142,6 +142,7 @@ fn main() { }), }), ]), + "errors": json!(null), }); let actual_json = serde_json::to_string(&document).unwrap(); diff --git a/src/builders/document.rs b/src/builders/document.rs index d71ef94..6b1b280 100644 --- a/src/builders/document.rs +++ b/src/builders/document.rs @@ -6,12 +6,26 @@ pub struct DocumentBuilder { meta: Option, links: Option, data: Option, + errors: Option>, } impl Builder<'_> for DocumentBuilder { type Entity = Document; fn finish(self) -> Result { + let errors = match self.errors { + None => None, + Some(errors) => { + let mut new_errors = Vec::new(); + + for error in errors { + new_errors.push(error.finish()?); + } + + Some(new_errors) + } + }; + Ok(Self::Entity { jsonapi: match self.jsonapi { None => None, @@ -29,6 +43,7 @@ impl Builder<'_> for DocumentBuilder { None => None, Some(data) => Some(data.finish()?), }, + errors, }) } } @@ -62,6 +77,19 @@ impl DocumentBuilder { } } + pub fn errors>(self, errors: Vec) -> Self { + let mut new_errors = Vec::new(); + + for error in errors { + new_errors.push(error.into()); + } + + Self { + errors: Some(new_errors), + ..self + } + } + pub fn meta1>(self, name: N, meta1: V) -> Self { let meta = self.meta.unwrap_or_default().item(name, meta1); @@ -83,15 +111,39 @@ impl DocumentBuilder { ..self } } + + pub fn error>(self, error: E) -> Self { + let mut errors = self.errors.unwrap_or_default(); + errors.push(error.into()); + + Self { + errors: Some(errors), + ..self + } + } } impl From for DocumentBuilder { fn from(document: Document) -> Self { + let errors = match document.errors { + None => None, + Some(errors) => { + let mut new_errors = Vec::new(); + + for error in errors { + new_errors.push(error.into()); + } + + Some(new_errors) + } + }; + Self { jsonapi: document.jsonapi.map(|jsonapi| jsonapi.into()), meta: document.meta.map(|meta| meta.into()), links: document.links.map(|links| links.into()), data: document.data.map(|data| data.into()), + errors, } } } @@ -127,6 +179,19 @@ mod tests { } } + fn errors() -> Vec { + vec![Error { + id: Some("789".into()), + links: None, + status: None, + code: None, + title: None, + detail: None, + source: None, + meta: None, + }] + } + #[test] fn empty() { assert_eq!( @@ -136,6 +201,7 @@ mod tests { meta: None, links: None, data: None, + errors: None, }, ); } @@ -156,6 +222,7 @@ mod tests { .link("qwe", LinkBuilder::new("http://qwe.com")), ) .data(DataBuilder::Single(ResourceBuilder::new("qwerties"))) + .errors(vec![ErrorBuilder::default().id("789")]) .unwrap(), Document { jsonapi: Some(JsonApi { @@ -172,6 +239,7 @@ mod tests { attributes: None, relationships: None, })), + errors: Some(errors()), }, ); } @@ -186,6 +254,7 @@ mod tests { .link("self", LinkBuilder::new("http://self.com")) .link("qwe", LinkBuilder::new("http://qwe.com")) .data(DataBuilder::Single(ResourceBuilder::new("qwerties"))) + .error(ErrorBuilder::default().id("789")) .unwrap(), Document { jsonapi: Some(JsonApi { @@ -202,6 +271,7 @@ mod tests { attributes: None, relationships: None, })), + errors: Some(errors()), }, ); } @@ -220,6 +290,7 @@ mod tests { meta: None, links: None, data: None, + errors: None, }, ); } @@ -238,6 +309,7 @@ mod tests { meta: None, links: None, data: None, + errors: None, }, ); } @@ -257,6 +329,7 @@ mod tests { meta: Some(meta()), links: None, data: None, + errors: None, }, ); } @@ -294,6 +367,7 @@ mod tests { about: None, }), data: None, + errors: None, }, ); } @@ -318,6 +392,7 @@ mod tests { attributes: None, relationships: None, }])), + errors: None, }, ); } @@ -340,6 +415,7 @@ mod tests { attributes: None, relationships: None, })), + errors: None, }, ); } @@ -362,6 +438,23 @@ mod tests { attributes: None, relationships: None, }])), + errors: None, + }, + ); + } + + #[test] + fn with_errors() { + assert_eq!( + DocumentBuilder::default() + .errors(vec![ErrorBuilder::default().id("789")]) + .unwrap(), + Document { + jsonapi: None, + meta: None, + links: None, + data: None, + errors: Some(errors()), }, ); } @@ -383,6 +476,7 @@ mod tests { }), links: None, data: None, + errors: None, }, ); } @@ -415,6 +509,7 @@ mod tests { about: None, }), data: None, + errors: None, }, ); } @@ -427,16 +522,7 @@ mod tests { meta: Some(meta()), }), meta: Some(meta()), - links: Some(Links { - other: HashMap::new(), - self_: Some(Link::String("http://self.com".into())), - related: Some(Link::String("http://related.com".into())), - first: None, - last: None, - prev: None, - next: None, - about: None, - }), + links: Some(links()), data: Some(Data::Single(Resource { type_: "qwerties".into(), id: Some("123".into()), @@ -445,6 +531,7 @@ mod tests { attributes: None, relationships: None, })), + errors: Some(errors()), }; let builder: DocumentBuilder = document.clone().into(); @@ -461,6 +548,7 @@ mod tests { meta: Some(meta()), links: None, data: None, + errors: None, }, ); } @@ -474,6 +562,21 @@ mod tests { meta: None, links: Some(links()), data: None, + errors: None, + }, + ); + } + + #[test] + fn with_errors_implicit_from_entity() { + assert_eq!( + DocumentBuilder::default().errors(errors()).unwrap(), + Document { + jsonapi: None, + meta: None, + links: None, + data: None, + errors: Some(errors()), }, ); } diff --git a/src/entities/document.rs b/src/entities/document.rs index 17dcfcb..200a4c4 100644 --- a/src/entities/document.rs +++ b/src/entities/document.rs @@ -8,6 +8,7 @@ pub struct Document { pub meta: Option, pub links: Option, pub data: Option, + pub errors: Option>, } #[cfg(test)] @@ -24,13 +25,15 @@ mod tests { meta: None, links: None, data: None, + errors: None, }, ), "Document { \ jsonapi: None, \ meta: None, \ links: None, \ - data: None \ + data: None, \ + errors: None \ }", ); } @@ -43,12 +46,14 @@ mod tests { meta: None, links: None, data: None, + errors: None, }, Document { jsonapi: None, meta: None, links: None, data: None, + errors: None, }, ); @@ -58,6 +63,7 @@ mod tests { meta: None, links: None, data: None, + errors: None, }, Document { jsonapi: Some(JsonApi { @@ -67,6 +73,7 @@ mod tests { meta: None, links: None, data: None, + errors: None, }, ); } diff --git a/src/entities/mod.rs b/src/entities/mod.rs index 373ec30..b177e03 100644 --- a/src/entities/mod.rs +++ b/src/entities/mod.rs @@ -165,6 +165,22 @@ mod tests { }) } + fn expected_errors() -> Vec { + vec![Error { + id: Some("789".into()), + links: Some(expected_links()), + status: Some(HttpStatus(http::StatusCode::OK)), + code: Some("some code".into()), + title: Some("some title".into()), + detail: Some("some detail".into()), + source: Some(ErrorSource { + pointer: Some("/foo/0/bar/1".into()), + parameter: Some("car".into()), + }), + meta: Some(expected_meta_or_attrs()), + }] + } + #[test] fn serialize_and_deserialize() { let document = Document { @@ -182,6 +198,7 @@ mod tests { attributes: Some(expected_meta_or_attrs()), relationships: Some(expected_relationships()), }])), + errors: Some(expected_errors()), }; let serialized = serde_json::to_string(&document).unwrap(); @@ -204,6 +221,7 @@ mod tests { meta: Some(expected_meta_or_attrs()), links: Some(expected_links()), data: None, + errors: None, }; let value = json!({ @@ -229,6 +247,7 @@ mod tests { meta: None, links: None, data: None, + errors: None, }; let json = "{\"data\": null}"; @@ -245,6 +264,7 @@ mod tests { meta: None, links: None, data: Some(Data::Multiple(vec![])), + errors: None, }; let json = "{\"data\": []}"; @@ -268,6 +288,7 @@ mod tests { attributes: Some(expected_meta_or_attrs()), relationships: Some(expected_relationships()), })), + errors: None, }; let value = json!({ @@ -302,6 +323,7 @@ mod tests { attributes: Some(expected_meta_or_attrs()), relationships: Some(expected_relationships()), }])), + errors: None, }; let value = json!({ @@ -335,6 +357,7 @@ mod tests { meta: None, links: None, data: None, + errors: None, }; let json = serde_json::to_string(&document).unwrap(); @@ -348,6 +371,7 @@ mod tests { "meta": json!(null), "links": json!(null), "data": json!(null), + "errors": json!(null), }) ); } @@ -369,6 +393,7 @@ mod tests { attributes: Some(expected_meta_or_attrs()), relationships: Some(expected_relationships()), }])), + errors: Some(expected_errors()), }; let json = serde_json::to_string(&document).unwrap(); @@ -394,6 +419,21 @@ mod tests { "relationships": expected_relationships_value(), }), ]), + "errors": json!([ + json!({ + "id": json!("789"), + "links": expected_links_value(), + "status": Some(HttpStatus(http::StatusCode::OK)), + "code": json!("some code"), + "title": json!("some title"), + "detail": json!("some detail"), + "source": json!({ + "pointer": json!("/foo/0/bar/1"), + "parameter": json!("car"), + }), + "meta": expected_meta_or_attrs_value(), + }), + ]), }) ); }