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