All Downloads are FREE. Search and download functionalities are using the official Maven repository.

app.cash.quiver.extensions.Validated.kt Maven / Gradle / Ivy

@file:Suppress("TYPEALIAS_EXPANSION_DEPRECATION", "DEPRECATION")

package app.cash.quiver.extensions

import arrow.core.Either
import arrow.core.ValidatedNel
import arrow.core.flatMap
import arrow.core.getOrElse
import arrow.core.invalidNel
import arrow.core.left
import arrow.core.right
import arrow.core.validNel
import arrow.core.zip

/**
 * Turns your Validated List into an Either, but will throw an exception in the Left hand case.
 */
fun  ValidatedNel.attemptValidated(): Either =
  this.toEither()
    .mapLeft { errors -> RuntimeException(errors.toString()) }

/**
 * Given a predicate and an error generating function return either the original value in a ValidNel if the
 * predicate evaluates as true or the generated error in an InvalidNel.
 *
 * eg:
 * "hi mum".validate({it.contains("hi")},{"where's your manners?"})
 *
 */
inline fun  A.validate(predicate: (A) -> Boolean, error: (A) -> ERR): ValidatedNel =
  if (predicate(this)) this.validNel() else error(this).invalidNel()

/**
 * Given a predicate and an error generating function return either the original value in a Right if the
 * predicate evaluates as true or the error as a Left.
 *
 * eg:
 * "hi mum".validate({it.contains("hi")},{"where's your manners?"})
 *
 */
inline fun  A.validateEither(predicate: (A) -> Boolean, error: (A) -> ERR): Either =
  if (predicate(this)) this.right() else error(this).left()

/**
 * Often you have two validations that return the same thing, and you don't want necessarily
 * to pair them. takeLeft will return the value of the left side iff both validations
 * succeed.
 *
 * eg.
 *
 * Valid("hi").takeLeft(Valid("mum")) == Valid("hi")
 */
fun  ValidatedNel.takeLeft(other: ValidatedNel): ValidatedNel =
  this.zip(other) { a, _ ->
    a
  }

/**
 * Often you have two validations that return the same thing, and you don't want necessarily
 * to pair them. takeRight will return the value of the right side iff both validations
 * succeed.
 *
 * eg.
 *
 * Valid("hi").takeRight(Valid("mum")) == Valid("mum")
 */
fun  ValidatedNel.takeRight(other: ValidatedNel): ValidatedNel =
  this.zip(other) { _, b ->
    b
  }

/**
 * Given a mapping function and an error message, return either the result of the function in a
 * ValidNel if the function completes successfully, or the error message in an InvalidNel.
 */
inline fun  A.validateMap(
  f: (A) -> Either,
  error: (A, Throwable) -> ERR
): ValidatedNel =
  f(this).map { it.validNel() }.getOrElse { error(this, it).invalidNel() }

/**
 * The Validated type doesn't natively support flatMap because of the monad laws that it breaks. But this
 * is what flatMap would do if it were allowed. We've called it concatMap because the Kotlin compiler will
 * want to wire in the Monad flatMap extension instead and confusion reigns.
 *
 * eg:
 *
 * val maybeParty: ValidatedNel = ...
 *
 * val result : ValidatedNel = maybeParty.concatMap { party -> validateCashTag(party.responder.cashTag) }
 *
 * result == ValidNel("$jackjack")
 */
inline fun  ValidatedNel.concatMap(f: (A) -> ValidatedNel): ValidatedNel =
  this.withEither { either -> either.flatMap { f(it).toEither() } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy