jsonapis/builders/
relationship.rs

1use super::*;
2
3#[derive(Clone, Debug, Default, Eq, PartialEq)]
4pub struct RelationshipBuilder {
5    meta: Option<MetaOrAttrsBuilder>,
6    links: Option<LinksBuilder>,
7    data: Option<DataBuilder>,
8}
9
10impl Builder<'_> for RelationshipBuilder {
11    type Entity = Relationship;
12
13    fn finish(self) -> Result<Self::Entity, BuildErrors> {
14        Ok(Self::Entity {
15            meta: match self.meta {
16                None => None,
17                Some(meta) => Some(meta.finish()?),
18            },
19            links: match self.links {
20                None => None,
21                Some(links) => Some(links.finish()?),
22            },
23            data: match self.data {
24                None => None,
25                Some(data) => Some(data.finish()?),
26            },
27        })
28    }
29}
30
31impl RelationshipBuilder {
32    pub fn meta<M: Into<MetaOrAttrsBuilder>>(self, meta: M) -> Self {
33        Self {
34            meta: Some(meta.into()),
35            ..self
36        }
37    }
38
39    pub fn links<L: Into<LinksBuilder>>(self, links: L) -> Self {
40        Self {
41            links: Some(links.into()),
42            ..self
43        }
44    }
45
46    pub fn data<D: Into<DataBuilder>>(self, data: D) -> Self {
47        Self {
48            data: Some(data.into()),
49            ..self
50        }
51    }
52
53    pub fn meta1<N: ToString, V: Into<Value>>(self, name: N, meta1: V) -> Self {
54        let meta = self.meta.unwrap_or_default().item(name, meta1);
55
56        Self {
57            meta: Some(meta),
58            ..self
59        }
60    }
61
62    pub fn link<N: ToString, L: Into<LinkBuilder>>(
63        self,
64        name: N,
65        link: L,
66    ) -> Self {
67        let links = self.links.unwrap_or_default().link(name, link);
68
69        Self {
70            links: Some(links),
71            ..self
72        }
73    }
74}
75
76impl From<Relationship> for RelationshipBuilder {
77    fn from(relationship: Relationship) -> Self {
78        Self {
79            meta: relationship.meta.map(|meta| meta.into()),
80            links: relationship.links.map(|links| links.into()),
81            data: relationship.data.map(|data| data.into()),
82        }
83    }
84}
85
86impl<R: Into<ResourceBuilder>> From<R> for RelationshipBuilder {
87    fn from(resource: R) -> Self {
88        Self::default().data(resource.into())
89    }
90}
91
92#[cfg(test)]
93mod tests {
94    use super::*;
95    use crate::fixtures;
96
97    #[test]
98    fn empty() {
99        assert_eq!(
100            RelationshipBuilder::default().unwrap(),
101            Relationship {
102                meta: None,
103                links: None,
104                data: None,
105            },
106        );
107    }
108
109    #[test]
110    fn full() {
111        assert_eq!(
112            RelationshipBuilder::default()
113                .meta(
114                    MetaOrAttrsBuilder::default()
115                        .item("foo", 123)
116                        .item("bar", "qwe"),
117                )
118                .links(
119                    LinksBuilder::default()
120                        .self_(LinkBuilder::new("http://self.com"))
121                        .prev(
122                            LinkBuilder::new("http://prev.com").meta(
123                                MetaOrAttrsBuilder::default()
124                                    .item("foo", 123)
125                                    .item("bar", "qwe"),
126                            ),
127                        ),
128                )
129                .data(DataBuilder::Single(ResourceBuilder::new("qwerties")))
130                .unwrap(),
131            Relationship {
132                meta: Some(fixtures::meta_or_attrs()),
133                links: Some(Links {
134                    other: HashMap::new(),
135                    self_: Some(Link::String("http://self.com".into())),
136                    related: None,
137                    first: None,
138                    last: None,
139                    prev: Some(Link::Object(LinkObject {
140                        href: "http://prev.com".into(),
141                        meta: Some(fixtures::meta_or_attrs()),
142                    })),
143                    next: None,
144                    about: None,
145                }),
146                data: Some(Data::Single(Resource {
147                    type_: "qwerties".into(),
148                    id: None,
149                    meta: None,
150                    links: None,
151                    attributes: None,
152                    relationships: None,
153                })),
154            },
155        );
156    }
157
158    #[test]
159    fn full_delegators() {
160        assert_eq!(
161            RelationshipBuilder::default()
162                .meta1("foo", 123)
163                .meta1("bar", "qwe")
164                .link("self", LinkBuilder::new("http://self.com"))
165                .link(
166                    "prev",
167                    LinkBuilder::new("http://prev.com").meta(
168                        MetaOrAttrsBuilder::default()
169                            .item("foo", 123)
170                            .item("bar", "qwe"),
171                    )
172                )
173                .data(DataBuilder::Single(ResourceBuilder::new("qwerties")))
174                .unwrap(),
175            Relationship {
176                meta: Some(fixtures::meta_or_attrs()),
177                links: Some(Links {
178                    other: HashMap::new(),
179                    self_: Some(Link::String("http://self.com".into())),
180                    related: None,
181                    first: None,
182                    last: None,
183                    prev: Some(Link::Object(LinkObject {
184                        href: "http://prev.com".into(),
185                        meta: Some(fixtures::meta_or_attrs()),
186                    })),
187                    next: None,
188                    about: None,
189                }),
190                data: Some(Data::Single(Resource {
191                    type_: "qwerties".into(),
192                    id: None,
193                    meta: None,
194                    links: None,
195                    attributes: None,
196                    relationships: None,
197                })),
198            },
199        );
200    }
201
202    #[test]
203    fn with_data_from_resource() {
204        assert_eq!(
205            RelationshipBuilder::default()
206                .data(ResourceBuilder::new("qwerties"))
207                .unwrap(),
208            Relationship {
209                meta: None,
210                links: None,
211                data: Some(Data::Single(Resource {
212                    type_: "qwerties".into(),
213                    id: None,
214                    meta: None,
215                    links: None,
216                    attributes: None,
217                    relationships: None,
218                })),
219            },
220        );
221    }
222
223    #[test]
224    fn with_data_from_resources() {
225        assert_eq!(
226            RelationshipBuilder::default()
227                .data(vec![ResourceBuilder::new("qwerties")])
228                .unwrap(),
229            Relationship {
230                meta: None,
231                links: None,
232                data: Some(Data::Multiple(vec![Resource {
233                    type_: "qwerties".into(),
234                    id: None,
235                    meta: None,
236                    links: None,
237                    attributes: None,
238                    relationships: None,
239                }])),
240            },
241        );
242    }
243
244    #[test]
245    fn with_meta1_implicit() {
246        assert_eq!(
247            RelationshipBuilder::default()
248                .meta1("foo", 123)
249                .meta1("bar", "car")
250                .unwrap(),
251            Relationship {
252                meta: Some({
253                    let mut meta = MetaOrAttrs::new();
254                    meta.insert("foo".into(), Value::Number(123.into()));
255                    meta.insert("bar".into(), Value::String("car".into()));
256                    meta
257                }),
258                links: None,
259                data: None,
260            },
261        );
262    }
263
264    #[test]
265    fn with_link_implicit_from_str() {
266        assert_eq!(
267            RelationshipBuilder::default()
268                .link("self", "http://self.com")
269                .link("qwe", "http://qwe.com")
270                .unwrap(),
271            Relationship {
272                meta: None,
273                links: Some(fixtures::simple_links()),
274                data: None,
275            },
276        );
277    }
278
279    #[test]
280    fn implicit_from_entity() {
281        let relationship = Relationship {
282            meta: Some(fixtures::meta_or_attrs()),
283            links: Some(fixtures::simple_links()),
284            data: Some(Data::Single(Resource {
285                type_: "qwerties".into(),
286                id: Some("123".into()),
287                meta: None,
288                links: None,
289                attributes: None,
290                relationships: None,
291            })),
292        };
293
294        let builder: RelationshipBuilder = relationship.clone().into();
295
296        assert_eq!(builder.unwrap(), relationship);
297    }
298
299    #[test]
300    fn with_meta_implicit_from_entity() {
301        assert_eq!(
302            RelationshipBuilder::default()
303                .meta(fixtures::meta_or_attrs())
304                .unwrap(),
305            Relationship {
306                meta: Some(fixtures::meta_or_attrs()),
307                links: None,
308                data: None,
309            },
310        );
311    }
312
313    #[test]
314    fn with_links_implicit_from_entity() {
315        assert_eq!(
316            RelationshipBuilder::default()
317                .links(fixtures::simple_links())
318                .unwrap(),
319            Relationship {
320                meta: None,
321                links: Some(fixtures::simple_links()),
322                data: None,
323            },
324        );
325    }
326
327    #[test]
328    fn with_data_implicit_from_entity() {
329        assert_eq!(
330            RelationshipBuilder::default()
331                .data(Data::Single(Resource {
332                    type_: "qwerties".into(),
333                    id: Some("123".into()),
334                    meta: None,
335                    links: None,
336                    attributes: None,
337                    relationships: None,
338                }))
339                .unwrap(),
340            Relationship {
341                meta: None,
342                links: None,
343                data: Some(Data::Single(Resource {
344                    type_: "qwerties".into(),
345                    id: Some("123".into()),
346                    meta: None,
347                    links: None,
348                    attributes: None,
349                    relationships: None,
350                })),
351            },
352        );
353    }
354
355    #[test]
356    fn with_data_single_implicit_from_entity() {
357        assert_eq!(
358            RelationshipBuilder::default()
359                .data(Resource {
360                    type_: "qwerties".into(),
361                    id: Some("123".into()),
362                    meta: None,
363                    links: None,
364                    attributes: None,
365                    relationships: None,
366                })
367                .unwrap(),
368            Relationship {
369                meta: None,
370                links: None,
371                data: Some(Data::Single(Resource {
372                    type_: "qwerties".into(),
373                    id: Some("123".into()),
374                    meta: None,
375                    links: None,
376                    attributes: None,
377                    relationships: None,
378                })),
379            },
380        );
381    }
382}