Slide 67
Slide 67 text
val successfulAndUnsuccessfulPaymentValidations: List[Validation[Error,Payment]] =
List(Payment(PaymentAmount(10), Currency.USD, CheckNumber(15)),
Payment(PaymentAmount(-10), Currency.USD, CheckNumber(2_000_000)),
Payment(PaymentAmount(20), Currency.EUR, CardType.Visa, CardNumber("123")),
Payment(PaymentAmount(-20), Currency.EUR, CardType.Visa, CardNumber("005")),
Payment(PaymentAmount(30), Currency.EUR),
Payment(PaymentAmount(-30), Currency.EUR))
val expectedSuccessfulAndUnsuccessfulPaymentValidations
: List[Validation[Error,Payment]] =
List(Success(Payment.unsafe(PaymentAmount.unsafe(10.0),
Currency.USD,
PaymentMethod.Check(CheckNumber.unsafe(15)))),
Failure(Error(List("PaymentAmount cannot be negative: -10.0",
"CheckNumber cannot be greater than 1,000,000: 2000000"))),
Success(Payment.unsafe(PaymentAmount.unsafe(20.0),
Currency.EUR,
PaymentMethod.Card(CreditCardInfo(CardType.Visa,CardNumber.unsafe("123"))))),
Failure(Error(List("PaymentAmount cannot be negative: -20.0",
"CardNumber cannot be less than 111111: 005"))),
Success(Payment.unsafe(PaymentAmount.unsafe(30.0),
Currency.EUR,
PaymentMethod.Cash)),
Failure(Error(List("PaymentAmount cannot be negative: -30.0"))))
// turn a list of partly failed payment validations into a failed validation of a list of payments
val failedValidationOfPayments : Validation[Error,List[Payment]] =
listTraverse.sequence(successfulAndUnsuccessfulPaymentValidations)(errorValidationApplicative)
val expectedFailedValidationOfPayments : Validation[Error,List[Payment]] =
Failure(Error(List("PaymentAmount cannot be negative: -10.0",
"CheckNumber cannot be greater than 1,000,000: 2000000",
"PaymentAmount cannot be negative: -20.0",
"CardNumber cannot be less than 111111: 005",
"PaymentAmount cannot be negative: -30.0")))
assert( successfulAndUnsuccessfulPaymentValidations
== expectedSuccessfulAndUnsuccessfulPaymentValidations)
assert(failedValidationOfPayments
== expectedFailedValidationOfPayments)
On this slide we revisit the previous two tests but
include failed validations. This showcases how the
Validation Applicative for Error is able to return
Validation failures informing us of all constraint
violations, rather than just one (the first one).
Note that since sequence is defined in terms of the
map2 function of the applicative that it is being passed,
the sequence function benefits from the ability of said
map2 function to combine failed validations and so the
end result of sequencing is a single failure whose Error
informs us of all constraint violations.
val successfulAndUnsuccessfulPaymentValidations: List[Validation[Error,Payment]] =
List(Payment(PaymentAmount(10), Currency.USD, CheckNumber(15)),
Payment(PaymentAmount(-10), Currency.USD, CheckNumber(2_000_000)),
Payment(PaymentAmount(20), Currency.EUR, CardType.Visa, CardNumber("123")),
Payment(PaymentAmount(-20), Currency.EUR, CardType.Visa, CardNumber("005")),
Payment(PaymentAmount(30), Currency.EUR),
Payment(PaymentAmount(-30), Currency.EUR))
val expectedSuccessfulAndUnsuccessfulPaymentValidations
: List[Validation[Error,Payment]] =
List(Success(Payment.unsafe(PaymentAmount.unsafe(10.0),
Currency.USD,
PaymentMethod.Check(CheckNumber.unsafe(15)))),
Failure(Error(List("PaymentAmount cannot be negative: -10.0",
"CheckNumber cannot be greater than 1,000,000: 2000000"))),
Success(Payment.unsafe(PaymentAmount.unsafe(20.0),
Currency.EUR,
PaymentMethod.Card(CreditCardInfo(CardType.Visa,CardNumber.unsafe("123"))))),
Failure(Error(List("PaymentAmount cannot be negative: -20.0",
"CardNumber cannot be less than 111111: 005"))),
Success(Payment.unsafe(PaymentAmount.unsafe(30.0),
Currency.EUR,
PaymentMethod.Cash)),
Failure(Error(List("PaymentAmount cannot be negative: -30.0"))))
// turn a list of partly failed payment validations into a failed validation of a list of payments
val failedValidationOfPayments : Validation[Error,List[Payment]] =
listTraverse.sequence(successfulAndUnsuccessfulPaymentValidations)(errorValidationApplicative)
val expectedFailedValidationOfPayments : Validation[Error,List[Payment]] =
Failure(Error(List("PaymentAmount cannot be negative: -10.0",
"CheckNumber cannot be greater than 1,000,000: 2000000",
"PaymentAmount cannot be negative: -20.0",
"CardNumber cannot be less than 111111: 005",
"PaymentAmount cannot be negative: -30.0")))
assert( successfulAndUnsuccessfulPaymentValidations
== expectedSuccessfulAndUnsuccessfulPaymentValidations)
assert(failedValidationOfPayments
== expectedFailedValidationOfPayments)
On this slide we revisit the previous two tests but
include failed validations. This showcases how the
Validation Applicative for Error is able to return
Validation failures informing us of all constraint
violations, rather than just one (the first one).
Note that since sequence is defined in terms of the
map2 function of the applicative that it is being passed,
the sequence function benefits from the ability of said
map2 function to combine failed validations and so the
end result of sequencing is a single failure whose Error
informs us of all constraint violations.