Oscar Godson
Oscar Godson

Reputation: 32756

Add key/value to existing JsValue in Scala

I'm new to Scala and I'm trying to figure out how I would add a key/value to a JsValue. In JavaScript you might do something like SomeObject.newKey = newValue. Here's my real use case:

  def doAccountUpdate(account: db.models.Account, config: JsObject, job: JsValue) : JsValue = {
    val passwordParam = (job \ "params" \ "password")
    if (passwordParam.toOption.isDefined) {
      val password = (job \ "params" \ "password").get.as[String]
      val encrypted_password = Auth.passwordEncrypt(password)
      // ADD `encrypted_password`'s value TO `job \ params` so its `job \ params \ encryptedPassword`
    }

    Account.update(account, config, job)
  }

Account.update actually updates the DB so in my doAccountUpdate i'm prepping the data. One of those items I need to prep is password by encrypting it before passing it to Account.update. How do I do this?

EDIT

To explain why the question this is marked a duplicate of doesn't work for me is this is their example:

jsonObject.as[JsObject] + ("c" -> Json.toJson(3))

If I duplicate that in my code it would look like this:

updateJob = job.as[JsObject] + ("encryptedPassword" -> Json.toJson(encrypted_password))

but that outputs:

{
    "id":"...",
    "params": {
        "password":"Programmer2!"
    },
    "encryptedPassword":"$2a$10$EHnJHXh1sTORxliPocWfDuHnlRzu1YwG.kyBee.u85apCXTuLij.y"
}

Note how encryptedPassword isn't in params

Upvotes: 0

Views: 2804

Answers (1)

Mikesname
Mikesname

Reputation: 8901

As @danielnixon suggests, you can use JSON transformers for this. Here is an example:

val encryptPassword: Reads[JsObject] = (__ \ "params").json.update(
  (__ \ "password").read[String].flatMap(pw =>
    (__ \ "encryptedPassword").json.put(JsString(Auth.passwordEncrypt(pw)))
  )
)

This says we will:

  1. update the params object
  2. read the existing password
  3. put a new encryptedPassword branch in the params object

When you apply that with job.transform(encryptPassword) you'll get a JsResult that, if the params object exists and has a password field with a string value, will be JsSuccess - otherwise you'll get JsError. You can handle that with something like the following:

def doAccountUpdate(account: db.models.Account, config: JsObject, job: JsValue) : JsValue = {
  job.transform(encryptPassword) match {
    case JsSuccess(newJob, _) => Account.update(account, config, newJob)
    case JsError(errors) => sys.error("No password supplied!")
  }
}

Upvotes: 1

Related Questions