@@ -33,7 +33,7 @@ class JsonDiff[Json](diffArray: Boolean, rememberOld: Boolean)(implicit J: Jsony
33
33
34
34
private def diff (json1 : Json , json2 : Json , pointer : Pointer ): Eval [Chain [Operation [Json ]]] =
35
35
(json1, json2) match {
36
- case (JsObject (fields1), JsObject (fields2)) => fieldsDiff(fields1.toList, fields2.toList , pointer)
36
+ case (JsObject (fields1), JsObject (fields2)) => fieldsDiff(fields1.toList, fields2, pointer)
37
37
case (JsArray (arr1), JsArray (arr2)) if diffArray => arraysDiff(arr1.toList, arr2.toList, pointer)
38
38
case _ if json1 === json2 =>
39
39
// if they are equal, this one is easy...
@@ -42,51 +42,22 @@ class JsonDiff[Json](diffArray: Boolean, rememberOld: Boolean)(implicit J: Jsony
42
42
}
43
43
44
44
private def fieldsDiff (fields1 : List [(String , Json )],
45
- fields2 : List [(String , Json )],
46
- path : Pointer ): Eval [Chain [Operation [Json ]]] = {
47
- // sort fields by name in both objects
48
- val sorted1 = fields1.sortBy(_._1)
49
- val sorted2 = fields2.sortBy(_._1)
50
- @ tailrec
51
- def associate (fields1 : List [(String , Json )],
52
- fields2 : List [(String , Json )],
53
- acc : Chain [(Option [(String , Json )], Option [(String , Json )])])
54
- : Chain [(Option [(String , Json )], Option [(String , Json )])] = (fields1, fields2) match {
55
- case (f1 :: t1, f2 :: t2) if f1._1 == f2._1 =>
56
- // same name, associate both
57
- associate(t1, t2, acc.prepend((Some (f1), Some (f2))))
58
- case (f1 :: t1, f2 :: _) if f1._1 < f2._1 =>
59
- // the first field is not present in the second object
60
- associate(t1, fields2, acc.prepend((Some (f1), None )))
61
- case (_ :: _, f2 :: t2) =>
62
- // the second field is not present in the first object
63
- associate(fields1, t2, acc.prepend((None , Some (f2))))
64
- case (_, Nil ) =>
65
- Chain .fromSeq(fields1.map(Some (_) -> None )) ++ acc
66
- case (Nil , _) =>
67
- Chain .fromSeq(fields2.map(None -> Some (_))) ++ acc
45
+ fields2 : Map [String , Json ],
46
+ path : Pointer ): Eval [Chain [Operation [Json ]]] =
47
+ fields1 match {
48
+ case (fld, value1) :: fields1 =>
49
+ fields2.get(fld) match {
50
+ case Some (value2) =>
51
+ fieldsDiff(fields1, fields2.removed(fld), path).flatMap(d => diff(value1, value2, path / fld).map(_ ++ d))
52
+ case None =>
53
+ // field is not in the second object, delete it
54
+ fieldsDiff(fields1, fields2, path).map(
55
+ _.prepend(Remove (path / fld, if (rememberOld) Some (value1) else None )))
56
+ }
57
+ case Nil =>
58
+ Eval .now(Chain .fromSeq(fields2.toList).map { case (fld, value) => Add (path / fld, value) })
68
59
}
69
60
70
- def fields (fs : List [(Option [(String , Json )], Option [(String , Json )])],
71
- acc : Chain [Operation [Json ]]): Eval [Chain [Operation [Json ]]] = fs match {
72
- case (Some (f1), Some (f2)) :: tl if f1._2 === f2._2 =>
73
- // all right, nothing changed
74
- fields(tl, acc)
75
- case (Some (f1), Some (f2)) :: tl =>
76
- // same field name, different values
77
- diff(f1._2, f2._2, path / f1._1).flatMap(d => fields(tl, d ++ acc))
78
- case (Some (f1), None ) :: tl =>
79
- // the field was deleted
80
- fields(tl, acc.prepend(Remove [Json ](path / f1._1, if (rememberOld) Some (f1._2) else None )))
81
- case (None , Some (f2)) :: tl =>
82
- // the field was added
83
- fields(tl, acc.prepend(Add (path / f2._1, f2._2)))
84
- case _ =>
85
- Eval .now(acc)
86
- }
87
- fields(associate(sorted1, sorted2, Chain .empty).toList, Chain .empty)
88
- }
89
-
90
61
private def arraysDiff (arr1 : List [Json ], arr2 : List [Json ], path : Pointer ): Eval [Chain [Operation [Json ]]] = {
91
62
// get the longest common subsequence in the array
92
63
val lcs = Lcs .lcs(arr1, arr2)
0 commit comments