api-swift / Sources / IrdAPI / Core / Paginator.swift
197 words
 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
import Foundation

/// Collects every page of a listing into one array.
public enum Paginator {
    /// Cursor listings: `fetch` is called with nil first, then with each page's `next`
    /// cursor until it is nil.
    public static func cursor<Cursor: Sendable, Page: Sendable, Item: Sendable>(
        fetch: (Cursor?) async throws -> Page,
        items: (Page) -> [Item],
        next: (Page) -> Cursor?
    ) async throws -> [Item] {
        var all: [Item] = []
        var cursor: Cursor? = nil
        repeat {
            let page = try await fetch(cursor)
            all.append(contentsOf: items(page))
            cursor = next(page)
        } while cursor != nil
        return all
    }

    /// Offset listings: walks `limit`/`offset` (defaults 100 and 0) until a page comes
    /// back short. A `total` field is deliberately ignored.
    public static func offset<Page: Sendable, Item: Sendable>(
        limit: Int? = nil, offset: Int? = nil,
        fetch: (_ limit: Int, _ offset: Int) async throws -> Page,
        items: (Page) -> [Item]
    ) async throws -> [Item] {
        let limit = limit ?? 100
        var offset = offset ?? 0
        var all: [Item] = []
        while true {
            let rows = items(try await fetch(limit, offset))
            all.append(contentsOf: rows)
            if rows.count < limit { return all }
            offset += rows.count
        }
    }
}

static mirror of HEAD · about · clone: git clone https://ird.cod-sursa.ro/api-swift.git