diff options
Diffstat (limited to 'src/main/scala/xyz/driver/pdsuidomain/services')
8 files changed, 284 insertions, 13 deletions
diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/CriterionService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/CriterionService.scala index fd9268b..7dbf0d9 100644 --- a/src/main/scala/xyz/driver/pdsuidomain/services/CriterionService.scala +++ b/src/main/scala/xyz/driver/pdsuidomain/services/CriterionService.scala @@ -21,7 +21,9 @@ object CriterionService { def userMessage: String = "Access denied" } - final case class RichCriterion(criterion: Criterion, armIds: Seq[LongId[Arm]], labels: Seq[CriterionLabel]) + final case class RichCriterion(criterion: Criterion, + armIds: Seq[LongId[EligibilityArm]], + labels: Seq[CriterionLabel]) object RichCriterion { implicit def toPhiString(x: RichCriterion): PhiString = { import x._ diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/EligibilityArmService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/EligibilityArmService.scala new file mode 100644 index 0000000..1e0f65e --- /dev/null +++ b/src/main/scala/xyz/driver/pdsuidomain/services/EligibilityArmService.scala @@ -0,0 +1,139 @@ +package xyz.driver.pdsuidomain.services + +import xyz.driver.pdsuicommon.auth.AuthenticatedRequestContext +import xyz.driver.pdsuicommon.db._ +import xyz.driver.pdsuicommon.domain.LongId +import xyz.driver.pdsuicommon.error.DomainError +import xyz.driver.pdsuicommon.logging._ +import xyz.driver.pdsuidomain.entities.{EligibilityArm, EligibilityArmWithDiseases, SlotArm} + +import scala.concurrent.Future + +object EligibilityArmService { + + trait DefaultAccessDeniedError { + def userMessage: String = "Access denied" + } + + trait DefaultNotFoundError { + def userMessage: String = "EligibilityArm not found" + } + + trait SlotArmNotFoundError { + def userMessage: String = "SlotArm not found" + } + + sealed trait GetByIdReply + object GetByIdReply { + + final case class Entity(x: EligibilityArmWithDiseases) extends GetByIdReply + + type Error = GetByIdReply with DomainError + + case object NotFoundError extends GetByIdReply with DefaultNotFoundError with DomainError.NotFoundError + + case object AuthorizationError + extends GetByIdReply with DomainError.AuthorizationError with DefaultAccessDeniedError + + final case class CommonError(userMessage: String)(implicit requestContext: AuthenticatedRequestContext) + extends GetByIdReply with DomainError + } + + sealed trait GetListReply + object GetListReply { + type Error = GetListReply with DomainError + + final case class EntityList(xs: Seq[EligibilityArmWithDiseases], totalFound: Int) extends GetListReply + + case object AuthorizationError + extends GetListReply with DomainError.AuthorizationError with DefaultAccessDeniedError + } + + sealed trait UpdateReply + object UpdateReply { + + final case class Updated(updated: EligibilityArmWithDiseases) extends UpdateReply + + type Error = UpdateReply with DomainError + + case object NotFoundError extends UpdateReply with DefaultNotFoundError with DomainError.NotFoundError + + case object AuthorizationError + extends UpdateReply with DefaultAccessDeniedError with DomainError.AuthorizationError + + final case class CommonError(userMessage: String) extends UpdateReply with DomainError + + final case class AlreadyExistsError(x: EligibilityArmWithDiseases) extends UpdateReply with DomainError { + val userMessage = s"The arm with such name of trial already exists." + } + + implicit def toPhiString(reply: UpdateReply): PhiString = reply match { + case Updated(x) => phi"Updated($x)" + case x: Error => DomainError.toPhiString(x) + } + } + + sealed trait CreateReply + object CreateReply { + final case class Created(x: EligibilityArmWithDiseases) extends CreateReply + + type Error = CreateReply with DomainError + + case object AuthorizationError + extends CreateReply with DefaultAccessDeniedError with DomainError.AuthorizationError + + case object NotFoundError extends CreateReply with SlotArmNotFoundError with DomainError.NotFoundError + + final case class CommonError(userMessage: String) extends CreateReply with DomainError + + final case class AlreadyExistsError(x: EligibilityArmWithDiseases) extends CreateReply with DomainError { + val userMessage = s"The arm with this name of trial already exists." + } + + implicit def toPhiString(reply: CreateReply): PhiString = reply match { + case Created(x) => phi"Created($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 AuthorizationError + extends DeleteReply with DefaultAccessDeniedError with DomainError.AuthorizationError + + final case class CommonError(userMessage: String) extends DeleteReply with DomainError + } +} + +trait EligibilityArmService { + + import EligibilityArmService._ + + def getAll(filter: SearchFilterExpr = SearchFilterExpr.Empty, + sorting: Option[Sorting] = None, + pagination: Option[Pagination] = None)( + implicit requestContext: AuthenticatedRequestContext): Future[GetListReply] + + def getByEligibilityId(armId: LongId[EligibilityArm])( + implicit requestContext: AuthenticatedRequestContext): Future[GetByIdReply] + + def getBySlotId(armId: LongId[SlotArm], + filter: SearchFilterExpr = SearchFilterExpr.Empty, + sorting: Option[Sorting] = None, + pagination: Option[Pagination] = None)( + implicit requestContext: AuthenticatedRequestContext): Future[GetListReply] + + def create(slotArmId: LongId[SlotArm], draftEligibilityArm: EligibilityArmWithDiseases)( + implicit requestContext: AuthenticatedRequestContext): Future[CreateReply] + + def update(origEligibilityArm: EligibilityArmWithDiseases, draftEligibilityArm: EligibilityArmWithDiseases)( + implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] + + def delete(id: LongId[EligibilityArm])(implicit requestContext: AuthenticatedRequestContext): Future[DeleteReply] +} diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/EligibilityVerificationService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/EligibilityVerificationService.scala index c09dd9a..3788617 100644 --- a/src/main/scala/xyz/driver/pdsuidomain/services/EligibilityVerificationService.scala +++ b/src/main/scala/xyz/driver/pdsuidomain/services/EligibilityVerificationService.scala @@ -6,7 +6,7 @@ import xyz.driver.entities.patient.{CancerType, Patient} import xyz.driver.entities.users.AuthUserInfo import xyz.driver.pdsuicommon.domain.LongId import xyz.driver.pdsuidomain.entities.eligibility.{MatchedPatient, MismatchRankedLabels} -import xyz.driver.pdsuidomain.entities.Arm +import xyz.driver.pdsuidomain.entities.EligibilityArm import scala.concurrent.Future import scalaz.ListT @@ -15,6 +15,8 @@ trait EligibilityVerificationService { def getMatchedPatients()(implicit ctx: AuthorizedServiceRequestContext[AuthUserInfo]): ListT[Future, MatchedPatient] - def getMismatchRankedLabels(patientId: Id[Patient], cancerType: CancerType, excludedArms: Seq[LongId[Arm]])( + def getMismatchRankedLabels(patientId: Id[Patient], + cancerType: CancerType, + excludedArms: Seq[LongId[EligibilityArm]])( implicit ctx: AuthorizedServiceRequestContext[AuthUserInfo]): Future[MismatchRankedLabels] } diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/MedicalRecordService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/MedicalRecordService.scala index 7a0502b..ebcb0f9 100644 --- a/src/main/scala/xyz/driver/pdsuidomain/services/MedicalRecordService.scala +++ b/src/main/scala/xyz/driver/pdsuidomain/services/MedicalRecordService.scala @@ -56,7 +56,11 @@ object MedicalRecordService { sealed trait CreateReply object CreateReply { + type Error = CreateReply with DomainError + final case class Created(x: MedicalRecord) extends CreateReply + + final case class CommonError(userMessage: String) extends CreateReply with DomainError } sealed trait UpdateReply diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/SlotArmService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/SlotArmService.scala new file mode 100644 index 0000000..af7084b --- /dev/null +++ b/src/main/scala/xyz/driver/pdsuidomain/services/SlotArmService.scala @@ -0,0 +1,125 @@ +package xyz.driver.pdsuidomain.services + +import xyz.driver.pdsuicommon.auth.AuthenticatedRequestContext +import xyz.driver.pdsuicommon.db._ +import xyz.driver.pdsuicommon.domain.LongId +import xyz.driver.pdsuicommon.error.DomainError +import xyz.driver.pdsuicommon.logging._ +import xyz.driver.pdsuidomain.entities.SlotArm + +import scala.concurrent.Future + +object SlotArmService { + + trait DefaultAccessDeniedError { + def userMessage: String = "Access denied" + } + + trait DefaultNotFoundError { + def userMessage: String = "SlotArm not found" + } + + sealed trait GetByIdReply + object GetByIdReply { + + final case class Entity(x: SlotArm) extends GetByIdReply + + type Error = GetByIdReply with DomainError + + case object NotFoundError extends GetByIdReply with DefaultNotFoundError with DomainError.NotFoundError + + case object AuthorizationError + extends GetByIdReply with DomainError.AuthorizationError with DefaultAccessDeniedError + + final case class CommonError(userMessage: String)(implicit requestContext: AuthenticatedRequestContext) + extends GetByIdReply with DomainError + } + + sealed trait GetListReply + object GetListReply { + type Error = GetListReply with DomainError + + final case class EntityList(xs: Seq[SlotArm], totalFound: Int) extends GetListReply + + case object AuthorizationError + extends GetListReply with DomainError.AuthorizationError with DefaultAccessDeniedError + } + + sealed trait UpdateReply + object UpdateReply { + + final case class Updated(updated: SlotArm) extends UpdateReply + + type Error = UpdateReply with DomainError + + case object NotFoundError extends UpdateReply with DefaultNotFoundError with DomainError.NotFoundError + + case object AuthorizationError + extends UpdateReply with DefaultAccessDeniedError with DomainError.AuthorizationError + + final case class CommonError(userMessage: String) extends UpdateReply with DomainError + + final case class AlreadyExistsError(x: SlotArm) extends UpdateReply with DomainError { + val userMessage = s"The arm with such name of trial already exists." + } + + implicit def toPhiString(reply: UpdateReply): PhiString = reply match { + case Updated(x) => phi"Updated($x)" + case x: Error => DomainError.toPhiString(x) + } + } + + sealed trait CreateReply + object CreateReply { + final case class Created(x: SlotArm) extends CreateReply + + type Error = CreateReply with DomainError + + case object AuthorizationError + extends CreateReply with DefaultAccessDeniedError with DomainError.AuthorizationError + + final case class CommonError(userMessage: String) extends CreateReply with DomainError + + final case class AlreadyExistsError(x: SlotArm) extends CreateReply with DomainError { + val userMessage = s"The arm with this name of trial already exists." + } + + implicit def toPhiString(reply: CreateReply): PhiString = reply match { + case Created(x) => phi"Created($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 AuthorizationError + extends DeleteReply with DefaultAccessDeniedError with DomainError.AuthorizationError + + final case class CommonError(userMessage: String) extends DeleteReply with DomainError + } +} + +trait SlotArmService { + + import SlotArmService._ + + def getAll(filter: SearchFilterExpr = SearchFilterExpr.Empty, + sorting: Option[Sorting] = None, + pagination: Option[Pagination] = None)( + implicit requestContext: AuthenticatedRequestContext): Future[GetListReply] + + def getById(armId: LongId[SlotArm])(implicit requestContext: AuthenticatedRequestContext): Future[GetByIdReply] + + def create(draftSlotArm: SlotArm)(implicit requestContext: AuthenticatedRequestContext): Future[CreateReply] + + def update(origSlotArm: SlotArm, draftSlotArm: SlotArm)( + implicit requestContext: AuthenticatedRequestContext): Future[UpdateReply] + + def delete(id: LongId[SlotArm])(implicit requestContext: AuthenticatedRequestContext): Future[DeleteReply] +} diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/fake/FakeEligibilityVerificationService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/fake/FakeEligibilityVerificationService.scala index c9b5443..35c518c 100644 --- a/src/main/scala/xyz/driver/pdsuidomain/services/fake/FakeEligibilityVerificationService.scala +++ b/src/main/scala/xyz/driver/pdsuidomain/services/fake/FakeEligibilityVerificationService.scala @@ -7,7 +7,7 @@ import xyz.driver.entities.patient.Patient import xyz.driver.entities.users.AuthUserInfo import xyz.driver.pdsuicommon.domain.LongId import xyz.driver.pdsuidomain.entities.eligibility.MismatchRankedLabels -import xyz.driver.pdsuidomain.entities.{Arm, eligibility} +import xyz.driver.pdsuidomain.entities.{EligibilityArm, eligibility} import xyz.driver.pdsuidomain.services.EligibilityVerificationService import scala.concurrent.Future @@ -22,7 +22,7 @@ class FakeEligibilityVerificationService extends EligibilityVerificationService override def getMismatchRankedLabels(patientId: Id[Patient], cancerType: patient.CancerType, - excludedArms: Seq[LongId[Arm]])( + excludedArms: Seq[LongId[EligibilityArm]])( implicit ctx: AuthorizedServiceRequestContext[AuthUserInfo]): Future[eligibility.MismatchRankedLabels] = Future.successful( MismatchRankedLabels( diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/fake/FakeTrialService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/fake/FakeTrialService.scala index a1efdac..e0efcd1 100644 --- a/src/main/scala/xyz/driver/pdsuidomain/services/fake/FakeTrialService.scala +++ b/src/main/scala/xyz/driver/pdsuidomain/services/fake/FakeTrialService.scala @@ -11,8 +11,8 @@ import xyz.driver.entities.patient.CancerType import xyz.driver.pdsuicommon.auth.AuthenticatedRequestContext import xyz.driver.pdsuicommon.db._ import xyz.driver.pdsuicommon.domain.{LongId, StringId, UuidId} -import xyz.driver.pdsuidomain.entities.{Arm, Criterion, Trial} import xyz.driver.pdsuidomain.entities.export.trial.{ExportTrialArm, ExportTrialLabelCriterion, ExportTrialWithLabels} +import xyz.driver.pdsuidomain.entities.{Criterion, EligibilityArm, Trial} import xyz.driver.pdsuidomain.services.TrialService import scala.concurrent.Future @@ -30,7 +30,6 @@ class FakeTrialService extends TrialService { previousAssignee = None, lastActiveUserId = None, lastUpdate = LocalDateTime.now(), - disease = CancerType.Breast, phase = "", hypothesisId = None, studyDesignId = None, @@ -70,20 +69,20 @@ class FakeTrialService extends TrialService { ExportTrialWithLabels( StringId[Trial]("NCT" + generators.nextInt(999999).toString), UuidId[Trial](generators.nextUuid()), - generators.oneOf("adenocarcinoma", "breast", "prostate"), LocalDateTime.now(), labelVersion = 1L, generators.listOf( new ExportTrialArm( - LongId[Arm](generators.nextInt(999999).toLong), - generators.nextName().value + LongId[EligibilityArm](generators.nextInt(999999).toLong), + generators.nextName().value, + generators.listOf(generators.oneOf("adenocarcinoma", "breast", "prostate")) )), generators.listOf( new ExportTrialLabelCriterion( LongId[Criterion](generators.nextInt(999999).toLong), generators.nextOption(generators.nextBoolean()), LongId[Label](generators.nextInt(999999).toLong), - generators.setOf(LongId[Arm](generators.nextInt(999999).toLong)), + generators.setOf(LongId[EligibilityArm](generators.nextInt(999999).toLong)), generators.nextName().value, generators.nextBoolean(), generators.nextBoolean() diff --git a/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestEligibilityVerificationService.scala b/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestEligibilityVerificationService.scala index 8869106..d727d70 100644 --- a/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestEligibilityVerificationService.scala +++ b/src/main/scala/xyz/driver/pdsuidomain/services/rest/RestEligibilityVerificationService.scala @@ -10,7 +10,7 @@ import xyz.driver.entities.patient.Patient import xyz.driver.entities.users.AuthUserInfo import xyz.driver.pdsuicommon.domain.LongId import xyz.driver.pdsuidomain.entities.eligibility.{MatchedPatient, MismatchRankedLabels} -import xyz.driver.pdsuidomain.entities.{Arm, eligibility} +import xyz.driver.pdsuidomain.entities.{EligibilityArm, eligibility} import xyz.driver.pdsuidomain.services.EligibilityVerificationService import scala.concurrent.{ExecutionContext, Future} @@ -34,7 +34,7 @@ class RestEligibilityVerificationService(transport: ServiceTransport, baseUri: U override def getMismatchRankedLabels(patientId: Id[Patient], cancerType: patient.CancerType, - excludedArms: Seq[LongId[Arm]])( + excludedArms: Seq[LongId[EligibilityArm]])( implicit ctx: AuthorizedServiceRequestContext[AuthUserInfo]): Future[eligibility.MismatchRankedLabels] = { val query = |