Make your trait sealed.
sealed trait Refreshable {
val expireAt: Instant
val version: Int
}
With Typelevel Scala the following variant works:
def refresh[T <: Refreshable, R <: HList](v: T)(implicit
generic: LabelledGeneric.Aux[T, R],
modifier: Modifier.Aux[R, Symbol @@ "version", Int, Int, R],
modifier1: Modifier.Aux[R, Symbol @@ "expireAt", Instant, Instant, R]): R = {
val rec = generic.to(v)
val rec1 = modifier(rec, _ + 1)
modifier1(rec1, _.plus(1L, ChronoUnit.MILLIS))
}
With Lightbend Scala (i.e. standard Scala)
def refresh[T <: Refreshable, R <: HList](v: T)(implicit
generic: LabelledGeneric.Aux[T, R],
modifier: Modifier.Aux[R, Witness.`'version`.T, Int, Int, R],
modifier1: Modifier.Aux[R, Witness.`'expireAt`.T, Instant, Instant, R]): R = {
val rec = generic.to(v)
val rec1 = modifier(rec, _ + 1)
modifier1(rec1, _.plus(1L, ChronoUnit.MILLIS))
}
If you prefer to work with updateWith
this is also possible:
def refresh[T <: Refreshable, R <: HList](v: T)(implicit
generic: LabelledGeneric.Aux[T, R],
modifier: Modifier.Aux[R, Witness.`'version`.T, Int, Int, R],
modifier1: Modifier.Aux[R, Witness.`'expireAt`.T, Instant, Instant, R],
selector: Selector.Aux[R, Witness.`'version`.T, Int],
selector1: Selector.Aux[R, Witness.`'expireAt`.T, Instant]): R = {
val rec = generic.to(v)
rec.updateWith('expireAt)(_.plus(1L, ChronoUnit.MILLIS))
.updateWith('version)(_ + 1)
}
Normally you don't need to specify type parameters T
and R
, they should be inferred:
refresh(A(1, Instant.now, 1)) //1 :: 2017-09-20T18:53:34.039Z :: 2 :: HNil
refresh(B("a", Instant.now, 1)) // a :: 2017-09-20T18:53:34.074Z :: 2 :: HNil
But if you do need you can specify them:
refresh[A, Record.`'id -> Int, 'expireAt -> Instant, 'version -> Int`.T](A(1, Instant.now, 1))
refresh[B, Record.`'name -> String, 'expireAt -> Instant, 'version -> Int`.T](B("a", Instant.now, 1))