Проверка, которая возвращает более 1 ошибки - PullRequest
1 голос
/ 16 марта 2020

Я делаю несколько проверок, используя более старую Scala версию (2.0), но для каждой записи в настоящее время я получаю только 1 ошибку, предполагая, что в записи есть 2 или более ошибок - я хочу получить все неправильно с этим record / item

case class Response(request: JsValue,
    success: Boolean,
    column: Option[String] = None,
    message: String = "")

Вот валидатор, который возвращает все ошибки в json объекте

def validator(asJson: JsValue): Response = {
  if (name == "")
    return Response(asJson, false, Some("name"), "Name can't be blank")
  if (age == -1 || age == "N/A")
    return Response(asJson, false, Some("age"), "Age can't be blank")
  if (DOB == -1 || DOB == "N/A" )
    return Response(asJson, false, Some("DOB"), "DOB cannot be blank")
  else
    Response(asJson, true)
}

В настоящее время, если record1 не имеет имени + age + DOB ---> Я получаю только «Имя не может быть пустым»

Как получить (несколько ошибок на элемент вместо одной ошибки на элемент):

Имя не может быть пустым, возраст не может быть пустым, DOB не может быть пустым

Ответы [ 4 ]

4 голосов
/ 16 марта 2020

Это просто схема того, как это может работать:

def validator(asJson: JsValue): Response = {
  val errors = List(
    if (name == "" ) Some("Name can't be blank") else None,
    if (age == -1 || age == "N/A") Some("Age can't be blank") else None,
    if (DOB == -1 || DOB == "N/A" ) Some("DOB cannot be blank") else None,
  ).flatten

  if (errors.isEmpty) {
    Response(asJson, true)
  } else {
    Response(asJson, false, errors.mkString(", "))
  }
}

Значение errors создается путем создания значений List из Option, по одному для каждой проверки правильности. Метод flatten извлекает содержимое всех значений Some и удаляет все значения None. В результате получается список строк ошибок.

Остальной код форматирует Response на основе списка ошибок.


Если вы используете Scala 2.13, то Option.when делает тесты короче и понятнее:

Option.when(name == "")("Name can't be blank"),
Option.when(age == -1 || age == "N/A")("Age can't be blank"),
Option.when(DOB == -1 || DOB == "N/A")("DOB cannot be blank"),
3 голосов
/ 16 марта 2020

Прежде всего, в scala у вас нет оператора return, последний оператор возвращается (фактически он существует, но его использование не рекомендуется).

Во-вторых, в вашем коде Я полагаю, вы хотите пройти через несколько if заявлений. Но если вы вернетесь после каждого оператора if, то ваша функция будет существовать с первым истинным условием, и вы никогда не будете go для остальной части кода.

Если вы хотите собрать несколько экземпляров Response, просто соберите их в коллекцию и верните коллекцию в конце функции. Коллекция может быть List или Seq, или чем-то еще.

2 голосов
/ 16 марта 2020

Здесь является альтернативой с использованием Validated, которую вы могли бы рассмотреть в какой-то момент

import play.api.libs.json._
import cats.data.ValidatedNec
import cats.implicits._

case class User(name: String, age: Int, dob: String)
case class UserDTO(name: Option[String], age: Option[Int], dob: Option[String])
implicit val userDtoFormat = Json.format[UserDTO]
val raw =
  """
    |{
    |  "name": "Picard"
    |}
    |""".stripMargin
val userDto = Json.parse(raw).as[UserDTO]

def validateUser(userDto: UserDTO): ValidatedNec[String, User] = {
  def validateName(user: UserDTO): ValidatedNec[String, String] =
    user.name.map(_.validNec).getOrElse("Name is empty".invalidNec)

  def validateAge(user: UserDTO): ValidatedNec[String, Int] =
    user.age.map(_.validNec).getOrElse("Age is empty".invalidNec)

  def validateDob(user: UserDTO): ValidatedNec[String, String] =
    user.dob.map(_.validNec).getOrElse("DOB is empty".invalidNec)

  (validateName(userDto), validateAge(userDto), validateDob(userDto)).mapN(User)
}

validateUser(userDto)
// res0: cats.data.ValidatedNec[String,User] = Invalid(Chain(Age is empty, DOB is empty))

Обратите внимание на различие между UserDTO ("передача данных" объект "), который моделирует любую полезную нагрузку, отправленную по проводам, и User, которая моделирует фактические данные, которые нам требуются для нашей бизнес-логики c. Мы разделяем заботу о валидации пользователя на собственный метод validateUser. Теперь мы можем работать с действительным пользователем или ошибками вроде

validateUserDTO(userDto) match {
  case Valid(user) =>     
    // do something with valid user

  case Invalid(errors) => 
    // do something with errors
}
0 голосов
/ 16 марта 2020

В моем коде есть простой Validator, который делает именно это:

abstract class Validator[T, ERR >: Null] {
  def validate(a:T):Seq[ERR]
  protected def is(errorCase:Boolean, err: => ERR) = if (errorCase) err else null
  protected def check(checks:ERR*) = checks.collectFirst{ case x if x != null => x }.getOrElse(null)
  protected def checkAll(checks:ERR*) = checks.filter(_ != null)
}

//implement checks on some types
val passwordValidator = new Validator[String, String] {
  val universalPasswordInstruction = "Password needs to have at least one small letter, big letter, number and other sign."
  def validate(a: String) = checkAll( //here we check all cases
    is(a.length < 10, "Password should be longer than 10"),
    check( //here we check only first one.
      is(a.forall(_.isLetter), s"Passowrd has only letters. $universalPasswordInstruction"),
      is(a.forall(_.isLetterOrDigit), s"Use at least one ascii character like '#' or '*'. $universalPasswordInstruction"),
    ),
    is(a.contains("poop"), "Really!")
  )
}

val userValidator = new Validator[(String, String), (Int, String)] {
  override def validate(a: (String, String)): Seq[(Int, String)] = checkAll(
    is(a._1.length > 0, (0, "Username is empty!")),
  ) ++ passwordValidator.validate(a._2).map(x => (1, x))
}

//use
userValidator.validate("SomeUserName" -> "SomePassword") match {
  case Seq() => //OK case
  case errors => //deal with it
}

Возможно, это не так уж и красиво, но у меня работает :). Код прост и довольно понятен. Пустые значения здесь - это просто детали реализации (они не отображаются в коде пользователя и могут быть переключены на Опции).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...