-1

I have an usecase on my work and I want to discuss with you what should be the best approach to do it.

In repository functions that should finds only one line what should be the best approach, return left when entity is not found on database or return right null.

WHat do you think about it?

I tried to find some consistent answer to this question but could not find it. Imho the left behavior should be the best as the most cases on code you expect to find the entity on database to continue your function, so return null will cause to have null checks every time.

1 Answers1

1

There are a number of approaches you can take here, but nullable is certainly a fair option and there are idiomatic ways to deal with null in Kotlin and Arrow.

Let's take an example, if you're already working with Either, or typed errors, than I personally prefer to use domain specific errors. Since I try to always follow DDD.

EntityNotFound is often not more descriptive than null but UserNotFound or ArticleNotFound is much more precise about what went wrong. So if you DDD then I would recommend modelling your errors precisely like that.

sealed interface UserError
data class UserNotFound(val uuid: UUID): UserError
data class UserAlreadyExists(val username: String): UserError

data class User(val uuid: UUID)

interface UserPersistence {
  suspend fun insert(user: User): Either<UserAlreadyExists, UUID>
  suspend fun fetch(user: UUID): Either<UserNotFound, User>
}

Alternatively you could user User? instead of Either<UserNotFound, User> and use ensureNotNull inside either to achieve the same behavior.

interface UserPersistence {
  suspend fun insert(user: User): Either<UserAlreadyExists, UUID>
  suspend fun fetchOrNull(user: UUID): User?

  suspend fun fetch(uuid: UUID): Either<UserNotFound, User> =
    either { ensureNotNull(fetchOrNull(uuid)) { UserNotFound(uuid) }
}

This shows that the two can easily be converted between each-other. ensureNotNull also applies smart-casting on the value passed to it, similar to kotlin.requireNotNull of if(value != null) so you get all the goodies from the Kotlin language as well.

You can find a full example of a repository layer here, https://github.com/nomisRev/ktor-arrow-example/blob/main/src/main/kotlin/io/github/nomisrev/repo/UserPersistence.kt

nomisRev
  • 1,881
  • 8
  • 15