/scala-recursive-map

Scala utility to recursively traverse and transform json like tree structure made of Lists and Maps

Primary LanguageScala

Scala Recursive Map

Scala utility to recursively traverse and transform json like tree structure made of Lists and Maps

Installation

There is no maven artifact published jet. One way how to add this project is to add direct dependency to github repo in build file

build.sbt:

lazy val p = project.
  dependsOn(uri("git://github.com/muntis/scala-recursive-map"))

or project/Build.scala:

lazy val p = Project(id = "project" ...).
  dependsOn(uri("git://github.com/muntis/scala-recursive-map"))

Usage

  import org.recmap.MapRecursiveExtensions._
  tree.recursiveMap{
    // partial transformation function
  }

Partial function signature:

  ((path: Any, value: Any)) => newValue: Any

To unleash full power of scala matcher, path is case class created by "/" operand. Path nodes are strings for map keys and integers for list indexes.

Example

Let's consider structure

  val department = Map(
    "name" -> "Sales",
    "employees" -> List(
      Map("name" -> "Bob", "surname"-> "Smith", "salary" -> BigDecimal(1000.00)),
      Map("name" -> "Mary", "surname"-> "Jones", "salary" -> BigDecimal(1700.10))
    )
  )

Partial function will be called with values:

("name", "Sales")
("employees", List(Map("name" -> "Bob", "surname" -> "Smith", "salary" -> BigDecimal(1000.0)), Map("name" -> "Mary", "surname" -> "Jones", "salary" -> BigDecimal(1700.1))))
("employees" / 0, Map("name" -> "Bob", "surname" -> "Smith", "salary" -> BigDecimal(1000.0)))
("employees" / 0 / "name", "Bob")
("employees" / 0 / "surname", "Smith")
("employees" / 0 / "salary", BigDecimal(1000.0))
("employees" / 1, Map("name" -> "Mary", "surname" -> "Jones", "salary" -> BigDecimal(1700.1)))
("employees" / 1 / "name", "Mary")
("employees" / 1 / "surname", "Jones")
("employees" / 1 / "salary", BigDecimal(1700.1))

Transformations:

Adding index to employee:

  department.recursiveMap{
    case ("employees" / index, employee: Map[String, Any]) => employee + ("index" -> index)
  }
  
  // Result: 
  // Map(name -> Sales, employees ->  List(
  //  Map(name -> Bob, surname -> Smith, salary -> 1000.0, index -> 0), 
  //  Map(name -> Mary, surname -> Jones, salary -> 1700.1, index -> 1)
  // ))

Employee name/surname to lower case:

  department.recursiveMap{
    case ("employees" / _ / ("name"| "surname"), name: String) => name.toLowerCase
  }
  
  // Result:
  // Map(name -> Sales, employees ->  List(
  //  Map(name -> bob, surname -> smith, salary -> 1000.0), 
  //  Map(name -> mary, surname -> jones, salary -> 1700.1)
  // ))

Change types of tree leaves (I'm looking at you MongoDb):

  department.recursiveMap{
    case (_, bd: BigDecimal) => "Now as string: "+bd.toString
  }
  
  // Result:
  // Map(name -> Sales, employees ->  List(
  //  Map(name -> Bob, surname -> Smith, salary -> Now as string: 1000.0), 
  //  Map(name -> Mary, surname -> Jones, salary -> Now as string: 1700.1)
  // ))

Or mix them all in one transformation:

  department.recursiveMap{
    case ("employees" / index, employee: Map[String, Any]) => employee + ("index" -> index)
    case ("employees" / _ / ("name"| "surname"), name: String) => name.toLowerCase
    case (_, bd: BigDecimal) => "Now as string: "+bd.toString
  }
  
  // Result:
  // Map(name -> Sales, employees ->  List(
  //  Map(name -> bob, surname -> smith, salary -> Now as string: 1000.0, index -> 0), 
  //  Map(name -> mary, surname -> jones, salary -> Now as string: 1700.1, index -> 1)
  // ))