diff options
Diffstat (limited to 'src/main/scala/xyz/driver/pdsuidomain')
24 files changed, 526 insertions, 28 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..329c15c --- /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.pdsuicommon.domain.{LongId, StringId} +import xyz.driver.pdsuicommon.logging._ +import xyz.driver.pdsuidomain.entities.Trial.Condition + +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: Condition) + +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 9ccc267..a838d64 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..f9aed6c --- /dev/null +++ b/src/main/scala/xyz/driver/pdsuidomain/entities/SlotArmEligibilityArm.scala @@ -0,0 +1,15 @@ +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 db4def2..bd86057 100644 --- a/src/main/scala/xyz/driver/pdsuidomain/entities/Trial.scala +++ b/src/main/scala/xyz/driver/pdsuidomain/entities/Trial.scala @@ -5,7 +5,7 @@ import java.time.LocalDateTime import xyz.driver.pdsuicommon.domain.{LongId, StringId, User, UuidId} import xyz.driver.pdsuicommon.logging._ import xyz.driver.pdsuicommon.utils.Utils -import xyz.driver.pdsuidomain.entities.Trial.{Condition, Status} +import xyz.driver.pdsuidomain.entities.Trial.Status final case class StudyDesign(id: LongId[StudyDesign], name: String) @@ -86,7 +86,6 @@ final case class Trial(id: StringId[Trial], previousAssignee: Option[StringId[User]], lastActiveUserId: Option[StringId[User]], lastUpdate: LocalDateTime, - condition: Condition, phase: String, hypothesisId: Option[UuidId[Hypothesis]], studyDesignId: Option[LongId[StudyDesign]], 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 9a5022c..86ea765 100644 --- a/src/main/scala/xyz/driver/pdsuidomain/fakes/entities/trialcuration.scala +++ b/src/main/scala/xyz/driver/pdsuidomain/fakes/entities/trialcuration.scala @@ -19,7 +19,6 @@ object trialcuration { previousAssignee = Option(nextStringId[User]), lastActiveUserId = Option(nextStringId[User]), lastUpdate = nextLocalDateTime, - condition = nextCondition, phase = generators.nextString(), hypothesisId = Option(nextUuidId[Hypothesis]), studyDesignId = Option(nextLongId[StudyDesign]), @@ -62,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) @@ -85,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..4d6d0a2 --- /dev/null +++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/eligibilityarm/ApiEligibilityArm.scala @@ -0,0 +1,48 @@ +package xyz.driver.pdsuidomain.formats.json.eligibilityarm + +import play.api.libs.functional.syntax._ +import play.api.libs.json._ +import xyz.driver.pdsuicommon.domain.{LongId, StringId} +import xyz.driver.pdsuidomain.entities.{EligibilityArm, EligibilityArmDisease, EligibilityArmWithDiseases, Trial} + +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 = Trial.Condition.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..6cf71a2 --- /dev/null +++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/eligibilityarm/ApiEligibilityCreateArm.scala @@ -0,0 +1,28 @@ +package xyz.driver.pdsuidomain.formats.json.eligibilityarm + +import xyz.driver.pdsuicommon.domain.{LongId, StringId} +import xyz.driver.pdsuidomain.entities.{EligibilityArm, EligibilityArmDisease, EligibilityArmWithDiseases, Trial} +import play.api.libs.json.{Format, Json} + +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 = Trial.Condition.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..3d9445f --- /dev/null +++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/eligibilityarm/ApiPartialEligibilityArm.scala @@ -0,0 +1,22 @@ +package xyz.driver.pdsuidomain.formats.json.eligibilityarm + +import play.api.libs.json.{Format, Json} +import xyz.driver.pdsuidomain.entities.{EligibilityArmDisease, EligibilityArmWithDiseases, Trial} + +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, + Trial.Condition.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/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/trial.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/trial.scala index 8000a27..aeec90f 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 @@ -41,7 +41,6 @@ object trial { "previousStatus" -> obj.previousStatus.toJson, "previousAssignee" -> obj.previousAssignee.toJson, "lastActiveUser" -> obj.lastActiveUserId.toJson, - "condition" -> obj.condition.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 1b4ac64..fbf506b 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 @@ -16,7 +16,6 @@ final case class ApiTrial(id: String, previousStatus: Option[String], previousAssignee: Option[String], lastActiveUser: Option[String], - condition: String, phase: String, hypothesisId: Option[UUID], studyDesignId: Option[Long], @@ -37,11 +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, - condition = Trial.Condition - .fromString(this.condition) - .getOrElse( - throw new NoSuchElementException(s"unknown condition ${this.condition}") - ), phase = this.phase, hypothesisId = this.hypothesisId.map(id => UuidId(id)), studyDesignId = this.studyDesignId.map(id => LongId(id)), @@ -67,7 +61,6 @@ object ApiTrial { (JsPath \ "previousStatus").formatNullable[String] and (JsPath \ "previousAssignee").formatNullable[String] and (JsPath \ "lastActiveUser").formatNullable[String] and - (JsPath \ "condition").format[String] and (JsPath \ "phase").format[String] and (JsPath \ "hypothesisId").formatNullable[UUID] and (JsPath \ "studyDesignId").formatNullable[Long] and @@ -89,7 +82,6 @@ object ApiTrial { previousAssignee = trial.previousAssignee.map(_.id), lastActiveUser = trial.lastActiveUserId.map(_.id), lastUpdate = ZonedDateTime.of(trial.lastUpdate, ZoneId.of("Z")), - condition = trial.condition.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..e250e8f --- /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 cd62d48..59f300b 100644 --- a/src/main/scala/xyz/driver/pdsuidomain/services/fake/FakeTrialService.scala +++ b/src/main/scala/xyz/driver/pdsuidomain/services/fake/FakeTrialService.scala @@ -29,7 +29,6 @@ class FakeTrialService extends TrialService { previousAssignee = None, lastActiveUserId = None, lastUpdate = LocalDateTime.now(), - condition = Trial.Condition.Breast, phase = "", hypothesisId = None, studyDesignId = None, |