sui_gql_client/queries/
full_objects.rs

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