2

Я новичок в Scala и в настоящее время пытаюсь работать с картой игры.Scala: Либо, вправо, влево

Это работает код, который я написал:

def authenticate = Action (BodyParsers.parse.json) { req => 
    req.body.validate[AuthenticationForm].map {form => 
     UserRepository.findByCredentials(form).map { user => 
      user.apiKeys.find(_.deviceId == form.deviceId).map { apiKey => 
       Ok(Json.toJson(apiKey)) 
      }.getOrElse({ 
       // HOW DO I TRANSFORM THIS INTO MORE BEAUTIFUL CODE 
       val createdApiKey = ApiKeyRepository.create(new ApiKey(form.deviceId, form.deviceId)) 
       val userToWithNewApiKey = user.copy(apiKeys = user.apiKeys.:+(createdApiKey)) 
       UserRepository.update(userToWithNewApiKey) 

       Ok(Json.toJson(createdApiKey)) 
      }) 
     }.getOrElse { 
      Unauthorized 
     } 
    }.getOrElse { 
     BadRequest 
    } 
} 

Ну, это не выглядит tooo приятно. Мы можем сделать лучше? Я еще не могу. Но я видел эту запись stackoverflow: https://stackoverflow.com/a/24085333/3038183 Это выглядит довольно хорошо :)

Теперь мне интересно, как преобразовать мой код, чтобы он выглядел в данном примере. Конечно, я уже пробовал, но я не мог скомпилировать его, а также не знаю, как обрабатывать код после комментария («КАК Я ПЕРЕДАЮ ЭТО В БОЛЬШЕ КРАСИВЕЙШЕГО КОДА»). В моем случае я использую play.api.mvc.Result вместо «Failure», как указано в ссылке выше. Итак, какого типа должен быть мой Ли [play.api.mvc.Result,? WhatHere?]?

С наилучшими пожеланиями

EDIT: Я принял ответ Трэвиса. Большое спасибо.

Для тех, кто заинтересован здесь лучше выглядит код, который я мог бы написать благодаря Travis:

def getApiKey(user: User, deviceId: String) : ApiKey = { 
    user.apiKeys.find(_.deviceId == deviceId).getOrElse { 
    val createdApiKey = 
     ApiKeyRepository.create(new ApiKey(deviceId, deviceId)) 

    val userToWithNewApiKey = 
     user.copy(apiKeys = user.apiKeys.:+(createdApiKey)) 

    UserRepository.update(userToWithNewApiKey) 
    createdApiKey 
    } 
} 

def authenticate = Action (BodyParsers.parse.json) { req => 
    (for { 
    form <- req.body.validate[AuthenticationForm].asOpt.toRight(BadRequest).right 
    user <- UserRepository.findByCredentials(form).toRight(Unauthorized).right 
    } yield { 
     Ok(Json.toJson(getApiKey(user, form.deviceId))) 
    }).merge 
} 

ответ

2

Это быстро и тестировался, но должен быть достойный старт. Сначала вы можете свернуть часть гнездования, используя toRight, чтобы получить Either[Status, ?]. Either не является монадическим, но его правая проекция (которую мы можем получить с помощью .right). Как только отказ больше не является возможным, мы используем yield для работы с результатами. Я переписал ваш материал apiKey, чтобы избежать дублирования части Ok(Json.toJson(key)).

def authenticate = Action (BodyParsers.parse.json) { req => 
    for { 
    form <- req.body.asOpt.toRight[Status](BadRequest).right 
    user <- UserRepository.findByCredentials(form).toRight[Status](
     Unauthorized 
    ).right 
    } yield { 
    val apiKey = user.apiKeys.find(_.deviceId == form.deviceId).getOrElse { 
     val createdApiKey = 
     ApiKeyRepository.create(new ApiKey(form.deviceId, form.deviceId)) 

     val userToWithNewApiKey = 
     user.copy(apiKeys = user.apiKeys.:+(createdApiKey)) 

     UserRepository.update(userToWithNewApiKey) 
     createdApiKey 
    } 
    Ok(Json.toJson(apiKey)): Status 
    }.e.merge 
} 

Конечный результат for -comprehension (то есть все, кроме .e.merge) является RightProjection[Status, Status]. Мы преобразуем это обратно в простой старый Either[Status, Status] с .e. На этом этапе нам больше не нужно отслеживать различия между неудачами и успехом, поэтому мы преобразуем все это в Status с .merge.

Смежные вопросы