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