方向分页
GraphQLQueryPager
支持双向分页,即正方向和反方向的分页。
正向分页
正向分页是最常见的分页形式。它用于获取列表中的下一n
项。根据我们的需求有许多选择 —— 无论我们使用一个查询还是两个,我们是否想使用一个游标或者偏移,我们是否想转换结果,等等 - 我们将检查使用单个查询中的游标。
let initialQuery = MyQuery(first: 10, after: nil)let pager = GraphQLQueryPager(client: client,initialQuery: initialQuery,extractPageInfo: { data inCursorBasedPagination.Forward(hasNext: data.values.pageInfo.hasNextPage ?? false,endCursor: data.values.pageInfo.endCursor)},pageResolver: { page, paginationDirection in// As we only want to support forward pagination, we can return `nil` for reverse paginationswitch paginationDirection {case .next:return MyQuery(first: 10, after: page.endCursor ?? .none)case .previous:return nil}})
反向分页
反向分页用于获取列表中的前 n
项。虽然根据需求我们有很多选择——是使用一个还是两个查询,是希望使用游标还是偏移量,是否想要转换结果等——但我们将探讨使用单个查询与游标结合的方法。
let initialQuery = MyQuery(first: 10, after: nil)let pager = GraphQLQueryPager(client: client,initialQuery: initialQuery,extractPageInfo: { data inCursorBasedPagination.Reverse(hasNext: data.values.pageInfo.hasPrevious ?? false,endCursor: data.values.pageInfo.startCursor)},pageResolver: { page, paginationDirection in// As we only want to support reverse pagination, we can return `nil` for forward paginationswitch paginationDirection {case .next:return nilcase .previous:return MyQuery(first: 10, before: page.startCursor ?? .none)}})
双向分页
双向分页用于获取列表中下一个 n
项以及前 n
项。考虑到我们可以双向获取,这意味着最初的查询结果既不在列表的头部也不在尾部。在这个例子中,我们将探讨使用单个查询与游标结合的方法。
let pager = GraphQLQueryPager(client: client,initialQuery: MyQuery(first: 10, after: nil),extractPageInfo: { data inCursorBasedPagination.Bidirectional(hasNext: data.values.pageInfo.hasNextPage ?? false,endCursor: data.values.pageInfo.endCursor,hasPrevious: data.values.pageInfo.hasPreviousPage ?? false,startCursor: data.values.pageInfo.startCursor)},pageResolver: { page, direction inswitch direction {case .next:return MyQuery(first: 10, after: page?.endCursor ?? .none)case .previous:return MyQuery(first: 10, before: page?.startCursor ?? .none)}})
自定义配置
通常,建议使用便利初始化器来创建配置好的 GraphQLQueryPager
。然而,如果您需要自定义配置,可以直接使用 init
方法。如果您的应用程序只使用特定类型的分页,您可以声明一个可通用于整个应用的自定义 GraphQLQueryPager
便利初始化器。这允许您轻松地实例化分页器,无需担心应用程序不支持的情况。如果您的分页方案只支持向前分页和偏移量,您可以声明一个只支持向前分页和偏移量的自定义 GraphQLQueryPager
便利初始化器。在这个例子中,我们声明了两个正向偏移量分页的初始化器——一个是带有 transform
的,另一个不带:
extension GraphQLQueryPager {static func makeForwardOffsetQueryPager<InitialQuery: GraphQLQuery>(client: ApolloClientProtocol,watcherDispatchQueue: DispatchQueue = .main,queryProvider: @escaping (OffsetPagination.Forward?) -> InitialQuery,extractPageInfo: @escaping (InitialQuery.Data) -> OffsetPagination.Forward) -> GraphQLQueryPager where Model == PaginationOutput<InitialQuery, InitialQuery> {GraphQLQueryPager.init(client: client,initialQuery: queryProvider(nil),watcherDispatchQueue: watcherDispatchQueue,extractPageInfo: pageExtraction(transform: extractPageInfo),pageResolver: { page, direction inguard direction == .next else { return nil }return queryProvider(page)})}static func makeForwardOffsetQueryPager<InitialQuery: GraphQLQuery, T>(client: ApolloClientProtocol,watcherDispatchQueue: DispatchQueue = .main,queryProvider: @escaping (OffsetPagination.Forward?) -> InitialQuery,extractPageInfo: @escaping (InitialQuery.Data) -> OffsetPagination.Forward,transform: @escaping (InitialQuery.Data) throws -> Model) -> GraphQLQueryPager where Model: RangeReplaceableCollection, T == Model.Element {GraphQLQueryPager.init(client: client,initialQuery: queryProvider(nil),watcherDispatchQueue: watcherDispatchQueue,extractPageInfo: pageExtraction(transform: extractPageInfo),pageResolver: { page, direction inguard direction == .next else { return nil }return queryProvider(page)},initialTransform: transform,pageTransform: transform)}}private func pageExtraction<InitialQuery: GraphQLQuery, P: PaginationInfo, T>(transform: @escaping (InitialQuery.Data) -> P) -> (PageExtractionData<InitialQuery, InitialQuery, T>) -> P {{ extractionData inswitch extractionData {case .initial(let value, _), .paginated(let value, _):return transform(value)}}}private func pageExtraction<InitialQuery: GraphQLQuery, PaginatedQuery: GraphQLQuery, P: PaginationInfo, T>(initialTransform: @escaping (InitialQuery.Data) -> P,paginatedTransform: @escaping (PaginatedQuery.Data) -> P) -> (PageExtractionData<InitialQuery, PaginatedQuery, T>) -> P {{ extractionData inswitch extractionData {case .initial(let value, _):return initialTransfom(value)case .paginated(let value, _):return paginatedTransform(value)}}}