summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md3
-rw-r--r--src/main/scala/spray/json/lenses/Operations.scala13
-rw-r--r--src/main/scala/spray/json/lenses/OptionLenses.scala9
-rw-r--r--src/test/scala/cc/spray/json/lenses/JsonLensesSpec.scala5
4 files changed, 25 insertions, 5 deletions
diff --git a/README.md b/README.md
index 717e3ee..4bc7734 100644
--- a/README.md
+++ b/README.md
@@ -199,6 +199,9 @@ Currently, there are these update operations defined:
* `set[T: JsonWriter](t: => T)` uses the `JsonWriter` to set the value to a constant value.
* `modify[T: JsonFormat](f: T => T)` applies an update function to an existing value. The value has to be
serializable from and to `T`.
+ * `modifyOrDeleteField[T: JsonFormat](f: T => Option[T])` can be used in conjunction with the `optionalField` lens. It
+ applies an update function to an existing value. If the function returns `Some(newValue)` the field value will be
+ updated to the new value. If the function returns `None` the field will be deleted.
#### Using lenses to extract or update json data
diff --git a/src/main/scala/spray/json/lenses/Operations.scala b/src/main/scala/spray/json/lenses/Operations.scala
index 646cd98..ed2c3f7 100644
--- a/src/main/scala/spray/json/lenses/Operations.scala
+++ b/src/main/scala/spray/json/lenses/Operations.scala
@@ -31,9 +31,20 @@ trait Operations { _: ExtraImplicits =>
value.as[T] map (v => f(v).toJson)
}
+ /**
+ * The `modifyOrDeleteField` operation works together with the `optionalField` lens.
+ * The passed function is called for every existing field. If the function returns
+ * `Some(value)`, this will become the new value. If the function returns `None` the
+ * field will be deleted.
+ */
+ def modifyOrDeleteField[T: Reader : JsonWriter](f: T => Option[T]): Operation = new MapOperation {
+ def apply(value: JsValue): SafeJsValue =
+ value.as[T] flatMap (v => f(v).map(x => Right(x.toJson)).getOrElse(OptionLenses.FieldMissing))
+ }
+
def append(update: Update): Operation = ???
def update(update: Update): Operation = ???
def extract[M[_], T](value: Lens[M])(f: M[T] => Update): Operation = ???
}
-object Operations extends Operations with ExtraImplicits \ No newline at end of file
+object Operations extends Operations with ExtraImplicits
diff --git a/src/main/scala/spray/json/lenses/OptionLenses.scala b/src/main/scala/spray/json/lenses/OptionLenses.scala
index 5f407dc..2eebca3 100644
--- a/src/main/scala/spray/json/lenses/OptionLenses.scala
+++ b/src/main/scala/spray/json/lenses/OptionLenses.scala
@@ -25,16 +25,15 @@ trait OptionLenses {
}
}
- val FieldMissing = unexpected("Field missing")
-
/**
* Accesses a maybe missing field of a JsObject.
*/
def optionalField(name: String): OptLens = new LensImpl[Option] {
+ import OptionLenses._
def updated(f: SafeJsValue => SafeJsValue)(parent: JsValue): SafeJsValue =
retr(parent).flatMap { oldValueO =>
f(oldValueO.map(Right(_)).getOrElse(FieldMissing)) match {
- case FieldMissing => Right(parent)
+ case FieldMissing => Right(JsObject(fields = parent.asJsObject.fields - name))
case x => x.map(newVal => JsObject(fields = parent.asJsObject.fields + (name -> newVal)))
}
}
@@ -46,4 +45,6 @@ trait OptionLenses {
}
}
-object OptionLenses extends OptionLenses
+object OptionLenses extends OptionLenses {
+ val FieldMissing = unexpected("Field missing")
+}
diff --git a/src/test/scala/cc/spray/json/lenses/JsonLensesSpec.scala b/src/test/scala/cc/spray/json/lenses/JsonLensesSpec.scala
index 118f47e..b115afd 100644
--- a/src/test/scala/cc/spray/json/lenses/JsonLensesSpec.scala
+++ b/src/test/scala/cc/spray/json/lenses/JsonLensesSpec.scala
@@ -124,6 +124,11 @@ class JsonLensesSpec extends Specification with SpecHelpers {
"create" in {
"""[{"b": 4}, {"c": 5}]""".update((* / 'b.?) ! set(38)) must be_json("""[{"b": 38}, {"c": 5, "b": 38}]""")
}
+ "delete some" in {
+ def f(i: Int): Option[Int] =
+ Some(i).filter(_ % 2 == 0)
+ """[{"b": 4}, {"b": 3}]""".update((* / 'b.?) ! modifyOrDeleteField(f)) must be_json("""[{"b": 4}, {}]""")
+ }
}
"set field of member" in {
"""{"n": {"b": 4}}""" update ("n" / "b" ! set(23)) must be_json( """{"n": {"b": 23}}""")