Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using map() or foreach() in validation #82

Closed
buildreactive opened this issue Nov 8, 2016 · 3 comments
Closed

Using map() or foreach() in validation #82

buildreactive opened this issue Nov 8, 2016 · 3 comments
Assignees
Labels

Comments

@buildreactive
Copy link

We have several cases where a collection of values need to be validated. Here's one:

    p.guestDetails.foreach { gd =>
      val passengerID: Try[Int] = Try(gd.paxNumber.replaceAll(BookingPrefix.concat(p.booking.bookingNumber), "").toInt)
      (passengerID.isSuccess is true) and (passengerID.get is between(1, 99))
    }

As you can see, the guest details contain some kind of oddly coded number. We have to try and convert it to an integer, make sure it is within 1..99, and validate accordingly.

I haven't been able to find a way to do this successfully. The obvious solutions of using foreach (or map) result in this error:

[error] /Users/zbeckman/Projects/Accenture/xiIntegrate/source/src/main/scala/common/validator/GuestBookingValidator.scala:24: Failed to extract object under validation from tree com.wix.accord.combinators.And[Int with Boolean] (type=com.wix.accord.combinators.And[Int with Boolean], raw=TypeTree())
[error]     p.guestDetails.foreach { gd =>
@buildreactive
Copy link
Author

buildreactive commented Nov 8, 2016

I'm struggling with finding an alternative that actually works with Accord. Tried this:

    p.guestDetails.each match {
      case gd: GuestDetail => Try(gd.paxNumber.replaceAll(BookingPrefix.concat(p.booking.bookingNumber), "").toInt) match {
        case Success(id) => id is between(1, 99)
        case _ => -1 is between(1, 99)
      }
    }

But, no good. (Yea, I know, the failure case is strange I'm still trying to find something that will work). Lots of errors from that one...

@holograph
Copy link
Contributor

There is a variety of ways to do this but, as with any testing framework, the recommended approach would be to create your own combinators. In this case what you basically have is a validator over paxNumber, which probably has its own type. You can extract this to its separate combinator fairly easily:

import com.wix.accord.dsl._
import scala.util.Try
import com.wix.accord._
import com.wix.accord.ViolationBuilder._

val BookingPrefix = "/booking"
case class GuestDetail(paxNumber: String)
case class Purchase(guestDetails: Option[GuestDetail], bookingNumber: String)

def aValidGuestId: Validator[Int] = between(1, 99)

def aValidPaxNumber(bookingNumber: String) = new Validator[String] {
  def apply(pax: String) =
    Try(pax.replace(BookingPrefix.concat(bookingNumber), "").toInt) match {
      case scala.util.Failure(_) => pax -> "is not a valid PAX number"
      case scala.util.Success(id) => aValidGuestId(id)
    }
}

def validForPurchase(bookingNumber: String) = validator[GuestDetail] { gd =>
   gd.paxNumber is aValidPaxNumber(bookingNumber)
}

implicit val pv = validator[Purchase] { p =>
  p.guestDetails.each is validForPurchase(p.bookingNumber)
}

validate(Purchase(Some(GuestDetail("12345")), "12345"))
// res8: com.wix.accord.Result = Failure(Set(RuleViolation(12345,got 12345, expected between 1 and 99,AccessChain(ArrayBuffer(guestDetails, paxNumber)))))

validate(Purchase(Some(GuestDetail("45")), "12"))
// res10: com.wix.accord.Result = Success

validate(Purchase(Some(GuestDetail("/booking/1245")), "12"))
// res11: com.wix.accord.Result = Failure(Set(RuleViolation(/booking/1245,is not a valid PAX number,AccessChain(ArrayBuffer(guestDetails, paxNumber)))))

validate(Purchase(Some(GuestDetail("/booking1245")), "12"))
// res12: com.wix.accord.Result = Success

I hope this helps...

@holograph holograph self-assigned this Nov 9, 2016
@holograph
Copy link
Contributor

P.S. there's a future feature to support map and the like directly, see #52. Feedback (or votes) appreciated as always.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants