Search code examples
scalacase-class

Merge two case class of same type, except some fields


If you have a case class like:

case class Foo(x: String, y: String, z: String)

And you have two instances like:

Foo("x1","y1","z1")
Foo("x2","y2","z2")

Is it possible to merge instance 1 in instance 2, except for field z, so that the result would be:

Foo("x1","y1","z2")

My usecase is just that I give JSON objects to a Backbone app through a Scala API, and the Backbone app gives me back a JSON of the same structure so that I can save/update it. These JSON objects are parsed as case class for easy Scala manipulation. But some fields should never be updated by the client side (like creationDate). For now I'm doing a manual merge but I'd like a more generic solution, a bit like an enhanced copy function.

What I'd like is something like this:

instanceFromDB.updateWith(instanceFromBackbone, excludeFields = "creationDate" )

But I'd like it to be typesafe :)

Edit: My case class have a lot more fields and I'd like the default bevavior to merge fields unless I explicitly say to not merge them.


Solution

  • What you want is already there; you just need to approach the problem the other way.

    case class Bar(x: String, y: String)
    val b1 = Bar("old", "tired")
    val b2 = Bar("new", "fresh")
    

    If you want everything in b2 not specifically mentioned, you should copy from b2; anything from b1 you want to keep you can mention explicitly:

    def keepY(b1: Bar, b2: Bar) = b2.copy(y = b1.y)
    
    scala> keepY(b1, b2)
    res1: Bar = Bar(new,tired)
    

    As long as you are copying between two instances of the same case class, and the fields are immutable like they are by default, this will do what you want.