iota_sdk_graphql_client/api/
iota_names.rs1use std::str::FromStr;
8
9use cynic::QueryBuilder;
10use futures::Stream;
11use iota_types::{
12 Address,
13 iota_names::{NameFormat, NameRegistration, name::Name},
14};
15
16use crate::{
17 GraphQLClient,
18 api::define_query,
19 error::{GraphQLError, GraphQLResult},
20 pagination::{Page, PaginationFilter, PaginationFilterResponse},
21 query_types::{
22 IotaNamesAddressDefaultNameQueryFragment, IotaNamesAddressRegistrationsQueryFragment,
23 IotaNamesDefaultNameArgs, IotaNamesDefaultNameQueryFragment, IotaNamesRegistrationsArgs,
24 IotaNamesRegistrationsQueryFragment, ResolveIotaNamesAddressArgs,
25 ResolveIotaNamesAddressQueryFragment,
26 },
27 streams::stream_paginated_query,
28};
29
30define_query! {
31 #[derive(Clone)]
34 pub struct ListIotaNamesRegistrationsQuery {
35 client: GraphQLClient,
36 address: Address,
37 pagination: PaginationFilter,
38 }
39 output: GraphQLResult<Page<NameRegistration>>;
40}
41
42impl ListIotaNamesRegistrationsQuery {
43 pub fn pagination(mut self, pagination: PaginationFilter) -> Self {
45 self.pagination = pagination;
46 self
47 }
48
49 pub fn stream(self) -> impl Stream<Item = GraphQLResult<NameRegistration>> + Unpin {
52 let pagination = self.pagination.clone();
53 stream_paginated_query(move |page| self.clone().pagination(page).send(), pagination)
54 }
55
56 fn operation(
57 address: Address,
58 pagination: PaginationFilterResponse,
59 ) -> cynic::Operation<IotaNamesAddressRegistrationsQueryFragment, IotaNamesRegistrationsArgs>
60 {
61 IotaNamesAddressRegistrationsQueryFragment::build(IotaNamesRegistrationsArgs {
62 address,
63 after: pagination.after,
64 before: pagination.before,
65 first: pagination.first,
66 last: pagination.last,
67 })
68 }
69
70 async fn send(self) -> GraphQLResult<Page<NameRegistration>> {
71 let Self {
72 client,
73 pagination,
74 address,
75 } = self;
76 let pagination = client.pagination_filter(pagination).await;
77 let response = client
78 .run_query(&Self::operation(address, pagination))
79 .await?;
80
81 let IotaNamesAddressRegistrationsQueryFragment {
82 address:
83 Some(IotaNamesRegistrationsQueryFragment {
84 iota_names_registrations,
85 }),
86 } = response
87 else {
88 return Ok(Page::new_empty());
89 };
90
91 Ok(Page::new(
92 iota_names_registrations.page_info,
93 iota_names_registrations
94 .nodes
95 .into_iter()
96 .map(TryInto::try_into)
97 .collect::<GraphQLResult<Vec<_>>>()?,
98 ))
99 }
100}
101
102define_query! {
103 pub struct GetIotaNamesDefaultNameQuery {
106 client: GraphQLClient,
107 address: Address,
108 format: Option<NameFormat>,
109 }
110 output: GraphQLResult<Option<Name>>;
111}
112
113impl GetIotaNamesDefaultNameQuery {
114 pub fn format(mut self, format: NameFormat) -> Self {
116 self.format = Some(format);
117 self
118 }
119
120 async fn send(self) -> GraphQLResult<Option<Name>> {
121 let operation = IotaNamesAddressDefaultNameQueryFragment::build(IotaNamesDefaultNameArgs {
122 address: self.address,
123 format: self.format.map(Into::into),
124 });
125 let response = self.client.run_query(&operation).await?;
126
127 let IotaNamesAddressDefaultNameQueryFragment {
128 address:
129 Some(IotaNamesDefaultNameQueryFragment {
130 iota_names_default_name: Some(name),
131 }),
132 } = response
133 else {
134 return Ok(None);
135 };
136
137 Ok(Some(Name::from_str(&name).map_err(|source| {
138 GraphQLError::InvalidName { name, source }
139 })?))
140 }
141}
142
143define_query! {
144 pub struct GetIotaNamesLookupQuery {
147 client: GraphQLClient,
148 name: Name,
149 }
150 output: GraphQLResult<Option<Address>>;
151}
152
153impl GetIotaNamesLookupQuery {
154 async fn send(self) -> GraphQLResult<Option<Address>> {
155 let operation = ResolveIotaNamesAddressQueryFragment::build(ResolveIotaNamesAddressArgs {
156 name: self.name.to_string(),
157 });
158 let response = self.client.run_query(&operation).await?;
159
160 let ResolveIotaNamesAddressQueryFragment {
161 resolve_iota_names_address: Some(address),
162 } = response
163 else {
164 return Ok(None);
165 };
166
167 Ok(Some(address.address))
168 }
169}
170
171impl GraphQLClient {
172 pub fn iota_names_lookup(&self, name: Name) -> GetIotaNamesLookupQuery {
174 GetIotaNamesLookupQuery {
175 client: self.clone(),
176 name,
177 }
178 }
179
180 pub fn iota_names_registrations(&self, address: Address) -> ListIotaNamesRegistrationsQuery {
182 ListIotaNamesRegistrationsQuery {
183 client: self.clone(),
184 address,
185 pagination: PaginationFilter::default(),
186 }
187 }
188
189 pub fn iota_names_default_name(&self, address: Address) -> GetIotaNamesDefaultNameQuery {
191 GetIotaNamesDefaultNameQuery {
192 client: self.clone(),
193 address,
194 format: None,
195 }
196 }
197}
198
199#[cfg(all(test, not(target_arch = "wasm32")))]
200mod tests {
201 use iota_types::{Address, iota_names::NameFormat};
202
203 use crate::test_utils::{
204 assert_backward_page, assert_forward_page, backward_page, forward_page, sent_variables,
205 };
206
207 #[tokio::test]
208 async fn iota_names_lookup_sends_the_name() {
209 let vars = sent_variables(
210 "ResolveIotaNamesAddressQueryFragment",
211 |client| async move {
212 let _ = client
213 .iota_names_lookup("example.iota".parse().unwrap())
214 .await;
215 },
216 )
217 .await;
218 assert_eq!(vars["name"], "example.iota");
219 }
220
221 #[tokio::test]
222 async fn iota_names_default_name_sends_the_address_and_format() {
223 let vars = sent_variables(
224 "IotaNamesAddressDefaultNameQueryFragment",
225 |client| async move {
226 let _ = client
227 .iota_names_default_name(Address::FRAMEWORK)
228 .format(NameFormat::Dot)
229 .await;
230 },
231 )
232 .await;
233 assert_eq!(vars["address"], Address::FRAMEWORK.to_string());
234 assert_eq!(vars["format"], "DOT");
235
236 let vars = sent_variables(
237 "IotaNamesAddressDefaultNameQueryFragment",
238 |client| async move {
239 let _ = client.iota_names_default_name(Address::FRAMEWORK).await;
240 },
241 )
242 .await;
243 assert!(vars["format"].is_null());
244 }
245
246 #[tokio::test]
247 async fn iota_names_registrations_sends_the_address_and_pagination() {
248 let vars = sent_variables(
249 "IotaNamesAddressRegistrationsQueryFragment",
250 |client| async move {
251 let _ = client
252 .iota_names_registrations(Address::FRAMEWORK)
253 .pagination(backward_page())
254 .await;
255 },
256 )
257 .await;
258 assert_eq!(vars["address"], Address::FRAMEWORK.to_string());
259 assert_backward_page(&vars);
260
261 let vars = sent_variables(
262 "IotaNamesAddressRegistrationsQueryFragment",
263 |client| async move {
264 let _ = client
265 .iota_names_registrations(Address::FRAMEWORK)
266 .pagination(forward_page())
267 .await;
268 },
269 )
270 .await;
271 assert_forward_page(&vars);
272 }
273}