Home > Enterprise >  Combine array of object from different endpoint so it can also pagination
Combine array of object from different endpoint so it can also pagination

Time:11-27

I have 2 different endpoint:

  1. The first one have a pagination.
  2. The second one doesn't have pagination

I mapping the object from the first and second endpoint so they have the same object when i display it and limit only 10 item.

The Question is.. Is that possible to combine the API called so i can use pagination with different endpoint? so the result is

  1. Merge the object into 1
  2. Sort by date
  3. Limit the item only 10 item

So far i can't figure it out how to combine an API, this is my service setup

func getMessageList(page: Int) -> Single<[Message]> {
        return platformBanking.getMessageList(token: sessionStore.token, page: page, pageSize: 10)
    }

func getMoInbox() -> Single<[Message]> {
        return Single.create { single in
            MOInbox.sharedInstance.getInboxMessages { inboxMessages, accountMeta in
                var messages: [Message] = []

                inboxMessages.forEach { entry in
                    let message: Message = .init()
                    message.title = entry.notificationTitle
                    message.subtitle = entry.notificationSubTitle
                    message.body = entry.notificationBody
                    message.messageType = !(entry.campaignID?.isEmpty ?? false) ? 5 : 1
                    message.imageName = entry.notificationMediaURL ?? ""
                    message.date = entry.receivedDate?.string(withFormat: "dd MMM") ?? ""
                    message.isRead = entry.isRead
                    message.action = entry.deepLinkURL ?? ""

                    messages.append(message)
                }

                single(.success(messages))
            }
            return Disposables.create()
        }
    }

This is in my ViewModel

var filterMessages: [Message] = []
private var page: Int = 1
private var isLoading: Bool = false
private var endOfMessage: Bool = false

private func getMessageInboxList() {
        var inboxMessages: [Message] = []
        isLoading = true

        Single.zip(manageMessages.getMessageList(page: page), manageMessages.getMoInbox())
            .subscribe(onSuccess: { [weak self] firstMessage, secondMessage in
                inboxMessages.append(contentsOf: firstMessage)
                inboxMessages.append(contentsOf: secondMessage)
                self?.processMessages(messages: inboxMessages)
            }).disposed(by: disposedBag)
    }

    private func processMessages(messages: [Message]) {
        self.messages.append(contentsOf: messages)
        self.filterMessages = self.messages.sorted(by: { $0.date > $1.date })
        eventShowHideLoadingIndicator.onNext(false)
        if messages.count < 10 {
            endOfMessage = true
        }
        eventMessagesDataUpdated.onNext(())
        isLoading = false
    }

This is a function to called pagination in viewModel, when i try paginate i just realize i make a duplicate item from getMoInbox API called. but still combining the object and limiting by 10 item i still can't find the answer.

func loadMoreMessageInbox() {
        guard !endOfMessage, !isLoading, selectedIndex == 0 else { return }
        page = page   1
        getMessageInboxList()
}

Please help me guys.

CodePudding user response:

This requires a state machine. There are a number of different libraries that you could use (a partial list is at the bottom.)

Here is an example using the cycle function from my library.

enum Input {
    case nextPageRequested // emit this to `input` when you are ready for the next page.
    case pageReceived(Int, [Message]) // this is emitted with the page results.
}

struct State<T> {
    var pages: [Int: [T]] = [:] // stores the pages as they come in. The MoMessages will be stored in page 0
}

func example(input: Observable<Input>, messageManager: MessageManager) -> Observable<[Message]> {
    Single.zip(messageManager.getMoInbox(), messageManager.getMessageList(page: 1))
        .asObservable()
        .flatMap { moMessages, page1Messages in
            // create state machine initialized with the moMessages and page1Messages
            cycle(
                input: input,
                initialState: State(pages: [0: moMessages, 1: page1Messages]),
                reduce: { state, input in
                    // when a new page is received, store it
                    if case let .pageReceived(page, messages) = input {
                        state.pages[page] = messages
                    }
                },
                reaction: reaction(
                    request: { state, input in
                        // when a new page is requested, figure out what page number you need and return it (otherwise return nil)
                        guard case .nextPageRequested = input else { return nil }
                        return state.pages.keys.max()   1
                    },
                    effect: { page in
                        // get the page you need
                        messageManager.getMessageList(page: page)
                            .map { Input.pageReceived(page, $0) }
                            .asObservable()
                    }
                )
            )
        }
        .map { state in
            // sort the messages in the pages and return them
            state.pages.values.flatMap { $0 }.sorted(by: { $0.date > $1.date })
        }
}

Here's that promised list:

  • Related