-
Notifications
You must be signed in to change notification settings - Fork 40
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Circe's KeyDecoder and KeyEncoder derivations? #239
Comments
I don't think .asInstanceOf[p.Type] is a good idea here 1. Derive instances only for newtypes.Here you don't need magnolia at all. You can demand newtype-only derivation object keyEncoder extends Derivation[KeyEncoder] with NewTypeDerivation[KeyEncoder]{
def instance(implicit x: OnlyNewtypes): Nothing = x.absurd
}
object keyDecoder extends Derivation[KeyDecoder] with NewTypeDerivation[KeyDecoder]{
def instance(implicit x: OnlyNewtypes): Nothing = x.absurd
}
@implicitNotFound("use keyEncoder and keyDecoder annotations only for newtypes")
abstract final class OnlyNewtypes{
def absurd = Nothing
} 2. Derive instances for newtypes any single-parameter case classesActually I don't know exactly how to compile-time check for single-variabilty, I suppose it may involve shapeless or custom macro 3. Derive instances for newtypes and case classes of any arityI suppose we can define some general scheme, such as using some separators in the keys to derive variable class keyDecoder(sep: String = "::") {
type Typeclass[T] = KeyDecoder[T]
def combine[T](ctx: CaseClass[KeyDecoder, T]): KeyDecoder[T] =
if (ctx.isObject) key => if (key == ctx.typeName.short) Some(ctx.rawConstruct(Seq.empty)) else None
else { key =>
val parts = key.split(sep)
if (parts.length != ctx.parameters.length) None
else ctx.constructMonadic(p => p.typeclass.apply(parts(p.index)))
}
def dispatch[T](ctx: SealedTrait[KeyDecoder, T]): KeyDecoder[T] =
key => ctx.subtypes.view.flatMap(_.typeclass(key)).headOption
def instance[T]: KeyDecoder[T] = macro Magnolia.gen[T]
}
object keyDecoder extends keyDecoder("::") with Derivation[KeyDecoder] with NewTypeDerivation[KeyDecoder]
class keyEncoder(sep: String = "::") {
type Typeclass[T] = KeyEncoder[T]
def combine[T](ctx: CaseClass[KeyEncoder, T]): KeyEncoder[T] =
if (ctx.isObject) obj => ctx.typeName.short
else { cc =>
ctx.parameters.view.map(p => p.typeclass(p.dereference(cc))).mkString("::")
}
def dispatch[T](ctx: SealedTrait[KeyEncoder, T]): KeyEncoder[T] =
obj => ctx.dispatch(obj)(sub => sub.typeclass(sub.cast(obj)))
def instance[T]: KeyDecoder[T] = macro Magnolia.gen[T]
}
object keyEncoder extends keyEncoder("::") with Derivation[KeyEncoder] with NewTypeDerivation[KeyEncoder] This will handle most of basic cases with default separator as well as simple type for creating key encoders with custom separators |
@Odomontois thanks a lot! Option 3 seems great, got it working but I have no idea how to make the Also, I have another one for Http4s' Query Params, and it's probably completely wrong even if it works 😄 If you have any spare time, I would appreciate if you could have a look: https://github.com/gvolpe/pfps-shopping-cart/blob/second-edition/modules/core/src/main/scala/shop/ext/http4s/queryParam.scala I added a new Typeclass Derivation chapter to the book, which is centered around Derevo, would you be interested in giving it a proof-read once I have something presentable? It would mean a lot 😇 |
Oh you just updated the comment, nice! 😃 |
@gvolpe Sorry, unlike me you react so fast, I've updated my comment with more comprehensive solution |
@gvolpe Yeah I would gladly pre-read your book! |
That's great to hear, got an email to contact you? If you don't want to make it public, you can ping me first at |
@Odomontois sorry to bother again, I was thinking, do you think these instances could be part of Derevo? It seems something very common to have. Happy to submit a PR with these implementations. |
@gvolpe that would be great |
Here we go :) #257 |
AFAIU the derivations supported by
derevo
are the ones supported bycirce-derivation
, is that right? If so, then I guess it is not possible to deriveKeyDecoder
andKeyEncoder
instances without upstream support?Anyhow, my only need for now is to support derivation for these typeclasses for newtypes. Here's a simple example:
There are
KeyDecoder[UUID]
andKeyEncoder[UUID]
instances so this works but I wanted to go a bit further and get Derevo to do this for me. This is what I come up with.Do you see anything wrong?
I did something similiar for
KeyEncoder
but this one is weird because I need to return aString
and not sure what the empty case should be.This works but I wonder if there is any downside or something wrong in my implementations?
Appreciate your help, I've never used Magnolia before.
The text was updated successfully, but these errors were encountered: