aboutsummaryrefslogtreecommitdiff
path: root/src/main/scala/xyz/driver/pdsuidomain/formats/json/extracteddata.scala
blob: 232bb399b954453cb6a822cae6c914ac26452142 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
package xyz.driver.pdsuidomain.formats.json

import spray.json._
import xyz.driver.entities.labels.{Label, LabelCategory, LabelValue}
import xyz.driver.formats.json.labels._
import xyz.driver.pdsuicommon.domain.{LongId, TextJson}
import xyz.driver.pdsuidomain.entities._
import xyz.driver.pdsuidomain.services.ExtractedDataService.RichExtractedData

object extracteddata {
  import DefaultJsonProtocol._
  import ExtractedData._
  import common._

  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")
        .flatMap(_.convertTo[Option[LongId[Label]]])

      val categoryId = fields
        .get("categoryId")
        .flatMap(_.convertTo[Option[LongId[LabelCategory]]])

      val value = fields
        .get("value")
        .flatMap(_.convertTo[Option[LabelValue]])

      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.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 id = fields
          .get("id")
          .flatMap(_.convertTo[Option[LongId[ExtractedData]]])

        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")
          .flatMap(_.convertTo[Option[LongId[Keyword]]])

        val evidence = fields
          .get("evidence")
          .flatMap(_.convertTo[Option[String]])

        val meta = fields
          .get("meta")
          .flatMap(_.convertTo[Option[TextJson[Meta]]])

        val labels = fields
          .get("labels")
          .map(_.convertTo[List[JsValue]])
          .getOrElse(List.empty[JsValue])
          .map(l => applyLabelsForExtractedData(l, LongId(0)))

        val extractedData = ExtractedData(
          id = id.getOrElse(LongId(0L)),
          documentId = documentId,
          keywordId = keywordId,
          evidenceText = evidence,
          meta = meta
        )

        RichExtractedData(extractedData, labels)

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

}