sui_gql_client/queries/
objects_content.rs

1use std::collections::HashMap;
2
3use af_sui_types::Address;
4use futures::TryStreamExt as _;
5use sui_gql_schema::schema;
6
7use super::fragments::{MoveValueRaw, ObjectFilterV2};
8use super::objects_flat::Variables;
9use super::outputs::RawMoveStruct;
10use super::{Error, objects_flat};
11use crate::{GraphQlClient, GraphQlResponseExt as _, missing_data};
12
13pub(super) async fn query<C: GraphQlClient>(
14    client: &C,
15    object_ids: Vec<Address>,
16) -> super::Result<HashMap<Address, RawMoveStruct>, C> {
17    let vars = Variables {
18        after: None,
19        first: None,
20        filter: Some(ObjectFilterV2 {
21            object_ids: Some(&object_ids),
22            ..Default::default()
23        }),
24    };
25
26    let mut stream = std::pin::pin!(super::stream::forward(client, vars, request));
27
28    let mut raw_objs = HashMap::new();
29
30    while let Some(object) = stream.try_next().await? {
31        let object_id = object.object_id;
32        let struct_ = object
33            .as_move_object
34            .ok_or(missing_data!("Not a Move object"))?
35            .contents
36            .ok_or(missing_data!("Object contents"))?
37            .try_into()
38            .expect("Only structs can be top-level objects");
39        raw_objs.insert(object_id, struct_);
40    }
41
42    Ok(raw_objs)
43}
44
45type Query = objects_flat::Query<Object>;
46
47async fn request<C: GraphQlClient>(
48    client: &C,
49    vars: Variables<'_>,
50) -> super::Result<
51    super::stream::Page<impl Iterator<Item = super::Result<Object, C>> + 'static + use<C>>,
52    C,
53> {
54    let data = client
55        .query::<Query, _>(vars)
56        .await
57        .map_err(Error::Client)?
58        .try_into_data()?;
59
60    graphql_extract::extract!(data => {
61        objects
62    });
63
64    Ok(super::stream::Page {
65        info: objects.page_info.into(),
66        data: objects.nodes.into_iter().map(Ok),
67    })
68}
69
70#[cfg(test)]
71#[allow(clippy::unwrap_used)]
72#[test]
73fn gql_output() {
74    use cynic::QueryBuilder as _;
75
76    let vars = Variables {
77        filter: None,
78        first: None,
79        after: None,
80    };
81    let operation = Query::build(vars);
82    insta::assert_snapshot!(operation.query, @r###"
83    query Query($filter: ObjectFilter, $after: String, $first: Int) {
84      objects(filter: $filter, first: $first, after: $after) {
85        nodes {
86          address
87          asMoveObject {
88            contents {
89              type {
90                repr
91              }
92              bcs
93            }
94          }
95        }
96        pageInfo {
97          hasNextPage
98          endCursor
99        }
100      }
101    }
102    "###);
103}
104
105#[derive(cynic::QueryFragment, Clone, Debug)]
106struct Object {
107    #[cynic(rename = "address")]
108    object_id: Address,
109    as_move_object: Option<super::fragments::MoveObjectContent<MoveValueRaw>>,
110}