sui_gql_client/queries/
multi_get_objects.rs

1use af_sui_types::{Address, Object, Version};
2use itertools::Itertools as _;
3use sui_gql_schema::scalars::Base64Bcs;
4
5use super::fragments::ObjectKey;
6use crate::queries::Error;
7use crate::{GraphQlClient, GraphQlResponseExt as _, schema};
8
9pub(super) async fn query<C: GraphQlClient>(
10    client: &C,
11    objects: impl IntoIterator<Item = (Address, Version)> + Send,
12) -> super::Result<Vec<Object>, C> {
13    let mut object_keys = objects
14        .into_iter()
15        .sorted()
16        .dedup()
17        .map(|(object_id, version)| ObjectKey { object_id, version })
18        .collect_vec();
19
20    let vars = Variables { keys: &object_keys };
21
22    let data = client
23        .query::<Query, _>(vars)
24        .await
25        .map_err(Error::Client)?
26        .try_into_data()?;
27
28    graphql_extract::extract!(data => {
29        objects: multi_get_objects
30    });
31
32    let returned = objects
33        .into_iter()
34        .flatten()
35        .filter_map(|o| o.object)
36        .map(Base64Bcs::into_inner)
37        .inspect(|o| {
38            object_keys
39                .iter()
40                .position(|k| k.object_id == o.object_id() && k.version == o.version())
41                .map(|p| object_keys.swap_remove(p));
42        })
43        .collect_vec();
44
45    if !object_keys.is_empty() {
46        return Err(Error::MissingData(format!("Objects {object_keys:?}")));
47    }
48    Ok(returned)
49}
50
51#[cfg(test)]
52#[allow(clippy::unwrap_used)]
53#[test]
54fn gql_output() -> color_eyre::Result<()> {
55    use cynic::QueryBuilder as _;
56
57    // Variables don't matter, we just need it so taht `Query::build()` compiles
58    let vars = Variables { keys: &[] };
59
60    let operation = Query::build(vars);
61    insta::assert_snapshot!(operation.query, @r###"
62    query Query($keys: [ObjectKey!]!) {
63      multiGetObjects(keys: $keys) {
64        object: bcs
65      }
66    }
67    "###);
68    Ok(())
69}
70
71#[derive(cynic::QueryVariables, Clone, Debug)]
72struct Variables<'a> {
73    keys: &'a [ObjectKey],
74}
75
76#[derive(cynic::QueryFragment, Clone, Debug)]
77#[cynic(variables = "Variables")]
78struct Query {
79    #[arguments(keys: $keys)]
80    multi_get_objects: Vec<Option<ObjectGql>>,
81}
82
83#[derive(cynic::QueryFragment, Debug, Clone)]
84#[cynic(graphql_type = "Object")]
85struct ObjectGql {
86    #[cynic(alias, rename = "bcs")]
87    object: Option<Base64Bcs<Object>>,
88}