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