Skip to content
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

Kebs 2.0 - further minor changes #358

Closed
wants to merge 1 commit into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Replace given with implicits
pkiersznowski committed Apr 16, 2024

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
commit 4f869baf4b54b3864d935430aa30118448d94b38
9 changes: 1 addition & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -668,13 +668,6 @@ If you're using recursive types - due to [this issue](https://github.com/circe/c
case class R(a: Int, rs: Seq[R]) derives Decoder, Encoder.AsObject
```


3. If you're using flat format or Snakified/Capitalized formats, remember to import `given` instances, e.g.:
```scala
object KebsProtocol extends KebsCirce with KebsCirce.Snakified
import KebsProtocol.{given, _}
```

#### - kebs generates akka-http / pekko-http Unmarshaller (kebs-akka-http / kebs-pekko-http)

It makes it very easy to use 1-element case-classes or `enumeratum` enums/value enums in eg. `parameters` directive:
@@ -729,7 +722,7 @@ import org.http4s.dsl.io._
import org.http4s.implicits._

import pl.iterators.kebs.opaque.Opaque
import pl.iterators.kebs.http4s.{given, _}
import pl.iterators.kebs.http4s._
import pl.iterators.kebs.instances.KebsInstances._ // optional, if you want instances support, ex. java.util.Currency

opaque type Age = Int
Original file line number Diff line number Diff line change
@@ -30,17 +30,17 @@ private[circe] trait KebsAutoDerivation extends CaseClass1ToValueClass {
}
trait KebsCirce extends KebsAutoDerivation {

inline given[T, A](using rep: ValueClassLike[T, A], decoder: Decoder[A]): Decoder[T] = {
implicit inline def kebsDecoder[T, A](using rep: ValueClassLike[T, A], decoder: Decoder[A]): Decoder[T] = {
decoder.emap(obj => Try(rep.apply(obj)).toEither.left.map(_.getMessage))
}

inline given[T, A](using rep: ValueClassLike[T, A], encoder: Encoder[A]): Encoder[T] =
implicit inline def kebsEncoder[T, A](using rep: ValueClassLike[T, A], encoder: Encoder[A]): Encoder[T] =
encoder.contramap(rep.unapply)

inline given[T, A](using rep: InstanceConverter[T, A], encoder: Encoder[A]): Encoder[T] =
implicit inline def kebsEncoder[T, A](using rep: InstanceConverter[T, A], encoder: Encoder[A]): Encoder[T] =
encoder.contramap(rep.encode)

inline given[T, A](using rep: InstanceConverter[T, A], decoder: Decoder[A]): Decoder[T] =
implicit inline def kebsDecoder[T, A](using rep: InstanceConverter[T, A], decoder: Decoder[A]): Decoder[T] =
decoder.emap(obj => Try(rep.decode(obj)).toEither.left.map(_.getMessage))
}

Original file line number Diff line number Diff line change
@@ -60,29 +60,29 @@ trait CirceValueEnum {
}

trait KebsEnumFormats extends CirceEnum with CirceValueEnum {
implicit inline given[E <: Enum](using ev: EnumLike[E]): Decoder[E] = enumDecoder(ev)
implicit inline def kebsEnumDecoder[E <: Enum](using ev: EnumLike[E]): Decoder[E] = enumDecoder(ev)

implicit inline given[E <: Enum](using ev: EnumLike[E]): Encoder[E] = enumEncoder(ev)
implicit inline def kebsEnumEncoder[E <: Enum](using ev: EnumLike[E]): Encoder[E] = enumEncoder(ev)

implicit inline given[V, E <: ValueEnumLikeEntry[V]](using ev: ValueEnumLike[V, E], decoder: Decoder[V]): Decoder[E] =
implicit inline def kebsValueEnumDecoder[V, E <: ValueEnumLikeEntry[V]](using ev: ValueEnumLike[V, E], decoder: Decoder[V]): Decoder[E] =
valueEnumDecoder(ev)

implicit inline given[V, E <: ValueEnumLikeEntry[V]](using ev: ValueEnumLike[V, E], encoder: Encoder[V]): Encoder[E] =
implicit inline def kebsValueEnumEncoder[V, E <: ValueEnumLikeEntry[V]](using ev: ValueEnumLike[V, E], encoder: Encoder[V]): Encoder[E] =
valueEnumEncoder(ev)

trait Uppercase extends CirceEnum {
implicit inline given[E <: Enum](using ev: EnumLike[E]): Decoder[E] =
implicit inline def kebsUppercaseEnumDecoder[E <: Enum](using ev: EnumLike[E]): Decoder[E] =
uppercaseEnumDecoder(ev)

implicit inline given[E <: Enum](using ev: EnumLike[E]): Encoder[E] =
implicit inline def kebsUppercaseEnumEncoder[E <: Enum](using ev: EnumLike[E]): Encoder[E] =
uppercaseEnumEncoder(ev)
}

trait Lowercase extends CirceEnum {
implicit inline given[E <: Enum](using ev: EnumLike[E]): Decoder[E] =
implicit inline def kebsLowercaseEnumDecoder[E <: Enum](using ev: EnumLike[E]): Decoder[E] =
lowercaseEnumDecoder(ev)

implicit inline given[E <: Enum](using ev: EnumLike[E]): Encoder[E] =
implicit inline def kebsLowercaseEnumEncoder[E <: Enum](using ev: EnumLike[E]): Encoder[E] =
lowercaseEnumEncoder(ev)
}
}
Original file line number Diff line number Diff line change
@@ -10,7 +10,7 @@ import pl.iterators.kebs.circe.model._

class CirceFormatCapitalizedVariantTests extends AnyFunSuite with Matchers {
object KebsProtocol extends KebsCirce with KebsCirce.Capitalized
import KebsProtocol.{given, _}
import KebsProtocol._

test("Flat format remains unchanged") {
val decoder = implicitly[Decoder[C]]
Original file line number Diff line number Diff line change
@@ -12,7 +12,7 @@ import io.circe.derivation.Configuration

class CirceFormatSnakifiedVariantTests extends AnyFunSuite with Matchers {
object KebsProtocol extends KebsCirce with KebsCirce.Snakified
import KebsProtocol.{given, _}
import KebsProtocol._

test("Flat format remains unchanged") {
val decoder = implicitly[Decoder[C]]
Original file line number Diff line number Diff line change
@@ -13,7 +13,7 @@ import pl.iterators.kebs.circe.model._

class CirceFormatTests extends AnyFunSuite with Matchers {
object KebsProtocol extends KebsCirce
import KebsProtocol.{given, _}
import KebsProtocol._

// https://github.com/circe/circe/issues/1980
case class R(a: Int, rs: Seq[R]) derives Decoder, Encoder.AsObject
Original file line number Diff line number Diff line change
@@ -17,7 +17,7 @@ class TimeInstancesMixinTests extends AnyFunSuite with Matchers {

test("Instant epoch milli format") {
object TimeInstancesProtocol extends KebsCirce with InstantEpochMilliLong
import TimeInstancesProtocol.{given, _}
import TimeInstancesProtocol._

"implicitly[ValueClassLike[Instant, Long]]" shouldNot typeCheck
"implicitly[ValueClassLike[Long, Instant]]" shouldNot typeCheck
@@ -33,7 +33,7 @@ class TimeInstancesMixinTests extends AnyFunSuite with Matchers {

test("Duration nanos format, Instant epoch milli format") {
object TimeInstancesProtocol extends KebsCirce with DurationNanosLong with InstantEpochMilliLong
import TimeInstancesProtocol.{given, _}
import TimeInstancesProtocol._

"implicitly[ValueClassLike[Instant, Long]]" shouldNot typeCheck
"implicitly[ValueClassLike[Long, Instant]]" shouldNot typeCheck
@@ -64,7 +64,7 @@ class TimeInstancesMixinTests extends AnyFunSuite with Matchers {
override implicit val localDateTimeFormatter: InstanceConverter[LocalDateTime, String] =
InstanceConverter.apply[LocalDateTime, String](_.format(formatter), LocalDateTime.parse(_, formatter))
}
import TimeInstancesProtocol.{given, _}
import TimeInstancesProtocol._

"implicitly[ValueClassLike[LocalDateTime, String]]" shouldNot typeCheck
"implicitly[ValueClassLike[String, LocalDateTime]]" shouldNot typeCheck
@@ -98,7 +98,7 @@ class TimeInstancesMixinTests extends AnyFunSuite with Matchers {
}
}
}
import TimeInstancesProtocol.{given, _}
import TimeInstancesProtocol._

"implicitly[ValueClassLike[LocalDateTime, String]]" shouldNot typeCheck
"implicitly[ValueClassLike[String, LocalDateTime]]" shouldNot typeCheck
Original file line number Diff line number Diff line change
@@ -5,7 +5,7 @@ import scala.deriving.Mirror
final class ValueClassLike[VC, F1](val apply: F1 => VC, val unapply: VC => F1)

trait CaseClass1ToValueClass {
inline given[T <: Product, F1](using m: Mirror.ProductOf[T], teq: m.MirroredElemTypes =:= F1 *: EmptyTuple.type): ValueClassLike[T, F1] = {
implicit inline def caseClass1ToValueClassLike[T <: Product, F1](using m: Mirror.ProductOf[T], teq: m.MirroredElemTypes =:= F1 *: EmptyTuple.type): ValueClassLike[T, F1] = {
new ValueClassLike[T, F1](f1 => m.fromProduct(Tuple1(f1)), _.productElement(0).asInstanceOf[F1])
}
}
14 changes: 7 additions & 7 deletions doobie/src/main/scala-3/pl/iterators/kebs/doobie/Kebs.scala
Original file line number Diff line number Diff line change
@@ -8,17 +8,17 @@ import pl.iterators.kebs.core.macros.ValueClassLike
import scala.reflect.ClassTag

trait Kebs {
inline given[A, M](using vcLike: ValueClassLike[A, M], m: Meta[M]): Meta[A] = m.imap(vcLike.apply)(vcLike.unapply)
implicit inline def meta[A, M](using vcLike: ValueClassLike[A, M], m: Meta[M]): Meta[A] = m.imap(vcLike.apply)(vcLike.unapply)

inline given[A, M](using vcLike: ValueClassLike[A, M], m: Meta[Option[M]]): Meta[Option[A]] = m.imap(_.map(vcLike.apply))(_.map(vcLike.unapply))
implicit inline def metaOption[A, M](using vcLike: ValueClassLike[A, M], m: Meta[Option[M]]): Meta[Option[A]] = m.imap(_.map(vcLike.apply))(_.map(vcLike.unapply))

inline given[A, M](using vcLike: ValueClassLike[A, M], m: Meta[Array[M]], cta: ClassTag[A], ctm: ClassTag[M]): Meta[Array[A]] = m.imap(_.map(vcLike.apply))(_.map(vcLike.unapply))
implicit inline def metaArray[A, M](using vcLike: ValueClassLike[A, M], m: Meta[Array[M]], cta: ClassTag[A], ctm: ClassTag[M]): Meta[Array[A]] = m.imap(_.map(vcLike.apply))(_.map(vcLike.unapply))

inline given[A, M](using vcLike: ValueClassLike[A, M], m: Meta[Array[Option[M]]], cta: ClassTag[Option[A]]): Meta[Array[Option[A]]] = m.imap(_.map(_.map(vcLike.apply)))(_.map(_.map(vcLike.unapply)))
implicit inline def metaArrayOption[A, M](using vcLike: ValueClassLike[A, M], m: Meta[Array[Option[M]]], cta: ClassTag[Option[A]]): Meta[Array[Option[A]]] = m.imap(_.map(_.map(vcLike.apply)))(_.map(_.map(vcLike.unapply)))

inline given[A, M](using instanceConverter: InstanceConverter[A, M], m: Meta[M]): Meta[A] = m.imap(instanceConverter.decode)(instanceConverter.encode)
implicit inline def meta[A, M](using instanceConverter: InstanceConverter[A, M], m: Meta[M]): Meta[A] = m.imap(instanceConverter.decode)(instanceConverter.encode)

inline given[A, M](using instanceConverter: InstanceConverter[A, M], m: Meta[Array[M]], cta: ClassTag[A], ctm: ClassTag[M]): Meta[Array[A]] = m.imap(_.map(instanceConverter.decode))(_.map(instanceConverter.encode))
implicit inline def metaArray[A, M](using instanceConverter: InstanceConverter[A, M], m: Meta[Array[M]], cta: ClassTag[A], ctm: ClassTag[M]): Meta[Array[A]] = m.imap(_.map(instanceConverter.decode))(_.map(instanceConverter.encode))

inline given[A, M](using instanceConverter: InstanceConverter[A, M], m: Meta[Array[Option[M]]], cta: ClassTag[Option[A]]): Meta[Array[Option[A]]] = m.imap(_.map(_.map(instanceConverter.decode)))(_.map(_.map(instanceConverter.encode)))
implicit inline def metaArrayOption[A, M](using instanceConverter: InstanceConverter[A, M], m: Meta[Array[Option[M]]], cta: ClassTag[Option[A]]): Meta[Array[Option[A]]] = m.imap(_.map(_.map(instanceConverter.decode)))(_.map(_.map(instanceConverter.encode)))
}
Original file line number Diff line number Diff line change
@@ -7,19 +7,19 @@ import scala.reflect.Enum
import pl.iterators.kebs.core.enums.EnumLike

trait KebsEnums {
inline given enumMeta[E](using e: EnumLike[E]): Meta[E] = Meta.StringMeta.imap(e.valueOf)(_.toString)
inline given enumArrayMeta[E](using e: EnumLike[E], m: Meta[Array[String]], ct: ClassTag[E]): Meta[Array[E]] = m.imap(_.map(e.valueOf))(_.map(_.toString))
inline given enumOptionArrayMeta[E](using e: EnumLike[E], m: Meta[Array[Option[String]]], ct: ClassTag[Option[E]]): Meta[Array[Option[E]]] = m.imap(_.map(_.map(e.valueOf)))(_.map(_.map(_.toString)))
implicit inline def enumMeta[E](using e: EnumLike[E]): Meta[E] = Meta.StringMeta.imap(e.valueOf)(_.toString)
implicit inline def enumArrayMeta[E](using e: EnumLike[E], m: Meta[Array[String]], ct: ClassTag[E]): Meta[Array[E]] = m.imap(_.map(e.valueOf))(_.map(_.toString))
implicit inline def enumOptionArrayMeta[E](using e: EnumLike[E], m: Meta[Array[Option[String]]], ct: ClassTag[Option[E]]): Meta[Array[Option[E]]] = m.imap(_.map(_.map(e.valueOf)))(_.map(_.map(_.toString)))

trait Uppercase {
inline given enumUppercaseMeta[E](using e: EnumLike[E]): Meta[E] = Meta.StringMeta.imap(s => e.values.find(_.toString.toUpperCase == s).getOrElse(throw new IllegalArgumentException(s"enum case not found: $s")))(_.toString.toUpperCase)
inline given enumUppercaseArrayMeta[E](using e: EnumLike[E], m: Meta[Array[String]], ct: ClassTag[E]): Meta[Array[E]] = m.imap(_.map(s => e.values.find(_.toString.toUpperCase == s).getOrElse(throw new IllegalArgumentException(s"enum case not found: $s"))))(_.map(_.toString.toUpperCase))
inline given enumUppercaseOptionArrayMeta[E](using e: EnumLike[E], m: Meta[Array[Option[String]]], ct: ClassTag[Option[E]]): Meta[Array[Option[E]]] = m.imap(_.map(_.map(s => e.values.find(_.toString.toUpperCase == s).getOrElse(throw new IllegalArgumentException(s"enum case not found: $s")))))(_.map(_.map(_.toString.toUpperCase)))
implicit inline def enumUppercaseMeta[E](using e: EnumLike[E]): Meta[E] = Meta.StringMeta.imap(s => e.values.find(_.toString.toUpperCase == s).getOrElse(throw new IllegalArgumentException(s"enum case not found: $s")))(_.toString.toUpperCase)
implicit inline def enumUppercaseArrayMeta[E](using e: EnumLike[E], m: Meta[Array[String]], ct: ClassTag[E]): Meta[Array[E]] = m.imap(_.map(s => e.values.find(_.toString.toUpperCase == s).getOrElse(throw new IllegalArgumentException(s"enum case not found: $s"))))(_.map(_.toString.toUpperCase))
implicit inline def enumUppercaseOptionArrayMeta[E](using e: EnumLike[E], m: Meta[Array[Option[String]]], ct: ClassTag[Option[E]]): Meta[Array[Option[E]]] = m.imap(_.map(_.map(s => e.values.find(_.toString.toUpperCase == s).getOrElse(throw new IllegalArgumentException(s"enum case not found: $s")))))(_.map(_.map(_.toString.toUpperCase)))
}

trait Lowercase {
inline given enumLowercaseMeta[E](using e: EnumLike[E]): Meta[E] = Meta.StringMeta.imap(s => e.values.find(_.toString.toLowerCase == s).getOrElse(throw new IllegalArgumentException(s"enum case not found: $s")))(_.toString.toLowerCase)
inline given enumLowercaseMeta[E](using e: EnumLike[E], m: Meta[Array[String]], ct: ClassTag[E]): Meta[Array[E]] = m.imap(_.map(s => e.values.find(_.toString.toLowerCase == s).getOrElse(throw new IllegalArgumentException(s"enum case not found: $s"))))(_.map(_.toString.toLowerCase))
inline given enumLowercaseOptionArrayMeta[E](using e: EnumLike[E], m: Meta[Array[Option[String]]], ct: ClassTag[Option[E]]): Meta[Array[Option[E]]] = m.imap(_.map(_.map(s => e.values.find(_.toString.toLowerCase == s).getOrElse(throw new IllegalArgumentException(s"enum case not found: $s")))))(_.map(_.map(_.toString.toLowerCase)))
implicit inline def enumLowercaseMeta[E](using e: EnumLike[E]): Meta[E] = Meta.StringMeta.imap(s => e.values.find(_.toString.toLowerCase == s).getOrElse(throw new IllegalArgumentException(s"enum case not found: $s")))(_.toString.toLowerCase)
implicit inline def enumLowercaseMeta[E](using e: EnumLike[E], m: Meta[Array[String]], ct: ClassTag[E]): Meta[Array[E]] = m.imap(_.map(s => e.values.find(_.toString.toLowerCase == s).getOrElse(throw new IllegalArgumentException(s"enum case not found: $s"))))(_.map(_.toString.toLowerCase))
implicit inline def enumLowercaseOptionArrayMeta[E](using e: EnumLike[E], m: Meta[Array[Option[String]]], ct: ClassTag[Option[E]]): Meta[Array[Option[E]]] = m.imap(_.map(_.map(s => e.values.find(_.toString.toLowerCase == s).getOrElse(throw new IllegalArgumentException(s"enum case not found: $s")))))(_.map(_.map(_.toString.toLowerCase)))
}
}
Original file line number Diff line number Diff line change
@@ -8,9 +8,9 @@ import org.scalatest.funsuite.AnyFunSuite
import org.scalatest.matchers.should.Matchers
import pl.iterators.kebs.doobie.model._
import pl.iterators.kebs.enums.KebsEnum
import pl.iterators.kebs.doobie.given
import pl.iterators.kebs.doobie.enums.given
import pl.iterators.kebs.instances.KebsInstances.given
import pl.iterators.kebs.doobie._
import pl.iterators.kebs.doobie.enums._
import pl.iterators.kebs.instances.KebsInstances._
import pl.iterators.kebs.opaque.Opaque

import java.util.Currency
Original file line number Diff line number Diff line change
@@ -10,7 +10,7 @@ import scala.reflect.{ClassTag, Enum}
import pl.iterators.kebs.core.enums.EnumLike

trait KebsEnumeratum {
inline given [E <: EnumEntry](using m: Mirror.SumOf[E], ct: ClassTag[E]): EnumLike[E] = {
implicit inline def enumLike[E <: EnumEntry](using m: Mirror.SumOf[E], ct: ClassTag[E]): EnumLike[E] = {
val enumValues = summonCases[m.MirroredElemTypes, E]
new EnumLike[E] {
override def values: immutable.Seq[E] = enumValues.toSeq
Original file line number Diff line number Diff line change
@@ -10,7 +10,7 @@ import scala.reflect.{ClassTag, Enum}
import pl.iterators.kebs.core.enums.{ValueEnumLike, ValueEnumLikeEntry}

trait KebsValueEnumeratum {
inline given [V, E <: ValueEnumEntry[V] with ValueEnumLikeEntry[V]](using m: Mirror.SumOf[E], ct: ClassTag[E]): ValueEnumLike[V, E] = {
inline implicit def valueEnumLike[V, E <: ValueEnumEntry[V] with ValueEnumLikeEntry[V]](using m: Mirror.SumOf[E], ct: ClassTag[E]): ValueEnumLike[V, E] = {
val enumValues = summonValueCases[m.MirroredElemTypes, V, E]
new ValueEnumLike[V, E] {
override def values: immutable.Seq[E] = enumValues
Original file line number Diff line number Diff line change
@@ -18,7 +18,7 @@ trait EnumUnmarshallers {
}
}

given kebsEnumUnmarshaller[E <: Enum](using e: EnumLike[E]): FromStringUnmarshaller[E] =
implicit def kebsEnumUnmarshaller[E <: Enum](using e: EnumLike[E]): FromStringUnmarshaller[E] =
enumUnmarshaller
}

@@ -39,19 +39,19 @@ trait ValueEnumUnmarshallers extends EnumUnmarshallers {
}
}

given kebsValueEnumUnmarshaller[V, E <: ValueEnumLikeEntry[V]](using `enum`: ValueEnumLike[V, E], cls: ClassTag[V]): Unmarshaller[V, E] =
implicit def kebsValueEnumUnmarshaller[V, E <: ValueEnumLikeEntry[V]](using `enum`: ValueEnumLike[V, E], cls: ClassTag[V]): Unmarshaller[V, E] =
valueEnumUnmarshaller

given kebsIntValueEnumFromStringUnmarshaller[E <: ValueEnumLikeEntry[Int]](using ev: ValueEnumLike[Int, E]): FromStringUnmarshaller[E] =
implicit def kebsIntValueEnumFromStringUnmarshaller[E <: ValueEnumLikeEntry[Int]](using ev: ValueEnumLike[Int, E]): FromStringUnmarshaller[E] =
intFromStringUnmarshaller andThen valueEnumUnmarshaller

given kebsLongValueEnumFromStringUnmarshaller[E <: ValueEnumLikeEntry[Long]](using ev: ValueEnumLike[Long, E]): FromStringUnmarshaller[E] =
implicit def kebsLongValueEnumFromStringUnmarshaller[E <: ValueEnumLikeEntry[Long]](using ev: ValueEnumLike[Long, E]): FromStringUnmarshaller[E] =
longFromStringUnmarshaller andThen valueEnumUnmarshaller

given kebsShortValueEnumFromStringUnmarshaller[E <: ValueEnumLikeEntry[Short]](using ev: ValueEnumLike[Short, E]): FromStringUnmarshaller[E] =
implicit def kebsShortValueEnumFromStringUnmarshaller[E <: ValueEnumLikeEntry[Short]](using ev: ValueEnumLike[Short, E]): FromStringUnmarshaller[E] =
shortFromStringUnmarshaller andThen valueEnumUnmarshaller

given kebsByteValueEnumFromStringUnmarshaller[E <: ValueEnumLikeEntry[Byte]](using ev: ValueEnumLike[Byte, E]): FromStringUnmarshaller[E] =
implicit def kebsByteValueEnumFromStringUnmarshaller[E <: ValueEnumLikeEntry[Byte]](using ev: ValueEnumLike[Byte, E]): FromStringUnmarshaller[E] =
byteFromStringUnmarshaller andThen valueEnumUnmarshaller
}

Original file line number Diff line number Diff line change
@@ -52,6 +52,6 @@ object InstanceUUID {
def apply[T](using rep: InstanceConverter[T, UUID]) = new PathVar[T](str => Try(rep.decode(UUID.fromString(str))))
}

given[T, U](using rep: ValueClassLike[T, U], qpd: QueryParamDecoder[U]): QueryParamDecoder[T] = qpd.emap(u => Try(rep.apply(u)).toEither.left.map(t => ParseFailure(t.getMessage, t.getMessage)))
given[T, U](using rep: InstanceConverter[T, U], qpd: QueryParamDecoder[U]): QueryParamDecoder[T] = qpd.emap(u => Try(rep.decode(u)).toEither.left.map(t => ParseFailure(t.getMessage, t.getMessage)))
given[E <: Enum](using e: EnumLike[E]): QueryParamDecoder[E] = QueryParamDecoder[String].emap(str => Try(e.values.find(_.toString.toUpperCase == str.toUpperCase).getOrElse(throw new IllegalArgumentException(s"enum case not found: $str"))).toEither.left.map(t => ParseFailure(t.getMessage, t.getMessage)))
implicit def valueClassQueryParamDecoder[T, U](using rep: ValueClassLike[T, U], qpd: QueryParamDecoder[U]): QueryParamDecoder[T] = qpd.emap(u => Try(rep.apply(u)).toEither.left.map(t => ParseFailure(t.getMessage, t.getMessage)))
implicit def instanceConverterQueryParamDecoder[T, U](using rep: InstanceConverter[T, U], qpd: QueryParamDecoder[U]): QueryParamDecoder[T] = qpd.emap(u => Try(rep.decode(u)).toEither.left.map(t => ParseFailure(t.getMessage, t.getMessage)))
implicit def enumQueryParamDecoder[E <: Enum](using e: EnumLike[E]): QueryParamDecoder[E] = QueryParamDecoder[String].emap(str => Try(e.values.find(_.toString.toUpperCase == str.toUpperCase).getOrElse(throw new IllegalArgumentException(s"enum case not found: $str"))).toEither.left.map(t => ParseFailure(t.getMessage, t.getMessage)))
Loading