blob: 7f17886c211874623a4159f49eb461a52db98e03 (
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
|
package cc.spray.json
package lenses
/**
* A projection combines read and update functions of UpdateLens and ReadLens into
* combinable chunks.
*
* A projection can either operate on a scalar value, or on an optional value, or on a
* sequence value. This is denoted by the `M[_]` type constructor.
*/
trait Projection[M[_]] extends UpdateLens with ReadLens[M] {
/**
* Combines two projections.
*/
def /[M2[_], R[_]](next: Projection[M2])(implicit ev: Join[M2, M, R]): Projection[R]
def toSeq: Projection[Seq]
def ops: Ops[M]
}
/**
* This implements most of the methods of `Projection`. Implementors of a new type of projection
* must implement `retr` for the read side of the lens and `updated` for the update side of the lens.
*/
trait ProjectionImpl[M[_]] extends Projection[M] {
outer =>
def tryGet[T: MonadicReader](p: JsValue): Validated[M[T]] =
retr(p).flatMap(mapValue(_)(_.as[T]))
def get[T: MonadicReader](p: JsValue): M[T] =
tryGet[T](p).getOrThrow
def !(op: Operation): Update = new Update {
def apply(parent: JsValue): JsValue =
updated(op)(parent).getOrThrow
}
def is[U: MonadicReader](f: U => Boolean): JsPred = value =>
tryGet[U](value) exists (x => ops.map(x)(f).forall(identity))
def /[M2[_], R[_]](next: Projection[M2])(implicit ev: Join[M2, M, R]): Projection[R] = new ProjectionImpl[R] {
val ops: Ops[R] = ev.get(next.ops, outer.ops)
def retr: JsValue => Validated[R[JsValue]] = parent =>
for {
outerV <- outer.retr(parent)
innerV <- ops.allRight(outer.ops.flatMap(outerV)(x => next.ops.toSeq(next.retr(x))))
} yield innerV
def updated(f: SafeJsValue => SafeJsValue)(parent: JsValue): SafeJsValue =
outer.updated(_.flatMap(next.updated(f)))(parent)
}
def toSeq: Projection[Seq] = this / SeqLenses.asSeq
private[this] def mapValue[T](value: M[JsValue])(f: JsValue => Validated[T]): Validated[M[T]] =
ops.allRight(ops.map(value)(f))
}
abstract class Proj[M[_]](implicit val ops: Ops[M]) extends ProjectionImpl[M]
|