sui_gql_client/queries/
mod.rs

1use std::collections::HashMap;
2
3use af_sui_types::{
4    Address as SuiAddress,
5    Object,
6    ObjectArg,
7    ObjectId,
8    ObjectRef,
9    StructTag,
10    TransactionData,
11};
12// For `object_args!` macro only
13#[doc(hidden)]
14pub use bimap::BiMap;
15use futures::Stream;
16use outputs::{DynamicField, ObjectKey, RawMoveStruct, RawMoveValue};
17
18use crate::{GraphQlClient, GraphQlErrors};
19
20mod current_epoch_id;
21mod epoch_final_checkpoint_num;
22mod events_backward;
23mod filtered_full_objects;
24pub mod fragments;
25mod full_object;
26mod full_objects;
27mod gas_payment;
28mod genesis_tx;
29mod latest_checkpoint;
30mod latest_object_version;
31mod latest_objects_version;
32mod latest_version_at_checkpoint_v2;
33mod max_page_size;
34mod object_args;
35mod object_args_and_content;
36mod object_content;
37mod object_type;
38mod objects_content;
39mod objects_flat;
40pub mod outputs;
41mod owner_df_content;
42mod owner_df_contents;
43mod owner_dof_content;
44mod packages_from_original;
45mod packages_published_epoch;
46mod reference_gas_price;
47pub(crate) mod stream;
48mod transaction_blocks_status;
49
50pub use self::events_backward::{EventEdge, EventFilter};
51pub use self::gas_payment::Error as GasPaymentError;
52pub use self::latest_version_at_checkpoint_v2::Error as LatestVersionAtCheckpointError;
53pub use self::object_args::Error as ObjectArgsError;
54pub use self::object_args_and_content::Error as ObjectArgsAndContentError;
55
56/// Standard query result type to aid in adding new queries.
57type Result<T, C> = std::result::Result<T, Error<<C as GraphQlClient>::Error>>;
58
59/// Extension trait to [`GraphQlClient`] collecting all defined queries in one place.
60#[trait_variant::make(Send)]
61pub trait GraphQlClientExt: GraphQlClient + Sized {
62    // NOTE: `.await` is not used in the implementations below because `trait_variant` de-sugars the
63    // method definitions removing their `async` prefixes
64
65    /// The latest epoch id.
66    async fn current_epoch_id(&self) -> Result<u64, Self> {
67        current_epoch_id::query(self)
68    }
69
70    /// The last checkpoint number of an epoch.
71    async fn epoch_final_checkpoint_num(&self, epoch_id: u64) -> Result<u64, Self> {
72        epoch_final_checkpoint_num::query(self, epoch_id)
73    }
74
75    /// Return a single page of events + cursors and a flag indicating if there's a previous page.
76    ///
77    /// If `page_size` is left `None`, the server decides the size of the page.
78    ///
79    /// The edges are returned in reverse order of which they where returned by the server
80    async fn events_backward(
81        &self,
82        filter: Option<EventFilter>,
83        cursor: Option<String>,
84        page_size: Option<u32>,
85    ) -> Result<(Vec<EventEdge>, bool), Self> {
86        events_backward::query(self, filter, cursor, page_size)
87    }
88
89    /// The full [`Object`] contents with the possibility to filter by owner or object type.
90    fn filtered_full_objects(
91        &self,
92        owner: Option<SuiAddress>,
93        type_: Option<String>,
94        page_size: Option<u32>,
95    ) -> impl Stream<Item = Result<Object, Self>> + '_ {
96        filtered_full_objects::query(self, owner, type_, page_size)
97    }
98
99    /// The full [`Object`] contents at a certain version or the latest if not specified.
100    async fn full_object(&self, object_id: ObjectId, version: Option<u64>) -> Result<Object, Self> {
101        full_object::query(self, object_id, version)
102    }
103
104    /// The full [`Object`] contents at certain versions or the latest if not specified.
105    ///
106    /// Fails if any requested object id is not in the final map.
107    ///
108    /// # Note
109    ///
110    /// The check for returned object ids is just so that the caller can safely do `map[object_id]`
111    /// on the returned map. Keep in mind:
112    /// - The result if an object id is repeated in `objects` is undefined. Avoid doing so.
113    /// - This won't check if the returned object version matches the requested version (if any)
114    ///   for each object
115    async fn full_objects(
116        &self,
117        objects: impl IntoIterator<Item = (ObjectId, Option<u64>)> + Send,
118        page_size: Option<u32>,
119    ) -> Result<HashMap<ObjectId, Object>, Self> {
120        full_objects::query(self, objects, page_size)
121    }
122
123    /// Genesis transaction of the Sui network instance.
124    async fn genesis_tx(&self) -> Result<TransactionData, Self> {
125        genesis_tx::query(self)
126    }
127
128    /// Latest checkpoint number.
129    async fn latest_checkpoint(&self) -> Result<u64, Self> {
130        latest_checkpoint::query(self)
131    }
132
133    /// The latest checkpoint number and object version of an object.
134    async fn latest_object_version(&self, object_id: ObjectId) -> Result<(u64, u64), Self> {
135        latest_object_version::query(self, object_id)
136    }
137
138    /// The latest checkpoint number and the map of object ids to the their version at that
139    /// checkpoint.
140    ///
141    /// Fails if the server doesn't return the version for any of the requested objects.
142    async fn latest_objects_version(
143        &self,
144        object_ids: &[ObjectId],
145    ) -> Result<(u64, HashMap<ObjectId, u64>), Self> {
146        latest_objects_version::query(self, object_ids)
147    }
148
149    /// Version of the object at this checkpoint.
150    async fn latest_version_at_checkpoint(
151        &self,
152        id: ObjectId,
153        ckpt_num: u64,
154    ) -> std::result::Result<u64, LatestVersionAtCheckpointError<Self::Error>> {
155        latest_version_at_checkpoint_v2::query(self, id, ckpt_num)
156    }
157
158    /// Turn a bijective map of names and object ids into one of names and object args.
159    ///
160    /// Fails if the query response does not have the necessary data for the input map.
161    async fn object_args(
162        &self,
163        names: BiMap<String, ObjectId>,
164        page_size: Option<u32>,
165    ) -> std::result::Result<BiMap<String, ObjectArg>, ObjectArgsError<Self::Error>> {
166        object_args::query(self, names, page_size)
167    }
168
169    /// Get a sequence of object args and contents corresponding to `object_ids`, but not
170    /// necessarily in the same order.
171    ///
172    /// **NOTE**: prefer [`GraphQlClientExt::full_objects`] instead and call `Object::object_arg`
173    /// on each returned object.
174    ///
175    /// The `mutable` argument controls whether we want to create mutable [`ObjectArg`]s, if they
176    /// are of the [`ObjectArg::SharedObject`] variant.
177    ///
178    /// Fails if any object in the response is missing data.
179    async fn object_args_and_content(
180        &self,
181        object_ids: impl IntoIterator<Item = ObjectId> + Send,
182        mutable: bool,
183        page_size: Option<u32>,
184    ) -> std::result::Result<Vec<(ObjectArg, RawMoveStruct)>, ObjectArgsAndContentError<Self::Error>>
185    {
186        object_args_and_content::query(self, object_ids, mutable, page_size)
187    }
188
189    /// Get the raw Move struct of an object's content.
190    async fn object_content(
191        &self,
192        object_id: ObjectId,
193        version: Option<u64>,
194    ) -> Result<RawMoveStruct, Self> {
195        object_content::query(self, object_id, version)
196    }
197
198    async fn objects_content(
199        &self,
200        object_ids: Vec<ObjectId>,
201    ) -> Result<HashMap<ObjectId, RawMoveStruct>, Self> {
202        objects_content::query(self, object_ids)
203    }
204
205    /// Get the raw Move value of a dynamic field's value.
206    async fn owner_df_content(
207        &self,
208        address: SuiAddress,
209        raw_move_value: RawMoveValue,
210        root_version: Option<u64>,
211    ) -> Result<RawMoveValue, Self> {
212        owner_df_content::query(self, address, raw_move_value, root_version)
213    }
214
215    /// Map of all keys to dynamic field values: [`RawMoveValue`] -> [`DynamicField`].
216    async fn owner_df_contents(
217        &self,
218        address: SuiAddress,
219        root_version: Option<u64>,
220        first: Option<i32>,
221        after: Option<String>,
222    ) -> Result<(HashMap<RawMoveValue, DynamicField>, Option<String>), Self> {
223        owner_df_contents::query(self, address, root_version, first, after)
224    }
225
226    /// Get the raw Move struct of a dynamic object field's value.
227    async fn owner_dof_content(
228        &self,
229        address: SuiAddress,
230        raw_move_value: RawMoveValue,
231        root_version: Option<u64>,
232    ) -> Result<(ObjectKey, RawMoveStruct), Self> {
233        owner_dof_content::query(self, address, raw_move_value, root_version)
234    }
235
236    /// Get all the package ids and versions given the original package id.
237    async fn packages_from_original(
238        &self,
239        package_id: ObjectId,
240    ) -> Result<impl Iterator<Item = (ObjectId, u64)>, Self> {
241        packages_from_original::query(self, package_id)
242    }
243
244    /// The epoch and checkpoint number (in this order) for each package id.
245    async fn packages_published_epoch(
246        &self,
247        package_ids: Vec<ObjectId>,
248    ) -> Result<impl Iterator<Item = (ObjectId, u64, u64)>, Self> {
249        packages_published_epoch::query(self, package_ids)
250    }
251
252    /// The reference gas price for the latest epoch.
253    async fn reference_gas_price(&self) -> Result<u64, Self> {
254        reference_gas_price::query(self)
255    }
256
257    /// Get execution status for the input transaction digests
258    #[expect(deprecated, reason = "Internal module deprecation")]
259    async fn transaction_blocks_status(
260        &self,
261        transaction_digests: Vec<String>,
262    ) -> Result<impl Iterator<Item = crate::extract::Result<(String, bool)>>, Self> {
263        transaction_blocks_status::query(self, transaction_digests)
264    }
265
266    /// Gas coins to satisfy the budget, excluding some object ids.
267    ///
268    /// The `exclude` is here because it can be useful if a SUI coin is already being used in the
269    /// PTB itself. However in such a scenario one can use [`Argument::Gas`] instead.
270    ///
271    /// [`Argument::Gas`]: af_sui_types::Argument::Gas
272    async fn gas_payment(
273        &self,
274        sponsor: SuiAddress,
275        budget: u64,
276        exclude: Vec<ObjectId>,
277    ) -> std::result::Result<Vec<ObjectRef>, GasPaymentError<Self::Error>> {
278        gas_payment::query(self, sponsor, budget, exclude)
279    }
280
281    /// The maximum size for pagination allowed by the server.
282    async fn max_page_size(&self) -> Result<i32, Self> {
283        max_page_size::query(self)
284    }
285
286    /// Struct type of an object given its ID.
287    async fn object_type(&self, id: ObjectId) -> Result<StructTag, Self> {
288        object_type::query(self, id)
289    }
290}
291
292impl<T: GraphQlClient> GraphQlClientExt for T {}
293
294/// Generic error type for queries.
295#[derive(thiserror::Error, Clone, Debug)]
296pub enum Error<C: std::error::Error> {
297    #[error("Client error: {0:?}")]
298    Client(C),
299    #[error("In server response: {0}")]
300    Server(#[from] GraphQlErrors),
301    #[error("Missing data in response: {0}")]
302    MissingData(String),
303}
304
305#[expect(deprecated, reason = "Internal module deprecation")]
306impl<C: std::error::Error> From<crate::extract::Error> for Error<C> {
307    fn from(value: crate::extract::Error) -> Self {
308        Self::MissingData(value.0)
309    }
310}
311
312impl<C: std::error::Error> From<&'static str> for Error<C> {
313    fn from(value: &'static str) -> Self {
314        Self::MissingData(value.into())
315    }
316}
317
318/// Helper to generate [`Error::MissingData`].
319///
320/// Works very much like an `anyhow!`/`eyre!` macro, but intended for the case when trying to
321/// extract some data from the query.
322#[macro_export]
323macro_rules! missing_data {
324    ($($msg:tt)*) => {
325        $crate::queries::Error::MissingData(format!($($msg)*))
326    };
327}