0
votes

I have the following extension on a Publisher which allows me to paginate a URL request. I originally used this in a specific use case, where the Output of the publisher was of type CustomType.

extension Publisher where Output == CustomType,
                          Failure == Error {
  func paginate(pageIdPublisher: CurrentValueSubject<String?, Never>) -> AnyPublisher<[User], Never> {
    return self
      .handleEvents(receiveOutput: { response in
        if let maxId = response.pageId {
          pageIdPublisher.send(maxId)
        } else {
          pageIdPublisher.send(completion: .finished)
        }
      })
      .reduce([]) { allUsers, response in
        return response.users + allUsers
      }
      .catch { error in
        Just([])
      }
      .eraseToAnyPublisher()
  }
}

struct CustomType: Codable {
  let users: [User]
  let pageId: String?
}

This is called like this:

func loadItem() async throws -> [String] {
  let pageIdPublisher = CurrentValueSubject<String?, Never>(nil)

  return try await pageIdPublisher
    .flatMap { pageId in
      urlSession
        .publisher(
          for: .item(pageId: pageId),
          receiveOn: queue
        )
    }
    .paginate(pageIdPublisher: pageIdPublisher) // <- This part
    .singleOutput()
}

However, I now want to make it generic so that it can be used on any Output type, so long as it has a pageId and some kind of array.

I tried using a protocol Pageable like this:

protocol Pageable {
  associatedtype T

  var pageId: String? {get}
  var items: [T] {get}
}

But I can't use that with the extension because Output can't have be used with a protocol that contains an associatedType.

Is this possible?

You would be kinder to your potential helpers if you provided enough code to allow your example code to compile. - matt
Added a bit more... - Tometoyou