af_iperps/graphql/
map_orders.rs1use af_move_type::MoveInstance;
2use af_sui_types::Address;
3use enum_as_inner::EnumAsInner;
4use futures::Stream;
5pub use sui_gql_client::queries::Error;
6use sui_gql_client::queries::model::fragments::{MoveValueGql, PageInfoForward};
7use sui_gql_client::{GraphQlClient, GraphQlResponseExt as _, schema};
8
9use crate::orderbook::Order;
10use crate::ordered_map::Leaf;
11
12pub(super) fn query<C: GraphQlClient>(
13 client: &C,
14 map: Address,
15 at_checkpoint: Option<u64>,
16) -> impl Stream<Item = Result<(u128, Order), Error<C::Error>>> + '_ {
17 async_stream::try_stream! {
18 let mut vars = Variables {
19 map,
20 at_checkpoint,
21 first: Some(32),
22 after: None,
23 };
24 let mut has_next_page = true;
25 while has_next_page {
26 let (page_info, orders) = request(client, vars.clone()).await?;
27
28 vars.after = page_info.end_cursor.clone();
29 has_next_page = page_info.has_next_page;
30
31 for value in orders {
32 yield value;
33 }
34 }
35 }
36}
37
38async fn request<C: GraphQlClient>(
39 client: &C,
40 vars: Variables,
41) -> Result<
42 (
43 PageInfoForward,
44 impl Iterator<Item = (u128, Order)> + 'static,
45 ),
46 Error<C::Error>,
47> {
48 let response = client
49 .query::<Query, _>(vars)
50 .await
51 .map_err(Error::Client)?;
52 let data = response.try_into_data()?;
53
54 let MapDfsConnection { nodes, page_info } = extract(data)?;
55 Ok((page_info, nodes.into_iter().flat_map(MapDf::into_orders)))
56}
57
58fn extract(data: Option<Query>) -> Result<MapDfsConnection, &'static str> {
59 graphql_extract::extract!(data => {
60 map? {
61 map_dfs?
62 }
63 });
64 Ok(map_dfs)
65}
66
67#[cfg(test)]
68#[allow(clippy::unwrap_used)]
69#[test]
70fn gql_output() {
71 use cynic::QueryBuilder as _;
72
73 let vars = Variables {
74 map: Address::ZERO,
75 at_checkpoint: None,
76 first: Some(10),
77 after: None,
78 };
79 let operation = Query::build(vars);
80 insta::assert_snapshot!(operation.query, @r"
81 query Query($map: SuiAddress!, $atCheckpoint: UInt53, $first: Int, $after: String) {
82 map: object(address: $map, atCheckpoint: $atCheckpoint) {
83 map_dfs: dynamicFields(first: $first, after: $after) {
84 nodes {
85 map_df: value {
86 __typename
87 ... on MoveValue {
88 type {
89 repr
90 }
91 bcs
92 }
93 }
94 }
95 pageInfo {
96 hasNextPage
97 endCursor
98 }
99 }
100 }
101 }
102 ");
103}
104
105#[derive(cynic::QueryVariables, Clone, Debug)]
106struct Variables {
107 map: Address,
108 at_checkpoint: Option<u64>,
109 first: Option<i32>,
110 after: Option<String>,
111}
112
113#[derive(cynic::QueryFragment, Debug)]
114#[cynic(variables = "Variables")]
115struct Query {
116 #[arguments(address: $map, atCheckpoint: $at_checkpoint)]
117 #[cynic(alias, rename = "object")]
118 map: Option<MapAsOwner>,
119}
120
121#[derive(cynic::QueryFragment, Debug)]
122#[cynic(graphql_type = "Object", variables = "Variables")]
123struct MapAsOwner {
124 #[arguments(first: $first, after: $after)]
125 #[cynic(alias, rename = "dynamicFields")]
126 map_dfs: Option<MapDfsConnection>,
127}
128
129#[derive(cynic::QueryFragment, Debug)]
130#[cynic(graphql_type = "DynamicFieldConnection")]
131struct MapDfsConnection {
132 nodes: Vec<MapDf>,
133 page_info: PageInfoForward,
134}
135
136#[derive(cynic::QueryFragment, Debug)]
137#[cynic(graphql_type = "DynamicField")]
138struct MapDf {
139 #[cynic(alias, rename = "value")]
140 map_df: Option<MapDfValue>,
141}
142
143impl MapDf {
144 fn into_orders(self) -> impl Iterator<Item = (u128, Order)> {
145 self.map_df
146 .into_iter()
147 .map(MapDfValue::into_move_value)
148 .filter_map(Result::ok)
149 .map(MoveInstance::<Leaf<Order>>::try_from)
150 .filter_map(Result::ok)
152 .flat_map(|leaf| Vec::from(leaf.value.keys_vals).into_iter())
153 .map(|pair| (pair.key, pair.val))
154 }
155}
156
157#[derive(cynic::InlineFragments, Debug, EnumAsInner)]
158#[cynic(graphql_type = "DynamicFieldValue")]
159enum MapDfValue {
160 MoveValue(MoveValueGql),
161 #[cynic(fallback)]
162 Unknown,
163}