j3d
j3d

Reputation: 9724

Play & JSON: How to make scala code more concise

Given the following case class...

case class Address(
  name: Option[String],
  zip: String,
  city: String
)

... I need to generate different JSON depending on whether or not name is defined:

val selector = address.name.map { addressName =>
  Json.obj(
    userId.key -> userId.value,
    "addresses.name" -> name,
    "$or" -> Json.arr(
      Json.obj(s"addresses.name" -> name),
      Json.obj("addresses.name" -> Json.obj("$ne" -> addressName))
    )
  )
} getOrElse {
  Json.obj(
    userId.key -> userId.value,
    "addresses.name" -> name
  )
}

If you look at the code above, both blocks have a common part:

Json.obj(
  userId.key -> userId.value,
  "addresses.name" -> name

Is there any way to make the code more concise without repeating the common part?

Upvotes: 1

Views: 123

Answers (1)

Dimitri
Dimitri

Reputation: 1786

There are two methods on JsObject you can use: ++ or +. The first one merges with another JsObject, the second one adds a new field.

val commonPart = Json.obj(
  userId.key -> userId.value,
  "addresses.name" -> name
)
val selector = address.name.map { addressName =>
  commonPart + "$or" -> Json.arr(
    Json.obj(s"addresses.name" -> name),
    Json.obj("addresses.name" -> Json.obj("$ne" -> addressName))
  )
} getOrElse(commonPart)

Using foldLeft:

val selector = address.name.foldLeft(Json.obj(userId.key -> userId.value, "addresses.name" -> name)) {
  (commonPart, addressName) =>
    commonPart + ("$or" -> Json.arr(
      Json.obj(s"addresses.name" -> name),
      Json.obj("addresses.name" -> Json.obj("$ne" -> addressName))
    ))
}

Upvotes: 1

Related Questions