1
/*
2
* This file is part of the diffson project.
3
* Copyright (c) 2016 Lucas Satabin
4
*
5
* Licensed under the Apache License, Version 2.0 (the "License");
6
* you may not use this file except in compliance with the License.
7
* You may obtain a copy of the License at
8
*
9
* http://www.apache.org/licenses/LICENSE-2.0
10
*
11
* Unless required by applicable law or agreed to in writing, software
12
* distributed under the License is distributed on an "AS IS" BASIS,
13
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
* See the License for the specific language governing permissions and
15
* limitations under the License.
16
*/
17
package diffson
18

19
import jsonpatch._
20
import jsonpointer._
21
import jsonmergepatch._
22

23
import cats.{ Apply, FlatMap }
24
import cats.implicits._
25
import io.circe._
26
import io.circe.Decoder.Result
27
import io.circe.syntax._
28

29
package object circe {
30

31
  implicit object jsonyCirce extends Jsony[Json] {
32

33 1
    def Null: Json = Json.Null
34

35
    def array(json: Json): Option[Vector[Json]] =
36 1
      json.asArray
37

38
    def fields(json: Json): Option[Map[String, Json]] =
39 1
      json.asObject.map(_.toMap)
40

41
    def makeArray(values: Vector[Json]): Json =
42 1
      Json.fromValues(values)
43

44
    def makeObject(fields: Map[String, Json]): Json =
45 1
      Json.fromFields(fields)
46

47
    def show(json: Json): String =
48 0
      json.noSpaces
49

50
    def eqv(json1: Json, json2: Json) =
51 1
      Json.eqJson.eqv(json1, json2)
52

53
  }
54

55
  implicit val pointerEncoder: Encoder[Pointer] =
56 1
    Encoder[String].contramap(_.show)
57

58
  implicit val pointerDecoder: Decoder[Pointer] =
59 1
    Decoder[String].emap(Pointer.parse[Either[Throwable, ?]](_).leftMap(_.getMessage))
60

61
  implicit val operationEncoder: Encoder[Operation[Json]] =
62 1
    Encoder.instance[Operation[Json]] {
63
      case Add(path, value) =>
64 1
        Json.obj(
65 1
          "op" -> Json.fromString("add"),
66 1
          "path" -> Json.fromString(path.show),
67 1
          "value" -> value)
68
      case Remove(path, Some(old)) =>
69 0
        Json.obj(
70 0
          "op" -> Json.fromString("remove"),
71 0
          "path" -> Json.fromString(path.show),
72 0
          "old" -> old)
73
      case Remove(path, None) =>
74 1
        Json.obj(
75 1
          "op" -> Json.fromString("remove"),
76 1
          "path" -> Json.fromString(path.show))
77
      case Replace(path, value, Some(old)) =>
78 0
        Json.obj(
79 0
          "op" -> Json.fromString("replace"),
80 0
          "path" -> Json.fromString(path.show),
81 0
          "value" -> value,
82 0
          "old" -> old)
83
      case Replace(path, value, None) =>
84 1
        Json.obj(
85 1
          "op" -> Json.fromString("replace"),
86 1
          "path" -> Json.fromString(path.show),
87 1
          "value" -> value)
88
      case Move(from, path) =>
89 1
        Json.obj(
90 1
          "op" -> Json.fromString("move"),
91 1
          "from" -> Json.fromString(from.show),
92 1
          "path" -> Json.fromString(path.show))
93
      case Copy(from, path) =>
94 1
        Json.obj(
95 1
          "op" -> Json.fromString("copy"),
96 1
          "from" -> Json.fromString(from.show),
97 1
          "path" -> Json.fromString(path.show))
98
      case Test(path, value) =>
99 1
        Json.obj(
100 1
          "op" -> Json.fromString("test"),
101 1
          "path" -> Json.fromString(path.show),
102 1
          "value" -> value)
103
    }
104

105
  implicit val operationDecoder: Decoder[Operation[Json]] =
106 1
    new Decoder[Operation[Json]] {
107

108 1
      private val A = Apply[Result]
109 1
      private val F = FlatMap[Result]
110

111
      override def apply(c: HCursor): Result[Operation[Json]] =
112 1
        F.flatMap(c.get[String]("op").leftMap(_.copy(message = "missing 'op' field"))) {
113
          case "add" =>
114 1
            A.map2(c.get[Pointer]("path"), c.get[Json]("value"))(Add[Json])
115 1
              .leftMap(_.copy(message = "missing 'path' or 'value' field"))
116
          case "remove" =>
117 1
            A.map2(c.get[Pointer]("path"), c.get[Option[Json]]("old"))(Remove[Json])
118 1
              .leftMap(_.copy(message = "missing 'path' field"))
119
          case "replace" =>
120 1
            A.map3(c.get[Pointer]("path"), c.get[Json]("value"), c.get[Option[Json]]("old"))(Replace[Json] _)
121 1
              .leftMap(_.copy(message = "missing 'path' or 'value' field"))
122
          case "move" =>
123 1
            A.map2(c.get[Pointer]("from"), c.get[Pointer]("path"))(Move[Json])
124 1
              .leftMap(_.copy(message = "missing 'from' or 'path' field"))
125
          case "copy" =>
126 1
            A.map2(c.get[Pointer]("from"), c.get[Pointer]("path"))(Copy[Json])
127 1
              .leftMap(_.copy(message = "missing 'from' or 'path' field"))
128
          case "test" =>
129 1
            A.map2(c.get[Pointer]("path"), c.get[Json]("value"))(Test[Json])
130 1
              .leftMap(_.copy(message = "missing 'path' or 'value' field"))
131
          case other =>
132 1
            Left(DecodingFailure(s"""Unknown operation "$other"""", c.history))
133
        }
134
    }
135

136
  implicit val jsonPatchEncoder: Encoder[JsonPatch[Json]] =
137 1
    Encoder[List[Json]].contramap(_.ops.map(_.asJson))
138

139
  implicit val jsonPatchDecoder: Decoder[JsonPatch[Json]] =
140 1
    new Decoder[JsonPatch[Json]] {
141

142 1
      private val F = FlatMap[Result]
143

144
      override def apply(c: HCursor): Result[JsonPatch[Json]] =
145 1
        F.flatMap(c.as[List[Json]]) { list =>
146 1
          F.map(list.traverse(_.as[Operation[Json]]))(JsonPatch(_))
147
        }
148
    }
149

150
  implicit val jsonMergePatchEncoder: Encoder[JsonMergePatch[Json]] =
151 1
    Encoder.instance[JsonMergePatch[Json]](_.toJson)
152

153
  implicit val jsonMergePatchDecoder: Decoder[JsonMergePatch[Json]] =
154 1
    new Decoder[JsonMergePatch[Json]] {
155
      override def apply(c: HCursor): Result[JsonMergePatch[Json]] =
156 1
        c.value.asObject match {
157 1
          case Some(obj) => Right(JsonMergePatch.Object(obj.toMap))
158 1
          case None      => Right(JsonMergePatch.Value(c.value))
159
        }
160
    }
161
}

Read our documentation on viewing source code .

Loading