Similar to this case class question but with a twist:
I have a case class which has some deeply nested case classes as properties. As a simple example,
case class Foo(fooPropA:Option[String], fooPropB:Option[Int])
case class Bar(barPropA:String, barPropB:Int)
case class FooBar(name:Option[String], foo:Foo, optionFoo: Option[Foo], bar:Option[Bar])
I'd like to merge two FooBar case classes together, taking the values which exist for an input and applying them to an existing instance, producing an updated version:
val fb1 = FooBar(Some("one"), Foo(Some("propA"), None), Some(Foo(Some("propA"), Some(3))), Some(Bar("propA", 4)))
val fb2 = FooBar(None, Foo(Some("updated"), Some(2)), Some(Foo(Some("baz"), None)), None)
val merged = fb1.merge(fb2)
//merged = FooBar(Some("one"), Foo(Some("updated"), Some(2)), Some(Foo(Some("baz"), Some(3))), Some(Bar("propA", 4)))
I know I can use a lens to compose the deeply nested property updates; however, I feel this will require a lot of boiler plate code: I need a lens for every property, and another composed lens in the parent class. This seems like a lot to maintain, even if using the more succinct lens creation approach in shapeless.
The tricky part is the optionFoo element: in this scenario, both elements exist with a Some(value). However, I'd like to merge the inner-option properties, not just overwrite fb1 with fb2's new values.
I'm wondering if there is a good approach to merge these two values together in a way which requires minimal code. My gut feeling tells me to try to use the unapply
method on the case class to return a tuple, iterate over and combine the tuples into a new tuple, and then apply the tuple back to a case class.
Is there a more efficient way to go about doing this?