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

co.actioniq.luna.dao.DAOAction.scala Maven / Gradle / Ivy

There is a newer version: 0.0.9
Show newest version
package co.actioniq.luna.dao

import slick.jdbc.{JdbcProfile, JdbcType}

import scala.concurrent.ExecutionContext
import scala.util.{Failure, Success}

/**
  * Take the queries generated and actually perform the action.  Most functions return a nonblocking DBIOAction
  * @tparam T slick table, extends aiqtable
  * @tparam V case class to store result set rows
  * @tparam I id type (option long and uuid)
  */
trait DAOAction[T <: DAOTable.Table[V, I, P], V <: IdModel[I], I <: IdType, P <: JdbcProfile]
  extends DAOQuery[T, V, I, P] with DAOHook[V] with DAOActionValidate[V] {
  protected val profile: JdbcProfile // scalastyle:ignore
  import profile.api._ // scalastyle:ignore

  /**
    * Perform read with join
    * @param other other DAO to join to
    * @param on lambda filter function to specify "on" clause for join
    * @param extraQueryOps extra where clause
    * @tparam A type of other slick table
    * @tparam B type of other slick model
    * @tparam C type of other idtype
    * @return action of join query
    */
  protected def readJoinAction[A <: DAOTable.Table[B, C, P], B <: IdModel[C], C <: IdType]
  (
    other: DAOAction[A, B, C, P],
    on: (T, A) => Rep[Option[Boolean]],
    extraQueryOps: QueryJoin[A, B] => QueryJoin[A, B] = (query: QueryJoin[A, B]) => query
  ):
  DBIOAction[Seq[(V, B)], NoStream, Effect.Read]
  = {
    joinQuery[A, B, C](other, (mine, theirs) => on(mine, theirs), extraQueryOps).result
  }

  protected def readJoinActionTwo[A <: DAOTable.Table[B, C, P], B <: IdModel[C], C <: IdType,
  AA <: DAOTable.Table[BB, CC, P], BB <: IdModel[CC], CC <: IdType]
  (
    otherFirst: DAOAction[A, B, C, P],
    onFirst: (T, A) => Rep[Option[Boolean]],
    otherSecond: DAOAction[AA, BB, CC, P],
    onSecond: (T, A, AA) => Rep[Option[Boolean]],
    extraQueryOps: QueryJoinTwo[A, B, AA, BB] => QueryJoinTwo[A, B, AA, BB]
      = (query: QueryJoinTwo[A, B, AA, BB]) => query
  )(implicit ec: ExecutionContext):
  DBIOAction[Seq[(V, B, BB)], NoStream, Effect.Read]
  = {
    joinQueryTwo[A, B, C, AA, BB, CC](otherFirst, onFirst, otherSecond, onSecond, extraQueryOps).result
      .map { rs =>
        rs.map { row =>
          (row._1._1, row._1._2, row._2)
        }
      }
  }

  /**
    * Perform read with left join
    * @param other other DAO to join to
    * @param on lambda filter function to specify "on" clause for join
    * @param extraQueryOps extra where clause
    * @tparam A type of other slick table
    * @tparam B type of other slick model
    * @tparam C type of other idtype
    * @return action to do left join, "other" piece is option to return
    */
  protected def readLeftJoinAction[A <: DAOTable.Table[B, C, P], B <: IdModel[C], C <: IdType]
  (
    other: DAOAction[A, B, C, P],
    on: (T, A) => Rep[Option[Boolean]],
    extraQueryOps: QueryLeftJoin[A, B] => QueryLeftJoin[A, B] = (query: QueryLeftJoin[A, B]) => query
  ):
  DBIOAction[Seq[(V, Option[B])], NoStream, Effect.Read]
  = {
    leftJoinQuery[A, B, C](other, (mine, theirs) => on(mine, theirs), extraQueryOps).result
  }

  /**
    * Perform a read with child table results.  Think many to many relationships.  This actually runs a query to get
    * results from the "parent", uses that to generate a query for "children", and then merge the data together
    * @param other other DAO that is "child"
    * @param filterChildOn lambda function to filter "child" table on
    * @param merge function to merge both resultsets
    * @param extraQueryOps any extra query params for parent table
    * @param ec
    * @tparam A type of other slick table
    * @tparam B type of other slick model
    * @tparam C type of other idtype
    * @tparam Z return type, typically Seq[(A, Seq[B])]
    * @return
    */
  protected def readWithChildAction[A <: DAOTable.Table[B, C, P], B <: IdModel[C], C <: IdType, Z]
  (
    other: DAOAction[A, B, C, P],
    filterChildOn: (Seq[V], A) => Rep[Option[Boolean]],
    merge: (Seq[V], Seq[B]) => Seq[Z],
    extraQueryOps: (QueryWithFilter)=> QueryWithFilter = (query) => query
  )(implicit ec: ExecutionContext):
  DBIOAction[Seq[Z], NoStream, Effect.Read] = {
    for {
      leftRows <- readAction(extraQueryOps)
      childRows <- other.readAction(q => q.filter(row => filterChildOn(leftRows, row)))
    } yield merge(leftRows, childRows)
  }

  /**
    * Read ids only
    * @param extraQueryOps extra query params
    * @param ec
    * @return dbioaction of sequence of ids
    */
  protected def readIdsAction(
    extraQueryOps: (QueryWithFilter)=> QueryWithFilter = (query) => query
  )(implicit ec: ExecutionContext): DBIOAction[Seq[I], NoStream, Effect.Read] = {
    val query = readQuery
    idMap(extraQueryOps(query)).result
  }

  /**
    * Perform action to read object by id, throw exception if not found
    * @param id id of object
    * @param ec
    * @return dbioaction of model or failure with SlickException
    */
  protected def readByIdRequiredAction(id: I)(implicit ec: ExecutionContext):
  DBIOAction[T#TableElementType, NoStream, Effect.Read]= {
    readByIdQuery(id).result
      .map(_.headOption.getOrElse(throw new SlickException(s"Unknown $nameSingle id: $id")))
  }

  /**
    * Perform action to read object by set of ids, throw exception if any not found
 *
    * @param id set of ids
    * @param ec
    * @throws DAOException if any id is invalid
    * @return dbioaction of sequence of model or failure with SlickException
    */
  protected def readByIdRequiredAction(id: Set[I])(implicit ec: ExecutionContext):
  DBIOAction[Seq[T#TableElementType], NoStream, Effect.Read]= {
    for {
      objects <- readByIdQuery(id).result
      assert =
      if (objects.size == id.size) {
        true
      } else {
          val outputIds = objects.map(_.id).toSet
          throw new SlickException(s"Unkonwn $nameSingle id: ${id.diff(outputIds)}")
      }
    } yield objects
  }

  /**
    * Perform action to read object by id
    * @param id id of object
    * @param ec
    * @return Option of object
    */
  protected def readByIdAction(id: I)(implicit ec: ExecutionContext):
  DBIOAction[Option[T#TableElementType], NoStream, Effect.Read]= {
    readByIdQuery(id).result.map(_.headOption)
  }

  /**
    * Perform action to read objects by set of ids
    * @param id set of ids
    * @param ec
    * @return sequence of objects
    */
  protected def readByIdAction(id: Set[I])(implicit ec: ExecutionContext):
  DBIOAction[Seq[T#TableElementType], NoStream, Effect.Read]= {
    readByIdQuery(id).result
  }

  /**
    * Perform read action
    * @param extraQueryOps extra query params
    * @param ec
    * @return
    */
  protected def readAction(extraQueryOps: (QueryWithFilter)=> QueryWithFilter = (query) => query)
    (implicit ec: ExecutionContext): DBIOAction[Seq[T#TableElementType], NoStream, Effect.Read]= {
    val query = readQuery
    extraQueryOps(query).result
  }

  private def booleanToCreateValidationFunction(toValidate: Boolean)(implicit ec: ExecutionContext) = {
    if (toValidate) {
      (input: V) => validateCreate(input)
    } else {
      (input: V) => DBIO.successful(FormValidatorMessageSeq())
    }
  }


  /**
    * Perform action to create objects
    * @param inputs sequence of inputs
    * @param toValidate run validation on inputs using default validator
    * @param ec
    * @return sequence of ids or failure with exception
    */
  protected def createAction(inputs: Seq[V], toValidate: Boolean)(implicit ec: ExecutionContext):
  DBIOAction[Seq[I], NoStream, Effect.Read with Effect.Write] = {
    createAction(inputs, booleanToCreateValidationFunction(toValidate))
  }

  /**
    * Perform action to create objects
    * @param inputs sequence of inputs
    * @param validationInput run validation function
    * @param ec
    * @return sequence of ids or failure with exception
    */
  protected def createAction(
    inputs: Seq[V],
    validationInput: (V) => DBIOAction[FormValidatorMessageSeq, NoStream, Effect.Read]
  )(implicit ec: ExecutionContext):
  DBIOAction[Seq[I], NoStream, Effect.Read with Effect.Write] = {
    val actions = inputs.map(input => {
      createAction(input, validationInput)
    })
    DBIO.sequence(actions)
  }

  /**
    * Perform action to create a single object
    * @param input object to create
    * @param toValidate run validation on input using default validator
    * @param ec
    * @return ID of object inserted or failure with exception
    */
  protected def createAction(input: V, toValidate: Boolean = true)(implicit ec: ExecutionContext):
  DBIOAction[I, NoStream, Effect.Read with Effect.Write] = {
    createAction(input, booleanToCreateValidationFunction(toValidate))
  }

  /**
    * Perform action to create a single object
    * @param input object to create
    * @param validationInput run validation function
    * @param ec
    * @return ID of object inserted or failure with exception
    */
  protected def createAction(
    input: V,
    validationInput: (V) => DBIOAction[FormValidatorMessageSeq, NoStream, Effect.Read]
  )(implicit ec: ExecutionContext):
  DBIOAction[I, NoStream, Effect.Read with Effect.Write] = {
    val create = for {
      _ <- validationsToException(validationInput(input))
      insert <- createQuery(input)
    } yield insert
    create.asTry map {
      case Success(v) => {
        addCreateTransaction(v, input)
        v
      }
      case Failure(th) => th match {
        case ex: FormValidatorExceptions =>
          throw new DAOException(message = ex.errors.head.message, code = ex.errors.head.code,
            klass = Some(classOf[FormValidatorExceptions].getName))
        case ex: Throwable => throw ex
      }
    }
  }

  /**
    * For update action try to get the id from input or throw exception
    * @param input
    * @return
    */
  protected def updateGetId(input: V)(implicit ec: ExecutionContext): DBIOAction[I, NoStream, Effect.Read] = {
    DBIO.successful(input.id)
      .map(_.getOrElse(throw new Exception(s"Update $nameSingle missing ID"))
        .asInstanceOf[I]
      )
  }

  /**
    * For update action try to get the original
    * @param id id of object
    * @return Option of the original
    */
  protected def updateGetOriginal(id: I)
    (implicit ec: ExecutionContext): DBIOAction[Option[V], NoStream, Effect.Read] = {
    readAction(query => idEquals(query, id).take(1))
      .map(_.headOption)
  }

  /**
    * For update action log a transaction on success.  On failure through the correct exception
    * @param result result of the chain of actions in update action
    * @return
    */
  protected def updateHandleResult(result: DBIOAction[(I, Option[V], V), NoStream, Effect.Read with Effect.Write])
    (implicit ec: ExecutionContext): DBIOAction[I, NoStream, Effect.Read with Effect.Write] = {
    result.asTry map {
      case Success(v) => {
        addUpdateTransaction(id = v._1, input = v._3, original = v._2.head)
        v._1
      }
      case Failure(th) => th match {
        case ex: FormValidatorExceptions =>
          throw new DAOException(message = ex.errors.head.message, code = ex.errors.head.code,
            klass = Some(classOf[FormValidatorExceptions].getName))
        case ex: Throwable => throw ex
      }
    }
  }

  private def booleanToUpdateValidationFunction(toValidate: Boolean)(implicit ec: ExecutionContext) = {
    if (toValidate) {
      (newAndOriginal: NewAndOriginal[V]) => validateUpdate(newAndOriginal)
    } else {
      (newAndOriginal: NewAndOriginal[V]) => DBIO.successful(FormValidatorMessageSeq())
    }
  }

  /**
    * Perform an update action
    * @param id id of object
    * @param toValidate run validation on input using default validator
    * @param updateFunction function taking in original object returning an end result object to persist
    * @param ec
    * @return id of object or failure with exception
    */
  protected def updateActionFunctional(
    id: I,
    toValidate: Boolean,
    updateFunction: V => V
  )(implicit ec: ExecutionContext): DBIOAction[I, NoStream, Effect.Read with Effect.Write] = {
    val validationFunction = booleanToUpdateValidationFunction(toValidate)
    updateActionFunctional(id, validationFunction, updateFunction)
  }

  /**
    * Perform an update action
    * @param id id of object
    * @param validationInputOriginal run validation on input using validation function
    * @param updateFunction function taking in original object returning an end result object to persist
    * @param ec
    * @return id of object or failure with exception
    */
  protected def updateActionFunctional(
    id: I,
    validationInputOriginal: (NewAndOriginal[V]) => DBIOAction[FormValidatorMessageSeq, NoStream, Effect.Read],
    updateFunction: V => V
  )(implicit ec: ExecutionContext): DBIOAction[I, NoStream, Effect.Read with Effect.Write] = {
    for {
      // why am i go doing another get to get the original?  it should already be passed in (possibly)
      originalOpt <- updateGetOriginal(id)
      original = originalOpt match {
        case Some(originalObject) =>
          originalObject
        case _ => throw new Exception(s"Object $nameSingle not found with id $id")
      }
      result <- updateActionFunctional(original, validationInputOriginal, updateFunction)
    } yield result
  }

  /**
    * Perform an update action
    * @param original original object
    * @param toValidate run validation on input using default validator
    * @param updateFunction function taking in original object returning an end result object to persist
    * @param ec
    * @return id of object or failure with exception
    */
  protected def updateActionFunctional(
    original: V,
    toValidate: Boolean,
    updateFunction: V => V
  )(implicit ec: ExecutionContext): DBIOAction[I, NoStream, Effect.Read with Effect.Write] = {
    val validationFunction = booleanToUpdateValidationFunction(toValidate)
    updateActionFunctional(original, validationFunction, updateFunction)
  }

  /**
    * Perform an update action
    * @param original original object
    * @param validationInputOriginal run validation on input using validation function
    * @param updateFunction function taking in original object returning an end result object to persist
    * @param ec
    * @return id of object or failure with exception
    */
  protected def updateActionFunctional(
    original: V,
    validationInputOriginal: (NewAndOriginal[V]) => DBIOAction[FormValidatorMessageSeq, NoStream, Effect.Read],
    updateFunction: V => V
  )(implicit ec: ExecutionContext): DBIOAction[I, NoStream, Effect.Read with Effect.Write] = {
    val input = updateFunction(original)
    val newAndOriginal = NewAndOriginal(originalObject = original, newObject = input)
    val action = for {
      inputId <- updateGetId(input)
      validate <- validationsToException(validationInputOriginal(newAndOriginal))
      // At some point we probably don't want to update all columns (updating keys is bad)
      update <- updateQuery(inputId, input)
    } yield (update, Some(original), input)
    updateHandleResult(action)
  }

  /**
    * Perform an update action
    * @param input object to update, id will be extracted
    * @param toValidate run validation on input using default validator
    * @param ec
    * @return id of object or failure with exception
    */
  protected def updateAction(
    input: V,
    toValidate: Boolean,
    inOriginal: Option[V]
  )(implicit ec: ExecutionContext): DBIOAction[I, NoStream, Effect.Read with Effect.Write] = {
    val validationFunction = booleanToUpdateValidationFunction(toValidate)
    updateAction(input, validationFunction, inOriginal)
  }

  /**
    * Perform an update action
    * @param input object to update, id will be extracted
    * @param validationInputOriginal run validation on input using validation function
    * @param ec
    * @return id of object or failure with exception
    */
  protected def updateAction(
    input: V,
    validationInputOriginal: (NewAndOriginal[V]) => DBIOAction[FormValidatorMessageSeq, NoStream, Effect.Read],
    inOriginal: Option[V]
  )(implicit ec: ExecutionContext): DBIOAction[I, NoStream, Effect.Read with Effect.Write] = {
    for {
      inputId <- updateGetId(input)
      result <- updateActionFunctional(inputId, validationInputOriginal, (inOriginal: V) => input)
    } yield result
  }

  /**
    *
    * Perform an update action on a seq of values
    * @param inputs objects to update, id will be extracted
    * @param toValidate run validation on input
    * @param ec
    * @return id of object or failure with exceptions
    */
  protected def updateAction(
    inputs: Seq[V],
    toValidate: Boolean,
    originals: Seq[V]
  )(implicit ec: ExecutionContext): DBIOAction[Seq[I], NoStream, Effect.Read with Effect.Write] = {
    val validationFunction = booleanToUpdateValidationFunction(toValidate)
    updateAction(inputs, validationFunction, originals)
  }

  /**
    *
    * Perform an update action on a seq of values
    * @param inputs objects to update, id will be extracted
    * @param validationInputOriginal run validation on input using validation function
    * @param ec
    * @return id of object or failure with exceptions
    */
  protected def updateAction(
    inputs: Seq[V],
    validationInputOriginal: (NewAndOriginal[V]) => DBIOAction[FormValidatorMessageSeq, NoStream, Effect.Read],
    originals: Seq[V]
  )(implicit ec: ExecutionContext): DBIOAction[Seq[I], NoStream, Effect.Read with Effect.Write] = {
    val actions = inputs.map(input => {
      updateAction(input, validationInputOriginal, originals.find(_.id == input.id))
    })
    DBIO.sequence(actions)
  }

  /**
    * Update a single field without touching the rest of the row.  UpdateActionFunctional actually replaces the whole
    * row with input mixed with original
    * @param id id of the object
    * @param fieldFunction function to go from row to field
    * @param setTo value to set field to
    * @param validationFieldsOriginal function to validate new field value and original object
    * @param original original object
    * @param ec execution context
    * @param aType evidence of field type
    * @tparam A field type
    * @return id
    */
  protected def updateFieldAction[A](
    id: I,
    fieldFunction:  (T => Rep[A]),
    setTo: A,
    validationFieldsOriginal: (A, V) => DBIOAction[FormValidatorMessageSeq, NoStream, Effect.Read],
    original: Option[V]
  )(implicit ec: ExecutionContext, aType: JdbcType[A]): DBIOAction[I, NoStream, Effect.Read with Effect.Write] = {
    for {
      originalObject <- original match {
        case None => readByIdRequiredAction(id)
        case Some(row) => DBIO.successful(row)
      }
      _ <- validationsToException(
        validationFieldsOriginal(setTo, originalObject)
      )
      _ <- updateFieldQuery(id, fieldFunction, setTo)
    } yield id
  }

  /**
    * Update TWO fields without touching the rest of the row.  UpdateActionFunctional actually replaces the whole
    * row with input mixed with original
    * @param id id of the object
    * @param fieldFunction function to go from row to fields
    * @param setTo tuple of values to set fields to
    * @param validationFieldsOriginal function to validate new field values and original object
    * @param original original object
    * @param ec execution context
    * @param a1Type evidence of field 1 type
    * @param a2Type evidence of field 2 type
    * @tparam A1 field 1 type
    * @tparam A2 field 2 type
    * @return
    */
  protected def updateFieldAction[A1, A2](
    id: I,
    fieldFunction:  (T => (Rep[A1], Rep[A2])),
    setTo: (A1, A2),
    validationFieldsOriginal: ((A1, A2), V) => DBIOAction[FormValidatorMessageSeq, NoStream, Effect.Read],
    original: Option[V]
  )(
    implicit ec: ExecutionContext,
    a1Type: JdbcType[A1],
    a2Type: JdbcType[A2]
  ): DBIOAction[I, NoStream, Effect.Read with Effect.Write] = {
    for {
      originalObject <- original match {
        case None => readByIdRequiredAction(id)
        case Some(row) => DBIO.successful(row)
      }
      _ <- validationsToException(
        validationFieldsOriginal(setTo, originalObject)
      )
      _ <- updateFieldQuery(id, fieldFunction, setTo)
    } yield id
  }

  /**
    * Update THREE fields without touching the rest of the row.  UpdateActionFunctional actually replaces the whole
    * row with input mixed with original
    * @param id id of the object
    * @param fieldFunction function to go from row to fields
    * @param setTo tuple of values to set fields to
    * @param validationFieldsOriginal function to validate new field values and original object
    * @param original original object
    * @param ec execution context
    * @param a1Type evidence of field 1 type
    * @param a2Type evidence of field 2 type
    * @param a3Type evidence of field 3 type
    * @tparam A1 field 1 type
    * @tparam A2 field 2 type
    * @tparam A3 field 3 type
    * @return
    */
  protected def updateFieldAction[A1, A2, A3](
    id: I,
    fieldFunction:  (T => (Rep[A1], Rep[A2], Rep[A3])),
    setTo: (A1, A2, A3),
    validationFieldsOriginal: ((A1, A2, A3), V) => DBIOAction[FormValidatorMessageSeq, NoStream, Effect.Read],
    original: Option[V]
  )(
    implicit ec: ExecutionContext,
    a1Type: JdbcType[A1],
    a2Type: JdbcType[A2],
    a3Type: JdbcType[A3]
  ): DBIOAction[I, NoStream, Effect.Read with Effect.Write] = {
    for {
      originalObject <- original match {
        case None => readByIdRequiredAction(id)
        case Some(row) => DBIO.successful(row)
      }
      _ <- validationsToException(
        validationFieldsOriginal(setTo, originalObject)
      )
      _ <- updateFieldQuery(id, fieldFunction, setTo)
    } yield id
  }

  /**
    * Perform a delete action
    * @param inputId id of object to delete
    * @param ec
    * @return number of rows deleted or failure with exception
    */
  protected def deleteAction(inputId: I)(implicit ec: ExecutionContext):
  DBIOAction[Int, NoStream, Effect.Read with Effect.Write] = {
    for {
      original <- readAction(query => idEquals(query, inputId).take(1))
      validate = original match {
        case Nil => throw new Exception(s"Object $nameSingle not found with id $inputId")
        case _ => true
      }
      delete <- deleteQuery(inputId).map(result => {
        addDeleteTransaction(inputId, original.head)
        result
      })
    } yield delete
  }

  /**
    *  Perform a delete action on a seq of values
    *  @param inputIds ids of objects to delete
    *  @param ec
    *  @return number of rows deleted for each input
    */
  protected def deleteAction(inputIds: Seq[I])(implicit ec: ExecutionContext):
  DBIOAction[Seq[Int], NoStream, Effect.Read with Effect.Write] = {
    val actions = inputIds.map(inputId => {
      deleteAction(inputId)
    })
    DBIO.sequence(actions)
  }


  /**
    * Add to transaction log a create operation
    * @param id id of object
    * @param input input
    */
  protected def addCreateTransaction(id: I, input: V): Unit

  /**
    * Add to transaction log an update operation
    * @param id id of object
    * @param input new object
    * @param original original object
    */
  protected def addUpdateTransaction(id: I, input: V, original: V): Unit

  /**
    * Add to transaction log a delete operation
    * @param id id of object
    * @param original original object
    */
  protected def addDeleteTransaction(id: I, original: V): Unit
}

/**
  * Trait with functions to implement to perform validations.  Functions need to return DBIOActions so that they can
  * be included in transactions.  You would probably do DBIO.successful(....)
  * @tparam V model / slick case class
  */
trait DAOActionValidate[V] {
  protected val profile: JdbcProfile
  import profile.api._ // scalastyle:ignore
  /**
    * Validate create
    * @param input input to validate
    * @param ec
    * @return DBIOAction of FormValidatorMessageSeq
    */
  def validateCreate(input: V)(implicit ec: ExecutionContext):
  DBIOAction[FormValidatorMessageSeq, NoStream, Effect.Read]

  /**
    * Validate an update
    * @param input input to validate
    * @param original original object
    * @param ec
    * @return DBIOAction of FormValidatorMessageSeq
    */
  def validateUpdate(input: V, original: V)(implicit ec: ExecutionContext):
  DBIOAction[FormValidatorMessageSeq, NoStream, Effect.Read]

  /**
    * Validate an input using NewAndOriginal wrapper
    * @param newAndOriginal wrapper around new and original value
    * @param ec
    * @return DBIOAction of FormValidatorMessageSeq
    */
  def validateUpdate(newAndOriginal: NewAndOriginal[V])(implicit ec: ExecutionContext):
  DBIOAction[FormValidatorMessageSeq, NoStream, Effect.Read] = {
    validateUpdate(newAndOriginal.newObject, newAndOriginal.originalObject)
  }

  /**
    * Throw exception if validations fails
    * @param results DBIOAction of FormValidatorSeq from validation function
    * @param ec execution context
    * @return nothing or failure with FormValidatorExceptions
    */
  def validationsToException(
    results: DBIOAction[FormValidatorMessageSeq, NoStream, Effect.Read]
  ) (implicit ec: ExecutionContext): DBIOAction[Unit, NoStream, Effect.Read] = {
    results map {
      case FormValidatorMessageSeq(Seq()) => Unit
      case items: FormValidatorMessageSeq => throw new FormValidatorExceptions(items)
    }
  }
}

/**
  * Simple wrapper to pass new and original objects.  Using a case class makes it more explicit so you know which is
  * new and which is original
  * @param newObject
  * @param originalObject
  * @tparam V
  */
case class NewAndOriginal[V](newObject: V, originalObject: V)




© 2015 - 2024 Weber Informatics LLC | Privacy Policy