I’m not really sure but I’d guess that it’s impossible to summon “the” instance of the case class (as there isn’t a single, unambiguous instance that can be summoned).
Unfortunately, I haven’t really dived into metaprogramming any more than required for what I have above, so I fear I can’t help you out here.
I think it is such a common use case to get a list of all child 'ClassTag’s for a given sealed trait/abstract class. It would save me so much error prone boilerplate. There are options, but only on JVM. I need something that also works in scala.js in a browser. If I find some solution I will post it here.
Wow. Thanks a lot @Jasper-M. Your scastie helped me to solve my problem.
tldr;
I adopted the code to compile with strict Scala 3 (? for _) and changed the names.
The context is an eventsourcing/cqrs framework built with Scala 3/JS (in browsers) using ZIO2, io.bullet.borer.Cbor, Skunk, Postgres and a few more. A fundamental idea is to use the same domain logic in the browser as on server side. In between is a transparent RPC mechanism (websockets) based on “registered” codecs for domain-specific objects like entities, events, completions, errors. Users can define them in custom domains, but they need to register the codecs. This is probably standard practice e. g. in Java EE, but the challenge was to make it work in jvm and js, if possible without dependencies. With this in place, there is no need for an additional transport layer, e.g. a REST api.
Now boilerplate is reduced a lot and it is much more robust to changes:
val live = ZLayer.scoped(makeLayer)
private def makeLayer = for
codecregistry <- ZIO.service[CodecRegistry]
result <- ZIO.fromAutoCloseable(make(codecregistry).register) // register is called on first usage
yield result
inline private def make(codecRegistry: CodecRegistry): Errors = new:
def register =
// given Codec[NotWorkable] = deriveCodec[NotWorkable]
// given Codec[NotInSequence] = deriveCodec[NotInSequence]
// given Codec[AggregateNotFound] = deriveCodec[AggregateNotFound]
// given Codec[RegistrationError] = deriveCodec[RegistrationError]
// given Codec[EncodingError] = deriveCodec[EncodingError]
// given Codec[DecodingError] = deriveCodec[DecodingError]
// given Codec[NoResult] = deriveCodec[NoResult]
// given Codec[ServerSideError] = deriveCodec[ServerSideError]
// given Codec[ClientSideError] = deriveCodec[ClientSideError]
given Codec[EventstoreError] = deriveAllCodecs[EventstoreError]
for
_ <- codecRegistry.registerSealed[EventstoreError]
// _ <- codecRegistry.register[NotWorkable]
// _ <- codecRegistry.register[NotInSequence]
// _ <- codecRegistry.register[AggregateNotFound]
// _ <- codecRegistry.register[RegistrationError]
// _ <- codecRegistry.register[EncodingError]
// _ <- codecRegistry.register[DecodingError]
// _ <- codecRegistry.register[NoResult]
// uups, I forgot ClientSideError
// _ <- codecRegistry.register[ServerSideError]
yield this
Thank you for this gist. If you remove the .toSet[T] in findSubclassModulesOfSealedTrait it will (obviously) return a List[T]. Will the order of this list always be equal to the order of definition in the source code?