FollowProfileUseCase.kt

package com.example.realworldkotlinspringbootjdbc.usecase.profile

import arrow.core.Either
import arrow.core.Either.Left
import arrow.core.Either.Right
import arrow.core.left
import arrow.core.right
import com.example.realworldkotlinspringbootjdbc.domain.OtherUser
import com.example.realworldkotlinspringbootjdbc.domain.ProfileRepository
import com.example.realworldkotlinspringbootjdbc.domain.RegisteredUser
import com.example.realworldkotlinspringbootjdbc.domain.user.Username
import com.example.realworldkotlinspringbootjdbc.util.MyError
import org.springframework.stereotype.Service

interface FollowProfileUseCase {
    fun execute(username: String?, currentUser: RegisteredUser): Either<Error, OtherUser> = throw NotImplementedError()
    sealed interface Error : MyError {
        data class InvalidUsername(override val errors: List<MyError.ValidationError>) :
            Error,
            MyError.ValidationErrors

        data class NotFound(override val cause: MyError) : Error, MyError.MyErrorWithMyError
    }
}

@Service
class FollowProfileUseCaseImpl(val profileRepository: ProfileRepository) :
    FollowProfileUseCase {
    override fun execute(
        username: String?,
        currentUser: RegisteredUser
    ): Either<FollowProfileUseCase.Error, OtherUser> {
        /**
         * Username のバリデーション
         * Invalid -> 早期リターン
         */
        val validatedUsername = Username.new(username).fold(
            { return FollowProfileUseCase.Error.InvalidUsername(it).left() },
            { it }
        )

        return when (val followResult = profileRepository.follow(validatedUsername, currentUser.userId)) {
            /**
             * フォロー 失敗
             */
            is Left -> when (val error = followResult.value) {
                /**
                 * 原因: プロフィールが見つからなかった
                 */
                is ProfileRepository.FollowError.NotFoundProfileByUsername -> FollowProfileUseCase.Error.NotFound(
                    error
                ).left()
            }
            /**
             * フォロー 成功
             */
            is Right -> OtherUser.newWithoutValidation(
                followResult.value.userId,
                followResult.value.username,
                followResult.value.bio,
                followResult.value.image,
                followResult.value.following
            ).right()
        }
    }
}