sui_gql_client/queries/
objects_content.rs

1use std::collections::HashMap;
2
3use af_sui_types::ObjectId;
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::{objects_flat, Error};
11use crate::{missing_data, GraphQlClient, GraphQlResponseExt as _};
12
13pub(super) async fn query<C: GraphQlClient>(
14    client: &C,
15    object_ids: Vec<ObjectId>,
16) -> super::Result<HashMap<ObjectId, 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<super::stream::Page<impl Iterator<Item = super::Result<Object, C>> + 'static>, C>
51{
52    let data = client
53        .query::<Query, _>(vars)
54        .await
55        .map_err(Error::Client)?
56        .try_into_data()?;
57
58    graphql_extract::extract!(data => {
59        objects
60    });
61
62    Ok(super::stream::Page {
63        info: objects.page_info.into(),
64        data: objects.nodes.into_iter().map(Ok),
65    })
66}
67
68#[cfg(test)]
69#[allow(clippy::unwrap_used)]
70#[test]
71fn gql_output() {
72    use cynic::QueryBuilder as _;
73
74    let vars = Variables {
75        filter: None,
76        first: None,
77        after: None,
78    };
79    let operation = Query::build(vars);
80    insta::assert_snapshot!(operation.query, @r###"
81    query Query($filter: ObjectFilter, $after: String, $first: Int) {
82      objects(filter: $filter, first: $first, after: $after) {
83        nodes {
84          address
85          asMoveObject {
86            contents {
87              type {
88                repr
89              }
90              bcs
91            }
92          }
93        }
94        pageInfo {
95          hasNextPage
96          endCursor
97        }
98      }
99    }
100    "###);
101}
102
103#[derive(cynic::QueryFragment, Clone, Debug)]
104struct Object {
105    #[cynic(rename = "address")]
106    object_id: ObjectId,
107    as_move_object: Option<super::fragments::MoveObjectContent<MoveValueRaw>>,
108}