Skip to content

Commit

Permalink
Additional conveniences for offset pagination
Browse files Browse the repository at this point in the history
  • Loading branch information
Iron-Ham committed Feb 14, 2024
1 parent c2de5b7 commit fe2de1a
Show file tree
Hide file tree
Showing 5 changed files with 306 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ public extension GraphQLQueryPager {
static func makeForwardOffsetQueryPager<InitialQuery: GraphQLQuery>(
client: ApolloClientProtocol,
watcherDispatchQueue: DispatchQueue = .main,
queryProvider: @escaping (OffsetPagination?) -> InitialQuery,
extractPageInfo: @escaping (InitialQuery.Data) -> OffsetPagination
queryProvider: @escaping (OffsetPagination.Forward?) -> InitialQuery,
extractPageInfo: @escaping (InitialQuery.Data) -> OffsetPagination.Forward
) -> GraphQLQueryPager where Model == PaginationOutput<InitialQuery, InitialQuery> {
GraphQLQueryPager(pager: GraphQLQueryPagerCoordinator(
client: client,
Expand All @@ -26,11 +26,33 @@ public extension GraphQLQueryPager {
))
}

static func makeForwardOffsetQueryPager<InitialQuery: GraphQLQuery>(
client: ApolloClientProtocol,
watcherDispatchQueue: DispatchQueue = .main,
queryProvider: @escaping (OffsetPagination.Forward?) -> InitialQuery,
extractPageInfo: @escaping (InitialQuery.Data) -> OffsetPagination.Forward,
transform: @escaping ([InitialQuery.Data], InitialQuery.Data, [InitialQuery.Data]) throws -> Model
) -> GraphQLQueryPager {
GraphQLQueryPager(
pager: GraphQLQueryPagerCoordinator(
client: client,
initialQuery: queryProvider(nil),
watcherDispatchQueue: watcherDispatchQueue,
extractPageInfo: pageExtraction(transform: extractPageInfo),
pageResolver: { page, direction in
guard direction == .next else { return nil }
return queryProvider(page)
}
),
transform: transform
)
}

static func makeForwardOffsetQueryPager<InitialQuery: GraphQLQuery, T>(
client: ApolloClientProtocol,
watcherDispatchQueue: DispatchQueue = .main,
queryProvider: @escaping (OffsetPagination?) -> InitialQuery,
extractPageInfo: @escaping (InitialQuery.Data) -> OffsetPagination,
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(
Expand All @@ -52,8 +74,8 @@ public extension GraphQLQueryPager {
static func makeReverseOffsetQueryPager<InitialQuery: GraphQLQuery>(
client: ApolloClientProtocol,
watcherDispatchQueue: DispatchQueue = .main,
queryProvider: @escaping (OffsetPagination?) -> InitialQuery,
extractPageInfo: @escaping (InitialQuery.Data) -> OffsetPagination
queryProvider: @escaping (OffsetPagination.Reverse?) -> InitialQuery,
extractPageInfo: @escaping (InitialQuery.Data) -> OffsetPagination.Reverse
) -> GraphQLQueryPager where Model == PaginationOutput<InitialQuery, InitialQuery> {
GraphQLQueryPager(pager: GraphQLQueryPagerCoordinator(
client: client,
Expand All @@ -67,11 +89,33 @@ public extension GraphQLQueryPager {
))
}

static func makeReverseOffsetQueryPager<InitialQuery: GraphQLQuery>(
client: ApolloClientProtocol,
watcherDispatchQueue: DispatchQueue = .main,
queryProvider: @escaping (OffsetPagination.Reverse?) -> InitialQuery,
extractPageInfo: @escaping (InitialQuery.Data) -> OffsetPagination.Reverse,
transform: @escaping ([InitialQuery.Data], InitialQuery.Data, [InitialQuery.Data]) throws -> Model
) -> GraphQLQueryPager {
GraphQLQueryPager(
pager: GraphQLQueryPagerCoordinator(
client: client,
initialQuery: queryProvider(nil),
watcherDispatchQueue: watcherDispatchQueue,
extractPageInfo: pageExtraction(transform: extractPageInfo),
pageResolver: { page, direction in
guard direction == .previous else { return nil }
return queryProvider(page)
}
),
transform: transform
)
}

static func makeReverseOffsetQueryPager<InitialQuery: GraphQLQuery, T>(
client: ApolloClientProtocol,
watcherDispatchQueue: DispatchQueue = .main,
queryProvider: @escaping (OffsetPagination?) -> InitialQuery,
extractPageInfo: @escaping (InitialQuery.Data) -> OffsetPagination,
queryProvider: @escaping (OffsetPagination.Reverse?) -> InitialQuery,
extractPageInfo: @escaping (InitialQuery.Data) -> OffsetPagination.Reverse,
transform: @escaping (InitialQuery.Data) throws -> Model
) -> GraphQLQueryPager where Model: RangeReplaceableCollection, T == Model.Element {
GraphQLQueryPager(
Expand All @@ -90,6 +134,87 @@ public extension GraphQLQueryPager {
)
}

static func makeBidirectionalOffsetQueryPager<InitialQuery: GraphQLQuery>(
client: ApolloClientProtocol,
start: OffsetPagination.Bidirectional?,
watcherDispatchQueue: DispatchQueue = .main,
queryProvider: @escaping (OffsetPagination.Bidirectional?) -> InitialQuery,
previousQueryProvider: @escaping (OffsetPagination.Bidirectional?) -> InitialQuery,
extractPageInfo: @escaping (InitialQuery.Data) -> OffsetPagination.Bidirectional
) -> GraphQLQueryPager where Model == PaginationOutput<InitialQuery, InitialQuery> {
GraphQLQueryPager(pager: GraphQLQueryPagerCoordinator(
client: client,
initialQuery: queryProvider(start),
watcherDispatchQueue: watcherDispatchQueue,
extractPageInfo: pageExtraction(transform: extractPageInfo),
pageResolver: { page, direction in
switch direction {
case .next:
return queryProvider(page)
case .previous:
return previousQueryProvider(page)
}
}
))
}

static func makeBidirectionalOffsetQueryPager<InitialQuery: GraphQLQuery>(
client: ApolloClientProtocol,
start: OffsetPagination.Bidirectional?,
watcherDispatchQueue: DispatchQueue = .main,
queryProvider: @escaping (OffsetPagination.Bidirectional?) -> InitialQuery,
previousQueryProvider: @escaping (OffsetPagination.Bidirectional?) -> InitialQuery,
extractPageInfo: @escaping (InitialQuery.Data) -> OffsetPagination.Bidirectional,
transform: @escaping ([InitialQuery.Data], InitialQuery.Data, [InitialQuery.Data]) throws -> Model
) -> GraphQLQueryPager {
GraphQLQueryPager(
pager: GraphQLQueryPagerCoordinator(
client: client,
initialQuery: queryProvider(start),
watcherDispatchQueue: watcherDispatchQueue,
extractPageInfo: pageExtraction(transform: extractPageInfo),
pageResolver: { page, direction in
switch direction {
case .next:
return queryProvider(page)
case .previous:
return previousQueryProvider(page)
}
}
),
transform: transform
)
}

static func makeBidirectionalOffsetQueryPager<InitialQuery: GraphQLQuery, T>(
client: ApolloClientProtocol,
start: OffsetPagination.Bidirectional?,
watcherDispatchQueue: DispatchQueue = .main,
queryProvider: @escaping (OffsetPagination.Bidirectional?) -> InitialQuery,
previousQueryProvider: @escaping (OffsetPagination.Bidirectional?) -> InitialQuery,
extractPageInfo: @escaping (InitialQuery.Data) -> OffsetPagination.Bidirectional,
transform: @escaping (InitialQuery.Data) throws -> Model
) -> GraphQLQueryPager where Model: RangeReplaceableCollection, T == Model.Element {
GraphQLQueryPager(
pager: GraphQLQueryPagerCoordinator(
client: client,
initialQuery: queryProvider(start),
watcherDispatchQueue: watcherDispatchQueue,
extractPageInfo: pageExtraction(transform: extractPageInfo),
pageResolver: { page, direction in
switch direction {
case .next:
return queryProvider(page)
case .previous:
return previousQueryProvider(page)
}
}
),
initialTransform: transform,
pageTransform: transform
)
}

// MARK: CursorBasedPagination.Forward Initializers

/// This convenience function creates an `GraphQLQueryPager` that paginates forward with only one query and has an output type of `Result<(PaginationOutput<InitialQuery, InitialQuery>, UpdateSource), Error>`.
Expand Down Expand Up @@ -522,8 +647,8 @@ public extension AsyncGraphQLQueryPager {
static func makeForwardOffsetQueryPager<InitialQuery: GraphQLQuery>(
client: ApolloClientProtocol,
watcherDispatchQueue: DispatchQueue = .main,
queryProvider: @escaping (OffsetPagination?) -> InitialQuery,
extractPageInfo: @escaping (InitialQuery.Data) -> OffsetPagination
queryProvider: @escaping (OffsetPagination.Forward?) -> InitialQuery,
extractPageInfo: @escaping (InitialQuery.Data) -> OffsetPagination.Forward
) async -> AsyncGraphQLQueryPager where Model == PaginationOutput<InitialQuery, InitialQuery> {
await AsyncGraphQLQueryPager(pager: AsyncGraphQLQueryPagerCoordinator(
client: client,
Expand All @@ -537,11 +662,33 @@ public extension AsyncGraphQLQueryPager {
))
}

static func makeForwardOffsetQueryPager<InitialQuery: GraphQLQuery>(
client: ApolloClientProtocol,
watcherDispatchQueue: DispatchQueue = .main,
queryProvider: @escaping (OffsetPagination.Forward?) -> InitialQuery,
extractPageInfo: @escaping (InitialQuery.Data) -> OffsetPagination.Forward,
transform: @escaping ([InitialQuery.Data], InitialQuery.Data, [InitialQuery.Data]) throws -> Model
) async -> AsyncGraphQLQueryPager {
await AsyncGraphQLQueryPager(
pager: AsyncGraphQLQueryPagerCoordinator(
client: client,
initialQuery: queryProvider(nil),
watcherDispatchQueue: watcherDispatchQueue,
extractPageInfo: pageExtraction(transform: extractPageInfo),
pageResolver: { page, direction in
guard direction == .next else { return nil }
return queryProvider(page)
}
),
transform: transform
)
}

static func makeForwardOffsetQueryPager<InitialQuery: GraphQLQuery, T>(
client: ApolloClientProtocol,
watcherDispatchQueue: DispatchQueue = .main,
queryProvider: @escaping (OffsetPagination?) -> InitialQuery,
extractPageInfo: @escaping (InitialQuery.Data) -> OffsetPagination,
queryProvider: @escaping (OffsetPagination.Forward?) -> InitialQuery,
extractPageInfo: @escaping (InitialQuery.Data) -> OffsetPagination.Forward,
transform: @escaping (InitialQuery.Data) throws -> Model
) async -> AsyncGraphQLQueryPager where Model: RangeReplaceableCollection, T == Model.Element {
await AsyncGraphQLQueryPager(
Expand All @@ -563,8 +710,8 @@ public extension AsyncGraphQLQueryPager {
static func makeReverseOffsetQueryPager<InitialQuery: GraphQLQuery>(
client: ApolloClientProtocol,
watcherDispatchQueue: DispatchQueue = .main,
queryProvider: @escaping (OffsetPagination?) -> InitialQuery,
extractPageInfo: @escaping (InitialQuery.Data) -> OffsetPagination
queryProvider: @escaping (OffsetPagination.Reverse?) -> InitialQuery,
extractPageInfo: @escaping (InitialQuery.Data) -> OffsetPagination.Reverse
) async -> AsyncGraphQLQueryPager where Model == PaginationOutput<InitialQuery, InitialQuery> {
await AsyncGraphQLQueryPager(pager: AsyncGraphQLQueryPagerCoordinator(
client: client,
Expand All @@ -578,11 +725,33 @@ public extension AsyncGraphQLQueryPager {
))
}

static func makeReverseOffsetQueryPager<InitialQuery: GraphQLQuery>(
client: ApolloClientProtocol,
watcherDispatchQueue: DispatchQueue = .main,
queryProvider: @escaping (OffsetPagination.Reverse?) -> InitialQuery,
extractPageInfo: @escaping (InitialQuery.Data) -> OffsetPagination.Reverse,
transform: @escaping ([InitialQuery.Data], InitialQuery.Data, [InitialQuery.Data]) throws -> Model
) async -> AsyncGraphQLQueryPager {
await AsyncGraphQLQueryPager(
pager: AsyncGraphQLQueryPagerCoordinator(
client: client,
initialQuery: queryProvider(nil),
watcherDispatchQueue: watcherDispatchQueue,
extractPageInfo: pageExtraction(transform: extractPageInfo),
pageResolver: { page, direction in
guard direction == .previous else { return nil }
return queryProvider(page)
}
),
transform: transform
)
}

static func makeReverseOffsetQueryPager<InitialQuery: GraphQLQuery, T>(
client: ApolloClientProtocol,
watcherDispatchQueue: DispatchQueue = .main,
queryProvider: @escaping (OffsetPagination?) -> InitialQuery,
extractPageInfo: @escaping (InitialQuery.Data) -> OffsetPagination,
queryProvider: @escaping (OffsetPagination.Reverse?) -> InitialQuery,
extractPageInfo: @escaping (InitialQuery.Data) -> OffsetPagination.Reverse,
transform: @escaping (InitialQuery.Data) throws -> Model
) async -> AsyncGraphQLQueryPager where Model: RangeReplaceableCollection, T == Model.Element {
await AsyncGraphQLQueryPager(
Expand All @@ -601,6 +770,87 @@ public extension AsyncGraphQLQueryPager {
)
}

static func makeBidirectionalOffsetQueryPager<InitialQuery: GraphQLQuery>(
client: ApolloClientProtocol,
start: OffsetPagination.Bidirectional?,
watcherDispatchQueue: DispatchQueue = .main,
queryProvider: @escaping (OffsetPagination.Bidirectional?) -> InitialQuery,
previousQueryProvider: @escaping (OffsetPagination.Bidirectional?) -> InitialQuery,
extractPageInfo: @escaping (InitialQuery.Data) -> OffsetPagination.Bidirectional
) async -> AsyncGraphQLQueryPager where Model == PaginationOutput<InitialQuery, InitialQuery> {
await AsyncGraphQLQueryPager(pager: AsyncGraphQLQueryPagerCoordinator(
client: client,
initialQuery: queryProvider(start),
watcherDispatchQueue: watcherDispatchQueue,
extractPageInfo: pageExtraction(transform: extractPageInfo),
pageResolver: { page, direction in
switch direction {
case .next:
return queryProvider(page)
case .previous:
return previousQueryProvider(page)
}
}
))
}

static func makeBidirectionalOffsetQueryPager<InitialQuery: GraphQLQuery>(
client: ApolloClientProtocol,
start: OffsetPagination.Bidirectional?,
watcherDispatchQueue: DispatchQueue = .main,
queryProvider: @escaping (OffsetPagination.Bidirectional?) -> InitialQuery,
previousQueryProvider: @escaping (OffsetPagination.Bidirectional?) -> InitialQuery,
extractPageInfo: @escaping (InitialQuery.Data) -> OffsetPagination.Bidirectional,
transform: @escaping ([InitialQuery.Data], InitialQuery.Data, [InitialQuery.Data]) throws -> Model
) async -> AsyncGraphQLQueryPager {
await AsyncGraphQLQueryPager(
pager: AsyncGraphQLQueryPagerCoordinator(
client: client,
initialQuery: queryProvider(start),
watcherDispatchQueue: watcherDispatchQueue,
extractPageInfo: pageExtraction(transform: extractPageInfo),
pageResolver: { page, direction in
switch direction {
case .next:
return queryProvider(page)
case .previous:
return previousQueryProvider(page)
}
}
),
transform: transform
)
}

static func makeBidirectionalOffsetQueryPager<InitialQuery: GraphQLQuery, T>(
client: ApolloClientProtocol,
start: OffsetPagination.Bidirectional?,
watcherDispatchQueue: DispatchQueue = .main,
queryProvider: @escaping (OffsetPagination.Bidirectional?) -> InitialQuery,
previousQueryProvider: @escaping (OffsetPagination.Bidirectional?) -> InitialQuery,
extractPageInfo: @escaping (InitialQuery.Data) -> OffsetPagination.Bidirectional,
transform: @escaping (InitialQuery.Data) throws -> Model
) async -> AsyncGraphQLQueryPager where Model: RangeReplaceableCollection, T == Model.Element {
await AsyncGraphQLQueryPager(
pager: AsyncGraphQLQueryPagerCoordinator(
client: client,
initialQuery: queryProvider(start),
watcherDispatchQueue: watcherDispatchQueue,
extractPageInfo: pageExtraction(transform: extractPageInfo),
pageResolver: { page, direction in
switch direction {
case .next:
return queryProvider(page)
case .previous:
return previousQueryProvider(page)
}
}
),
initialTransform: transform,
pageTransform: transform
)
}

// MARK: CursorBasedPagination.Forward Initializers

/// This convenience function creates an `AsyncGraphQLQueryPager` that paginates forward with only one query and has an output type of `Result<(PaginationOutput<InitialQuery, InitialQuery>, UpdateSource), Error>`.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
extension OffsetPagination {
public struct Bidirectional: PaginationInfo, Hashable {
public let offset: Int
public var canLoadNext: Bool
public let canLoadPrevious: Bool

public init(offset: Int, canLoadNext: Bool, canLoadPrevious: Bool) {
self.offset = offset
self.canLoadNext = canLoadNext
self.canLoadPrevious = canLoadPrevious
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
extension OffsetPagination {
public struct Forward: PaginationInfo, Hashable {
public let offset: Int
public let canLoadNext: Bool
public var canLoadPrevious: Bool { false }

public init(offset: Int, canLoadNext: Bool) {
self.offset = offset
self.canLoadNext = canLoadNext
}
}

}
Loading

0 comments on commit fe2de1a

Please sign in to comment.