sui_gql_client/queries/stream/
mod.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
//! Experimental abstractions to help create stream queries.
//!
//! Should be private until we iron out the api.
use std::future::Future;

use futures::Stream;

use super::fragments::PageInfo;
use super::Result;
use crate::GraphQlClient;

/// Helper for paginating queries forward.
///
/// # Arguments
/// - `client`
/// - `vars`: [`cynic::QueryVariables`] fragment; must implement [`UpdatePageInfo`]
/// - `request`: async function that maps `(client, vars) -> Page<Iter>`, where `Iter` is an
///   iterator over items of a **single** page's results
pub(super) fn forward<'a, Client, Vars, Req, Fut, Iter, T>(
    client: &'a Client,
    mut vars: Vars,
    mut request: Req,
) -> impl Stream<Item = Result<T, Client>> + 'a
where
    Client: GraphQlClient,
    Vars: 'a + UpdatePageInfo + Clone,
    Req: 'a + FnMut(&'a Client, Vars) -> Fut,
    Fut: Future<Output = Result<Page<Iter>, Client>>,
    Iter: IntoIterator<Item = Result<T, Client>>,
    T: 'static,
{
    async_stream::try_stream! {
        let mut has_next_page = true;
        while has_next_page {
            let page = request(client, vars.clone()).await?;

            vars.update_page_info(&page.info);
            has_next_page = page.info.has_next_page;

            for value in page.data {
                yield value?;
            }
        }
    }
}

pub(super) struct Page<T> {
    pub(super) info: PageInfo,
    pub(super) data: T,
}

impl<T> Page<T> {
    pub(super) fn new(page_info: impl Into<PageInfo>, data: T) -> Self {
        Self {
            info: page_info.into(),
            data,
        }
    }
}

pub(super) trait UpdatePageInfo {
    fn update_page_info(&mut self, info: &PageInfo);
}