sui_gql_client/queries/
mod.rs

1use af_sui_types::{
2    Address as SuiAddress,
3    Address,
4    Object,
5    ObjectRef,
6    StructTag,
7    Transaction,
8    Version,
9};
10// For `object_args!` macro only
11#[doc(hidden)]
12use futures::Stream;
13
14mod coin_metadata;
15mod current_epoch;
16mod events_backward;
17mod full_objects;
18mod latest_checkpoint;
19mod latest_full_objects;
20pub mod model;
21mod object_df_by_name;
22mod object_dfs;
23mod object_dof_by_name;
24mod object_type;
25mod owner_gas_coins;
26mod packages;
27pub(crate) mod stream;
28use crate::queries::model::fragments::{EventEdge, EventFilter};
29// mod transaction_blocks_status;
30mod transactions_by_digests;
31use crate::queries::model::outputs::{DynamicField, RawMoveValue};
32use crate::{GraphQlClient, GraphQlErrors};
33
34/// Standard query result type to aid in adding new queries.
35type Result<T, C> = std::result::Result<T, Error<<C as GraphQlClient>::Error>>;
36
37/// Extension trait to [`GraphQlClient`] collecting all defined queries in one place.
38#[trait_variant::make(Send)]
39pub trait GraphQlClientExt: GraphQlClient + Sized {
40    // NOTE: `.await` is not used in the implementations below because `trait_variant` de-sugars the
41    // method definitions removing their `async` prefixes
42
43    /// The latest epoch id and reference gas price
44    async fn current_epoch(&self) -> Result<(u64, u64), Self> {
45        current_epoch::query(self)
46    }
47
48    /// Return a single page of events + cursors and a flag indicating if there's a previous page.
49    ///
50    /// If `page_size` is left `None`, the server decides the size of the page.
51    ///
52    /// The edges are returned in reverse order of which they where returned by the server
53    async fn events_backward(
54        &self,
55        filter: Option<EventFilter>,
56        cursor: Option<String>,
57        page_size: Option<u32>,
58    ) -> Result<(Vec<EventEdge>, bool), Self> {
59        events_backward::query(self, filter, cursor, page_size)
60    }
61
62    /// The full [`Object`] contents at specific versions.
63    ///
64    /// Duplicate object keys are automatically discarded.
65    async fn full_objects(
66        &self,
67        keys: impl IntoIterator<Item = (Address, Option<Version>)> + Send,
68        at_checkpoint: Option<u64>,
69    ) -> Result<Vec<Object>, Self> {
70        self::full_objects::query(self, keys, at_checkpoint)
71    }
72
73    /// Latest checkpoint number.
74    async fn latest_checkpoint(&self) -> Result<u64, Self> {
75        latest_checkpoint::query(self)
76    }
77
78    /// The full [`Object`] contents at their latest versions.
79    ///
80    /// Fails if any requested object id is not in the final map.
81    ///
82    /// # Note
83    ///
84    /// The check for returned object ids is just so that the caller can safely do `map[object_id]`
85    /// on the returned map. Keep in mind that the result if an object id is repeated in `objects`
86    /// is undefined. Avoid doing so.
87    fn latest_full_objects(
88        &self,
89        owner: Option<SuiAddress>,
90        type_: Option<String>,
91        page_size: Option<u32>,
92    ) -> impl Stream<Item = Result<Object, Self>> + '_ {
93        latest_full_objects::query(self, owner, type_, page_size)
94    }
95
96    /// Get the raw Move value of a dynamic field's value.
97    async fn object_df_by_name(
98        &self,
99        address: Address,
100        raw_move_value: RawMoveValue,
101        at_checkpoint: Option<u64>,
102    ) -> Result<DynamicField, Self> {
103        object_df_by_name::query(self, address, raw_move_value, at_checkpoint)
104    }
105
106    /// Get the raw Move value of a dynamic object field's value.
107    async fn object_dof_by_name(
108        &self,
109        address: Address,
110        raw_move_value: RawMoveValue,
111        at_checkpoint: Option<u64>,
112    ) -> Result<DynamicField, Self> {
113        object_dof_by_name::query(self, address, raw_move_value, at_checkpoint)
114    }
115
116    /// **Streamed** map of all keys to dynamic field and dynamic object field values
117    /// [`RawMoveValue`] -> [`DynamicField`].
118    async fn object_dfs(
119        &self,
120        address: Address,
121        at_checkpoint: Option<u64>,
122        page_size: Option<i32>,
123    ) -> impl Stream<Item = Result<(RawMoveValue, DynamicField), Self>> + '_ {
124        object_dfs::query(self, address, at_checkpoint, page_size)
125    }
126
127    /// The full [`Object`] contents at their latest versions.
128    ///
129    /// Fails if any requested object id is not in the final map.
130    ///
131    /// # Note
132    ///
133    /// The check for returned object ids is just so that the caller can safely do `map[object_id]`
134    /// on the returned map. Keep in mind that the result if an object id is repeated in `objects`
135    /// is undefined. Avoid doing so.
136    fn owner_gas_coins(
137        &self,
138        owner: SuiAddress,
139        type_: Option<String>,
140        page_size: Option<u32>,
141    ) -> impl Stream<Item = Result<(u64, ObjectRef, u64), Self>> + '_ {
142        owner_gas_coins::query(self, owner, type_, page_size)
143    }
144
145    /// Get all the package ids and versions given either the original package id or
146    /// an upgraded package id.
147    async fn packages(&self, package_id: Address) -> Result<Vec<(Address, u64)>, Self> {
148        packages::query(self, package_id)
149    }
150
151    /// Get transactions given their digests
152    async fn transactions(
153        &self,
154        transaction_digests: Vec<String>,
155    ) -> Result<Vec<Transaction>, Self> {
156        transactions_by_digests::query(self, transaction_digests)
157    }
158
159    // /// Get execution status for the input transaction digests
160    // async fn transaction_blocks_status(
161    //     &self,
162    //     transaction_digests: Vec<String>,
163    // ) -> Result<impl Iterator<Item = crate::extract::Result<(String, bool)>>, Self> {
164    //     transaction_blocks_status::query(self, transaction_digests)
165    // }
166
167    /// Struct type of an object given its ID.
168    async fn object_type(&self, id: Address) -> Result<StructTag, Self> {
169        object_type::query(self, id)
170    }
171
172    /// Fetches metadata for the given coin type
173    ///
174    /// Returns a tuple containing (decimals, name, symbol)
175    async fn coin_metadata(
176        &self,
177        type_: &str,
178    ) -> Result<(Option<u8>, Option<String>, Option<String>), Self> {
179        coin_metadata::query(self, type_)
180    }
181}
182
183impl<T: GraphQlClient> GraphQlClientExt for T {}
184
185/// Generic error type for queries.
186#[derive(thiserror::Error, Clone, Debug)]
187pub enum Error<C: std::error::Error> {
188    #[error("Client error: {0:?}")]
189    Client(C),
190    #[error("In server response: {0}")]
191    Server(#[from] GraphQlErrors),
192    #[error("Missing data in response: {0}")]
193    MissingData(String),
194}
195
196#[expect(deprecated, reason = "Internal module deprecation")]
197impl<C: std::error::Error> From<crate::extract::Error> for Error<C> {
198    fn from(value: crate::extract::Error) -> Self {
199        Self::MissingData(value.0)
200    }
201}
202
203impl<C: std::error::Error> From<&'static str> for Error<C> {
204    fn from(value: &'static str) -> Self {
205        Self::MissingData(value.into())
206    }
207}
208
209/// Helper to generate [`Error::MissingData`].
210///
211/// Works very much like an `anyhow!`/`eyre!` macro, but intended for the case when trying to
212/// extract some data from the query.
213#[macro_export]
214macro_rules! missing_data {
215    ($($msg:tt)*) => {
216        $crate::queries::Error::MissingData(format!($($msg)*))
217    };
218}