aboutsummaryrefslogtreecommitdiff
path: root/src/main/scala/xyz/driver
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/scala/xyz/driver')
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/entities/Criterion.scala2
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/entities/EligibilityArm.scala42
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/entities/Intervention.scala2
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/entities/SlotArmEligibilityArm.scala13
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/entities/SlotArms.scala20
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/entities/Trial.scala2
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/entities/export/trial/ExportTrialArm.scala6
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/entities/export/trial/ExportTrialLabelCriterion.scala4
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/entities/export/trial/ExportTrialWithLabels.scala3
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/fakes/entities/export.scala11
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/fakes/entities/trialcuration.scala8
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/formats/json/criterion/ApiCriterion.scala4
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/formats/json/criterion/ApiNewCriterion.scala2
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/formats/json/criterion/ApiUpdateCriterion.scala4
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/formats/json/eligibilityarm/ApiEligibilityArm.scala57
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/formats/json/eligibilityarm/ApiEligibilityCreateArm.scala33
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/formats/json/eligibilityarm/ApiPartialEligibilityArm.scala23
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/formats/json/slotarm/ApiPartialSlotArm.scala14
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/formats/json/slotarm/ApiSlotArm.scala35
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/formats/json/slotarm/ApiSlotCreateArm.scala20
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/criterion.scala6
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/eligibilityarm.scala44
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/export.scala19
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/intervention.scala4
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/slotarm.scala44
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/trial.scala4
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/formats/json/trial/ApiTrial.scala11
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/services/CriterionService.scala4
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/services/EligibilityArmService.scala139
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/services/SlotArmService.scala125
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/services/fake/FakeTrialService.scala11
31 files changed, 653 insertions, 63 deletions
diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/Criterion.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/Criterion.scala
index 2432251..26ced22 100644
--- a/src/main/scala/xyz/driver/pdsuidomain/entities/Criterion.scala
+++ b/src/main/scala/xyz/driver/pdsuidomain/entities/Criterion.scala
@@ -30,7 +30,7 @@ object Criterion {
}
}
-final case class CriterionArm(criterionId: LongId[Criterion], armId: LongId[Arm])
+final case class CriterionArm(criterionId: LongId[Criterion], armId: LongId[EligibilityArm])
object CriterionArm {
diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/EligibilityArm.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/EligibilityArm.scala
new file mode 100644
index 0000000..50b49ad
--- /dev/null
+++ b/src/main/scala/xyz/driver/pdsuidomain/entities/EligibilityArm.scala
@@ -0,0 +1,42 @@
+package xyz.driver.pdsuidomain.entities
+
+import java.time.LocalDateTime
+
+import xyz.driver.entities.patient.CancerType
+import xyz.driver.pdsuicommon.domain.{LongId, StringId}
+import xyz.driver.pdsuicommon.logging._
+
+final case class EligibilityArm(id: LongId[EligibilityArm],
+ name: String,
+ originalName: String,
+ trialId: StringId[Trial],
+ deleted: Option[LocalDateTime] = None)
+
+object EligibilityArm {
+
+ implicit def toPhiString(x: EligibilityArm): PhiString = {
+ import x._
+ phi"Arm(id=$id, name=${Unsafe(x.name)}, trialId=${Unsafe(x.trialId)})"
+ }
+}
+
+final case class EligibilityArmDisease(eligibilityArmId: LongId[EligibilityArm], disease: CancerType)
+
+object EligibilityArmDisease {
+
+ implicit def toPhiString(x: EligibilityArmDisease): PhiString = {
+ phi"EligibilityArmDisease(eligibilityArmId=${Unsafe(x.eligibilityArmId)}, disease=${Unsafe(x.disease)})"
+ }
+
+}
+
+final case class EligibilityArmWithDiseases(eligibilityArm: EligibilityArm,
+ eligibilityArmDiseases: Seq[EligibilityArmDisease])
+
+object EligibilityArmWithDiseases {
+
+ implicit def toPhiString(x: EligibilityArmWithDiseases): PhiString = {
+ import x._
+ phi"EligibilityArmWithDiseases(eligibilityArm=$eligibilityArm, eligibilityArmDiseases=$eligibilityArmDiseases)"
+ }
+}
diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/Intervention.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/Intervention.scala
index cc831cd..f02bedc 100644
--- a/src/main/scala/xyz/driver/pdsuidomain/entities/Intervention.scala
+++ b/src/main/scala/xyz/driver/pdsuidomain/entities/Intervention.scala
@@ -188,7 +188,7 @@ object InterventionType {
}
}
-final case class InterventionArm(armId: LongId[Arm], interventionId: LongId[Intervention])
+final case class InterventionArm(armId: LongId[SlotArm], interventionId: LongId[Intervention])
object InterventionArm {
implicit def toPhiString(x: InterventionArm): PhiString = {
diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/SlotArmEligibilityArm.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/SlotArmEligibilityArm.scala
new file mode 100644
index 0000000..70114de
--- /dev/null
+++ b/src/main/scala/xyz/driver/pdsuidomain/entities/SlotArmEligibilityArm.scala
@@ -0,0 +1,13 @@
+package xyz.driver.pdsuidomain.entities
+
+import xyz.driver.pdsuicommon.domain.LongId
+import xyz.driver.pdsuicommon.logging._
+
+final case class SlotArmEligibilityArm(slotArmId: LongId[SlotArm], eligibilityArmId: LongId[EligibilityArm])
+
+object SlotArmEligibilityArm {
+ implicit def toPhiString(x: SlotArmEligibilityArm): PhiString = {
+ import x._
+ phi"SlotArmEligibilityArm(slotArmId=$slotArmId, eligibilityArmId=$eligibilityArmId)"
+ }
+}
diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/SlotArms.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/SlotArms.scala
new file mode 100644
index 0000000..932de38
--- /dev/null
+++ b/src/main/scala/xyz/driver/pdsuidomain/entities/SlotArms.scala
@@ -0,0 +1,20 @@
+package xyz.driver.pdsuidomain.entities
+
+import java.time.LocalDateTime
+
+import xyz.driver.pdsuicommon.domain.{LongId, StringId}
+import xyz.driver.pdsuicommon.logging._
+
+final case class SlotArm(id: LongId[SlotArm],
+ name: String,
+ originalName: String,
+ trialId: StringId[Trial],
+ deleted: Option[LocalDateTime] = None)
+
+object SlotArm {
+
+ implicit def toPhiString(x: SlotArm): PhiString = {
+ import x._
+ phi"Arm(id=$id, name=${Unsafe(x.name)}, trialId=${Unsafe(x.trialId)})"
+ }
+}
diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/Trial.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/Trial.scala
index 7584e9c..ac5feef 100644
--- a/src/main/scala/xyz/driver/pdsuidomain/entities/Trial.scala
+++ b/src/main/scala/xyz/driver/pdsuidomain/entities/Trial.scala
@@ -2,7 +2,6 @@ package xyz.driver.pdsuidomain.entities
import java.time.LocalDateTime
-import xyz.driver.entities.patient.CancerType
import xyz.driver.pdsuicommon.domain.{LongId, StringId, User, UuidId}
import xyz.driver.pdsuicommon.logging._
import xyz.driver.pdsuicommon.utils.Utils
@@ -69,7 +68,6 @@ final case class Trial(id: StringId[Trial],
previousAssignee: Option[StringId[User]],
lastActiveUserId: Option[StringId[User]],
lastUpdate: LocalDateTime,
- disease: CancerType,
phase: String,
hypothesisId: Option[UuidId[Hypothesis]],
studyDesignId: Option[LongId[StudyDesign]],
diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/export/trial/ExportTrialArm.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/export/trial/ExportTrialArm.scala
index 5a9a406..fbac0df 100644
--- a/src/main/scala/xyz/driver/pdsuidomain/entities/export/trial/ExportTrialArm.scala
+++ b/src/main/scala/xyz/driver/pdsuidomain/entities/export/trial/ExportTrialArm.scala
@@ -2,14 +2,14 @@ package xyz.driver.pdsuidomain.entities.export.trial
import xyz.driver.pdsuicommon.domain._
import xyz.driver.pdsuicommon.logging._
-import xyz.driver.pdsuidomain.entities.Arm
+import xyz.driver.pdsuidomain.entities.EligibilityArm
-final case class ExportTrialArm(armId: LongId[Arm], armName: String)
+final case class ExportTrialArm(armId: LongId[EligibilityArm], armName: String, diseaseList: Seq[String])
object ExportTrialArm {
implicit def toPhiString(x: ExportTrialArm): PhiString = {
import x._
- phi"ExportTrialArm(armId=$armId, armName=${Unsafe(armName)})"
+ phi"ExportTrialArm(armId=$armId, armName=${Unsafe(armName)}, diseaseList=${Unsafe(diseaseList)})"
}
}
diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/export/trial/ExportTrialLabelCriterion.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/export/trial/ExportTrialLabelCriterion.scala
index 385bbbe..8376e34 100644
--- a/src/main/scala/xyz/driver/pdsuidomain/entities/export/trial/ExportTrialLabelCriterion.scala
+++ b/src/main/scala/xyz/driver/pdsuidomain/entities/export/trial/ExportTrialLabelCriterion.scala
@@ -3,12 +3,12 @@ package xyz.driver.pdsuidomain.entities.export.trial
import xyz.driver.entities.labels.Label
import xyz.driver.pdsuicommon.domain._
import xyz.driver.pdsuicommon.logging._
-import xyz.driver.pdsuidomain.entities.{Arm, Criterion}
+import xyz.driver.pdsuidomain.entities.{Criterion, EligibilityArm}
final case class ExportTrialLabelCriterion(criterionId: LongId[Criterion],
value: Option[Boolean],
labelId: LongId[Label],
- armIds: Set[LongId[Arm]],
+ armIds: Set[LongId[EligibilityArm]],
criteria: String,
isCompound: Boolean,
isDefining: Boolean)
diff --git a/src/main/scala/xyz/driver/pdsuidomain/entities/export/trial/ExportTrialWithLabels.scala b/src/main/scala/xyz/driver/pdsuidomain/entities/export/trial/ExportTrialWithLabels.scala
index 3a9434b..3681945 100644
--- a/src/main/scala/xyz/driver/pdsuidomain/entities/export/trial/ExportTrialWithLabels.scala
+++ b/src/main/scala/xyz/driver/pdsuidomain/entities/export/trial/ExportTrialWithLabels.scala
@@ -8,7 +8,6 @@ import xyz.driver.pdsuidomain.entities.Trial
final case class ExportTrialWithLabels(nctId: StringId[Trial],
trialId: UuidId[Trial],
- disease: String,
lastReviewed: LocalDateTime,
labelVersion: Long,
arms: List[ExportTrialArm],
@@ -18,7 +17,7 @@ object ExportTrialWithLabels {
implicit def toPhiString(x: ExportTrialWithLabels): PhiString = {
import x._
- phi"TrialWithLabels(nctId=$nctId, trialId=$trialId, disease=${Unsafe(disease)}, " +
+ phi"TrialWithLabels(nctId=$nctId, trialId=$trialId}, " +
phi"lastReviewed=$lastReviewed, labelVersion=${Unsafe(labelVersion)}, arms=$arms, criteria=$criteria)"
}
}
diff --git a/src/main/scala/xyz/driver/pdsuidomain/fakes/entities/export.scala b/src/main/scala/xyz/driver/pdsuidomain/fakes/entities/export.scala
index a3ba562..1fe7533 100644
--- a/src/main/scala/xyz/driver/pdsuidomain/fakes/entities/export.scala
+++ b/src/main/scala/xyz/driver/pdsuidomain/fakes/entities/export.scala
@@ -1,22 +1,24 @@
package xyz.driver.pdsuidomain.fakes.entities
import xyz.driver.entities.labels.Label
-import xyz.driver.pdsuidomain.entities.{Arm, Criterion, Trial}
import xyz.driver.pdsuidomain.entities.export.trial._
+import xyz.driver.pdsuidomain.entities.{Criterion, EligibilityArm, Trial}
object export {
- import xyz.driver.core.generators._
import common._
+ import xyz.driver.core.generators._
def nextExportTrialArm(): ExportTrialArm =
- ExportTrialArm(armId = nextLongId[Arm], armName = nextString(100))
+ ExportTrialArm(armId = nextLongId[EligibilityArm],
+ armName = nextString(100),
+ diseaseList = listOf(nextString(100)))
def nextExportTrialLabelCriterion(): ExportTrialLabelCriterion =
ExportTrialLabelCriterion(
criterionId = nextLongId[Criterion],
value = nextOption[Boolean](nextBoolean()),
labelId = nextLongId[Label],
- armIds = setOf(nextLongId[Arm]),
+ armIds = setOf(nextLongId[EligibilityArm]),
criteria = nextString(100),
isCompound = nextBoolean(),
isDefining = nextBoolean()
@@ -26,7 +28,6 @@ object export {
ExportTrialWithLabels(
nctId = nextStringId[Trial],
trialId = nextUuidId[Trial],
- disease = nextString(100),
lastReviewed = nextLocalDateTime,
labelVersion = nextInt(100).toLong,
arms = listOf(nextExportTrialArm()),
diff --git a/src/main/scala/xyz/driver/pdsuidomain/fakes/entities/trialcuration.scala b/src/main/scala/xyz/driver/pdsuidomain/fakes/entities/trialcuration.scala
index 069d1f1..ade0115 100644
--- a/src/main/scala/xyz/driver/pdsuidomain/fakes/entities/trialcuration.scala
+++ b/src/main/scala/xyz/driver/pdsuidomain/fakes/entities/trialcuration.scala
@@ -1,14 +1,13 @@
package xyz.driver.pdsuidomain.fakes.entities
import xyz.driver.entities.labels.{Label, LabelCategory}
-import xyz.driver.entities.patient.CancerType
import xyz.driver.pdsuicommon.domain.{LongId, User}
import xyz.driver.pdsuidomain.entities._
import xyz.driver.pdsuidomain.services.CriterionService.RichCriterion
object trialcuration {
- import xyz.driver.core.generators
import common._
+ import xyz.driver.core.generators
import xyz.driver.pdsuidomain.entities.InterventionType._
def nextTrial(): Trial = Trial(
@@ -20,7 +19,6 @@ object trialcuration {
previousAssignee = Option(nextStringId[User]),
lastActiveUserId = Option(nextStringId[User]),
lastUpdate = nextLocalDateTime,
- disease = generators.oneOf[CancerType](CancerType.Breast, CancerType.Lung, CancerType.Prostate),
phase = generators.nextString(),
hypothesisId = Option(nextUuidId[Hypothesis]),
studyDesignId = Option(nextLongId[StudyDesign]),
@@ -63,7 +61,7 @@ object trialcuration {
val criterion = nextCriterion()
RichCriterion(
criterion = criterion,
- armIds = Seq(nextLongId[Arm], nextLongId[Arm]),
+ armIds = Seq(nextLongId[EligibilityArm], nextLongId[EligibilityArm]),
labels = Seq(
nextCriterionLabel(criterion.id),
nextCriterionLabel(criterion.id)
@@ -86,7 +84,7 @@ object trialcuration {
def nextInterventionArm(interventionId: LongId[Intervention]): InterventionArm = InterventionArm(
interventionId = interventionId,
- armId = nextLongId[Arm]
+ armId = nextLongId[SlotArm]
)
def nextInterventionWithArms(): InterventionWithArms = {
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 43b5494..239adb1 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
@@ -4,7 +4,7 @@ import xyz.driver.pdsuicommon.json.Serialization.seqJsonFormat
import play.api.libs.functional.syntax._
import play.api.libs.json._
import xyz.driver.pdsuicommon.domain.{LongId, StringId}
-import xyz.driver.pdsuidomain.entities.{Arm, Criterion, Trial}
+import xyz.driver.pdsuidomain.entities.{EligibilityArm, Criterion, Trial}
import xyz.driver.pdsuidomain.formats.json.label.ApiCriterionLabel
import xyz.driver.pdsuidomain.services.CriterionService.RichCriterion
@@ -26,7 +26,7 @@ final case class ApiCriterion(id: Long,
meta.getOrElse(""),
inclusion
),
- armIds = arms.map(LongId[Arm]),
+ armIds = arms.map(LongId[EligibilityArm]),
labels = labels.map(_.toDomain(LongId[Criterion](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 d72a9b4..4b85f83 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
@@ -25,7 +25,7 @@ final case class ApiNewCriterion(meta: Option[String],
text = text,
inclusion = inclusion
),
- armIds = arms.getOrElse(Seq.empty).map(LongId[Arm]),
+ armIds = arms.getOrElse(Seq.empty).map(LongId[EligibilityArm]),
labels = labels.map(_.toDomain(LongId(Long.MaxValue))) // A developer should specify right criterionId himself
)
}
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 77989f0..a700309 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
@@ -2,7 +2,7 @@ package xyz.driver.pdsuidomain.formats.json.criterion
import xyz.driver.pdsuicommon.domain.LongId
import xyz.driver.pdsuicommon.json.Serialization.seqJsonFormat
-import xyz.driver.pdsuidomain.entities.{Arm, Criterion}
+import xyz.driver.pdsuidomain.entities.{EligibilityArm, Criterion}
import org.davidbild.tristate._
import org.davidbild.tristate.contrib.play.ToJsPathOpsFromJsPath
import play.api.libs.functional.syntax._
@@ -19,7 +19,7 @@ final case class ApiUpdateCriterion(meta: Tristate[String],
def applyTo(orig: RichCriterion): RichCriterion = RichCriterion(
criterion = applyTo(orig.criterion),
- armIds = arms.cata(_.map(LongId[Arm]), Seq.empty, orig.armIds),
+ armIds = arms.cata(_.map(LongId[EligibilityArm]), Seq.empty, orig.armIds),
labels = labels.cata(_.map(_.toDomain(orig.criterion.id)), Seq.empty, orig.labels)
)
diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/eligibilityarm/ApiEligibilityArm.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/eligibilityarm/ApiEligibilityArm.scala
new file mode 100644
index 0000000..71423e8
--- /dev/null
+++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/eligibilityarm/ApiEligibilityArm.scala
@@ -0,0 +1,57 @@
+package xyz.driver.pdsuidomain.formats.json.eligibilityarm
+
+import play.api.libs.functional.syntax._
+import play.api.libs.json._
+import xyz.driver.entities.patient.CancerType
+import xyz.driver.pdsuicommon.domain.{LongId, StringId}
+import xyz.driver.pdsuidomain.entities.{EligibilityArm, EligibilityArmDisease, EligibilityArmWithDiseases}
+
+final case class ApiEligibilityArm(id: Long,
+ name: String,
+ originalName: String,
+ trialId: String,
+ diseases: Seq[String]) {
+
+ def toDomain: EligibilityArmWithDiseases = {
+ val eligibilityArm = EligibilityArm(
+ id = LongId(this.id),
+ name = this.name,
+ originalName = this.originalName,
+ trialId = StringId(this.trialId),
+ deleted = None // if we have an ApiEligibilityArm object, the EligibilityArm itself has not been deleted
+ )
+
+ EligibilityArmWithDiseases(
+ eligibilityArm,
+ this.diseases.map { disease =>
+ val condition = CancerType
+ .fromString(disease)
+ .getOrElse(throw new NoSuchElementException(s"unknown condition $disease"))
+ EligibilityArmDisease(eligibilityArm.id, condition)
+ }
+ )
+ }
+}
+
+object ApiEligibilityArm {
+
+ implicit val format: Format[ApiEligibilityArm] = (
+ (JsPath \ "id").format[Long] and
+ (JsPath \ "name").format[String] and
+ (JsPath \ "originalName").format[String] and
+ (JsPath \ "trialId").format[String] and
+ (JsPath \ "diseases").format[Seq[String]]
+ )(ApiEligibilityArm.apply, unlift(ApiEligibilityArm.unapply))
+
+ def fromDomain(eligibilityArmWithDiseases: EligibilityArmWithDiseases): ApiEligibilityArm = {
+ import eligibilityArmWithDiseases.{eligibilityArm, eligibilityArmDiseases}
+
+ ApiEligibilityArm(
+ id = eligibilityArm.id.id,
+ name = eligibilityArm.name,
+ originalName = eligibilityArm.originalName,
+ trialId = eligibilityArm.trialId.id,
+ diseases = eligibilityArmDiseases.map(_.disease.toString)
+ )
+ }
+}
diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/eligibilityarm/ApiEligibilityCreateArm.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/eligibilityarm/ApiEligibilityCreateArm.scala
new file mode 100644
index 0000000..087fed5
--- /dev/null
+++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/eligibilityarm/ApiEligibilityCreateArm.scala
@@ -0,0 +1,33 @@
+package xyz.driver.pdsuidomain.formats.json.eligibilityarm
+
+import play.api.libs.json.{Format, Json}
+import xyz.driver.entities.patient.CancerType
+import xyz.driver.pdsuicommon.domain.{LongId, StringId}
+import xyz.driver.pdsuidomain.entities.{EligibilityArm, EligibilityArmDisease, EligibilityArmWithDiseases}
+
+final case class ApiCreateEligibilityArm(name: String, trialId: String, diseases: Seq[String]) {
+
+ def toDomain: EligibilityArmWithDiseases = {
+ val eligibilityArm = EligibilityArm(
+ id = LongId(0),
+ name = name,
+ trialId = StringId(trialId),
+ originalName = name
+ )
+
+ EligibilityArmWithDiseases(
+ eligibilityArm,
+ diseases.map { disease =>
+ val condition = CancerType
+ .fromString(disease)
+ .getOrElse(throw new NoSuchElementException(s"unknown condition $disease"))
+ EligibilityArmDisease(eligibilityArm.id, condition)
+ }
+ )
+ }
+}
+
+object ApiCreateEligibilityArm {
+
+ implicit val format: Format[ApiCreateEligibilityArm] = Json.format[ApiCreateEligibilityArm]
+}
diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/eligibilityarm/ApiPartialEligibilityArm.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/eligibilityarm/ApiPartialEligibilityArm.scala
new file mode 100644
index 0000000..aca22ef
--- /dev/null
+++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/eligibilityarm/ApiPartialEligibilityArm.scala
@@ -0,0 +1,23 @@
+package xyz.driver.pdsuidomain.formats.json.eligibilityarm
+
+import play.api.libs.json.{Format, Json}
+import xyz.driver.entities.patient.CancerType
+import xyz.driver.pdsuidomain.entities.{EligibilityArmDisease, EligibilityArmWithDiseases}
+
+final case class ApiPartialEligibilityArm(name: String, diseases: Seq[String]) {
+
+ def applyTo(armWithDisease: EligibilityArmWithDiseases): EligibilityArmWithDiseases = {
+ val arm = armWithDisease.eligibilityArm.copy(name = name)
+ val armDiseases = diseases.map { disease =>
+ EligibilityArmDisease(
+ armWithDisease.eligibilityArm.id,
+ CancerType.fromString(disease).getOrElse(throw new NoSuchElementException(s"unknown condition $disease")))
+ }
+ EligibilityArmWithDiseases(arm, armDiseases)
+ }
+}
+
+object ApiPartialEligibilityArm {
+
+ implicit val format: Format[ApiPartialEligibilityArm] = Json.format
+}
diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/slotarm/ApiPartialSlotArm.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/slotarm/ApiPartialSlotArm.scala
new file mode 100644
index 0000000..2f8e93f
--- /dev/null
+++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/slotarm/ApiPartialSlotArm.scala
@@ -0,0 +1,14 @@
+package xyz.driver.pdsuidomain.formats.json.slotarm
+
+import xyz.driver.pdsuidomain.entities.SlotArm
+import play.api.libs.json.{Format, Json}
+
+final case class ApiPartialSlotArm(name: String) {
+
+ def applyTo(arm: SlotArm): SlotArm = arm.copy(name = name)
+}
+
+object ApiPartialSlotArm {
+
+ implicit val format: Format[ApiPartialSlotArm] = Json.format
+}
diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/slotarm/ApiSlotArm.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/slotarm/ApiSlotArm.scala
new file mode 100644
index 0000000..375c1a2
--- /dev/null
+++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/slotarm/ApiSlotArm.scala
@@ -0,0 +1,35 @@
+package xyz.driver.pdsuidomain.formats.json.slotarm
+
+import xyz.driver.pdsuicommon.domain.{LongId, StringId}
+import xyz.driver.pdsuidomain.entities.SlotArm
+import play.api.libs.functional.syntax._
+import play.api.libs.json._
+
+final case class ApiSlotArm(id: Long, name: String, originalName: String, trialId: String) {
+
+ def toDomain: SlotArm = SlotArm(
+ id = LongId(this.id),
+ name = this.name,
+ originalName = this.originalName,
+ trialId = StringId(this.trialId),
+ deleted = None // if we have an ApiSlotArm object, the SlotArm itself has not been deleted
+ )
+
+}
+
+object ApiSlotArm {
+
+ implicit val format: Format[ApiSlotArm] = (
+ (JsPath \ "id").format[Long] and
+ (JsPath \ "name").format[String] and
+ (JsPath \ "originalName").format[String] and
+ (JsPath \ "trialId").format[String]
+ )(ApiSlotArm.apply, unlift(ApiSlotArm.unapply))
+
+ def fromDomain(arm: SlotArm): ApiSlotArm = ApiSlotArm(
+ id = arm.id.id,
+ name = arm.name,
+ originalName = arm.originalName,
+ trialId = arm.trialId.id
+ )
+}
diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/slotarm/ApiSlotCreateArm.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/slotarm/ApiSlotCreateArm.scala
new file mode 100644
index 0000000..3e52c13
--- /dev/null
+++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/slotarm/ApiSlotCreateArm.scala
@@ -0,0 +1,20 @@
+package xyz.driver.pdsuidomain.formats.json.slotarm
+
+import xyz.driver.pdsuicommon.domain.{LongId, StringId}
+import xyz.driver.pdsuidomain.entities.SlotArm
+import play.api.libs.json.{Format, Json}
+
+final case class ApiCreateSlotArm(name: String, trialId: String) {
+
+ def toDomain = SlotArm(
+ id = LongId(0),
+ name = name,
+ trialId = StringId(trialId),
+ originalName = name
+ )
+}
+
+object ApiCreateSlotArm {
+
+ implicit val format: Format[ApiCreateSlotArm] = Json.format[ApiCreateSlotArm]
+}
diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/criterion.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/criterion.scala
index 89c843f..a43e92a 100644
--- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/criterion.scala
+++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/criterion.scala
@@ -80,7 +80,7 @@ object criterion {
val arms = fields
.get("arms")
- .map(_.convertTo[Option[List[LongId[Arm]]]].getOrElse(List.empty[LongId[Arm]]))
+ .map(_.convertTo[Option[List[LongId[EligibilityArm]]]].getOrElse(List.empty[LongId[EligibilityArm]]))
.getOrElse(orig.armIds)
val labels = fields
@@ -143,8 +143,8 @@ object criterion {
val arms = fields
.get("arms")
- .map(_.convertTo[List[LongId[Arm]]])
- .getOrElse(List.empty[LongId[Arm]])
+ .map(_.convertTo[List[LongId[EligibilityArm]]])
+ .getOrElse(List.empty[LongId[EligibilityArm]])
val labels = fields
.get("labels")
diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/eligibilityarm.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/eligibilityarm.scala
new file mode 100644
index 0000000..acb790a
--- /dev/null
+++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/eligibilityarm.scala
@@ -0,0 +1,44 @@
+package xyz.driver.pdsuidomain.formats.json.sprayformats
+
+import spray.json._
+import xyz.driver.pdsuicommon.domain.{LongId, StringId}
+import xyz.driver.pdsuidomain.entities.{EligibilityArm, Trial}
+
+object eligibilityarm {
+ import DefaultJsonProtocol._
+ import common._
+
+ def applyUpdateToArm(json: JsValue, orig: EligibilityArm): EligibilityArm = json match {
+ case JsObject(fields) =>
+ val name = fields
+ .get("name")
+ .map(_.convertTo[String])
+ .getOrElse(deserializationError(s"Arm json object does not contain `name` field: $json"))
+ orig.copy(name = name)
+
+ case _ => deserializationError(s"Expected Json Object as partial Arm, but got $json")
+ }
+
+ def eligibilityArmFormat: RootJsonFormat[EligibilityArm] = new RootJsonFormat[EligibilityArm] {
+ override def write(obj: EligibilityArm): JsValue =
+ JsObject(
+ "id" -> obj.id.toJson,
+ "name" -> obj.name.toJson,
+ "originalName" -> obj.originalName.toJson,
+ "trialId" -> obj.trialId.toJson
+ )
+
+ override def read(json: JsValue): EligibilityArm = json.asJsObject.getFields("trialId", "name") match {
+ case Seq(trialId, name) =>
+ EligibilityArm(
+ id = LongId(0),
+ name = name.convertTo[String],
+ trialId = trialId.convertTo[StringId[Trial]],
+ originalName = name.convertTo[String]
+ )
+
+ case _ => deserializationError(s"Expected Json Object as Arm, but got $json")
+ }
+ }
+
+}
diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/export.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/export.scala
index 85d614d..4391453 100644
--- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/export.scala
+++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/export.scala
@@ -2,16 +2,16 @@ package xyz.driver.pdsuidomain.formats.json.sprayformats
import spray.json._
import xyz.driver.entities.labels.Label
-import xyz.driver.pdsuidomain.entities.{Arm, Criterion}
+import xyz.driver.formats.json.labels._
import xyz.driver.pdsuidomain.entities.export.patient._
import xyz.driver.pdsuidomain.entities.export.trial.{ExportTrialArm, ExportTrialLabelCriterion, ExportTrialWithLabels}
-import xyz.driver.formats.json.labels._
+import xyz.driver.pdsuidomain.entities.{Criterion, EligibilityArm}
object export {
import DefaultJsonProtocol._
import common._
- import record._
import document._
+ import record._
implicit val patientLabelEvidenceDocumentFormat: RootJsonFormat[ExportPatientLabelEvidenceDocument] =
jsonFormat5(ExportPatientLabelEvidenceDocument.apply)
@@ -25,7 +25,7 @@ object export {
implicit val patientWithLabelsFormat: RootJsonFormat[ExportPatientWithLabels] =
jsonFormat(ExportPatientWithLabels.apply, "patientId", "labelVersion", "labels")
- implicit val trialArmFormat: RootJsonFormat[ExportTrialArm] = jsonFormat2(ExportTrialArm.apply)
+ implicit val trialArmFormat: RootJsonFormat[ExportTrialArm] = jsonFormat3(ExportTrialArm.apply)
implicit val trialLabelCriterionFormat: RootJsonFormat[ExportTrialLabelCriterion] =
new RootJsonFormat[ExportTrialLabelCriterion] {
@@ -68,7 +68,7 @@ object export {
longIdFormat[Criterion].read(criterionId),
value,
longIdFormat[Label].read(labelId),
- armIdsVector.map(longIdFormat[Arm].read).toSet,
+ armIdsVector.map(longIdFormat[EligibilityArm].read).toSet,
criterionText,
isCompound,
isDefining
@@ -82,12 +82,5 @@ object export {
}
implicit val trialWithLabelsFormat: RootJsonFormat[ExportTrialWithLabels] =
- jsonFormat(ExportTrialWithLabels.apply,
- "nctId",
- "trialId",
- "disease",
- "lastReviewed",
- "labelVersion",
- "arms",
- "criteria")
+ jsonFormat(ExportTrialWithLabels.apply, "nctId", "trialId", "lastReviewed", "labelVersion", "arms", "criteria")
}
diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/intervention.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/intervention.scala
index 62cb9fa..2ced434 100644
--- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/intervention.scala
+++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/intervention.scala
@@ -56,7 +56,7 @@ object intervention {
val arms = fields
.get("arms")
- .map(_.convertTo[List[LongId[Arm]]].map(x => InterventionArm(armId = x, interventionId = LongId(0))))
+ .map(_.convertTo[List[LongId[SlotArm]]].map(x => InterventionArm(armId = x, interventionId = LongId(0))))
.getOrElse(List.empty[InterventionArm])
InterventionWithArms(
@@ -104,7 +104,7 @@ object intervention {
val origIntervention = orig.intervention
val arms = fields
.get("arms")
- .map(_.convertTo[List[LongId[Arm]]].map(x => InterventionArm(x, orig.intervention.id)))
+ .map(_.convertTo[List[LongId[SlotArm]]].map(x => InterventionArm(x, orig.intervention.id)))
orig.copy(
intervention = origIntervention.copy(
diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/slotarm.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/slotarm.scala
new file mode 100644
index 0000000..192bd6a
--- /dev/null
+++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/slotarm.scala
@@ -0,0 +1,44 @@
+package xyz.driver.pdsuidomain.formats.json.sprayformats
+
+import spray.json._
+import xyz.driver.pdsuicommon.domain.{LongId, StringId}
+import xyz.driver.pdsuidomain.entities.{SlotArm, Trial}
+
+object slotarm {
+ import DefaultJsonProtocol._
+ import common._
+
+ def applyUpdateToArm(json: JsValue, orig: SlotArm): SlotArm = json match {
+ case JsObject(fields) =>
+ val name = fields
+ .get("name")
+ .map(_.convertTo[String])
+ .getOrElse(deserializationError(s"Arm json object does not contain `name` field: $json"))
+ orig.copy(name = name)
+
+ case _ => deserializationError(s"Expected Json Object as partial Arm, but got $json")
+ }
+
+ def slotArmFormat: RootJsonFormat[SlotArm] = new RootJsonFormat[SlotArm] {
+ override def write(obj: SlotArm): JsValue =
+ JsObject(
+ "id" -> obj.id.toJson,
+ "name" -> obj.name.toJson,
+ "originalName" -> obj.originalName.toJson,
+ "trialId" -> obj.trialId.toJson
+ )
+
+ override def read(json: JsValue): SlotArm = json.asJsObject.getFields("trialId", "name") match {
+ case Seq(trialId, name) =>
+ SlotArm(
+ id = LongId(0),
+ name = name.convertTo[String],
+ trialId = trialId.convertTo[StringId[Trial]],
+ originalName = name.convertTo[String]
+ )
+
+ case _ => deserializationError(s"Expected Json Object as Arm, but got $json")
+ }
+ }
+
+}
diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/trial.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/trial.scala
index d851c2c..b25ed1d 100644
--- a/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/trial.scala
+++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/trial.scala
@@ -6,12 +6,11 @@ import spray.json._
import xyz.driver.core.json.EnumJsonFormat
import xyz.driver.pdsuicommon.domain.{LongId, UuidId}
import xyz.driver.pdsuidomain.entities._
-import xyz.driver.formats.json.patient._
object trial {
import DefaultJsonProtocol._
- import common._
import Trial._
+ import common._
implicit val trialStatusFormat = new EnumJsonFormat[Status](
"New" -> Status.New,
@@ -36,7 +35,6 @@ object trial {
"previousStatus" -> obj.previousStatus.toJson,
"previousAssignee" -> obj.previousAssignee.toJson,
"lastActiveUser" -> obj.lastActiveUserId.toJson,
- "disease" -> obj.disease.toJson,
"phase" -> obj.phase.toJson,
"hypothesisId" -> obj.hypothesisId.toJson,
"studyDesignId" -> obj.studyDesignId.toJson,
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 a2a1ca9..133a2c8 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
@@ -3,11 +3,10 @@ package xyz.driver.pdsuidomain.formats.json.trial
import java.time.{ZoneId, ZonedDateTime}
import java.util.UUID
-import xyz.driver.pdsuicommon.domain.{LongId, StringId, UuidId}
-import xyz.driver.pdsuidomain.entities.Trial
import play.api.libs.functional.syntax._
import play.api.libs.json._
-import xyz.driver.entities.patient.CancerType
+import xyz.driver.pdsuicommon.domain.{LongId, StringId, UuidId}
+import xyz.driver.pdsuidomain.entities.Trial
final case class ApiTrial(id: String,
externalId: UUID,
@@ -17,7 +16,6 @@ final case class ApiTrial(id: String,
previousStatus: Option[String],
previousAssignee: Option[String],
lastActiveUser: Option[String],
- disease: String,
phase: String,
hypothesisId: Option[UUID],
studyDesignId: Option[Long],
@@ -38,9 +36,6 @@ final case class ApiTrial(id: String,
previousAssignee = this.previousAssignee.map(id => StringId(id)),
lastActiveUserId = this.lastActiveUser.map(id => StringId(id)),
lastUpdate = this.lastUpdate.toLocalDateTime,
- disease = CancerType
- .fromString(this.disease)
- .getOrElse(throw new NoSuchElementException(s"Unknown disease ${this.disease}")),
phase = this.phase,
hypothesisId = this.hypothesisId.map(id => UuidId(id)),
studyDesignId = this.studyDesignId.map(id => LongId(id)),
@@ -66,7 +61,6 @@ object ApiTrial {
(JsPath \ "previousStatus").formatNullable[String] and
(JsPath \ "previousAssignee").formatNullable[String] and
(JsPath \ "lastActiveUser").formatNullable[String] and
- (JsPath \ "disease").format[String] and
(JsPath \ "phase").format[String] and
(JsPath \ "hypothesisId").formatNullable[UUID] and
(JsPath \ "studyDesignId").formatNullable[Long] and
@@ -88,7 +82,6 @@ object ApiTrial {
previousAssignee = trial.previousAssignee.map(_.id),
lastActiveUser = trial.lastActiveUserId.map(_.id),
lastUpdate = ZonedDateTime.of(trial.lastUpdate, ZoneId.of("Z")),
- disease = trial.disease.toString,
phase = trial.phase,
hypothesisId = trial.hypothesisId.map(_.id),
studyDesignId = trial.studyDesignId.map(_.id),
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/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/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()