diff options
-rw-r--r-- | README.md | 3 | ||||
-rw-r--r-- | src/main/scala/spray/json/lenses/Operations.scala | 13 | ||||
-rw-r--r-- | src/main/scala/spray/json/lenses/OptionLenses.scala | 9 | ||||
-rw-r--r-- | src/test/scala/cc/spray/json/lenses/JsonLensesSpec.scala | 5 |
4 files changed, 25 insertions, 5 deletions
@@ -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}}""") |