magnolia
magnolia copied to clipboard
scala 3 auto derivation not totally automatic
I'm not understanding why with the following it its making me define Scalacheck arbitraries for nested models:
object ArbDerivation extends AutoDerivation[Arbitrary] {
override def join[T](ctx: CaseClass[Arbitrary, T]): Arbitrary[T] =
Arbitrary {
Gen.lzy(ctx.constructMonadic(param => param.typeclass.arbitrary))
}
override def split[T](ctx: SealedTrait[Arbitrary, T]): Arbitrary[T] =
Arbitrary {
Gen.oneOf(ctx.subtypes.map(_.typeclass.arbitrary)).flatMap(identity)
}
implicit private val monadicGen: Monadic[Gen] = new Monadic[Gen] {
override def point[A](value: A): Gen[A] = Gen.const(value)
override def flatMap[A, B](from: Gen[A])(fn: A => Gen[B]): Gen[B] = from.flatMap(fn)
override def map[A, B](from: Gen[A])(fn: A => B): Gen[B] = from.map(fn)
}
}
object ArbitraryInstances {
implicit val arbChange: Arbitrary[Event.Change] = ArbDerivation.autoDerived // not sure why this is required, it's just a case class
val arbEvent: Arbitrary[Event] = ArbDerivation.autoDerived
}
For example we have sealed trait Event And one of the Events has a list of Change like so:
sealed trait Event
object Event {
case class Change(
theType: String,
theId: String,
anotherType: String,
name: Option[String],
lastModifiedTime: Option[Long],
creationTime: Option[Long]
)
case class MyEventA
trace: String,
time: Instant,
auxInfo: String,
changes: List[Change]
) extends Event
case class MyEventB
trace: String,
time: Instant,
auxInfo: String,
changes: List[Change]
) extends Event
}
I don't understand why these supporting case classes are not autoDerived with when auto deriving the sealed trait Event.
There are 105 event case classes. 7 events reference the same list of changes.
Am I doing something wrong?
Could Magnolia be auto deriving the typeclass for Change for one of the events but then not finding it for the others or something?
Shouldn't you do an import ArbDerivation.{*, given} inside of ArbitraryInstances so that the given is visible?
@adamw I'll try that out and see if it works. I wasn't thinking this was the way it was working in Scala 2 but perhaps I was wrong in thinking this.
The APIs aren't 1:1 identical, as the way macros / implicits in Scala 2 and Scala 3 work differ in some details
@adamw I added import ArbDerivation.{*, given} and it now works as expected, thank you for the help.
@adamw I ran into another issue with this as well, autoDerived doesn't seem to handle value classes, is that true or is my ArbDerivation missing something? Here's what I see:
[error] |But Failed to synthesize an instance of type scala.deriving.Mirror.Of[
[error] | com.mycopackage.events.LastModifiedTime]:
[error] | * class LastModifiedTime is not a generic product because it is a value class
[error] | * class LastModifiedTime is not a generic sum because it is not a sealed class
It is indeed a value class around instant and there is an implicit arbitrary instance for Instant in scope where autoDerived is called.
I'm afraid value classes aren't supported: https://github.com/softwaremill/magnolia/blob/6b4ef79e102e045649e38c8b9212931b0c86b087/test/src/test/scala/magnolia1/tests/ValueClassesTests.scala#L7