• Stars
    star
    70
  • Rank 447,840 (Top 9 %)
  • Language
    Scala
  • License
    MIT License
  • Created over 11 years ago
  • Updated over 6 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

play-json-zipper

EXPERIMENTAL / DRAFT

JsZipper : Play2 Json advanced (& monadic) manipulations

JsZipper is a new tool allowing much more complex & powerful manipulations of Json structures for Play2/Json API:

JsZipper is inspired by the Zipper concept introduced by Gerard Huet in 1997.

The Zipper allows to update immutable traversable structures in an efficient way. Json is an immutable AST so it fits well. FYI, the Zipper behaves like a loupe that walks through each node of the AST (left/right/up/down) while keeping aware of the nodes on its left, its right and its upper. The interesting idea behind the loupe is that when it targets a node, it can modify and even delete the focused node. The analogy to the pants zipper is quite good too because when it goes down the tree, it behaves as if it was opening the tree to be able to drive the loupe through all nodes and when it goes up, it closes back the tree... I won't tell more here, it would be too long.

JsZipper is a specific interpretation of Zipper concept for Play/Json API based on :

  • Scala Streams to go through / update / construct Json AST in a lazy way
  • Monadic aspects to provide funnier ways of manipulating the Json AST (plz see below)

Please note, JsZipper is not an end in itself but a tool useful to provide new API to manipulate Json.

Use it in your SBT project

I've just published v1.1 of JsZipper to Bintray instead of my fake maven repo in github. It's much more reliable.

resolvers += "mandubian maven bintray" at "http://dl.bintray.com/mandubian/maven"

libraryDependencies ++= Seq(
  "com.mandubian"     %% "play-json-zipper"    % "1.2"
)

Samples

Let's go to samples.

We'll use following Json Object.

scala> import play.api.libs.json._
scala> import play.api.libs.json.monad.syntax._
scala> import play.api.libs.json.extensions._
scala> val js = Json.obj(
  "key1" -> Json.obj(
    "key11" -> "TO_FIND",
    "key12" -> 123L,
    "key13" -> JsNull
  ),
  "key2" -> 123,
  "key3" -> true,
  "key4" -> Json.arr("TO_FIND", 345.6, "test", Json.obj("key411" -> Json.obj("key4111" -> "TO_FIND")))
)
js: play.api.libs.json.JsObject = {"key1":{"key11":"TO_FIND","key12":123,"key13":null},"key2":123,"key3":true,"key4":["TO_FIND",345.6,"test",{"key411":{"key4111":"TO_FIND"}}]}

Basic manipulations

Setting multiple paths/values

scala> js.set(
  (__ \ "key4")(2) -> JsNumber(765.23),
  (__ \ "key1" \ "key12") -> JsString("toto")
)
res1: play.api.libs.json.JsValue = {"key1":{"key11":"TO_FIND","key12":"toto","key13":null},"key2":123,"key3":true,"key4":["TO_FIND",345.6,765.23,{"key411":{"key4111":"TO_FIND"}}]}

Deleting multiple paths/values

scala> js.delete(
  (__ \ "key4")(2),
  (__ \ "key1" \ "key12"),
  (__ \ "key1" \ "key13")
)
res2: play.api.libs.json.JsValue = {"key1":{"key11":"TO_FIND"},"key2":123,"key3":true,"key4":["TO_FIND",345.6,{"key411":{"key4111":"TO_FIND"}}]}

Finding paths/values according to a filter

scala> js.findAll( (_,v) => v == JsString("TO_FIND") ).toList
res5: List[(play.api.libs.json.JsPath, play.api.libs.json.JsValue)] = List(
  (/key1/key11,"TO_FIND"), 
  (/key4(0),"TO_FIND"), 
  (/key4(3)/key411/key4111,"TO_FIND")
)

Updating values according to a filter based on value

scala> js.updateAll( (_:JsValue) == JsString("TO_FIND") ){ js =>
  val JsString(str) = js
  JsString(str + "2")
}
res6: play.api.libs.json.JsValue = {"key1":{"key11":"TO_FIND2","key12":123,"key13":null},"key2":123,"key3":true,"key4":["TO_FIND2",345.6,"test",{"key411":{"key4111":"TO_FIND2"}}]}

Updating values according to a filter based on path+value

scala> js.updateAll{ (path, js) =>
  JsPathExtension.hasKey(path) == Some("key4111")
}{ (path, js) =>
  val JsString(str) = js
  JsString(str + path.path.last)
}
res1: play.api.libs.json.JsValue = {"key1":{"key11":"TO_FIND","key12":123,"key13":null},"key2":123,"key3":true,"key4":["TO_FIND",345.6,"test",{"key411":{"key4111":"TO_FIND/key4111"}}]}

Creating an object from scratch

scala> val build = JsExtensions.buildJsObject( 
  __ \ "key1" \ "key11" -> JsString("toto"),
  __ \ "key1" \ "key12" -> JsNumber(123L),
  (__ \ "key2")(0)      -> JsBoolean(true),
  __ \ "key3"           -> Json.arr(1, 2, 3)
)
build: play.api.libs.json.JsValue = {"key1":{"key11":"toto","key12":123},"key3":[1,2,3],"key2":[true]}

# Let's be funnier with Monads now

Let's use Future as our Monad because it's... coooool to do things in the future ;)

Imagine you call several services returning Future[JsValue] and you want to build/update a JsObject from it. Until now, if you wanted to do that with Play2/Json, it was quite tricky and required some code.

Here is what you can do now.

Updating multiple FUTURE values at given paths

scala> val maybeJs = js.setM[Future](
  (__ \ "key4")(2)        -> future{ JsNumber(765.23) },
  (__ \ "key1" \ "key12") -> future{ JsString("toto") }
)
maybeJs: scala.concurrent.Future[play.api.libs.json.JsValue] = scala.concurrent.impl.Promise$DefaultPromise@6beb722d

scala> Await.result(maybeJs, Duration("2 seconds"))
res4: play.api.libs.json.JsValue = {"key1":{"key11":"TO_FIND","key12":"toto","key13":null},"key2":123,"key3":true,"key4":["TO_FIND",345.6,765.23,{"key411":{"key4111":"TO_FIND"}}]}

Update multiple FUTURE values according to a filter

scala> val maybeJs = js.updateAllM[Future]( (_:JsValue) == JsString("TO_FIND") ){ js =>
  future {
    val JsString(str) = js
    JsString(str + "2")
  }
}
maybeJs: scala.concurrent.Future[play.api.libs.json.JsValue] = scala.concurrent.impl.Promise$DefaultPromise@35a4bb1a

scala> Await.result(maybeJs, Duration("2 seconds"))
res6: play.api.libs.json.JsValue = {"key1":{"key11":"TO_FIND2","key12":123,"key13":null},"key2":123,"key3":true,"key4":["TO_FIND2",345.6,"test",{"key411":{"key4111":"TO_FIND2"}}]}

Creating a FUTURE JsArray from scratch

scala> val maybeArr = JsExtensions.buildJsArrayM[Future](
  future { JsNumber(123.45) },
  future { JsString("toto") }
)
maybeArr: scala.concurrent.Future[play.api.libs.json.JsValue] = scala.concurrent.impl.Promise$DefaultPromise@220d48e4

scala> Await.result(maybeArr, Duration("2 seconds"))
res0: play.api.libs.json.JsValue = [123.45,"toto"]

Ok, much more can be done... Have fun!

More Repositories

1

play-autosource

Play Autosource : 1mn REST/Crud/Async/Typesafe Datasource for Play Framework
Scala
153
star
2

neurocat

From neural networks to the Category of composable supervised learning algorithms in Scala with compile-time matrix checking based on singleton-types
Scala
135
star
3

neural-ode

Neural Ordinary Differential Equation
Jupyter Notebook
97
star
4

siena

Siena is a persitence API for Java inspired on the Google App Engine Python Datastore API
Java
81
star
5

play-actor-room

A Room manager for Play Framework 2.2 based on WebSocket & Bots
Scala
50
star
6

play-siena

Siena Module for Play! Framework
Java
42
star
7

play2-json-demo

Play2 Json Demos
JavaScript
42
star
8

scaledn

Scala EDN parser based on Parboiled2
Scala
39
star
9

scala-xmlsoap-ersatz

XML/SOAP Ersatz tools, for Scala (developed & used with Play Framework 2.0 Scala) to read/write XML/SOAP without code generation, annotations or whatever magic
Scala
39
star
10

scalaeff

Scala
35
star
11

injective

Runorama injection with Free / Coproduct / Coyoneda
Scala
28
star
12

zpark-ztream

Driving Spark stream with Scalaz-Stream
Scala
26
star
13

play-capistrano

A module to deploy Play apps with Capistrano
Ruby
24
star
14

play-json-alone

Sample of Play2.2-SNAPSHOT JSON API used stand-alone
Scala
24
star
15

freek

Free wrapper specialized to Coproducts of DSL/Containers
Scala
24
star
16

shapelaysson

Shapelaysson = Shapeless + Play-Json
Scala
23
star
17

freez

Optimizing FreeMonads with other representations of the structure
Scala
21
star
18

scalaio-2014

ScalaIO Talk 2014 code sample
Scala
20
star
19

codenets

My own playground for PLP (Programming Language Processing) using DeepLearning techniques
Python
19
star
20

pytorch_math_dataset

Pytorch Playground for Mathematical Reasoning Dataset
Jupyter Notebook
18
star
21

khats

Khats, cats on Higher-Kinded amphets
Scala
16
star
22

play-crud-siena

A module for the Play! web framework providing a CRUD mechanism when using Siena DB APIs.
Java
16
star
23

daemonad

A categorical programming facility for Scala that offers a direct API for working with monad & a few monad stacks (at least trying).
Scala
11
star
24

pytorch-neural-ode

Experiment with Neural ODE on Pytorch
Jupyter Notebook
9
star
25

maquereau

Come on taste my fresh Scala Macrooooos!!!
Scala
9
star
26

playzstream

Scala
8
star
27

freevan

Van Laarhoven Free Monad implementation
Scala
6
star
28

shapeless-rules

Play 2.3 generic Validation API with Shapeless
Scala
6
star
29

shameless

Shapeless funny extensions
Scala
6
star
30

snapshot_ensembles

Neural Network Snapshot Ensembles
Jupyter Notebook
5
star
31

jszipper

Generic Json Zipper
Scala
4
star
32

where-is-felipe2

where-is-felipe 2
Scala
4
star
33

scalameta-diff

Scala
3
star
34

mandubian-mvn

mandubian maven repo
3
star
35

generic-dao

Generic Dao for Java Generics and Enum + Spring + Hibernate
3
star
36

xwiki-selector

A GWT XWiki space/page selector with hooks on an existing form
Java
2
star
37

play2json

Play20 Json Demo
Scala
2
star
38

play2-mongodb-async

MongoDB Async Support to Play! Framework 2.0 based on Mongo Async Driver
Scala
2
star
39

mutimmutable

mutable in the small, immutable in the large
Scala
2
star
40

activator-play-autosource-reactivemongo

Activator template for ReactiveMongo Play Autosource - Automatic CRUD/REST Datasource.
Shell
2
star
41

shapotomic

Shapeless HList + Datomisca/Datomic Schema
Scala
1
star
42

buyme

Buy Me
JavaScript
1
star
43

play2-scala-richjson

Play2 Scala Rich Json
Scala
1
star
44

monitored

Scala
1
star
45

webgl-stream

JavaScript
1
star
46

mandubian.com

Mandubian Website
CSS
1
star
47

resource-test

Scala
1
star
48

memopedia

memopedia
JavaScript
1
star
49

FreeFood

FreeFood[I[_]] is the simplest recipe that can give food from ingredients I[_]
1
star
50

play2-data-resources

Play2 Scala Data Resources
Scala
1
star
51

rescator

Scala Very Simple Json API
Scala
1
star
52

ad-rust

An experimental study on using (& learning) Rust for Automatic Differentiation with ArrayFire and then applying that to build neural networks
Rust
1
star