I am trying to write code that tracks changes to records and applies them later. In a dynamic language, I would do this by simply saving the list [List [(String, Any)] pairs log and then simply applying them as an update to the original record when I finally decide to commit the changes.
I need to be able to analyze updates, so the list of update functions is not suitable.
In Scala, this is pretty trivial using reflection, however I would like to implement a safe version.
My first attempt was to try with the formless. This works well if we know specific types.
import shapeless._ import record._ import syntax.singleton._ case class Person(name:String, age:Int) val bob = Person("Bob", 31) val gen = LabelledGeneric[Person] val updated = gen.from( gen.to(bob) + ('age ->> 32) ) // Result: Person("Bob", 32)
However, I canβt understand how to make this work as a whole.
trait Record[T] def update( ??? ):T }
Given how shapeless does this, I'm not sure if this is even possible?
If I accept a lot of patterns, as an option with a poor mother, I could do something in the following order.
object Contact { sealed trait Field[T] case object Name extends Field[String] case object Age extends Field[Int] } // A typeclass would be cleaner, but too verbose for this simple example. case class Contact(...) extends Record[Contact, Contact.Field] { def update[T]( field:Contact.Field[T], value:T ) = field match { case Contact.Name => contact.copy( name = value ) case Contact.Age => contact.copy( age = value ) } }
However, this is not particularly elegant and requires a large number of templates. Perhaps I could write my own macro to handle this, however this seems like a pretty common thing - is there a way to handle this using Shapeless or a similar macro library already?