sui_gql_client/queries/
object_dof_by_name.rs

1use af_sui_types::Address as SuiAddress;
2use cynic::GraphQlResponse;
3
4use super::Error;
5use super::model::outputs::RawMoveValue;
6use crate::queries::model::fragments::{
7    DynamicFieldByName,
8    DynamicFieldName,
9    DynamicFieldValue,
10    MoveObject,
11    ObjectKey,
12};
13use crate::queries::model::outputs::DynamicField as OutputDf;
14use crate::{GraphQlClient, GraphQlResponseExt, missing_data, scalars, schema};
15
16#[derive(cynic::QueryVariables, Debug)]
17struct Variables {
18    address: SuiAddress,
19    name: DynamicFieldName,
20    at_checkpoint: Option<u64>,
21}
22
23#[derive(cynic::QueryFragment, Debug)]
24#[cynic(variables = "Variables")]
25struct Query {
26    #[arguments(address: $address, atCheckpoint: $at_checkpoint)]
27    pub object: Option<ObjectDynamicField>,
28}
29
30#[derive(cynic::QueryFragment, Debug)]
31#[cynic(graphql_type = "Object")]
32#[cynic(variables = "Variables")]
33struct ObjectDynamicField {
34    #[arguments(name: $name)]
35    dynamic_object_field: Option<DynamicFieldByName>,
36}
37
38pub async fn query<C: GraphQlClient>(
39    client: &C,
40    address: SuiAddress,
41    RawMoveValue {
42        type_: df_name_type,
43        bcs: df_name_bcs,
44    }: RawMoveValue,
45    at_checkpoint: Option<u64>,
46) -> Result<OutputDf, Error<C::Error>> {
47    let vars = Variables {
48        address,
49        at_checkpoint,
50        name: DynamicFieldName {
51            type_: scalars::TypeTag(df_name_type),
52            bcs: scalars::Base64::new(df_name_bcs),
53        },
54    };
55    let result: GraphQlResponse<Query> = client.query(vars).await.map_err(Error::Client)?;
56    let data = result
57        .try_into_data()?
58        .ok_or(missing_data!("Response empty"))?;
59    let df_value = data
60        .object
61        .ok_or(missing_data!("Object not found"))?
62        .dynamic_object_field
63        .ok_or(missing_data!("Dynamic object field not found"))?
64        .value
65        .ok_or(missing_data!("No dynamic object field value"))?;
66
67    let out = match df_value {
68        DynamicFieldValue::MoveObject(MoveObject {
69            address,
70            version,
71            contents,
72        }) => {
73            let struct_ = contents
74                .ok_or(missing_data!("No contents for DF"))?
75                .try_into()
76                .expect("Only Move structs can be top-level objects");
77            OutputDf::Object(
78                ObjectKey {
79                    version,
80                    address,
81                    root_version: None,
82                    at_checkpoint: None,
83                },
84                struct_,
85            )
86        }
87        DynamicFieldValue::MoveValue(value) => OutputDf::Field(
88            value
89                .try_into()
90                .map_err(|e| missing_data!("Dynamic field name content empty. Error: {e}"))?,
91        ),
92        DynamicFieldValue::Unknown => return Err(missing_data!("Unknown dynamic field type")),
93    };
94
95    Ok(out)
96}
97
98#[cfg(test)]
99#[allow(clippy::unwrap_used)]
100#[test]
101fn gql_output() {
102    use cynic::QueryBuilder as _;
103    let vars = Variables {
104        address: SuiAddress::new(rand::random()),
105        at_checkpoint: None,
106        name: DynamicFieldName {
107            type_: scalars::TypeTag("0x2::sui::SUI".parse().unwrap()),
108            bcs: scalars::Base64::new(vec![]),
109        },
110    };
111    let operation = Query::build(vars);
112    insta::assert_snapshot!(operation.query, @r"
113    query Query($address: SuiAddress!, $name: DynamicFieldName!, $atCheckpoint: UInt53) {
114      object(address: $address, atCheckpoint: $atCheckpoint) {
115        dynamicObjectField(name: $name) {
116          value {
117            __typename
118            ... on MoveObject {
119              address
120              version
121              contents {
122                type {
123                  repr
124                }
125                bcs
126              }
127            }
128            ... on MoveValue {
129              type {
130                repr
131              }
132              bcs
133            }
134          }
135        }
136      }
137    }
138    ");
139}