sui_gql_client/queries/
object_args_and_content.rs1use af_sui_types::{ObjectArg, ObjectId, Version};
2use sui_gql_schema::{scalars, schema};
3
4use super::fragments::{MoveObjectContent, MoveValueRaw};
5use super::object_args::{build_oarg_set_mut, ObjectOwner};
6use super::objects_flat;
7use super::objects_flat::Variables;
8use crate::queries::fragments::ObjectFilter;
9use crate::queries::outputs::RawMoveStruct;
10use crate::{GraphQlClient, GraphQlErrors, PagedResponse};
11
12type Query = objects_flat::Query<Object>;
13
14#[derive(thiserror::Error, Debug)]
15pub enum Error<T> {
16 #[error(transparent)]
17 Client(T),
18 #[error(transparent)]
19 Server(#[from] GraphQlErrors),
20 #[error("No data in object args query response")]
21 NoData,
22 #[error("Missing data for object: {0}")]
23 MissingObject(ObjectId),
24}
25
26pub async fn query<C: GraphQlClient>(
34 client: &C,
35 object_ids: impl IntoIterator<Item = ObjectId> + Send,
36 mutable: bool,
37 page_size: Option<u32>,
38) -> Result<Vec<(ObjectArg, RawMoveStruct)>, Error<C::Error>> {
39 #[expect(
40 deprecated,
41 reason = "TODO: build query from scratch with new ObjectFilter"
42 )]
43 let filter = ObjectFilter {
44 object_ids: Some(object_ids.into_iter().collect()),
45 type_: None,
46 owner: None,
47 object_keys: None,
48 };
49 let vars = Variables {
50 filter: Some(filter),
51 after: None,
52 first: page_size.map(|n| n as i32),
53 };
54 let response: PagedResponse<Query> = client.query_paged(vars).await.map_err(Error::Client)?;
55 let Some((init, pages)) = response.try_into_data()? else {
56 return Err(Error::NoData);
57 };
58
59 let mut result = vec![];
60 for Object {
61 object_id,
62 version,
63 digest,
64 owner,
65 as_move_object,
66 } in init
67 .objects
68 .nodes
69 .into_iter()
70 .chain(pages.into_iter().flat_map(|p| p.objects.nodes))
71 {
72 let oarg = build_oarg_set_mut(object_id, version, owner, digest, mutable)
73 .ok_or_else(|| Error::MissingObject(object_id))?;
74 let content = as_move_object
75 .and_then(|c| c.into_content())
76 .ok_or_else(|| Error::MissingObject(object_id))?
77 .try_into()
78 .expect("Only Move structs can be top-level objects");
79 result.push((oarg, content));
80 }
81
82 Ok(result)
83}
84
85#[cfg(test)]
86#[allow(clippy::unwrap_used)]
87#[test]
88fn gql_output() {
89 use cynic::QueryBuilder as _;
90 let vars = Variables {
91 filter: None,
92 first: None,
93 after: None,
94 };
95 let operation = Query::build(vars);
96 insta::assert_snapshot!(operation.query, @r###"
97 query Query($filter: ObjectFilter, $after: String, $first: Int) {
98 objects(filter: $filter, first: $first, after: $after) {
99 nodes {
100 address
101 version
102 digest
103 owner {
104 __typename
105 ... on Immutable {
106 _
107 }
108 ... on Shared {
109 __typename
110 initialSharedVersion
111 }
112 ... on Parent {
113 __typename
114 }
115 ... on AddressOwner {
116 __typename
117 }
118 }
119 asMoveObject {
120 contents {
121 type {
122 repr
123 }
124 bcs
125 }
126 }
127 }
128 pageInfo {
129 hasNextPage
130 endCursor
131 }
132 }
133 }
134 "###);
135}
136
137#[derive(cynic::QueryFragment, Debug)]
142struct Object {
143 #[cynic(rename = "address")]
144 object_id: ObjectId,
145 version: Version,
146 digest: Option<scalars::Digest>,
147 owner: Option<ObjectOwner>,
148 as_move_object: Option<MoveObjectContent<MoveValueRaw>>,
149}