am_api/resource/
relationship.rs1use crate::error::Error;
4use crate::request::context::{ContextContainer, RequestContext};
5use crate::resource::ErrorResponse;
6use crate::ApiClient;
7use async_stream::try_stream;
8use futures::Stream;
9use reqwest::Response;
10use serde::de::DeserializeOwned;
11use serde::{Deserialize, Serialize};
12use std::fmt::{Debug, Formatter};
13use std::hash::{Hash, Hasher};
14use std::sync::Arc;
15
16#[derive(Serialize, Deserialize, Clone)]
18#[serde(rename_all = "camelCase")]
19pub struct Relationship<T> {
20 #[serde(default)]
22 pub href: Option<String>,
23 #[serde(default)]
25 pub next: Option<String>,
26 #[serde(default = "Vec::default")]
28 pub data: Vec<T>,
29 #[serde(skip, default)]
31 context: Option<Arc<RequestContext>>,
32}
33
34impl<T> Relationship<T>
35where
36 T: Clone + DeserializeOwned + ContextContainer,
37{
38 pub fn iter(&self, client: &ApiClient) -> impl Stream<Item = Result<T, Error>> {
40 let relationship = self.clone();
41 let client = client.clone();
42 let context = relationship
43 .context
44 .clone()
45 .expect("context should always exist on relationships");
46
47 try_stream! {
48 let mut relationship = relationship;
49
50 loop {
51 for mut entry in relationship.data {
52 entry.set_context(context.clone());
53 yield entry;
54 }
55
56 let Some(next) = relationship.next.as_ref() else {
57 return;
58 };
59
60 let response = client.get(next.as_str()).query(&context.query).send().await?;
61 relationship = Self::try_relationship_response(response).await?;
62 }
63 }
64 }
65
66 async fn try_relationship_response(response: Response) -> Result<Self, Error> {
67 if !response.status().is_success() {
68 let error_response: ErrorResponse = response.json().await?;
69 return Err(Error::MusicError(error_response));
70 }
71
72 let result = response.json().await?;
73 Ok(result)
74 }
75}
76
77impl<T> ContextContainer for Relationship<T>
78where
79 T: ContextContainer,
80{
81 fn set_context(&mut self, context: Arc<RequestContext>) {
82 self.context = Some(context.clone());
83 self.data.set_context(context.clone());
84 }
85}
86
87impl<T> Debug for Relationship<T>
88where
89 T: Debug,
90{
91 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
92 f.debug_struct("Relationship")
93 .field("href", &self.href)
94 .field("next", &self.next)
95 .field("data", &self.data)
96 .finish()
97 }
98}
99
100impl<T> PartialEq for Relationship<T>
101where
102 T: PartialEq,
103{
104 fn eq(&self, other: &Self) -> bool {
105 self.href == other.href && self.next == other.next && self.data == other.data
106 }
107}
108
109impl<T> Eq for Relationship<T> where T: PartialEq + Eq {}
110
111impl<T> Hash for Relationship<T>
112where
113 T: Hash,
114{
115 fn hash<H: Hasher>(&self, state: &mut H) {
116 self.href.hash(state);
117 self.next.hash(state);
118 self.data.hash(state);
119 }
120}
121
122impl<T> Default for Relationship<T> {
123 fn default() -> Self {
124 Relationship {
125 href: None,
126 next: None,
127 data: Vec::default(),
128 context: None,
129 }
130 }
131}