sui_gql_client/queries/
transaction_blocks_status.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
use super::fragments::{PageInfoForward, TransactionBlockFilter};
use crate::queries::Error;
use crate::{extract, missing_data, schema, GraphQlClient, Paged, PagedResponse};

pub(super) async fn query<C: GraphQlClient>(
    client: &C,
    transaction_digests: Vec<String>,
) -> Result<impl Iterator<Item = Result<(String, bool), extract::Error>>, Error<C::Error>> {
    let vars = Variables {
        filter: Some(TransactionBlockFilter {
            transaction_ids: Some(transaction_digests),
            ..Default::default()
        }),
        first: None,
        after: None,
    };

    let response: PagedResponse<Query> = client.query_paged(vars).await.map_err(Error::Client)?;
    let (init, pages) = response
        .try_into_data()?
        .ok_or_else(|| missing_data!("No data"))?;

    Ok(init
        .transaction_blocks
        .nodes
        .into_iter()
        .chain(pages.into_iter().flat_map(|p| p.transaction_blocks.nodes))
        .map(digest_and_status))
}

fn digest_and_status(tx_block: TransactionBlock) -> Result<(String, bool), extract::Error> {
    let d = extract!(tx_block.digest?);
    let success = match extract!(tx_block.effects?.status?) {
        ExecutionStatus::Success => true,
        ExecutionStatus::Failure => false,
    };
    Ok((d, success))
}

#[derive(cynic::QueryVariables, Debug, Clone)]
pub struct Variables {
    filter: Option<TransactionBlockFilter>,
    after: Option<String>,
    first: Option<i32>,
}

#[derive(cynic::QueryFragment, Debug)]
#[cynic(graphql_type = "Query")]
#[cynic(variables = "Variables")]
pub struct Query {
    #[arguments(filter: $filter, first: $first, after: $after)]
    pub transaction_blocks: TransactionBlockConnection,
}

impl Paged for Query {
    type Input = Variables;
    type NextPage = Self;
    type NextInput = Variables;

    fn next_variables(&self, mut prev_vars: Self::Input) -> Option<Self::NextInput> {
        let PageInfoForward {
            has_next_page,
            end_cursor,
        } = &self.transaction_blocks.page_info;
        if *has_next_page {
            prev_vars.after.clone_from(end_cursor);
            Some(prev_vars)
        } else {
            None
        }
    }
}

#[derive(cynic::QueryFragment, Debug)]
pub struct TransactionBlockConnection {
    pub page_info: PageInfoForward,
    pub nodes: Vec<TransactionBlock>,
}

#[derive(cynic::QueryFragment, Debug)]
pub struct TransactionBlock {
    digest: Option<String>,
    effects: Option<TransactionBlockEffects>,
}

#[derive(cynic::QueryFragment, Debug)]
struct TransactionBlockEffects {
    status: Option<ExecutionStatus>,
}

#[derive(cynic::Enum, Clone, Copy, Debug)]
pub enum ExecutionStatus {
    Success,
    Failure,
}

#[cfg(test)]
#[test]
fn gql_output() {
    use cynic::QueryBuilder as _;

    let vars = Variables {
        filter: None,
        after: None,
        first: None,
    };
    let operation = Query::build(vars);
    insta::assert_snapshot!(operation.query, @r###"
    query Query($filter: TransactionBlockFilter, $after: String, $first: Int) {
      transactionBlocks(filter: $filter, first: $first, after: $after) {
        pageInfo {
          hasNextPage
          endCursor
        }
        nodes {
          digest
          effects {
            status
          }
        }
      }
    }
    "###);
}