Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Kotlin - How to properly map result using Either?

I'm trying to read a list of objects from the database and mapping it to another type of list.

// Returns either a Failure or the expected result
suspend fun getCountries(): Either<Failure, List<CountryItem>> {
    // Get the result from the database
    val result = countryLocalDataSource.getCountries()

    // Left means Failure
    if (result.isLeft) {
        // Retrieve the error from the database
        lateinit var error: Failure
        result.either({
            error = it
        }, {})

        // Return the result
        return Either.Left(error)
    }

    // The database returns a List of Country objects, we need to map it to another object (CountryItem)
    val countryItems: MutableList<CountryItem> = mutableListOf()

    // Iterate the Country List and construct a new List of CountryItems
    result.map { countries -> {
        countries.forEach {
            // Assign some values from an Enum (localized string resources)
            val countryEnumValue = Countries.fromId(it.id)
            countryEnumValue?.let { countryIt ->
                val countryStringNameRes = countryIt.nameStringRes;

                // Create the new CountryItem object (@StringRes value: Int, isSelected: Bool)
                countryItems.add(CountryItem(countryStringNameRes, false))
            }
        }
    } }

    // Because this is a success, return as Right with the newly created List of CountryItems
    return Either.Right(countryItems)
}

For the sake of readability I didn't included the whole Repository or the DAO classes and I have left comments in the code snippet above.

In a nutshell: I'm using Kotlin's Coroutines for accessing the database in a separated thread and I'm handling the response on the UI Thread. Using the Either class in order to return two different results (failure or success).

The above code works, however It's too ugly. Is this the right approach to deliver the result?

What I'm trying to do is to refactor the code above.

The whole problem is caused by the two different object types. The Database Data Source API is returning an Either<Failure, List<Country>>, meanwhile the function is expected to return an Either<Failure, List<CountryItem>>.

I can't deliver a List<CountryItem> directly from the Database Data Source API, because Android Studio doesn't let me compile the project (entities implementing interfaces, compile error, etc.). What I'm trying to achieve is to map the Either result in a nicer way.

like image 602
Zbarcea Christian Avatar asked Feb 28 '19 22:02

Zbarcea Christian


1 Answers

Try using Kotlin's Result

So in your case you can write something like:

return result.mapCatching { list: List<Country> -> /*return here List<CountryItem>>*/ }

And for checking result call:

result.fold(
    onSuccess = {...},
    onFailure = {...}
)

In order to invoke a constructor you should call Result.success(T) or Result.failure(Throwable)

Unfortunately, you'll also need to suppress use-as-return-type warnings How to

like image 56
krsnk Avatar answered Nov 02 '22 08:11

krsnk