美文网首页rust语言
如何将 Rust async-graphql 游标分页改为 pa

如何将 Rust async-graphql 游标分页改为 pa

作者: 子十一刻 | 来源:发表于2021-12-25 15:48 被阅读0次

按官方文档默认是游标链接的分页方式

游标链接代码如下:

    async fn numbers(
        &self,
        after: Option<String>,
        before: Option<String>,
        first: Option<i32>,
        last: Option<i32>,
    ) -> FieldResult<Connection<usize, i32, EmptyFields, EmptyFields>> {
        query(
            after, before, first, last,
            |after, before, first, last| async move {
            let mut start = after.map(|after| after + 1).unwrap_or(0);
            let mut end = before.unwrap_or(10000);
            if let Some(first) = first {
                end = (start + first).min(end);
            }
            if let Some(last) = last {
                start = if last > end - start {
                    end
                } else {
                    end - last
                };
            }
            let mut connection = Connection::new(
                start > 0,
                end < 10000
            );
            connection.append(
                (start..end)
                    .into_iter()
                    .map(|n| Edge::new(n, n as i32),
                ));
            Ok(connection)
        }).await
    }

类型 Connection<usize, i32, EmptyFields, EmptyFields> 需要4个泛型参数,定义如下:

pub struct Connection<C, T, EC = EmptyFields, EE = EmptyFields> {
    /// All edges of the current page.
    edges: Vec<Edge<C, T, EE>>,
    additional_fields: EC,
    has_previous_page: bool,
    has_next_page: bool,
}
  • C 游标 cursor 的类型 本例是 usize
  • T Edges.node列表数据的类型 本例是 i32
  • EC 附加数据类型
  • EE node列表数据的附加数据类型

返回数据类型如下图


numbers-types.png

接口 numbers 接收4个可选参数 after/before/first/last
返回 pageInfo 和 edges

要改用 page pageSize 的形式改动如下:

  • 原接口 after first 等4个参数 改为 page pageSize
  • 增加附加数据 EC, 我们使用 PageInfo
  • 修改Edges.node类型为我们实际的数据类型 DetailNode
  • 使用 Connection::with_additional_fields(false, false, page_info) 的第三个参数增加附加的分页数据

PageInfo 定义如下:

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct PageInfo {
    pub page: i32,
    pub page_size: i32,
    pub total_count: i32,
}

#[Object]
impl PageInfo {
    async fn page(&self) -> i32 {
        self.page
    }
    async fn page_size(&self) -> i32 {
        self.page_size
    }
    async fn total_count(&self) -> i32 {
        self.total_count
    }
}

具体实现:

    async fn nodes(
        &self,
        ctx: &Context<'_>,
        category: Option<String>,  // 相关筛选参数
        page: Option<i32>,   // 分页参数
        page_size: Option<i32>,
    ) -> FieldResult<Connection<i32, DetailNode, PageInfo, EmptyFields>> {
        let rb = ctx.data_unchecked::<GqlState>().rbatis.clone();
        let bundle = NodeBundle::Article.to_string();
        let page = page.unwrap_or(1);
        let page_size = page_size.unwrap_or(10);
        let category = category.unwrap_or(String::from(""));
        let limit = page_size;
        let offset = (page - 1 ) * limit;

        let mut total_count = 0;
        let mut data: Vec<DetailNode> = vec!();

        // 查询数据列表
        if let Ok(res) = find_nodes(
            rb.clone(),
            &bundle,
            &category,
            &offset,
            &limit
        ).await {
            data = res;
        }

        // 获取当前筛选条件对应的数据总数
        if let Ok(res) = find_nodes_count(
            rb.clone(),
            &bundle,
            &category,
        ).await {
            total_count = res.count;
        }
       
        // 附加分页数据
        let page_info = PageInfo {
            page,
            page_size,
            total_count
        };

        query(None, None, None, None,
              |_after, _before, _first, _last| async move {
                    let mut connection = Connection::with_additional_fields(
                        false, false, page_info
                    );
                    connection.append(
                        data
                            .iter()
                            .map(|item| Edge::new(item.nid, item.clone()))
                    );
                    Ok(connection)
              }
        ).await
    }

接口类型如图:

nodes-types.png

请求示例 获取第2页2条数据如下:

nodes-results.png

相关文章