Skip to content

Commit 00583fd

Browse files
committed
add ujson bridge
1 parent 175e5d8 commit 00583fd

11 files changed

+454
-0
lines changed

build.sbt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,20 @@ lazy val circe = crossProject(JSPlatform, JVMPlatform, NativePlatform)
9292
)
9393
.dependsOn(core, testkit % Test)
9494

95+
lazy val ujson = crossProject(JVMPlatform)
96+
.crossType(CrossType.Full)
97+
.in(file("ujson"))
98+
.settings(commonSettings: _*)
99+
.settings(
100+
name := "diffson-ujson",
101+
libraryDependencies ++= Seq(
102+
"com.lihaoyi" %% "ujson" % "3.1.4",
103+
"com.lihaoyi" %% "upickle" % "3.1.4"
104+
)
105+
)
106+
.dependsOn(core, testkit % Test)
107+
108+
95109
lazy val benchmarks = crossProject(JVMPlatform)
96110
.crossType(CrossType.Pure)
97111
.in(file("benchmarks"))
Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
/*
2+
* Copyright 2024 Raphael Bosshard
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package diffson
18+
19+
import cats.implicits._
20+
import diffson.jsonmergepatch.JsonMergePatch
21+
import diffson.jsonpatch._
22+
import diffson.jsonpointer.Pointer
23+
import _root_.ujson as lihaoyUjson
24+
import lihaoyUjson.{Value, Arr, Obj, Str}
25+
import upickle.default._
26+
27+
import scala.util.Try
28+
29+
package object ujson {
30+
31+
implicit val jsonyUjson: Jsony[Value] = new Jsony[Value] {
32+
33+
def Null: Value = _root_.ujson.Null
34+
35+
def array(json: Value): Option[Vector[Value]] =
36+
json.arrOpt.map(_.toVector)
37+
38+
def fields(json: Value): Option[Map[String, Value]] =
39+
json.objOpt.map(_.toMap)
40+
41+
def makeArray(values: Vector[Value]): Value =
42+
Arr.from(values)
43+
44+
def makeObject(fields: Map[String, Value]): Value =
45+
Obj.from(fields)
46+
47+
def show(json: Value): String =
48+
json.render()
49+
50+
def eqv(json1: Value, json2: Value): Boolean = json1 == json2
51+
}
52+
53+
implicit val pointerEncoder: Writer[Pointer] =
54+
implicitly[Writer[String]].comap(a => a.show)
55+
56+
implicit val pointerDecoder: Reader[Pointer] =
57+
implicitly[Reader[String]].map { str =>
58+
import cats.implicits._
59+
Pointer.parse[Try](str).get
60+
}
61+
62+
private val operationAsJson: Operation[Value] => Value = {
63+
case Add(path, value) =>
64+
Obj(
65+
"op" -> Str("add"),
66+
"path" -> Str(path.show),
67+
"value" -> value,
68+
)
69+
case Remove(path, Some(old)) =>
70+
Obj(
71+
"op" -> Str("remove"),
72+
"path" -> Str(path.show),
73+
"old" -> old,
74+
)
75+
case Remove(path, None) =>
76+
Obj(
77+
"op" -> Str("remove"),
78+
"path" -> Str(path.show),
79+
)
80+
case Replace(path, value, Some(old)) =>
81+
Obj(
82+
"op" -> Str("replace"),
83+
"path" -> Str(path.show),
84+
"value" -> value,
85+
"old" -> old,
86+
)
87+
case Replace(path, value, None) =>
88+
Obj(
89+
"op" -> Str("replace"),
90+
"path" -> Str(path.show),
91+
"value" -> value,
92+
)
93+
case Move(from, path) =>
94+
Obj(
95+
"op" -> Str("move"),
96+
"from" -> Str(from.show),
97+
"path" -> Str(path.show),
98+
)
99+
case Copy(from, path) =>
100+
Obj(
101+
"op" -> Str("copy"),
102+
"from" -> Str(from.show),
103+
"path" -> Str(path.show),
104+
)
105+
case Test(path, value) =>
106+
Obj(
107+
"op" -> Str("test"),
108+
"path" -> Str(path.show),
109+
"value" -> value,
110+
)
111+
}
112+
113+
implicit val operationEncoder: Writer[Operation[Value]] =
114+
implicitly[Writer[Value]].comap(operationAsJson)
115+
116+
def throwFieldExpected(
117+
fieldName: String
118+
): PartialFunction[Throwable, Nothing] = {
119+
case t: Throwable =>
120+
throw new Exception(s"Expected field `$fieldName`, but it is missing", t)
121+
}
122+
123+
private def decodeOperation(value: Value): Operation[Value] = {
124+
def readPointer(value: Value, path: String = "path"): Pointer = {
125+
val p = try { value.obj(path) } catch throwFieldExpected(path)
126+
read[Pointer](p)
127+
}
128+
129+
val op = try value.obj("op").str catch throwFieldExpected("op")
130+
131+
op match {
132+
case "add" =>
133+
val path = readPointer(value)
134+
val v =
135+
try value.obj("value")
136+
catch throwFieldExpected("value")
137+
Add(path, v)
138+
case "remove" =>
139+
val path = readPointer(value)
140+
val old = value.objOpt.flatMap(_.get("old"))
141+
Remove(path, old)
142+
case "replace" =>
143+
val path = readPointer(value)
144+
val payload =
145+
try value.obj("value")
146+
catch throwFieldExpected("value")
147+
val old = value.objOpt.flatMap(_.get("old"))
148+
Replace(path, payload, old)
149+
case "move" =>
150+
val path = readPointer(value)
151+
val from = readPointer(value, "from")
152+
Move(from, path)
153+
case "copy" =>
154+
val path = readPointer(value)
155+
val from = readPointer(value, "from")
156+
Copy(from, path)
157+
case "test" =>
158+
val path = readPointer(value)
159+
val payload =
160+
try value.obj("value")
161+
catch throwFieldExpected("value")
162+
Test(path, payload)
163+
case other =>
164+
throw new Exception(s"Expected operation `$other` but it is missing")
165+
}
166+
}
167+
168+
implicit val operationDecoder: Reader[Operation[Value]] =
169+
implicitly[Reader[Value]].map(decodeOperation)
170+
171+
implicit val jsonPatchEncoder: Writer[JsonPatch[Value]] = {
172+
implicitly[Writer[List[Value]]].comap(_.ops.map(operationAsJson))
173+
}
174+
175+
implicit val jsonPatchDecoder: Reader[JsonPatch[Value]] = {
176+
implicitly[Reader[List[Value]]].map(q => JsonPatch(q.map(decodeOperation)))
177+
}
178+
179+
implicit val jsonMergePatchEncoder: Writer[JsonMergePatch[Value]] = {
180+
implicitly[Writer[Value]].comap(_.toJson)
181+
}
182+
183+
implicit val jsonMergePatchDecoder: Reader[JsonMergePatch[Value]] = {
184+
implicitly[Reader[Value]]
185+
.map { value =>
186+
value.objOpt
187+
.map(obj => JsonMergePatch.Object(obj.toMap))
188+
.getOrElse(JsonMergePatch.Value(value))
189+
}
190+
}
191+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/*
2+
* Copyright 2024 Raphael Bosshard
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package diffson
18+
package ujson
19+
20+
import jsonpatch._
21+
import _root_.ujson._
22+
23+
class UjsonJsonDiff extends TestJsonDiff[Value] with UjsonTestProtocol
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*
2+
* Copyright 2024 Raphael Bosshard
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package diffson
18+
package ujson
19+
import _root_.ujson._
20+
21+
import jsonmergepatch._
22+
23+
class UjsonJsonJsonMergeDiff
24+
extends TestJsonMergeDiff[Value] with UjsonTestProtocol
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/*
2+
* Copyright 2024 Raphael Bosshard
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package diffson
18+
package ujson
19+
20+
import jsonpatch._
21+
import _root_.ujson._
22+
23+
class UjsonSimpleDiff extends TestSimpleDiff[Value] with UjsonTestProtocol
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*
2+
* Copyright 2024 Raphael Bosshard
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package diffson
18+
package ujson
19+
20+
import jsonpatch._
21+
import _root_.ujson as lihaoyUjson
22+
23+
class UjsonTestArrayDiff
24+
extends TestArrayDiff[lihaoyUjson.Value] with UjsonTestProtocol
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*
2+
* Copyright 2024 Raphael Bosshard
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package diffson
18+
package ujson
19+
20+
import jsonmergepatch._
21+
import _root_.ujson._
22+
23+
class UjsonTestJsonMergePatch
24+
extends TestJsonMergePatch[Value] with UjsonTestProtocol
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/*
2+
* Copyright 2024 Raphael Bosshard
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package diffson
18+
package ujson
19+
20+
import jsonpatch._
21+
import _root_.ujson._
22+
23+
class UjsonTestJsonPatch extends TestJsonPatch[Value] with UjsonTestProtocol
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
/*
2+
* Copyright 2024 Raphael Bosshard
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package diffson
18+
package ujson
19+
20+
import jsonpointer._
21+
import _root_.ujson._
22+
23+
class UjsonTestJsonPointer extends TestJsonPointer[Value] with UjsonTestProtocol

0 commit comments

Comments
 (0)