aboutsummaryrefslogblamecommitdiff
path: root/src/main/scala/xyz/driver/pdsuidomain/formats/json/record.scala
blob: d3fe2c905e88c8889f8c351c6746326f298f9041 (plain) (tree)
1
2
3
4
5
6
7
8
9
                                           

                              

                   


                                                
                                                               
                                                           






                                        
                                                                                       

                                      






                                        





                                                                                                    
                                                                                                             




                                                                           
                                                                                             




                                                                
 



                                                                                               







                                                              

















                                                                                                                   
                                               

                  











                                                                                                             
                                                                       


                                                            




                                                                                                             
                      






                                                                                                           
                                                                        


                                                             




                                                                                                              
                               




                                                                                                            
                                                                           



                                                                   


     
                                                                                                                  










                                                                                                        
                                                 










                                                                                               

                                                         



                                                                    



                                                                











                                                                                                                    
                                                 


                                                                                                                    
                                         










                                              

                                             







                                                                                                  



                                                       





                                                                                                   
package xyz.driver.pdsuidomain.formats.json

import java.time.LocalDateTime

import spray.json._
import xyz.driver.core.Id
import xyz.driver.core.json._
import xyz.driver.entities.clinic.ClinicalRecord
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: EnumJsonFormat[Status] = new EnumJsonFormat[Status](
    "New"           -> Status.New,
    "Cleaned"       -> Status.Cleaned,
    "Reviewed"      -> Status.Reviewed,
    "Organized"     -> Status.Organized,
    "Done"          -> Status.Done,
    "Flagged"       -> Status.Flagged,
    "Archived"      -> Status.Archived
  )

  implicit val providerTypeFormat: RootJsonFormat[ProviderType] = new RootJsonFormat[ProviderType] {
    override def read(json: JsValue): ProviderType = json match {
      case JsObject(fields) =>
        val name = fields
          .get("name")
          .map(_.convertTo[String])
          .getOrElse(deserializationError(s"Provider type json object does not contain `name` field: $json"))

        ProviderType
          .fromString(name)
          .getOrElse(deserializationError(s"Unknown provider type: $name"))

      case _ => deserializationError(s"Expected Json Object as Provider type, but got $json")
    }

    override def write(obj: ProviderType) =
      JsObject("id" -> obj.id.toJson, "name" -> obj.name.toJson)
  }

  implicit val duplicateMetaFormat: RootJsonFormat[Duplicate] = new RootJsonFormat[Duplicate] {
    override def write(obj: Duplicate) =
      JsObject(
        "type"              -> "duplicate".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 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")
          .flatMap(_.convertTo[Option[Double]])

        Duplicate(
          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, "items" -> obj.items.toJson)

    override def read(json: JsValue): Reorder = json match {
      case JsObject(fields) =>
        val items = fields
          .get("items")
          .map(_.convertTo[Seq[Int]])
          .getOrElse(deserializationError(s"Reorder meta json object does not contain `items` field: $json"))

        Reorder(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, "items" -> obj.items.toJson)

    override def read(json: JsValue): Rotation = json match {
      case JsObject(fields) =>
        val items = fields
          .get("items")
          .map(_.convertTo[Map[String, Int]])
          .getOrElse(deserializationError(s"Rotation meta json object does not contain `items` field: $json"))

        Rotation(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: RootJsonFormat[TextJson[List[Meta]]] = 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.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,
          "totalPages"       -> record.totalPages.toJson
        )

      override def read(json: JsValue): MedicalRecord = json match {
        case JsObject(fields) =>
          val id = fields
            .get("id")
            .flatMap(_.convertTo[Option[LongId[MedicalRecord]]])

          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[Id[ClinicalRecord]])
            .getOrElse(deserializationError(s"MedicalRecord json object does not contain `requestId` field: $json"))

          MedicalRecord(
            id = id.getOrElse(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,
            lastUpdate = LocalDateTime.now(),
            totalPages = 0
          )

        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")
  }

}