app/models/ValidationJobDAO.scala (66 lines of code) (raw):

package models import play.api.db.slick.DatabaseConfigProvider import slick.jdbc.PostgresProfile.api._ import slick.jdbc.PostgresProfile import slick.lifted.TableQuery import java.sql.Timestamp import java.time.Instant import java.util.UUID import javax.inject.{Inject, Singleton} import scala.concurrent.Future import scala.concurrent.ExecutionContext.Implicits.global @Singleton class ValidationJobDAO @Inject() (dbConfigProvider:DatabaseConfigProvider) { import ValidationJobMappers._ private val db = dbConfigProvider.get[PostgresProfile].db /** * writes the given ValidationJob record to the database. If the `id` field is set then the existing record is updated, * if it is not then a new record is inserted. * * Returns the ValidationJob that was input, with the `id` field set if it was not set before * @param job ValidationJob to write to the database * @return a Future with the ValidationJob returned, the returned value will always have the `id` field set correctly */ def writeJob(job:ValidationJob) = { job.id match { case None=> db.run( (TableQuery[ValidationJobRow] returning TableQuery[ValidationJobRow].map(_.id)) += job) .map(newId=>job.copy(id=Some(newId))) case Some(existingId)=> db.run(TableQuery[ValidationJobRow].filter(_.id===existingId).update(job)) .flatMap(rows=>{ if(rows==0) { Future.failed(new RuntimeException("No rows were updated")) } else { Future(job) } }) } } /** * update just the job status field, and optionally the completion timestamp * @param jobId job ID to update * @param newStatus the new status value * @param completionTimestamp optionally, a value to set for `completionTimestamp` * @return a Future with the updated row count for each query */ def updateJobStatus(jobId:UUID, newStatus:ValidationJobStatus.Value, completionTimestamp:Option[Timestamp]=None) = { val queries = Seq( Some(TableQuery[ValidationJobRow].filter(_.uuid===jobId).map(_.status).update(newStatus)), completionTimestamp.map(ts=> TableQuery[ValidationJobRow].filter(_.uuid===jobId).map(_.completedAt).update(Some(ts)) ) ) db.run( DBIO.sequence(queries.collect({case Some(q)=>q})) ) } def setJobCompleted(job:ValidationJob) = { updateJobStatus(job.uuid, ValidationJobStatus.Success, Some(Timestamp.from(Instant.now()))) } /** * retrieves the ValidationJob with the given UUID. If no such job exists returns None * @param uuid uuid to look up * @return */ def jobForUUID(uuid:UUID) = { db.run( TableQuery[ValidationJobRow].filter(_.uuid===uuid).result ).map(_.headOption) } /** * search for jobs with the given parameters. If no search parameters are given then will return everything. * @param userName username to search for, or None to ignore username * @param status status to search for, or None to ignore status * @param limit maximum number of results to return. Defaults to 100. * @return a list of the matching validation rows, or an empty sequence if nothing matches */ def queryJobs(userName:Option[String]=None, status:Option[ValidationJobStatus.Value]=None, limit:Int=100) = { val baseQuery = TableQuery[ValidationJobRow] val userQuery = userName match { case None=>baseQuery case Some(user)=>baseQuery.filter(_.userName===user) } val statusQuery = status match { case None=>userQuery case Some(statusValue)=>userQuery.filter(_.status===statusValue) } for { hitCount <- db.run(statusQuery.length.result) results <- db.run(statusQuery.sortBy(_.startedAt.desc).take(limit).result) } yield (hitCount, results) } }