diff options
author | vlad <vlad@driver.xyz> | 2017-06-30 12:29:54 -0700 |
---|---|---|
committer | vlad <vlad@driver.xyz> | 2017-06-30 12:29:54 -0700 |
commit | a997aa6539d1f0af4ab4fc395ff2033335da312a (patch) | |
tree | 4f24529cd0beed94368caafdc0bdbb5677184851 | |
parent | 5832f63b84d7388441d1200f2442dc1e9de0225c (diff) | |
download | rest-query-a997aa6539d1f0af4ab4fc395ff2033335da312a.tar.gz rest-query-a997aa6539d1f0af4ab4fc395ff2033335da312a.tar.bz2 rest-query-a997aa6539d1f0af4ab4fc395ff2033335da312a.zip |
Latest PDS UI utils
100 files changed, 1159 insertions, 942 deletions
@@ -7,7 +7,7 @@ lazy val core = (project in file(".")) .settings(libraryDependencies ++= Seq( "ch.qos.logback" % "logback-classic" % "1.1.7", "org.slf4j" % "slf4j-api" % "1.7.21", - "com.typesafe.scala-logging" %% "scala-logging" % "3.4.0", + "com.typesafe.scala-logging" %% "scala-logging" % "3.5.0", "com.typesafe" % "config" % "1.3.0", "com.fasterxml.jackson.module" %% "jackson-module-scala" % "2.8.3", "com.fasterxml.jackson.datatype" % "jackson-datatype-jsr310" % "2.8.4", diff --git a/src/main/scala/xyz/driver/pdsuicommon/acl/ACL.scala b/src/main/scala/xyz/driver/pdsuicommon/acl/ACL.scala index 394e49f..1bb5bcd 100644 --- a/src/main/scala/xyz/driver/pdsuicommon/acl/ACL.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/acl/ACL.scala @@ -31,7 +31,21 @@ object ACL extends PhiLogging { object Label extends BaseACL( label = "label", - read = RepRoles ++ TcRoles ++ TreatmentMatchingRoles + read = RepRoles ++ TcRoles ++ TreatmentMatchingRoles + ResearchOncologist + ) + + object UserHistory + extends BaseACL( + label = "user history", + read = Set(RecordAdmin, TrialAdmin, TreatmentMatchingAdmin) + ) + + object Queue + extends BaseACL( + label = "queue", + create = Set(SystemUser), + read = Set(SystemUser), + update = Set(SystemUser) ) // REP @@ -39,7 +53,7 @@ object ACL extends PhiLogging { object MedicalRecord extends BaseACL( label = "medical record", - read = RepRoles + RoutesCurator + TreatmentMatchingAdmin, + read = RepRoles + RoutesCurator + TreatmentMatchingAdmin + ResearchOncologist, update = RepRoles - DocumentExtractor ) @@ -47,7 +61,7 @@ object ACL extends PhiLogging { extends BaseACL( label = "document", create = Set(RecordOrganizer, RecordAdmin), - read = RepRoles - RecordCleaner + RoutesCurator + TreatmentMatchingAdmin, + read = RepRoles - RecordCleaner + RoutesCurator + TreatmentMatchingAdmin + ResearchOncologist, update = RepRoles - RecordCleaner, delete = Set(RecordOrganizer, RecordAdmin) ) @@ -56,7 +70,7 @@ object ACL extends PhiLogging { extends BaseACL( label = "extracted data", create = Set(DocumentExtractor, RecordAdmin), - read = Set(DocumentExtractor, RecordAdmin, RoutesCurator, TreatmentMatchingAdmin), + read = Set(DocumentExtractor, RecordAdmin, RoutesCurator, TreatmentMatchingAdmin, ResearchOncologist), update = Set(DocumentExtractor, RecordAdmin), delete = Set(DocumentExtractor, RecordAdmin) ) @@ -70,13 +84,13 @@ object ACL extends PhiLogging { object ProviderType extends BaseACL( label = "provider type", - read = RepRoles + RoutesCurator + TreatmentMatchingAdmin + read = RepRoles + RoutesCurator + TreatmentMatchingAdmin + ResearchOncologist ) object DocumentType extends BaseACL( label = "document type", - read = RepRoles + RoutesCurator + TreatmentMatchingAdmin + read = RepRoles + RoutesCurator + TreatmentMatchingAdmin + ResearchOncologist ) object Message @@ -93,7 +107,7 @@ object ACL extends PhiLogging { object Trial extends BaseACL( label = "trial", - read = TcRoles + RoutesCurator + TreatmentMatchingAdmin, + read = TcRoles + RoutesCurator + TreatmentMatchingAdmin + ResearchOncologist, update = TcRoles ) @@ -113,7 +127,7 @@ object ACL extends PhiLogging { extends BaseACL( label = "criterion", create = Set(CriteriaCurator, TrialAdmin), - read = Set(CriteriaCurator, TrialAdmin, RoutesCurator, TreatmentMatchingAdmin), + read = Set(CriteriaCurator, TrialAdmin, RoutesCurator, TreatmentMatchingAdmin, ResearchOncologist), update = Set(CriteriaCurator, TrialAdmin), delete = Set(CriteriaCurator, TrialAdmin) ) @@ -151,34 +165,34 @@ object ACL extends PhiLogging { object Patient extends BaseACL( label = "patient", - read = TreatmentMatchingRoles, + read = TreatmentMatchingRoles + ResearchOncologist, update = TreatmentMatchingRoles ) object PatientLabel extends BaseACL( label = "patient label", - read = TreatmentMatchingRoles, + read = TreatmentMatchingRoles + ResearchOncologist, update = TreatmentMatchingRoles ) object PatientCriterion extends BaseACL( label = "patient criterion", - read = TreatmentMatchingRoles, + read = TreatmentMatchingRoles + ResearchOncologist, update = TreatmentMatchingRoles ) object PatientLabelEvidence extends BaseACL( label = "patient label evidence", - read = TreatmentMatchingRoles + read = TreatmentMatchingRoles + ResearchOncologist ) object EligibleTrial extends BaseACL( label = "eligible trial", - read = Set(RoutesCurator, TreatmentMatchingAdmin), + read = Set(RoutesCurator, TreatmentMatchingAdmin, ResearchOncologist), update = Set(RoutesCurator, TreatmentMatchingAdmin) ) diff --git a/src/main/scala/xyz/driver/pdsuicommon/computation/Computation.scala b/src/main/scala/xyz/driver/pdsuicommon/computation/Computation.scala index ad458de..159c144 100644 --- a/src/main/scala/xyz/driver/pdsuicommon/computation/Computation.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/computation/Computation.scala @@ -16,7 +16,7 @@ import scala.concurrent.{ExecutionContext, Future} * {{{ * import scala.concurrent.ExecutionContext.Implicits.global * import scala.concurrent.{ExecutionContext, Future} - * import com.drivergrp.server.com.drivergrp.server.common.utils.Computation + * import xyz.driver.pdsuicommon.computation.Computation * * def successful = for { * x <- Computation.continue(1) @@ -65,6 +65,13 @@ final case class Computation[+R, +T](future: Future[Either[R, T]]) { Computation.continue(f(a)) } + def mapLeft[R2](f: R => R2)(implicit ec: ExecutionContext): Computation[R2, T] = { + Computation(future.map { + case Left(x) => Left(f(x)) + case Right(x) => Right(x) + }) + } + def andThen(f: T => Any)(implicit ec: ExecutionContext): Computation[R, T] = map { a => f(a) a diff --git a/src/main/scala/xyz/driver/pdsuicommon/computation/FutureToComputationOps.scala b/src/main/scala/xyz/driver/pdsuicommon/computation/FutureToComputationOps.scala index c5800dc..6951e79 100644 --- a/src/main/scala/xyz/driver/pdsuicommon/computation/FutureToComputationOps.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/computation/FutureToComputationOps.scala @@ -6,19 +6,17 @@ import scala.concurrent.{ExecutionContext, Future} final class FutureToComputationOps[T](val self: Future[T]) extends AnyVal { - def handleDomainError[U, ER](f: PartialFunction[T, U]) - (implicit unsuitableToErrorsResponse: DomainError => ER, - ec: ExecutionContext): Future[Either[ER, U]] = { + def handleDomainError[U, ER](f: PartialFunction[T, U])(implicit unsuitableToErrorsResponse: DomainError => ER, + ec: ExecutionContext): Future[Either[ER, U]] = { self.map { case x if f.isDefinedAt(x) => Right(f(x)) - case x: DomainError => Left(unsuitableToErrorsResponse(x)) - case x => throw new RuntimeException(s"Can not process $x") + case x: DomainError => Left(unsuitableToErrorsResponse(x)) + case x => throw new RuntimeException(s"Can not process $x") } } - def toComputation[U, ER](f: PartialFunction[T, U]) - (implicit unsuitableToErrorsResponse: DomainError => ER, - ec: ExecutionContext): Computation[ER, U] = { + def toComputation[U, ER](f: PartialFunction[T, U])(implicit unsuitableToErrorsResponse: DomainError => ER, + ec: ExecutionContext): Computation[ER, U] = { Computation(handleDomainError(f)) } } diff --git a/src/main/scala/xyz/driver/pdsuicommon/computation/TryToComputationOps.scala b/src/main/scala/xyz/driver/pdsuicommon/computation/TryToComputationOps.scala index 8282bc6..45f6d41 100644 --- a/src/main/scala/xyz/driver/pdsuicommon/computation/TryToComputationOps.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/computation/TryToComputationOps.scala @@ -6,10 +6,10 @@ import scala.util.{Failure, Success, Try} final class TryToComputationOps[T](val self: Try[T]) extends AnyVal { - def toComputation[ER](implicit exceptionToErrorResponse: Throwable => ER, - ec: ExecutionContext): Computation[ER, T] = self match { - case Success(x) => Computation.continue(x) - case Failure(NonFatal(e)) => Computation.abort(exceptionToErrorResponse(e)) - case Failure(e) => Computation.fail(e) - } + def toComputation[ER](implicit exceptionToErrorResponse: Throwable => ER, ec: ExecutionContext): Computation[ER, T] = + self match { + case Success(x) => Computation.continue(x) + case Failure(NonFatal(e)) => Computation.abort(exceptionToErrorResponse(e)) + case Failure(e) => Computation.fail(e) + } } diff --git a/src/main/scala/xyz/driver/pdsuicommon/concurrent/BridgeUploadQueue.scala b/src/main/scala/xyz/driver/pdsuicommon/concurrent/BridgeUploadQueue.scala index feb3774..8213262 100644 --- a/src/main/scala/xyz/driver/pdsuicommon/concurrent/BridgeUploadQueue.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/concurrent/BridgeUploadQueue.scala @@ -3,7 +3,6 @@ package xyz.driver.pdsuicommon.concurrent import java.time.LocalDateTime import xyz.driver.pdsuicommon.concurrent.BridgeUploadQueue.Item -import xyz.driver.pdsuicommon.domain.LongId import xyz.driver.pdsuicommon.logging._ import scala.concurrent.Future @@ -17,8 +16,7 @@ object BridgeUploadQueue { * @param created When the task was created * @param nextAttempt Time of the next attempt */ - final case class Item(id: LongId[Item], - kind: String, + final case class Item(kind: String, tag: String, created: LocalDateTime, attempts: Int, @@ -40,7 +38,7 @@ object BridgeUploadQueue { implicit def toPhiString(x: Item): PhiString = { import x._ - phi"BridgeUploadQueue.Item(id=$id, kind=${Unsafe(kind)}, tag=${Unsafe(tag)}, " + + phi"BridgeUploadQueue.Item(kind=${Unsafe(kind)}, tag=${Unsafe(tag)}, " + phi"attempts=${Unsafe(attempts)}, start=$created, nextAttempt=$nextAttempt, completed=$completed, " + phi"dependency=$dependency)" } @@ -49,7 +47,6 @@ object BridgeUploadQueue { val now = LocalDateTime.now() Item( - id = LongId(0), kind = kind, tag = tag, created = now, @@ -76,11 +73,11 @@ object BridgeUploadQueue { trait BridgeUploadQueue { - def add(item: Item): Future[Unit] + def add(item: Item): Future[Item] def get(kind: String): Future[Option[Item]] - def remove(item: LongId[Item]): Future[Unit] + def complete(kind: String, tag: String): Future[Unit] def tryRetry(item: Item): Future[Option[Item]] diff --git a/src/main/scala/xyz/driver/pdsuicommon/concurrent/BridgeUploadQueueRepositoryAdapter.scala b/src/main/scala/xyz/driver/pdsuicommon/concurrent/BridgeUploadQueueRepositoryAdapter.scala index 528be59..48c81c2 100644 --- a/src/main/scala/xyz/driver/pdsuicommon/concurrent/BridgeUploadQueueRepositoryAdapter.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/concurrent/BridgeUploadQueueRepositoryAdapter.scala @@ -5,9 +5,8 @@ import java.time.temporal.ChronoUnit import xyz.driver.pdsuicommon.concurrent.BridgeUploadQueue.Item import xyz.driver.pdsuicommon.concurrent.BridgeUploadQueueRepositoryAdapter.Strategy -import xyz.driver.pdsuicommon.db.Transactions +import xyz.driver.pdsuicommon.db._ import xyz.driver.pdsuicommon.db.repositories.BridgeUploadQueueRepository -import xyz.driver.pdsuicommon.domain.LongId import xyz.driver.pdsuicommon.logging._ import scala.concurrent.duration.{Duration, FiniteDuration} @@ -16,6 +15,9 @@ import scala.util.Try object BridgeUploadQueueRepositoryAdapter { + /** + * Defines how we work with queue, when an user attempts to remove/tryRetry an item. + */ sealed trait Strategy { def onComplete: Strategy.OnComplete @@ -48,9 +50,7 @@ object BridgeUploadQueueRepositoryAdapter { /** * Used only in tests. */ - case object Ignore extends Strategy { - - override val onComplete = OnComplete.Delete + final case class Stop(onComplete: OnComplete = OnComplete.Delete) extends Strategy { override def on(attempt: Int) = OnAttempt.Complete @@ -85,33 +85,33 @@ object BridgeUploadQueueRepositoryAdapter { } } -class BridgeUploadQueueRepositoryAdapter(strategy: Strategy, - repository: BridgeUploadQueueRepository, - transactions: Transactions)(implicit executionContext: ExecutionContext) +class BridgeUploadQueueRepositoryAdapter(strategy: Strategy, repository: BridgeUploadQueueRepository, dbIo: DbIo)( + implicit executionContext: ExecutionContext) extends BridgeUploadQueue with PhiLogging { - override def add(item: Item): Future[Unit] = transactions.run { _ => - repository.add(item) - } + override def add(item: Item): Future[Item] = dbIo.runAsync(repository.add(item)) - override def get(kind: String): Future[Option[Item]] = { - repository.getOne(kind) - } + override def get(kind: String): Future[Option[Item]] = dbIo.runAsync(repository.getOne(kind)) - override def remove(item: LongId[Item]): Future[Unit] = transactions.run { _ => + override def complete(kind: String, tag: String): Future[Unit] = { import Strategy.OnComplete._ strategy.onComplete match { - case Delete => repository.delete(item) + case Delete => dbIo.runAsync(repository.delete(kind, tag)) case Mark => - repository.getById(item) match { - case Some(x) => repository.update(x.copy(completed = true)) - case None => throw new RuntimeException(s"Can not find the $item task") + dbIo.runAsyncTx { + repository.getById(kind, tag) match { + case Some(x) => repository.update(x.copy(completed = true)) + case None => throw new RuntimeException(s"Can not find the task: kind=$kind, tag=$tag") + } } } } - override def tryRetry(item: Item): Future[Option[Item]] = transactions.run { _ => + /** + * Tries to continue the task or complete it + */ + override def tryRetry(item: Item): Future[Option[Item]] = { import Strategy.OnAttempt._ logger.trace(phi"tryRetry($item)") @@ -128,11 +128,13 @@ class BridgeUploadQueueRepositoryAdapter(strategy: Strategy, ) logger.debug(draftItem) - Some(repository.update(draftItem)) + dbIo.runAsync { + Some(repository.update(draftItem)) + } case Complete => - repository.delete(item.id) - None + logger.warn(phi"All attempts are out for $item, complete the task") + complete(item.kind, item.tag).map(_ => None) } } } diff --git a/src/main/scala/xyz/driver/pdsuicommon/concurrent/InMemoryBridgeUploadQueue.scala b/src/main/scala/xyz/driver/pdsuicommon/concurrent/InMemoryBridgeUploadQueue.scala index bff566b..658b5b1 100644 --- a/src/main/scala/xyz/driver/pdsuicommon/concurrent/InMemoryBridgeUploadQueue.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/concurrent/InMemoryBridgeUploadQueue.scala @@ -1,9 +1,9 @@ package xyz.driver.pdsuicommon.concurrent import java.util.concurrent.LinkedBlockingQueue +import java.util.function.Predicate import xyz.driver.pdsuicommon.concurrent.BridgeUploadQueue.Item -import xyz.driver.pdsuicommon.domain.LongId import xyz.driver.pdsuicommon.logging.PhiLogging import scala.collection.JavaConverters._ @@ -16,9 +16,9 @@ class InMemoryBridgeUploadQueue extends BridgeUploadQueue with PhiLogging { private val queue = new LinkedBlockingQueue[Item]() - override def add(item: Item): Future[Unit] = { + override def add(item: Item): Future[Item] = { queue.add(item) - done + Future.successful(item) } override def tryRetry(item: Item): Future[Option[Item]] = Future.successful(Some(item)) @@ -28,11 +28,10 @@ class InMemoryBridgeUploadQueue extends BridgeUploadQueue with PhiLogging { Future.successful(r) } - override def remove(item: LongId[Item]): Future[Unit] = { - queue.remove(item) - done + override def complete(kind: String, tag: String): Future[Unit] = { + queue.removeIf(new Predicate[Item] { + override def test(t: Item): Boolean = t.kind == kind && t.tag == tag + }) + Future.successful(()) } - - private val done = Future.successful(()) - } diff --git a/src/main/scala/xyz/driver/pdsuicommon/concurrent/SafeBridgeUploadQueue.scala b/src/main/scala/xyz/driver/pdsuicommon/concurrent/SafeBridgeUploadQueue.scala new file mode 100644 index 0000000..bab29d5 --- /dev/null +++ b/src/main/scala/xyz/driver/pdsuicommon/concurrent/SafeBridgeUploadQueue.scala @@ -0,0 +1,61 @@ +package xyz.driver.pdsuicommon.concurrent + +import xyz.driver.pdsuicommon.concurrent.BridgeUploadQueue.Dependency +import xyz.driver.pdsuicommon.concurrent.SafeBridgeUploadQueue.{DependencyResolver, SafeTask, Tag} +import xyz.driver.pdsuicommon.logging._ +import xyz.driver.pdsuicommon.serialization.Marshaller + +import scala.concurrent.{ExecutionContext, Future} + +object SafeBridgeUploadQueue { + + trait Tag extends Product with Serializable + + case class SafeTask[T <: Tag](tag: T, + private[SafeBridgeUploadQueue] val queueItem: BridgeUploadQueue.Item) + + object SafeTask { + implicit def toPhiString[T <: Tag](x: SafeTask[T]): PhiString = { + import x._ + phi"SafeTask(tag=${Unsafe(tag)}, $queueItem)" + } + } + + trait DependencyResolver[T <: Tag] { + def getDependency(tag: T): Option[Dependency] + } + +} + +class SafeBridgeUploadQueue[T <: Tag](kind: String, + origQueue: BridgeUploadQueue) + (implicit + tagMarshaller: Marshaller[T, String], + dependencyResolver: DependencyResolver[T], + executionContext: ExecutionContext) { + + type Task = SafeTask[T] + + def add(tag: T): Future[BridgeUploadQueue.Item] = origQueue.add(BridgeUploadQueue.Item( + kind = kind, + tag = tagMarshaller.write(tag), + dependency = dependencyResolver.getDependency(tag) + )) + + def tryRetry(task: Task): Future[Option[Task]] = wrap(origQueue.tryRetry(task.queueItem)) + + def get: Future[Option[Task]] = wrap(origQueue.get(kind)) + + def complete(tag: T): Future[Unit] = origQueue.complete(kind, tagMarshaller.write(tag)) + + private def wrap(x: Future[Option[BridgeUploadQueue.Item]]): Future[Option[Task]] = x.map(_.map(cover)) + + private def cover(rawTask: BridgeUploadQueue.Item): Task = { + val tag = tagMarshaller + .read(rawTask.tag) + .getOrElse(throw new IllegalArgumentException(s"Can not parse tag '${rawTask.tag}'")) + + SafeTask(tag, rawTask) + } + +} diff --git a/src/main/scala/xyz/driver/pdsuicommon/db/DbCommand.scala b/src/main/scala/xyz/driver/pdsuicommon/db/DbCommand.scala index 5dafc00..0af104e 100644 --- a/src/main/scala/xyz/driver/pdsuicommon/db/DbCommand.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/db/DbCommand.scala @@ -4,12 +4,12 @@ import scala.concurrent.Future trait DbCommand { def runSync(): Unit - def runAsync(transactions: Transactions): Future[Unit] + def runAsync(transactions: DbIo): Future[Unit] } object DbCommand { val Empty: DbCommand = new DbCommand { - override def runSync(): Unit = {} - override def runAsync(transactions: Transactions): Future[Unit] = Future.successful(()) + override def runSync(): Unit = {} + override def runAsync(transactions: DbIo): Future[Unit] = Future.successful(()) } } diff --git a/src/main/scala/xyz/driver/pdsuicommon/db/DbIo.scala b/src/main/scala/xyz/driver/pdsuicommon/db/DbIo.scala new file mode 100644 index 0000000..7c290d1 --- /dev/null +++ b/src/main/scala/xyz/driver/pdsuicommon/db/DbIo.scala @@ -0,0 +1,13 @@ +package xyz.driver.pdsuicommon.db + +import scala.concurrent.Future + +/** + * Where queries should run + */ +trait DbIo { + def runAsync[T](f: => T): Future[T] + def runSync[T](f: => T): T = f + def runAsyncTx[T](f: => T): Future[T] + def runSyncTx[T](f: => T): Unit +} diff --git a/src/main/scala/xyz/driver/pdsuicommon/db/EntityNotFoundException.scala b/src/main/scala/xyz/driver/pdsuicommon/db/EntityNotFoundException.scala index d779e10..d765833 100644 --- a/src/main/scala/xyz/driver/pdsuicommon/db/EntityNotFoundException.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/db/EntityNotFoundException.scala @@ -2,7 +2,7 @@ package xyz.driver.pdsuicommon.db import xyz.driver.pdsuicommon.domain.Id -class EntityNotFoundException private (id: String, tableName: String) +class EntityNotFoundException(id: String, tableName: String) extends RuntimeException(s"Entity with id $id is not found in $tableName table") { def this(id: Id[_], tableName: String) = this(id.toString, tableName) diff --git a/src/main/scala/xyz/driver/pdsuicommon/db/FakeDbIo.scala b/src/main/scala/xyz/driver/pdsuicommon/db/FakeDbIo.scala new file mode 100644 index 0000000..e5a628c --- /dev/null +++ b/src/main/scala/xyz/driver/pdsuicommon/db/FakeDbIo.scala @@ -0,0 +1,9 @@ +package xyz.driver.pdsuicommon.db + +import scala.concurrent.Future + +object FakeDbIo extends DbIo { + override def runAsync[T](f: => T): Future[T] = Future.successful(f) + override def runAsyncTx[T](f: => T): Future[T] = Future.successful(f) + override def runSyncTx[T](f: => T): Unit = f +} diff --git a/src/main/scala/xyz/driver/pdsuicommon/db/JdbcDbIo.scala b/src/main/scala/xyz/driver/pdsuicommon/db/JdbcDbIo.scala new file mode 100644 index 0000000..44f177c --- /dev/null +++ b/src/main/scala/xyz/driver/pdsuicommon/db/JdbcDbIo.scala @@ -0,0 +1,28 @@ +package xyz.driver.pdsuicommon.db + +import xyz.driver.pdsuicommon.logging._ + +import scala.concurrent.Future +import scala.util.{Failure, Success, Try} + +class JdbcDbIo(sqlContext: TransactionalContext) extends DbIo with PhiLogging { + + override def runAsync[T](f: => T): Future[T] = { + Future(f)(sqlContext.executionContext) + } + + override def runAsyncTx[T](f: => T): Future[T] = { + import sqlContext.executionContext + + Future(sqlContext.transaction(f)).andThen { + case Failure(e) => logger.error(phi"Can't run a transaction: $e") + } + } + + override def runSyncTx[T](f: => T): Unit = { + Try(sqlContext.transaction(f)) match { + case Success(_) => + case Failure(e) => logger.error(phi"Can't run a transaction: $e") + } + } +} diff --git a/src/main/scala/xyz/driver/pdsuicommon/db/SqlContext.scala b/src/main/scala/xyz/driver/pdsuicommon/db/MySqlContext.scala index c929eae..768d1e3 100644 --- a/src/main/scala/xyz/driver/pdsuicommon/db/SqlContext.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/db/MySqlContext.scala @@ -8,15 +8,15 @@ import javax.sql.DataSource import com.typesafe.config.Config import io.getquill._ import xyz.driver.pdsuicommon.concurrent.MdcExecutionContext -import xyz.driver.pdsuicommon.db.SqlContext.Settings +import xyz.driver.pdsuicommon.db.MySqlContext.Settings import xyz.driver.pdsuicommon.error.IncorrectIdException -import xyz.driver.pdsuicommon.logging.{PhiLogging, Unsafe} +import xyz.driver.pdsuicommon.logging._ import scala.concurrent.ExecutionContext import scala.util.control.NonFatal import scala.util.{Failure, Success, Try} -object SqlContext extends PhiLogging { +object MySqlContext extends PhiLogging { case class DbCredentials(user: String, password: String, @@ -33,20 +33,21 @@ object SqlContext extends PhiLogging { connectionAttemptsOnStartup: Int, threadPoolSize: Int) - def apply(settings: Settings): SqlContext = { + def apply(settings: Settings): MySqlContext = { // Prevent leaking credentials to a log Try(JdbcContextConfig(settings.connection).dataSource) match { - case Success(dataSource) => new SqlContext(dataSource, settings) + case Success(dataSource) => new MySqlContext(dataSource, settings) case Failure(NonFatal(e)) => logger.error(phi"Can not load dataSource, error: ${Unsafe(e.getClass.getName)}") throw new IllegalArgumentException("Can not load dataSource from config. Check your database and config") } } - } -class SqlContext(dataSource: DataSource with Closeable, settings: Settings) - extends MysqlJdbcContext[MysqlEscape](dataSource) with EntityExtractorDerivation[Literal] { +class MySqlContext(dataSource: DataSource with Closeable, settings: Settings) + extends MysqlJdbcContext[MysqlEscape](dataSource) + with TransactionalContext + with EntityExtractorDerivation[Literal] { private val tpe = Executors.newFixedThreadPool(settings.threadPoolSize) diff --git a/src/main/scala/xyz/driver/pdsuicommon/db/MysqlQueryBuilder.scala b/src/main/scala/xyz/driver/pdsuicommon/db/MysqlQueryBuilder.scala index 6b7639a..e2936e3 100644 --- a/src/main/scala/xyz/driver/pdsuicommon/db/MysqlQueryBuilder.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/db/MysqlQueryBuilder.scala @@ -2,12 +2,12 @@ package xyz.driver.pdsuicommon.db import java.sql.ResultSet +import xyz.driver.pdsuicommon.logging._ import io.getquill.{MySQLDialect, MysqlEscape} import scala.collection.breakOut -import scala.concurrent.{ExecutionContext, Future} -object MysqlQueryBuilder { +object MysqlQueryBuilder extends PhiLogging { import xyz.driver.pdsuicommon.db.QueryBuilder._ def apply[T](tableName: String, @@ -15,46 +15,44 @@ object MysqlQueryBuilder { nullableFields: Set[String], links: Set[TableLink], runner: Runner[T], - countRunner: CountRunner)(implicit ec: ExecutionContext): MysqlQueryBuilder[T] = { + countRunner: CountRunner): MysqlQueryBuilder[T] = { val parameters = MysqlQueryBuilderParameters( tableData = TableData(tableName, lastUpdateFieldName, nullableFields), links = links.map(x => x.foreignTableName -> x)(breakOut) ) - new MysqlQueryBuilder[T](parameters)(runner, countRunner, ec) + new MysqlQueryBuilder[T](parameters)(runner, countRunner) } def apply[T](tableName: String, lastUpdateFieldName: Option[String], nullableFields: Set[String], links: Set[TableLink], - extractor: (ResultSet) => T)(implicit sqlContext: SqlContext): MysqlQueryBuilder[T] = { - - val runner = (parameters: QueryBuilderParameters) => { - Future { - val (sql, binder) = parameters.toSql(namingStrategy = MysqlEscape) - sqlContext.executeQuery[T](sql, binder, { resultSet => - extractor(resultSet) - }) - }(sqlContext.executionContext) + extractor: (ResultSet) => T)(implicit sqlContext: MySqlContext): MysqlQueryBuilder[T] = { + + val runner: Runner[T] = { parameters => + val (sql, binder) = parameters.toSql(namingStrategy = MysqlEscape) + logger.trace(phi"Query for execute: ${Unsafe(sql)}") + sqlContext.executeQuery[T](sql, binder, { resultSet => + extractor(resultSet) + }) } - val countRunner = (parameters: QueryBuilderParameters) => { - Future { - val (sql, binder) = parameters.toSql(countQuery = true, namingStrategy = MysqlEscape) - sqlContext - .executeQuery[CountResult]( - sql, - binder, { resultSet => - val count = resultSet.getInt(1) - val lastUpdate = if (parameters.tableData.lastUpdateFieldName.isDefined) { - Option(sqlContext.localDateTimeDecoder.decoder(2, resultSet)) - } else None - - (count, lastUpdate) - } - ) - .head - }(sqlContext.executionContext) + val countRunner: CountRunner = { parameters => + val (sql, binder) = parameters.toSql(countQuery = true, namingStrategy = MysqlEscape) + logger.trace(phi"Query for execute: ${Unsafe(sql)}") + sqlContext + .executeQuery[CountResult]( + sql, + binder, { resultSet => + val count = resultSet.getInt(1) + val lastUpdate = if (parameters.tableData.lastUpdateFieldName.isDefined) { + Option(sqlContext.localDateTimeDecoder.decoder(2, resultSet)) + } else None + + (count, lastUpdate) + } + ) + .head } apply[T]( @@ -64,13 +62,12 @@ object MysqlQueryBuilder { links = links, runner = runner, countRunner = countRunner - )(sqlContext.executionContext) + ) } } class MysqlQueryBuilder[T](parameters: MysqlQueryBuilderParameters)(implicit runner: QueryBuilder.Runner[T], - countRunner: QueryBuilder.CountRunner, - ec: ExecutionContext) + countRunner: QueryBuilder.CountRunner) extends QueryBuilder[T, MySQLDialect, MysqlEscape](parameters) { def withFilter(newFilter: SearchFilterExpr): QueryBuilder[T, MySQLDialect, MysqlEscape] = { @@ -88,5 +85,4 @@ class MysqlQueryBuilder[T](parameters: MysqlQueryBuilderParameters)(implicit run def resetPagination: QueryBuilder[T, MySQLDialect, MysqlEscape] = { new MysqlQueryBuilder[T](parameters.copy(pagination = None)) } - } diff --git a/src/main/scala/xyz/driver/pdsuicommon/db/QueryBuilder.scala b/src/main/scala/xyz/driver/pdsuicommon/db/QueryBuilder.scala index 733d355..f941627 100644 --- a/src/main/scala/xyz/driver/pdsuicommon/db/QueryBuilder.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/db/QueryBuilder.scala @@ -9,15 +9,14 @@ import xyz.driver.pdsuicommon.db.Sorting.{Dimension, Sequential} import xyz.driver.pdsuicommon.db.SortingOrder.{Ascending, Descending} import scala.collection.mutable.ListBuffer -import scala.concurrent.{ExecutionContext, Future} object QueryBuilder { - type Runner[T] = (QueryBuilderParameters) => Future[Seq[T]] + type Runner[T] = QueryBuilderParameters => Seq[T] type CountResult = (Int, Option[LocalDateTime]) - type CountRunner = (QueryBuilderParameters) => Future[CountResult] + type CountRunner = QueryBuilderParameters => CountResult /** * Binder for PreparedStatement @@ -207,12 +206,14 @@ sealed trait QueryBuilderParameters { val bindings = ListBuffer[AnyRef]() val sqlPlaceholder = placeholder(dimension.name) - val formattedValues = values - .map { value => - bindings += value - sqlPlaceholder - } - .mkString(", ") + val formattedValues = if (values.nonEmpty) { + values + .map { value => + bindings += value + sqlPlaceholder + } + .mkString(", ") + } else "NULL" (s"${escapeDimension(dimension)} $sqlOp ($formattedValues)", bindings.toList) case Intersection(operands) => @@ -297,23 +298,18 @@ case class MysqlQueryBuilderParameters(tableData: QueryBuilder.TableData, abstract class QueryBuilder[T, D <: SqlIdiom, N <: NamingStrategy](val parameters: QueryBuilderParameters)( implicit runner: QueryBuilder.Runner[T], - countRunner: QueryBuilder.CountRunner, - ec: ExecutionContext) { + countRunner: QueryBuilder.CountRunner) { - def run: Future[Seq[T]] = runner(parameters) + def run: Seq[T] = runner(parameters) - def runCount: Future[QueryBuilder.CountResult] = countRunner(parameters) + def runCount: QueryBuilder.CountResult = countRunner(parameters) /** * Runs the query and returns total found rows without considering of pagination. */ - def runWithCount: Future[(Seq[T], Int, Option[LocalDateTime])] = { - val countFuture = runCount - val selectAllFuture = run - for { - (total, lastUpdate) <- countFuture - all <- selectAllFuture - } yield (all, total, lastUpdate) + def runWithCount: (Seq[T], Int, Option[LocalDateTime]) = { + val (total, lastUpdate) = runCount + (run, total, lastUpdate) } def withFilter(newFilter: SearchFilterExpr): QueryBuilder[T, D, N] diff --git a/src/main/scala/xyz/driver/pdsuicommon/db/SearchFilterExpr.scala b/src/main/scala/xyz/driver/pdsuicommon/db/SearchFilterExpr.scala index 5144163..4b66f22 100644 --- a/src/main/scala/xyz/driver/pdsuicommon/db/SearchFilterExpr.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/db/SearchFilterExpr.scala @@ -54,7 +54,7 @@ object SearchFilterExpr { } } - case class Intersection private (operands: Seq[SearchFilterExpr]) + final case class Intersection private (operands: Seq[SearchFilterExpr]) extends SearchFilterExpr with SearchFilterExprSeqOps { override def replace(f: PartialFunction[SearchFilterExpr, SearchFilterExpr]): SearchFilterExpr = { @@ -80,7 +80,8 @@ object SearchFilterExpr { } } - case class Union private (operands: Seq[SearchFilterExpr]) extends SearchFilterExpr with SearchFilterExprSeqOps { + final case class Union private (operands: Seq[SearchFilterExpr]) + extends SearchFilterExpr with SearchFilterExprSeqOps { override def replace(f: PartialFunction[SearchFilterExpr, SearchFilterExpr]): SearchFilterExpr = { if (f.isDefinedAt(this)) f(this) diff --git a/src/main/scala/xyz/driver/pdsuicommon/db/TransactionalContext.scala b/src/main/scala/xyz/driver/pdsuicommon/db/TransactionalContext.scala new file mode 100644 index 0000000..9883b9e --- /dev/null +++ b/src/main/scala/xyz/driver/pdsuicommon/db/TransactionalContext.scala @@ -0,0 +1,11 @@ +package xyz.driver.pdsuicommon.db + +import scala.concurrent.ExecutionContext + +trait TransactionalContext { + + implicit def executionContext: ExecutionContext + + def transaction[T](f: => T): T + +} diff --git a/src/main/scala/xyz/driver/pdsuicommon/db/Transactions.scala b/src/main/scala/xyz/driver/pdsuicommon/db/Transactions.scala deleted file mode 100644 index 72c358a..0000000 --- a/src/main/scala/xyz/driver/pdsuicommon/db/Transactions.scala +++ /dev/null @@ -1,23 +0,0 @@ -package xyz.driver.pdsuicommon.db - -import xyz.driver.pdsuicommon.logging.PhiLogging - -import scala.concurrent.Future -import scala.util.{Failure, Success, Try} - -class Transactions()(implicit context: SqlContext) extends PhiLogging { - def run[T](f: SqlContext => T): Future[T] = { - import context.executionContext - - Future(context.transaction(f(context))).andThen { - case Failure(e) => logger.error(phi"Can't run a transaction: $e") - } - } - - def runSync[T](f: SqlContext => T): Unit = { - Try(context.transaction(f(context))) match { - case Success(_) => - case Failure(e) => logger.error(phi"Can't run a transaction: $e") - } - } -} diff --git a/src/main/scala/xyz/driver/pdsuicommon/db/repositories/BridgeUploadQueueRepository.scala b/src/main/scala/xyz/driver/pdsuicommon/db/repositories/BridgeUploadQueueRepository.scala index a3140a6..4c25afa 100644 --- a/src/main/scala/xyz/driver/pdsuicommon/db/repositories/BridgeUploadQueueRepository.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/db/repositories/BridgeUploadQueueRepository.scala @@ -1,24 +1,21 @@ package xyz.driver.pdsuicommon.db.repositories import xyz.driver.pdsuicommon.concurrent.BridgeUploadQueue -import xyz.driver.pdsuicommon.domain.LongId - -import scala.concurrent.Future +import xyz.driver.pdsuicommon.db.MysqlQueryBuilder trait BridgeUploadQueueRepository extends Repository { type EntityT = BridgeUploadQueue.Item - type IdT = LongId[EntityT] def add(draft: EntityT): EntityT - def getById(id: LongId[EntityT]): Option[EntityT] - - def isCompleted(kind: String, tag: String): Future[Boolean] + def getById(kind: String, tag: String): Option[EntityT] - def getOne(kind: String): Future[Option[BridgeUploadQueue.Item]] + def getOne(kind: String): Option[BridgeUploadQueue.Item] def update(entity: EntityT): EntityT - def delete(id: IdT): Unit + def delete(kind: String, tag: String): Unit + + def buildQuery: MysqlQueryBuilder[EntityT] } diff --git a/src/main/scala/xyz/driver/pdsuicommon/domain/User.scala b/src/main/scala/xyz/driver/pdsuicommon/domain/User.scala index 45adefc..bf4970e 100644 --- a/src/main/scala/xyz/driver/pdsuicommon/domain/User.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/domain/User.scala @@ -1,5 +1,7 @@ package xyz.driver.pdsuicommon.domain +import java.math.BigInteger +import java.security.SecureRandom import java.time.LocalDateTime import xyz.driver.pdsuicommon.logging._ @@ -31,16 +33,18 @@ object User { } object Role extends PhiLogging { - case object RecordAdmin extends Role { val bit = 1 << 0 } - case object RecordCleaner extends Role { val bit = 1 << 1 } - case object RecordOrganizer extends Role { val bit = 1 << 2 } - case object DocumentExtractor extends Role { val bit = 1 << 3 } - case object TrialSummarizer extends Role { val bit = 1 << 4 } - case object CriteriaCurator extends Role { val bit = 1 << 5 } - case object TrialAdmin extends Role { val bit = 1 << 6 } - case object EligibilityVerifier extends Role { val bit = 1 << 7 } - case object TreatmentMatchingAdmin extends Role { val bit = 1 << 8 } - case object RoutesCurator extends Role { val bit = 1 << 9 } + case object RecordAdmin extends Role { val bit = 1 << 0 } + case object RecordCleaner extends Role { val bit = 1 << 1 } + case object RecordOrganizer extends Role { val bit = 1 << 2 } + case object DocumentExtractor extends Role { val bit = 1 << 3 } + case object TrialSummarizer extends Role { val bit = 1 << 4 } + case object CriteriaCurator extends Role { val bit = 1 << 5 } + case object TrialAdmin extends Role { val bit = 1 << 6 } + case object EligibilityVerifier extends Role { val bit = 1 << 7 } + case object TreatmentMatchingAdmin extends Role { val bit = 1 << 8 } + case object RoutesCurator extends Role { val bit = 1 << 9 } + case object SystemUser extends Role { val bit = 1 << 10 } + case object ResearchOncologist extends Role { val bit = 1 << 11 } val RepRoles = Set[Role](RecordAdmin, RecordCleaner, RecordOrganizer, DocumentExtractor) @@ -48,7 +52,9 @@ object User { val TreatmentMatchingRoles = Set[Role](RoutesCurator, EligibilityVerifier, TreatmentMatchingAdmin) - val All = RepRoles ++ TcRoles ++ TreatmentMatchingRoles + val PepRoles = Set[Role](ResearchOncologist) + + val All = RepRoles ++ TcRoles ++ TreatmentMatchingRoles ++ PepRoles + SystemUser def apply(bitMask: Int): Role = { def extractRole(role: Role): Set[Role] = @@ -71,4 +77,9 @@ object User { phi"User(id=$id, role=$role)" } + // SecureRandom is thread-safe, see the implementation + private val random = new SecureRandom() + + def createPassword: String = new BigInteger(240, random).toString(32) + } diff --git a/src/main/scala/xyz/driver/pdsuicommon/http/AsyncHttpClientFetcher.scala b/src/main/scala/xyz/driver/pdsuicommon/http/AsyncHttpClientFetcher.scala index d836b9d..085dcd8 100644 --- a/src/main/scala/xyz/driver/pdsuicommon/http/AsyncHttpClientFetcher.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/http/AsyncHttpClientFetcher.scala @@ -85,6 +85,6 @@ class AsyncHttpClientFetcher(settings: AsyncHttpClientFetcher.Settings) object AsyncHttpClientFetcher { - case class Settings(connectTimeout: FiniteDuration, readTimeout: FiniteDuration) + final case class Settings(connectTimeout: FiniteDuration, readTimeout: FiniteDuration) } diff --git a/src/main/scala/xyz/driver/pdsuicommon/json/JsResultOps.scala b/src/main/scala/xyz/driver/pdsuicommon/json/JsResultOps.scala new file mode 100644 index 0000000..07dfefc --- /dev/null +++ b/src/main/scala/xyz/driver/pdsuicommon/json/JsResultOps.scala @@ -0,0 +1,15 @@ +package xyz.driver.pdsuicommon.json + +import play.api.libs.json.JsResult + +import scala.util.{Failure, Success, Try} + +final class JsResultOps[T](val self: JsResult[T]) extends AnyVal { + + def toTry: Try[T] = { + self.fold( + errors => Failure(new JsonValidationException(errors)), + Success(_) + ) + } +} diff --git a/src/main/scala/xyz/driver/pdsuicommon/json/Serialization.scala b/src/main/scala/xyz/driver/pdsuicommon/json/Serialization.scala index a6d3ee9..223c66e 100644 --- a/src/main/scala/xyz/driver/pdsuicommon/json/Serialization.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/json/Serialization.scala @@ -10,7 +10,10 @@ object Serialization { // @TODO Test and check all items in an array private def seqJsonReads[T](implicit argFormat: Reads[T]): Reads[Seq[T]] = Reads { - case JsArray(xs) => JsSuccess(xs.map { x => argFormat.reads(x).get }) + case JsArray(xs) => + JsSuccess(xs.map { x => + argFormat.reads(x).get + }) case x => JsError(s"Expected JsArray, but got $x") } @@ -20,23 +23,25 @@ object Serialization { implicit def seqJsonFormat[T](implicit f: Format[T]): Format[Seq[T]] = Format(seqJsonReads[T], seqJsonWrites[T]) - private val uriJsonReads: Reads[URI] = Reads.StringReads.map(URI.create) - private val uriJsonWrites: Writes[URI] = Writes(uri => JsString(uri.toString)) + private val uriJsonReads: Reads[URI] = Reads.StringReads.map(URI.create) + private val uriJsonWrites: Writes[URI] = Writes(uri => JsString(uri.toString)) implicit val uriJsonFormat: Format[URI] = Format(uriJsonReads, uriJsonWrites) - private def uuidIdJsonReads[T]: Reads[UuidId[T]] = Reads.uuidReads.map(x => UuidId[T](x)) - private def uuidIdJsonWrites[T]: Writes[UuidId[T]] = Writes.UuidWrites.contramap(_.id) + private def uuidIdJsonReads[T]: Reads[UuidId[T]] = Reads.uuidReads.map(x => UuidId[T](x)) + private def uuidIdJsonWrites[T]: Writes[UuidId[T]] = Writes.UuidWrites.contramap(_.id) implicit def uuidIdJsonFormat[T]: Format[UuidId[T]] = Format(uuidIdJsonReads, uuidIdJsonWrites) - private def longIdJsonReads[T]: Reads[LongId[T]] = Reads.LongReads.map(x => LongId[T](x)) - private def longIdJsonWrites[T]: Writes[LongId[T]] = Writes.LongWrites.contramap(_.id) + private def longIdJsonReads[T]: Reads[LongId[T]] = Reads.LongReads.map(x => LongId[T](x)) + private def longIdJsonWrites[T]: Writes[LongId[T]] = Writes.LongWrites.contramap(_.id) implicit def longIdJsonFormat[T]: Format[LongId[T]] = Format(longIdJsonReads, longIdJsonWrites) - private val emailJsonReads: Reads[Email] = Reads.email.map(Email.apply) - private val emailJsonWrites: Writes[Email] = Writes(email => JsString(email.value)) + private val emailJsonReads: Reads[Email] = Reads.email.map(Email.apply) + private val emailJsonWrites: Writes[Email] = Writes(email => JsString(email.value)) implicit val emailJsonFormat: Format[Email] = Format(emailJsonReads, emailJsonWrites) - private val passwordHashJsonReads: Reads[PasswordHash] = Reads.StringReads.map(hash => PasswordHash(hash.getBytes("UTF-8"))) - private val passwordHashJsonWrites: Writes[PasswordHash] = Writes(passwordHash => JsString(passwordHash.value.toString)) + private val passwordHashJsonReads: Reads[PasswordHash] = + Reads.StringReads.map(hash => PasswordHash(hash.getBytes("UTF-8"))) + private val passwordHashJsonWrites: Writes[PasswordHash] = Writes( + passwordHash => JsString(passwordHash.value.toString)) implicit val passwordHashJsonFormat: Format[PasswordHash] = Format(passwordHashJsonReads, passwordHashJsonWrites) } diff --git a/src/main/scala/xyz/driver/pdsuicommon/TimeLogger.scala b/src/main/scala/xyz/driver/pdsuicommon/logging/TimeLogger.scala index 41c83d5..dd5ba5e 100644 --- a/src/main/scala/xyz/driver/pdsuicommon/TimeLogger.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/logging/TimeLogger.scala @@ -1,9 +1,8 @@ -package xyz.driver.pdsuicommon +package xyz.driver.pdsuicommon.logging import java.time.{LocalDateTime, ZoneId} import xyz.driver.pdsuicommon.domain.{LongId, User} -import xyz.driver.pdsuicommon.logging._ object TimeLogger extends PhiLogging { diff --git a/src/main/scala/xyz/driver/pdsuicommon/logging/Unsafe.scala b/src/main/scala/xyz/driver/pdsuicommon/logging/Unsafe.scala index 7fd810f..c3ebe80 100644 --- a/src/main/scala/xyz/driver/pdsuicommon/logging/Unsafe.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/logging/Unsafe.scala @@ -3,5 +3,5 @@ package xyz.driver.pdsuicommon.logging /** * Use it with care! */ -case class Unsafe[T](private[logging] val value: T) +final case class Unsafe[T](private[logging] val value: T) extends PhiString(Option(value).map(_.toString).getOrElse("<null>")) diff --git a/src/main/scala/xyz/driver/pdsuicommon/serialization/Marshaller.scala b/src/main/scala/xyz/driver/pdsuicommon/serialization/Marshaller.scala new file mode 100644 index 0000000..6702de2 --- /dev/null +++ b/src/main/scala/xyz/driver/pdsuicommon/serialization/Marshaller.scala @@ -0,0 +1,6 @@ +package xyz.driver.pdsuicommon.serialization + +trait Marshaller[T, Repr] { + def read(x: Repr): Option[T] + def write(x: T): Repr +} diff --git a/src/main/scala/xyz/driver/pdsuicommon/utils/CharOps.scala b/src/main/scala/xyz/driver/pdsuicommon/utils/CharOps.scala new file mode 100644 index 0000000..42bf92d --- /dev/null +++ b/src/main/scala/xyz/driver/pdsuicommon/utils/CharOps.scala @@ -0,0 +1,31 @@ +package xyz.driver.pdsuicommon.utils + +final class CharOps(val self: Char) extends AnyVal { + + import CharOps._ + + def isSafeWhitespace: Boolean = Whitespace.matches(self) + + def isSafeControl: Boolean = JavaIsoControl.matches(self) +} + +// From Guava +private object CharOps { + + object Whitespace { + private val Table: String = + "\u2002\u3000\r\u0085\u200A\u2005\u2000\u3000" + + "\u2029\u000B\u3000\u2008\u2003\u205F\u3000\u1680" + + "\u0009\u0020\u2006\u2001\u202F\u00A0\u000C\u2009" + + "\u3000\u2004\u3000\u3000\u2028\n\u2007\u3000" + + private val Multiplier: Int = 1682554634 + private val Shift: Int = Integer.numberOfLeadingZeros(Table.length - 1) + + def matches(c: Char): Boolean = Table.charAt((Multiplier * c) >>> Shift) == c + } + + object JavaIsoControl { + def matches(c: Char): Boolean = c <= '\u001f' || (c >= '\u007f' && c <= '\u009f') + } +} diff --git a/src/main/scala/xyz/driver/pdsuicommon/utils/FutureUtils.scala b/src/main/scala/xyz/driver/pdsuicommon/utils/FutureUtils.scala index 9eecb7f..e8b1f5c 100644 --- a/src/main/scala/xyz/driver/pdsuicommon/utils/FutureUtils.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/utils/FutureUtils.scala @@ -1,7 +1,7 @@ package xyz.driver.pdsuicommon.utils import scala.concurrent.{ExecutionContext, Future} -import scala.util.Try +import scala.util.{Failure, Try} object FutureUtils { @@ -13,6 +13,6 @@ object FutureUtils { override def execute(runnable: Runnable): Unit = runnable.run() } } - future.value.get + future.value.getOrElse(Failure(new IllegalStateException("Can not evaluate the result of future"))) } } diff --git a/src/main/scala/xyz/driver/pdsuicommon/utils/Implicits.scala b/src/main/scala/xyz/driver/pdsuicommon/utils/Implicits.scala index c8af125..9411beb 100644 --- a/src/main/scala/xyz/driver/pdsuicommon/utils/Implicits.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/utils/Implicits.scala @@ -1,5 +1,8 @@ package xyz.driver.pdsuicommon.utils +import play.api.libs.json.JsResult +import xyz.driver.pdsuicommon.json.JsResultOps + import scala.collection.generic.CanBuildFrom object Implicits { @@ -19,4 +22,8 @@ object Implicits { new ConditionalAppend[U, T](c) implicit def toMapOps[K, V](x: Map[K, V]): MapOps[K, V] = new MapOps(x) + + implicit def toCharOps(self: Char): CharOps = new CharOps(self) + implicit def toStringOps(self: String): StringOps = new StringOps(self) + implicit def toJsResultOps[T](self: JsResult[T]): JsResultOps[T] = new JsResultOps(self) } diff --git a/src/main/scala/xyz/driver/pdsuicommon/utils/StringOps.scala b/src/main/scala/xyz/driver/pdsuicommon/utils/StringOps.scala new file mode 100644 index 0000000..b38721e --- /dev/null +++ b/src/main/scala/xyz/driver/pdsuicommon/utils/StringOps.scala @@ -0,0 +1,23 @@ +package xyz.driver.pdsuicommon.utils + +import xyz.driver.pdsuicommon.utils.Implicits.toCharOps + +final class StringOps(val self: String) extends AnyVal { + + def safeTrim: String = { + def shouldKeep(c: Char): Boolean = !c.isSafeControl && !c.isSafeWhitespace + + if (self.isEmpty) { + "" + } else { + val start = self.indexWhere(shouldKeep) + val end = self.lastIndexWhere(shouldKeep) + + if (start >= 0 && end >= 0) { + self.substring(start, end + 1) + } else { + "" + } + } + } +} diff --git a/src/main/scala/xyz/driver/pdsuicommon/utils/WriteableImplicits.scala b/src/main/scala/xyz/driver/pdsuicommon/utils/WriteableImplicits.scala new file mode 100644 index 0000000..2c66a23 --- /dev/null +++ b/src/main/scala/xyz/driver/pdsuicommon/utils/WriteableImplicits.scala @@ -0,0 +1,15 @@ +package xyz.driver.pdsuicommon.utils + +import play.api.http.{ContentTypes, Writeable} +import play.api.libs.json.{Json, Writes} + +// @TODO this should be an object with a method, that gets HTTP-headers and returns suitable Writeable +trait WriteableImplicits { + + // Write JSON by default at now + implicit def defaultWriteable[T](implicit inner: Writes[T]) = Writeable[T]( + { x: T => Writeable.writeableOf_JsValue.transform(Json.toJson(x)) }, + Option(ContentTypes.JSON) + ) + +} diff --git a/src/main/scala/xyz/driver/pdsuicommon/utils/WritesUtils.scala b/src/main/scala/xyz/driver/pdsuicommon/utils/WritesUtils.scala new file mode 100644 index 0000000..fa05e96 --- /dev/null +++ b/src/main/scala/xyz/driver/pdsuicommon/utils/WritesUtils.scala @@ -0,0 +1,21 @@ +package xyz.driver.pdsuicommon.utils + +import play.api.libs.json._ + +object WritesUtils { + + def filterKeys[T](p: String => Boolean)(implicit w: Writes[T]): Writes[T] = { + filter { + case (key, _) => p(key) + } + } + + def filter[T](p: (String, JsValue) => Boolean)(implicit w: Writes[T]): Writes[T] = { + w.transform { input: JsValue => + input match { + case JsObject(map) => JsObject(map.filter(Function.tupled(p))) + case x => x + } + } + } +} diff --git a/src/main/scala/xyz/driver/pdsuicommon/validation/AdditionalConstraints.scala b/src/main/scala/xyz/driver/pdsuicommon/validation/AdditionalConstraints.scala index 115163c..cb1082f 100644 --- a/src/main/scala/xyz/driver/pdsuicommon/validation/AdditionalConstraints.scala +++ b/src/main/scala/xyz/driver/pdsuicommon/validation/AdditionalConstraints.scala @@ -5,17 +5,25 @@ import play.api.data.validation._ object AdditionalConstraints { + val nonNegativePrintedNumber: Constraint[String] = { + Constraints.pattern("^\\d+$".r, "printedInt.nonNegative", "must be a non-negative number") + } + + val positivePrintedNumber: Constraint[String] = { + Constraints.pattern("^[1-9]\\d*$".r, "printedInt.positive", "must be a positive number") + } + val optionNonEmptyConstraint: Constraint[Option[Any]] = { Constraint("option.nonEmpty") { case Some(x) => Valid - case None => Invalid("is empty") + case None => Invalid("is empty") } } val tristateSpecifiedConstraint: Constraint[Tristate[Any]] = { Constraint("tristate.specified") { case Tristate.Unspecified => Invalid("unspecified") - case _ => Valid + case _ => Valid } } diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/ScrapedTrial.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/ScrapedTrial.scala index 40e84c9..87c5fd9 100644 --- a/src/main/scala/xyz/driver/pdsuidomain/entities/ScrapedTrial.scala +++ b/src/main/scala/xyz/driver/pdsuidomain/entities/ScrapedTrial.scala @@ -51,9 +51,7 @@ object ScrapedIntervention { implicit def toPhiString(x: ScrapedIntervention): PhiString = phi"ScrapedIntervention(${Unsafe(x.name)})" } -final case class ScrapedArm(name: String, - kind: Option[String], - interventions: Set[ScrapedIntervention]) +final case class ScrapedArm(name: String, kind: Option[String], interventions: Set[ScrapedIntervention]) object ScrapedArm { diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/arm/ApiArm.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/arm/ApiArm.scala index 509ea35..2185e3a 100644 --- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/arm/ApiArm.scala +++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/arm/ApiArm.scala @@ -12,7 +12,7 @@ object ApiArm { (JsPath \ "id").format[Long] and (JsPath \ "name").format[String] and (JsPath \ "trialId").format[String] - ) (ApiArm.apply, unlift(ApiArm.unapply)) + )(ApiArm.apply, unlift(ApiArm.unapply)) def fromDomain(arm: Arm): ApiArm = ApiArm( id = arm.id.id, diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/category/ApiCategory.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/category/ApiCategory.scala index fabdaa2..f1e15f3 100644 --- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/category/ApiCategory.scala +++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/category/ApiCategory.scala @@ -13,7 +13,7 @@ object ApiCategory { (JsPath \ "id").format[Long] and (JsPath \ "name").format[String] and (JsPath \ "labels").format[List[ApiLabel]] - ) (ApiCategory.apply, unlift(ApiCategory.unapply)) + )(ApiCategory.apply, unlift(ApiCategory.unapply)) def fromDomain(categoryWithLabels: CategoryWithLabels) = ApiCategory( id = categoryWithLabels.category.id.id, diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/criterion/ApiCriterion.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/criterion/ApiCriterion.scala index 0f3b76e..1e7114a 100644 --- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/criterion/ApiCriterion.scala +++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/criterion/ApiCriterion.scala @@ -26,7 +26,7 @@ object ApiCriterion { (JsPath \ "isCompound").format[Boolean] and (JsPath \ "labels").format(seqJsonFormat[ApiCriterionLabel]) and (JsPath \ "trialId").format[String] - ) (ApiCriterion.apply, unlift(ApiCriterion.unapply)) + )(ApiCriterion.apply, unlift(ApiCriterion.unapply)) def fromDomain(richCriterion: RichCriterion) = ApiCriterion( id = richCriterion.criterion.id.id, diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/criterion/ApiNewCriterion.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/criterion/ApiNewCriterion.scala index 85c91d5..604a98b 100644 --- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/criterion/ApiNewCriterion.scala +++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/criterion/ApiNewCriterion.scala @@ -37,5 +37,5 @@ object ApiNewCriterion { (JsPath \ "text").formatNullable[String] and (JsPath \ "labels").format(seqJsonFormat[ApiCriterionLabel]) and (JsPath \ "trialId").format[String] - ) (ApiNewCriterion.apply, unlift(ApiNewCriterion.unapply)) + )(ApiNewCriterion.apply, unlift(ApiNewCriterion.unapply)) } diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/criterion/ApiUpdateCriterion.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/criterion/ApiUpdateCriterion.scala index c73c3ef..2bcda56 100644 --- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/criterion/ApiUpdateCriterion.scala +++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/criterion/ApiUpdateCriterion.scala @@ -34,15 +34,19 @@ final case class ApiUpdateCriterion(meta: Tristate[String], object ApiUpdateCriterion { private val reads: Reads[ApiUpdateCriterion] = ( - (JsPath \ "meta").readTristate(Reads { x => JsSuccess(Json.stringify(x)) }).map { - case Tristate.Present("{}") => Tristate.Absent - case x => x - } and + (JsPath \ "meta") + .readTristate(Reads { x => + JsSuccess(Json.stringify(x)) + }) + .map { + case Tristate.Present("{}") => Tristate.Absent + case x => x + } and (JsPath \ "arms").readTristate(seqJsonFormat[Long]) and (JsPath \ "text").readNullable[String] and (JsPath \ "isCompound").readNullable[Boolean] and (JsPath \ "labels").readTristate(seqJsonFormat[ApiCriterionLabel]) - ) (ApiUpdateCriterion.apply _) + )(ApiUpdateCriterion.apply _) private val writes: Writes[ApiUpdateCriterion] = ( (JsPath \ "meta").writeTristate(Writes[String](Json.parse)) and @@ -50,7 +54,7 @@ object ApiUpdateCriterion { (JsPath \ "text").writeNullable[String] and (JsPath \ "isCompound").writeNullable[Boolean] and (JsPath \ "labels").writeTristate(seqJsonFormat[ApiCriterionLabel]) - ) (unlift(ApiUpdateCriterion.unapply)) + )(unlift(ApiUpdateCriterion.unapply)) implicit val format: Format[ApiUpdateCriterion] = Format(reads, writes) } diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/document/ApiDocument.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/document/ApiDocument.scala index be9c65b..0fd96b3 100644 --- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/document/ApiDocument.scala +++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/document/ApiDocument.scala @@ -28,7 +28,7 @@ object ApiDocument { private val statusFormat = Format( Reads.StringReads.filter(ValidationError("unknown status")) { case x if DocumentUtils.statusFromString.isDefinedAt(x) => true - case _ => false + case _ => false }, Writes.StringWrites ) @@ -47,8 +47,10 @@ object ApiDocument { (JsPath \ "previousStatus").formatNullable(statusFormat) and (JsPath \ "assignee").formatNullable[Long] and (JsPath \ "previousAssignee").formatNullable[Long] and - (JsPath \ "meta").formatNullable(Format(Reads { x => JsSuccess(Json.stringify(x)) }, Writes[String](Json.parse))) - ) (ApiDocument.apply, unlift(ApiDocument.unapply)) + (JsPath \ "meta").formatNullable(Format(Reads { x => + JsSuccess(Json.stringify(x)) + }, Writes[String](Json.parse))) + )(ApiDocument.apply, unlift(ApiDocument.unapply)) def fromDomain(document: Document): ApiDocument = { ApiDocument( diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/document/ApiDocumentType.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/document/ApiDocumentType.scala index e00da20..8b11b91 100644 --- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/document/ApiDocumentType.scala +++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/document/ApiDocumentType.scala @@ -11,7 +11,7 @@ object ApiDocumentType { implicit val format: Format[ApiDocumentType] = ( (JsPath \ "id").format[Long] and (JsPath \ "name").format[String] - ) (ApiDocumentType.apply, unlift(ApiDocumentType.unapply)) + )(ApiDocumentType.apply, unlift(ApiDocumentType.unapply)) def fromDomain(documentType: DocumentType) = ApiDocumentType( id = documentType.id.id, diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/document/ApiProviderType.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/document/ApiProviderType.scala index 7b370ba..eb0ac46 100644 --- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/document/ApiProviderType.scala +++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/document/ApiProviderType.scala @@ -11,7 +11,7 @@ object ApiProviderType { implicit val format: Format[ApiProviderType] = ( (JsPath \ "id").format[Long] and (JsPath \ "name").format[String] - ) (ApiProviderType.apply, unlift(ApiProviderType.unapply)) + )(ApiProviderType.apply, unlift(ApiProviderType.unapply)) def fromDomain(providerType: ProviderType) = ApiProviderType( id = providerType.id.id, diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/document/DocumentUtils.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/document/DocumentUtils.scala index 87e449f..24e388e 100644 --- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/document/DocumentUtils.scala +++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/document/DocumentUtils.scala @@ -5,20 +5,20 @@ import xyz.driver.pdsuidomain.entities.Document.Status object DocumentUtils { val statusFromString: PartialFunction[String, Status] = { - case "New" => Status.New + case "New" => Status.New case "Organized" => Status.Organized case "Extracted" => Status.Extracted - case "Done" => Status.Done - case "Flagged" => Status.Flagged - case "Archived" => Status.Archived + case "Done" => Status.Done + case "Flagged" => Status.Flagged + case "Archived" => Status.Archived } def statusToString(x: Status): String = x match { - case Status.New => "New" + case Status.New => "New" case Status.Organized => "Organized" case Status.Extracted => "Extracted" - case Status.Done => "Done" - case Status.Flagged => "Flagged" - case Status.Archived => "Archived" + case Status.Done => "Done" + case Status.Flagged => "Flagged" + case Status.Archived => "Archived" } } diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/extracteddata/ApiExtractedData.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/extracteddata/ApiExtractedData.scala index dad7a1e..ec4185f 100644 --- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/extracteddata/ApiExtractedData.scala +++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/extracteddata/ApiExtractedData.scala @@ -26,12 +26,17 @@ object ApiExtractedData { (JsPath \ "keywordId").formatNullable[Long] and (JsPath \ "evidence").formatNullable[String] and (JsPath \ "meta").formatNullable[String] and - (JsPath \ "labels").formatNullable[List[ApiExtractedDataLabel]](Format( - Reads.of[List[ApiExtractedDataLabel]].filter(ValidationError("empty labels"))({ - case x if x.nonEmpty => true - case _ => false - }), Writes.of[List[ApiExtractedDataLabel]])) - ) (ApiExtractedData.apply, unlift(ApiExtractedData.unapply)) + (JsPath \ "labels").formatNullable[List[ApiExtractedDataLabel]]( + Format( + Reads + .of[List[ApiExtractedDataLabel]] + .filter(ValidationError("empty labels"))({ + case x if x.nonEmpty => true + case _ => false + }), + Writes.of[List[ApiExtractedDataLabel]] + )) + )(ApiExtractedData.apply, unlift(ApiExtractedData.unapply)) def fromDomain(extractedDataWithLabels: RichExtractedData) = ApiExtractedData( id = extractedDataWithLabels.extractedData.id.id, diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/extracteddata/ApiPartialExtractedData.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/extracteddata/ApiPartialExtractedData.scala index 69b5627..cfd55fd 100644 --- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/extracteddata/ApiPartialExtractedData.scala +++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/extracteddata/ApiPartialExtractedData.scala @@ -66,7 +66,7 @@ object ApiPartialExtractedData { (JsPath \ "evidence").readTristate[String] and (JsPath \ "meta").readTristate[String] and (JsPath \ "labels").readTristate[List[ApiExtractedDataLabel]] - ) (ApiPartialExtractedData.apply _) + )(ApiPartialExtractedData.apply _) private val writes: Writes[ApiPartialExtractedData] = ( (JsPath \ "documentId").writeNullable[Long] and @@ -74,7 +74,7 @@ object ApiPartialExtractedData { (JsPath \ "evidence").writeTristate[String] and (JsPath \ "meta").writeTristate[String] and (JsPath \ "labels").writeTristate[List[ApiExtractedDataLabel]] - ) (unlift(ApiPartialExtractedData.unapply)) + )(unlift(ApiPartialExtractedData.unapply)) implicit val format: Format[ApiPartialExtractedData] = Format(reads, writes) } diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/hypothesis/ApiHypothesis.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/hypothesis/ApiHypothesis.scala index 0d6763c..7446ec3 100644 --- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/hypothesis/ApiHypothesis.scala +++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/hypothesis/ApiHypothesis.scala @@ -15,7 +15,7 @@ object ApiHypothesis { (JsPath \ "name").format[String] and (JsPath \ "treatmentType").format[String] and (JsPath \ "description").format[String] - ) (ApiHypothesis.apply, unlift(ApiHypothesis.unapply)) + )(ApiHypothesis.apply, unlift(ApiHypothesis.unapply)) def fromDomain(hypothesis: Hypothesis) = ApiHypothesis( id = hypothesis.id.id, diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/intervention/ApiIntervention.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/intervention/ApiIntervention.scala index 37a9758..39e0000 100644 --- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/intervention/ApiIntervention.scala +++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/intervention/ApiIntervention.scala @@ -22,7 +22,7 @@ object ApiIntervention { (JsPath \ "isActive").format[Boolean] and (JsPath \ "arms").format[List[Long]] and (JsPath \ "trialId").format[String] - ) (ApiIntervention.apply, unlift(ApiIntervention.unapply)) + )(ApiIntervention.apply, unlift(ApiIntervention.unapply)) def fromDomain(interventionWithArms: InterventionWithArms): ApiIntervention = { import interventionWithArms.intervention diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/intervention/ApiInterventionType.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/intervention/ApiInterventionType.scala index ca444eb..54d2cb7 100644 --- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/intervention/ApiInterventionType.scala +++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/intervention/ApiInterventionType.scala @@ -11,7 +11,7 @@ object ApiInterventionType { implicit val format: Format[ApiInterventionType] = ( (JsPath \ "id").format[Long] and (JsPath \ "name").format[String] - ) (ApiInterventionType.apply, unlift(ApiInterventionType.unapply)) + )(ApiInterventionType.apply, unlift(ApiInterventionType.unapply)) def fromDomain(interventionType: InterventionType) = ApiInterventionType( id = interventionType.id.id, diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/intervention/ApiPartialIntervention.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/intervention/ApiPartialIntervention.scala index 416237a..f67ba6b 100644 --- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/intervention/ApiPartialIntervention.scala +++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/intervention/ApiPartialIntervention.scala @@ -12,7 +12,7 @@ final case class ApiPartialIntervention(typeId: Option[Long], def applyTo(orig: InterventionWithArms): InterventionWithArms = { val origIntervention = orig.intervention - val draftArmList = arms.map(_.map(x => InterventionArm(LongId(x), orig.intervention.id))) + val draftArmList = arms.map(_.map(x => InterventionArm(LongId(x), orig.intervention.id))) orig.copy( intervention = origIntervention.copy( typeId = typeId.map(LongId(_)).orElse(origIntervention.typeId), @@ -31,14 +31,14 @@ object ApiPartialIntervention { (JsPath \ "description").readNullable[String] and (JsPath \ "isActive").readNullable[Boolean] and (JsPath \ "arms").readNullable[List[Long]] - ) (ApiPartialIntervention.apply _) + )(ApiPartialIntervention.apply _) private val writes: Writes[ApiPartialIntervention] = ( (JsPath \ "typeId").writeNullable[Long] and (JsPath \ "description").writeNullable[String] and (JsPath \ "isActive").writeNullable[Boolean] and (JsPath \ "arms").writeNullable[List[Long]] - ) (unlift(ApiPartialIntervention.unapply)) + )(unlift(ApiPartialIntervention.unapply)) implicit val format: Format[ApiPartialIntervention] = Format(reads, writes) } diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/keyword/ApiKeyword.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/keyword/ApiKeyword.scala index afd012d..a9d02fc 100644 --- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/keyword/ApiKeyword.scala +++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/keyword/ApiKeyword.scala @@ -13,7 +13,7 @@ object ApiKeyword { (JsPath \ "id").format[Long] and (JsPath \ "keyword").format[String] and (JsPath \ "labels").format[List[ApiLabel]] - ) (ApiKeyword.apply, unlift(ApiKeyword.unapply)) + )(ApiKeyword.apply, unlift(ApiKeyword.unapply)) def fromDomain(keywordWithLabels: KeywordWithLabels) = ApiKeyword( id = keywordWithLabels.keyword.id.id, diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/label/ApiCriterionLabel.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/label/ApiCriterionLabel.scala index 2788bf2..7a65af8 100644 --- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/label/ApiCriterionLabel.scala +++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/label/ApiCriterionLabel.scala @@ -21,7 +21,7 @@ final case class ApiCriterionLabel(labelId: Option[Long], categoryId = categoryId.map(LongId[Category]), value = value.map { case "Yes" => true - case "No" => false + case "No" => false }, isDefining = isDefining ) @@ -41,9 +41,13 @@ object ApiCriterionLabel { implicit val format: Format[ApiCriterionLabel] = ( (JsPath \ "labelId").formatNullable[Long] and (JsPath \ "categoryId").formatNullable[Long] and - (JsPath \ "value").formatNullable[String](Format(Reads.of[String].filter(ValidationError("unknown value"))({ x => - x == "Yes" || x == "No" - }), Writes.of[String])) and + (JsPath \ "value").formatNullable[String]( + Format(Reads + .of[String] + .filter(ValidationError("unknown value"))({ x => + x == "Yes" || x == "No" + }), + Writes.of[String])) and (JsPath \ "isDefining").format[Boolean] - ) (ApiCriterionLabel.apply, unlift(ApiCriterionLabel.unapply)) + )(ApiCriterionLabel.apply, unlift(ApiCriterionLabel.unapply)) } diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/label/ApiExtractedDataLabel.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/label/ApiExtractedDataLabel.scala index 9159d27..cb45025 100644 --- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/label/ApiExtractedDataLabel.scala +++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/label/ApiExtractedDataLabel.scala @@ -22,11 +22,15 @@ object ApiExtractedDataLabel { implicit val format: Format[ApiExtractedDataLabel] = ( (JsPath \ "id").formatNullable[Long] and (JsPath \ "categoryId").formatNullable[Long] and - (JsPath \ "value").formatNullable[String](Format(Reads.of[String].filter(ValidationError("unknown value"))({ - case x if FuzzyValue.fromString.isDefinedAt(x) => true - case _ => false - }), Writes.of[String])) - ) (ApiExtractedDataLabel.apply, unlift(ApiExtractedDataLabel.unapply)) + (JsPath \ "value").formatNullable[String]( + Format(Reads + .of[String] + .filter(ValidationError("unknown value"))({ + case x if FuzzyValue.fromString.isDefinedAt(x) => true + case _ => false + }), + Writes.of[String])) + )(ApiExtractedDataLabel.apply, unlift(ApiExtractedDataLabel.unapply)) def fromDomain(dataLabel: ExtractedDataLabel) = ApiExtractedDataLabel( id = dataLabel.labelId.map(_.id), diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/label/ApiLabel.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/label/ApiLabel.scala index 8c30f3a..042b380 100644 --- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/label/ApiLabel.scala +++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/label/ApiLabel.scala @@ -12,7 +12,7 @@ object ApiLabel { (JsPath \ "id").format[Long] and (JsPath \ "name").format[String] and (JsPath \ "categoryId").format[Long] - ) (ApiLabel.apply, unlift(ApiLabel.unapply)) + )(ApiLabel.apply, unlift(ApiLabel.unapply)) def fromDomain(x: Label) = ApiLabel( id = x.id.id, diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/message/ApiMessage.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/message/ApiMessage.scala index 20b2607..05f9564 100644 --- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/message/ApiMessage.scala +++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/message/ApiMessage.scala @@ -55,5 +55,5 @@ object ApiMessage { (JsPath \ "evidence").formatNullable[String] and (JsPath \ "archiveRequired").formatNullable[Boolean] and (JsPath \ "meta").formatNullable[String] - ) (ApiMessage.apply, unlift(ApiMessage.unapply)) + )(ApiMessage.apply, unlift(ApiMessage.unapply)) } diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/message/ApiPartialMessage.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/message/ApiPartialMessage.scala index 151234c..8c390e7 100644 --- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/message/ApiPartialMessage.scala +++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/message/ApiPartialMessage.scala @@ -66,7 +66,7 @@ object ApiPartialMessage { (JsPath \ "evidence").formatNullable[String] and (JsPath \ "archiveRequired").formatNullable[Boolean] and (JsPath \ "meta").formatNullable[String] - ) (ApiPartialMessage.apply, unlift(ApiPartialMessage.unapply)) + )(ApiPartialMessage.apply, unlift(ApiPartialMessage.unapply)) def fromDomain(domain: Message) = ApiPartialMessage( text = Some(domain.text), diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/patient/ApiPatient.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/patient/ApiPatient.scala index 0a3938c..caa556b 100644 --- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/patient/ApiPatient.scala +++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/patient/ApiPatient.scala @@ -28,7 +28,7 @@ object ApiPatient { (JsPath \ "previousAssignee").formatNullable[Long] and (JsPath \ "lastUpdate").format[ZonedDateTime] and (JsPath \ "condition").format[String] - ) (ApiPatient.apply, unlift(ApiPatient.unapply)) + )(ApiPatient.apply, unlift(ApiPatient.unapply)) def fromDomain(patient: Patient) = ApiPatient( id = patient.id.toString, diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/patient/PatientStatus.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/patient/PatientStatus.scala index d906fc6..a23a1de 100644 --- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/patient/PatientStatus.scala +++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/patient/PatientStatus.scala @@ -5,20 +5,20 @@ import xyz.driver.pdsuidomain.entities.Patient.Status object PatientStatus { val statusFromString: PartialFunction[String, Status] = { - case "New" => Status.New + case "New" => Status.New case "Verified" => Status.Verified case "Reviewed" => Status.Reviewed - case "Curated" => Status.Curated - case "Flagged" => Status.Flagged - case "Done" => Status.Done + case "Curated" => Status.Curated + case "Flagged" => Status.Flagged + case "Done" => Status.Done } def statusToString(x: Status): String = x match { - case Status.New => "New" + case Status.New => "New" case Status.Verified => "Verified" case Status.Reviewed => "Reviewed" - case Status.Curated => "Curated" - case Status.Flagged => "Flagged" - case Status.Done => "Done" + case Status.Curated => "Curated" + case Status.Flagged => "Flagged" + case Status.Done => "Done" } } diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/patient/eligible/ApiPatientEligibleTrial.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/patient/eligible/ApiPatientEligibleTrial.scala index c1a6e76..42c3259 100644 --- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/patient/eligible/ApiPatientEligibleTrial.scala +++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/patient/eligible/ApiPatientEligibleTrial.scala @@ -26,12 +26,17 @@ object ApiPatientEligibleTrial { (JsPath \ "trialTitle").format[String] and (JsPath \ "arms").format[List[String]] and (JsPath \ "hypothesisId").format[UUID] and - (JsPath \ "eligibilityStatus").formatNullable[String](Format(Reads.of[String].filter(ValidationError("unknown eligibility status"))({ - case x if FuzzyValue.fromString.isDefinedAt(x) => true - case _ => false - }), Writes.of[String])) and + (JsPath \ "eligibilityStatus").formatNullable[String](Format( + Reads + .of[String] + .filter(ValidationError("unknown eligibility status"))({ + case x if FuzzyValue.fromString.isDefinedAt(x) => true + case _ => false + }), + Writes.of[String] + )) and (JsPath \ "isVerified").format[Boolean] - ) (ApiPatientEligibleTrial.apply, unlift(ApiPatientEligibleTrial.unapply)) + )(ApiPatientEligibleTrial.apply, unlift(ApiPatientEligibleTrial.unapply)) def fromDomain(eligibleTrialWithTrial: RichPatientEligibleTrial) = ApiPatientEligibleTrial( id = eligibleTrialWithTrial.group.id.id, diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/patient/hypothesis/ApiPatientHypothesis.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/patient/hypothesis/ApiPatientHypothesis.scala index 1b0767d..374370e 100644 --- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/patient/hypothesis/ApiPatientHypothesis.scala +++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/patient/hypothesis/ApiPatientHypothesis.scala @@ -20,7 +20,7 @@ object ApiPatientHypothesis { (JsPath \ "hypothesisId").format[UUID] and (JsPath \ "matchedTrials").format[Long] and (JsPath \ "rationale").formatNullable[String] - ) (ApiPatientHypothesis.apply, unlift(ApiPatientHypothesis.unapply)) + )(ApiPatientHypothesis.apply, unlift(ApiPatientHypothesis.unapply)) def fromDomain(patientHypothesis: PatientHypothesis) = ApiPatientHypothesis( id = patientHypothesis.id.id, diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/patient/label/ApiPartialPatientLabel.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/patient/label/ApiPartialPatientLabel.scala index 82e3a3f..40f7de4 100644 --- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/patient/label/ApiPartialPatientLabel.scala +++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/patient/label/ApiPartialPatientLabel.scala @@ -8,13 +8,13 @@ import play.api.libs.functional.syntax._ import play.api.libs.json._ import xyz.driver.pdsuicommon.domain.FuzzyValue -final case class ApiPartialPatientLabel(primaryValue: Option[String], - verifiedPrimaryValue: Tristate[String]) { +final case class ApiPartialPatientLabel(primaryValue: Option[String], verifiedPrimaryValue: Tristate[String]) { def applyTo(orig: PatientLabel): PatientLabel = { orig.copy( primaryValue = primaryValue.map(FuzzyValue.fromString).orElse(orig.primaryValue), - verifiedPrimaryValue = verifiedPrimaryValue.cata(x => Some(FuzzyValue.fromString(x)), None, orig.verifiedPrimaryValue) + verifiedPrimaryValue = + verifiedPrimaryValue.cata(x => Some(FuzzyValue.fromString(x)), None, orig.verifiedPrimaryValue) ) } @@ -23,16 +23,24 @@ final case class ApiPartialPatientLabel(primaryValue: Option[String], object ApiPartialPatientLabel { implicit val format: Format[ApiPartialPatientLabel] = ( - (JsPath \ "primaryValue").formatNullable[String](Format( - Reads.of[String].filter(ValidationError("unknown primary value"))({ - case x if FuzzyValue.fromString.isDefinedAt(x) => true - case _ => false - }), Writes.of[String])) and - (JsPath \ "verifiedPrimaryValue").formatTristate[String](Format( - Reads.of[String].filter(ValidationError("unknown verified primary value"))({ - case x if FuzzyValue.fromString.isDefinedAt(x) => true - case _ => false - }), Writes.of[String])) - ) (ApiPartialPatientLabel.apply, unlift(ApiPartialPatientLabel.unapply)) + (JsPath \ "primaryValue").formatNullable[String]( + Format(Reads + .of[String] + .filter(ValidationError("unknown primary value"))({ + case x if FuzzyValue.fromString.isDefinedAt(x) => true + case _ => false + }), + Writes.of[String])) and + (JsPath \ "verifiedPrimaryValue").formatTristate[String]( + Format( + Reads + .of[String] + .filter(ValidationError("unknown verified primary value"))({ + case x if FuzzyValue.fromString.isDefinedAt(x) => true + case _ => false + }), + Writes.of[String] + )) + )(ApiPartialPatientLabel.apply, unlift(ApiPartialPatientLabel.unapply)) } diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/patient/label/ApiPatientLabelDefiningCriteria.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/patient/label/ApiPatientLabelDefiningCriteria.scala index 3fe135e..ae64c33 100644 --- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/patient/label/ApiPatientLabelDefiningCriteria.scala +++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/patient/label/ApiPatientLabelDefiningCriteria.scala @@ -12,11 +12,15 @@ object ApiPatientLabelDefiningCriteria { implicit val format: Format[ApiPatientLabelDefiningCriteria] = ( (JsPath \ "labelId").format[Long] and - (JsPath \ "value").formatNullable[String](Format(Reads.of[String].filter(ValidationError("unknown value"))({ - case x if FuzzyValue.fromString.isDefinedAt(x) => true - case _ => false - }), Writes.of[String])) - ) (ApiPatientLabelDefiningCriteria.apply, unlift(ApiPatientLabelDefiningCriteria.unapply)) + (JsPath \ "value").formatNullable[String]( + Format(Reads + .of[String] + .filter(ValidationError("unknown value"))({ + case x if FuzzyValue.fromString.isDefinedAt(x) => true + case _ => false + }), + Writes.of[String])) + )(ApiPatientLabelDefiningCriteria.apply, unlift(ApiPatientLabelDefiningCriteria.unapply)) def fromDomain(x: PatientLabel) = ApiPatientLabelDefiningCriteria( labelId = x.labelId.id, diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/patient/trial/ApiPartialPatientCriterion.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/patient/trial/ApiPartialPatientCriterion.scala index b68dad5..399bc7d 100644 --- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/patient/trial/ApiPartialPatientCriterion.scala +++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/patient/trial/ApiPartialPatientCriterion.scala @@ -9,16 +9,13 @@ import play.api.libs.json.{Format, JsPath, Reads, Writes} import xyz.driver.pdsuicommon.domain.FuzzyValue final case class ApiPartialPatientCriterion(eligibilityStatus: Option[String], - verifiedEligibilityStatus: Tristate[String]) { + verifiedEligibilityStatus: Tristate[String]) { def applyTo(orig: PatientCriterion): PatientCriterion = { orig.copy( eligibilityStatus = eligibilityStatus.map(FuzzyValue.fromString).orElse(orig.eligibilityStatus), - verifiedEligibilityStatus = verifiedEligibilityStatus.cata(x => - Some(FuzzyValue.fromString(x)), - None, - orig.verifiedEligibilityStatus - ) + verifiedEligibilityStatus = + verifiedEligibilityStatus.cata(x => Some(FuzzyValue.fromString(x)), None, orig.verifiedEligibilityStatus) ) } } @@ -26,15 +23,25 @@ final case class ApiPartialPatientCriterion(eligibilityStatus: Option[String], object ApiPartialPatientCriterion { implicit val format: Format[ApiPartialPatientCriterion] = ( - (JsPath \ "eligibilityStatus").formatNullable[String](Format( - Reads.of[String].filter(ValidationError("unknown eligibility status"))({ - case x if FuzzyValue.fromString.isDefinedAt(x) => true - case _ => false - }), Writes.of[String])) and - (JsPath \ "verifiedEligibilityStatus").formatTristate[String](Format( - Reads.of[String].filter(ValidationError("unknown verified eligibility status"))({ - case x if FuzzyValue.fromString.isDefinedAt(x) => true - case _ => false - }), Writes.of[String])) - ) (ApiPartialPatientCriterion.apply, unlift(ApiPartialPatientCriterion.unapply)) + (JsPath \ "eligibilityStatus").formatNullable[String]( + Format( + Reads + .of[String] + .filter(ValidationError("unknown eligibility status"))({ + case x if FuzzyValue.fromString.isDefinedAt(x) => true + case _ => false + }), + Writes.of[String] + )) and + (JsPath \ "verifiedEligibilityStatus").formatTristate[String]( + Format( + Reads + .of[String] + .filter(ValidationError("unknown verified eligibility status"))({ + case x if FuzzyValue.fromString.isDefinedAt(x) => true + case _ => false + }), + Writes.of[String] + )) + )(ApiPartialPatientCriterion.apply, unlift(ApiPartialPatientCriterion.unapply)) } diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/patient/trial/ApiPartialPatientCriterionList.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/patient/trial/ApiPartialPatientCriterionList.scala index 71cb58f..4b08970 100644 --- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/patient/trial/ApiPartialPatientCriterionList.scala +++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/patient/trial/ApiPartialPatientCriterionList.scala @@ -8,8 +8,8 @@ import play.api.libs.json.{Format, JsPath, Reads, Writes} import xyz.driver.pdsuidomain.services.PatientCriterionService.DraftPatientCriterion final case class ApiPartialPatientCriterionList(id: Long, - eligibilityStatus: Option[String], - isVerified: Option[Boolean]) { + eligibilityStatus: Option[String], + isVerified: Option[Boolean]) { def toDomain: DraftPatientCriterion = DraftPatientCriterion( id = LongId[PatientCriterion](id), @@ -23,10 +23,14 @@ object ApiPartialPatientCriterionList { implicit val format: Format[ApiPartialPatientCriterionList] = ( (JsPath \ "id").format[Long] and (JsPath \ "eligibilityStatus").formatNullable[String](Format( - Reads.of[String].filter(ValidationError("unknown eligibility status"))({ - case x if FuzzyValue.fromString.isDefinedAt(x) => true - case _ => false - }), Writes.of[String])) and + Reads + .of[String] + .filter(ValidationError("unknown eligibility status"))({ + case x if FuzzyValue.fromString.isDefinedAt(x) => true + case _ => false + }), + Writes.of[String] + )) and (JsPath \ "isVerified").formatNullable[Boolean] - ) (ApiPartialPatientCriterionList.apply, unlift(ApiPartialPatientCriterionList.unapply)) + )(ApiPartialPatientCriterionList.apply, unlift(ApiPartialPatientCriterionList.unapply)) } diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/record/ApiCreateRecord.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/record/ApiCreateRecord.scala index 57c030b..cee67b2 100644 --- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/record/ApiCreateRecord.scala +++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/record/ApiCreateRecord.scala @@ -7,10 +7,7 @@ import xyz.driver.pdsuicommon.domain._ import xyz.driver.pdsuidomain.entities._ import play.api.libs.json._ -final case class ApiCreateRecord(disease: String, - patientId: String, - requestId: UUID, - filename: String) { +final case class ApiCreateRecord(disease: String, patientId: String, requestId: UUID, filename: String) { def toDomain = MedicalRecord( id = LongId(0), diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/record/ApiRecord.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/record/ApiRecord.scala index 6096006..de54a9e 100644 --- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/record/ApiRecord.scala +++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/record/ApiRecord.scala @@ -24,7 +24,7 @@ object ApiRecord { private val statusFormat = Format( Reads.StringReads.filter(ValidationError("unknown status")) { case x if MedicalRecordStatus.statusFromString.isDefinedAt(x) => true - case _ => false + case _ => false }, Writes.StringWrites ) @@ -39,8 +39,10 @@ object ApiRecord { (JsPath \ "previousStatus").formatNullable(statusFormat) and (JsPath \ "assignee").formatNullable[Long] and (JsPath \ "previousAssignee").formatNullable[Long] and - (JsPath \ "meta").format(Format(Reads { x => JsSuccess(Json.stringify(x)) }, Writes[String](Json.parse))) - ) (ApiRecord.apply, unlift(ApiRecord.unapply)) + (JsPath \ "meta").format(Format(Reads { x => + JsSuccess(Json.stringify(x)) + }, Writes[String](Json.parse))) + )(ApiRecord.apply, unlift(ApiRecord.unapply)) def fromDomain(record: MedicalRecord) = ApiRecord( id = record.id.id, diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/record/ApiUpdateRecord.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/record/ApiUpdateRecord.scala index b752a4c..0d17b66 100644 --- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/record/ApiUpdateRecord.scala +++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/record/ApiUpdateRecord.scala @@ -10,9 +10,7 @@ import play.api.libs.functional.syntax._ import play.api.libs.json._ import xyz.driver.pdsuicommon.json.JsonSerializer -final case class ApiUpdateRecord(status: Option[String], - assignee: Tristate[Long], - meta: Tristate[String]) { +final case class ApiUpdateRecord(status: Option[String], assignee: Tristate[Long], meta: Tristate[String]) { def applyTo(orig: MedicalRecord): MedicalRecord = { orig.copy( @@ -26,22 +24,29 @@ final case class ApiUpdateRecord(status: Option[String], object ApiUpdateRecord { private val reads: Reads[ApiUpdateRecord] = ( - (JsPath \ "status").readNullable[String](Reads.of[String].filter(ValidationError("unknown status"))({ - case x if MedicalRecordStatus.statusFromString.isDefinedAt(x) => true - case _ => false - })) and + (JsPath \ "status").readNullable[String]( + Reads + .of[String] + .filter(ValidationError("unknown status"))({ + case x if MedicalRecordStatus.statusFromString.isDefinedAt(x) => true + case _ => false + })) and (JsPath \ "assignee").readTristate[Long] and - (JsPath \ "meta").readTristate(Reads { x => JsSuccess(Json.stringify(x)) }).map { - case Tristate.Present("{}") => Tristate.Absent - case x => x - } - ) (ApiUpdateRecord.apply _) + (JsPath \ "meta") + .readTristate(Reads { x => + JsSuccess(Json.stringify(x)) + }) + .map { + case Tristate.Present("{}") => Tristate.Absent + case x => x + } + )(ApiUpdateRecord.apply _) private val writes: Writes[ApiUpdateRecord] = ( (JsPath \ "status").writeNullable[String] and (JsPath \ "assignee").writeTristate[Long] and (JsPath \ "meta").writeTristate(Writes[String](Json.parse)) - ) (unlift(ApiUpdateRecord.unapply)) + )(unlift(ApiUpdateRecord.unapply)) implicit val format: Format[ApiUpdateRecord] = Format(reads, writes) } diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/record/MedicalRecordStatus.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/record/MedicalRecordStatus.scala index bde4af0..a77b76b 100644 --- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/record/MedicalRecordStatus.scala +++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/record/MedicalRecordStatus.scala @@ -5,30 +5,30 @@ import xyz.driver.pdsuidomain.entities.MedicalRecord.Status object MedicalRecordStatus { val statusFromString: PartialFunction[String, Status] = { - case "Unprocessed" => Status.Unprocessed - case "PreCleaning" => Status.PreCleaning - case "New" => Status.New - case "Cleaned" => Status.Cleaned - case "PreOrganized" => Status.PreOrganized + case "Unprocessed" => Status.Unprocessed + case "PreCleaning" => Status.PreCleaning + case "New" => Status.New + case "Cleaned" => Status.Cleaned + case "PreOrganized" => Status.PreOrganized case "PreOrganizing" => Status.PreOrganizing - case "Reviewed" => Status.Reviewed - case "Organized" => Status.Organized - case "Done" => Status.Done - case "Flagged" => Status.Flagged - case "Archived" => Status.Archived + case "Reviewed" => Status.Reviewed + case "Organized" => Status.Organized + case "Done" => Status.Done + case "Flagged" => Status.Flagged + case "Archived" => Status.Archived } def statusToString(x: Status): String = x match { - case Status.Unprocessed => "Unprocessed" - case Status.PreCleaning => "PreCleaning" - case Status.New => "New" - case Status.Cleaned => "Cleaned" - case Status.PreOrganized => "PreOrganized" + case Status.Unprocessed => "Unprocessed" + case Status.PreCleaning => "PreCleaning" + case Status.New => "New" + case Status.Cleaned => "Cleaned" + case Status.PreOrganized => "PreOrganized" case Status.PreOrganizing => "PreOrganizing" - case Status.Reviewed => "Reviewed" - case Status.Organized => "Organized" - case Status.Done => "Done" - case Status.Flagged => "Flagged" - case Status.Archived => "Archived" + case Status.Reviewed => "Reviewed" + case Status.Organized => "Organized" + case Status.Done => "Done" + case Status.Flagged => "Flagged" + case Status.Archived => "Archived" } } diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/studydesign/ApiStudyDesign.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/studydesign/ApiStudyDesign.scala index 958ff5d..26c7352 100644 --- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/studydesign/ApiStudyDesign.scala +++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/studydesign/ApiStudyDesign.scala @@ -11,7 +11,7 @@ object ApiStudyDesign { implicit val format: Format[ApiStudyDesign] = ( (JsPath \ "id").format[Long] and (JsPath \ "name").format[String] - ) (ApiStudyDesign.apply, unlift(ApiStudyDesign.unapply)) + )(ApiStudyDesign.apply, unlift(ApiStudyDesign.unapply)) def fromDomain(studyDesign: StudyDesign) = ApiStudyDesign( id = studyDesign.id.id, diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/trial/ApiPartialTrial.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/trial/ApiPartialTrial.scala index 0dc1446..f89f181 100644 --- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/trial/ApiPartialTrial.scala +++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/trial/ApiPartialTrial.scala @@ -31,14 +31,14 @@ object ApiPartialTrial { (JsPath \ "studyDesignId").readTristate[Long] and (JsPath \ "overview").readTristate[String] and (JsPath \ "title").readTristate[String] - ) (ApiPartialTrial.apply _) + )(ApiPartialTrial.apply _) private val writes: Writes[ApiPartialTrial] = ( (JsPath \ "hypothesisId").writeTristate[UUID] and (JsPath \ "studyDesignId").writeTristate[Long] and (JsPath \ "overview").writeTristate[String] and (JsPath \ "title").writeTristate[String] - ) (unlift(ApiPartialTrial.unapply)) + )(unlift(ApiPartialTrial.unapply)) implicit val format: Format[ApiPartialTrial] = Format(reads, writes) } diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/trial/ApiTrial.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/trial/ApiTrial.scala index 3267617..db980ee 100644 --- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/trial/ApiTrial.scala +++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/trial/ApiTrial.scala @@ -41,7 +41,7 @@ object ApiTrial { (JsPath \ "overviewTemplate").format[String] and (JsPath \ "isUpdated").format[Boolean] and (JsPath \ "title").format[String] - ) (ApiTrial.apply, unlift(ApiTrial.unapply)) + )(ApiTrial.apply, unlift(ApiTrial.unapply)) def fromDomain(trial: Trial): ApiTrial = ApiTrial( id = trial.id.id, diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/trial/TrialStatus.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/trial/TrialStatus.scala index 49bcbcb..a5b557b 100644 --- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/trial/TrialStatus.scala +++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/trial/TrialStatus.scala @@ -5,26 +5,26 @@ import xyz.driver.pdsuidomain.entities.Trial.Status object TrialStatus { val statusFromString: PartialFunction[String, Status] = { - case "New" => Status.New - case "ReviewSummary" => Status.ReviewSummary - case "Summarized" => Status.Summarized - case "PendingUpdate" => Status.PendingUpdate - case "Update" => Status.Update + case "New" => Status.New + case "ReviewSummary" => Status.ReviewSummary + case "Summarized" => Status.Summarized + case "PendingUpdate" => Status.PendingUpdate + case "Update" => Status.Update case "ReviewCriteria" => Status.ReviewCriteria - case "Done" => Status.Done - case "Flagged" => Status.Flagged - case "Archived" => Status.Archived + case "Done" => Status.Done + case "Flagged" => Status.Flagged + case "Archived" => Status.Archived } def statusToString(x: Status): String = x match { - case Status.New => "New" - case Status.ReviewSummary => "ReviewSummary" - case Status.Summarized => "Summarized" - case Status.PendingUpdate => "PendingUpdate" - case Status.Update => "Update" + case Status.New => "New" + case Status.ReviewSummary => "ReviewSummary" + case Status.Summarized => "Summarized" + case Status.PendingUpdate => "PendingUpdate" + case Status.Update => "Update" case Status.ReviewCriteria => "ReviewCriteria" - case Status.Done => "Done" - case Status.Flagged => "Flagged" - case Status.Archived => "Archived" + case Status.Done => "Done" + case Status.Flagged => "Flagged" + case Status.Archived => "Archived" } } diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/user/ApiPartialUser.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/user/ApiPartialUser.scala index 977934b..654508c 100644 --- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/user/ApiPartialUser.scala +++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/user/ApiPartialUser.scala @@ -14,9 +14,7 @@ import ApiPartialUser._ import xyz.driver.pdsuicommon.json.JsonValidationException import xyz.driver.pdsuicommon.validation.{AdditionalConstraints, JsonValidationErrors} -final case class ApiPartialUser(email: Option[String], - name: Option[String], - roleId: Option[String]) { +final case class ApiPartialUser(email: Option[String], name: Option[String], roleId: Option[String]) { def applyTo(orig: User): Try[User] = Try { val validation = Map( @@ -36,8 +34,8 @@ final case class ApiPartialUser(email: Option[String], def toDomain(id: LongId[User] = LongId(0L)): Try[User] = Try { val validation = Map( - JsPath \ "email" -> AdditionalConstraints.optionNonEmptyConstraint(email), - JsPath \ "name" -> AdditionalConstraints.optionNonEmptyConstraint(name), + JsPath \ "email" -> AdditionalConstraints.optionNonEmptyConstraint(email), + JsPath \ "name" -> AdditionalConstraints.optionNonEmptyConstraint(name), JsPath \ "roleId" -> AdditionalConstraints.optionNonEmptyConstraint(roleId) ) @@ -71,13 +69,19 @@ object ApiPartialUser { implicit val format: Format[ApiPartialUser] = ( (JsPath \ "email").formatNullable[String](Format(Reads.email, Writes.StringWrites)) and - (JsPath \ "name").formatNullable[String](Format( - Reads.filterNot[String](ValidationError("Username is too long (max length is 255 chars)", 255))(_.length > 255), - Writes.StringWrites - )) and - (JsPath \ "roleId").formatNullable[String](Format(Reads.of[String].filter(ValidationError("unknown role"))({ - case x if UserRole.roleFromString.isDefinedAt(x) => true - case _ => false - }), Writes.of[String])) - ) (ApiPartialUser.apply, unlift(ApiPartialUser.unapply)) + (JsPath \ "name").formatNullable[String]( + Format( + Reads.filterNot[String](ValidationError("Username is too long (max length is 255 chars)", 255))( + _.length > 255), + Writes.StringWrites + )) and + (JsPath \ "roleId").formatNullable[String]( + Format(Reads + .of[String] + .filter(ValidationError("unknown role"))({ + case x if UserRole.roleFromString.isDefinedAt(x) => true + case _ => false + }), + Writes.of[String])) + )(ApiPartialUser.apply, unlift(ApiPartialUser.unapply)) } diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/user/ApiUser.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/user/ApiUser.scala index c2653ec..29138ed 100644 --- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/user/ApiUser.scala +++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/user/ApiUser.scala @@ -15,12 +15,16 @@ object ApiUser { (JsPath \ "id").format[Long] and (JsPath \ "email").format[String](Reads.email) and (JsPath \ "name").format[String] and - (JsPath \ "roleId").format[String](Format(Reads.of[String].filter(ValidationError("unknown role"))({ - case x if UserRole.roleFromString.isDefinedAt(x) => true - case _ => false - }), Writes.of[String])) and + (JsPath \ "roleId").format[String]( + Format(Reads + .of[String] + .filter(ValidationError("unknown role"))({ + case x if UserRole.roleFromString.isDefinedAt(x) => true + case _ => false + }), + Writes.of[String])) and (JsPath \ "latestActivity").formatNullable[ZonedDateTime] - ) (ApiUser.apply, unlift(ApiUser.unapply)) + )(ApiUser.apply, unlift(ApiUser.unapply)) def fromDomain(user: User) = ApiUser( user.id.id, diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/user/UserRole.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/user/UserRole.scala index 74acb81..412a969 100644 --- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/user/UserRole.scala +++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/user/UserRole.scala @@ -5,29 +5,33 @@ import xyz.driver.pdsuicommon.domain.User.Role object UserRole { val roleFromString: PartialFunction[String, Role] = { - case "Cleaner" => Role.RecordCleaner - case "Organizer" => Role.RecordOrganizer - case "Extractor" => Role.DocumentExtractor - case "RecordAdmin" => Role.RecordAdmin - case "TrialSummarizer" => Role.TrialSummarizer - case "CriteriaCurator" => Role.CriteriaCurator - case "TrialAdmin" => Role.TrialAdmin - case "EligibilityVerifier" => Role.EligibilityVerifier + case "Cleaner" => Role.RecordCleaner + case "Organizer" => Role.RecordOrganizer + case "Extractor" => Role.DocumentExtractor + case "RecordAdmin" => Role.RecordAdmin + case "TrialSummarizer" => Role.TrialSummarizer + case "CriteriaCurator" => Role.CriteriaCurator + case "TrialAdmin" => Role.TrialAdmin + case "EligibilityVerifier" => Role.EligibilityVerifier case "TreatmentMatchingAdmin" => Role.TreatmentMatchingAdmin - case "RoutesCurator" => Role.RoutesCurator + case "RoutesCurator" => Role.RoutesCurator + case "SystemUser" => Role.SystemUser + case "ResearchOncologist" => Role.ResearchOncologist // No Mixed at this time } def roleToString(x: Role): String = x match { - case Role.RecordCleaner => "Cleaner" - case Role.RecordOrganizer => "Organizer" - case Role.DocumentExtractor => "Extractor" - case Role.RecordAdmin => "RecordAdmin" - case Role.TrialSummarizer => "TrialSummarizer" - case Role.CriteriaCurator => "CriteriaCurator" - case Role.TrialAdmin => "TrialAdmin" - case Role.EligibilityVerifier => "EligibilityVerifier" + case Role.RecordCleaner => "Cleaner" + case Role.RecordOrganizer => "Organizer" + case Role.DocumentExtractor => "Extractor" + case Role.RecordAdmin => "RecordAdmin" + case Role.TrialSummarizer => "TrialSummarizer" + case Role.CriteriaCurator => "CriteriaCurator" + case Role.TrialAdmin => "TrialAdmin" + case Role.EligibilityVerifier => "EligibilityVerifier" case Role.TreatmentMatchingAdmin => "TreatmentMatchingAdmin" - case Role.RoutesCurator => "RoutesCurator" + case Role.RoutesCurator => "RoutesCurator" + case Role.SystemUser => "SystemUser" + case Role.ResearchOncologist => "ResearchOncologist" } } diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/ArmService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/ArmService.scala index bc59f0c..43e46ed 100644 --- a/src/main/scala/xyz/driver/pdsuidomain/services/ArmService.scala +++ b/src/main/scala/xyz/driver/pdsuidomain/services/ArmService.scala @@ -1,6 +1,5 @@ package xyz.driver.pdsuidomain.services - import xyz.driver.pdsuicommon.auth.AuthenticatedRequestContext import xyz.driver.pdsuicommon.db._ import xyz.driver.pdsuicommon.domain.LongId @@ -27,14 +26,13 @@ object ArmService { type Error = GetByIdReply with DomainError - case object NotFoundError - extends GetByIdReply with DefaultNotFoundError with DomainError.NotFoundError + case object NotFoundError extends GetByIdReply with DefaultNotFoundError with DomainError.NotFoundError case object AuthorizationError - extends GetByIdReply with DomainError.AuthorizationError with DefaultAccessDeniedError + extends GetByIdReply with DomainError.AuthorizationError with DefaultAccessDeniedError case class CommonError(userMessage: String)(implicit requestContext: AuthenticatedRequestContext) - extends GetByIdReply with DomainError + extends GetByIdReply with DomainError } @@ -45,7 +43,7 @@ object ArmService { case class EntityList(xs: Seq[Arm], totalFound: Int) extends GetListReply case object AuthorizationError - extends GetListReply with DomainError.AuthorizationError with DefaultAccessDeniedError + extends GetListReply with DomainError.AuthorizationError with DefaultAccessDeniedError } @@ -56,14 +54,12 @@ object ArmService { type Error = UpdateReply with DomainError - case object NotFoundError - extends UpdateReply with DefaultNotFoundError with DomainError.NotFoundError + case object NotFoundError extends UpdateReply with DefaultNotFoundError with DomainError.NotFoundError case object AuthorizationError - extends UpdateReply with DefaultAccessDeniedError with DomainError.AuthorizationError + extends UpdateReply with DefaultAccessDeniedError with DomainError.AuthorizationError - case class CommonError(userMessage: String) - extends UpdateReply with DomainError + case class CommonError(userMessage: String) extends UpdateReply with DomainError case class AlreadyExistsError(x: Arm) extends UpdateReply with DomainError { val userMessage = s"The arm with such name of trial already exists." @@ -71,7 +67,7 @@ object ArmService { implicit def toPhiString(reply: UpdateReply): PhiString = reply match { case Updated(x) => phi"Updated($x)" - case x: Error => DomainError.toPhiString(x) + case x: Error => DomainError.toPhiString(x) } } @@ -82,10 +78,9 @@ object ArmService { type Error = CreateReply with DomainError case object AuthorizationError - extends CreateReply with DefaultAccessDeniedError with DomainError.AuthorizationError + extends CreateReply with DefaultAccessDeniedError with DomainError.AuthorizationError - case class CommonError(userMessage: String) - extends CreateReply with DomainError + case class CommonError(userMessage: String) extends CreateReply with DomainError case class AlreadyExistsError(x: Arm) extends CreateReply with DomainError { val userMessage = s"The arm with this name of trial already exists." @@ -93,7 +88,7 @@ object ArmService { implicit def toPhiString(reply: CreateReply): PhiString = reply match { case Created(x) => phi"Created($x)" - case x: Error => DomainError.toPhiString(x) + case x: Error => DomainError.toPhiString(x) } } @@ -103,14 +98,12 @@ object ArmService { type Error = DeleteReply with DomainError - case object NotFoundError - extends DeleteReply with DefaultNotFoundError with DomainError.NotFoundError + case object NotFoundError extends DeleteReply with DefaultNotFoundError with DomainError.NotFoundError case object AuthorizationError - extends DeleteReply with DefaultAccessDeniedError with DomainError.AuthorizationError + extends DeleteReply with DefaultAccessDeniedError with DomainError.AuthorizationError - case class CommonError(userMessage: String) - extends DeleteReply with DomainError + case class CommonError(userMessage: String) extends DeleteReply with DomainError } } @@ -120,8 +113,8 @@ trait ArmService { def getAll(filter: SearchFilterExpr = SearchFilterExpr.Empty, sorting: Option[Sorting] = None, - pagination: Option[Pagination] = None) - (implicit requestContext: AuthenticatedRequestContext): Future[GetListReply] + pagination: Option[Pagination] = None)( + implicit requestContext: AuthenticatedRequestContext): Future[GetListReply] def getById(armId: LongId[Arm])(implicit requestContext: AuthenticatedRequestContext): Future[GetByIdReply] diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/CriterionService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/CriterionService.scala index e3d806c..ffb7843 100644 --- a/src/main/scala/xyz/driver/pdsuidomain/services/CriterionService.scala +++ b/src/main/scala/xyz/driver/pdsuidomain/services/CriterionService.scala @@ -21,9 +21,7 @@ object CriterionService { def userMessage: String = "Access denied" } - case class RichCriterion(criterion: Criterion, - armIds: Seq[LongId[Arm]], - labels: Seq[CriterionLabel]) + case class RichCriterion(criterion: Criterion, armIds: Seq[LongId[Arm]], labels: Seq[CriterionLabel]) object RichCriterion { implicit def toPhiString(x: RichCriterion): PhiString = { import x._ @@ -38,7 +36,7 @@ object CriterionService { case class Created(x: RichCriterion) extends CreateReply case object AuthorizationError - extends CreateReply with DomainError.AuthorizationError with DefaultAccessDeniedError + extends CreateReply with DomainError.AuthorizationError with DefaultAccessDeniedError case class CommonError(userMessage: String) extends CreateReply with DomainError } @@ -49,29 +47,27 @@ object CriterionService { type Error = GetByIdReply with DomainError - case object NotFoundError - extends GetByIdReply with DefaultNotFoundError with DomainError.NotFoundError + case object NotFoundError extends GetByIdReply with DefaultNotFoundError with DomainError.NotFoundError case object AuthorizationError - extends GetByIdReply with DomainError.AuthorizationError with DefaultAccessDeniedError + extends GetByIdReply with DomainError.AuthorizationError with DefaultAccessDeniedError case class CommonError(userMessage: String)(implicit requestContext: AuthenticatedRequestContext) - extends GetByIdReply with DomainError + extends GetByIdReply with DomainError implicit def toPhiString(reply: GetByIdReply): PhiString = reply match { case x: DomainError => phi"GetByIdReply.Error($x)" - case Entity(x) => phi"GetByIdReply.Entity($x)" + case Entity(x) => phi"GetByIdReply.Entity($x)" } } sealed trait GetListReply object GetListReply { - case class EntityList(xs: Seq[RichCriterion], - totalFound: Int, - lastUpdate: Option[LocalDateTime]) extends GetListReply + case class EntityList(xs: Seq[RichCriterion], totalFound: Int, lastUpdate: Option[LocalDateTime]) + extends GetListReply case object AuthorizationError - extends GetListReply with DomainError.AuthorizationError with DefaultAccessDeniedError + extends GetListReply with DomainError.AuthorizationError with DefaultAccessDeniedError } sealed trait UpdateReply @@ -80,14 +76,12 @@ object CriterionService { case class Updated(updated: RichCriterion) extends UpdateReply - case object NotFoundError - extends UpdateReply with DefaultNotFoundError with DomainError.NotFoundError + case object NotFoundError extends UpdateReply with DefaultNotFoundError with DomainError.NotFoundError case object AuthorizationError - extends UpdateReply with DefaultAccessDeniedError with DomainError.AuthorizationError + extends UpdateReply with DefaultAccessDeniedError with DomainError.AuthorizationError - case class CommonError(userMessage: String) - extends UpdateReply with DomainError + case class CommonError(userMessage: String) extends UpdateReply with DomainError } sealed trait DeleteReply @@ -96,14 +90,12 @@ object CriterionService { type Error = DeleteReply with DomainError - case object NotFoundError - extends DeleteReply with DefaultNotFoundError with DomainError.NotFoundError + case object NotFoundError extends DeleteReply with DefaultNotFoundError with DomainError.NotFoundError case object AuthorizationError - extends DeleteReply with DefaultAccessDeniedError with DomainError.AuthorizationError + extends DeleteReply with DefaultAccessDeniedError with DomainError.AuthorizationError - case class CommonError(userMessage: String) - extends DeleteReply with DomainError + case class CommonError(userMessage: String) extends DeleteReply with DomainError } } @@ -111,21 +103,18 @@ trait CriterionService { import CriterionService._ - def create(draftRichCriterion: RichCriterion) - (implicit requestContext: AuthenticatedRequestContext): Future[CreateReply] + def create(draftRichCriterion: RichCriterion)( + implicit requestContext: AuthenticatedRequestContext): Future[CreateReply] - def getById(id: LongId[Criterion]) - (implicit requestContext: AuthenticatedRequestContext): Future[GetByIdReply] + def getById(id: LongId[Criterion])(implicit requestContext: AuthenticatedRequestContext): Future[GetByIdReply] def getAll(filter: SearchFilterExpr = SearchFilterExpr.Empty, sorting: Option[Sorting] = None, - pagination: Option[Pagination] = None) - (implicit requestContext: AuthenticatedRequestContext): Future[GetListReply] + pagination: Option[Pagination] = None)( + implicit requestContext: AuthenticatedRequestContext): Future[GetListReply] - def update(origRichCriterion: RichCriterion, - draftRichCriterion: RichCriterion) - (implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] + def update(origRichCriterion: RichCriterion, draftRichCriterion: RichCriterion)( + implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] - def delete(id: LongId[Criterion]) - (implicit requestContext: AuthenticatedRequestContext): Future[DeleteReply] + def delete(id: LongId[Criterion])(implicit requestContext: AuthenticatedRequestContext): Future[DeleteReply] } diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/DocumentService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/DocumentService.scala index cd242c9..ffa252c 100644 --- a/src/main/scala/xyz/driver/pdsuidomain/services/DocumentService.scala +++ b/src/main/scala/xyz/driver/pdsuidomain/services/DocumentService.scala @@ -27,31 +27,28 @@ object DocumentService { type Error = GetByIdReply with DomainError - case object NotFoundError - extends GetByIdReply with DefaultNotFoundError with DomainError.NotFoundError + case object NotFoundError extends GetByIdReply with DefaultNotFoundError with DomainError.NotFoundError case object AuthorizationError - extends GetByIdReply with DomainError.AuthorizationError with DefaultAccessDeniedError + extends GetByIdReply with DomainError.AuthorizationError with DefaultAccessDeniedError case class CommonError(userMessage: String)(implicit requestContext: AuthenticatedRequestContext) - extends GetByIdReply with DomainError + extends GetByIdReply with DomainError implicit def toPhiString(reply: GetByIdReply): PhiString = reply match { case x: DomainError => phi"GetByIdReply.Error($x)" - case Entity(x) => phi"GetByIdReply.Entity($x)" + case Entity(x) => phi"GetByIdReply.Entity($x)" } } sealed trait GetListReply object GetListReply { - case class EntityList(xs: Seq[Document], - totalFound: Int, - lastUpdate: Option[LocalDateTime]) extends GetListReply + case class EntityList(xs: Seq[Document], totalFound: Int, lastUpdate: Option[LocalDateTime]) extends GetListReply type Error = GetListReply with DomainError case object AuthorizationError - extends GetListReply with DefaultAccessDeniedError with DomainError.AuthorizationError + extends GetListReply with DefaultAccessDeniedError with DomainError.AuthorizationError case class CommonError(userMessage: String) extends GetListReply with DomainError } @@ -62,14 +59,12 @@ object DocumentService { type Error = CreateReply with DomainError - case object NotFoundError - extends CreateReply with DefaultNotFoundError with DomainError.NotFoundError + case object NotFoundError extends CreateReply with DefaultNotFoundError with DomainError.NotFoundError case object AuthorizationError - extends CreateReply with DefaultAccessDeniedError with DomainError.AuthorizationError + extends CreateReply with DefaultAccessDeniedError with DomainError.AuthorizationError - case class CommonError(userMessage: String) - extends CreateReply with DomainError + case class CommonError(userMessage: String) extends CreateReply with DomainError } sealed trait UpdateReply @@ -78,36 +73,31 @@ object DocumentService { type Error = UpdateReply with DomainError - case object NotFoundError - extends UpdateReply with DefaultNotFoundError with DomainError.NotFoundError + case object NotFoundError extends UpdateReply with DefaultNotFoundError with DomainError.NotFoundError case object AuthorizationError - extends UpdateReply with DefaultAccessDeniedError with DomainError.AuthorizationError + extends UpdateReply with DefaultAccessDeniedError with DomainError.AuthorizationError - case class CommonError(userMessage: String) - extends UpdateReply with DomainError + case class CommonError(userMessage: String) extends UpdateReply with DomainError implicit def toPhiString(reply: UpdateReply): PhiString = reply match { case Updated(x) => phi"Updated($x)" - case x: Error => DomainError.toPhiString(x) + case x: Error => DomainError.toPhiString(x) } } - sealed trait DeleteReply object DeleteReply { case object Deleted extends DeleteReply type Error = DeleteReply with DomainError - case object NotFoundError - extends DeleteReply with DefaultNotFoundError with DomainError.NotFoundError + case object NotFoundError extends DeleteReply with DefaultNotFoundError with DomainError.NotFoundError case object AuthorizationError - extends DeleteReply with DefaultAccessDeniedError with DomainError.AuthorizationError + extends DeleteReply with DefaultAccessDeniedError with DomainError.AuthorizationError - case class CommonError(userMessage: String) - extends DeleteReply with DomainError + case class CommonError(userMessage: String) extends DeleteReply with DomainError } } @@ -116,42 +106,32 @@ trait DocumentService { import DocumentService._ - - def getById(id: LongId[Document]) - (implicit requestContext: AuthenticatedRequestContext): Future[GetByIdReply] + def getById(id: LongId[Document])(implicit requestContext: AuthenticatedRequestContext): Future[GetByIdReply] def getAll(filter: SearchFilterExpr = SearchFilterExpr.Empty, sorting: Option[Sorting] = None, - pagination: Option[Pagination] = None) - (implicit requestContext: AuthenticatedRequestContext): Future[GetListReply] + pagination: Option[Pagination] = None)( + implicit requestContext: AuthenticatedRequestContext): Future[GetListReply] def create(draftDocument: Document)(implicit requestContext: AuthenticatedRequestContext): Future[CreateReply] // Update operations are validated in internal.*Command - def update(orig: Document, draft: Document) - (implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] + def update(orig: Document, draft: Document)( + implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] - def delete(id: LongId[Document]) - (implicit requestContext: AuthenticatedRequestContext): Future[DeleteReply] + def delete(id: LongId[Document])(implicit requestContext: AuthenticatedRequestContext): Future[DeleteReply] - def start(orig: Document) - (implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] + def start(orig: Document)(implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] - def submit(orig: Document) - (implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] + def submit(orig: Document)(implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] - def restart(orig: Document) - (implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] + def restart(orig: Document)(implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] - def flag(orig: Document) - (implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] + def flag(orig: Document)(implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] - def resolve(orig: Document) - (implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] + def resolve(orig: Document)(implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] - def unassign(orig: Document) - (implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] + def unassign(orig: Document)(implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] - def archive(orig: Document) - (implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] + def archive(orig: Document)(implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] } diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/DocumentTypeService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/DocumentTypeService.scala index 30fd348..1268cbf 100644 --- a/src/main/scala/xyz/driver/pdsuidomain/services/DocumentTypeService.scala +++ b/src/main/scala/xyz/driver/pdsuidomain/services/DocumentTypeService.scala @@ -12,8 +12,7 @@ object DocumentTypeService { sealed trait GetListReply object GetListReply { case class EntityList(xs: Seq[DocumentType], totalFound: Int) extends GetListReply - case object AuthorizationError - extends GetListReply with DomainError.AuthorizationError { + case object AuthorizationError extends GetListReply with DomainError.AuthorizationError { def userMessage: String = "Access denied" } } @@ -21,6 +20,6 @@ object DocumentTypeService { trait DocumentTypeService { - def getAll(sorting: Option[Sorting] = None) - (implicit requestContext: AuthenticatedRequestContext): Future[GetListReply] + def getAll(sorting: Option[Sorting] = None)( + implicit requestContext: AuthenticatedRequestContext): Future[GetListReply] } diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/ExtractedDataService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/ExtractedDataService.scala index 6cde411..93cb3ea 100644 --- a/src/main/scala/xyz/driver/pdsuidomain/services/ExtractedDataService.scala +++ b/src/main/scala/xyz/driver/pdsuidomain/services/ExtractedDataService.scala @@ -19,8 +19,7 @@ object ExtractedDataService { def userMessage: String = "Access denied" } - case class RichExtractedData(extractedData: ExtractedData, - labels: List[ExtractedDataLabel]) + case class RichExtractedData(extractedData: ExtractedData, labels: List[ExtractedDataLabel]) object RichExtractedData { implicit def toPhiString(x: RichExtractedData): PhiString = { @@ -35,10 +34,9 @@ object ExtractedDataService { case class Entity(x: RichExtractedData) extends GetByIdReply case object AuthorizationError - extends GetByIdReply with DomainError.AuthorizationError with DefaultAccessDeniedError + extends GetByIdReply with DomainError.AuthorizationError with DefaultAccessDeniedError - case object NotFoundError - extends GetByIdReply with DefaultNotFoundError with DomainError.NotFoundError + case object NotFoundError extends GetByIdReply with DefaultNotFoundError with DomainError.NotFoundError case class CommonError(userMessage: String) extends GetByIdReply with DomainError } @@ -48,7 +46,7 @@ object ExtractedDataService { case class EntityList(xs: Seq[RichExtractedData], totalFound: Int) extends GetListReply case object AuthorizationError - extends GetListReply with DomainError.AuthorizationError with DefaultAccessDeniedError + extends GetListReply with DomainError.AuthorizationError with DefaultAccessDeniedError } sealed trait CreateReply @@ -57,7 +55,7 @@ object ExtractedDataService { case class Created(x: RichExtractedData) extends CreateReply case object AuthorizationError - extends CreateReply with DomainError.AuthorizationError with DefaultAccessDeniedError + extends CreateReply with DomainError.AuthorizationError with DefaultAccessDeniedError case class CommonError(userMessage: String) extends CreateReply with DomainError } @@ -68,13 +66,11 @@ object ExtractedDataService { case class Updated(updated: RichExtractedData) extends UpdateReply case object AuthorizationError - extends UpdateReply with DefaultAccessDeniedError with DomainError.AuthorizationError + extends UpdateReply with DefaultAccessDeniedError with DomainError.AuthorizationError - case object NotFoundError - extends UpdateReply with DefaultNotFoundError with DomainError.NotFoundError + case object NotFoundError extends UpdateReply with DefaultNotFoundError with DomainError.NotFoundError - case class CommonError(userMessage: String) - extends UpdateReply with DomainError + case class CommonError(userMessage: String) extends UpdateReply with DomainError } sealed trait DeleteReply @@ -83,10 +79,9 @@ object ExtractedDataService { case object Deleted extends DeleteReply case object AuthorizationError - extends DeleteReply with DefaultAccessDeniedError with DomainError.AuthorizationError + extends DeleteReply with DefaultAccessDeniedError with DomainError.AuthorizationError - case object NotFoundError - extends DeleteReply with DefaultNotFoundError with DomainError.NotFoundError + case object NotFoundError extends DeleteReply with DefaultNotFoundError with DomainError.NotFoundError case class CommonError(userMessage: String) extends DeleteReply with DomainError } @@ -96,21 +91,18 @@ trait ExtractedDataService { import ExtractedDataService._ - def getById(id: LongId[ExtractedData]) - (implicit requestContext: AuthenticatedRequestContext): Future[GetByIdReply] + def getById(id: LongId[ExtractedData])(implicit requestContext: AuthenticatedRequestContext): Future[GetByIdReply] def getAll(filter: SearchFilterExpr = SearchFilterExpr.Empty, sorting: Option[Sorting] = None, - pagination: Option[Pagination] = None) - (implicit requestContext: AuthenticatedRequestContext): Future[GetListReply] + pagination: Option[Pagination] = None)( + implicit requestContext: AuthenticatedRequestContext): Future[GetListReply] - def create(draftRichExtractedData: RichExtractedData) - (implicit requestContext: AuthenticatedRequestContext): Future[CreateReply] + def create(draftRichExtractedData: RichExtractedData)( + implicit requestContext: AuthenticatedRequestContext): Future[CreateReply] - def update(origRichExtractedData: RichExtractedData, - draftRichExtractedData: RichExtractedData) - (implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] + def update(origRichExtractedData: RichExtractedData, draftRichExtractedData: RichExtractedData)( + implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] - def delete(id: LongId[ExtractedData]) - (implicit requestContext: AuthenticatedRequestContext): Future[DeleteReply] + def delete(id: LongId[ExtractedData])(implicit requestContext: AuthenticatedRequestContext): Future[DeleteReply] } diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/HypothesisService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/HypothesisService.scala index 64ce3ea..7fccf7f 100644 --- a/src/main/scala/xyz/driver/pdsuidomain/services/HypothesisService.scala +++ b/src/main/scala/xyz/driver/pdsuidomain/services/HypothesisService.scala @@ -12,8 +12,7 @@ object HypothesisService { object GetListReply { case class EntityList(xs: Seq[Hypothesis], totalFound: Int) extends GetListReply - case object AuthorizationError - extends GetListReply with DomainError.AuthorizationError { + case object AuthorizationError extends GetListReply with DomainError.AuthorizationError { def userMessage: String = "Access denied" } } @@ -23,6 +22,6 @@ trait HypothesisService { import HypothesisService._ - def getAll(sorting: Option[Sorting] = None) - (implicit requestContext: AuthenticatedRequestContext): Future[GetListReply] + def getAll(sorting: Option[Sorting] = None)( + implicit requestContext: AuthenticatedRequestContext): Future[GetListReply] } diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/InterventionService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/InterventionService.scala index d65c9f9..a4b380f 100644 --- a/src/main/scala/xyz/driver/pdsuidomain/services/InterventionService.scala +++ b/src/main/scala/xyz/driver/pdsuidomain/services/InterventionService.scala @@ -21,11 +21,10 @@ object InterventionService { sealed trait GetListReply object GetListReply { - case class EntityList(xs: Seq[InterventionWithArms], totalFound: Int) - extends GetListReply + case class EntityList(xs: Seq[InterventionWithArms], totalFound: Int) extends GetListReply case object AuthorizationError - extends GetListReply with DomainError.AuthorizationError with DefaultAccessDeniedError + extends GetListReply with DomainError.AuthorizationError with DefaultAccessDeniedError } sealed trait GetByIdReply @@ -34,18 +33,17 @@ object InterventionService { type Error = GetByIdReply with DomainError - case object NotFoundError - extends GetByIdReply with DefaultNotFoundError with DomainError.NotFoundError + case object NotFoundError extends GetByIdReply with DefaultNotFoundError with DomainError.NotFoundError case object AuthorizationError - extends GetByIdReply with DomainError.AuthorizationError with DefaultAccessDeniedError + extends GetByIdReply with DomainError.AuthorizationError with DefaultAccessDeniedError case class CommonError(userMessage: String)(implicit requestContext: AuthenticatedRequestContext) - extends GetByIdReply with DomainError + extends GetByIdReply with DomainError implicit def toPhiString(reply: GetByIdReply): PhiString = reply match { case x: DomainError => phi"GetByIdReply.Error($x)" - case Entity(x) => phi"GetByIdReply.Entity($x)" + case Entity(x) => phi"GetByIdReply.Entity($x)" } } @@ -55,14 +53,12 @@ object InterventionService { case class Updated(updated: InterventionWithArms) extends UpdateReply - case object NotFoundError - extends UpdateReply with DefaultNotFoundError with DomainError.NotFoundError + case object NotFoundError extends UpdateReply with DefaultNotFoundError with DomainError.NotFoundError case object AuthorizationError - extends UpdateReply with DefaultAccessDeniedError with DomainError.AuthorizationError + extends UpdateReply with DefaultAccessDeniedError with DomainError.AuthorizationError - case class CommonError(userMessage: String) - extends UpdateReply with DomainError + case class CommonError(userMessage: String) extends UpdateReply with DomainError } } @@ -73,13 +69,11 @@ trait InterventionService { def getAll(filter: SearchFilterExpr = SearchFilterExpr.Empty, sorting: Option[Sorting] = None, - pagination: Option[Pagination] = None) - (implicit requestContext: AuthenticatedRequestContext): Future[GetListReply] + pagination: Option[Pagination] = None)( + implicit requestContext: AuthenticatedRequestContext): Future[GetListReply] - def getById(id: LongId[Intervention]) - (implicit requestContext: AuthenticatedRequestContext): Future[GetByIdReply] + def getById(id: LongId[Intervention])(implicit requestContext: AuthenticatedRequestContext): Future[GetByIdReply] - def update(origIntervention: InterventionWithArms, - draftIntervention: InterventionWithArms) - (implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] + def update(origIntervention: InterventionWithArms, draftIntervention: InterventionWithArms)( + implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] } diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/InterventionTypeService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/InterventionTypeService.scala index db7473e..5805655 100644 --- a/src/main/scala/xyz/driver/pdsuidomain/services/InterventionTypeService.scala +++ b/src/main/scala/xyz/driver/pdsuidomain/services/InterventionTypeService.scala @@ -12,8 +12,7 @@ object InterventionTypeService { object GetListReply { case class EntityList(xs: Seq[InterventionType], totalFound: Int) extends GetListReply - case object AuthorizationError - extends GetListReply with DomainError.AuthorizationError { + case object AuthorizationError extends GetListReply with DomainError.AuthorizationError { def userMessage: String = "Access denied" } } @@ -23,6 +22,6 @@ trait InterventionTypeService { import InterventionTypeService._ - def getAll(sorting: Option[Sorting] = None) - (implicit requestContext: AuthenticatedRequestContext): Future[GetListReply] + def getAll(sorting: Option[Sorting] = None)( + implicit requestContext: AuthenticatedRequestContext): Future[GetListReply] } diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/KeywordService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/KeywordService.scala index 5ee69a2..8824c41 100644 --- a/src/main/scala/xyz/driver/pdsuidomain/services/KeywordService.scala +++ b/src/main/scala/xyz/driver/pdsuidomain/services/KeywordService.scala @@ -13,8 +13,7 @@ object KeywordService { object GetListReply { case class EntityList(xs: Seq[KeywordWithLabels], totalFound: Int) extends GetListReply - case object AuthorizationError - extends GetListReply with DomainError.AuthorizationError { + case object AuthorizationError extends GetListReply with DomainError.AuthorizationError { def userMessage: String = "Access denied" } } @@ -24,6 +23,6 @@ trait KeywordService { import KeywordService._ - def getAll(sorting: Option[Sorting] = None) - (implicit requestContext: AuthenticatedRequestContext): Future[GetListReply] + def getAll(sorting: Option[Sorting] = None)( + implicit requestContext: AuthenticatedRequestContext): Future[GetListReply] } diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/MedicalRecordService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/MedicalRecordService.scala index 7b5aa66..f077d82 100644 --- a/src/main/scala/xyz/driver/pdsuidomain/services/MedicalRecordService.scala +++ b/src/main/scala/xyz/driver/pdsuidomain/services/MedicalRecordService.scala @@ -29,14 +29,12 @@ object MedicalRecordService { type Error = GetByIdReply with DomainError - case object NotFoundError extends GetByIdReply - with DomainError.NotFoundError with DefaultNotFoundError + case object NotFoundError extends GetByIdReply with DomainError.NotFoundError with DefaultNotFoundError - case class CommonError(userMessage: String) extends GetByIdReply - with DomainError + case class CommonError(userMessage: String) extends GetByIdReply with DomainError - case object AuthorizationError extends GetByIdReply - with DomainError.AuthorizationError with DefaultAccessDeniedError + case object AuthorizationError + extends GetByIdReply with DomainError.AuthorizationError with DefaultAccessDeniedError } sealed trait GetPdfSourceReply @@ -46,27 +44,24 @@ object MedicalRecordService { case class Entity(x: PdfSource.Channel) extends GetPdfSourceReply case object AuthorizationError - extends GetPdfSourceReply with DomainError.AuthorizationError with DefaultAccessDeniedError + extends GetPdfSourceReply with DomainError.AuthorizationError with DefaultAccessDeniedError - case object NotFoundError - extends GetPdfSourceReply with DomainError.NotFoundError { + case object NotFoundError extends GetPdfSourceReply with DomainError.NotFoundError { def userMessage: String = "Medical record PDF hasn't been found" } - case object RecordNotFoundError - extends GetPdfSourceReply with DomainError.NotFoundError with DefaultNotFoundError + case object RecordNotFoundError extends GetPdfSourceReply with DomainError.NotFoundError with DefaultNotFoundError - case class CommonError(userMessage: String) - extends GetPdfSourceReply with DomainError + case class CommonError(userMessage: String) extends GetPdfSourceReply with DomainError } sealed trait GetListReply object GetListReply { case class EntityList(xs: Seq[MedicalRecord], totalFound: Int, lastUpdate: Option[LocalDateTime]) - extends GetListReply + extends GetListReply case object AuthorizationError - extends GetListReply with DomainError.AuthorizationError with DefaultAccessDeniedError + extends GetListReply with DomainError.AuthorizationError with DefaultAccessDeniedError } sealed trait CreateReply @@ -80,14 +75,12 @@ object MedicalRecordService { case class Updated(updated: MedicalRecord) extends UpdateReply - case object NotFoundError - extends UpdateReply with DefaultNotFoundError with DomainError.NotFoundError + case object NotFoundError extends UpdateReply with DefaultNotFoundError with DomainError.NotFoundError case object AuthorizationError - extends UpdateReply with DefaultAccessDeniedError with DomainError.AuthorizationError + extends UpdateReply with DefaultAccessDeniedError with DomainError.AuthorizationError - case class CommonError(userMessage: String) - extends UpdateReply with DomainError + case class CommonError(userMessage: String) extends UpdateReply with DomainError } case class Settings(pdfSourceBucket: String) @@ -97,41 +90,33 @@ trait MedicalRecordService { import MedicalRecordService._ - def getById(recordId: LongId[MedicalRecord]) - (implicit requestContext: AuthenticatedRequestContext): Future[GetByIdReply] + def getById(recordId: LongId[MedicalRecord])( + implicit requestContext: AuthenticatedRequestContext): Future[GetByIdReply] - def getPdfSource(recordId: LongId[MedicalRecord]) - (implicit requestContext: AuthenticatedRequestContext): Future[GetPdfSourceReply] + def getPdfSource(recordId: LongId[MedicalRecord])( + implicit requestContext: AuthenticatedRequestContext): Future[GetPdfSourceReply] def getAll(filter: SearchFilterExpr = SearchFilterExpr.Empty, sorting: Option[Sorting] = None, - pagination: Option[Pagination] = None) - (implicit requestContext: AuthenticatedRequestContext): Future[GetListReply] + pagination: Option[Pagination] = None)( + implicit requestContext: AuthenticatedRequestContext): Future[GetListReply] def create(draft: MedicalRecord): Future[CreateReply] - def update(origRecord: MedicalRecord, - draftRecord: MedicalRecord) - (implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] + def update(origRecord: MedicalRecord, draftRecord: MedicalRecord)( + implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] - def start(orig: MedicalRecord) - (implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] + def start(orig: MedicalRecord)(implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] - def submit(orig: MedicalRecord) - (implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] + def submit(orig: MedicalRecord)(implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] - def restart(orig: MedicalRecord) - (implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] + def restart(orig: MedicalRecord)(implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] - def flag(orig: MedicalRecord) - (implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] + def flag(orig: MedicalRecord)(implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] - def resolve(orig: MedicalRecord) - (implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] + def resolve(orig: MedicalRecord)(implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] - def unassign(orig: MedicalRecord) - (implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] + def unassign(orig: MedicalRecord)(implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] - def archive(orig: MedicalRecord) - (implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] + def archive(orig: MedicalRecord)(implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] } diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/PatientCriterionService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/PatientCriterionService.scala index ff95ed0..593e2ce 100644 --- a/src/main/scala/xyz/driver/pdsuidomain/services/PatientCriterionService.scala +++ b/src/main/scala/xyz/driver/pdsuidomain/services/PatientCriterionService.scala @@ -42,16 +42,16 @@ object PatientCriterionService { case class EntityList(xs: Seq[(PatientCriterion, LongId[Label], List[Arm], Boolean)], totalFound: Int, - lastUpdate: Option[LocalDateTime]) extends GetListReply + lastUpdate: Option[LocalDateTime]) + extends GetListReply case object AuthorizationError - extends GetListReply with DomainError.AuthorizationError with DefaultAccessDeniedError + extends GetListReply with DomainError.AuthorizationError with DefaultAccessDeniedError case object PatientNotFoundError - extends GetListReply with DomainError.NotFoundError with DefaultPatientNotFoundError + extends GetListReply with DomainError.NotFoundError with DefaultPatientNotFoundError - case class CommonError(userMessage: String) - extends GetListReply with DomainError + case class CommonError(userMessage: String) extends GetListReply with DomainError } @@ -59,22 +59,18 @@ object PatientCriterionService { object GetByIdReply { type Error = GetByIdReply with DomainError - case class Entity(x: PatientCriterion, - labelId: LongId[Label], - armList: List[Arm], - criterionIsCompound: Boolean) extends GetByIdReply + case class Entity(x: PatientCriterion, labelId: LongId[Label], armList: List[Arm], criterionIsCompound: Boolean) + extends GetByIdReply case object AuthorizationError - extends GetByIdReply with DomainError.AuthorizationError with DefaultAccessDeniedError + extends GetByIdReply with DomainError.AuthorizationError with DefaultAccessDeniedError - case object NotFoundError - extends GetByIdReply with DomainError.NotFoundError with DefaultNotFoundError + case object NotFoundError extends GetByIdReply with DomainError.NotFoundError with DefaultNotFoundError case object PatientNotFoundError - extends GetByIdReply with DomainError.NotFoundError with DefaultPatientNotFoundError + extends GetByIdReply with DomainError.NotFoundError with DefaultPatientNotFoundError - case class CommonError(userMessage: String) - extends GetByIdReply with DomainError + case class CommonError(userMessage: String) extends GetByIdReply with DomainError implicit def toPhiString(reply: GetByIdReply): PhiString = reply match { case x: DomainError => phi"GetByIdReply.Error($x)" @@ -91,13 +87,12 @@ object PatientCriterionService { case object Updated extends UpdateReply case object AuthorizationError - extends UpdateReply with DomainError.AuthorizationError with DefaultAccessDeniedError + extends UpdateReply with DomainError.AuthorizationError with DefaultAccessDeniedError case object PatientNotFoundError - extends UpdateReply with DomainError.NotFoundError with DefaultPatientNotFoundError + extends UpdateReply with DomainError.NotFoundError with DefaultPatientNotFoundError - case class CommonError(userMessage: String) - extends UpdateReply with DomainError + case class CommonError(userMessage: String) extends UpdateReply with DomainError } } @@ -108,19 +103,15 @@ trait PatientCriterionService { def getAll(patientId: UuidId[Patient], filter: SearchFilterExpr = SearchFilterExpr.Empty, sorting: Option[Sorting] = None, - pagination: Option[Pagination] = None) - (implicit requestContext: AuthenticatedRequestContext): Future[GetListReply] + pagination: Option[Pagination] = None)( + implicit requestContext: AuthenticatedRequestContext): Future[GetListReply] - def getById(patientId: UuidId[Patient], - id: LongId[PatientCriterion]) - (implicit requestContext: AuthenticatedRequestContext): Future[GetByIdReply] + def getById(patientId: UuidId[Patient], id: LongId[PatientCriterion])( + implicit requestContext: AuthenticatedRequestContext): Future[GetByIdReply] - def updateList(patientId: UuidId[Patient], - draftEntities: List[DraftPatientCriterion]) - (implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] + def updateList(patientId: UuidId[Patient], draftEntities: List[DraftPatientCriterion])( + implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] - def update(origEntity: PatientCriterion, - draftEntity: PatientCriterion, - patientId: UuidId[Patient]) - (implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] + def update(origEntity: PatientCriterion, draftEntity: PatientCriterion, patientId: UuidId[Patient])( + implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] } diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/PatientEligibleTrialService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/PatientEligibleTrialService.scala index 64b4b81..d322fdd 100644 --- a/src/main/scala/xyz/driver/pdsuidomain/services/PatientEligibleTrialService.scala +++ b/src/main/scala/xyz/driver/pdsuidomain/services/PatientEligibleTrialService.scala @@ -23,9 +23,7 @@ object PatientEligibleTrialService { def userMessage: String = "Access denied" } - case class RichPatientEligibleTrial(trial: Trial, - group: PatientTrialArmGroupView, - arms: List[Arm]) + case class RichPatientEligibleTrial(trial: Trial, group: PatientTrialArmGroupView, arms: List[Arm]) object RichPatientEligibleTrial { implicit def toPhiString(x: RichPatientEligibleTrial): PhiString = { phi"RichPatientEligibleTrial(group=${x.group}, trial=${x.trial}, arms=${x.arms})" @@ -34,14 +32,13 @@ object PatientEligibleTrialService { sealed trait GetListReply object GetListReply { - case class EntityList(xs: Seq[RichPatientEligibleTrial], totalFound: Int) - extends GetListReply + case class EntityList(xs: Seq[RichPatientEligibleTrial], totalFound: Int) extends GetListReply case object AuthorizationError - extends GetListReply with DomainError.AuthorizationError with DefaultAccessDeniedError + extends GetListReply with DomainError.AuthorizationError with DefaultAccessDeniedError case object PatientNotFoundError - extends GetListReply with DefaultPatientNotFoundError with DomainError.NotFoundError + extends GetListReply with DefaultPatientNotFoundError with DomainError.NotFoundError case class CommonError(userMessage: String) extends GetListReply with DomainError } @@ -52,38 +49,37 @@ object PatientEligibleTrialService { type Error = GetByIdReply with DomainError - case object NotFoundError - extends GetByIdReply with DefaultNotFoundError with DomainError.NotFoundError + case object NotFoundError extends GetByIdReply with DefaultNotFoundError with DomainError.NotFoundError case object PatientNotFoundError - extends GetByIdReply with DefaultPatientNotFoundError with DomainError.NotFoundError + extends GetByIdReply with DefaultPatientNotFoundError with DomainError.NotFoundError case object AuthorizationError - extends GetByIdReply with DomainError.AuthorizationError with DefaultAccessDeniedError + extends GetByIdReply with DomainError.AuthorizationError with DefaultAccessDeniedError case class CommonError(userMessage: String) extends GetByIdReply with DomainError implicit def toPhiString(reply: GetByIdReply): PhiString = reply match { case x: DomainError => phi"GetByIdReply.Error($x)" - case Entity(x) => phi"GetByIdReply.Entity($x)" + case Entity(x) => phi"GetByIdReply.Entity($x)" } } sealed trait GetCriterionListOfGroupReply object GetCriterionListOfGroupReply { case class EntityList(xs: Seq[(PatientCriterion, LongId[Label], List[Arm], Boolean)], totalFound: Int) - extends GetCriterionListOfGroupReply + extends GetCriterionListOfGroupReply type Error = GetCriterionListOfGroupReply with DomainError case object AuthorizationError - extends GetCriterionListOfGroupReply with DomainError.AuthorizationError with DefaultAccessDeniedError + extends GetCriterionListOfGroupReply with DomainError.AuthorizationError with DefaultAccessDeniedError case object NotFoundError - extends GetCriterionListOfGroupReply with DefaultNotFoundError with DomainError.NotFoundError + extends GetCriterionListOfGroupReply with DefaultNotFoundError with DomainError.NotFoundError case object PatientNotFoundError - extends GetCriterionListOfGroupReply with DefaultPatientNotFoundError with DomainError.NotFoundError + extends GetCriterionListOfGroupReply with DefaultPatientNotFoundError with DomainError.NotFoundError case class CommonError(userMessage: String) extends GetCriterionListOfGroupReply with DomainError } @@ -94,21 +90,19 @@ object PatientEligibleTrialService { case class Updated(updated: RichPatientEligibleTrial) extends UpdateReply - case object NotFoundError - extends UpdateReply with DefaultNotFoundError with DomainError.NotFoundError + case object NotFoundError extends UpdateReply with DefaultNotFoundError with DomainError.NotFoundError case object PatientNotFoundError - extends UpdateReply with DefaultPatientNotFoundError with DomainError.NotFoundError + extends UpdateReply with DefaultPatientNotFoundError with DomainError.NotFoundError case object AuthorizationError - extends UpdateReply with DomainError.AuthorizationError with DefaultAccessDeniedError + extends UpdateReply with DomainError.AuthorizationError with DefaultAccessDeniedError - case class CommonError(userMessage: String) - extends UpdateReply with DomainError + case class CommonError(userMessage: String) extends UpdateReply with DomainError implicit def toPhiString(reply: UpdateReply): PhiString = reply match { case Updated(x) => phi"Updated($x)" - case x: Error => DomainError.toPhiString(x) + case x: Error => DomainError.toPhiString(x) } } } @@ -120,18 +114,16 @@ trait PatientEligibleTrialService { def getAll(patientId: UuidId[Patient], filter: SearchFilterExpr = SearchFilterExpr.Empty, sorting: Option[Sorting] = None, - pagination: Option[Pagination] = None) - (implicit requestContext: AuthenticatedRequestContext): Future[GetListReply] + pagination: Option[Pagination] = None)( + implicit requestContext: AuthenticatedRequestContext): Future[GetListReply] - def getById(patientId: UuidId[Patient], - id: LongId[PatientTrialArmGroup]) - (implicit requestContext: AuthenticatedRequestContext): Future[GetByIdReply] + def getById(patientId: UuidId[Patient], id: LongId[PatientTrialArmGroup])( + implicit requestContext: AuthenticatedRequestContext): Future[GetByIdReply] - def getCriterionListByGroupId(patientId: UuidId[Patient], - id: LongId[PatientTrialArmGroup]) - (implicit requestContext: AuthenticatedRequestContext): Future[GetCriterionListOfGroupReply] + def getCriterionListByGroupId(patientId: UuidId[Patient], id: LongId[PatientTrialArmGroup])( + implicit requestContext: AuthenticatedRequestContext): Future[GetCriterionListOfGroupReply] def update(origEligibleTrialWithTrial: RichPatientEligibleTrial, - draftPatientTrialArmGroup: PatientTrialArmGroupView) - (implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] + draftPatientTrialArmGroup: PatientTrialArmGroupView)( + implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] } diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/PatientHypothesisService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/PatientHypothesisService.scala index dff595a..39ee2b1 100644 --- a/src/main/scala/xyz/driver/pdsuidomain/services/PatientHypothesisService.scala +++ b/src/main/scala/xyz/driver/pdsuidomain/services/PatientHypothesisService.scala @@ -25,14 +25,13 @@ object PatientHypothesisService { sealed trait GetListReply object GetListReply { - case class EntityList(xs: Seq[PatientHypothesis], totalFound: Int) - extends GetListReply + case class EntityList(xs: Seq[PatientHypothesis], totalFound: Int) extends GetListReply case object AuthorizationError - extends GetListReply with DomainError.AuthorizationError with DefaultAccessDeniedError + extends GetListReply with DomainError.AuthorizationError with DefaultAccessDeniedError case object PatientNotFoundError - extends GetListReply with DefaultPatientNotFoundError with DomainError.NotFoundError + extends GetListReply with DefaultPatientNotFoundError with DomainError.NotFoundError case class CommonError(userMessage: String) extends GetListReply with DomainError } @@ -43,20 +42,19 @@ object PatientHypothesisService { type Error = GetByIdReply with DomainError - case object NotFoundError - extends GetByIdReply with DefaultNotFoundError with DomainError.NotFoundError + case object NotFoundError extends GetByIdReply with DefaultNotFoundError with DomainError.NotFoundError case object PatientNotFoundError - extends GetByIdReply with DefaultPatientNotFoundError with DomainError.NotFoundError + extends GetByIdReply with DefaultPatientNotFoundError with DomainError.NotFoundError case object AuthorizationError - extends GetByIdReply with DomainError.AuthorizationError with DefaultAccessDeniedError + extends GetByIdReply with DomainError.AuthorizationError with DefaultAccessDeniedError case class CommonError(userMessage: String) extends GetByIdReply with DomainError implicit def toPhiString(reply: GetByIdReply): PhiString = reply match { case x: DomainError => phi"GetByIdReply.Error($x)" - case Entity(x) => phi"GetByIdReply.Entity($x)" + case Entity(x) => phi"GetByIdReply.Entity($x)" } } @@ -66,21 +64,19 @@ object PatientHypothesisService { case class Updated(updated: PatientHypothesis) extends UpdateReply - case object NotFoundError - extends UpdateReply with DefaultNotFoundError with DomainError.NotFoundError + case object NotFoundError extends UpdateReply with DefaultNotFoundError with DomainError.NotFoundError case object PatientNotFoundError - extends UpdateReply with DefaultPatientNotFoundError with DomainError.NotFoundError + extends UpdateReply with DefaultPatientNotFoundError with DomainError.NotFoundError case object AuthorizationError - extends UpdateReply with DomainError.AuthorizationError with DefaultAccessDeniedError + extends UpdateReply with DomainError.AuthorizationError with DefaultAccessDeniedError - case class CommonError(userMessage: String) - extends UpdateReply with DomainError + case class CommonError(userMessage: String) extends UpdateReply with DomainError implicit def toPhiString(reply: UpdateReply): PhiString = reply match { case Updated(x) => phi"Updated($x)" - case x: Error => DomainError.toPhiString(x) + case x: Error => DomainError.toPhiString(x) } } } @@ -92,14 +88,12 @@ trait PatientHypothesisService { def getAll(patientId: UuidId[Patient], filter: SearchFilterExpr = SearchFilterExpr.Empty, sorting: Option[Sorting] = None, - pagination: Option[Pagination] = None) - (implicit requestContext: AuthenticatedRequestContext): Future[GetListReply] + pagination: Option[Pagination] = None)( + implicit requestContext: AuthenticatedRequestContext): Future[GetListReply] - def getById(patientId: UuidId[Patient], - hypothesisId: UuidId[Hypothesis]) - (implicit requestContext: AuthenticatedRequestContext): Future[GetByIdReply] + def getById(patientId: UuidId[Patient], hypothesisId: UuidId[Hypothesis])( + implicit requestContext: AuthenticatedRequestContext): Future[GetByIdReply] - def update(origPatientHypothesis: PatientHypothesis, - draftPatientHypothesis: PatientHypothesis) - (implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] + def update(origPatientHypothesis: PatientHypothesis, draftPatientHypothesis: PatientHypothesis)( + implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] } diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/PatientLabelEvidenceService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/PatientLabelEvidenceService.scala index 8e791d4..f6039f0 100644 --- a/src/main/scala/xyz/driver/pdsuidomain/services/PatientLabelEvidenceService.scala +++ b/src/main/scala/xyz/driver/pdsuidomain/services/PatientLabelEvidenceService.scala @@ -12,10 +12,7 @@ import scala.concurrent.Future object PatientLabelEvidenceService { - case class Aggregated(evidence: PatientLabelEvidence, - date: LocalDate, - documentType: String, - providerType: String) + case class Aggregated(evidence: PatientLabelEvidence, date: LocalDate, documentType: String, providerType: String) trait DefaultAccessDeniedError { def userMessage: String = "Access denied" @@ -27,28 +24,24 @@ object PatientLabelEvidenceService { type Error = GetByIdReply with DomainError - case class NotFoundError(userMessage: String) extends GetByIdReply - with DomainError.NotFoundError + case class NotFoundError(userMessage: String) extends GetByIdReply with DomainError.NotFoundError - case class CommonError(userMessage: String) extends GetByIdReply - with DomainError + case class CommonError(userMessage: String) extends GetByIdReply with DomainError - case object AuthorizationError extends GetByIdReply - with DomainError.AuthorizationError with DefaultAccessDeniedError + case object AuthorizationError + extends GetByIdReply with DomainError.AuthorizationError with DefaultAccessDeniedError } sealed trait GetListReply object GetListReply { - case class EntityList(xs: Seq[Aggregated], totalFound: Int) - extends GetListReply + case class EntityList(xs: Seq[Aggregated], totalFound: Int) extends GetListReply type Error = GetListReply with DomainError case object AuthorizationError - extends GetListReply with DomainError.AuthorizationError with DefaultAccessDeniedError + extends GetListReply with DomainError.AuthorizationError with DefaultAccessDeniedError - case class CommonError(userMessage: String) extends GetListReply - with DomainError + case class CommonError(userMessage: String) extends GetListReply with DomainError } } @@ -56,15 +49,13 @@ trait PatientLabelEvidenceService { import PatientLabelEvidenceService._ - def getById(patientId: UuidId[Patient], - labelId: LongId[Label], - id: LongId[PatientLabelEvidence]) - (implicit requestContext: AuthenticatedRequestContext): Future[GetByIdReply] + def getById(patientId: UuidId[Patient], labelId: LongId[Label], id: LongId[PatientLabelEvidence])( + implicit requestContext: AuthenticatedRequestContext): Future[GetByIdReply] def getAll(patientId: UuidId[Patient], labelId: LongId[Label], filter: SearchFilterExpr = SearchFilterExpr.Empty, sorting: Option[Sorting] = None, - pagination: Option[Pagination] = None) - (implicit requestContext: AuthenticatedRequestContext): Future[GetListReply] + pagination: Option[Pagination] = None)( + implicit requestContext: AuthenticatedRequestContext): Future[GetListReply] } diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/PatientLabelService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/PatientLabelService.scala index 1d488ad..5fa2a4d 100644 --- a/src/main/scala/xyz/driver/pdsuidomain/services/PatientLabelService.scala +++ b/src/main/scala/xyz/driver/pdsuidomain/services/PatientLabelService.scala @@ -25,28 +25,26 @@ object PatientLabelService { sealed trait GetListReply object GetListReply { - case class EntityList(xs: Seq[(PatientLabel, Boolean)], totalFound: Int) - extends GetListReply + case class EntityList(xs: Seq[(PatientLabel, Boolean)], totalFound: Int) extends GetListReply case object AuthorizationError - extends GetListReply with DomainError.AuthorizationError with DefaultAccessDeniedError + extends GetListReply with DomainError.AuthorizationError with DefaultAccessDeniedError case object PatientNotFoundError - extends GetListReply with DefaultPatientNotFoundError with DomainError.NotFoundError + extends GetListReply with DefaultPatientNotFoundError with DomainError.NotFoundError case class CommonError(userMessage: String) extends GetListReply with DomainError } sealed trait GetDefiningCriteriaListReply object GetDefiningCriteriaListReply { - case class EntityList(xs: Seq[PatientLabel], totalFound: Int) - extends GetDefiningCriteriaListReply + case class EntityList(xs: Seq[PatientLabel], totalFound: Int) extends GetDefiningCriteriaListReply case object AuthorizationError - extends GetDefiningCriteriaListReply with DomainError.AuthorizationError with DefaultAccessDeniedError + extends GetDefiningCriteriaListReply with DomainError.AuthorizationError with DefaultAccessDeniedError case object PatientNotFoundError - extends GetDefiningCriteriaListReply with DefaultPatientNotFoundError with DomainError.NotFoundError + extends GetDefiningCriteriaListReply with DefaultPatientNotFoundError with DomainError.NotFoundError case class CommonError(userMessage: String) extends GetDefiningCriteriaListReply with DomainError } @@ -57,20 +55,19 @@ object PatientLabelService { type Error = GetByLabelIdReply with DomainError - case object NotFoundError - extends GetByLabelIdReply with DefaultNotFoundError with DomainError.NotFoundError + case object NotFoundError extends GetByLabelIdReply with DefaultNotFoundError with DomainError.NotFoundError case object PatientNotFoundError - extends GetByLabelIdReply with DefaultPatientNotFoundError with DomainError.NotFoundError + extends GetByLabelIdReply with DefaultPatientNotFoundError with DomainError.NotFoundError case object AuthorizationError - extends GetByLabelIdReply with DomainError.AuthorizationError with DefaultAccessDeniedError + extends GetByLabelIdReply with DomainError.AuthorizationError with DefaultAccessDeniedError case class CommonError(userMessage: String) extends GetByLabelIdReply with DomainError implicit def toPhiString(reply: GetByLabelIdReply): PhiString = reply match { case x: DomainError => phi"GetByIdReply.Error($x)" - case Entity(x, y) => phi"GetByIdReply.Entity($x, $y)" + case Entity(x, y) => phi"GetByIdReply.Entity($x, $y)" } } @@ -80,21 +77,19 @@ object PatientLabelService { case class Updated(updated: PatientLabel, isVerified: Boolean) extends UpdateReply - case object NotFoundError - extends UpdateReply with DefaultNotFoundError with DomainError.NotFoundError + case object NotFoundError extends UpdateReply with DefaultNotFoundError with DomainError.NotFoundError case object PatientNotFoundError - extends UpdateReply with DefaultPatientNotFoundError with DomainError.NotFoundError + extends UpdateReply with DefaultPatientNotFoundError with DomainError.NotFoundError case object AuthorizationError - extends UpdateReply with DomainError.AuthorizationError with DefaultAccessDeniedError + extends UpdateReply with DomainError.AuthorizationError with DefaultAccessDeniedError - case class CommonError(userMessage: String) - extends UpdateReply with DomainError + case class CommonError(userMessage: String) extends UpdateReply with DomainError implicit def toPhiString(reply: UpdateReply): PhiString = reply match { case Updated(x, y) => phi"Updated($x, $y)" - case x: Error => DomainError.toPhiString(x) + case x: Error => DomainError.toPhiString(x) } } } @@ -106,19 +101,17 @@ trait PatientLabelService { def getAll(patientId: UuidId[Patient], filter: SearchFilterExpr = SearchFilterExpr.Empty, sorting: Option[Sorting] = None, - pagination: Option[Pagination] = None) - (implicit requestContext: AuthenticatedRequestContext): Future[GetListReply] + pagination: Option[Pagination] = None)( + implicit requestContext: AuthenticatedRequestContext): Future[GetListReply] def getDefiningCriteriaList(patientId: UuidId[Patient], hypothesisId: UuidId[Hypothesis], - pagination: Option[Pagination] = None) - (implicit requestContext: AuthenticatedRequestContext): Future[GetDefiningCriteriaListReply] + pagination: Option[Pagination] = None)( + implicit requestContext: AuthenticatedRequestContext): Future[GetDefiningCriteriaListReply] - def getByLabelIdOfPatient(patientId: UuidId[Patient], - labelId: LongId[Label]) - (implicit requestContext: AuthenticatedRequestContext): Future[GetByLabelIdReply] + def getByLabelIdOfPatient(patientId: UuidId[Patient], labelId: LongId[Label])( + implicit requestContext: AuthenticatedRequestContext): Future[GetByLabelIdReply] - def update(origPatientLabel: PatientLabel, - draftPatientLabel: PatientLabel) - (implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] + def update(origPatientLabel: PatientLabel, draftPatientLabel: PatientLabel)( + implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] } diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/PatientService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/PatientService.scala index 3f8b606..4619011 100644 --- a/src/main/scala/xyz/driver/pdsuidomain/services/PatientService.scala +++ b/src/main/scala/xyz/driver/pdsuidomain/services/PatientService.scala @@ -23,11 +23,10 @@ object PatientService { sealed trait GetListReply object GetListReply { - case class EntityList(xs: Seq[Patient], totalFound: Int, lastUpdate: Option[LocalDateTime]) - extends GetListReply + case class EntityList(xs: Seq[Patient], totalFound: Int, lastUpdate: Option[LocalDateTime]) extends GetListReply case object AuthorizationError - extends GetListReply with DomainError.AuthorizationError with DefaultAccessDeniedError + extends GetListReply with DomainError.AuthorizationError with DefaultAccessDeniedError } sealed trait GetByIdReply @@ -36,18 +35,17 @@ object PatientService { type Error = GetByIdReply with DomainError - case object NotFoundError - extends GetByIdReply with DefaultNotFoundError with DomainError.NotFoundError + case object NotFoundError extends GetByIdReply with DefaultNotFoundError with DomainError.NotFoundError case object AuthorizationError - extends GetByIdReply with DomainError.AuthorizationError with DefaultAccessDeniedError + extends GetByIdReply with DomainError.AuthorizationError with DefaultAccessDeniedError case class CommonError(userMessage: String)(implicit requestContext: AuthenticatedRequestContext) - extends GetByIdReply with DomainError + extends GetByIdReply with DomainError implicit def toPhiString(reply: GetByIdReply): PhiString = reply match { case x: DomainError => phi"GetByIdReply.Error($x)" - case Entity(x) => phi"GetByIdReply.Entity($x)" + case Entity(x) => phi"GetByIdReply.Entity($x)" } } @@ -57,18 +55,16 @@ object PatientService { case class Updated(updated: Patient) extends UpdateReply - case object NotFoundError - extends UpdateReply with DefaultNotFoundError with DomainError.NotFoundError + case object NotFoundError extends UpdateReply with DefaultNotFoundError with DomainError.NotFoundError case object AuthorizationError - extends UpdateReply with DefaultAccessDeniedError with DomainError.AuthorizationError + extends UpdateReply with DefaultAccessDeniedError with DomainError.AuthorizationError - case class CommonError(userMessage: String) - extends UpdateReply with DomainError + case class CommonError(userMessage: String) extends UpdateReply with DomainError implicit def toPhiString(reply: UpdateReply): PhiString = reply match { case Updated(x) => phi"Updated($x)" - case x: Error => DomainError.toPhiString(x) + case x: Error => DomainError.toPhiString(x) } } } @@ -77,29 +73,22 @@ trait PatientService { import PatientService._ - def getById(id: UuidId[Patient]) - (implicit requestContext: AuthenticatedRequestContext): Future[GetByIdReply] + def getById(id: UuidId[Patient])(implicit requestContext: AuthenticatedRequestContext): Future[GetByIdReply] def getAll(filter: SearchFilterExpr = SearchFilterExpr.Empty, sorting: Option[Sorting] = None, - pagination: Option[Pagination] = None) - (implicit requestContext: AuthenticatedRequestContext): Future[GetListReply] + pagination: Option[Pagination] = None)( + implicit requestContext: AuthenticatedRequestContext): Future[GetListReply] - def unassign(origPatient: Patient) - (implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] + def unassign(origPatient: Patient)(implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] - def start(origPatient: Patient) - (implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] + def start(origPatient: Patient)(implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] - def submit(origPatient: Patient) - (implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] + def submit(origPatient: Patient)(implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] - def restart(origPatient: Patient) - (implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] + def restart(origPatient: Patient)(implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] - def flag(origPatient: Patient) - (implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] + def flag(origPatient: Patient)(implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] - def resolve(origPatient: Patient) - (implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] + def resolve(origPatient: Patient)(implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] } diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/ProviderTypeService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/ProviderTypeService.scala index 49901a4..ef48aa0 100644 --- a/src/main/scala/xyz/driver/pdsuidomain/services/ProviderTypeService.scala +++ b/src/main/scala/xyz/driver/pdsuidomain/services/ProviderTypeService.scala @@ -11,8 +11,7 @@ object ProviderTypeService { sealed trait GetListReply object GetListReply { case class EntityList(xs: Seq[ProviderType], totalFound: Int) extends GetListReply - case object AuthorizationError - extends GetListReply with DomainError.AuthorizationError { + case object AuthorizationError extends GetListReply with DomainError.AuthorizationError { def userMessage: String = "Access denied" } } @@ -22,6 +21,6 @@ trait ProviderTypeService { import ProviderTypeService._ - def getAll(sorting: Option[Sorting] = None) - (implicit requestContext: AuthenticatedRequestContext): Future[GetListReply] + def getAll(sorting: Option[Sorting] = None)( + implicit requestContext: AuthenticatedRequestContext): Future[GetListReply] } diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/ScrapedTrialsService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/ScrapedTrialsService.scala index 4417a54..b595584 100644 --- a/src/main/scala/xyz/driver/pdsuidomain/services/ScrapedTrialsService.scala +++ b/src/main/scala/xyz/driver/pdsuidomain/services/ScrapedTrialsService.scala @@ -25,8 +25,7 @@ object ScrapedTrialsService { sealed trait GetAllRawTrialsExceptReply object GetAllRawTrialsExceptReply { - case class MultipleRawTrials(rawTrials: Seq[ScrapedTrial]) - extends GetAllRawTrialsExceptReply + case class MultipleRawTrials(rawTrials: Seq[ScrapedTrial]) extends GetAllRawTrialsExceptReply } sealed trait GetHtmlForReply diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/StudyDesignService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/StudyDesignService.scala index d086c5f..a1ce613 100644 --- a/src/main/scala/xyz/driver/pdsuidomain/services/StudyDesignService.scala +++ b/src/main/scala/xyz/driver/pdsuidomain/services/StudyDesignService.scala @@ -12,8 +12,7 @@ object StudyDesignService { object GetListReply { case class EntityList(xs: Seq[StudyDesign], totalFound: Int) extends GetListReply - case object AuthorizationError - extends GetListReply with DomainError.AuthorizationError { + case object AuthorizationError extends GetListReply with DomainError.AuthorizationError { def userMessage: String = "Access denied" } } @@ -23,6 +22,6 @@ trait StudyDesignService { import StudyDesignService._ - def getAll(sorting: Option[Sorting] = None) - (implicit requestContext: AuthenticatedRequestContext): Future[GetListReply] + def getAll(sorting: Option[Sorting] = None)( + implicit requestContext: AuthenticatedRequestContext): Future[GetListReply] } diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/TrialService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/TrialService.scala index 4af4449..47f76f2 100644 --- a/src/main/scala/xyz/driver/pdsuidomain/services/TrialService.scala +++ b/src/main/scala/xyz/driver/pdsuidomain/services/TrialService.scala @@ -1,6 +1,5 @@ package xyz.driver.pdsuidomain.services - import java.time.LocalDateTime import xyz.driver.pdsuicommon.auth.AuthenticatedRequestContext @@ -25,11 +24,10 @@ object TrialService { sealed trait GetListReply object GetListReply { - case class EntityList(xs: Seq[Trial], totalFound: Int, lastUpdate: Option[LocalDateTime]) - extends GetListReply + case class EntityList(xs: Seq[Trial], totalFound: Int, lastUpdate: Option[LocalDateTime]) extends GetListReply case object AuthorizationError - extends GetListReply with DomainError.AuthorizationError with DefaultAccessDeniedError + extends GetListReply with DomainError.AuthorizationError with DefaultAccessDeniedError } sealed trait GetByIdReply @@ -38,18 +36,17 @@ object TrialService { type Error = GetByIdReply with DomainError - case object NotFoundError - extends GetByIdReply with DefaultNotFoundError with DomainError.NotFoundError + case object NotFoundError extends GetByIdReply with DefaultNotFoundError with DomainError.NotFoundError case object AuthorizationError - extends GetByIdReply with DomainError.AuthorizationError with DefaultAccessDeniedError + extends GetByIdReply with DomainError.AuthorizationError with DefaultAccessDeniedError case class CommonError(userMessage: String)(implicit requestContext: AuthenticatedRequestContext) - extends GetByIdReply with DomainError + extends GetByIdReply with DomainError implicit def toPhiString(reply: GetByIdReply): PhiString = reply match { case x: DomainError => phi"GetByIdReply.Error($x)" - case Entity(x) => phi"GetByIdReply.Entity($x)" + case Entity(x) => phi"GetByIdReply.Entity($x)" } } @@ -60,18 +57,15 @@ object TrialService { case class Entity(x: PdfSource) extends GetPdfSourceReply case object AuthorizationError - extends GetPdfSourceReply with DomainError.AuthorizationError with DefaultAccessDeniedError + extends GetPdfSourceReply with DomainError.AuthorizationError with DefaultAccessDeniedError - case object NotFoundError - extends GetPdfSourceReply with DomainError.NotFoundError { + case object NotFoundError extends GetPdfSourceReply with DomainError.NotFoundError { def userMessage: String = "Trial's PDF hasn't been found" } - case object TrialNotFoundError - extends GetPdfSourceReply with DomainError.NotFoundError with DefaultNotFoundError + case object TrialNotFoundError extends GetPdfSourceReply with DomainError.NotFoundError with DefaultNotFoundError - case class CommonError(userMessage: String) - extends GetPdfSourceReply with DomainError + case class CommonError(userMessage: String) extends GetPdfSourceReply with DomainError } sealed trait UpdateReply @@ -80,18 +74,16 @@ object TrialService { case class Updated(updated: Trial) extends UpdateReply - case object NotFoundError - extends UpdateReply with DefaultNotFoundError with DomainError.NotFoundError + case object NotFoundError extends UpdateReply with DefaultNotFoundError with DomainError.NotFoundError case object AuthorizationError - extends UpdateReply with DefaultAccessDeniedError with DomainError.AuthorizationError + extends UpdateReply with DefaultAccessDeniedError with DomainError.AuthorizationError - case class CommonError(userMessage: String) - extends UpdateReply with DomainError + case class CommonError(userMessage: String) extends UpdateReply with DomainError implicit def toPhiString(reply: UpdateReply): PhiString = reply match { case Updated(x) => phi"Updated($x)" - case x: Error => DomainError.toPhiString(x) + case x: Error => DomainError.toPhiString(x) } } } @@ -100,19 +92,18 @@ trait TrialService { import TrialService._ - def getById(id: StringId[Trial]) - (implicit requestContext: AuthenticatedRequestContext): Future[GetByIdReply] + def getById(id: StringId[Trial])(implicit requestContext: AuthenticatedRequestContext): Future[GetByIdReply] - def getPdfSource(trialId: StringId[Trial]) - (implicit requestContext: AuthenticatedRequestContext): Future[GetPdfSourceReply] + def getPdfSource(trialId: StringId[Trial])( + implicit requestContext: AuthenticatedRequestContext): Future[GetPdfSourceReply] def getAll(filter: SearchFilterExpr = SearchFilterExpr.Empty, sorting: Option[Sorting] = None, - pagination: Option[Pagination] = None) - (implicit requestContext: AuthenticatedRequestContext): Future[GetListReply] + pagination: Option[Pagination] = None)( + implicit requestContext: AuthenticatedRequestContext): Future[GetListReply] - def update(origTrial: Trial, draftTrial: Trial) - (implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] + def update(origTrial: Trial, draftTrial: Trial)( + implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] def start(origTrial: Trial)(implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] diff --git a/src/main/scala/xyz/driver/pdsuidomain/storage/RequestStorage.scala b/src/main/scala/xyz/driver/pdsuidomain/storage/RequestStorage.scala index 9e3ad67..6aa49a1 100644 --- a/src/main/scala/xyz/driver/pdsuidomain/storage/RequestStorage.scala +++ b/src/main/scala/xyz/driver/pdsuidomain/storage/RequestStorage.scala @@ -30,13 +30,13 @@ class RequestStorage extends PhiLogging { } def get(patientId: UuidId[Patient], disease: String): Option[Value] = { - logger.debug(phi"get($patientId,${Unsafe(disease)}") + logger.debug(phi"get($patientId, ${Unsafe(disease)}") val key = (patientId, disease.toLowerCase) storage.get(key) } def contains(patientId: UuidId[Patient], disease: String, value: Set[LongId[Arm]]): Boolean = { - logger.debug(phi"contains(key=($patientId,${Unsafe(disease)}),value=$value") + logger.debug(phi"contains(key=($patientId,${Unsafe(disease)}), value=$value") get(patientId, disease.toLowerCase).contains(value) } diff --git a/src/test/scala/xyz/driver/pdsuicommon/BaseSuite.scala b/src/test/scala/xyz/driver/pdsuicommon/BaseSuite.scala index 656ee24..71f8ebf 100644 --- a/src/test/scala/xyz/driver/pdsuicommon/BaseSuite.scala +++ b/src/test/scala/xyz/driver/pdsuicommon/BaseSuite.scala @@ -5,18 +5,15 @@ import java.time.{LocalDateTime, ZoneId} import org.scalatest.FreeSpecLike import org.scalatest.concurrent.ScalaFutures import org.scalatest.time.{Millis, Span} -import xyz.driver.pdsuicommon.db.{MysqlQueryBuilder, SearchFilterExpr, SqlContext, Transactions} +import xyz.driver.pdsuicommon.db._ import xyz.driver.pdsuicommon.domain.{Email, LongId, PasswordHash, User} import xyz.driver.pdsuicommon.error.UnexpectedFilterException import xyz.driver.pdsuicommon.utils.DiffUtils -import scala.concurrent.ExecutionContext.Implicits._ -import scala.concurrent.Future - trait BaseSuite extends FreeSpecLike with DiffUtils with ScalaFutures { implicit val defaultPatience = PatienceConfig(timeout = Span(1000, Millis), interval = Span(20, Millis)) - implicit val sqlContext = new MockSqlContext(global) + implicit val sqlContext = new MockMySqlContext() def sampleUser(role: User.Role, email: String = "test@example.com", password: String = "123") = User( id = LongId(2001), @@ -30,20 +27,10 @@ trait BaseSuite extends FreeSpecLike with DiffUtils with ScalaFutures { def createMockQueryBuilder[T](isExpectedFilter: SearchFilterExpr => Boolean): MysqlQueryBuilder[T] = { MockQueryBuilder[T] { - case (filter, _, _) if isExpectedFilter(filter) => - Future.successful(Seq.empty) - case (filter, _, _) => - Future.failed(new UnexpectedFilterException(s"Filter is unexpected: $filter")) + case (filter, _, _) if isExpectedFilter(filter) => Seq.empty + case (filter, _, _) => throw new UnexpectedFilterException(s"Filter is unexpected: $filter") } { - case _ => - Future.successful((0, Option.empty[LocalDateTime])) + case _ => (0, Option.empty[LocalDateTime]) } } - - def transactions = new Transactions { - override def run[T](f: (SqlContext) => T): Future[T] = { - Future(f(sqlContext)) - } - } - } diff --git a/src/test/scala/xyz/driver/pdsuicommon/Mocks.scala b/src/test/scala/xyz/driver/pdsuicommon/Mocks.scala index d4b4d3c..1c01483 100644 --- a/src/test/scala/xyz/driver/pdsuicommon/Mocks.scala +++ b/src/test/scala/xyz/driver/pdsuicommon/Mocks.scala @@ -10,7 +10,7 @@ import com.typesafe.config.ConfigFactory import xyz.driver.pdsuicommon.db._ import xyz.driver.pdsuicommon.http.HttpFetcher -import scala.concurrent.{ExecutionContext, Future} +import scala.concurrent.Future class MockDataSource extends DataSource with Closeable { override def getConnection: Connection = throw new NotImplementedError("MockDataSource.getConnection") @@ -27,10 +27,10 @@ class MockDataSource extends DataSource with Closeable { override def isWrapperFor(iface: Class[_]): Boolean = throw new NotImplementedError("MockDataSource.isWrapperFor") } -object MockSqlContext { +object MockMySqlContext { - val Settings = SqlContext.Settings( - credentials = SqlContext.DbCredentials( + val Settings = MySqlContext.Settings( + credentials = MySqlContext.DbCredentials( user = "test", password = "test", host = "localhost", @@ -45,18 +45,16 @@ object MockSqlContext { connectionAttemptsOnStartup = 1, threadPoolSize = 10 ) - } -class MockSqlContext(ec: ExecutionContext) extends SqlContext(new MockDataSource, MockSqlContext.Settings) { - override implicit val executionContext = ec - override protected def withConnection[T](f: Connection => T) = { +class MockMySqlContext() extends MySqlContext(new MockDataSource, MockMySqlContext.Settings) { + override protected def withConnection[T](f: Connection => T): Nothing = { throw new NotImplementedError("MockSqlContext.withConnection") } } -class MockFactory()(implicit val sqlContext: SqlContext) { - val MockHttpFetcher: HttpFetcher = (url: URL) => { +class MockFactory()(implicit val sqlContext: MySqlContext) { + val MockHttpFetcher: HttpFetcher = { (url: URL) => Future.successful(Array.empty[Byte]) } } @@ -64,25 +62,28 @@ class MockFactory()(implicit val sqlContext: SqlContext) { object MockQueryBuilder { type MockRunnerIn = (SearchFilterExpr, Sorting, Option[Pagination]) - type MockRunnerOut[T] = Future[Seq[T]] - type MockCountRunnerOut = Future[QueryBuilder.CountResult] + type MockRunnerOut[T] = Seq[T] + type MockCountRunnerOut = QueryBuilder.CountResult def apply[T](matcher: PartialFunction[MockRunnerIn, MockRunnerOut[T]])( countMatcher: PartialFunction[MockRunnerIn, MockCountRunnerOut])( - implicit context: SqlContext): MysqlQueryBuilder[T] = { - def runner(parameters: QueryBuilderParameters): MockRunnerOut[T] = { + implicit context: MySqlContext): MysqlQueryBuilder[T] = { + + val runner: QueryBuilder.Runner[T] = { parameters => matcher((parameters.filter, parameters.sorting, parameters.pagination)) } - def countRunner(parameters: QueryBuilderParameters): MockCountRunnerOut = { + + val countRunner: QueryBuilder.CountRunner = { parameters => countMatcher((parameters.filter, parameters.sorting, parameters.pagination)) } + MysqlQueryBuilder[T]( tableName = "", lastUpdateFieldName = Option.empty[String], nullableFields = Set.empty[String], links = Set.empty[TableLink], - runner = runner _, - countRunner = countRunner _ - )(context.executionContext) + runner = runner, + countRunner = countRunner + ) } } diff --git a/src/test/scala/xyz/driver/pdsuicommon/concurrent/BridgeUploadQueueRepositoryAdapterSuite.scala b/src/test/scala/xyz/driver/pdsuicommon/concurrent/BridgeUploadQueueRepositoryAdapterSuite.scala index d0dbb04..8b38316 100644 --- a/src/test/scala/xyz/driver/pdsuicommon/concurrent/BridgeUploadQueueRepositoryAdapterSuite.scala +++ b/src/test/scala/xyz/driver/pdsuicommon/concurrent/BridgeUploadQueueRepositoryAdapterSuite.scala @@ -3,11 +3,10 @@ package xyz.driver.pdsuicommon.concurrent import java.util.concurrent.ThreadLocalRandom import xyz.driver.pdsuicommon.BaseSuite -import xyz.driver.pdsuicommon.concurrent.BridgeUploadQueue.Item import xyz.driver.pdsuicommon.concurrent.BridgeUploadQueueRepositoryAdapter.Strategy import xyz.driver.pdsuicommon.concurrent.BridgeUploadQueueRepositoryAdapter.Strategy.{OnAttempt, OnComplete} +import xyz.driver.pdsuicommon.db.{FakeDbIo, MysqlQueryBuilder} import xyz.driver.pdsuicommon.db.repositories.BridgeUploadQueueRepository -import xyz.driver.pdsuicommon.domain.LongId import scala.concurrent.Future import scala.concurrent.duration.DurationInt @@ -48,6 +47,71 @@ class BridgeUploadQueueRepositoryAdapterSuite extends BaseSuite { } } + "complete" - { + "onComplete == mark" - { + "should update the item" in { + var done = false + val item = defaultItem + + val repository = new BridgeUploadQueueRepository { + override def add(draft: EntityT): EntityT = draft + override def getOne(kind: String): Option[EntityT] = fail("getOne should not be used!") + override def buildQuery: MysqlQueryBuilder[EntityT] = fail("buildQuery should not be used!") + + override def delete(kind: String, tag: String): Unit = throw new IllegalStateException("Impossible call") + + override def update(entity: EntityT): EntityT = { + assert(entity.kind == item.kind, "repository.delete, kind") + assert(entity.tag == item.tag, "repository.delete, tag") + done = true + entity + } + + override def getById(kind: String, tag: String): Option[EntityT] = Some(item) + } + + val adapter = new BridgeUploadQueueRepositoryAdapter( + strategy = Strategy.Stop(OnComplete.Mark), + repository = repository, + dbIo = FakeDbIo + ) + + assert(adapter.complete(item.kind, item.tag).isReadyWithin(100.millis)) + assert(done) + } + } + + "onComplete == delete" - { + "should delete the item" in { + var done = false + val item = defaultItem + + val repository = new BridgeUploadQueueRepository { + override def add(draft: EntityT): EntityT = draft + override def getOne(kind: String): Option[EntityT] = fail("getOne should not be used!") + override def buildQuery: MysqlQueryBuilder[EntityT] = fail("buildQuery should not be used!") + override def getById(kind: String, tag: String): Option[EntityT] = fail("getById should not be used!") + + override def delete(kind: String, tag: String): Unit = { + assert(kind == item.kind, "repository.delete, kind") + assert(tag == item.tag, "repository.delete, tag") + done = true + } + override def update(entity: EntityT): EntityT = throw new IllegalStateException("Impossible call") + } + + val adapter = new BridgeUploadQueueRepositoryAdapter( + strategy = Strategy.Stop(OnComplete.Delete), + repository = repository, + dbIo = FakeDbIo + ) + + assert(adapter.complete(item.kind, item.tag).isReadyWithin(100.millis)) + assert(done) + } + } + } + "tryRetry" - { "when all attempts are not out" - { @@ -56,19 +120,19 @@ class BridgeUploadQueueRepositoryAdapterSuite extends BaseSuite { "should return an updated item" in { val repository = new BridgeUploadQueueRepository { - override def update(draft: EntityT): EntityT = draft - override def delete(id: IdT): Unit = {} - override def add(draft: EntityT): EntityT = fail("add should not be used!") - override def getById(id: LongId[EntityT]): Option[EntityT] = fail("getById should not be used!") - override def isCompleted(kind: String, tag: String): Future[Boolean] = - fail("isCompleted should not be used!") - override def getOne(kind: String): Future[Option[Item]] = fail("getOne should not be used!") + override def add(draft: EntityT): EntityT = draft + override def getOne(kind: String): Option[EntityT] = fail("getOne should not be used!") + override def buildQuery: MysqlQueryBuilder[EntityT] = fail("buildQuery should not be used!") + override def getById(kind: String, tag: String): Option[EntityT] = fail("getById should not be used!") + + override def update(draft: EntityT): EntityT = draft + override def delete(kind: String, tag: String): Unit = throw new IllegalAccessError(s"kind=$kind, tag=$tag") } val adapter = new BridgeUploadQueueRepositoryAdapter( strategy = defaultStrategy, repository = repository, - transactions = transactions + dbIo = FakeDbIo ) val item = defaultItem @@ -77,147 +141,136 @@ class BridgeUploadQueueRepositoryAdapterSuite extends BaseSuite { assert(!r.contains(item)) } - "should add an item with increased attempts" in { + "should update an item with increased attempts" in { val item = defaultItem val repository = new BridgeUploadQueueRepository { + override def add(draft: EntityT): EntityT = draft + override def getOne(kind: String): Option[EntityT] = fail("getOne should not be used!") + override def buildQuery: MysqlQueryBuilder[EntityT] = fail("buildQuery should not be used!") + override def getById(kind: String, tag: String): Option[EntityT] = fail("getById should not be used!") + override def update(draft: EntityT): EntityT = { assert(draft.attempts === (item.attempts + 1), "repository.add") draft } - override def delete(id: IdT): Unit = {} - override def add(draft: EntityT): EntityT = fail("add should not be used!") - override def getById(id: LongId[EntityT]): Option[EntityT] = fail("getById should not be used!") - override def isCompleted(kind: String, tag: String): Future[Boolean] = - fail("isCompleted should not be used!") - override def getOne(kind: String): Future[Option[Item]] = fail("getOne should not be used!") + override def delete(kind: String, tag: String): Unit = throw new IllegalAccessError(s"kind=$kind, tag=$tag") } val adapter = new BridgeUploadQueueRepositoryAdapter( strategy = defaultStrategy, repository = repository, - transactions = transactions + dbIo = FakeDbIo ) - adapter.tryRetry(item).isReadyWithin(100.millis) + assert(adapter.tryRetry(item).isReadyWithin(100.millis)) } "should remove an old item" in { val item = defaultItem val repository = new BridgeUploadQueueRepository { - override def update(draft: EntityT): EntityT = draft - override def delete(id: IdT): Unit = { - assert(id == item.id, "repository.delete") + override def add(draft: EntityT): EntityT = draft + override def getOne(kind: String): Option[EntityT] = fail("getOne should not be used!") + override def buildQuery: MysqlQueryBuilder[EntityT] = fail("buildQuery should not be used!") + override def getById(kind: String, tag: String): Option[EntityT] = fail("getById should not be used!") + override def update(draft: EntityT): EntityT = draft + override def delete(kind: String, tag: String): Unit = { + assert(kind == item.kind, "repository.delete, kind") + assert(tag == item.tag, "repository.delete, kind") } - override def add(draft: EntityT): EntityT = fail("add should not be used!") - override def getById(id: LongId[EntityT]): Option[EntityT] = fail("getById should not be used!") - override def isCompleted(kind: String, tag: String): Future[Boolean] = - fail("isCompleted should not be used!") - override def getOne(kind: String): Future[Option[Item]] = fail("getOne should not be used!") } val adapter = new BridgeUploadQueueRepositoryAdapter( strategy = defaultStrategy, repository = repository, - transactions = transactions + dbIo = FakeDbIo ) - adapter.tryRetry(item).isReadyWithin(100.millis) + assert(adapter.tryRetry(item).isReadyWithin(100.millis)) } "should update time of the next attempt" in { val item = defaultItem val repository = new BridgeUploadQueueRepository { + override def add(draft: EntityT): EntityT = draft + override def getOne(kind: String): Option[EntityT] = fail("getOne should not be used!") + override def buildQuery: MysqlQueryBuilder[EntityT] = fail("buildQuery should not be used!") + override def getById(kind: String, tag: String): Option[EntityT] = fail("getById should not be used!") + override def update(draft: EntityT): EntityT = { assert(draft.nextAttempt.isAfter(item.nextAttempt), "repository.add") draft } - override def delete(id: IdT): Unit = {} - override def add(draft: EntityT): EntityT = fail("add should not be used!") - override def getById(id: LongId[EntityT]): Option[EntityT] = fail("getById should not be used!") - override def isCompleted(kind: String, tag: String): Future[Boolean] = - fail("isCompleted should not be used!") - override def getOne(kind: String): Future[Option[Item]] = fail("getOne should not be used!") + override def delete(kind: String, tag: String): Unit = throw new IllegalAccessError(s"kind=$kind, tag=$tag") } val adapter = new BridgeUploadQueueRepositoryAdapter( strategy = defaultStrategy, repository = repository, - transactions = transactions + dbIo = FakeDbIo ) - adapter.tryRetry(item).isReadyWithin(100.millis) + assert(adapter.tryRetry(item).isReadyWithin(100.millis)) } } "when all attempts are out" - { - val defaultStrategy = Strategy.Ignore + val defaultStrategy = Strategy.Stop() "should not return an item" in { val repository = new BridgeUploadQueueRepository { - override def delete(id: IdT): Unit = {} - override def update(entity: EntityT): EntityT = fail("update should not be used!") - override def add(draft: EntityT): EntityT = fail("add should not be used!") - override def getById(id: LongId[EntityT]): Option[EntityT] = fail("getById should not be used!") - override def isCompleted(kind: String, tag: String): Future[Boolean] = - fail("isCompleted should not be used!") - override def getOne(kind: String): Future[Option[Item]] = fail("getOne should not be used!") + override def add(draft: EntityT): EntityT = draft + override def getOne(kind: String): Option[EntityT] = fail("getOne should not be used!") + override def buildQuery: MysqlQueryBuilder[EntityT] = fail("buildQuery should not be used!") + override def getById(kind: String, tag: String): Option[EntityT] = fail("getById should not be used!") + override def update(entity: EntityT): EntityT = fail("update should not be used!") + + override def delete(kind: String, tag: String): Unit = {} } val adapter = new BridgeUploadQueueRepositoryAdapter( strategy = defaultStrategy, repository = repository, - transactions = transactions + dbIo = FakeDbIo ) val r = adapter.tryRetry(defaultItem).futureValue assert(r.isEmpty) } - "should not add any item to the queue" in { + "should complete the item" in { + var taskWasCompleted = false + val item = defaultItem + val repository = new BridgeUploadQueueRepository { - override def update(draft: EntityT): EntityT = throw new IllegalAccessException("add should not be called") - override def delete(id: IdT): Unit = {} - override def add(draft: EntityT): EntityT = fail("add should not be used!") - override def getById(id: LongId[EntityT]): Option[EntityT] = fail("getById should not be used!") - override def isCompleted(kind: String, tag: String): Future[Boolean] = - fail("isCompleted should not be used!") - override def getOne(kind: String): Future[Option[Item]] = fail("getOne should not be used!") + override def add(draft: EntityT): EntityT = draft + override def getOne(kind: String): Option[EntityT] = fail("getOne should not be used!") + override def buildQuery: MysqlQueryBuilder[EntityT] = fail("buildQuery should not be used!") + override def getById(kind: String, tag: String): Option[EntityT] = fail("getById should not be used!") + override def update(entity: EntityT): EntityT = fail("update should not be used!") + + override def delete(kind: String, tag: String): Unit = {} } val adapter = new BridgeUploadQueueRepositoryAdapter( strategy = defaultStrategy, repository = repository, - transactions = transactions - ) - - adapter.tryRetry(defaultItem).isReadyWithin(100.millis) - } - - "should remove the item from the queue" in { - val repository = new BridgeUploadQueueRepository { - override def delete(id: IdT): Unit = { - assert(id == defaultItem.id, "repository.delete") + dbIo = FakeDbIo + ) { + override def complete(kind: String, tag: String): Future[Unit] = Future { + assert(kind == item.kind, "adapter.complete, kind") + assert(tag == item.tag, "adapter.complete, tag") + taskWasCompleted = true } - override def update(entity: EntityT): EntityT = fail("update should not be used!") - override def add(draft: EntityT): EntityT = fail("add should not be used!") - override def getById(id: LongId[EntityT]): Option[EntityT] = fail("getById should not be used!") - override def isCompleted(kind: String, tag: String): Future[Boolean] = - fail("isCompleted should not be used!") - override def getOne(kind: String): Future[Option[Item]] = fail("getOne should not be used!") } - val adapter = new BridgeUploadQueueRepositoryAdapter( - strategy = defaultStrategy, - repository = repository, - transactions = transactions - ) - - adapter.tryRetry(defaultItem).isReadyWithin(100.millis) + val r = adapter.tryRetry(item).futureValue + assert(r.isEmpty) + assert(taskWasCompleted) } } |