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

Add ZValidation#toException #603

Open
wants to merge 7 commits into
base: series/1.x
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 64 additions & 1 deletion core/shared/src/main/scala/zio/prelude/ZValidation.scala
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,32 @@ sealed trait ZValidation[+W, +E, +A] { self =>
case Success(w, _) => w
}

/**
* Returns the value, if successful, or the transformed (using `f`) failure.
*/
final def getOrElse[A1 >: A](f: Failure[W, E] => A1): A1 = this match {
case Success(_, value) => value
case failure @ Failure(_, _) => f(failure)
}

/**
* Returns the value, if successful, or the transformed (using `f`) failure represented as an exception.
*/
final def getOrHandleException[A1 >: A](f: ZValidationFailureException[W, E] => A1): A1 = this match {
case Success(_, value) => value
case failure @ Failure(_, _) => f(failure.toException)
}

/**
* Returns the value, if successful, or the transformed (using `f`) failure represented as an exception with a set `cause`.
*/
final def getOrHandleExceptionWithCause[A1 >: A](
f: ZValidationFailureException[W, E] => A1
)(implicit ev: E <:< Throwable): A1 = this match {
case Success(_, value) => value
case failure @ Failure(_, _) => f(failure.toExceptionWithCause)
}

/**
* Writes an entry to the log.
*/
Expand Down Expand Up @@ -180,6 +206,24 @@ sealed trait ZValidation[+W, +E, +A] { self =>
final def toEither[E1 >: E]: Either[NonEmptyChunk[E1], A] =
fold(Left(_), Right(_))

/**
* Transforms `ZValidation` to an `Either`, where the failure case will be represented as an `Exception`.
*/
final def toEitherException: Either[ZValidationFailureException[W, E], A] = this match {
case Success(_, value) => Right(value)
case failure @ Failure(_, _) => Left(failure.toException)
}

/**
* Transforms `ZValidation` to an `Either`, where the failure case will be represented as an `Exception` with the first error as `cause`.
*/
final def toEitherExceptionWithCause(implicit
ev: E <:< Throwable
): Either[ZValidationFailureException[W, E], A] = this match {
case Success(_, value) => Right(value)
case failure @ Failure(_, _) => Left(failure.toExceptionWithCause)
}

/**
* Transforms this `ZValidation` to an `Either`, discarding the order in which the errors occurred and discarding the log.
*/
Expand Down Expand Up @@ -260,9 +304,28 @@ sealed trait ZValidation[+W, +E, +A] { self =>
object ZValidation extends LowPriorityValidationImplicits {

final case class Failure[+W, +E](log: Chunk[W], errors: NonEmptyChunk[E]) extends ZValidation[W, E, Nothing] {

/** The errors represented in a way which discards the order in which they occurred. */
lazy val errorsUnordered: NonEmptyMultiSet[E] = NonEmptyMultiSet.fromIterable(errors.head, errors.tail)

/** The description of the failure. */
lazy val message: String =
s"errors:\n ${errors.map(_.toString).mkString("\n ")}\nlog:\n ${log.map(_.toString).mkString("\n ")}"

/** The same failure, but represented as an `Exception` */
def toException: ZValidationFailureException[W, E] = ZValidationFailureException(this)

/** The same failure, but represented as an `Exception` which also has the `cause` set to the first error that occurred */
def toExceptionWithCause(implicit ev: E <:< Throwable): ZValidationFailureException[W, E] = {
val exn = toException
errors.tail.foreach(exn.addSuppressed(_))
sideeffffect marked this conversation as resolved.
Show resolved Hide resolved
val _ = exn.initCause(errors.head)
exn
}
}
final case class Success[+W, +A](log: Chunk[W], value: A) extends ZValidation[W, Nothing, A]
final case class Success[+W, +A](log: Chunk[W], value: A) extends ZValidation[W, Nothing, A]

final case class ZValidationFailureException[+W, +E](failure: Failure[W, E]) extends RuntimeException(failure.message)

/**
* The `Covariant` instance for `ZValidation`.
Expand Down