Home > OS >  Project Reactor: Obtain Size of List Contained Within a Mono
Project Reactor: Obtain Size of List Contained Within a Mono

Time:12-30

I'm trying to do something again here in project reactor that I'm sure is reeeeeal simple for any of you project reactor gurus out there! I've been searching and scratching around with this one for a while now, and feel I'm once again hitting a wall with this stuff.

All I'm trying to do is determine if a List of objects contained within a Mono is empty or not.

This is what I have so far:

private Mono<Boolean> isLastCardForAccount(String accountId) {
    return cardService.getAccountCards(accountId)
        .hasElement();
}

I'm thinking the above might work, but I'm having difficulty figuring out how to extract/access the 'Boolean' contained within the returned Mono. I think I have to use 'subscribe' somehow right? I've mucked around with this stuff for a while now, but still no luck.

Here is how 'getAccountCards' is defined:

public Mono<List<Card>> getAccountCards(final String accountId) {
    return cardCrudRepository.getCardsByAccountId(accountId)
        .collectList();
}

From CardCrudRepository:

//  @Query("SELECT * FROM card WHERE account_id = :accountId") <-Not sure if I need this
Flux<Card> getCardsByAccountId(String accountId);

And lastly, how I'm using 'isLastCardForAccount':

public Mono<Void> updateCardStatus(String accountId, String cardId, String cardStatus) {
    return accountService.getAccount(accountId)
        .map(Account::getClientId)
        .map(clientId -> createUpdateCardStatusServiceRequestData(clientId, cardId, cardStatus))
        .flatMap(requestData -> cartaClient.updateCardStatus(requestData)
            .then(Mono.defer(() -> isCardBeingCancelled(cardStatus) ? allCardsCancelledForAccount(accountId) ? removeAccount(accountId) : 
(isLostOrStolen(cardStatus) ? replaceCard(cardId, cardStatus).flatMap(this::updateCardNumber) : Mono.empty()) : Mono.empty())));
}

As always, any and all help and insight is tremendously appreciated!

CodePudding user response:

I am not sure if this would resolve the issue but this way you can try to write your logic

 return accountService.getAccount(accountId)
            .map(Account::getClientId)
            .map(clientId -> createUpdateCardStatusServiceRequestData(clientId, cardId, cardStatus))
            .flatMap(requestData -> cartaClient.updateCardStatus(requestData)
                    .then(Mono.defer(() ->
                            Mono.zip( 
                                    Mono.just(isCardBeingCancelled(cardStatus)),
                                    isLastCardForAccount(accountId),
                                    Mono.just( isLostOrStolen(cardStatus) )
                                    ) 
                                    .map(tuple -> {
                                                WRITE YOUR IF ELSE LOGIC 

                                            })

The idea is to use zip and then use the tuple for writing logic. The Tuple would be of type Tuple3 of <Boolean, Boolean ,Boolean>. I made the assumption that isLostOrStolen(cardStatus) returns Boolean.

CodePudding user response:

One way of doing that is by using filterWhen operator like this:

.then(Mono.defer(() -> {
    if (isCardBeingCancelled(cardStatus)) {
        return Mono.just(accountId)
            .filterWhen(this::allCardsCancelledForAccount)
            .flatMap(this::removeAccount);
    } else if (isLostOrStolen(cardStatus)) {
        return replaceCard(cardId, cardStatus).flatMap(this::updateCardNumber);
    }
    return Mono.empty();
}))

You can use filterWhen in the case of asynchronous filtering. Check this section of Which operator do I need? reference and this How to filter Flux asynchronously.

As a side note, this is not going to work as you expect:

private Mono<Boolean> isLastCardForAccount(String accountId) {
    return cardService.getAccountCards(accountId)
        .hasElement();
}

public Mono<List<Card>> getAccountCards(final String accountId) {
    return cardCrudRepository.getCardsByAccountId(accountId)
        .collectList();
}

The collectList() will emit an empty List if there is no card. I'd use exists query instead:

public Mono<Boolean> isLastCardForAccount(final String accountId) {
    return cardCrudRepository.existsByAccountId(accountId);
}
  • Related