Skip to main content

sui_gql_client/queries/
mod.rs

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