sui_gql_client/queries/
fragments.rs

1use af_sui_types::{Address as SuiAddress, ObjectId, TypeTag, Version};
2use cynic::QueryFragment;
3use sui_gql_schema::{scalars, schema};
4
5// ====================================================================================================
6//  Input objects
7// ====================================================================================================
8pub use self::object_filter_legacy::ObjectFilter;
9
10#[expect(deprecated, reason = "Derived impls using ObjectFilter::object_keys")]
11mod object_filter_legacy {
12    use af_sui_types::{Address, ObjectId};
13    use sui_gql_schema::{scalars, schema};
14
15    use super::ObjectKey;
16
17    #[derive(cynic::InputObject, Clone, Debug, Default)]
18    pub struct ObjectFilter {
19        /// Filter objects by their type's `package`, `package::module`, or their fully qualified type
20        /// name.
21        ///
22        /// Generic types can be queried by either the generic type name, e.g. `0x2::coin::Coin`, or by
23        /// the full type name, such as `0x2::coin::Coin<0x2::sui::SUI>`.
24        #[cynic(rename = "type")]
25        pub type_: Option<scalars::TypeTag>,
26        pub owner: Option<Address>,
27        pub object_ids: Option<Vec<ObjectId>>,
28        /// Filter for live objects by their ID and version.
29        #[deprecated = "this input filter has been deprecated in favor of `multiGetObjects` query as \
30        it does not make sense to query for live objects by their versions. This filter will be \
31        removed with v1.42.0 release."]
32        pub object_keys: Option<Vec<ObjectKey>>,
33    }
34}
35
36#[derive(cynic::InputObject, Clone, Debug)]
37pub struct ObjectKey {
38    pub object_id: ObjectId,
39    pub version: Version,
40}
41
42#[derive(cynic::InputObject, Clone, Debug, Default)]
43#[cynic(graphql_type = "ObjectFilter")]
44pub(crate) struct ObjectFilterV2<'a> {
45    /// Filter objects by their type's `package`, `package::module`, or their fully qualified type
46    /// name.
47    ///
48    /// Generic types can be queried by either the generic type name, e.g. `0x2::coin::Coin`, or by
49    /// the full type name, such as `0x2::coin::Coin<0x2::sui::SUI>`.
50    #[cynic(rename = "type")]
51    pub(crate) type_: Option<String>,
52    pub(crate) owner: Option<SuiAddress>,
53    pub(crate) object_ids: Option<&'a [ObjectId]>,
54}
55
56#[derive(cynic::InputObject, Clone, Debug)]
57pub struct DynamicFieldName {
58    /// The string type of the DynamicField's 'name' field.
59    /// A string representation of a Move primitive like 'u64', or a struct type like '0x2::kiosk::Listing'
60    #[cynic(rename = "type")]
61    pub type_: scalars::TypeTag,
62    /// The Base64 encoded bcs serialization of the DynamicField's 'name' field.
63    pub bcs: scalars::Base64<Vec<u8>>,
64}
65
66#[cfg(feature = "move-type")]
67impl<T: af_move_type::MoveType> TryFrom<af_move_type::MoveInstance<T>> for DynamicFieldName {
68    type Error = bcs::Error;
69
70    fn try_from(value: af_move_type::MoveInstance<T>) -> Result<Self, Self::Error> {
71        let af_move_type::MoveInstance { type_, value } = value;
72        Ok(Self {
73            type_: scalars::TypeTag(type_.into()),
74            bcs: scalars::Base64::new(bcs::to_bytes(&value)?),
75        })
76    }
77}
78
79#[derive(cynic::InputObject, Clone, Debug, Default)]
80pub(crate) struct TransactionBlockFilter {
81    pub(crate) function: Option<String>,
82    pub(crate) kind: Option<TransactionBlockKindInput>,
83    pub(crate) after_checkpoint: Option<Version>,
84    pub(crate) at_checkpoint: Option<Version>,
85    pub(crate) before_checkpoint: Option<Version>,
86    pub(crate) affected_address: Option<SuiAddress>,
87    pub(crate) sent_address: Option<SuiAddress>,
88    pub(crate) input_object: Option<SuiAddress>,
89    pub(crate) changed_object: Option<SuiAddress>,
90    pub(crate) transaction_ids: Option<Vec<String>>,
91}
92
93#[derive(cynic::Enum, Clone, Debug)]
94pub(crate) enum TransactionBlockKindInput {
95    SystemTx,
96    ProgrammableTx,
97}
98
99// ====================================================================================================
100//  Simple fragments
101// ====================================================================================================
102
103#[derive(cynic::QueryFragment, Clone, Debug, Default)]
104pub(crate) struct PageInfo {
105    pub(crate) has_next_page: bool,
106    pub(crate) end_cursor: Option<String>,
107    #[expect(dead_code, reason = "For generality")]
108    pub(crate) has_previous_page: bool,
109    #[expect(dead_code, reason = "For generality")]
110    pub(crate) start_cursor: Option<String>,
111}
112
113impl From<PageInfoForward> for PageInfo {
114    fn from(
115        PageInfoForward {
116            has_next_page,
117            end_cursor,
118        }: PageInfoForward,
119    ) -> Self {
120        Self {
121            has_next_page,
122            end_cursor,
123            ..Default::default()
124        }
125    }
126}
127
128impl From<PageInfoBackward> for PageInfo {
129    fn from(
130        PageInfoBackward {
131            has_previous_page,
132            start_cursor,
133        }: PageInfoBackward,
134    ) -> Self {
135        Self {
136            has_previous_page,
137            start_cursor,
138            ..Default::default()
139        }
140    }
141}
142
143#[derive(cynic::QueryFragment, Clone, Debug)]
144#[cynic(graphql_type = "PageInfo")]
145pub struct PageInfoForward {
146    pub has_next_page: bool,
147    pub end_cursor: Option<String>,
148}
149
150#[derive(cynic::QueryFragment, Clone, Debug)]
151#[cynic(graphql_type = "PageInfo")]
152pub struct PageInfoBackward {
153    pub has_previous_page: bool,
154    pub start_cursor: Option<String>,
155}
156
157#[derive(cynic::QueryFragment, Clone, Debug)]
158#[cynic(graphql_type = "MoveValue")]
159pub struct MoveValueRaw {
160    #[cynic(rename = "type")]
161    pub type_: MoveTypeTag,
162    pub bcs: scalars::Base64<Vec<u8>>,
163}
164
165impl From<MoveValueRaw> for super::outputs::RawMoveValue {
166    fn from(MoveValueRaw { type_, bcs }: MoveValueRaw) -> Self {
167        Self {
168            type_: type_.into(),
169            bcs: bcs.into_inner(),
170        }
171    }
172}
173
174#[derive(thiserror::Error, Debug)]
175#[error("TypeTag is not a Struct variant")]
176pub struct NotMoveStructError;
177
178impl TryFrom<MoveValueRaw> for super::outputs::RawMoveStruct {
179    type Error = NotMoveStructError;
180    fn try_from(MoveValueRaw { type_, bcs }: MoveValueRaw) -> Result<Self, Self::Error> {
181        let tag: TypeTag = type_.into();
182        let TypeTag::Struct(stag) = tag else {
183            return Err(NotMoveStructError);
184        };
185        Ok(Self {
186            type_: *stag,
187            bcs: bcs.into_inner(),
188        })
189    }
190}
191
192#[cfg(feature = "move-type")]
193impl<T> TryFrom<MoveValueRaw> for af_move_type::MoveInstance<T>
194where
195    T: af_move_type::MoveType,
196{
197    type Error = ToMoveInstanceError;
198    fn try_from(MoveValueRaw { bcs, type_ }: MoveValueRaw) -> Result<Self, Self::Error> {
199        // Fail early if type tag is not expected
200        let type_ = TypeTag::from(type_).try_into()?;
201        let value = bcs::from_bytes(bcs.as_ref())?;
202        Ok(Self { type_, value })
203    }
204}
205
206#[cfg(feature = "move-type")]
207#[derive(thiserror::Error, Debug)]
208pub enum ToMoveInstanceError {
209    #[error("Mismatched types: {0}")]
210    TypeTag(#[from] af_move_type::TypeTagError),
211    #[error("Deserializing value: {0}")]
212    Bcs(#[from] bcs::Error),
213}
214
215/// Helper to extract a strongly typed [`TypeTag`] from the `MoveType` GQL type.
216#[derive(cynic::QueryFragment, Clone)]
217#[cynic(graphql_type = "MoveType")]
218pub struct MoveTypeTag {
219    /// Keep this private so that we can change where we get the [TypeTag] from.
220    repr: scalars::TypeTag,
221}
222
223impl std::fmt::Debug for MoveTypeTag {
224    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
225        write!(f, "MoveTypeTag({})", self.repr.0)
226    }
227}
228
229impl From<MoveTypeTag> for TypeTag {
230    fn from(value: MoveTypeTag) -> Self {
231        value.repr.0
232    }
233}
234
235// ====================================================================================================
236//  Internal
237// ====================================================================================================
238
239#[derive(cynic::QueryFragment, Clone, Debug)]
240#[cynic(graphql_type = "MoveObject")]
241pub(super) struct MoveObjectContent<MoveValue = MoveValueRaw>
242where
243    MoveValue: QueryFragment<SchemaType = schema::MoveValue, VariablesFields = ()>,
244{
245    pub(super) contents: Option<MoveValue>,
246}
247
248impl<MoveValue> MoveObjectContent<MoveValue>
249where
250    MoveValue: QueryFragment<SchemaType = schema::MoveValue, VariablesFields = ()>,
251{
252    pub fn into_content(self) -> Option<MoveValue> {
253        self.contents
254    }
255}