Issue #451

For some services, we need to deal with separated APIs for getting ids and getting detail based on id.

To chain requests, we can use flatMap and Sequence, then collect to wait and get all elements in a single publish


Transforms all elements from an upstream publisher into a new or existing publisher.

struct FlatMap<NewPublisher, Upstream> where NewPublisher : Publisher, Upstream : Publisher, NewPublisher.Failure == Upstream.Failure


A publisher that publishes a given sequence of elements.

struct Sequence<Elements, Failure> where Elements : Sequence, Failure : Error
func fetchItems(completion: @escaping ([ItemProtocol]) -> Void) {
    requestCancellable = URLSession.shared
        .dataTaskPublisher(for: topStoriesUrl())
        .map({ $ })
        .decode(type: [Int].self, decoder: JSONDecoder())
        .flatMap({ (ids: [Int]) -> AnyPublisher<[HackerNews.Item], Error> in
            let publishers = ids.prefix(10).map({ id in
                return URLSession.shared
                    .dataTaskPublisher(for: self.storyUrl(id: id))
                    .map({ $ })
                    .decode(type: HackerNews.Item.self, decoder: JSONDecoder())

            return Publishers.Sequence<[AnyPublisher<HackerNews.Item, Error>], Error>(sequence: publishers)
                // Publishers.Sequence<[AnyPublisher<HackerNews.Item, Error>], Error>
                .flatMap({ $0 })
                // Publishers.FlatMap<AnyPublisher<HackerNews.Item, Error>, Publishers.Sequence<[AnyPublisher<HackerNews.Item, Error>], Error>>
                // Publishers.Collect<Publishers.FlatMap<AnyPublisher<HackerNews.Item, Error>, Publishers.Sequence<[AnyPublisher<HackerNews.Item, Error>], Error>>>
                // AnyPublisher<[HackerNews.Item], Error>
        .receive(on: RunLoop.main)
        .sink(receiveCompletion: { completionStatus in
            switch completionStatus {
            case .finished:
            case .failure(let error):
        }, receiveValue: { items in