cats.data.Validated.Invalid Scala Examples
The following examples show how to use cats.data.Validated.Invalid.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example.
Example 1
Source File: SimulatePlanAppIT.scala From Scala-Programming-Projects with MIT License | 5 votes |
package retcalc import cats.data.Validated.{Invalid, Valid} import org.scalactic.TypeCheckedTripleEquals import org.scalatest.{Matchers, WordSpec} class SimulatePlanAppIT extends WordSpec with Matchers with TypeCheckedTripleEquals { "SimulatePlanApp.strMain" should { "simulate a retirement plan using market returns" in { val actualResult = SimulatePlanApp.strMain( Array("1952.09,2017.09", "25", "40", "3000", "2000", "10000")) val expectedResult = s""" |Capital after 25 years of savings: 468925 |Capital after 40 years in retirement: 2958842 |""".stripMargin actualResult should ===(Valid(expectedResult)) } "return an error when the period exceeds the returns bounds" in { val actualResult = SimulatePlanApp.strMain( Array("1952.09,2017.09", "25", "60", "3000", "2000", "10000")) val expectedResult = "Cannot get the return for month 780. Accepted range: 0 to 779" actualResult should ===(Invalid(expectedResult)) } "return an usage example when the number of arguments is incorrect" in { val result = SimulatePlanApp.strMain( Array("1952.09:2017.09", "25.0", "60", "3'000", "2000.0")) result should ===(Invalid( """Usage: |simulatePlan from,until nbOfYearsSaving nbOfYearsRetired netIncome currentExpenses initialCapital | |Example: |simulatePlan 1952.09,2017.09 25 40 3000 2000 10000 |""".stripMargin)) } "return several errors when several arguments are invalid" in { val result = SimulatePlanApp.strMain( Array("1952.09:2017.09", "25.0", "60", "3'000", "2000.0", "10000")) result should ===(Invalid( """Invalid format for fromUntil. Expected: from,until, actual: 1952.09:2017.09 |Invalid number for nbOfYearsSaving: 25.0 |Invalid number for netIncome: 3'000 |Invalid number for currentExpenses: 2000.0""".stripMargin)) } } }
Example 2
Source File: fileValidation.scala From sbt-org-policies with Apache License 2.0 | 5 votes |
package sbtorgpolicies.settings import cats.data.Validated.{Invalid, Valid} import sbt.Keys._ import sbt._ import sbtorgpolicies.exceptions.ValidationException import sbtorgpolicies.rules._ import sbtorgpolicies.OrgPoliciesKeys._ import sbtorgpolicies.templates.FileType trait fileValidation extends ValidationFunctions { val fileValidation = new FileValidation val orgFileValidationTasks = Seq( orgValidateFiles := Def.task { val baseDirFile: File = (baseDirectory in LocalRootProject).value onlyRootUnitTask(baseDirectory.value, baseDirFile, streams.value.log) { val files: List[FileType] = orgEnforcedFilesSetting.value val validations: List[Validation] = files.flatMap { case FileType(true, _, _, _, path, _, _, list) => List( mkValidation( (baseDirFile / path).getAbsolutePath, if (list.isEmpty) List(emptyValidation) else list ) ) case _ => Nil } validationFilesTask(validations, streams.value.log) } }.value ) private[this] def validationFilesTask(list: List[Validation], log: Logger): Unit = list foreach (validationFileTask(_, log)) private[this] def validationFileTask(validation: Validation, log: Logger): Unit = { def errorHandler(description: String, errorList: List[ValidationException]): Unit = { val errorMessage = s"""$description |${errorList map (e => s" - ${e.message}") mkString "\n"} """.stripMargin if (validation.policyLevel == PolicyWarning) log.warn(errorMessage) else { throw ValidationException(errorMessage) } } fileValidation.validateFile( validation.validationRule.inputPath, validation.validationRule.validationList: _* ) match { case Valid(_) => log.info(s"File ${validation.validationRule.inputPath} was validated successfully") case Invalid(errors) => errorHandler( s"Some errors where found while validating ${validation.validationRule.inputPath}:", errors.toList ) } } }
Example 3
Source File: HealthCheckRoutes.scala From healthchecks with MIT License | 5 votes |
package com.github.everpeace.healthchecks.route import akka.http.scaladsl.model.StatusCodes._ import akka.http.scaladsl.server.Directives._ import akka.http.scaladsl.server.directives.PathDirectives import akka.http.scaladsl.server.{PathMatchers, Route} import cats.data.Validated.{Invalid, Valid} import com.github.everpeace.healthchecks.{HealthCheck, HealthCheckResult} import de.heikoseeberger.akkahttpcirce.FailFastCirceSupport._ import io.circe.JsonObject import io.circe.generic.JsonCodec import io.circe.generic.auto._ import scala.collection.convert.DecorateAsScala import scala.concurrent.{ExecutionContext, Future} object HealthCheckRoutes extends DecorateAsScala { @JsonCodec case class HealthCheckResultJson( name: String, severity: String, status: String, messages: List[String]) @JsonCodec case class ResponseJson(status: String, check_results: List[HealthCheckResultJson]) private def status(s: Boolean) = if (s) "healthy" else "unhealthy" private def statusCode(s: Boolean) = if (s) OK else ServiceUnavailable private def toResultJson(check: HealthCheck, result: HealthCheckResult) = HealthCheckResultJson( check.name, check.severity.toString, status(result.isValid), result match { case Valid(_) => List() case Invalid(errors) => errors.toList } ) def health( checks: HealthCheck* )(implicit ec: ExecutionContext ): Route = health("health", checks.toList) def health( path: String, checks: List[HealthCheck] )(implicit ec: ExecutionContext ): Route = { require(checks.nonEmpty, "checks must not empty.") require( checks.map(_.name).toSet.size == checks.length, s"HealthCheck name should be unique (given HealthCheck names = [${checks.map(_.name).mkString(",")}])." ) val rootSlashRemoved = if (path.startsWith("/")) path.substring(1) else path PathDirectives.path(PathMatchers.separateOnSlashes(rootSlashRemoved)) { parameter("full" ? false) { full => get { def isHealthy(checkAndResults: List[(HealthCheck, HealthCheckResult)]) = checkAndResults.forall(cr => cr._2.isValid || (!cr._1.severity.isFatal)) val checkAndResultsFuture = Future.traverse(checks) { c => c.run().map(c -> _) } if (full) { complete { checkAndResultsFuture.map { checkAndResults => val healthy = isHealthy(checkAndResults) statusCode(healthy) -> ResponseJson( status(healthy), checkAndResults.map { case (check, result) => toResultJson(check, result) } ) } } } else { complete { checkAndResultsFuture.map { checkAndResults => statusCode(isHealthy(checkAndResults)) -> JsonObject.empty } } } } } } } }
Example 4
Source File: ValidationExtension.scala From franklin with Apache License 2.0 | 5 votes |
package com.azavea.franklin.extensions.validation import cats.data.NonEmptyList import cats.data.Validated.{Invalid, Valid} import cats.kernel.Semigroup import com.azavea.stac4s.extensions.ItemAssetExtension import com.azavea.stac4s.extensions.{ExtensionResult, ItemExtension, LinkExtension} import eu.timepit.refined.types.string.NonEmptyString import io.circe._ import io.circe.refined._ import io.circe.syntax._ final case class ValidationExtension( attemptedExtensions: NonEmptyList[NonEmptyString], errors: List[NonEmptyString] ) object ValidationExtension { implicit val decValidationExtension: Decoder[ValidationExtension] = Decoder.forProduct2( "validation:attemptedExtensions", "validation:errors" )((extensions: NonEmptyList[NonEmptyString], errors: List[NonEmptyString]) => ValidationExtension(extensions, errors) ) implicit val encValidationExtension: Encoder.AsObject[ValidationExtension] = Encoder .AsObject[Map[String, Json]] .contramapObject((validationExtensionFields: ValidationExtension) => Map( "validation:attemptedExtensions" -> validationExtensionFields.attemptedExtensions.asJson, "validation:errors" -> validationExtensionFields.errors.asJson ) ) implicit val validationExtensionItemExtension: ItemExtension[ValidationExtension] = ItemExtension.instance implicit val validationExtensionLinkExtension: LinkExtension[ValidationExtension] = LinkExtension.instance implicit val validationExtensionAssetExtension: ItemAssetExtension[ValidationExtension] = ItemAssetExtension.instance implicit val semigroupValidationExtension: Semigroup[ValidationExtension] = new Semigroup[ValidationExtension] { def combine(x: ValidationExtension, y: ValidationExtension): ValidationExtension = { ValidationExtension( x.attemptedExtensions.concat(y.attemptedExtensions.toList), x.errors ++ y.errors ) } } def success(name: NonEmptyString) = ValidationExtension( NonEmptyList.of(name), Nil ) def failure(name: NonEmptyString, errors: List[DecodingFailure]) = ValidationExtension(NonEmptyList.of(name), errors map { (err: DecodingFailure) => NonEmptyString.from(CursorOp.opsToPath(err.history)) } collect { case Right(v) => v }) def fromResult[T](result: ExtensionResult[T], name: NonEmptyString) = result match { case Invalid(errs) => failure(name, errs collect { case e: DecodingFailure => e }) case Valid(_) => success(name) } }
Example 5
Source File: ConfigReaderInstances.scala From DataQuality with GNU Lesser General Public License v3.0 | 5 votes |
package com.agilelab.dataquality.common.instances import cats.data.Validated.{Invalid, Valid} import cats.data.{NonEmptyList, ValidatedNel} import cats.implicits._ import com.agilelab.dataquality.common.enumerations.DBTypes import com.agilelab.dataquality.common.models.DatabaseCommon import com.agilelab.dataquality.common.parsers.ConfigReader import com.agilelab.dataquality.common.parsers.DQConfig.AllErrorsOr import com.typesafe.config.Config import scala.util.{Failure, Success, Try} object ConfigReaderInstances { private def parseString(str: String)(implicit conf: Config): AllErrorsOr[String] = { Try(conf.getString(str)) match { case Success(v) => Valid(v) case Failure(_) => Invalid(NonEmptyList.one(s"Field $str is missing")) } } private def parseStringEnumerated(str: String, enum: Set[String])(implicit conf: Config): AllErrorsOr[String] = { Try(conf.getString(str)) match { case Success(v) if enum.contains(v) => Valid(v) case Success(v) => Invalid(NonEmptyList.one(s"Unsupported value of $str: $v")) case Failure(_) => Invalid(NonEmptyList.one(s"Field $str is missing")) } } implicit val databaseReader: ConfigReader[DatabaseCommon] = new ConfigReader[DatabaseCommon] { def read(conf: Config, enums: Set[String]*): AllErrorsOr[DatabaseCommon] = { val id: AllErrorsOr[String] = parseString("id")(conf) val subtype: AllErrorsOr[String] = parseStringEnumerated("subtype", DBTypes.names)(conf) Try(conf.getConfig("config")) match { case Success(innerConf) => val host: AllErrorsOr[String] = parseString("host")(innerConf) val port: AllErrorsOr[Option[Int]] = Valid(Try(innerConf.getString("port").toInt).toOption) val service: AllErrorsOr[Option[String]] = Valid(Try(innerConf.getString("service")).toOption) val user: AllErrorsOr[Option[String]] = Valid(Try(innerConf.getString("user")).toOption) val password: AllErrorsOr[Option[String]] = Valid(Try(innerConf.getString("password")).toOption) val schema: AllErrorsOr[Option[String]] = Valid(Try(innerConf.getString("schema")).toOption) (id, subtype, host, port, service, user, password, schema).mapN(DatabaseCommon.apply _) case Failure(_) => Invalid(NonEmptyList.one("Inner config is missing")) } } } // implicit val sourceReader: ConfigReader[SourceCommon] = // new ConfigReader[SourceCommon] { // override def read(value: Config): AllErrorsOr[SourceCommon] = ??? // } }
Example 6
Source File: BatchChangeInterfaces.scala From vinyldns with Apache License 2.0 | 5 votes |
package vinyldns.api.domain.batch import cats.data.Validated.{Invalid, Valid} import cats.data._ import cats.effect._ import cats.implicits._ import vinyldns.core.domain.DomainValidationError object BatchChangeInterfaces { type SingleValidation[A] = ValidatedNel[DomainValidationError, A] type ValidatedBatch[A] = List[ValidatedNel[DomainValidationError, A]] type BatchResult[A] = EitherT[IO, BatchChangeErrorResponse, A] implicit class IOBatchResultImprovements[A](theIo: IO[A]) { def toBatchResult: BatchResult[A] = EitherT.liftF(theIo) } implicit class IOEitherBatchResultImprovements[A](theIo: IO[Either[_, A]]) { def toBatchResult: BatchResult[A] = EitherT { theIo.map { case Right(r) => Right(r) case Left(err: BatchChangeErrorResponse) => Left(err) case Left(x) => Left(UnknownConversionError(s"Cannot convert item to BatchResponse: $x")) } } } implicit class EitherBatchResultImprovements[A](eth: Either[BatchChangeErrorResponse, A]) { def toBatchResult: BatchResult[A] = EitherT.fromEither[IO](eth) } implicit class BatchResultImprovements[A](a: A) { def toRightBatchResult: BatchResult[A] = EitherT.rightT[IO, BatchChangeErrorResponse](a) } implicit class BatchResultErrorImprovements[A](err: BatchChangeErrorResponse) { def toLeftBatchResult: BatchResult[A] = EitherT.leftT[IO, A](err) } implicit class ValidatedBatchImprovements[A](batch: ValidatedBatch[A]) { def mapValid[B](fn: A => ValidatedNel[DomainValidationError, B]): ValidatedBatch[B] = // gets rid of the map then flatmap thing we have to do when dealing with Seq[ValidatedNel[]] batch.map { case Valid(item) => fn(item) case Invalid(errList) => errList.invalid } def getValid: List[A] = batch.collect { case Valid(input) => input } def getInvalid: List[DomainValidationError] = batch .collect { case Invalid(input) => input } .flatMap(_.toList) } implicit class SingleValidationImprovements[A](validation: SingleValidation[A]) { def asUnit: SingleValidation[Unit] = validation.map(_ => ()) } implicit class IOCollectionImprovements[A](value: List[IO[A]]) { // Pulls out the successful IO from the list; drops IO failures def collectSuccesses(): IO[List[A]] = { val asSuccessfulOpt: List[IO[Option[A]]] = value.map { f => f.attempt.map { case Right(a) => Some(a) case _ => None } } asSuccessfulOpt.sequence[IO, Option[A]].map { lst => lst.collect { case Some(rs) => rs } } } } }
Example 7
Source File: ResultHelpers.scala From vinyldns with Apache License 2.0 | 5 votes |
package vinyldns.api import cats.data.Validated.{Invalid, Valid} import cats.data.ValidatedNel import cats.effect._ import cats.implicits._ import cats.scalatest.ValidatedMatchers import org.scalatest.matchers.should.Matchers import org.scalatest.propspec.AnyPropSpec import scala.concurrent.ExecutionContext import scala.concurrent.duration._ import scala.reflect.ClassTag final case class TimeoutException(message: String) extends Throwable(message) trait ResultHelpers { private implicit val timer: Timer[IO] = IO.timer(ExecutionContext.global) private implicit val cs: ContextShift[IO] = IO.contextShift(scala.concurrent.ExecutionContext.global) def await[T](f: => IO[_], duration: FiniteDuration = 1.second): T = awaitResultOf[T](f.map(_.asInstanceOf[T]).attempt, duration).toOption.get // Waits for the future to complete, then returns the value as an Either[Throwable, T] def awaitResultOf[T]( f: => IO[Either[Throwable, T]], duration: FiniteDuration = 1.second ): Either[Throwable, T] = { val timeOut = IO.sleep(duration) *> IO( TimeoutException("Timed out waiting for result").asInstanceOf[Throwable] ) IO.race(timeOut, f.handleError(e => Left(e))).unsafeRunSync() match { case Left(e) => Left(e) case Right(ok) => ok } } // Assumes that the result of the future operation will be successful, this will fail on a left disjunction def rightResultOf[T](f: => IO[Either[Throwable, T]], duration: FiniteDuration = 1.second): T = awaitResultOf[T](f, duration) match { case Right(result) => result case Left(error) => throw error } // Assumes that the result of the future operation will fail, this will error on a right disjunction def leftResultOf[T]( f: => IO[Either[Throwable, T]], duration: FiniteDuration = 1.second ): Throwable = awaitResultOf(f, duration).swap.toOption.get def leftValue[T](t: Either[Throwable, T]): Throwable = t.swap.toOption.get def rightValue[T](t: Either[Throwable, T]): T = t.toOption.get } object ValidationTestImprovements extends AnyPropSpec with Matchers with ValidatedMatchers { implicit class ValidatedNelTestImprovements[DomainValidationError, A]( value: ValidatedNel[DomainValidationError, A] ) { def failures: List[DomainValidationError] = value match { case Invalid(e) => e.toList case Valid(_) => fail("should have no failures!") // Will (correctly) cause expected failures to fail upon succeeding } def failWith[EE <: DomainValidationError](implicit tag: ClassTag[EE]): Unit = value.failures.map(_ shouldBe an[EE]) } }
Example 8
Source File: ValidatedMatchersSpec.scala From cats-scalatest with Apache License 2.0 | 5 votes |
package cats.scalatest import cats.data.Validated.{Invalid, Valid} import cats.data.{NonEmptyList, ValidatedNel} class ValidatedMatchersSpec extends TestBase with ValidatedMatchers { "ValidatedMatchers" should { val simpleFailureNel: ValidatedNel[String, Nothing] = Invalid(NonEmptyList.of(thisRecord, thisTobacconist)) "Match one specific element in an Invalid NEL" in { simpleFailureNel should haveInvalid(thisRecord) } "Match multiple specific elements in an Invalid NEL" in { simpleFailureNel should (haveInvalid(thisRecord).and(haveInvalid(thisTobacconist))) } "Match a specific element of a single Invalid" in { Invalid(thisRecord) should beInvalid(thisRecord) } "Test whether a Validated instance is a Invalid w/o specific element value" in { Invalid(thisTobacconist) should be(invalid) } "By negating 'invalid', test whether a Validated instance is a Valid" in { Valid(hovercraft) should not be (invalid) } "Test whether a Validated instance is a Valid" in { Valid(hovercraft) should be(valid) } "By negating 'valid', test whether a Validated instance is an invalid" in { Invalid(thisTobacconist) should not be (valid) } "Match a specific element of a single Valid" in { Valid(hovercraft) should beValid(hovercraft) } "Match one specific type in an Invalid NEL" in { simpleFailureNel should haveAnInvalid[String] val nel: ValidatedNel[String, Nothing] = Invalid(NonEmptyList.of("test")) nel should haveAnInvalid[String] nel should haveAnInvalid[Any] nel shouldNot haveAnInvalid[Int] val nel2: ValidatedNel[Nothing, Unit] = Valid(()) nel2 shouldNot haveAnInvalid[String] nel2 shouldNot haveAnInvalid[Unit] } } }
Example 9
Source File: GraphQLSuperMicroService.scala From cornichon with Apache License 2.0 | 5 votes |
package com.github.agourlay.cornichon.framework.examples.superHeroes.server import cats.data.Validated import cats.data.Validated.{ Invalid, Valid } import sangria.macros.derive._ import sangria.schema.Schema import sangria.schema._ import sangria.marshalling.circe._ import io.circe.generic.auto._ class GraphQLSuperMicroService(sm: SuperMicroService) { def publisherByName(sessionId: String, name: String): Option[Publisher] = unpack(sm.publisherByName(sessionId, name)) def superheroByName(sessionId: String, name: String, protectIdentity: Boolean = false): Option[SuperHero] = unpack(sm.superheroByName(sessionId, name, protectIdentity)) def updateSuperhero(sessionId: String, s: SuperHero): Option[SuperHero] = unpack(sm.updateSuperhero(sessionId, s)) private def unpack[A](v: Validated[ApiError, A]): Option[A] = v match { case Valid(p) => Some(p) case Invalid(e) => e match { case SessionNotFound(_) => None case PublisherNotFound(_) => None case SuperHeroNotFound(_) => None case _ => throw new RuntimeException(e.msg) } } } object GraphQlSchema { implicit val PublisherType = deriveObjectType[Unit, Publisher]( ObjectTypeDescription("A comics publisher.") ) implicit val SuperHeroType = deriveObjectType[Unit, SuperHero]( ObjectTypeDescription("A superhero.") ) implicit val PublisherInputType = deriveInputObjectType[Publisher]( InputObjectTypeName("PublisherInput") ) implicit val SuperHeroInputType = deriveInputObjectType[SuperHero]( InputObjectTypeName("SuperHeroInput") ) val QueryType = deriveObjectType[Unit, GraphQLSuperMicroService]( ObjectTypeName("Root"), ObjectTypeDescription("Gateway to awesomeness."), IncludeMethods("publisherByName", "superheroByName") ) val MutationType = deriveObjectType[Unit, GraphQLSuperMicroService]( ObjectTypeName("RootMut"), ObjectTypeDescription("Gateway to mutation awesomeness!"), IncludeMethods("updateSuperhero") ) val SuperHeroesSchema = Schema(QueryType, Some(MutationType)) }
Example 10
Source File: AssertStep.scala From cornichon with Apache License 2.0 | 5 votes |
package com.github.agourlay.cornichon.steps.regular.assertStep import cats.data._ import cats.data.Validated.Invalid import cats.syntax.either._ import com.github.agourlay.cornichon.core.ScenarioRunner._ import com.github.agourlay.cornichon.core._ import monix.eval.Task import scala.concurrent.duration.Duration case class AssertStep(title: String, action: ScenarioContext => Assertion, show: Boolean = true) extends LogValueStep[Done] { def setTitle(newTitle: String): Step = copy(title = newTitle) override def runLogValueStep(runState: RunState): Task[Either[NonEmptyList[CornichonError], Done]] = Task.delay { val assertion = action(runState.scenarioContext) assertion.validated match { case Invalid(e) => e.asLeft case _ => Done.rightDone } } override def onError(errors: NonEmptyList[CornichonError], runState: RunState, executionTime: Duration): (LogInstruction, FailedStep) = errorsToFailureStep(this, runState.depth, errors, Some(executionTime)) override def logOnSuccess(result: Done, runState: RunState, executionTime: Duration): LogInstruction = successLog(title, runState.depth, show, executionTime) }
Example 11
Source File: InvokeScriptTxValidator.scala From Waves with MIT License | 5 votes |
package com.wavesplatform.transaction.validation.impl import cats.data.NonEmptyList import cats.data.Validated.{Invalid, Valid} import cats.implicits._ import com.wavesplatform.lang.v1.compiler.Terms.FUNCTION_CALL import com.wavesplatform.lang.v1.{ContractLimits, FunctionHeader} import com.wavesplatform.protobuf.transaction.PBTransactions import com.wavesplatform.transaction.TxValidationError.{GenericError, NonPositiveAmount, TooBigArray} import com.wavesplatform.transaction.smart.InvokeScriptTransaction import com.wavesplatform.transaction.smart.InvokeScriptTransaction.Payment import com.wavesplatform.transaction.validation.{TxValidator, ValidatedNV, ValidatedV} import com.wavesplatform.utils._ import scala.util.Try object InvokeScriptTxValidator extends TxValidator[InvokeScriptTransaction] { override def validate(tx: InvokeScriptTransaction): ValidatedV[InvokeScriptTransaction] = { import tx._ def checkAmounts(payments: Seq[Payment]): ValidatedNV = { val invalid = payments.filter(_.amount <= 0) if (invalid.nonEmpty) Invalid(NonEmptyList.fromListUnsafe(invalid.toList).map(p => NonPositiveAmount(p.amount, p.assetId.fold("Waves")(_.toString)))) else Valid(()) } def checkLength = if (tx.isProtobufVersion) PBTransactions .toPBInvokeScriptData(tx.dAppAddressOrAlias, tx.funcCallOpt, tx.payments) .toByteArray .length <= ContractLimits.MaxInvokeScriptSizeInBytes else tx.bytes().length <= ContractLimits.MaxInvokeScriptSizeInBytes val callableNameSize = funcCallOpt match { case Some(FUNCTION_CALL(FunctionHeader.User(internalName, _), _)) => internalName.utf8Bytes.length case _ => 0 } V.seq(tx)( V.addressChainId(dAppAddressOrAlias, chainId), V.cond( funcCallOpt.isEmpty || funcCallOpt.get.args.size <= ContractLimits.MaxInvokeScriptArgs, GenericError(s"InvokeScript can't have more than ${ContractLimits.MaxInvokeScriptArgs} arguments") ), V.cond( callableNameSize <= ContractLimits.MaxDeclarationNameInBytes, GenericError(s"Callable function name size = $callableNameSize bytes must be less than ${ContractLimits.MaxDeclarationNameInBytes}") ), checkAmounts(payments), V.fee(fee), Try(checkLength) .toEither .leftMap(err => GenericError(err.getMessage)) .filterOrElse(identity, TooBigArray) .toValidatedNel .map(_ => ()) ) } }