aboutsummaryrefslogtreecommitdiff
path: root/src/main
diff options
context:
space:
mode:
Diffstat (limited to 'src/main')
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/arm.scala44
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/bridgeuploadqueue.scala68
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/common.scala74
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/criterion.scala158
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/document.scala164
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/documenthistory.scala29
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/documentissue.scala77
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/export.scala78
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/extracteddata.scala148
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/hypothesis.scala12
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/intervention.scala60
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/patient.scala46
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/patientcriterion.scala68
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/patientdefiningcriteria.scala18
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/patienteligibletrial.scala39
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/patienthistory.scala30
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/patienthypothesis.scala37
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/patientissue.scala54
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/patientlabel.scala64
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/record.scala237
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/recordhistory.scala30
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/recordissue.scala79
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/studydesign.scala12
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/trial.scala90
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/trialhistory.scala30
-rw-r--r--src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/trialissue.scala60
26 files changed, 1806 insertions, 0 deletions
diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/arm.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/arm.scala
new file mode 100644
index 0000000..39af1c3
--- /dev/null
+++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/arm.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._
+
+object arm {
+ import DefaultJsonProtocol._
+ import common._
+
+ def applyUpdateToArm(json: JsValue, orig: Arm): Arm = 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 armFormat: RootJsonFormat[Arm] = new RootJsonFormat[Arm] {
+ override def write(obj: Arm): JsValue =
+ JsObject(
+ "id" -> obj.id.toJson,
+ "name" -> obj.name.toJson,
+ "originalName" -> obj.originalName.toJson,
+ "trialId" -> obj.trialId.toJson
+ )
+
+ override def read(json: JsValue): Arm = json.asJsObject.getFields("trialId", "name") match {
+ case Seq(trialId, name) =>
+ Arm(
+ 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/bridgeuploadqueue.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/bridgeuploadqueue.scala
new file mode 100644
index 0000000..77fb4d2
--- /dev/null
+++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/bridgeuploadqueue.scala
@@ -0,0 +1,68 @@
+package xyz.driver.pdsuidomain.formats.json.sprayformats
+
+import java.time.LocalDateTime
+
+import spray.json._
+import xyz.driver.pdsuicommon.concurrent.BridgeUploadQueue
+import xyz.driver.pdsuicommon.concurrent.BridgeUploadQueue.Item
+
+object bridgeuploadqueue {
+ import DefaultJsonProtocol._
+ import common._
+
+ implicit val queueUploadItemFormat: RootJsonFormat[BridgeUploadQueue.Item] = new RootJsonFormat[Item] {
+ override def write(obj: Item) =
+ JsObject(
+ "kind" -> obj.kind.toJson,
+ "tag" -> obj.tag.toJson,
+ "created" -> obj.created.toJson,
+ "attempts" -> obj.attempts.toJson,
+ "nextAttempt" -> obj.nextAttempt.toJson,
+ "completed" -> obj.completed.toJson
+ )
+
+ override def read(json: JsValue): Item = json match {
+ case JsObject(fields) =>
+ val kind = fields
+ .get("kind")
+ .map(_.convertTo[String])
+ .getOrElse(deserializationError(s"BridgeUploadQueue.Item json object does not contain `kind` field: $json"))
+
+ val tag = fields
+ .get("tag")
+ .map(_.convertTo[String])
+ .getOrElse(deserializationError(s"BridgeUploadQueue.Item json object does not contain `tag` field: $json"))
+
+ val created = fields
+ .get("created")
+ .map(_.convertTo[LocalDateTime])
+ .getOrElse(
+ deserializationError(s"BridgeUploadQueue.Item json object does not contain `created` field: $json"))
+
+ val attempts = fields
+ .get("attempts")
+ .map(_.convertTo[Int])
+ .getOrElse(
+ deserializationError(s"BridgeUploadQueue.Item json object does not contain `attempts` field: $json"))
+
+ val nextAttempt = fields
+ .get("nextAttempt")
+ .map(_.convertTo[LocalDateTime])
+ .getOrElse(
+ deserializationError(s"BridgeUploadQueue.Item json object does not contain `nextAttempt` field: $json"))
+
+ BridgeUploadQueue.Item(
+ kind = kind,
+ tag = tag,
+ created = created,
+ attempts = attempts,
+ nextAttempt = nextAttempt,
+ completed = true,
+ dependencyKind = None,
+ dependencyTag = None
+ )
+
+ case _ => deserializationError(s"Expected Json Object as BridgeUploadQueue.Item, but got $json")
+ }
+ }
+}
diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/common.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/common.scala
new file mode 100644
index 0000000..dbd0a43
--- /dev/null
+++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/common.scala
@@ -0,0 +1,74 @@
+package xyz.driver.pdsuidomain.formats.json.sprayformats
+
+import java.time.{LocalDate, LocalDateTime, ZoneId, ZonedDateTime}
+
+import spray.json._
+import xyz.driver.pdsuicommon.domain.{FuzzyValue, LongId, StringId, UuidId}
+
+object common {
+
+ implicit def longIdFormat[T] = new RootJsonFormat[LongId[T]] {
+ override def write(id: LongId[T]): JsNumber = JsNumber(id.id)
+ override def read(json: JsValue): LongId[T] = json match {
+ case JsNumber(value) => LongId(value.toLong)
+ case _ => deserializationError(s"Expected number as LongId, but got $json")
+ }
+ }
+
+ implicit def stringIdFormat[T] = new RootJsonFormat[StringId[T]] {
+ override def write(id: StringId[T]): JsString = JsString(id.toString)
+ override def read(json: JsValue): StringId[T] = json match {
+ case JsString(value) => StringId(value)
+ case _ => deserializationError(s"Expected string as StringId, but got $json")
+ }
+ }
+
+ implicit def uuidIdFormat[T] = new RootJsonFormat[UuidId[T]] {
+ override def write(id: UuidId[T]): JsString = JsString(id.toString)
+ override def read(json: JsValue): UuidId[T] = json match {
+ case JsString(value) => UuidId(value)
+ case _ => deserializationError(s"Expected string as UuidId, but got $json")
+ }
+ }
+
+ implicit def dateTimeFormat = new RootJsonFormat[LocalDateTime] {
+ override def write(date: LocalDateTime): JsString = JsString(ZonedDateTime.of(date, ZoneId.of("Z")).toString)
+ override def read(json: JsValue): LocalDateTime = json match {
+ case JsString(value) => ZonedDateTime.parse(value).toLocalDateTime
+ case _ => deserializationError(s"Expected date as LocalDateTime, but got $json")
+ }
+ }
+
+ implicit def zonedDateTimeFormat = new RootJsonFormat[ZonedDateTime] {
+ override def write(date: ZonedDateTime): JsString = JsString(date.toString)
+ override def read(json: JsValue): ZonedDateTime = json match {
+ case JsString(value) => ZonedDateTime.parse(value)
+ case _ => deserializationError(s"Expected date as ZonedDateTime, but got $json")
+ }
+ }
+
+ implicit def dateFormat = new RootJsonFormat[LocalDate] {
+ override def write(date: LocalDate): JsString = JsString(date.toString)
+ override def read(json: JsValue): LocalDate = json match {
+ case JsString(value) => LocalDate.parse(value)
+ case _ => deserializationError(s"Expected date as LocalDate, but got $json")
+ }
+ }
+
+ implicit def fuzzyValueFormat: RootJsonFormat[FuzzyValue] = new RootJsonFormat[FuzzyValue] {
+ override def write(value: FuzzyValue): JsString = JsString(FuzzyValue.valueToString(value))
+ override def read(json: JsValue): FuzzyValue = json match {
+ case JsString(value) => FuzzyValue.fromString(value)
+ case _ => deserializationError(s"Expected value as FuzzyValue, but got $json")
+ }
+ }
+
+ implicit val integerFormat: RootJsonFormat[Integer] = new RootJsonFormat[Integer] {
+ override def write(obj: Integer): JsNumber = JsNumber(obj.intValue())
+ override def read(json: JsValue): Integer = json match {
+ case JsNumber(value) => value.toInt
+ case _ => deserializationError(s"Expected number as Integer, but got $json")
+ }
+ }
+
+}
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
new file mode 100644
index 0000000..732bcad
--- /dev/null
+++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/criterion.scala
@@ -0,0 +1,158 @@
+package xyz.driver.pdsuidomain.formats.json.sprayformats
+
+import spray.json._
+import xyz.driver.pdsuicommon.domain.{LongId, StringId}
+import xyz.driver.pdsuidomain.entities._
+import xyz.driver.pdsuidomain.services.CriterionService.RichCriterion
+
+object criterion {
+ import DefaultJsonProtocol._
+ import common._
+
+ implicit val criterionLabelWriter = new JsonWriter[CriterionLabel] {
+ override def write(obj: CriterionLabel) = JsObject(
+ "labelId" -> obj.labelId.toJson,
+ "categoryId" -> obj.categoryId.toJson,
+ "value" -> obj.value.map {
+ case true => "Yes"
+ case false => "No"
+ }.toJson,
+ "isDefining" -> obj.isDefining.toJson
+ )
+ }
+
+ def jsValueToCriterionLabel(json: JsValue, criterionId: LongId[Criterion]): CriterionLabel = json match {
+ case JsObject(fields) =>
+ val labelId = fields
+ .get("labelId")
+ .map(_.convertTo[LongId[Label]])
+
+ val categoryId = fields
+ .get("categoryId")
+ .map(_.convertTo[LongId[Category]])
+
+ val value = fields
+ .get("value")
+ .map(_.convertTo[String] match {
+ case "Yes" => true
+ case "No" => false
+ case other =>
+ deserializationError(s"Unknown `value` of CriterionLabel object: expected `yes` or `no`, but got $other")
+ })
+
+ val isDefining = fields
+ .get("isDefining")
+ .map(_.convertTo[Boolean])
+ .getOrElse(deserializationError(s"CriterionLabel json object does not contain `isDefining` field: $json"))
+
+ CriterionLabel(
+ id = LongId(0L),
+ labelId = labelId,
+ criterionId = criterionId,
+ categoryId = categoryId,
+ value = value,
+ isDefining = isDefining
+ )
+
+ case _ => deserializationError(s"Expected Json Object as CriterionLabel, but got $json")
+ }
+
+ def applyUpdateToCriterion(json: JsValue, orig: RichCriterion): RichCriterion = json match {
+ case JsObject(fields) =>
+ val text = fields
+ .get("text")
+ .map(_.convertTo[String])
+
+ val isCompound = fields
+ .get("isCompound")
+ .exists(_.convertTo[Boolean])
+
+ val meta = fields
+ .get("meta")
+ .map(_.convertTo[Option[String]].getOrElse("{}"))
+ .getOrElse(orig.criterion.meta)
+
+ val arms = fields
+ .get("arms")
+ .map(_.convertTo[Option[List[LongId[Arm]]]].getOrElse(List.empty[LongId[Arm]]))
+ .getOrElse(orig.armIds)
+
+ val labels = fields
+ .get("labels")
+ .map(_.convertTo[Option[List[JsValue]]].getOrElse(List.empty[JsValue]))
+ .map(_.map(l => jsValueToCriterionLabel(l, orig.criterion.id)))
+ .getOrElse(orig.labels)
+
+ orig.copy(
+ criterion = orig.criterion.copy(
+ meta = meta,
+ text = text,
+ isCompound = isCompound
+ ),
+ armIds = arms,
+ labels = labels
+ )
+
+ case _ => deserializationError(s"Expected Json Object as partial Criterion, but got $json")
+ }
+
+ val richCriterionFormat = new RootJsonFormat[RichCriterion] {
+ override def write(obj: RichCriterion): JsValue =
+ JsObject(
+ "id" -> obj.criterion.id.toJson,
+ "meta" -> Option(obj.criterion.meta).toJson,
+ "arms" -> obj.armIds.toJson,
+ "text" -> obj.criterion.text.toJson,
+ "isCompound" -> obj.criterion.isCompound.toJson,
+ "labels" -> obj.labels.map(_.toJson).toJson,
+ "trialId" -> obj.criterion.trialId.toJson
+ )
+
+ override def read(json: JsValue): RichCriterion = json match {
+ case JsObject(fields) =>
+ val trialId = fields
+ .get("trialId")
+ .map(_.convertTo[StringId[Trial]])
+ .getOrElse(deserializationError(s"Criterion json object does not contain `trialId` field: $json"))
+
+ val text = fields
+ .get("text")
+ .map(_.convertTo[String])
+
+ val isCompound = fields
+ .get("isCompound")
+ .exists(_.convertTo[Boolean])
+
+ val meta = fields
+ .get("meta")
+ .map(_.convertTo[String])
+ .getOrElse("")
+
+ val arms = fields
+ .get("arms")
+ .map(_.convertTo[List[LongId[Arm]]])
+ .getOrElse(List.empty[LongId[Arm]])
+
+ val labels = fields
+ .get("labels")
+ .map(_.convertTo[List[JsValue]])
+ .map(_.map(l => jsValueToCriterionLabel(l, LongId(0))))
+ .getOrElse(List.empty[CriterionLabel])
+
+ RichCriterion(
+ criterion = Criterion(
+ id = LongId(0),
+ trialId = trialId,
+ text = text,
+ isCompound = isCompound,
+ meta = meta
+ ),
+ armIds = arms,
+ labels = labels
+ )
+
+ case _ => deserializationError(s"Expected Json Object as Criterion, but got $json")
+ }
+ }
+
+}
diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/document.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/document.scala
new file mode 100644
index 0000000..baf1b4e
--- /dev/null
+++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/document.scala
@@ -0,0 +1,164 @@
+package xyz.driver.pdsuidomain.formats.json.sprayformats
+
+import java.time.{LocalDate, LocalDateTime}
+
+import spray.json._
+import xyz.driver.core.json.EnumJsonFormat
+import xyz.driver.pdsuicommon.domain.{LongId, TextJson}
+import xyz.driver.pdsuidomain.entities._
+
+object document {
+ import DefaultJsonProtocol._
+ import Document._
+ import common._
+
+ implicit val documentStatusFormat = new EnumJsonFormat[Status](
+ "New" -> Status.New,
+ "Organized" -> Status.Organized,
+ "Extracted" -> Status.Extracted,
+ "Done" -> Status.Done,
+ "Flagged" -> Status.Flagged,
+ "Archived" -> Status.Archived
+ )
+
+ implicit val requiredTypeFormat = new EnumJsonFormat[RequiredType](
+ "OPN" -> RequiredType.OPN,
+ "PN" -> RequiredType.PN
+ )
+
+ implicit val documentMetaFormat: RootJsonFormat[Meta] = jsonFormat3(Meta.apply)
+
+ implicit val fullDocumentMetaFormat = new RootJsonFormat[TextJson[Meta]] {
+ override def write(obj: TextJson[Meta]): JsValue = obj.content.toJson
+ override def read(json: JsValue) = TextJson(documentMetaFormat.read(json))
+ }
+
+ def applyUpdateToDocument(json: JsValue, orig: Document): Document = json match {
+ case JsObject(fields) =>
+ val physician = fields
+ .get("physician")
+ .map(_.convertTo[String])
+
+ val typeId = fields
+ .get("typeId")
+ .map(_.convertTo[Option[LongId[DocumentType]]])
+ .getOrElse(orig.typeId)
+
+ val provider = fields
+ .get("provider")
+ .map(_.convertTo[Option[String]])
+ .getOrElse(orig.providerName)
+
+ val providerTypeId = fields
+ .get("providerTypeId")
+ .map(_.convertTo[Option[LongId[ProviderType]]])
+ .getOrElse(orig.providerTypeId)
+
+ val meta = fields
+ .get("meta")
+ .map(_.convertTo[Option[TextJson[Meta]]])
+ .getOrElse(orig.meta)
+
+ val startDate = fields
+ .get("startDate")
+ .map(_.convertTo[Option[LocalDate]])
+ .getOrElse(orig.startDate)
+
+ val endDate = fields
+ .get("endDate")
+ .map(_.convertTo[Option[LocalDate]])
+ .getOrElse(orig.endDate)
+
+ orig.copy(
+ physician = physician.orElse(orig.physician),
+ typeId = typeId,
+ providerName = provider,
+ providerTypeId = providerTypeId,
+ meta = meta,
+ startDate = startDate,
+ endDate = endDate
+ )
+
+ case _ => deserializationError(s"Expected Json Object as partial Document, but got $json")
+ }
+
+ implicit val documentFormat: RootJsonFormat[Document] = new RootJsonFormat[Document] {
+ override def write(document: Document): JsValue =
+ JsObject(
+ "id" -> document.id.id.toJson,
+ "recordId" -> document.recordId.toJson,
+ "physician" -> document.physician.toJson,
+ "typeId" -> document.typeId.toJson,
+ "provider" -> document.providerName.toJson,
+ "providerTypeId" -> document.providerTypeId.toJson,
+ "requiredType" -> document.requiredType.toJson,
+ "startDate" -> document.startDate.toJson,
+ "endDate" -> document.endDate.toJson,
+ "status" -> document.status.toJson,
+ "previousStatus" -> document.previousStatus.toJson,
+ "assignee" -> document.assignee.toJson,
+ "previousAssignee" -> document.previousAssignee.toJson,
+ "meta" -> document.meta.toJson,
+ "lastActiveUser" -> document.lastActiveUserId.toJson,
+ "lastUpdate" -> document.lastUpdate.toJson
+ )
+
+ override def read(json: JsValue): Document = json match {
+ case JsObject(fields) =>
+ val recordId = fields
+ .get("recordId")
+ .map(_.convertTo[LongId[MedicalRecord]])
+ .getOrElse(deserializationError(s"Document create json object does not contain `recordId` field: $json"))
+
+ val physician = fields
+ .get("physician")
+ .map(_.convertTo[String])
+
+ val typeId = fields
+ .get("typeId")
+ .map(_.convertTo[LongId[DocumentType]])
+
+ val provider = fields
+ .get("provider")
+ .map(_.convertTo[String])
+
+ val providerTypeId = fields
+ .get("providerTypeId")
+ .map(_.convertTo[LongId[ProviderType]])
+
+ val meta = fields
+ .get("meta")
+ .map(_.convertTo[TextJson[Meta]])
+
+ val startDate = fields
+ .get("startDate")
+ .map(_.convertTo[LocalDate])
+
+ val endDate = fields
+ .get("endDate")
+ .map(_.convertTo[LocalDate])
+
+ Document(
+ id = LongId(0),
+ recordId = recordId,
+ status = Document.Status.New,
+ physician = physician,
+ typeId = typeId,
+ startDate = startDate,
+ endDate = endDate,
+ providerName = provider,
+ providerTypeId = providerTypeId,
+ requiredType = None,
+ meta = meta,
+ previousStatus = None,
+ assignee = None,
+ previousAssignee = None,
+ lastActiveUserId = None,
+ lastUpdate = LocalDateTime.MIN
+ )
+
+ case _ => deserializationError(s"Expected Json Object as Document, but got $json")
+ }
+ }
+
+}
diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/documenthistory.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/documenthistory.scala
new file mode 100644
index 0000000..419c252
--- /dev/null
+++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/documenthistory.scala
@@ -0,0 +1,29 @@
+package xyz.driver.pdsuidomain.formats.json.sprayformats
+
+import spray.json._
+import xyz.driver.core.json.EnumJsonFormat
+import xyz.driver.pdsuidomain.entities._
+
+object documenthistory {
+ import DefaultJsonProtocol._
+ import common._
+ import DocumentHistory._
+
+ implicit val documentStateFormat = new EnumJsonFormat[State](
+ "Extract" -> State.Extract,
+ "Review" -> State.Review,
+ "Flag" -> State.Flag
+ )
+
+ implicit val documentActionFormat = new EnumJsonFormat[Action](
+ "Start" -> Action.Start,
+ "Submit" -> Action.Submit,
+ "Unassign" -> Action.Unassign,
+ "Resolve" -> Action.Resolve,
+ "Flag" -> Action.Flag,
+ "Archive" -> Action.Archive
+ )
+
+ implicit val documentHistoryFormat: RootJsonFormat[DocumentHistory] = jsonFormat6(DocumentHistory.apply)
+
+}
diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/documentissue.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/documentissue.scala
new file mode 100644
index 0000000..28b2a5e
--- /dev/null
+++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/documentissue.scala
@@ -0,0 +1,77 @@
+package xyz.driver.pdsuidomain.formats.json.sprayformats
+
+import java.time.LocalDateTime
+
+import spray.json._
+import xyz.driver.pdsuicommon.domain.{LongId, StringId, User}
+import xyz.driver.pdsuidomain.entities._
+
+object documentissue {
+ import DefaultJsonProtocol._
+ import common._
+
+ def applyUpdateToDocumentIssue(json: JsValue, orig: DocumentIssue): DocumentIssue = json match {
+ case JsObject(fields) =>
+ val text = fields
+ .get("text")
+ .map(_.convertTo[String])
+ .getOrElse(deserializationError(s"DocumentIssue json object does not contain `text` field: $json"))
+
+ val archiveRequired = fields
+ .get("archiveRequired")
+ .map(_.convertTo[Boolean])
+ .getOrElse(deserializationError(s"DocumentIssue json object does not contain `archiveRequired` field: $json"))
+
+ val startPage = fields.get("startPage").map(_.convertTo[Double])
+ val endPage = fields.get("endPage").map(_.convertTo[Double])
+
+ orig.copy(
+ text = text,
+ archiveRequired = archiveRequired,
+ startPage = startPage,
+ endPage = endPage
+ )
+
+ case _ => deserializationError(s"Expected Json Object as partial DocumentIssue, but got $json")
+
+ }
+
+ def jsValueToDocumentIssue(json: JsValue, documentId: LongId[Document], userId: StringId[User]): DocumentIssue =
+ json match {
+ case JsObject(fields) =>
+ val text = fields
+ .get("text")
+ .map(_.convertTo[String])
+ .getOrElse(deserializationError(s"DocumentIssue json object does not contain `text` field: $json"))
+
+ val startPage = fields.get("startPage").map(_.convertTo[Double])
+ val endPage = fields.get("endPage").map(_.convertTo[Double])
+ DocumentIssue(
+ id = LongId(0),
+ userId = userId,
+ documentId = documentId,
+ lastUpdate = LocalDateTime.MIN,
+ isDraft = true,
+ text = text,
+ archiveRequired = false,
+ startPage = startPage,
+ endPage = endPage
+ )
+
+ case _ => deserializationError(s"Expected Json Object as DocumentIssue, but got $json")
+ }
+
+ implicit val documentIssueWriter = new JsonWriter[DocumentIssue] {
+ override def write(obj: DocumentIssue) = JsObject(
+ "id" -> obj.id.toJson,
+ "startPage" -> obj.startPage.toJson,
+ "endPage" -> obj.endPage.toJson,
+ "text" -> obj.text.toJson,
+ "lastUpdate" -> obj.lastUpdate.toJson,
+ "userId" -> obj.userId.toJson,
+ "isDraft" -> obj.isDraft.toJson,
+ "archiveRequired" -> obj.archiveRequired.toJson
+ )
+ }
+
+}
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
new file mode 100644
index 0000000..20b6ed0
--- /dev/null
+++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/export.scala
@@ -0,0 +1,78 @@
+package xyz.driver.pdsuidomain.formats.json.sprayformats
+
+import spray.json._
+import xyz.driver.pdsuidomain.entities.export.patient._
+import xyz.driver.pdsuidomain.entities.export.trial.{ExportTrialArm, ExportTrialLabelCriterion, ExportTrialWithLabels}
+
+object export {
+ import DefaultJsonProtocol._
+ import common._
+ import record._
+
+ implicit val patientLabelEvidenceDocumentFormat: RootJsonFormat[ExportPatientLabelEvidenceDocument] = jsonFormat5(
+ ExportPatientLabelEvidenceDocument.apply)
+
+ implicit val patientLabelEvidenceWriter: JsonWriter[ExportPatientLabelEvidence] =
+ new JsonWriter[ExportPatientLabelEvidence] {
+ override def write(obj: ExportPatientLabelEvidence): JsValue =
+ JsObject(
+ "evidenceId" -> obj.id.toJson,
+ "labelValue" -> obj.value.toJson,
+ "evidenceText" -> obj.evidenceText.toJson,
+ "document" -> obj.document.toJson
+ )
+ }
+
+ implicit val patientLabelWriter: JsonWriter[ExportPatientLabel] = new JsonWriter[ExportPatientLabel] {
+ override def write(obj: ExportPatientLabel): JsValue =
+ JsObject(
+ "labelId" -> obj.id.toJson,
+ "evidence" -> obj.evidences.map(_.toJson).toJson
+ )
+ }
+
+ implicit val patientWithLabelsWriter: JsonWriter[ExportPatientWithLabels] = new JsonWriter[ExportPatientWithLabels] {
+ override def write(obj: ExportPatientWithLabels): JsValue =
+ JsObject(
+ "patientId" -> obj.patientId.toJson,
+ "labelVersion" -> obj.labelVersion.toJson,
+ "labels" -> obj.labels.map(_.toJson).toJson
+ )
+ }
+
+ implicit val trialArmFormat: RootJsonFormat[ExportTrialArm] = jsonFormat2(ExportTrialArm.apply)
+
+ implicit val trialLabelCriterionWriter: JsonWriter[ExportTrialLabelCriterion] =
+ new JsonWriter[ExportTrialLabelCriterion] {
+ override def write(obj: ExportTrialLabelCriterion): JsValue =
+ JsObject(
+ "value" -> obj.value
+ .map {
+ case true => "Yes"
+ case false => "No"
+ }
+ .getOrElse("Unknown")
+ .toJson,
+ "labelId" -> obj.labelId.toJson,
+ "criterionId" -> obj.criterionId.toJson,
+ "criterionText" -> obj.criteria.toJson,
+ "armIds" -> obj.armIds.toJson,
+ "isCompound" -> obj.isCompound.toJson,
+ "isDefining" -> obj.isDefining.toJson
+ )
+ }
+
+ implicit val trialWithLabelsWriter: JsonWriter[ExportTrialWithLabels] = new JsonWriter[ExportTrialWithLabels] {
+ override def write(obj: ExportTrialWithLabels) =
+ JsObject(
+ "nctId" -> obj.nctId.toJson,
+ "trialId" -> obj.trialId.toJson,
+ "disease" -> obj.condition.toJson,
+ "lastReviewed" -> obj.lastReviewed.toJson,
+ "labelVersion" -> obj.labelVersion.toJson,
+ "arms" -> obj.arms.toJson,
+ "criteria" -> obj.criteria.map(_.toJson).toJson
+ )
+ }
+
+}
diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/extracteddata.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/extracteddata.scala
new file mode 100644
index 0000000..42473bc
--- /dev/null
+++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/extracteddata.scala
@@ -0,0 +1,148 @@
+package xyz.driver.pdsuidomain.formats.json.sprayformats
+
+import spray.json._
+import xyz.driver.pdsuicommon.domain.{FuzzyValue, LongId, TextJson}
+import xyz.driver.pdsuidomain.entities._
+import xyz.driver.pdsuidomain.services.ExtractedDataService.RichExtractedData
+
+object extracteddata {
+ import DefaultJsonProtocol._
+ import common._
+ import ExtractedData._
+
+ implicit val metaKeywordFormat: RootJsonFormat[Meta.Keyword] = jsonFormat4(Meta.Keyword)
+ implicit val metaTextLayerPositionFormat: RootJsonFormat[Meta.TextLayerPosition] = jsonFormat3(
+ Meta.TextLayerPosition)
+ implicit val metaEvidenceFormat: RootJsonFormat[Meta.Evidence] = jsonFormat3(Meta.Evidence)
+
+ implicit val extractedDataMetaFormat: RootJsonFormat[Meta] = jsonFormat2(Meta.apply)
+ implicit val fullExtractedDataMetaFormat = new RootJsonFormat[TextJson[Meta]] {
+ override def write(obj: TextJson[Meta]): JsValue = obj.content.toJson
+ override def read(json: JsValue): TextJson[Meta] = TextJson(extractedDataMetaFormat.read(json))
+ }
+
+ implicit val extractedDataLabelWriter: JsonWriter[ExtractedDataLabel] = new JsonWriter[ExtractedDataLabel] {
+ override def write(label: ExtractedDataLabel): JsObject = {
+ JsObject(
+ "id" -> label.labelId.toJson,
+ "categoryId" -> label.categoryId.toJson,
+ "value" -> label.value.toJson
+ )
+ }
+ }
+
+ def applyLabelsForExtractedData(json: JsValue, dataId: LongId[ExtractedData]): ExtractedDataLabel = json match {
+ case JsObject(fields) =>
+ val labelId = fields
+ .get("id")
+ .map(_.convertTo[LongId[Label]])
+
+ val categoryId = fields
+ .get("categoryId")
+ .map(_.convertTo[LongId[Category]])
+
+ val value = fields
+ .get("value")
+ .map(_.convertTo[FuzzyValue])
+
+ ExtractedDataLabel(
+ id = LongId(0),
+ dataId = dataId,
+ labelId = labelId,
+ categoryId = categoryId,
+ value = value
+ )
+
+ case _ => deserializationError(s"Expected Json Object as ExtractedDataLabel, but got $json")
+ }
+
+ def applyUpdateToExtractedData(json: JsValue, orig: RichExtractedData): RichExtractedData = json match {
+ case JsObject(fields) =>
+ val keywordId = fields
+ .get("keywordId")
+ .map(_.convertTo[Option[LongId[Keyword]]])
+ .getOrElse(orig.extractedData.keywordId)
+
+ val evidence = fields
+ .get("evidence")
+ .map(_.convertTo[Option[String]])
+ .getOrElse(orig.extractedData.evidenceText)
+
+ val meta = fields
+ .get("meta")
+ .map(_.convertTo[Option[TextJson[Meta]]])
+ .getOrElse(orig.extractedData.meta)
+
+ val labels = fields
+ .get("labels")
+ .map(
+ _.convertTo[Option[List[JsValue]]]
+ .getOrElse(List.empty[JsValue])
+ .map(l => applyLabelsForExtractedData(l, orig.extractedData.id)))
+ .getOrElse(orig.labels)
+
+ val extractedData = orig.extractedData.copy(
+ keywordId = keywordId,
+ evidenceText = evidence,
+ meta = meta
+ )
+
+ orig.copy(
+ extractedData = extractedData,
+ labels = labels
+ )
+
+ case _ => deserializationError(s"Expected Json Object as partial ExtractedData, but got $json")
+ }
+
+ implicit val extractedDataFormat: RootJsonFormat[RichExtractedData] = new RootJsonFormat[RichExtractedData] {
+ override def write(richData: RichExtractedData): JsValue =
+ JsObject(
+ "id" -> richData.extractedData.id.id.toJson,
+ "documentId" -> richData.extractedData.documentId.toJson,
+ "keywordId" -> richData.extractedData.keywordId.toJson,
+ "evidence" -> richData.extractedData.evidenceText.toJson,
+ "meta" -> richData.extractedData.meta.toJson,
+ "labels" -> richData.labels.map(_.toJson).toJson
+ )
+
+ override def read(json: JsValue): RichExtractedData = json match {
+ case JsObject(fields) =>
+ val documentId = fields
+ .get("documentId")
+ .map(_.convertTo[LongId[Document]])
+ .getOrElse(
+ deserializationError(s"ExtractedData create json object does not contain `documentId` field: $json"))
+
+ val keywordId = fields
+ .get("keywordId")
+ .map(_.convertTo[LongId[Keyword]])
+
+ val evidence = fields
+ .get("evidence")
+ .map(_.convertTo[String])
+
+ val meta = fields
+ .get("meta")
+ .map(_.convertTo[TextJson[Meta]])
+
+ val labels = fields
+ .get("labels")
+ .map(_.convertTo[List[JsValue]])
+ .getOrElse(List.empty[JsValue])
+ .map(l => applyLabelsForExtractedData(l, LongId(0)))
+
+ val extractedData = ExtractedData(
+ documentId = documentId,
+ keywordId = keywordId,
+ evidenceText = evidence,
+ meta = meta
+ )
+
+ RichExtractedData(extractedData, labels)
+
+ case _ => deserializationError(s"Expected Json Object as ExtractedData, but got $json")
+ }
+ }
+
+}
diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/hypothesis.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/hypothesis.scala
new file mode 100644
index 0000000..c05ff23
--- /dev/null
+++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/hypothesis.scala
@@ -0,0 +1,12 @@
+package xyz.driver.pdsuidomain.formats.json.sprayformats
+
+import spray.json._
+import xyz.driver.pdsuidomain.entities._
+
+object hypothesis {
+ import DefaultJsonProtocol._
+ import common._
+
+ implicit val hypothesisFormat: RootJsonFormat[Hypothesis] = jsonFormat4(Hypothesis.apply)
+
+}
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
new file mode 100644
index 0000000..a8ce950
--- /dev/null
+++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/intervention.scala
@@ -0,0 +1,60 @@
+package xyz.driver.pdsuidomain.formats.json.sprayformats
+
+import spray.json._
+import xyz.driver.pdsuicommon.domain.LongId
+import xyz.driver.pdsuidomain.entities._
+
+object intervention {
+ import DefaultJsonProtocol._
+ import common._
+
+ implicit val interventionWriter: JsonWriter[InterventionWithArms] = new JsonWriter[InterventionWithArms] {
+ override def write(obj: InterventionWithArms) =
+ JsObject(
+ "id" -> obj.intervention.id.toJson,
+ "name" -> obj.intervention.name.toJson,
+ "typeId" -> obj.intervention.typeId.toJson,
+ "description" -> obj.intervention.description.toJson,
+ "isActive" -> obj.intervention.isActive.toJson,
+ "arms" -> obj.arms.map(_.armId).toJson,
+ "trialId" -> obj.intervention.trialId.toJson,
+ "originalName" -> obj.intervention.originalName.toJson,
+ "originalDescription" -> obj.intervention.originalDescription.toJson,
+ "originalType" -> obj.intervention.originalType.toJson
+ )
+ }
+
+ def applyUpdateToInterventionWithArms(json: JsValue, orig: InterventionWithArms): InterventionWithArms = json match {
+ case JsObject(fields) =>
+ val typeId = fields
+ .get("typeId")
+ .map(_.convertTo[LongId[InterventionType]])
+
+ val description = fields
+ .get("description")
+ .map(_.convertTo[String])
+
+ val isActive = fields
+ .get("isActive")
+ .map(_.convertTo[Boolean])
+
+ val origIntervention = orig.intervention
+ val arms = fields
+ .get("arms")
+ .map(_.convertTo[List[LongId[Arm]]].map(x => InterventionArm(x, orig.intervention.id)))
+
+ orig.copy(
+ intervention = origIntervention.copy(
+ typeId = typeId.orElse(origIntervention.typeId),
+ description = description.getOrElse(origIntervention.description),
+ isActive = isActive.getOrElse(origIntervention.isActive)
+ ),
+ arms = arms.getOrElse(orig.arms)
+ )
+
+ case _ => deserializationError(s"Expected Json Object as partial Intervention, but got $json")
+ }
+
+ implicit val interventionTypeFormat: RootJsonFormat[InterventionType] = jsonFormat2(InterventionType.apply)
+
+}
diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/patient.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/patient.scala
new file mode 100644
index 0000000..724c391
--- /dev/null
+++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/patient.scala
@@ -0,0 +1,46 @@
+package xyz.driver.pdsuidomain.formats.json.sprayformats
+
+import spray.json._
+import xyz.driver.core.json.EnumJsonFormat
+import xyz.driver.pdsuidomain.entities._
+
+object patient {
+ import DefaultJsonProtocol._
+ import common._
+ import Patient._
+
+ implicit val patientStatusFormat = new EnumJsonFormat[Status](
+ "New" -> Status.New,
+ "Verified" -> Status.Verified,
+ "Reviewed" -> Status.Reviewed,
+ "Curated" -> Status.Curated,
+ "Done" -> Status.Done,
+ "Flagged" -> Status.Flagged
+ )
+
+ implicit val patientOrderIdFormat = new RootJsonFormat[PatientOrderId] {
+ override def write(orderId: PatientOrderId): JsString = JsString(orderId.toString)
+ override def read(json: JsValue): PatientOrderId = json match {
+ case JsString(value) => PatientOrderId(value)
+ case _ => deserializationError(s"Expected string as PatientOrderId, but got $json")
+ }
+ }
+
+ implicit val patientWriter: JsonWriter[Patient] = new JsonWriter[Patient] {
+ override def write(patient: Patient): JsValue =
+ JsObject(
+ "id" -> patient.id.toJson,
+ "status" -> patient.status.toJson,
+ "name" -> patient.name.toJson,
+ "dob" -> patient.dob.toJson,
+ "assignee" -> patient.assignee.toJson,
+ "previousStatus" -> patient.previousStatus.toJson,
+ "previousAssignee" -> patient.previousAssignee.toJson,
+ "lastActiveUser" -> patient.lastActiveUserId.toJson,
+ "lastUpdate" -> patient.lastUpdate.toJson,
+ "condition" -> patient.condition.toJson,
+ "orderId" -> patient.orderId.toJson
+ )
+ }
+
+}
diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/patientcriterion.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/patientcriterion.scala
new file mode 100644
index 0000000..53e927d
--- /dev/null
+++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/patientcriterion.scala
@@ -0,0 +1,68 @@
+package xyz.driver.pdsuidomain.formats.json.sprayformats
+
+import spray.json._
+import xyz.driver.pdsuicommon.domain.{FuzzyValue, LongId}
+import xyz.driver.pdsuidomain.entities._
+import xyz.driver.pdsuidomain.services.PatientCriterionService.DraftPatientCriterion
+
+object patientcriterion {
+ import DefaultJsonProtocol._
+ import common._
+
+ def applyUpdateToPatientCriterion(json: JsValue, orig: PatientCriterion): PatientCriterion = json match {
+ case JsObject(fields) =>
+ val eligibilityStatus = if (fields.contains("eligibilityStatus")) {
+ fields
+ .get("eligibilityStatus")
+ .map(_.convertTo[FuzzyValue])
+ } else orig.eligibilityStatus
+
+ val verifiedEligibilityStatus = if (fields.contains("verifiedEligibilityStatus")) {
+ fields
+ .get("verifiedEligibilityStatus")
+ .map(_.convertTo[FuzzyValue])
+ } else orig.verifiedEligibilityStatus
+
+ orig.copy(
+ eligibilityStatus = eligibilityStatus,
+ verifiedEligibilityStatus = verifiedEligibilityStatus
+ )
+
+ case _ => deserializationError(s"Expected Json Object as partial PatientCriterion, but got $json")
+ }
+
+ implicit val draftPatientCriterionFormat: RootJsonFormat[DraftPatientCriterion] = jsonFormat3(
+ DraftPatientCriterion.apply)
+ implicit val draftPatientCriterionListReader = new JsonReader[List[DraftPatientCriterion]] {
+ override def read(json: JsValue) = json.convertTo[List[JsValue]].map(_.convertTo[DraftPatientCriterion])
+ }
+
+ implicit val patientCriterionWriter: JsonWriter[(PatientCriterion, LongId[Label], List[PatientCriterionArm])] =
+ new JsonWriter[(PatientCriterion, LongId[Label], List[PatientCriterionArm])] {
+ override def write(obj: (PatientCriterion, LongId[Label], List[PatientCriterionArm])): JsValue = {
+ val criterion = obj._1
+ val labelId = obj._2
+ val arms = obj._3
+ JsObject(
+ "id" -> criterion.id.toJson,
+ "labelId" -> labelId.toJson,
+ "nctId" -> criterion.nctId.toJson,
+ "criterionId" -> criterion.criterionId.toJson,
+ "criterionText" -> criterion.criterionText.toJson,
+ "criterionValue" -> criterion.criterionValue.map {
+ case true => "Yes"
+ case false => "No"
+ }.toJson,
+ "criterionIsDefining" -> criterion.criterionIsDefining.toJson,
+ "criterionIsCompound" -> criterion.criterionValue.isEmpty.toJson,
+ "arms" -> arms.map(_.armName).toJson,
+ "eligibilityStatus" -> criterion.eligibilityStatus.toJson,
+ "verifiedEligibilityStatus" -> criterion.verifiedEligibilityStatus.toJson,
+ "isVerified" -> criterion.isVerified.toJson,
+ "isVisible" -> criterion.isVisible.toJson,
+ "lastUpdate" -> criterion.lastUpdate.toJson
+ )
+ }
+ }
+
+}
diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/patientdefiningcriteria.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/patientdefiningcriteria.scala
new file mode 100644
index 0000000..b97570a
--- /dev/null
+++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/patientdefiningcriteria.scala
@@ -0,0 +1,18 @@
+package xyz.driver.pdsuidomain.formats.json.sprayformats
+
+import spray.json._
+import xyz.driver.pdsuidomain.entities.PatientLabel
+
+object patientdefiningcriteria {
+ import DefaultJsonProtocol._
+ import common._
+
+ implicit val patientLabelDefiningCriteriaWriter: JsonWriter[PatientLabel] = new JsonWriter[PatientLabel] {
+ override def write(obj: PatientLabel) =
+ JsObject(
+ "id" -> obj.id.toJson,
+ "value" -> obj.verifiedPrimaryValue.toJson
+ )
+ }
+
+}
diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/patienteligibletrial.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/patienteligibletrial.scala
new file mode 100644
index 0000000..894e453
--- /dev/null
+++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/patienteligibletrial.scala
@@ -0,0 +1,39 @@
+package xyz.driver.pdsuidomain.formats.json.sprayformats
+
+import spray.json._
+import xyz.driver.pdsuidomain.entities._
+import xyz.driver.pdsuidomain.services.PatientEligibleTrialService.RichPatientEligibleTrial
+
+object patienteligibletrial {
+ import DefaultJsonProtocol._
+ import common._
+
+ def applyUpdateToTrialArmGroup(json: JsValue, orig: PatientTrialArmGroupView): PatientTrialArmGroupView =
+ json match {
+ case JsObject(fields) =>
+ val isVerified = fields
+ .get("isVerified")
+ .map(_.convertTo[Boolean])
+ .getOrElse(orig.isVerified)
+
+ orig.copy(isVerified = isVerified)
+
+ case _ => deserializationError(s"Expected Json Object as partial PatientTrialArmGroupView, but got $json")
+ }
+
+ implicit val patientEligibleTrialWriter: JsonWriter[RichPatientEligibleTrial] =
+ new JsonWriter[RichPatientEligibleTrial] {
+ override def write(obj: RichPatientEligibleTrial) =
+ JsObject(
+ "id" -> obj.group.id.toJson,
+ "patientId" -> obj.group.patientId.toJson,
+ "trialId" -> obj.group.trialId.toJson,
+ "trialTitle" -> obj.trial.title.toJson,
+ "arms" -> obj.arms.map(_.armName).toJson,
+ "hypothesisId" -> obj.trial.hypothesisId.toJson,
+ "verifiedEligibilityStatus" -> obj.group.verifiedEligibilityStatus.toJson,
+ "isVerified" -> obj.group.isVerified.toJson
+ )
+ }
+
+}
diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/patienthistory.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/patienthistory.scala
new file mode 100644
index 0000000..da7a664
--- /dev/null
+++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/patienthistory.scala
@@ -0,0 +1,30 @@
+package xyz.driver.pdsuidomain.formats.json.sprayformats
+
+import spray.json._
+import xyz.driver.core.json.EnumJsonFormat
+import xyz.driver.pdsuidomain.entities._
+
+object patienthistory {
+ import DefaultJsonProtocol._
+ import common._
+ import PatientHistory._
+
+ implicit val patientStateFormat = new EnumJsonFormat[State](
+ "Verify" -> State.Verify,
+ "Curate" -> State.Curate,
+ "Review" -> State.Review,
+ "Flag" -> State.Flag
+ )
+
+ implicit val patientActionFormat = new EnumJsonFormat[Action](
+ "Start" -> Action.Start,
+ "Submit" -> Action.Submit,
+ "Unassign" -> Action.Unassign,
+ "Resolve" -> Action.Resolve,
+ "Flag" -> Action.Flag,
+ "Archive" -> Action.Archive
+ )
+
+ implicit val patientHistoryFormat: RootJsonFormat[PatientHistory] = jsonFormat6(PatientHistory.apply)
+
+}
diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/patienthypothesis.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/patienthypothesis.scala
new file mode 100644
index 0000000..4f2783c
--- /dev/null
+++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/patienthypothesis.scala
@@ -0,0 +1,37 @@
+package xyz.driver.pdsuidomain.formats.json.sprayformats
+
+import spray.json._
+import xyz.driver.pdsuidomain.entities._
+
+object patienthypothesis {
+ import DefaultJsonProtocol._
+ import common._
+
+ def applyUpdateToPatientHypothesis(json: JsValue, orig: PatientHypothesis): PatientHypothesis = json match {
+ case JsObject(fields) =>
+ val rationale = if (fields.contains("rationale")) {
+ fields.get("rationale").map(_.convertTo[String])
+ } else orig.rationale
+
+ orig.copy(rationale = rationale)
+
+ case _ => deserializationError(s"Expected Json Object as partial PatientHypothesis, but got $json")
+ }
+
+ implicit val patientHypothesisWriter: JsonWriter[(PatientHypothesis, Boolean)] =
+ new JsonWriter[(PatientHypothesis, Boolean)] {
+ override def write(obj: (PatientHypothesis, Boolean)): JsValue = {
+ val patientHypothesis = obj._1
+ val isRationaleRequired = obj._2
+ JsObject(
+ "id" -> patientHypothesis.id.toJson,
+ "patientId" -> patientHypothesis.patientId.toJson,
+ "hypothesisId" -> patientHypothesis.hypothesisId.toJson,
+ "matchedTrials" -> patientHypothesis.matchedTrials.toJson,
+ "rationale" -> patientHypothesis.rationale.toJson,
+ "isRationaleRequired" -> isRationaleRequired.toJson
+ )
+ }
+ }
+
+}
diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/patientissue.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/patientissue.scala
new file mode 100644
index 0000000..7d35bd1
--- /dev/null
+++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/patientissue.scala
@@ -0,0 +1,54 @@
+package xyz.driver.pdsuidomain.formats.json.sprayformats
+
+import java.time.LocalDateTime
+
+import spray.json._
+import xyz.driver.pdsuicommon.domain.{LongId, StringId, User, UuidId}
+import xyz.driver.pdsuidomain.entities._
+
+object patientissue {
+ import DefaultJsonProtocol._
+ import common._
+
+ def applyUpdateToPatientIssue(json: JsValue, orig: PatientIssue): PatientIssue = {
+ json.asJsObject.getFields("text", "archiveRequired") match {
+ case Seq(text, archiveRequired) =>
+ orig.copy(
+ text = text.convertTo[String],
+ archiveRequired = archiveRequired.convertTo[Boolean]
+ )
+
+ case _ => deserializationError(s"Expected Json Object as partial PatientIssue, but got $json")
+ }
+ }
+
+ def jsValueToPatientIssue(json: JsValue, patientId: UuidId[Patient], userId: StringId[User]): PatientIssue = {
+ json.asJsObject.getFields("text") match {
+ case Seq(text) =>
+ PatientIssue(
+ id = LongId(0),
+ userId = userId,
+ patientId = patientId,
+ lastUpdate = LocalDateTime.MIN,
+ isDraft = true,
+ text = text.convertTo[String],
+ archiveRequired = false
+ )
+
+ case _ => deserializationError(s"Expected Json Object as PatientIssue, but got $json")
+ }
+
+ }
+
+ implicit val patientIssueWriter = new JsonWriter[PatientIssue] {
+ override def write(obj: PatientIssue) = JsObject(
+ "id" -> obj.id.toJson,
+ "text" -> obj.text.toJson,
+ "lastUpdate" -> obj.lastUpdate.toJson,
+ "userId" -> obj.userId.toJson,
+ "isDraft" -> obj.isDraft.toJson,
+ "archiveRequired" -> obj.archiveRequired.toJson
+ )
+ }
+
+}
diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/patientlabel.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/patientlabel.scala
new file mode 100644
index 0000000..3b52833
--- /dev/null
+++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/patientlabel.scala
@@ -0,0 +1,64 @@
+package xyz.driver.pdsuidomain.formats.json.sprayformats
+
+import spray.json._
+import xyz.driver.pdsuicommon.domain.FuzzyValue
+import xyz.driver.pdsuidomain.entities._
+
+object patientlabel {
+ import DefaultJsonProtocol._
+ import common._
+
+ def applyUpdateToPatientLabel(json: JsValue, orig: PatientLabel): PatientLabel = json match {
+ case JsObject(fields) =>
+ val primaryValue = fields
+ .get("primaryValue")
+ .map(_.convertTo[Option[FuzzyValue]])
+ .getOrElse(orig.primaryValue)
+
+ val verifiedPrimaryValue = fields
+ .get("verifiedPrimaryValue")
+ .map(_.convertTo[Option[FuzzyValue]])
+ .getOrElse(orig.verifiedPrimaryValue)
+
+ orig.copy(
+ primaryValue = primaryValue,
+ verifiedPrimaryValue = verifiedPrimaryValue
+ )
+
+ case _ => deserializationError(s"Expected Json Object as PatientLabel, but got $json")
+ }
+
+ implicit val patientLabelWriter: JsonWriter[(PatientLabel, Boolean)] = new JsonWriter[(PatientLabel, Boolean)] {
+ override def write(obj: (PatientLabel, Boolean)): JsValue = {
+ val patientLabel = obj._1
+ val isVerified = obj._2
+ JsObject(
+ "id" -> patientLabel.id.toJson,
+ "labelId" -> patientLabel.labelId.toJson,
+ "primaryValue" -> patientLabel.primaryValue.toJson,
+ "verifiedPrimaryValue" -> patientLabel.verifiedPrimaryValue.toJson,
+ "score" -> patientLabel.score.toJson,
+ "isImplicitMatch" -> patientLabel.isImplicitMatch.toJson,
+ "isVisible" -> patientLabel.isVisible.toJson,
+ "isVerified" -> isVerified.toJson
+ )
+ }
+ }
+
+ implicit val patientLabelEvidenceWriter: JsonWriter[PatientLabelEvidenceView] =
+ new JsonWriter[PatientLabelEvidenceView] {
+ override def write(evidence: PatientLabelEvidenceView): JsValue =
+ JsObject(
+ "id" -> evidence.id.toJson,
+ "value" -> evidence.value.toJson,
+ "evidenceText" -> evidence.evidenceText.toJson,
+ "documentId" -> evidence.documentId.toJson,
+ "evidenceId" -> evidence.evidenceId.toJson,
+ "reportId" -> evidence.reportId.toJson,
+ "documentType" -> evidence.documentType.toJson,
+ "date" -> evidence.date.toJson,
+ "providerType" -> evidence.providerType.toJson
+ )
+ }
+
+}
diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/record.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/record.scala
new file mode 100644
index 0000000..e378dbd
--- /dev/null
+++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/record.scala
@@ -0,0 +1,237 @@
+package xyz.driver.pdsuidomain.formats.json.sprayformats
+
+import java.time.LocalDateTime
+import java.util.UUID
+
+import spray.json._
+import xyz.driver.core.json.{EnumJsonFormat, GadtJsonFormat}
+import xyz.driver.pdsuicommon.domain.{LongId, TextJson, UuidId}
+import xyz.driver.pdsuidomain.entities.MedicalRecord.Meta._
+import xyz.driver.pdsuidomain.entities._
+
+object record {
+ import DefaultJsonProtocol._
+ import MedicalRecord._
+ import common._
+
+ implicit val recordStatusFormat = new EnumJsonFormat[Status](
+ "Unprocessed" -> Status.Unprocessed,
+ "PreOrganized" -> Status.PreOrganized,
+ "New" -> Status.New,
+ "Cleaned" -> Status.Cleaned,
+ "PreOrganized" -> Status.PreOrganized,
+ "PreOrganizing" -> Status.PreOrganizing,
+ "Reviewed" -> Status.Reviewed,
+ "Organized" -> Status.Organized,
+ "Done" -> Status.Done,
+ "Flagged" -> Status.Flagged,
+ "Archived" -> Status.Archived
+ )
+
+ implicit val requestIdFormat = new RootJsonFormat[RecordRequestId] {
+ override def write(requestId: RecordRequestId): JsString = JsString(requestId.toString)
+ override def read(json: JsValue): RecordRequestId = json match {
+ case JsString(value) => RecordRequestId(UUID.fromString(value))
+ case _ => deserializationError(s"Expected string as RecordRequestId, but got $json")
+ }
+ }
+
+ implicit val caseIdFormat = new RootJsonFormat[CaseId] {
+ override def write(caseId: CaseId): JsString = JsString(caseId.toString)
+ override def read(json: JsValue): CaseId = json match {
+ case JsString(value) => CaseId(value)
+ case _ => deserializationError(s"Expected string as CaseId, but got $json")
+ }
+ }
+
+ implicit val duplicateMetaFormat: RootJsonFormat[Duplicate] = new RootJsonFormat[Duplicate] {
+ override def write(obj: Duplicate) =
+ JsObject(
+ "type" -> "duplicate".toJson,
+ "predicted" -> obj.predicted.toJson,
+ "startPage" -> obj.startPage.toJson,
+ "endPage" -> obj.endPage.toJson,
+ "startOriginalPage" -> obj.startOriginalPage.toJson,
+ "endOriginalPage" -> obj.endOriginalPage.toJson
+ )
+
+ override def read(json: JsValue): Duplicate = json match {
+ case JsObject(fields) =>
+ val predicted = fields
+ .get("predicted")
+ .map(_.convertTo[Boolean])
+
+ val startPage = fields
+ .get("startPage")
+ .map(_.convertTo[Double])
+ .getOrElse(deserializationError(s"Duplicate meta json object does not contain `startPage` field: $json"))
+
+ val endPage = fields
+ .get("endPage")
+ .map(_.convertTo[Double])
+ .getOrElse(deserializationError(s"Duplicate meta json object does not contain `endPage` field: $json"))
+
+ val startOriginalPage = fields
+ .get("startOriginalPage")
+ .map(_.convertTo[Double])
+ .getOrElse(
+ deserializationError(s"Duplicate meta json object does not contain `startOriginalPage` field: $json"))
+
+ val endOriginalPage = fields
+ .get("endOriginalPage")
+ .map(_.convertTo[Double])
+
+ Duplicate(
+ predicted = predicted,
+ startPage = startPage,
+ endPage = endPage,
+ startOriginalPage = startOriginalPage,
+ endOriginalPage = endOriginalPage
+ )
+
+ case _ => deserializationError(s"Expected JsObject as Duplicate meta of medical record, but got $json")
+ }
+ }
+
+ implicit val reorderMetaFormat: RootJsonFormat[Reorder] = new RootJsonFormat[Reorder] {
+ override def write(obj: Reorder) =
+ JsObject(
+ "type" -> "reorder".toJson,
+ "predicted" -> obj.predicted.toJson,
+ "items" -> obj.items.toJson
+ )
+
+ override def read(json: JsValue): Reorder = json match {
+ case JsObject(fields) =>
+ val predicted = fields
+ .get("predicted")
+ .map(_.convertTo[Boolean])
+
+ val items = fields
+ .get("items")
+ .map(_.convertTo[Seq[Int]])
+ .getOrElse(deserializationError(s"Reorder meta json object does not contain `items` field: $json"))
+
+ Reorder(
+ predicted = predicted,
+ items = items
+ )
+
+ case _ => deserializationError(s"Expected JsObject as Reorder meta of medical record, but got $json")
+ }
+ }
+
+ implicit val rotateMetaFormat: RootJsonFormat[Rotation] = new RootJsonFormat[Rotation] {
+ override def write(obj: Rotation) =
+ JsObject(
+ "type" -> "rotation".toJson,
+ "predicted" -> obj.predicted.toJson,
+ "items" -> obj.items.toJson
+ )
+
+ override def read(json: JsValue): Rotation = json match {
+ case JsObject(fields) =>
+ val predicted = fields
+ .get("predicted")
+ .map(_.convertTo[Boolean])
+
+ val items = fields
+ .get("items")
+ .map(_.convertTo[Map[String, Int]])
+ .getOrElse(deserializationError(s"Rotation meta json object does not contain `items` field: $json"))
+
+ Rotation(
+ predicted = predicted,
+ items = items
+ )
+
+ case _ => deserializationError(s"Expected JsObject as Rotation meta of medical record, but got $json")
+ }
+ }
+
+ implicit val recordMetaTypeFormat: GadtJsonFormat[MedicalRecord.Meta] = {
+ GadtJsonFormat.create[Meta]("type")({ case m => m.metaType }) {
+ case "duplicate" => duplicateMetaFormat
+ case "reorder" => reorderMetaFormat
+ case "rotation" => rotateMetaFormat
+ }
+ }
+
+ implicit val recordMetaFormat = new RootJsonFormat[TextJson[List[Meta]]] {
+ override def write(obj: TextJson[List[Meta]]): JsArray = JsArray(obj.content.map(_.toJson).toVector)
+ override def read(json: JsValue): TextJson[List[Meta]] = json match {
+ case JsArray(values) => TextJson[List[Meta]](values.map(_.convertTo[Meta]).toList)
+ case _ => deserializationError(s"Expected array as Meta, but got $json")
+ }
+ }
+
+ implicit val recordFormat: RootJsonFormat[MedicalRecord] =
+ new RootJsonFormat[MedicalRecord] {
+ override def write(record: MedicalRecord): JsValue =
+ JsObject(
+ "id" -> record.id.id.toJson,
+ "patientId" -> record.patientId.toJson,
+ "caseId" -> record.caseId.toJson,
+ "disease" -> record.disease.toJson,
+ "physician" -> record.physician.toJson,
+ "status" -> record.status.toJson,
+ "previousStatus" -> record.previousStatus.toJson,
+ "assignee" -> record.assignee.toJson,
+ "previousAssignee" -> record.previousAssignee.toJson,
+ "requestId" -> record.requestId.toJson,
+ "meta" -> record.meta.getOrElse(TextJson[List[Meta]](List.empty)).toJson,
+ "lastActiveUser" -> record.lastActiveUserId.toJson,
+ "lastUpdate" -> record.lastUpdate.toJson
+ )
+
+ override def read(json: JsValue): MedicalRecord = json match {
+ case JsObject(fields) =>
+ val disease = fields
+ .get("disease")
+ .map(_.convertTo[String])
+ .getOrElse(deserializationError(s"MedicalRecord json object does not contain `disease` field: $json"))
+
+ val patientId = fields
+ .get("patientId")
+ .map(_.convertTo[UuidId[Patient]])
+ .getOrElse(deserializationError(s"MedicalRecord json object does not contain `patientId` field: $json"))
+
+ val requestId = fields
+ .get("requestId")
+ .map(_.convertTo[RecordRequestId])
+ .getOrElse(deserializationError(s"MedicalRecord json object does not contain `requestId` field: $json"))
+
+ MedicalRecord(
+ id = LongId(0),
+ status = MedicalRecord.Status.New,
+ previousStatus = None,
+ assignee = None,
+ previousAssignee = None,
+ lastActiveUserId = None,
+ patientId = patientId,
+ requestId = requestId,
+ disease = disease,
+ caseId = None,
+ physician = None,
+ meta = None,
+ predictedMeta = None,
+ predictedDocuments = None,
+ lastUpdate = LocalDateTime.now()
+ )
+
+ case _ => deserializationError(s"Expected Json Object as MedicalRecord, but got $json")
+ }
+ }
+
+ def applyUpdateToMedicalRecord(json: JsValue, orig: MedicalRecord): MedicalRecord = json match {
+ case JsObject(fields) =>
+ val meta = fields
+ .get("meta")
+ .map(_.convertTo[Option[TextJson[List[Meta]]]])
+ .getOrElse(orig.meta)
+ orig.copy(meta = meta)
+
+ case _ => deserializationError(s"Expected Json Object as partial MedicalRecord, but got $json")
+ }
+
+}
diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/recordhistory.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/recordhistory.scala
new file mode 100644
index 0000000..bd14d43
--- /dev/null
+++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/recordhistory.scala
@@ -0,0 +1,30 @@
+package xyz.driver.pdsuidomain.formats.json.sprayformats
+
+import spray.json._
+import xyz.driver.core.json.EnumJsonFormat
+import xyz.driver.pdsuidomain.entities._
+
+object recordhistory {
+ import DefaultJsonProtocol._
+ import common._
+ import MedicalRecordHistory._
+
+ implicit val recordStateFormat = new EnumJsonFormat[State](
+ "Clean" -> State.Clean,
+ "Organize" -> State.Organize,
+ "Review" -> State.Review,
+ "Flag" -> State.Flag
+ )
+
+ implicit val recordActionFormat = new EnumJsonFormat[Action](
+ "Start" -> Action.Start,
+ "Submit" -> Action.Submit,
+ "Unassign" -> Action.Unassign,
+ "Resolve" -> Action.Resolve,
+ "Flag" -> Action.Flag,
+ "Archive" -> Action.Archive
+ )
+
+ implicit val recordHistoryFormat: RootJsonFormat[MedicalRecordHistory] = jsonFormat6(MedicalRecordHistory.apply)
+
+}
diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/recordissue.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/recordissue.scala
new file mode 100644
index 0000000..4ae04d0
--- /dev/null
+++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/recordissue.scala
@@ -0,0 +1,79 @@
+package xyz.driver.pdsuidomain.formats.json.sprayformats
+
+import java.time.LocalDateTime
+
+import spray.json._
+import xyz.driver.pdsuicommon.domain.{LongId, StringId, User}
+import xyz.driver.pdsuidomain.entities._
+
+object recordissue {
+ import DefaultJsonProtocol._
+ import common._
+
+ def applyUpdateToRecordIssue(json: JsValue, orig: MedicalRecordIssue): MedicalRecordIssue = json match {
+ case JsObject(fields) =>
+ val text = fields
+ .get("text")
+ .map(_.convertTo[String])
+ .getOrElse(deserializationError(s"MedicalRecordIssue json object does not contain `text` field: $json"))
+
+ val archiveRequired = fields
+ .get("archiveRequired")
+ .map(_.convertTo[Boolean])
+ .getOrElse(
+ deserializationError(s"MedicalRecordIssue json object does not contain `archiveRequired` field: $json"))
+
+ val startPage = fields.get("startPage").map(_.convertTo[Double])
+ val endPage = fields.get("endPage").map(_.convertTo[Double])
+
+ orig.copy(
+ text = text,
+ archiveRequired = archiveRequired,
+ startPage = startPage,
+ endPage = endPage
+ )
+
+ case _ => deserializationError(s"Expected Json Object as partial MedicalRecordIssue, but got $json")
+
+ }
+
+ def jsValueToRecordIssue(json: JsValue,
+ recordId: LongId[MedicalRecord],
+ userId: StringId[User]): MedicalRecordIssue = json match {
+ case JsObject(fields) =>
+ val text = fields
+ .get("text")
+ .map(_.convertTo[String])
+ .getOrElse(deserializationError(s"MedicalRecordIssue json object does not contain `text` field: $json"))
+
+ val startPage = fields.get("startPage").map(_.convertTo[Double])
+ val endPage = fields.get("endPage").map(_.convertTo[Double])
+ MedicalRecordIssue(
+ id = LongId(0),
+ userId = userId,
+ recordId = recordId,
+ lastUpdate = LocalDateTime.MIN,
+ isDraft = true,
+ text = text,
+ archiveRequired = false,
+ startPage = startPage,
+ endPage = endPage
+ )
+
+ case _ => deserializationError(s"Expected Json Object as MedicalRecordIssue, but got $json")
+ }
+
+ implicit val recordIssueWriter = new JsonWriter[MedicalRecordIssue] {
+ override def write(obj: MedicalRecordIssue) = JsObject(
+ "id" -> obj.id.toJson,
+ "startPage" -> obj.startPage.toJson,
+ "endPage" -> obj.endPage.toJson,
+ "text" -> obj.text.toJson,
+ "lastUpdate" -> obj.lastUpdate.toJson,
+ "userId" -> obj.userId.toJson,
+ "isDraft" -> obj.isDraft.toJson,
+ "archiveRequired" -> obj.archiveRequired.toJson
+ )
+ }
+
+}
diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/studydesign.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/studydesign.scala
new file mode 100644
index 0000000..e801666
--- /dev/null
+++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/studydesign.scala
@@ -0,0 +1,12 @@
+package xyz.driver.pdsuidomain.formats.json.sprayformats
+
+import spray.json._
+import xyz.driver.pdsuidomain.entities._
+
+object studydesign {
+ import DefaultJsonProtocol._
+ import common._
+
+ implicit val studyDesignFormat: RootJsonFormat[StudyDesign] = jsonFormat2(StudyDesign.apply)
+
+}
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
new file mode 100644
index 0000000..c1751bf
--- /dev/null
+++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/trial.scala
@@ -0,0 +1,90 @@
+package xyz.driver.pdsuidomain.formats.json.sprayformats
+
+import java.time.{ZoneId, ZonedDateTime}
+
+import spray.json._
+import xyz.driver.core.json.EnumJsonFormat
+import xyz.driver.pdsuicommon.domain.{LongId, UuidId}
+import xyz.driver.pdsuidomain.entities._
+
+object trial {
+ import DefaultJsonProtocol._
+ import common._
+ import Trial._
+
+ implicit val trialStatusFormat = new EnumJsonFormat[Status](
+ "New" -> Status.New,
+ "ReviewSummary" -> Status.ReviewSummary,
+ "Summarized" -> Status.Summarized,
+ "PendingUpdate" -> Status.PendingUpdate,
+ "Update" -> Status.Update,
+ "ReviewCriteria" -> Status.ReviewCriteria,
+ "Done" -> Status.Done,
+ "Flagged" -> Status.Flagged,
+ "Archived" -> Status.Archived
+ )
+
+ implicit val conditionFormat = new EnumJsonFormat[Condition](
+ "Breast" -> Condition.Breast,
+ "Lung" -> Condition.Lung,
+ "Prostate" -> Condition.Prostate
+ )
+
+ implicit val trialWriter: JsonWriter[Trial] = new JsonWriter[Trial] {
+ override def write(obj: Trial) =
+ JsObject(
+ "id" -> obj.id.toJson,
+ "externalid" -> obj.externalId.toJson,
+ "lastUpdate" -> ZonedDateTime.of(obj.lastUpdate, ZoneId.of("Z")).toJson,
+ "status" -> obj.status.toJson,
+ "assignee" -> obj.assignee.toJson,
+ "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,
+ "originalStudyDesignId" -> obj.originalStudyDesign.toJson,
+ "isPartner" -> obj.isPartner.toJson,
+ "overview" -> obj.overview.toJson,
+ "overviewTemplate" -> obj.overviewTemplate.toJson,
+ "isUpdated" -> obj.isUpdated.toJson,
+ "title" -> obj.title.toJson,
+ "originalTitle" -> obj.originalTitle.toJson
+ )
+ }
+
+ def applyUpdateToTrial(json: JsValue, orig: Trial): Trial = json match {
+ case JsObject(fields) =>
+ val hypothesisId = fields
+ .get("hypothesisId")
+ .map(_.convertTo[Option[UuidId[Hypothesis]]])
+ .getOrElse(orig.hypothesisId)
+
+ val studyDesignId = fields
+ .get("studyDesignId")
+ .map(_.convertTo[Option[LongId[StudyDesign]]])
+ .getOrElse(orig.studyDesignId)
+
+ val overview = fields
+ .get("overview")
+ .map(_.convertTo[Option[String]])
+ .getOrElse(orig.overview)
+
+ val title = fields
+ .get("title")
+ .map(_.convertTo[Option[String]].getOrElse(""))
+ .getOrElse(orig.title)
+
+ orig.copy(
+ hypothesisId = hypothesisId,
+ studyDesignId = studyDesignId,
+ overview = overview,
+ title = title
+ )
+
+ case _ => deserializationError(s"Expected Json Object as Trial, but got $json")
+ }
+
+}
diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/trialhistory.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/trialhistory.scala
new file mode 100644
index 0000000..844c5f5
--- /dev/null
+++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/trialhistory.scala
@@ -0,0 +1,30 @@
+package xyz.driver.pdsuidomain.formats.json.sprayformats
+
+import spray.json._
+import xyz.driver.core.json.EnumJsonFormat
+import xyz.driver.pdsuidomain.entities._
+
+object trialhistory {
+ import DefaultJsonProtocol._
+ import common._
+ import TrialHistory._
+
+ implicit val trialStateFormat = new EnumJsonFormat[State](
+ "Summarize" -> State.Summarize,
+ "Criteriarize" -> State.Criteriarize,
+ "Review" -> State.Review,
+ "Flag" -> State.Flag
+ )
+
+ implicit val trialActionFormat = new EnumJsonFormat[Action](
+ "Start" -> Action.Start,
+ "Submit" -> Action.Submit,
+ "Unassign" -> Action.Unassign,
+ "Resolve" -> Action.Resolve,
+ "Flag" -> Action.Flag,
+ "Archive" -> Action.Archive
+ )
+
+ implicit val trialHistoryFormat: RootJsonFormat[TrialHistory] = jsonFormat6(TrialHistory.apply)
+
+}
diff --git a/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/trialissue.scala b/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/trialissue.scala
new file mode 100644
index 0000000..572f44d
--- /dev/null
+++ b/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/trialissue.scala
@@ -0,0 +1,60 @@
+package xyz.driver.pdsuidomain.formats.json.sprayformats
+
+import java.time.LocalDateTime
+
+import spray.json._
+import xyz.driver.pdsuicommon.domain.{LongId, StringId, User}
+import xyz.driver.pdsuidomain.entities._
+
+object trialissue {
+ import DefaultJsonProtocol._
+ import common._
+
+ def applyUpdateToTrialIssue(json: JsValue, orig: TrialIssue): TrialIssue = {
+ json.asJsObject.getFields("text", "evidence", "archiveRequired", "meta") match {
+ case Seq(text, evidence, archiveRequired, meta) =>
+ orig.copy(
+ text = text.convertTo[String],
+ evidence = evidence.convertTo[String],
+ archiveRequired = archiveRequired.convertTo[Boolean],
+ meta = meta.convertTo[String]
+ )
+
+ case _ => deserializationError(s"Expected Json Object as partial TrialIssue, but got $json")
+ }
+ }
+
+ def jsValueToTrialIssue(json: JsValue, trialId: StringId[Trial], userId: StringId[User]): TrialIssue = {
+ json.asJsObject.getFields("text", "evidence", "meta") match {
+ case Seq(text, evidence, meta) =>
+ TrialIssue(
+ id = LongId(0),
+ userId = userId,
+ trialId = trialId,
+ lastUpdate = LocalDateTime.MIN,
+ isDraft = true,
+ text = text.convertTo[String],
+ evidence = evidence.convertTo[String],
+ archiveRequired = false,
+ meta = meta.convertTo[String]
+ )
+
+ case _ => deserializationError(s"Expected Json Object as TrialIssue, but got $json")
+ }
+
+ }
+
+ implicit val trialIssueWriter = new JsonWriter[TrialIssue] {
+ override def write(obj: TrialIssue) = JsObject(
+ "id" -> obj.id.toJson,
+ "text" -> obj.text.toJson,
+ "lastUpdate" -> obj.lastUpdate.toJson,
+ "userId" -> obj.userId.toJson,
+ "isDraft" -> obj.isDraft.toJson,
+ "evidence" -> obj.evidence.toJson,
+ "archiveRequired" -> obj.archiveRequired.toJson,
+ "meta" -> obj.meta.toJson
+ )
+ }
+
+}