sui_gql_client/queries/
owner_df_contents_stream.rs1use af_sui_types::Address as SuiAddress;
2use futures_core::Stream;
3
4use super::fragments::MoveValueRaw;
5use super::outputs::{DynamicField as OutputDf, ObjectKey, RawMoveValue};
6use super::{Error, fragments, stream};
7use crate::{GraphQlClient, GraphQlResponseExt as _, missing_data, schema};
8
9pub async fn query<C: GraphQlClient>(
10 client: &C,
11 address: SuiAddress,
12 root_version: Option<u64>,
13 page_size: Option<i32>,
14) -> impl Stream<Item = super::Result<(RawMoveValue, OutputDf), C>> + '_ {
15 let vars = QueryVariables {
16 address,
17 root_version,
18 first: page_size,
19 after: None,
20 };
21
22 stream::forward(client, vars, request)
23}
24
25async fn request<C: GraphQlClient>(
26 client: &C,
27 vars: QueryVariables,
28) -> super::Result<
29 stream::Page<
30 impl Iterator<Item = super::Result<(RawMoveValue, OutputDf), C>> + 'static + use<C>,
31 >,
32 C,
33> {
34 let data = client
35 .query::<Query, _>(vars)
36 .await
37 .map_err(Error::Client)?
38 .try_into_data()?
39 .ok_or(missing_data!("Response empty"))?;
40
41 let DynamicFieldConnection { nodes, page_info } = data
42 .owner
43 .ok_or(missing_data!("No owner found"))?
44 .dynamic_fields;
45
46 let data = nodes.into_iter().map(|DynamicField { name, value }| {
47 let name = name
48 .ok_or(missing_data!("Dynamic field found but with no name"))?
49 .into();
50 let instance = value.ok_or(missing_data!("Dynamic field found but with no value"))?;
51 let out = match instance {
52 DynamicFieldValue::MoveObject(MoveObject {
53 object_id,
54 version,
55 contents,
56 }) => {
57 let struct_ = contents
58 .ok_or(missing_data!("No contents for DOF"))?
59 .try_into()
60 .expect("Only Move structs can be top-level objects");
61 OutputDf::Object(ObjectKey { object_id, version }, struct_)
62 }
63 DynamicFieldValue::MoveValue(value) => OutputDf::Field(value.into()),
64 DynamicFieldValue::Unknown => return Err(missing_data!("Unknown dynamic field type")),
65 };
66 Ok((name, out))
67 });
68
69 Ok(stream::Page {
70 info: page_info,
71 data,
72 })
73}
74
75#[cfg(test)]
76#[allow(clippy::unwrap_used)]
77#[test]
78fn gql_output() {
79 use cynic::QueryBuilder as _;
80 let vars = QueryVariables {
81 address: SuiAddress::new(rand::random()),
82 root_version: None,
83 first: None,
84 after: None,
85 };
86 let operation = Query::build(vars);
87 insta::assert_snapshot!(operation.query, @r###"
88 query Query($address: SuiAddress!, $rootVersion: UInt53, $after: String, $first: Int) {
89 owner(address: $address, rootVersion: $rootVersion) {
90 dynamicFields(first: $first, after: $after) {
91 nodes {
92 name {
93 type {
94 repr
95 }
96 bcs
97 }
98 value {
99 __typename
100 ... on MoveObject {
101 address
102 version
103 contents {
104 type {
105 repr
106 }
107 bcs
108 }
109 }
110 ... on MoveValue {
111 type {
112 repr
113 }
114 bcs
115 }
116 }
117 }
118 pageInfo {
119 hasNextPage
120 endCursor
121 hasPreviousPage
122 startCursor
123 }
124 }
125 }
126 }
127 "###);
128}
129
130#[derive(cynic::QueryVariables, Debug, Clone)]
135struct QueryVariables {
136 address: SuiAddress,
137 root_version: Option<af_sui_types::Version>,
138 after: Option<String>,
139 first: Option<i32>,
140}
141
142impl stream::UpdatePageInfo for QueryVariables {
143 fn update_page_info(&mut self, info: &fragments::PageInfo) {
144 self.after.clone_from(&info.end_cursor)
145 }
146}
147
148#[derive(cynic::QueryFragment, Debug)]
149#[cynic(variables = "QueryVariables")]
150struct Query {
151 #[arguments(address: $address, rootVersion: $root_version)]
152 owner: Option<Owner>,
153}
154
155#[derive(cynic::QueryFragment, Debug)]
156#[cynic(variables = "QueryVariables")]
157struct Owner {
158 #[arguments(first: $first, after: $after)]
159 dynamic_fields: DynamicFieldConnection,
160}
161
162#[derive(cynic::QueryFragment, Debug)]
163struct MoveObject {
164 #[cynic(rename = "address")]
165 object_id: SuiAddress,
166 version: af_sui_types::Version,
167 contents: Option<MoveValueRaw>,
168}
169
170#[derive(cynic::QueryFragment, Debug)]
171struct DynamicFieldConnection {
172 nodes: Vec<DynamicField>,
173 page_info: fragments::PageInfo,
174}
175
176#[derive(cynic::QueryFragment, Debug)]
177struct DynamicField {
178 name: Option<MoveValueRaw>,
179 value: Option<DynamicFieldValue>,
180}
181
182#[derive(cynic::InlineFragments, Debug)]
183enum DynamicFieldValue {
184 MoveObject(MoveObject),
185 MoveValue(MoveValueRaw),
186 #[cynic(fallback)]
187 Unknown,
188}