【问题标题】:Can you convert this code to monad comprehensions using Arrow FX?您可以使用 Arrow FX 将此代码转换为 monad 理解吗?
【发布时间】:2020-11-08 14:11:58
【问题描述】:

你能把这个反应式方法转换成Arrow Fx Project Reactor monad comprehension吗?

class ApplicationServiceImpl(private val applicationRepository: ApplicationRepository,
                             private val clientRepository: ClientRepository) : ApplicationService {

    override fun findByProjectId(clientId: String, projectId: String): Flux<ApplicationOut> {
        return clientRepository.findById(clientId)
                .switchIfEmpty(ClientDoesntExistException(clientId).toMono())
                .flatMapMany { client ->
                    applicationRepository.findByProjectIdOrderByNameAsc(projectId).map {
                        it.convertToApplicationOut(client.timeZone)
                    }
                }
    }

}

我尝试过类似的方法,但它无效。

我发现的第一个问题是,最初我使用 flatMapMany 将 Mono 转换为 Flux。如果我使用FluxK.monad().fx.monad clientRepository.findById(clientId).k().bind() 没有可用的.bind() 函数。

如果我改用MonoK.monad().fx.monad,我不知道如何将输出转换为 Flux:

    override fun findByProjectId(clientId: String, projectId: String): Flux<out ApplicationOut> {

        return FluxK.monad().fx.monad {
            val client = clientRepository.findById(clientId).k().bind()
            if (client != null) {
                !applicationRepository.findByProjectIdOrderByNameAsc(projectId)
                        .map { it.convertToApplicationOut(client.timeZone) }.k()
            } else {
                throw !ClientDoesntExistException(clientId).toMono<ApplicationOut>().k()
            }
        }.fix().flux

更新

按照 El Paco 的回答,我将代码修改为:

        return FluxK.monad().fx.monad {
            val client = !clientRepository.findById(clientId).toFlux().k()
            if (client != null) {
                !applicationRepository.findByProjectIdOrderByNameAsc(projectId)
                        .map { it.convertToApplicationOut(client.timeZone) }.k()
            } else {
                !ClientDoesntExistException(clientId).toFlux<ApplicationOut>().k()
            }
        }.fix().flux

clientRepository.findById(clientId) 存在时可以正常工作。如果没有,它不会将 null 分配给 val 客户端,而是退出理解(否则不执行),因此我无法从理解内启动我的异常,我想这是正常的。

考虑下面的方法,我需要控制两种情况下客户端或项目不存在:

    return clientRepository.findById(clientId)
            .switchIfEmpty(ClientDoesntExistException(clientId).toMono())
            .flatMapMany { client ->
                applicationRepository.findByProjectIdOrderByNameAsc(projectId)
                        .switchIfEmpty(ClientDoesntExistException(projectId).toMono())
                        .map { it.convertToApplicationOut(client.timeZone) }
            }

考虑到 if/else 方法不起作用,我如何在使用推导时处理那些不存在的情况?

我可以在理解之外使用 switchIfEmpty 运算符,但我不知道原因(客户端不存在与项目不存在)

    return FluxK.monad().fx.monad {
        val client = !clientRepository.findById(clientId).toFlux().k()
        !applicationRepository.findByProjectIdOrderByNameAsc(projectId)
              .map { it.convertToApplicationOut(client.timeZone) }.k()        
    }.fix().flux
            .switchIfEmpty(XXX)

【问题讨论】:

    标签: kotlin project-reactor arrow-kt


    【解决方案1】:

    然后,您应该将所有操作转换为 Flux,在您的情况下 clientRepository.findById(clientId).toFlux().k()

    此外,您无需抛出该异常来中断链。

    !ClientDoesntExistException(clientId).toMono<ApplicationOut>().k()
    

    【讨论】:

    • 感谢您抽出宝贵时间回答这个问题。我已经更新了这个问题,对如何处理 switchIfEmpty 有一些疑问
    • SwitchIfEmpty 是尚未在 Arrow 上的 Stream 运算符。如果不为空,您可以通过收集到带有 Flux.of 的列表来获得相同的行为,否则绑定错误。
    猜你喜欢
    • 2011-05-31
    • 1970-01-01
    • 2018-11-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多