hey channel. Beginner with Kotlin here… I really a...
# fp-in-kotlin
a
hey channel. Beginner with Kotlin here… I really appreciate if someone here could, please, share a tip for removing this duplicity of code. The data class for Entities and CrudRepository are similar but are different business domain.
Copy code
when(notificationType) {
    "x" -> npRepository.findByIdOrNull(notificationId)?.let {
        npsRepository.findByXId(notificationId, userId)
            .takeIf { it.isNotEmpty() }
            ?.map { it.apply { isRead = notificationRead } }
            ?.let { npsRepository.saveAll(it) }
            ?: npsRepository.save(
                NPS(
                    notificationPlatformId = notificationId,
                    userId = userId,
                    isRead = notificationRead
                )
            )
    } ?: logAndThrowNotFound(notificationType, notificationId, throwNotFound)

    "y" ->
        ntRepository.findByIdOrNull(notificationId)?.let {
            ntsRepository.findByXId(notificationId, userId)
                .takeIf { it.isNotEmpty() }
                ?.map { it.apply { isRead = notificationRead } }
                ?.let { ntsRepository.saveAll(it)}
                ?: ntsRepository.save(NTS(
                        notificationTenantId = notificationId,
                        userId = userId,
                        isRead = notificationRead
                    )
                )
        } ?: logAndThrowNotFound(notificationType, notificationId, throwNotFound)
...
}
b
Assuming
npRepo
and
ntRepo
have a common parent type: how about creating an extension function on that parent type to wrap
findByXId().map{}.lat{}
?
t
Also, if they are separate repositories (and therefore separate things) duplicate code doesnt have to be a bad thing, since they may be the same now, but might be different in the future. That said, making an extension method on CrudRepository would probably work indeed 🙂
b
The parent is
interface Repository<T>
and defines the common contract (methods) for both repositories. Then there is an extension method
findAndFlagReadOrCreate()
for specific Repositories whereby generic type
T: AbstractNS
. Class
AbstractNS
is the parent type for
NTS
and
NPS
. (AbstractNS could be an interface too) I could not figure out what type
findAndFlagReadOrCreate()
should return so picked Unit but that doesn’t really with with your
?: logAndThrowNotFound()
method.
Copy code
interface Repository<T> {
    fun findByIdOrNull(notiId: String): T?
    fun findByXId(notiId: String, userId: String): List<T>
    fun saveAll(t: Collection<T>)
    fun save(t: T)
}

fun <T : AbstractNS> Repository<T>.findAndFlagReadOrCreate(ns: T) {
    this.findByIdOrNull(ns.notificationId)?.let { nps ->
        this@findAndFlagReadOrCreate.findByXId(ns.notificationId, ns.userId)
            .takeIf { it.isNotEmpty() }
            ?.map { nps.apply { isRead = ns.isRead } }
            ?.let { this@findAndFlagReadOrCreate.saveAll(it) }
            ?: this@findAndFlagReadOrCreate.save(ns)
    }
}

abstract class AbstractNS {
    abstract val notificationId: String
    abstract val userId: String
    abstract var isRead: Boolean
}

class NPS(
    override val notificationId: String,
    override val userId: String,
    override var isRead: Boolean
) : AbstractNS() {
    val notificationPlatformId: String
        get() = this.notificationId
}

class NTS(
    override val notificationId: String,
    override val userId: String,
    override var isRead: Boolean
) : AbstractNS() {
    val notificationTenantId: String
        get() = this.notificationId
}

fun main() {
    val npsRepository: Repository<NPS>  /*to be initialized*/
    val ntsRepository: Repository<NTS> /*to be initialized*/
    val notificationId = "Bar"
    val userId = "Foo"
    val notificationRead = false

    npsRepository.findAndFlagReadOrCreate(NPS(notificationId, userId, notificationRead))
        ?: logAndThrowNotFound(notificationType, notificationId, throwNotFound)

    ntsRepository.findAndFlagReadOrCreate(NTS(notificationId, userId, notificationRead))
        ?: logAndThrowNotFound(notificationType, notificationId, throwNotFound)
}

fun logAndThrowNotFound(notificationType: String, notificationId: String): Unit {

}
a
Hi @Benoît Liessens I guess I got it. I’ve learned a lot here! Awesome! Thank you for your time.