sui_gql_client/queries/
latest_full_objects.rs1use af_sui_types::{Address, Object};
2use futures::Stream;
3use sui_gql_schema::scalars::Base64Bcs;
4
5use super::model::fragments::{ObjectFilter, PageInfo};
6use super::stream;
7use crate::queries::Error;
8use crate::queries::model::fragments::ObjectConnection;
9use crate::{GraphQlClient, GraphQlResponseExt, schema};
10
11#[derive(cynic::QueryVariables, Clone, Debug)]
12struct Variables {
13 filter: ObjectFilter,
14 after: Option<String>,
15 first: Option<i32>,
16}
17
18#[derive(cynic::QueryFragment, Clone, Debug)]
19#[cynic(variables = "Variables")]
20struct Query {
21 #[arguments(filter: $filter, first: $first, after: $after)]
22 objects: Option<ObjectConnection>,
23}
24
25pub(super) fn query<C: GraphQlClient>(
26 client: &C,
27 owner: Option<Address>,
28 type_: Option<String>,
29 page_size: Option<u32>,
30) -> impl Stream<Item = super::Result<Object, C>> {
31 let filter = ObjectFilter {
32 owner,
33 type_,
34 owner_kind: None,
35 };
36 let vars = Variables {
37 after: None,
38 first: page_size.map(|v| v.try_into().unwrap_or(i32::MAX)),
39 filter,
40 };
41 stream::forward(client, vars, request)
42}
43
44async fn request<C: GraphQlClient>(
45 client: &C,
46 vars: Variables,
47) -> super::Result<stream::Page<impl Iterator<Item = super::Result<Object, C>> + use<C>>, C> {
48 let data = client
49 .query::<Query, _>(vars)
50 .await
51 .map_err(Error::Client)?
52 .try_into_data()?;
53
54 let stream::Page { info, data } = extract(data)?;
55 Ok(stream::Page::new(
56 info,
57 data.map(|r| r.map_err(Error::MissingData)),
58 ))
59}
60
61fn extract(
62 data: Option<Query>,
63) -> Result<stream::Page<impl Iterator<Item = Result<Object, String>>>, &'static str> {
64 graphql_extract::extract!(data => {
65 objects? {
66 nodes[] {
67 id
68 object
69 }
70 page_info
71 }
72 });
73 let nodes = nodes
74 .into_iter()
75 .map(|r: Result<_, &'static str>| -> Result<_, String> {
76 let (id, bcs) = r?;
77 bcs.ok_or_else(|| format!("BCS for object {id}"))
78 .map(Base64Bcs::into_inner)
79 });
80 Ok(stream::Page::new(page_info, nodes))
81}
82
83impl stream::UpdatePageInfo for Variables {
84 fn update_page_info(&mut self, info: &PageInfo) {
85 self.after.clone_from(&info.end_cursor)
86 }
87}
88
89#[cfg(test)]
90#[test]
91fn gql_output() -> color_eyre::Result<()> {
92 use cynic::QueryBuilder as _;
93
94 let vars = Variables {
95 filter: ObjectFilter {
96 type_: None,
97 owner: None,
98 owner_kind: None,
99 },
100 after: None,
101 first: None,
102 };
103
104 let operation = Query::build(vars);
105 insta::assert_snapshot!(operation.query, @r"
106 query Query($filter: ObjectFilter!, $after: String, $first: Int) {
107 objects(filter: $filter, first: $first, after: $after) {
108 nodes {
109 address
110 objectBcs
111 }
112 pageInfo {
113 hasNextPage
114 endCursor
115 }
116 }
117 }
118 ");
119 Ok(())
120}