-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #306 from theiterators/feature/http4s-stir
Support for http4s-stir based on kebs-akka-http
- Loading branch information
Showing
16 changed files
with
931 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package pl.iterators.kebs.matchers | ||
|
||
import pl.iterators.stir.server.PathMatcher1 | ||
import enumeratum.{Enum, EnumEntry} | ||
import pl.iterators.kebs.instances.InstanceConverter | ||
import pl.iterators.kebs.macros.CaseClass1Rep | ||
|
||
import scala.language.implicitConversions | ||
|
||
trait KebsMatchers extends pl.iterators.stir.server.PathMatchers { | ||
|
||
implicit class SegmentIsomorphism[U](segment: PathMatcher1[U]) { | ||
def as[T](implicit rep: CaseClass1Rep[T, U]): PathMatcher1[T] = segment.map(rep.apply) | ||
} | ||
|
||
implicit class SegmentConversion[Source](segment: PathMatcher1[Source]) { | ||
def to[Type](implicit ico: InstanceConverter[Type, Source]): PathMatcher1[Type] = segment.map(ico.decode) | ||
} | ||
|
||
object EnumSegment { | ||
def as[T <: EnumEntry: Enum]: PathMatcher1[T] = { | ||
val enumCompanion = implicitly[Enum[T]] | ||
Segment.map(enumCompanion.withNameInsensitive) | ||
} | ||
} | ||
} |
48 changes: 48 additions & 0 deletions
48
http4s-stir/src/main/scala-2/unmarshallers/enums/KebsEnumUnmarshallers.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
package pl.iterators.kebs.unmarshallers.enums | ||
|
||
import pl.iterators.stir.unmarshalling.PredefinedFromStringUnmarshallers._ | ||
import pl.iterators.stir.unmarshalling.{FromStringUnmarshaller, Unmarshaller} | ||
import cats.effect.IO | ||
import enumeratum.values._ | ||
import enumeratum.{Enum, EnumEntry} | ||
import pl.iterators.kebs.macros.enums.{EnumOf, ValueEnumOf} | ||
|
||
trait EnumUnmarshallers { | ||
final def enumUnmarshaller[E <: EnumEntry](`enum`: Enum[E]): FromStringUnmarshaller[E] = Unmarshaller { name => | ||
`enum`.withNameInsensitiveOption(name) match { | ||
case Some(enumEntry) => IO.pure(enumEntry) | ||
case None => | ||
IO.raiseError(new IllegalArgumentException(s"""Invalid value '$name'. Expected one of: ${`enum`.namesToValuesMap.keysIterator | ||
.mkString(", ")}""")) | ||
} | ||
} | ||
|
||
implicit def kebsEnumUnmarshaller[E <: EnumEntry](implicit ev: EnumOf[E]): FromStringUnmarshaller[E] = | ||
enumUnmarshaller(ev.`enum`) | ||
} | ||
|
||
trait ValueEnumUnmarshallers { | ||
final def valueEnumUnmarshaller[V, E <: ValueEnumEntry[V]](`enum`: ValueEnum[V, E]): Unmarshaller[V, E] = Unmarshaller { v => | ||
`enum`.withValueOpt(v) match { | ||
case Some(enumEntry) => IO.pure(enumEntry) | ||
case None => | ||
IO.raiseError(new IllegalArgumentException(s"""Invalid value '$v'. Expected one of: ${`enum`.valuesToEntriesMap.keysIterator | ||
.mkString(", ")}""")) | ||
} | ||
} | ||
|
||
implicit def kebsValueEnumUnmarshaller[V, E <: ValueEnumEntry[V]](implicit ev: ValueEnumOf[V, E]): Unmarshaller[V, E] = | ||
valueEnumUnmarshaller(ev.valueEnum) | ||
|
||
implicit def kebsIntValueEnumFromStringUnmarshaller[E <: IntEnumEntry](implicit ev: ValueEnumOf[Int, E]): FromStringUnmarshaller[E] = | ||
intFromStringUnmarshaller andThen valueEnumUnmarshaller(ev.valueEnum) | ||
implicit def kebsLongValueEnumFromStringUnmarshaller[E <: LongEnumEntry](implicit ev: ValueEnumOf[Long, E]): FromStringUnmarshaller[E] = | ||
longFromStringUnmarshaller andThen valueEnumUnmarshaller(ev.valueEnum) | ||
implicit def kebsShortValueEnumFromStringUnmarshaller[E <: ShortEnumEntry]( | ||
implicit ev: ValueEnumOf[Short, E]): FromStringUnmarshaller[E] = | ||
shortFromStringUnmarshaller andThen valueEnumUnmarshaller(ev.valueEnum) | ||
implicit def kebsByteValueEnumFromStringUnmarshaller[E <: ByteEnumEntry](implicit ev: ValueEnumOf[Byte, E]): FromStringUnmarshaller[E] = | ||
byteFromStringUnmarshaller andThen valueEnumUnmarshaller(ev.valueEnum) | ||
} | ||
|
||
trait KebsEnumUnmarshallers extends EnumUnmarshallers with ValueEnumUnmarshallers {} |
3 changes: 3 additions & 0 deletions
3
http4s-stir/src/main/scala-2/unmarshallers/enums/package.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
package pl.iterators.kebs.unmarshallers | ||
|
||
package object enums extends KebsEnumUnmarshallers |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package pl.iterators.kebs.matchers | ||
|
||
import pl.iterators.stir.server.PathMatcher1 | ||
import pl.iterators.kebs.instances.InstanceConverter | ||
import pl.iterators.kebs.macros.CaseClass1Rep | ||
import pl.iterators.kebs.macros.enums.EnumOf | ||
import scala.reflect.Enum | ||
|
||
import scala.language.implicitConversions | ||
|
||
trait KebsMatchers extends pl.iterators.stir.server.PathMatchers { | ||
|
||
implicit class SegmentIsomorphism[U](segment: PathMatcher1[U]) { | ||
def as[T](implicit rep: CaseClass1Rep[T, U]): PathMatcher1[T] = segment.map(rep.apply) | ||
} | ||
|
||
implicit class SegmentConversion[Source](segment: PathMatcher1[Source]) { | ||
def to[Type](implicit ico: InstanceConverter[Type, Source]): PathMatcher1[Type] = segment.map(ico.decode) | ||
} | ||
|
||
object EnumSegment { | ||
def as[T <: Enum](using e: EnumOf[T]): PathMatcher1[T] = { | ||
Segment.map(s => e.`enum`.values.find(_.toString().toLowerCase() == s.toLowerCase()).getOrElse(throw new IllegalArgumentException(s"""Invalid value '$s'. Expected one of: ${e.`enum`.values.mkString(", ")}"""))) | ||
} | ||
} | ||
} |
47 changes: 47 additions & 0 deletions
47
http4s-stir/src/main/scala-3/unmarshallers/enums/KebsEnumUnmarshallers.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
package pl.iterators.kebs.unmarshallers.enums | ||
|
||
import pl.iterators.stir.unmarshalling.PredefinedFromStringUnmarshallers._ | ||
import pl.iterators.stir.unmarshalling.{FromStringUnmarshaller, Unmarshaller} | ||
import cats.effect.IO | ||
import pl.iterators.kebs.macros.enums.{EnumOf, ValueEnumOf} | ||
import pl.iterators.kebs.enums.ValueEnum | ||
import scala.reflect.Enum | ||
import scala.reflect.ClassTag | ||
|
||
trait EnumUnmarshallers { | ||
final def enumUnmarshaller[E <: Enum](using e: EnumOf[E]): FromStringUnmarshaller[E] = Unmarshaller { name => | ||
e.`enum`.values.find(_.toString().toLowerCase() == name.toLowerCase()) match { | ||
case Some(enumEntry) => IO.pure(enumEntry) | ||
case None => | ||
IO.raiseError(new IllegalArgumentException(s"""Invalid value '$name'. Expected one of: ${e.`enum`.values.mkString(", ")}""")) | ||
} | ||
} | ||
|
||
given kebsEnumUnmarshaller[E <: Enum](using e: EnumOf[E]): FromStringUnmarshaller[E] = | ||
enumUnmarshaller | ||
} | ||
|
||
trait ValueEnumUnmarshallers extends EnumUnmarshallers { | ||
final def valueEnumUnmarshaller[V, E <: ValueEnum[V] with Enum](using `enum`: ValueEnumOf[V, E], cls: ClassTag[V]): Unmarshaller[V, E] = Unmarshaller { v => | ||
`enum`.`enum`.values.find(e => e.value == v) match { | ||
case Some(enumEntry) => IO.pure(enumEntry) | ||
case None => | ||
IO.raiseError(new IllegalArgumentException(s"""Invalid value '$v'. Expected one of: ${`enum`.`enum`.values.map(_.value).mkString(", ")}""")) | ||
} | ||
} | ||
|
||
given kebsValueEnumUnmarshaller[V, E <: ValueEnum[V] with Enum](using `enum`: ValueEnumOf[V, E], cls: ClassTag[V]): Unmarshaller[V, E] = | ||
valueEnumUnmarshaller | ||
|
||
given kebsIntValueEnumFromStringUnmarshaller[E <: ValueEnum[Int] with Enum](using ev: ValueEnumOf[Int, E]): FromStringUnmarshaller[E] = | ||
intFromStringUnmarshaller andThen valueEnumUnmarshaller | ||
given kebsLongValueEnumFromStringUnmarshaller[E <: ValueEnum[Long] with Enum](using ev: ValueEnumOf[Long, E]): FromStringUnmarshaller[E] = | ||
longFromStringUnmarshaller andThen valueEnumUnmarshaller | ||
given kebsShortValueEnumFromStringUnmarshaller[E <: ValueEnum[Short] with Enum]( | ||
using ev: ValueEnumOf[Short, E]): FromStringUnmarshaller[E] = | ||
shortFromStringUnmarshaller andThen valueEnumUnmarshaller | ||
given kebsByteValueEnumFromStringUnmarshaller[E <: ValueEnum[Byte] with Enum](using ev: ValueEnumOf[Byte, E]): FromStringUnmarshaller[E] = | ||
byteFromStringUnmarshaller andThen valueEnumUnmarshaller | ||
} | ||
|
||
trait KebsEnumUnmarshallers extends ValueEnumUnmarshallers {} |
3 changes: 3 additions & 0 deletions
3
http4s-stir/src/main/scala-3/unmarshallers/enums/package.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
package pl.iterators.kebs.unmarshallers | ||
|
||
package object enums extends KebsEnumUnmarshallers |
3 changes: 3 additions & 0 deletions
3
http4s-stir/src/main/scala/pl/iterators/kebs/matchers/package.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
package pl.iterators.kebs | ||
|
||
package object matchers extends KebsMatchers |
27 changes: 27 additions & 0 deletions
27
http4s-stir/src/main/scala/pl/iterators/kebs/unmarshallers/KebsUnmarshallers.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package pl.iterators.kebs.unmarshallers | ||
|
||
import pl.iterators.stir.unmarshalling.{FromStringUnmarshaller, Unmarshaller} | ||
import pl.iterators.kebs.instances.InstanceConverter | ||
import pl.iterators.kebs.macros.CaseClass1Rep | ||
|
||
trait KebsUnmarshallers extends LowPriorityKebsUnmarshallers { | ||
@inline | ||
implicit def kebsFromStringUnmarshaller[A, B](implicit rep: CaseClass1Rep[B, A], | ||
fsu: FromStringUnmarshaller[A]): FromStringUnmarshaller[B] = | ||
fsu andThen kebsUnmarshaller(rep) | ||
|
||
|
||
@inline | ||
implicit def kebsInstancesFromStringUnmarshaller[A, B](implicit ico: InstanceConverter[B, A], | ||
fsu: FromStringUnmarshaller[A]): FromStringUnmarshaller[B] = | ||
fsu andThen kebsInstancesUnmarshaller(ico) | ||
|
||
} | ||
|
||
trait LowPriorityKebsUnmarshallers { | ||
implicit def kebsInstancesUnmarshaller[A, B](implicit ico: InstanceConverter[B, A]): Unmarshaller[A, B] = | ||
Unmarshaller.strict[A, B](ico.decode) | ||
|
||
implicit def kebsUnmarshaller[A, B](implicit rep: CaseClass1Rep[B, A]): Unmarshaller[A, B] = | ||
Unmarshaller.strict[A, B](rep.apply) | ||
} |
3 changes: 3 additions & 0 deletions
3
http4s-stir/src/main/scala/pl/iterators/kebs/unmarshallers/package.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
package pl.iterators.kebs | ||
|
||
package object unmarshallers extends KebsUnmarshallers |
83 changes: 83 additions & 0 deletions
83
http4s-stir/src/test/scala-2/pl/iterators/kebs/Http4sStirTagsDomain.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
package pl.iterators.kebs | ||
|
||
import enumeratum.values.{IntEnum, IntEnumEntry, StringEnum, StringEnumEntry} | ||
import enumeratum.{Enum, EnumEntry} | ||
import pl.iterators.kebs.tag.meta.tagged | ||
import pl.iterators.kebs.tagged._ | ||
|
||
import java.net.URI | ||
import java.util.UUID | ||
|
||
@tagged trait Tags { | ||
trait IdTag | ||
type Id = Long @@ IdTag | ||
|
||
trait TestIdTag | ||
type TestId = UUIDId @@ TestIdTag | ||
|
||
trait TestDoubleTag | ||
type TestDouble = Double @@ TestDoubleTag | ||
|
||
type UUIDId = UUID | ||
object UUIDId { | ||
def generate[T]: UUIDId @@ T = UUID.randomUUID().taggedWith[T] | ||
def fromString[T](str: String): UUIDId @@ T = | ||
UUID.fromString(str).taggedWith[T] | ||
} | ||
|
||
trait TestTaggedUriTag | ||
type TestTaggedUri = URI @@ TestTaggedUriTag | ||
|
||
} | ||
|
||
object Domain extends Tags { | ||
case class I(i: Int) | ||
case class S(s: String) | ||
case class P[A](a: A) | ||
case class CantUnmarshall(s: String, i: Int) | ||
case object O | ||
|
||
sealed trait Greeting extends EnumEntry | ||
object Greeting extends Enum[Greeting] { | ||
case object Hello extends Greeting | ||
case object GoodBye extends Greeting | ||
case object Hi extends Greeting | ||
case object Bye extends Greeting | ||
|
||
val values = findValues | ||
} | ||
|
||
sealed abstract class LibraryItem(val value: Int) extends IntEnumEntry | ||
|
||
object LibraryItem extends IntEnum[LibraryItem] { | ||
case object Book extends LibraryItem(1) | ||
case object Movie extends LibraryItem(2) | ||
case object Magazine extends LibraryItem(3) | ||
case object CD extends LibraryItem(4) | ||
|
||
val values = findValues | ||
} | ||
|
||
case class Red(value: Int) | ||
case class Green(value: Int) | ||
case class Blue(value: Int) | ||
case class Color(red: Red, green: Green, blue: Blue) | ||
|
||
sealed abstract class ShirtSize(val value: String) extends StringEnumEntry | ||
object ShirtSize extends StringEnum[ShirtSize] { | ||
case object Small extends ShirtSize("S") | ||
case object Medium extends ShirtSize("M") | ||
case object Large extends ShirtSize("L") | ||
|
||
val values = findValues | ||
} | ||
|
||
sealed trait SortOrder extends EnumEntry | ||
object SortOrder extends Enum[SortOrder] { | ||
case object Asc extends SortOrder | ||
case object Desc extends SortOrder | ||
|
||
override val values = findValues | ||
} | ||
|
||
} |
Oops, something went wrong.