aboutsummaryrefslogtreecommitdiff
path: root/src/main/scala/xyz/driver/pdsuidomain/formats/json/sprayformats/ListResponse.scala
blob: d294b38b2af55934c95839ec0aeb5f54e278fc15 (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
package xyz.driver.pdsuidomain.formats.json.sprayformats

import java.time.LocalDateTime

import spray.json.{RootJsonFormat, _}
import xyz.driver.pdsuicommon.db.Pagination
import xyz.driver.pdsuidomain.formats.json.sprayformats.common._

final case class ListResponse[+T](items: Seq[T], meta: ListResponse.Meta)

object ListResponse extends DefaultJsonProtocol {
  private val itemsField = "items"
  private val metaField = "meta"

  final case class Meta(itemsCount: Int, pageNumber: Int, pageSize: Int, lastUpdate: Option[LocalDateTime])

  object Meta {
    def apply(itemsCount: Int, pagination: Pagination, lastUpdate: Option[LocalDateTime]): Meta = {
      Meta(
        itemsCount,
        pagination.pageNumber,
        pagination.pageSize,
        lastUpdate
      )
    }
  }

  implicit val listResponseMetaFormat: RootJsonFormat[Meta] = jsonFormat4(Meta.apply)

  private def listResponseJsonWriter[T: JsonWriter](listResponse: ListResponse[T]) = {
    JsObject(
      itemsField -> listResponse.items.map(_.toJson).toJson,
      metaField -> listResponse.meta.toJson
    )
  }

  implicit def listResponseWriter[T: JsonWriter]: RootJsonWriter[ListResponse[T]] =
    new RootJsonWriter[ListResponse[T]] {
      override def write(listResponse: ListResponse[T]): JsValue = {
        listResponseJsonWriter(listResponse)
      }
    }

  implicit def listResponseFormat[T: RootJsonFormat]: RootJsonFormat[ListResponse[T]] =
    new RootJsonFormat[ListResponse[T]] {
      override def write(listResponse: ListResponse[T]): JsValue = {
        listResponseJsonWriter(listResponse)
      }

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

          val meta = fields
            .get(metaField)
            .map(_.convertTo[Meta])
            .getOrElse(deserializationError(s"ListResponse json object does not contain `$metaField` field: $json"))

          ListResponse(items, meta)
        case _ => deserializationError(s"Expected ListResponse json object, but got $json")
      }
    }
}