diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f3e11ef1..baf749fc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,7 +14,7 @@ jobs: strategy: matrix: os: [ubuntu-latest] - scala: [2.12.18, 2.13.11, 3.3.0] + scala: [2.13.11, 3.3.0] java: [temurin@17] runs-on: ${{ matrix.os }} steps: diff --git a/.mergify.yml b/.mergify.yml index ecd279f9..825656fc 100644 --- a/.mergify.yml +++ b/.mergify.yml @@ -11,7 +11,6 @@ pull_request_rules: conditions: - base=master - author=scala-steward - - status-success=Build and Test (ubuntu-latest, 2.12.18, temurin@17) - status-success=Build and Test (ubuntu-latest, 2.13.11, temurin@17) - status-success=Build and Test (ubuntu-latest, 3.3.0, temurin@17) actions: diff --git a/README.md b/README.md index 3a0762a8..ebd4c9a8 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,7 @@ A library maintained by [Iterators](https://www.iteratorshq.com). * [JsonSchema support](#jsonschema-support) * [Scalacheck support](#scalacheck-support) * [Kebs for IntelliJ](#kebs-for-intellij) +* [Kebs 2.0 migration guide](#kebs-20-migration-guide) ### Why? @@ -171,7 +172,7 @@ class People(tag: Tag) extends Table[Person](tag, "people") { If you prefer to **mix in trait** instead of import (for example you're using a custom driver like `slick-pg`), you can do it as well: ```scala -import pl.iterators.kebs.Kebs +import pl.iterators.kebs.slick.Kebs object MyPostgresProfile extends ExPostgresDriver with PgArraySupport { override val api: API = new API {} trait API extends super.API with ArrayImplicits with Kebs @@ -338,8 +339,8 @@ class People(tag: Tag) extends Table[Person](tag, "people") { ```scala -import pl.iterators.kebs._ -import enums._ +import pl.iterators.kebs.slick._ +import pl.iterators.kebs.slick.enums._ class People(tag: Tag) extends Table[Person](tag, "people") { @@ -361,8 +362,8 @@ If you import `enums.lowercase._` or `enums.uppercase._` then it'll save enum na Of course, enums also work with traits: ```scala -import pl.iterators.kebs.Kebs -import pl.iterators.kebs.enums.KebsEnums +import pl.iterators.kebs.slick.Kebs +import pl.iterators.kebs.slick.enums.KebsEnums object MyPostgresProfile extends ExPostgresDriver { override val api: API = new API {} @@ -389,12 +390,12 @@ import MyPostgresProfile.api._ kebs-doobie works similarly to [kebs-slick](#--kebs-generates-slick-mappers-for-your-case-class-wrappers-kebs-slick). It provides doobie's `Meta` instances for: -* Instances of `CaseClass1Rep` (value classes, tagged types, opaque types) +* Instances of `ValueClassLike` (value classes, tagged types, opaque types) * Instances of `InstanceConverter` * Enumeratum for Scala 2 * Native enums for Scala 3 -To make the magic happen, do `import pl.iterators.kebs._` and `import pl.iterators.kebs.enums._` (or `import pl.iterators.kebs.enums.uppercase._` or `import pl.iterators.kebs.enums.lowercase._`). +To make the magic happen, do `import pl.iterators.doobie.kebs._` and `import pl.iterators.kebs.doobie.enums._` (or `import pl.iterators.kebs.doobie.enums.uppercase._` or `import pl.iterators.kebs.doobie.enums.lowercase._`). #### - kebs eliminates spray-json induced boilerplate (kebs-spray-json) @@ -722,8 +723,8 @@ case class Limit(value: Int) extends AnyVal case class PaginationQuery(sortBy: Column, sortOrder: SortOrder, offset: Offset, limit: Limit) -import pl.iterators.kebs.unmarshallers._ -import enums._ +import pl.iterators.kebs.akkahttp.unmarshallers._ +import pl.iterators.kebs.akkahttp.unmarshallers.enums._ val route = get { parameters('sortBy.as[Column], 'order.as[SortOrder] ? (SortOrder.Desc: SortOrder), 'offset.as[Offset] ? Offset(0), 'limit.as[Limit]) @@ -901,13 +902,13 @@ object Tags { } object PositiveIntTag { - implicit val PositiveIntCaseClass1Rep = new CaseClass1Rep[PositiveInt, Int](PositiveInt.apply(_), identity) + implicit val PositiveIntValueClassLike = new ValueClassLike[PositiveInt, Int](PositiveInt.apply(_), identity) } object IdTag { - implicit def IdCaseClass1Rep[A] = new CaseClass1Rep[Id[A], Int](Id.apply(_), identity) + implicit def IdValueClassLike[A] = new ValueClassLike[Id[A], Int](Id.apply(_), identity) } object NameTag { - implicit val NameCaseClass1Rep = new CaseClass1Rep[Name, String](Name.apply(_), identity) + implicit val NameValueClassLike = new ValueClassLike[Name, String](Name.apply(_), identity) } } ``` @@ -946,7 +947,7 @@ There are some conventions that are assumed during generation. * take a single argument * return Either (this is not enforced though - you'll have a compilation error later) -Also, `CaseClass1Rep` is generated for each tag meaning you will get a lot of `kebs` machinery for free eg. spray formats etc. +Also, `ValueClassLike` is generated for each tag meaning you will get a lot of `kebs` machinery for free eg. spray formats etc. ### Opaque types @@ -954,7 +955,7 @@ As an alternative to tagged types, Scala 3 provides [opaque types](https://docs. The principles of opaque types are similar to tagged type. The basic usage of opaque types requires the same amount of boilerplate as tagged types - e.g. you have to write smart constructors, validations and unwrapping mechanisms all by hand. `kebs-opaque` is meant to help with that by generating a handful of methods and providing a -`CaseClass1Rep` for an easy typclass derivation. +`ValueClassLike` for an easy typclass derivation. ```scala import pl.iterators.kebs.opaque._ @@ -966,10 +967,10 @@ object MyDomain { ``` That's the basic usage. Inside the companion object you will get methods like `from`, `apply`, `unsafe` and extension -method `unwrap` plus an instance of `CaseClass1Rep[ISBN, String]`. A more complete example below. +method `unwrap` plus an instance of `ValueClassLike[ISBN, String]`. A more complete example below. ```scala -import pl.iterators.kebs.macros.CaseClass1Rep +import pl.iterators.kebs.core.macros.ValueClassLike import pl.iterators.kebs.opaque._ object MyDomain { @@ -1000,7 +1001,7 @@ trait Showable[A] { def show(a: A): String } given Showable[String] = (a: String) => a -given[S, A](using showable: Showable[S], cc1Rep: CaseClass1Rep[A, S]): Showable[A] = (a: A) => showable.show(cc1Rep.unapply(a)) +given[S, A](using showable: Showable[S], vcLike: ValueClassLike[A, S]): Showable[A] = (a: A) => showable.show(vcLike.unapply(a)) implicitly[Showable[ISBN]].show(ISBN("1234567890")) // "1234567890" ``` @@ -1105,3 +1106,34 @@ The code generated by macros in `kebs-tagged-meta` is not visible to IntelliJ ID plugin that enhances experience with the library by adding support for generated code. You can install it from the IntelliJ Marketplace. In the Settings/Preferences dialog, select "Plugins" and type "Kebs" into search input (see https://www.jetbrains.com/help/idea/managing-plugins.html for detailed instructions). You can also use this web page: https://plugins.jetbrains.com/plugin/16069-kebs. + +### Kebs 2.0 migration guide + +Please be aware that recent changes in the source code might require some changes in your codebase. Follow the guide below to migrate your code to Kebs 2.0: +* If you are using value classes instead of tagged/opaque types, please mix in the `CaseClass1ToValueClass` trait. +* Extend your value-enums with `pl.iterators.kebs.enums.ValueEnumLikeEntry` parameterized with the type of the value. + * Native Scala 3 value-enums: + ```scala + enum ColorButRGB(val value: Int) extends ValueEnumLikeEntry[Int] {slick + case Red extends ColorButRGB(0xFF0000) + case Green extends ColorButRGB(0x00FF00) + case Blue extends ColorButRGB(0x0000FF) + } + ``` + * enumeratum value-enums for Scala 2 and Scala 3: + ```scala + sealed abstract class LibraryItem(val value: Int) extends IntEnumEntry with ValueEnumLikeEntry[Int] + object LibraryItem extends IntEnum[LibraryItem] { + case object Book extends LibraryItem(value = 1) + case object Movie extends LibraryItem(value = 2) + case object Magazine extends LibraryItem(3) + case object CD extends LibraryItem(4) + val values = findValues + } + ``` +* Extend your traits/classes/objects, if inside of one an implicit enum (or value-enum) conversion for `kebs` library's needs should occur, with one of the following traits: + * For Scala 2 and Scala 3 enums from `enumeratum` library: `pl.iterators.kebs.enumeratum.KebsEnumeratum` + * For Scala 2 and Scala 3 value-enums from `enumeratum` library: `pl.iterators.kebs.enumeratum.KebsValueEnumeratum` + * For Scala 3 native value-enums: `pl.iterators.kebs.enums.KebsValueEnum` + * For Scala 2 `scala.Enumeration` enums or Scala 3 native enums: `pl.iterators.kebs.enums.KebsEnum` + diff --git a/akka-http/src/main/scala/pl/iterators/kebs/matchers/KebsMatchers.scala b/akka-http/src/main/scala/pl/iterators/kebs/akkahttp/matchers/KebsMatchers.scala similarity index 72% rename from akka-http/src/main/scala/pl/iterators/kebs/matchers/KebsMatchers.scala rename to akka-http/src/main/scala/pl/iterators/kebs/akkahttp/matchers/KebsMatchers.scala index a7932b4a..f778f026 100644 --- a/akka-http/src/main/scala/pl/iterators/kebs/matchers/KebsMatchers.scala +++ b/akka-http/src/main/scala/pl/iterators/kebs/akkahttp/matchers/KebsMatchers.scala @@ -1,16 +1,16 @@ -package pl.iterators.kebs.matchers +package pl.iterators.kebs.akkahttp.matchers import akka.http.scaladsl.server.{PathMatcher1, PathMatchers} import enumeratum.{Enum, EnumEntry} -import pl.iterators.kebs.instances.InstanceConverter -import pl.iterators.kebs.macros.CaseClass1Rep +import pl.iterators.kebs.core.instances.InstanceConverter +import pl.iterators.kebs.core.macros.ValueClassLike import scala.language.implicitConversions trait KebsMatchers extends PathMatchers { implicit class SegmentIsomorphism[U](segment: PathMatcher1[U]) { - def as[T](implicit rep: CaseClass1Rep[T, U]): PathMatcher1[T] = segment.map(rep.apply) + def as[T](implicit rep: ValueClassLike[T, U]): PathMatcher1[T] = segment.map(rep.apply) } implicit class SegmentConversion[Source](segment: PathMatcher1[Source]) { diff --git a/pekko-http/src/main/scala/pl/iterators/kebs/matchers/package.scala b/akka-http/src/main/scala/pl/iterators/kebs/akkahttp/matchers/package.scala similarity index 56% rename from pekko-http/src/main/scala/pl/iterators/kebs/matchers/package.scala rename to akka-http/src/main/scala/pl/iterators/kebs/akkahttp/matchers/package.scala index 610a2da7..34c0e7df 100644 --- a/pekko-http/src/main/scala/pl/iterators/kebs/matchers/package.scala +++ b/akka-http/src/main/scala/pl/iterators/kebs/akkahttp/matchers/package.scala @@ -1,3 +1,3 @@ -package pl.iterators.kebs +package pl.iterators.kebs.akkahttp package object matchers extends KebsMatchers diff --git a/akka-http/src/main/scala/pl/iterators/kebs/unmarshallers/KebsUnmarshallers.scala b/akka-http/src/main/scala/pl/iterators/kebs/akkahttp/unmarshallers/KebsUnmarshallers.scala similarity index 62% rename from akka-http/src/main/scala/pl/iterators/kebs/unmarshallers/KebsUnmarshallers.scala rename to akka-http/src/main/scala/pl/iterators/kebs/akkahttp/unmarshallers/KebsUnmarshallers.scala index 739055ac..5fb0562c 100644 --- a/akka-http/src/main/scala/pl/iterators/kebs/unmarshallers/KebsUnmarshallers.scala +++ b/akka-http/src/main/scala/pl/iterators/kebs/akkahttp/unmarshallers/KebsUnmarshallers.scala @@ -1,14 +1,14 @@ -package pl.iterators.kebs.unmarshallers +package pl.iterators.kebs.akkahttp.unmarshallers import akka.http.scaladsl.unmarshalling.{FromStringUnmarshaller, Unmarshaller} -import pl.iterators.kebs.instances.InstanceConverter -import pl.iterators.kebs.macros.CaseClass1Rep +import pl.iterators.kebs.core.instances.InstanceConverter +import pl.iterators.kebs.core.macros.{CaseClass1ToValueClass, ValueClassLike} -trait KebsUnmarshallers { - implicit def kebsUnmarshaller[A, B](implicit rep: CaseClass1Rep[B, A]): Unmarshaller[A, B] = +trait KebsUnmarshallers extends CaseClass1ToValueClass { + implicit def kebsUnmarshaller[A, B](implicit rep: ValueClassLike[B, A]): Unmarshaller[A, B] = Unmarshaller.strict[A, B](rep.apply) @inline - implicit def kebsFromStringUnmarshaller[A, B](implicit rep: CaseClass1Rep[B, A], + implicit def kebsFromStringUnmarshaller[A, B](implicit rep: ValueClassLike[B, A], fsu: FromStringUnmarshaller[A]): FromStringUnmarshaller[B] = fsu andThen kebsUnmarshaller(rep) diff --git a/akka-http/src/main/scala/pl/iterators/kebs/akkahttp/unmarshallers/enums/KebsEnumUnmarshallers.scala b/akka-http/src/main/scala/pl/iterators/kebs/akkahttp/unmarshallers/enums/KebsEnumUnmarshallers.scala new file mode 100644 index 00000000..c950720e --- /dev/null +++ b/akka-http/src/main/scala/pl/iterators/kebs/akkahttp/unmarshallers/enums/KebsEnumUnmarshallers.scala @@ -0,0 +1,46 @@ +package pl.iterators.kebs.akkahttp.unmarshallers.enums + +import akka.http.scaladsl.unmarshalling.PredefinedFromStringUnmarshallers._ +import akka.http.scaladsl.unmarshalling.{FromStringUnmarshaller, Unmarshaller} +import akka.http.scaladsl.util.FastFuture +import pl.iterators.kebs.core.enums.{EnumLike, ValueEnumLike, ValueEnumLikeEntry} + +trait EnumUnmarshallers { + final def enumUnmarshaller[E](`enum`: EnumLike[E]): FromStringUnmarshaller[E] = Unmarshaller { _ =>name => + `enum`.withNameInsensitiveOption(name) match { + case Some(enumEntry) => FastFuture.successful(enumEntry) + case None => + FastFuture.failed(new IllegalArgumentException(s"""Invalid value '$name'. Expected one of: ${`enum`.getNamesToValuesMap.keysIterator + .mkString(", ")}""")) + } + } + + implicit def kebsEnumUnmarshaller[E](implicit ev: EnumLike[E]): FromStringUnmarshaller[E] = + enumUnmarshaller(ev) +} + +trait ValueEnumUnmarshallers { + final def valueEnumUnmarshaller[V, E <: ValueEnumLikeEntry[V]](`enum`: ValueEnumLike[V, E]): Unmarshaller[V, E] = Unmarshaller { _ =>v => + `enum`.withValueOption(v) match { + case Some(enumEntry) => FastFuture.successful(enumEntry) + case None => + FastFuture.failed(new IllegalArgumentException(s"""Invalid value '$v'. Expected one of: ${`enum`.getValuesToEntriesMap.keysIterator + .mkString(", ")}""")) + } + } + + implicit def kebsValueEnumUnmarshaller[V, E <: ValueEnumLikeEntry[V]](implicit ev: ValueEnumLike[V, E]): Unmarshaller[V, E] = + valueEnumUnmarshaller(ev) + + implicit def kebsIntValueEnumFromStringUnmarshaller[E <: ValueEnumLikeEntry[Int]](implicit ev: ValueEnumLike[Int, E]): FromStringUnmarshaller[E] = + intFromStringUnmarshaller andThen valueEnumUnmarshaller(ev) + implicit def kebsLongValueEnumFromStringUnmarshaller[E <: ValueEnumLikeEntry[Long]](implicit ev: ValueEnumLike[Long, E]): FromStringUnmarshaller[E] = + longFromStringUnmarshaller andThen valueEnumUnmarshaller(ev) + implicit def kebsShortValueEnumFromStringUnmarshaller[E <: ValueEnumLikeEntry[Short]]( + implicit ev: ValueEnumLike[Short, E]): FromStringUnmarshaller[E] = + shortFromStringUnmarshaller andThen valueEnumUnmarshaller(ev) + implicit def kebsByteValueEnumFromStringUnmarshaller[E <: ValueEnumLikeEntry[Byte]](implicit ev: ValueEnumLike[Byte, E]): FromStringUnmarshaller[E] = + byteFromStringUnmarshaller andThen valueEnumUnmarshaller(ev) +} + +trait KebsEnumUnmarshallers extends EnumUnmarshallers with ValueEnumUnmarshallers {} diff --git a/http4s-stir/src/main/scala-2/unmarshallers/enums/package.scala b/akka-http/src/main/scala/pl/iterators/kebs/akkahttp/unmarshallers/enums/package.scala similarity index 51% rename from http4s-stir/src/main/scala-2/unmarshallers/enums/package.scala rename to akka-http/src/main/scala/pl/iterators/kebs/akkahttp/unmarshallers/enums/package.scala index a4fa82c6..fb2d9919 100644 --- a/http4s-stir/src/main/scala-2/unmarshallers/enums/package.scala +++ b/akka-http/src/main/scala/pl/iterators/kebs/akkahttp/unmarshallers/enums/package.scala @@ -1,3 +1,3 @@ -package pl.iterators.kebs.unmarshallers +package pl.iterators.kebs.akkahttp.unmarshallers package object enums extends KebsEnumUnmarshallers diff --git a/http4s-stir/src/main/scala/pl/iterators/kebs/unmarshallers/package.scala b/akka-http/src/main/scala/pl/iterators/kebs/akkahttp/unmarshallers/package.scala similarity index 61% rename from http4s-stir/src/main/scala/pl/iterators/kebs/unmarshallers/package.scala rename to akka-http/src/main/scala/pl/iterators/kebs/akkahttp/unmarshallers/package.scala index 6fd93de3..615d2a88 100644 --- a/http4s-stir/src/main/scala/pl/iterators/kebs/unmarshallers/package.scala +++ b/akka-http/src/main/scala/pl/iterators/kebs/akkahttp/unmarshallers/package.scala @@ -1,3 +1,3 @@ -package pl.iterators.kebs +package pl.iterators.kebs.akkahttp package object unmarshallers extends KebsUnmarshallers diff --git a/akka-http/src/main/scala/pl/iterators/kebs/matchers/package.scala b/akka-http/src/main/scala/pl/iterators/kebs/matchers/package.scala deleted file mode 100644 index 610a2da7..00000000 --- a/akka-http/src/main/scala/pl/iterators/kebs/matchers/package.scala +++ /dev/null @@ -1,3 +0,0 @@ -package pl.iterators.kebs - -package object matchers extends KebsMatchers diff --git a/akka-http/src/main/scala/pl/iterators/kebs/unmarshallers/enums/KebsEnumUnmarshallers.scala b/akka-http/src/main/scala/pl/iterators/kebs/unmarshallers/enums/KebsEnumUnmarshallers.scala deleted file mode 100644 index 62324d0f..00000000 --- a/akka-http/src/main/scala/pl/iterators/kebs/unmarshallers/enums/KebsEnumUnmarshallers.scala +++ /dev/null @@ -1,48 +0,0 @@ -package pl.iterators.kebs.unmarshallers.enums - -import akka.http.scaladsl.unmarshalling.PredefinedFromStringUnmarshallers._ -import akka.http.scaladsl.unmarshalling.{FromStringUnmarshaller, Unmarshaller} -import akka.http.scaladsl.util.FastFuture -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) => FastFuture.successful(enumEntry) - case None => - FastFuture.failed(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) => FastFuture.successful(enumEntry) - case None => - FastFuture.failed(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 {} diff --git a/akka-http/src/test/scala/pl/iterators/kebs/AkkaHttpTagsDomain.scala b/akka-http/src/test/scala/pl/iterators/kebs/akkahttp/domain/AkkaHttpTagsDomain.scala similarity index 92% rename from akka-http/src/test/scala/pl/iterators/kebs/AkkaHttpTagsDomain.scala rename to akka-http/src/test/scala/pl/iterators/kebs/akkahttp/domain/AkkaHttpTagsDomain.scala index f0661a1e..e40789a0 100644 --- a/akka-http/src/test/scala/pl/iterators/kebs/AkkaHttpTagsDomain.scala +++ b/akka-http/src/test/scala/pl/iterators/kebs/akkahttp/domain/AkkaHttpTagsDomain.scala @@ -1,9 +1,10 @@ -package pl.iterators.kebs +package pl.iterators.kebs.akkahttp.domain import enumeratum.values.{IntEnum, IntEnumEntry, StringEnum, StringEnumEntry} import enumeratum.{Enum, EnumEntry} import pl.iterators.kebs.tag.meta.tagged import pl.iterators.kebs.tagged._ +import pl.iterators.kebs.core.enums.ValueEnumLikeEntry import java.net.URI import java.util.UUID @@ -47,7 +48,7 @@ object Domain extends Tags { val values = findValues } - sealed abstract class LibraryItem(val value: Int) extends IntEnumEntry + sealed abstract class LibraryItem(val value: Int) extends IntEnumEntry with ValueEnumLikeEntry[Int] object LibraryItem extends IntEnum[LibraryItem] { case object Book extends LibraryItem(1) @@ -63,7 +64,7 @@ object Domain extends Tags { case class Blue(value: Int) case class Color(red: Red, green: Green, blue: Blue) - sealed abstract class ShirtSize(val value: String) extends StringEnumEntry + sealed abstract class ShirtSize(val value: String) extends StringEnumEntry with ValueEnumLikeEntry[String] object ShirtSize extends StringEnum[ShirtSize] { case object Small extends ShirtSize("S") case object Medium extends ShirtSize("M") diff --git a/akka-http/src/test/scala/pl/iterators/kebs/matchers/AkkaHttpMatchersTests.scala b/akka-http/src/test/scala/pl/iterators/kebs/akkahttp/matchers/AkkaHttpMatchersTests.scala similarity index 81% rename from akka-http/src/test/scala/pl/iterators/kebs/matchers/AkkaHttpMatchersTests.scala rename to akka-http/src/test/scala/pl/iterators/kebs/akkahttp/matchers/AkkaHttpMatchersTests.scala index ee7a207e..69d89753 100644 --- a/akka-http/src/test/scala/pl/iterators/kebs/matchers/AkkaHttpMatchersTests.scala +++ b/akka-http/src/test/scala/pl/iterators/kebs/akkahttp/matchers/AkkaHttpMatchersTests.scala @@ -1,14 +1,15 @@ -package pl.iterators.kebs.matchers +package pl.iterators.kebs.akkahttp.matchers import akka.http.scaladsl.server.Directives import akka.http.scaladsl.testkit.ScalatestRouteTest import org.scalatest.concurrent.ScalaFutures import org.scalatest.funsuite.AnyFunSuite import org.scalatest.matchers.should.Matchers -import pl.iterators.kebs.Domain._ +import pl.iterators.kebs.akkahttp.domain.Domain.Greeting +import pl.iterators.kebs.akkahttp.domain.Domain._ import pl.iterators.kebs.instances.net.URIString -import pl.iterators.kebs.instances.time.mixins.InstantEpochMilliLong import pl.iterators.kebs.instances.time.{DayOfWeekInt, ZonedDateTimeString} +import pl.iterators.kebs.instances.time.mixins.InstantEpochMilliLong import java.net.URI import java.time.{DayOfWeek, Instant, ZonedDateTime} @@ -24,15 +25,15 @@ class AkkaHttpMatchersTests with InstantEpochMilliLong with URIString { - test("No CaseClass1Rep implicits derived") { - import pl.iterators.kebs.macros.CaseClass1Rep + test("No ValueClassLike implicits derived") { + import pl.iterators.kebs.core.macros.ValueClassLike - "implicitly[CaseClass1Rep[DayOfWeek, Int]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[Int, DayOfWeek]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[Instant, Long]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[Long, Instant]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[URI, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, URI]]" shouldNot typeCheck + "implicitly[ValueClassLike[DayOfWeek, Int]]" shouldNot typeCheck + "implicitly[ValueClassLike[Int, DayOfWeek]]" shouldNot typeCheck + "implicitly[ValueClassLike[Instant, Long]]" shouldNot typeCheck + "implicitly[ValueClassLike[Long, Instant]]" shouldNot typeCheck + "implicitly[ValueClassLike[URI, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, URI]]" shouldNot typeCheck } test("Extract String to ZonedDateTime") { diff --git a/akka-http/src/test/scala/pl/iterators/kebs/unmarshallers/AkkaHttpUnmarshallersTests.scala b/akka-http/src/test/scala/pl/iterators/kebs/akkahttp/unmarshallers/AkkaHttpUnmarshallersTests.scala similarity index 84% rename from akka-http/src/test/scala/pl/iterators/kebs/unmarshallers/AkkaHttpUnmarshallersTests.scala rename to akka-http/src/test/scala/pl/iterators/kebs/akkahttp/unmarshallers/AkkaHttpUnmarshallersTests.scala index e2841e0d..2141c9ce 100644 --- a/akka-http/src/test/scala/pl/iterators/kebs/unmarshallers/AkkaHttpUnmarshallersTests.scala +++ b/akka-http/src/test/scala/pl/iterators/kebs/akkahttp/unmarshallers/AkkaHttpUnmarshallersTests.scala @@ -1,4 +1,4 @@ -package pl.iterators.kebs.unmarshallers +package pl.iterators.kebs.akkahttp.unmarshallers import akka.http.scaladsl.model.FormData import akka.http.scaladsl.server.{Directives, MalformedQueryParamRejection} @@ -7,10 +7,16 @@ import akka.http.scaladsl.unmarshalling.Unmarshal import org.scalatest.concurrent.ScalaFutures import org.scalatest.funsuite.AnyFunSuite import org.scalatest.matchers.should.Matchers -import pl.iterators.kebs.Domain._ +import pl.iterators.kebs.akkahttp.domain.Domain.{Blue, Color, Green, Greeting, I, LibraryItem, P, Red, S, ShirtSize, SortOrder} +import pl.iterators.kebs.akkahttp.unmarshallers.KebsUnmarshallers +import pl.iterators.kebs.akkahttp.domain.Domain._ import pl.iterators.kebs.instances.net.URIString import pl.iterators.kebs.instances.time.{DayOfWeekInt, YearMonthString} -import pl.iterators.kebs.unmarshallers.enums.KebsEnumUnmarshallers +import pl.iterators.kebs.enumeratum.{KebsEnumeratum, KebsValueEnumeratum} +import pl.iterators.kebs.instances.net.URIString +import pl.iterators.kebs.instances.time.{DayOfWeekInt, YearMonthString} +import pl.iterators.kebs.akkahttp.unmarshallers.enums.KebsEnumUnmarshallers +import pl.iterators.kebs.core.enums.ValueEnumLikeEntry import java.time.{DayOfWeek, YearMonth} @@ -24,17 +30,19 @@ class AkkaHttpUnmarshallersTests with KebsEnumUnmarshallers with URIString with YearMonthString - with DayOfWeekInt { - - test("No CaseClass1Rep implicits derived") { - import pl.iterators.kebs.macros.CaseClass1Rep - - "implicitly[CaseClass1Rep[URI, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, URI]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[YearMonth, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, YearMonth]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[DayOfWeek, Int]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[Int, DayOfWeek]]" shouldNot typeCheck + with DayOfWeekInt + with KebsEnumeratum + with KebsValueEnumeratum { + + test("No ValueClassLike implicits derived") { + import pl.iterators.kebs.core.macros.ValueClassLike + + "implicitly[ValueClassLike[URI, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, URI]]" shouldNot typeCheck + "implicitly[ValueClassLike[YearMonth, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, YearMonth]]" shouldNot typeCheck + "implicitly[ValueClassLike[DayOfWeek, Int]]" shouldNot typeCheck + "implicitly[ValueClassLike[Int, DayOfWeek]]" shouldNot typeCheck } test("Unmarshal") { diff --git a/benchmarks/src/main/scala/pl/iterators/kebs_benchmarks/SprayJsonFormatBenchmark.scala b/benchmarks/src/main/scala/pl/iterators/kebs/benchmarks/SprayJsonFormatBenchmark.scala similarity index 99% rename from benchmarks/src/main/scala/pl/iterators/kebs_benchmarks/SprayJsonFormatBenchmark.scala rename to benchmarks/src/main/scala/pl/iterators/kebs/benchmarks/SprayJsonFormatBenchmark.scala index 459d85b7..db91d715 100644 --- a/benchmarks/src/main/scala/pl/iterators/kebs_benchmarks/SprayJsonFormatBenchmark.scala +++ b/benchmarks/src/main/scala/pl/iterators/kebs/benchmarks/SprayJsonFormatBenchmark.scala @@ -1,4 +1,4 @@ -package pl.iterators.kebs_benchmarks +package pl.iterators.kebs.benchmarks import java.time.format.DateTimeFormatter import java.time.{LocalDate, LocalTime} diff --git a/build.sbt b/build.sbt index 238c2ed7..2fa91f12 100644 --- a/build.sbt +++ b/build.sbt @@ -1,10 +1,9 @@ import sbt.librarymanagement.ConflictWarning -val scala_2_12 = "2.12.18" val scala_2_13 = "2.13.11" val scala_3 = "3.3.1" val mainScalaVersion = scala_3 -val supportedScalaVersions = Seq(scala_2_12, scala_2_13, scala_3) +val supportedScalaVersions = Seq(scala_2_13, scala_3) ThisBuild / crossScalaVersions := supportedScalaVersions ThisBuild / scalaVersion := mainScalaVersion @@ -28,7 +27,6 @@ lazy val commonMacroSettings = baseSettings ++ Seq( lazy val metaSettings = commonSettings ++ Seq( scalacOptions ++= paradiseFlag(scalaVersion.value), - libraryDependencies ++= paradisePlugin(scalaVersion.value) ) lazy val crossBuildSettings = Seq(crossScalaVersions := supportedScalaVersions) @@ -94,17 +92,11 @@ def sv[A](scalaVersion: String, scala2_12Version: => A, scala2_13Version: => A) } def paradiseFlag(scalaVersion: String): Seq[String] = - if (scalaVersion == scala_2_12 || scalaVersion == scala_3) + if (scalaVersion == scala_3) Seq.empty else Seq("-Ymacro-annotations") -def paradisePlugin(scalaVersion: String): Seq[ModuleID] = - if (scalaVersion == scala_2_12) - Seq(compilerPlugin("org.scalamacros" % "paradise" % "2.1.1" cross CrossVersion.full)) - else - Seq.empty - val scalaTest = Def.setting("org.scalatest" %%% "scalatest" % "3.2.17") val scalaCheck = Def.setting("org.scalacheck" %%% "scalacheck" % "1.17.0") val slick = "com.typesafe.slick" %% "slick" % "3.4.1" @@ -199,6 +191,20 @@ lazy val coreSettings = commonMacroSettings ++ Seq( libraryDependencies += optionalEnumeratum ) +lazy val enumSettings = commonMacroSettings ++ Seq( + libraryDependencies += scalaCheck.value % "test", + libraryDependencies += scalaTest.value, + libraryDependencies += optionalEnumeratum, + scalacOptions ++= paradiseFlag(scalaVersion.value) +) + +lazy val enumeratumSettings = commonMacroSettings ++ Seq( + libraryDependencies += scalaCheck.value % "test", + libraryDependencies += scalaTest.value, + libraryDependencies += optionalEnumeratum, + scalacOptions ++= paradiseFlag(scalaVersion.value) ++ (if (scalaVersion.value.startsWith("3")) Seq("-Yretain-trees") else Seq.empty) +) + lazy val sprayJsonMacroSettings = commonMacroSettings ++ Seq( libraryDependencies += sprayJson.cross(CrossVersion.for3Use2_13) ) @@ -225,7 +231,6 @@ lazy val akkaHttpSettings = commonSettings ++ Seq( libraryDependencies += (akkaStreamTestkit % "test").cross(CrossVersion.for3Use2_13), libraryDependencies += (akkaHttpTestkit % "test").cross(CrossVersion.for3Use2_13), libraryDependencies += optionalEnumeratum, - libraryDependencies ++= paradisePlugin(scalaVersion.value), scalacOptions ++= paradiseFlag(scalaVersion.value) ) @@ -235,14 +240,12 @@ lazy val pekkoHttpSettings = commonSettings ++ Seq( libraryDependencies += pekkoStreamTestkit % "test", libraryDependencies += pekkoHttpTestkit % "test", libraryDependencies += optionalEnumeratum, - libraryDependencies ++= paradisePlugin(scalaVersion.value), scalacOptions ++= paradiseFlag(scalaVersion.value) ) lazy val http4sSettings = commonSettings ++ Seq( libraryDependencies += http4s, libraryDependencies += optionalEnumeratum, - libraryDependencies ++= paradisePlugin(scalaVersion.value), scalacOptions ++= paradiseFlag(scalaVersion.value) ) @@ -251,7 +254,6 @@ lazy val http4sStirSettings = commonSettings ++ Seq( libraryDependencies += http4sStir, libraryDependencies += http4sStirTestkit % "test", libraryDependencies += optionalEnumeratum, - libraryDependencies ++= paradisePlugin(scalaVersion.value), scalacOptions ++= paradiseFlag(scalaVersion.value) ) @@ -279,7 +281,6 @@ lazy val examplesSettings = commonSettings ++ Seq( libraryDependencies += circeParser, libraryDependencies ++= enumeratumInExamples, libraryDependencies ++= pekkoHttpInExamples, - libraryDependencies ++= paradisePlugin(scalaVersion.value), scalacOptions ++= paradiseFlag(scalaVersion.value) ) @@ -328,7 +329,7 @@ lazy val macroUtils = crossProject(JSPlatform, JVMPlatform) lazy val slickSupport = project .in(file("slick")) - .dependsOn(core.jvm, instances % "test -> test") + .dependsOn(core.jvm, enumeratumSupport, instances % "test -> test") .settings(slickSettings: _*) .settings(publishSettings: _*) .settings(disableScala(List("3"))) @@ -341,7 +342,7 @@ lazy val slickSupport = project lazy val doobieSupport = project .in(file("doobie")) - .dependsOn(instances, opaque.jvm % "test -> test") + .dependsOn(instances, enumeratumSupport, enumSupport, opaque.jvm % "test -> test") .settings(doobieSettings: _*) .settings(publishSettings: _*) .settings( @@ -366,7 +367,7 @@ lazy val sprayJsonMacros = project lazy val sprayJsonSupport = project .in(file("spray-json")) - .dependsOn(sprayJsonMacros, instances % "test -> test") + .dependsOn(sprayJsonMacros, enumeratumSupport, instances % "test -> test") .settings(sprayJsonSettings: _*) .settings(publishSettings: _*) .settings(disableScala(List("3"))) @@ -392,7 +393,7 @@ lazy val playJsonSupport = project lazy val circeSupport = project .in(file("circe")) - .dependsOn(core.jvm, instances % "test -> test") + .dependsOn(core.jvm, enumeratumSupport, enumSupport, instances % "test -> test") .settings(circeSettings: _*) .settings(crossBuildSettings: _*) .settings(publishSettings: _*) @@ -404,7 +405,7 @@ lazy val circeSupport = project lazy val akkaHttpSupport = project .in(file("akka-http")) - .dependsOn(core.jvm, instances % "test -> test", tagged.jvm % "test -> test", taggedMeta % "test -> test") + .dependsOn(core.jvm, enumeratumSupport, instances % "test -> test", tagged.jvm % "test -> test", taggedMeta % "test -> test") .settings(akkaHttpSettings: _*) .settings(publishSettings: _*) .settings(disableScala(List("3"))) @@ -417,7 +418,7 @@ lazy val akkaHttpSupport = project lazy val pekkoHttpSupport = project .in(file("pekko-http")) - .dependsOn(core.jvm, instances % "test -> test", tagged.jvm % "test -> test", taggedMeta % "test -> test") + .dependsOn(core.jvm, enumeratumSupport, enumSupport, instances % "test -> test", tagged.jvm % "test -> test", taggedMeta % "test -> test") .settings(pekkoHttpSettings: _*) .settings(publishSettings: _*) .settings( @@ -450,7 +451,7 @@ lazy val http4sStirSupport = project description := "Automatic generation of http4s-stir deserializers for 1-element case classes, opaque and tagged types", moduleName := "kebs-http4s-stir", crossScalaVersions := supportedScalaVersions - ).settings(disableScala(List("2.12"))) + ) lazy val jsonschemaSupport = project .in(file("jsonschema")) @@ -505,7 +506,7 @@ lazy val opaque = crossProject(JSPlatform, JVMPlatform) moduleName := "kebs-opaque", crossScalaVersions := supportedScalaVersions ) - .settings(disableScala(List("2.12", "2.13"))) + .settings(disableScala(List("2.13"))) lazy val taggedMeta = project .in(file("tagged-meta")) @@ -560,6 +561,27 @@ lazy val instances = project moduleName := "kebs-instances" ) +lazy val enumSupport = project + .in(file("enum")) + .dependsOn(core.jvm) + .settings(enumSettings: _*) + .settings(publishSettings: _*) + .settings( + name := "enum", + moduleName := "kebs-enum" + ) + +lazy val enumeratumSupport = project + .in(file("enumeratum")) + .dependsOn(core.jvm) + .settings(enumeratumSettings: _*) + .settings(publishSettings: _*) + .settings( + name := "enumeratum", + moduleName := "kebs-enumeratum" + ) + + lazy val kebs = project .in(file(".")) .aggregate( @@ -584,7 +606,9 @@ lazy val kebs = project http4sSupport, http4sStirSupport, taggedMeta, - instances + instances, + enumSupport, + enumeratumSupport ) .settings(baseSettings: _*) .settings(noPublishSettings) diff --git a/circe/src/main/scala-2/KebsEnumFormats.scala b/circe/src/main/scala-2/KebsEnumFormats.scala deleted file mode 100644 index 5f3f9dab..00000000 --- a/circe/src/main/scala-2/KebsEnumFormats.scala +++ /dev/null @@ -1,85 +0,0 @@ -package pl.iterators.kebs.circe - -import enumeratum.values.{ValueEnum, ValueEnumEntry} -import enumeratum.{Enum, EnumEntry} -import io.circe.Decoder.Result -import io.circe._ -import pl.iterators.kebs.macros.enums.{EnumOf, ValueEnumOf} - -trait CirceEnum { - @inline protected final def enumNameDeserializationError[E <: EnumEntry](`enum`: Enum[E], name: String): String = { - val enumNames = `enum`.namesToValuesMap.values.mkString(", ") - s"$name should be one of $enumNames" - } - - @inline protected final def enumValueDeserializationError[E <: EnumEntry](`enum`: Enum[E], value: Json): String = { - val enumNames = `enum`.namesToValuesMap.values.mkString(", ") - s"$value should be a string of value $enumNames" - } - - protected final def enumDecoder[E <: EnumEntry](`enum`: Enum[E], _comap: String => Option[E]): Decoder[E] = - (c: HCursor) => - Decoder.decodeString.emap(str => _comap(str).toRight("")).withErrorMessage(enumValueDeserializationError(`enum`, c.value))(c) - - protected final def enumEncoder[E <: EnumEntry](`enum`: Enum[E], _map: E => String): Encoder[E] = - (obj: E) => Encoder.encodeString(_map(obj)) - - def enumDecoder[E <: EnumEntry](`enum`: Enum[E]): Decoder[E] = - enumDecoder[E](`enum`, `enum`.withNameInsensitiveOption(_)) - def enumEncoder[E <: EnumEntry](`enum`: Enum[E]): Encoder[E] = - enumEncoder[E](`enum`, (e: EnumEntry) => e.entryName) - - def lowercaseEnumDecoder[E <: EnumEntry](`enum`: Enum[E]): Decoder[E] = - enumDecoder[E](`enum`, `enum`.withNameLowercaseOnlyOption(_)) - def lowercaseEnumEncoder[E <: EnumEntry](`enum`: Enum[E]): Encoder[E] = - enumEncoder[E](`enum`, (e: EnumEntry) => e.entryName.toLowerCase) - - def uppercaseEnumDecoder[E <: EnumEntry](`enum`: Enum[E]): Decoder[E] = - enumDecoder[E](`enum`, `enum`.withNameUppercaseOnlyOption(_)) - def uppercaseEnumEncoder[E <: EnumEntry](`enum`: Enum[E]): Encoder[E] = - enumEncoder[E](`enum`, (e: EnumEntry) => e.entryName.toUpperCase()) -} - -trait CirceValueEnum { - @inline protected final def valueEnumDeserializationError[V, E <: ValueEnumEntry[V]](`enum`: ValueEnum[V, E], value: Json): String = { - val enumValues = `enum`.valuesToEntriesMap.keys.mkString(", ") - s"$value is not a member of $enumValues" - } - - def valueEnumDecoder[V, E <: ValueEnumEntry[V]](`enum`: ValueEnum[V, E])(implicit decoder: Decoder[V]): Decoder[E] = - (c: HCursor) => - decoder.emap(obj => `enum`.withValueOpt(obj).toRight("")).withErrorMessage(valueEnumDeserializationError(`enum`, c.value))(c) - - def valueEnumEncoder[V, E <: ValueEnumEntry[V]](`enum`: ValueEnum[V, E])(implicit encoder: Encoder[V]): Encoder[E] = - (obj: E) => encoder(obj.value) -} - -trait KebsEnumFormats extends CirceEnum with CirceValueEnum { - implicit def enumDecoder[E <: EnumEntry](implicit ev: EnumOf[E]): Decoder[E] = enumDecoder(ev.`enum`) - - implicit def enumEncoder[E <: EnumEntry](implicit ev: EnumOf[E]): Encoder[E] = enumEncoder(ev.`enum`) - - implicit def valueEnumDecoder[V, E <: ValueEnumEntry[V]](implicit ev: ValueEnumOf[V, E], decoder: Decoder[V]): Decoder[E] = - valueEnumDecoder(ev.valueEnum) - - implicit def valueEnumEncoder[V, E <: ValueEnumEntry[V]](implicit ev: ValueEnumOf[V, E], encoder: Encoder[V]): Encoder[E] = - valueEnumEncoder(ev.valueEnum) - - trait Uppercase extends CirceEnum { - implicit def enumDecoder[E <: EnumEntry](implicit ev: EnumOf[E]): Decoder[E] = - uppercaseEnumDecoder(ev.`enum`) - - implicit def enumEncoder[E <: EnumEntry](implicit ev: EnumOf[E]): Encoder[E] = - uppercaseEnumEncoder(ev.`enum`) - } - - trait Lowercase extends CirceEnum { - implicit def enumDecoder[E <: EnumEntry](implicit ev: EnumOf[E]): Decoder[E] = - lowercaseEnumDecoder(ev.`enum`) - - implicit def enumEncoder[E <: EnumEntry](implicit ev: EnumOf[E]): Encoder[E] = - lowercaseEnumEncoder(ev.`enum`) - } -} - -object KebsEnumFormats extends KebsEnumFormats diff --git a/circe/src/main/scala-2/pl/iterators/kebs/circe/KebsCirce.scala b/circe/src/main/scala-2/pl/iterators/kebs/circe/KebsCirce.scala index 3d977105..7eaf6743 100644 --- a/circe/src/main/scala-2/pl/iterators/kebs/circe/KebsCirce.scala +++ b/circe/src/main/scala-2/pl/iterators/kebs/circe/KebsCirce.scala @@ -2,16 +2,16 @@ package pl.iterators.kebs.circe import io.circe.generic.AutoDerivation import io.circe.{Decoder, Encoder} -import pl.iterators.kebs.instances.InstanceConverter -import pl.iterators.kebs.macros.CaseClass1Rep +import pl.iterators.kebs.core.instances.InstanceConverter +import pl.iterators.kebs.core.macros.{CaseClass1ToValueClass, ValueClassLike} import scala.language.experimental.macros import scala.util.Try -trait KebsCirce extends AutoDerivation { - implicit def flatDecoder[T, A](implicit rep: CaseClass1Rep[T, A], decoder: Decoder[A]): Decoder[T] = +trait KebsCirce extends AutoDerivation with CaseClass1ToValueClass { + implicit def flatDecoder[T, A](implicit rep: ValueClassLike[T, A], decoder: Decoder[A]): Decoder[T] = decoder.emap(obj => Try(rep.apply(obj)).toEither.left.map(_.getMessage)) - implicit def flatEncoder[T, A](implicit rep: CaseClass1Rep[T, A], encoder: Encoder[A]): Encoder[T] = + implicit def flatEncoder[T, A](implicit rep: ValueClassLike[T, A], encoder: Encoder[A]): Encoder[T] = encoder.contramap(rep.unapply) implicit def instanceConverterEncoder[T, A](implicit rep: InstanceConverter[T, A], encoder: Encoder[A]): Encoder[T] = diff --git a/circe/src/main/scala-2/KebsCirceMacros.scala b/circe/src/main/scala-2/pl/iterators/kebs/circe/KebsCirceMacros.scala similarity index 97% rename from circe/src/main/scala-2/KebsCirceMacros.scala rename to circe/src/main/scala-2/pl/iterators/kebs/circe/KebsCirceMacros.scala index 77776a13..a7ae3fa0 100644 --- a/circe/src/main/scala-2/KebsCirceMacros.scala +++ b/circe/src/main/scala-2/pl/iterators/kebs/circe/KebsCirceMacros.scala @@ -2,7 +2,8 @@ package pl.iterators.kebs.circe import io.circe.generic.extras.Configuration import io.circe.{Decoder, Encoder} -import pl.iterators.kebs.macros.MacroUtils +import pl.iterators.kebs.core.macros.MacroUtils +import pl.iterators.kebs.core.macros.namingconventions.SnakifyVariant.snakify import scala.collection.immutable.Seq import scala.reflect.macros.whitebox @@ -110,7 +111,6 @@ object KebsCirceMacros { class SnakifyVariant(context: whitebox.Context) extends KebsCirceMacros(context) { - import pl.iterators.kebs.macros.namingconventions.SnakifyVariant.snakify import c.universe._ protected override val semiAutoNamingStrategy: Tree = q"implicit lazy val __config: _root_.io.circe.generic.extras.Configuration = _root_.io.circe.generic.extras.Configuration.default.withSnakeCaseMemberNames" diff --git a/circe/src/main/scala-2/pl/iterators/kebs/circe/KebsEnumFormats.scala b/circe/src/main/scala-2/pl/iterators/kebs/circe/KebsEnumFormats.scala new file mode 100644 index 00000000..36fca8da --- /dev/null +++ b/circe/src/main/scala-2/pl/iterators/kebs/circe/KebsEnumFormats.scala @@ -0,0 +1,83 @@ +package pl.iterators.kebs.circe + +import io.circe.Decoder.Result +import io.circe._ +import pl.iterators.kebs.core.enums.{EnumLike, ValueEnumLike, ValueEnumLikeEntry} + +trait CirceEnum { + @inline protected final def enumNameDeserializationError[E](`enum`: EnumLike[E], name: String): String = { + val enumNames = `enum`.getNamesToValuesMap.values.mkString(", ") + s"$name should be one of $enumNames" + } + + @inline protected final def enumValueDeserializationError[E](`enum`: EnumLike[E], value: Json): String = { + val enumNames = `enum`.getNamesToValuesMap.values.mkString(", ") + s"$value should be a string of value $enumNames" + } + + protected final def enumDecoder[E](`enum`: EnumLike[E], _comap: String => Option[E]): Decoder[E] = + (c: HCursor) => + Decoder.decodeString.emap(str => _comap(str).toRight("")).withErrorMessage(enumValueDeserializationError(`enum`, c.value))(c) + + protected final def enumEncoder[E](`enum`: EnumLike[E], _map: E => String): Encoder[E] = + (obj: E) => Encoder.encodeString(_map(obj)) + + def enumDecoder[E](`enum`: EnumLike[E]): Decoder[E] = + enumDecoder[E](`enum`, `enum`.withNameInsensitiveOption(_)) + def enumEncoder[E](`enum`: EnumLike[E]): Encoder[E] = + enumEncoder[E](`enum`, (e: E) => e.toString) + + def lowercaseEnumDecoder[E](`enum`: EnumLike[E]): Decoder[E] = + enumDecoder[E](`enum`, `enum`.withNameLowercaseOnlyOption(_)) + def lowercaseEnumEncoder[E](`enum`: EnumLike[E]): Encoder[E] = + enumEncoder[E](`enum`, (e: E) => e.toString.toLowerCase) + + def uppercaseEnumDecoder[E](`enum`: EnumLike[E]): Decoder[E] = + enumDecoder[E](`enum`, `enum`.withNameUppercaseOnlyOption(_)) + def uppercaseEnumEncoder[E](`enum`: EnumLike[E]): Encoder[E] = + enumEncoder[E](`enum`, (e: E) => e.toString.toUpperCase()) +} + +trait CirceValueEnum { + @inline protected final def valueEnumDeserializationError[V, E <: ValueEnumLikeEntry[V]](`enum`: ValueEnumLike[V, E], value: Json): String = { + val enumValues = `enum`.getValuesToEntriesMap.keys.mkString(", ") + s"$value is not a member of $enumValues" + } + + def valueEnumDecoder[V, E <: ValueEnumLikeEntry[V]](`enum`: ValueEnumLike[V, E])(implicit decoder: Decoder[V]): Decoder[E] = + (c: HCursor) => + decoder.emap(obj => `enum`.withValueOption(obj).toRight("")).withErrorMessage(valueEnumDeserializationError(`enum`, c.value))(c) + + def valueEnumEncoder[V, E <: ValueEnumLikeEntry[V]](`enum`: ValueEnumLike[V, E])(implicit encoder: Encoder[V]): Encoder[E] = + (obj: E) => encoder(obj.value) +} + +trait KebsEnumFormats extends CirceEnum with CirceValueEnum { + implicit def enumDecoderImpl[E](implicit ev: EnumLike[E]): Decoder[E] = enumDecoder(ev) + + implicit def enumEncoderImpl[E](implicit ev: EnumLike[E]): Encoder[E] = enumEncoder(ev) + + implicit def valueEnumDecoderImpl[V, E <: ValueEnumLikeEntry[V]](implicit ev: ValueEnumLike[V, E], decoder: Decoder[V]): Decoder[E] = + valueEnumDecoder(ev) + + implicit def valueEnumEncoderImpl[V, E <: ValueEnumLikeEntry[V]](implicit ev: ValueEnumLike[V, E], encoder: Encoder[V]): Encoder[E] = + valueEnumEncoder(ev) + + trait Uppercase extends CirceEnum { + implicit def enumDecoderImpl[E](implicit ev: EnumLike[E]): Decoder[E] = + uppercaseEnumDecoder(ev) + + implicit def enumEncoderImpl[E](implicit ev: EnumLike[E]): Encoder[E] = + uppercaseEnumEncoder(ev) + } + + trait Lowercase extends CirceEnum { + implicit def enumDecoderImpl[E](implicit ev: EnumLike[E]): Decoder[E] = + lowercaseEnumDecoder(ev) + + implicit def enumEncoderImpl[E](implicit ev: EnumLike[E]): Encoder[E] = + lowercaseEnumEncoder(ev) + } +} + +object KebsEnumFormats extends KebsEnumFormats diff --git a/circe/src/main/scala-3/pl/iterators/kebs/circe/KebsCirce.scala b/circe/src/main/scala-3/pl/iterators/kebs/circe/KebsCirce.scala index a6219081..d65ccd4c 100644 --- a/circe/src/main/scala-3/pl/iterators/kebs/circe/KebsCirce.scala +++ b/circe/src/main/scala-3/pl/iterators/kebs/circe/KebsCirce.scala @@ -5,8 +5,6 @@ import scala.deriving._ import scala.util.Try import scala.quoted.Quotes import io.circe.HCursor -import pl.iterators.kebs.macros.CaseClass1Rep -import pl.iterators.kebs.instances.InstanceConverter import io.circe.generic.AutoDerivation import scala.quoted.Type import io.circe.derivation.ConfiguredDecoder @@ -17,7 +15,10 @@ import io.circe.EncoderDerivation import io.circe.derivation.ConfiguredEncoder import scala.NonEmptyTuple -private[circe] trait KebsAutoDerivation { +import pl.iterators.kebs.core.macros.{CaseClass1ToValueClass, ValueClassLike} +import pl.iterators.kebs.core.instances.InstanceConverter + +private[circe] trait KebsAutoDerivation extends CaseClass1ToValueClass { implicit val configuration: Configuration = Configuration.default @@ -29,11 +30,11 @@ private[circe] trait KebsAutoDerivation { } trait KebsCirce extends KebsAutoDerivation { - inline given[T, A](using rep: CaseClass1Rep[T, A], decoder: Decoder[A]): Decoder[T] = { + inline given[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: CaseClass1Rep[T, A], encoder: Encoder[A]): Encoder[T] = + inline given[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] = diff --git a/circe/src/main/scala-3/pl/iterators/kebs/circe/KebsEnumFormats.scala b/circe/src/main/scala-3/pl/iterators/kebs/circe/KebsEnumFormats.scala index e31d8833..eb0da740 100644 --- a/circe/src/main/scala-3/pl/iterators/kebs/circe/KebsEnumFormats.scala +++ b/circe/src/main/scala-3/pl/iterators/kebs/circe/KebsEnumFormats.scala @@ -2,86 +2,87 @@ package pl.iterators.kebs.circe import io.circe.Decoder.Result import io.circe._ -import pl.iterators.kebs.macros.enums.{EnumOf} import scala.reflect.Enum import scala.util.Try -import pl.iterators.kebs.enums.ValueEnum -import pl.iterators.kebs.macros.enums.ValueEnumLike -import pl.iterators.kebs.macros.enums.ValueEnumOf + +import pl.iterators.kebs.core.enums.{EnumLike, ValueEnumLike, ValueEnumLikeEntry} + +import reflect.Selectable.reflectiveSelectable + trait CirceEnum { - @inline protected final def enumNameDeserializationError[E <: Enum](e: EnumOf[E], name: String): String = { - val enumNames = e.`enum`.values.mkString(", ") + @inline protected final def enumNameDeserializationError[E <: Enum](e: EnumLike[E], name: String): String = { + val enumNames = e.values.mkString(", ") s"$name should be one of $enumNames" } - @inline protected final def enumValueDeserializationError[E <: Enum](e: EnumOf[E], value: Json): String = { - val enumNames = e.`enum`.values.mkString(", ") + @inline protected final def enumValueDeserializationError[E <: Enum](e: EnumLike[E], value: Json): String = { + val enumNames = e.values.mkString(", ") s"$value should be a string of value $enumNames" } - protected final def enumDecoder[E <: Enum](e: EnumOf[E], _comap: String => Option[E]): Decoder[E] = + protected final def enumDecoder[E <: Enum](e: EnumLike[E], _comap: String => Option[E]): Decoder[E] = (c: HCursor) => Decoder.decodeString.emap(str => _comap(str).toRight("")) .withErrorMessage(enumValueDeserializationError(e, c.value))(c) - protected final def enumEncoder[E <: Enum](e: EnumOf[E], _map: E => String): Encoder[E] = + protected final def enumEncoder[E <: Enum](e: EnumLike[E], _map: E => String): Encoder[E] = (obj: E) => Encoder.encodeString(_map(obj)) - def enumDecoder[E <: Enum](e: EnumOf[E]): Decoder[E] = - enumDecoder[E](e, s => e.`enum`.values.find(_.toString.equalsIgnoreCase(s))) + def enumDecoder[E <: Enum](e: EnumLike[E]): Decoder[E] = + enumDecoder[E](e, s => e.values.find(_.toString.equalsIgnoreCase(s))) - def enumEncoder[E <: Enum](e: EnumOf[E]): Encoder[E] = + def enumEncoder[E <: Enum](e: EnumLike[E]): Encoder[E] = enumEncoder[E](e, (e: Enum) => e.toString) - def lowercaseEnumDecoder[E <: Enum](e: EnumOf[E]): Decoder[E] = - enumDecoder[E](e, s => e.`enum`.values.find(_.toString.toLowerCase == s)) - def lowercaseEnumEncoder[E <: Enum](e: EnumOf[E]): Encoder[E] = + def lowercaseEnumDecoder[E <: Enum](e: EnumLike[E]): Decoder[E] = + enumDecoder[E](e, s => e.values.find(_.toString.toLowerCase == s)) + def lowercaseEnumEncoder[E <: Enum](e: EnumLike[E]): Encoder[E] = enumEncoder[E](e, (e: Enum) => e.toString.toLowerCase) - def uppercaseEnumDecoder[E <: Enum](e: EnumOf[E]): Decoder[E] = - enumDecoder[E](e, s => e.`enum`.values.find(_.toString().toUpperCase() == s)) - def uppercaseEnumEncoder[E <: Enum](e: EnumOf[E]): Encoder[E] = + def uppercaseEnumDecoder[E <: Enum](e: EnumLike[E]): Decoder[E] = + enumDecoder[E](e, s => e.values.find(_.toString().toUpperCase() == s)) + def uppercaseEnumEncoder[E <: Enum](e: EnumLike[E]): Encoder[E] = enumEncoder[E](e, (e: Enum) => e.toString().toUpperCase()) } trait CirceValueEnum { - @inline protected final def valueEnumDeserializationError[V, E <: ValueEnum[V] with Enum](e: ValueEnumOf[V, E], value: Json): String = { - val enumValues = e.`enum`.values.map(_.value.toString()).mkString(", ") + @inline protected final def valueEnumDeserializationError[V, E <: ValueEnumLikeEntry[V]](e: ValueEnumLike[V, E], value: Json): String = { + val enumValues = e.values.map(_.value.toString()).mkString(", ") s"$value is not a member of $enumValues" } - def valueEnumDecoder[V, E <: ValueEnum[V] with Enum](e: ValueEnumOf[V, E])(implicit decoder: Decoder[V]): Decoder[E] = + def valueEnumDecoder[V, E <: ValueEnumLikeEntry[V]](e: ValueEnumLike[V, E])(implicit decoder: Decoder[V]): Decoder[E] = (c: HCursor) => - decoder.emap(obj => Try(e.`enum`.valueOf(obj)).toOption.toRight("")).withErrorMessage(valueEnumDeserializationError(e, c.value))(c) + decoder.emap(obj => Try(e.valueOf(obj)).toOption.toRight("")).withErrorMessage(valueEnumDeserializationError(e, c.value))(c) - def valueEnumEncoder[V, E <: ValueEnum[V] with Enum](e: ValueEnumOf[V, E])(implicit encoder: Encoder[V]): Encoder[E] = + def valueEnumEncoder[V, E <: ValueEnumLikeEntry[V]](e: ValueEnumLike[V, E])(implicit encoder: Encoder[V]): Encoder[E] = (obj: E) => { encoder(obj.value) } } trait KebsEnumFormats extends CirceEnum with CirceValueEnum { - implicit inline given[E <: Enum](using ev: EnumOf[E]): Decoder[E] = enumDecoder(ev) + implicit inline given[E <: Enum](using ev: EnumLike[E]): Decoder[E] = enumDecoder(ev) - implicit inline given[E <: Enum](using ev: EnumOf[E]): Encoder[E] = enumEncoder(ev) + implicit inline given[E <: Enum](using ev: EnumLike[E]): Encoder[E] = enumEncoder(ev) - implicit inline given[V, E <: ValueEnum[V] with Enum](using ev: ValueEnumOf[V, E], decoder: Decoder[V]): Decoder[E] = + implicit inline given[V, E <: ValueEnumLikeEntry[V]](using ev: ValueEnumLike[V, E], decoder: Decoder[V]): Decoder[E] = valueEnumDecoder(ev) - implicit inline given[V, E <: ValueEnum[V] with Enum](using ev: ValueEnumOf[V, E], encoder: Encoder[V]): Encoder[E] = + implicit inline given[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: EnumOf[E]): Decoder[E] = + implicit inline given[E <: Enum](using ev: EnumLike[E]): Decoder[E] = uppercaseEnumDecoder(ev) - implicit inline given[E <: Enum](using ev: EnumOf[E]): Encoder[E] = + implicit inline given[E <: Enum](using ev: EnumLike[E]): Encoder[E] = uppercaseEnumEncoder(ev) } trait Lowercase extends CirceEnum { - implicit inline given[E <: Enum](using ev: EnumOf[E]): Decoder[E] = + implicit inline given[E <: Enum](using ev: EnumLike[E]): Decoder[E] = lowercaseEnumDecoder(ev) - implicit inline given[E <: Enum](using ev: EnumOf[E]): Encoder[E] = + implicit inline given[E <: Enum](using ev: EnumLike[E]): Encoder[E] = lowercaseEnumEncoder(ev) } } diff --git a/circe/src/main/scala/noflat.scala b/circe/src/main/scala/pl/iterators/kebs/circe/noflat.scala similarity index 100% rename from circe/src/main/scala/noflat.scala rename to circe/src/main/scala/pl/iterators/kebs/circe/noflat.scala diff --git a/circe/src/test/scala-2/CirceEnumDecoderEncoderTests.scala b/circe/src/test/scala-2/pl/iterators/kebs/circe/CirceEnumDecoderEncoderTests.scala similarity index 91% rename from circe/src/test/scala-2/CirceEnumDecoderEncoderTests.scala rename to circe/src/test/scala-2/pl/iterators/kebs/circe/CirceEnumDecoderEncoderTests.scala index 6b970772..85c74543 100644 --- a/circe/src/test/scala-2/CirceEnumDecoderEncoderTests.scala +++ b/circe/src/test/scala-2/pl/iterators/kebs/circe/CirceEnumDecoderEncoderTests.scala @@ -1,10 +1,14 @@ -import enumeratum.{Enum, EnumEntry} +package pl.iterators.kebs.circe + +import _root_.enumeratum.{Enum, EnumEntry} import io.circe._ +import org.scalatest.funsuite.AnyFunSuite import org.scalatest.matchers.should.Matchers import org.scalatest.funsuite.AnyFunSuite import pl.iterators.kebs.circe.KebsEnumFormats +import pl.iterators.kebs.enumeratum.KebsEnumeratum -class CirceEnumDecoderEncoderTests extends AnyFunSuite with Matchers { +class CirceEnumDecoderEncoderTests extends AnyFunSuite with Matchers with KebsEnumeratum { sealed trait Greeting extends EnumEntry object Greeting extends Enum[Greeting] { diff --git a/circe/src/test/scala-2/CirceFormatCapitalizedVariantTests.scala b/circe/src/test/scala-2/pl/iterators/kebs/circe/CirceFormatCapitalizedVariantTests.scala similarity index 97% rename from circe/src/test/scala-2/CirceFormatCapitalizedVariantTests.scala rename to circe/src/test/scala-2/pl/iterators/kebs/circe/CirceFormatCapitalizedVariantTests.scala index 1cbb4dc7..30b664d6 100644 --- a/circe/src/test/scala-2/CirceFormatCapitalizedVariantTests.scala +++ b/circe/src/test/scala-2/pl/iterators/kebs/circe/CirceFormatCapitalizedVariantTests.scala @@ -1,5 +1,6 @@ -import io.circe.generic.extras.decoding.ConfiguredDecoder -import io.circe.{Decoder, Encoder, Json, JsonNumber} +package pl.iterators.kebs.circe + +import io.circe.{Decoder, Encoder, Json} import org.scalatest.funsuite.AnyFunSuite import org.scalatest.matchers.should.Matchers import pl.iterators.kebs.circe.KebsCirce diff --git a/circe/src/test/scala-2/CirceFormatNoFlatTests.scala b/circe/src/test/scala-2/pl/iterators/kebs/circe/CirceFormatNoFlatTests.scala similarity index 95% rename from circe/src/test/scala-2/CirceFormatNoFlatTests.scala rename to circe/src/test/scala-2/pl/iterators/kebs/circe/CirceFormatNoFlatTests.scala index bf799f54..78e38819 100644 --- a/circe/src/test/scala-2/CirceFormatNoFlatTests.scala +++ b/circe/src/test/scala-2/pl/iterators/kebs/circe/CirceFormatNoFlatTests.scala @@ -1,3 +1,6 @@ +package pl.iterators.kebs.circe + +import io.circe.parser.parse import io.circe.{Decoder, Encoder, Json} import org.scalatest.funsuite.AnyFunSuite import org.scalatest.matchers.should.Matchers diff --git a/circe/src/test/scala-2/CirceFormatSnakifiedVariantTests.scala b/circe/src/test/scala-2/pl/iterators/kebs/circe/CirceFormatSnakifiedVariantTests.scala similarity index 99% rename from circe/src/test/scala-2/CirceFormatSnakifiedVariantTests.scala rename to circe/src/test/scala-2/pl/iterators/kebs/circe/CirceFormatSnakifiedVariantTests.scala index 83a86e85..e9d89d3a 100644 --- a/circe/src/test/scala-2/CirceFormatSnakifiedVariantTests.scala +++ b/circe/src/test/scala-2/pl/iterators/kebs/circe/CirceFormatSnakifiedVariantTests.scala @@ -1,3 +1,5 @@ +package pl.iterators.kebs.circe + import io.circe.{Decoder, Encoder, Json} import org.scalatest.funsuite.AnyFunSuite import org.scalatest.matchers.should.Matchers diff --git a/circe/src/test/scala-2/CirceFormatTests.scala b/circe/src/test/scala-2/pl/iterators/kebs/circe/CirceFormatTests.scala similarity index 99% rename from circe/src/test/scala-2/CirceFormatTests.scala rename to circe/src/test/scala-2/pl/iterators/kebs/circe/CirceFormatTests.scala index 8cbbdcf6..4127e5b0 100644 --- a/circe/src/test/scala-2/CirceFormatTests.scala +++ b/circe/src/test/scala-2/pl/iterators/kebs/circe/CirceFormatTests.scala @@ -1,10 +1,12 @@ -import java.time.ZonedDateTime +package pl.iterators.kebs.circe import io.circe.{Decoder, Encoder, Json} import org.scalatest.funsuite.AnyFunSuite import pl.iterators.kebs.circe.KebsCirce import org.scalatest.matchers.should.Matchers +import java.time.ZonedDateTime + class CirceFormatTests extends AnyFunSuite with Matchers { object KebsProtocol extends KebsCirce import KebsProtocol._ diff --git a/circe/src/test/scala-2/CirceValueEnumDecoderEncoderTests.scala b/circe/src/test/scala-2/pl/iterators/kebs/circe/CirceValueEnumDecoderEncoderTests.scala similarity index 81% rename from circe/src/test/scala-2/CirceValueEnumDecoderEncoderTests.scala rename to circe/src/test/scala-2/pl/iterators/kebs/circe/CirceValueEnumDecoderEncoderTests.scala index e17eaca8..be23ba5c 100644 --- a/circe/src/test/scala-2/CirceValueEnumDecoderEncoderTests.scala +++ b/circe/src/test/scala-2/pl/iterators/kebs/circe/CirceValueEnumDecoderEncoderTests.scala @@ -1,10 +1,15 @@ -import enumeratum.values.{LongEnum, LongEnumEntry} +package pl.iterators.kebs.circe + +import _root_.enumeratum.values.{LongEnum, LongEnumEntry} import io.circe._ import org.scalatest.funsuite.AnyFunSuite import org.scalatest.matchers.should.Matchers import pl.iterators.kebs.circe.KebsEnumFormats -class CirceValueEnumDecoderEncoderTests extends AnyFunSuite with Matchers { - sealed abstract class LongGreeting(val value: Long) extends LongEnumEntry +import pl.iterators.kebs.enumeratum.KebsValueEnumeratum +import pl.iterators.kebs.core.enums.ValueEnumLikeEntry + +class CirceValueEnumDecoderEncoderTests extends AnyFunSuite with Matchers with KebsValueEnumeratum { + sealed abstract class LongGreeting(val value: Long) extends LongEnumEntry with ValueEnumLikeEntry[Long] object LongGreeting extends LongEnum[LongGreeting] { val values = findValues diff --git a/circe/src/test/scala-2/instances/TimeInstancesMixinTests.scala b/circe/src/test/scala-2/pl/iterators/kebs/circe/instances/TimeInstancesMixinTests.scala similarity index 82% rename from circe/src/test/scala-2/instances/TimeInstancesMixinTests.scala rename to circe/src/test/scala-2/pl/iterators/kebs/circe/instances/TimeInstancesMixinTests.scala index 537e4d63..b52cf60b 100644 --- a/circe/src/test/scala-2/instances/TimeInstancesMixinTests.scala +++ b/circe/src/test/scala-2/pl/iterators/kebs/circe/instances/TimeInstancesMixinTests.scala @@ -1,4 +1,4 @@ - +package pl.iterators.kebs.circe.instances import io.circe.{Decoder, Encoder, Json} import org.scalatest.funsuite.AnyFunSuite @@ -6,7 +6,8 @@ import org.scalatest.matchers.should.Matchers import pl.iterators.kebs.circe.KebsCirce import pl.iterators.kebs.instances.time.LocalDateTimeString import pl.iterators.kebs.instances.time.mixins.{DurationNanosLong, InstantEpochMilliLong} -import pl.iterators.kebs.instances.{InstanceConverter, TimeInstances} +import pl.iterators.kebs.core.instances.InstanceConverter +import pl.iterators.kebs.instances.TimeInstances import java.time._ import java.time.format.DateTimeFormatter @@ -17,8 +18,8 @@ class TimeInstancesMixinTests extends AnyFunSuite with Matchers { object TimeInstancesProtocol extends KebsCirce with InstantEpochMilliLong import TimeInstancesProtocol._ - "implicitly[CaseClass1Rep[Instant, Long]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[Long, Instant]]" shouldNot typeCheck + "implicitly[ValueClassLike[Instant, Long]]" shouldNot typeCheck + "implicitly[ValueClassLike[Long, Instant]]" shouldNot typeCheck val decoder = implicitly[Decoder[Instant]] val encoder = implicitly[Encoder[Instant]] @@ -33,10 +34,10 @@ class TimeInstancesMixinTests extends AnyFunSuite with Matchers { object TimeInstancesProtocol extends KebsCirce with DurationNanosLong with InstantEpochMilliLong import TimeInstancesProtocol._ - "implicitly[CaseClass1Rep[Instant, Long]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[Long, Instant]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[Duration, Long]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[Long, Duration]]" shouldNot typeCheck + "implicitly[ValueClassLike[Instant, Long]]" shouldNot typeCheck + "implicitly[ValueClassLike[Long, Instant]]" shouldNot typeCheck + "implicitly[ValueClassLike[Duration, Long]]" shouldNot typeCheck + "implicitly[ValueClassLike[Long, Duration]]" shouldNot typeCheck val decoder_duration = implicitly[Decoder[Duration]] val encoder_duration = implicitly[Encoder[Duration]] @@ -64,8 +65,8 @@ class TimeInstancesMixinTests extends AnyFunSuite with Matchers { } import TimeInstancesProtocol._ - "implicitly[CaseClass1Rep[LocalDateTime, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, LocalDateTime]]" shouldNot typeCheck + "implicitly[ValueClassLike[LocalDateTime, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, LocalDateTime]]" shouldNot typeCheck val encoder = implicitly[Encoder[LocalDateTime]] val decoder = implicitly[Decoder[LocalDateTime]] @@ -98,8 +99,8 @@ class TimeInstancesMixinTests extends AnyFunSuite with Matchers { } import TimeInstancesProtocol._ - "implicitly[CaseClass1Rep[LocalDateTime, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, LocalDateTime]]" shouldNot typeCheck + "implicitly[ValueClassLike[LocalDateTime, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, LocalDateTime]]" shouldNot typeCheck val encoder = implicitly[Encoder[LocalDateTime]] val decoder = implicitly[Decoder[LocalDateTime]] diff --git a/spray-json/src/test/scala/model/package.scala b/circe/src/test/scala-2/pl/iterators/kebs/circe/model/model.scala similarity index 98% rename from spray-json/src/test/scala/model/package.scala rename to circe/src/test/scala-2/pl/iterators/kebs/circe/model/model.scala index 5907590a..96e758df 100644 --- a/spray-json/src/test/scala/model/package.scala +++ b/circe/src/test/scala-2/pl/iterators/kebs/circe/model/model.scala @@ -1,3 +1,5 @@ +package pl.iterators.kebs.circe + package object model { case class F1(f1: String) extends AnyVal @@ -27,6 +29,7 @@ package object model { f22: String, f23: Boolean ) + object ClassWith23Fields { val Example = ClassWith23Fields( f1 = F1("f1 value"), @@ -80,6 +83,7 @@ package object model { f22: String, f23: Boolean ) + object ClassWith23FieldsNested { val Example: ClassWith23FieldsNested = ClassWith23FieldsNested( f1 = F1("f1 value"), diff --git a/circe/src/test/scala-3/CirceEnumDecoderEncoderTests.scala b/circe/src/test/scala-3/pl/iterators/kebs/circe/CirceEnumDecoderEncoderTests.scala similarity index 95% rename from circe/src/test/scala-3/CirceEnumDecoderEncoderTests.scala rename to circe/src/test/scala-3/pl/iterators/kebs/circe/CirceEnumDecoderEncoderTests.scala index d5a67b0d..aef49ef1 100644 --- a/circe/src/test/scala-3/CirceEnumDecoderEncoderTests.scala +++ b/circe/src/test/scala-3/pl/iterators/kebs/circe/CirceEnumDecoderEncoderTests.scala @@ -1,10 +1,14 @@ +package pl.iterators.kebs.circe + import io.circe._ import org.scalatest.matchers.should.Matchers import org.scalatest.funsuite.AnyFunSuite import pl.iterators.kebs.circe.KebsEnumFormats import scala.reflect.Enum -class CirceEnumDecoderEncoderTests extends AnyFunSuite with Matchers { +import pl.iterators.kebs.enums.KebsEnum + +class CirceEnumDecoderEncoderTests extends AnyFunSuite with Matchers with KebsEnum { enum Greeting { case Hello, GoodBye, Hi, Bye diff --git a/circe/src/test/scala-3/CirceFormatCapitalizedVariantTests.scala b/circe/src/test/scala-3/pl/iterators/kebs/circe/CirceFormatCapitalizedVariantTests.scala similarity index 99% rename from circe/src/test/scala-3/CirceFormatCapitalizedVariantTests.scala rename to circe/src/test/scala-3/pl/iterators/kebs/circe/CirceFormatCapitalizedVariantTests.scala index a0c4876f..e75056b4 100644 --- a/circe/src/test/scala-3/CirceFormatCapitalizedVariantTests.scala +++ b/circe/src/test/scala-3/pl/iterators/kebs/circe/CirceFormatCapitalizedVariantTests.scala @@ -1,3 +1,5 @@ +package pl.iterators.kebs.circe + import io.circe.{Decoder, Encoder, Json, JsonNumber} import org.scalatest.funsuite.AnyFunSuite import org.scalatest.matchers.should.Matchers diff --git a/circe/src/test/scala-3/CirceFormatNoFlatTests.scala b/circe/src/test/scala-3/pl/iterators/kebs/circe/CirceFormatNoFlatTests.scala similarity index 97% rename from circe/src/test/scala-3/CirceFormatNoFlatTests.scala rename to circe/src/test/scala-3/pl/iterators/kebs/circe/CirceFormatNoFlatTests.scala index c2c5d451..a4c4b4f0 100644 --- a/circe/src/test/scala-3/CirceFormatNoFlatTests.scala +++ b/circe/src/test/scala-3/pl/iterators/kebs/circe/CirceFormatNoFlatTests.scala @@ -1,3 +1,5 @@ +package pl.iterators.kebs.circe + import io.circe.{Decoder, Encoder, Json} import org.scalatest.funsuite.AnyFunSuite import org.scalatest.matchers.should.Matchers diff --git a/circe/src/test/scala-3/CirceFormatSnakifiedVariantTests.scala b/circe/src/test/scala-3/pl/iterators/kebs/circe/CirceFormatSnakifiedVariantTests.scala similarity index 99% rename from circe/src/test/scala-3/CirceFormatSnakifiedVariantTests.scala rename to circe/src/test/scala-3/pl/iterators/kebs/circe/CirceFormatSnakifiedVariantTests.scala index 7f0aa9ba..df5deef0 100644 --- a/circe/src/test/scala-3/CirceFormatSnakifiedVariantTests.scala +++ b/circe/src/test/scala-3/pl/iterators/kebs/circe/CirceFormatSnakifiedVariantTests.scala @@ -1,3 +1,5 @@ +package pl.iterators.kebs.circe + import io.circe.{Decoder, Encoder, Json} import org.scalatest.funsuite.AnyFunSuite import org.scalatest.matchers.should.Matchers diff --git a/circe/src/test/scala-3/CirceFormatTests.scala b/circe/src/test/scala-3/pl/iterators/kebs/circe/CirceFormatTests.scala similarity index 99% rename from circe/src/test/scala-3/CirceFormatTests.scala rename to circe/src/test/scala-3/pl/iterators/kebs/circe/CirceFormatTests.scala index b5b7a84b..c351608d 100644 --- a/circe/src/test/scala-3/CirceFormatTests.scala +++ b/circe/src/test/scala-3/pl/iterators/kebs/circe/CirceFormatTests.scala @@ -1,3 +1,5 @@ +package pl.iterators.kebs.circe + import java.time.ZonedDateTime import io.circe.{Decoder, Encoder, Json} diff --git a/circe/src/test/scala-3/CirceValueEnumDecoderEncoderTests.scala b/circe/src/test/scala-3/pl/iterators/kebs/circe/CirceValueEnumDecoderEncoderTests.scala similarity index 83% rename from circe/src/test/scala-3/CirceValueEnumDecoderEncoderTests.scala rename to circe/src/test/scala-3/pl/iterators/kebs/circe/CirceValueEnumDecoderEncoderTests.scala index 53ba8e4d..946fcbbd 100644 --- a/circe/src/test/scala-3/CirceValueEnumDecoderEncoderTests.scala +++ b/circe/src/test/scala-3/pl/iterators/kebs/circe/CirceValueEnumDecoderEncoderTests.scala @@ -1,15 +1,19 @@ +package pl.iterators.kebs.circe + import enumeratum.values.{LongEnum, LongEnumEntry} import io.circe._ import org.scalatest.funsuite.AnyFunSuite import org.scalatest.matchers.should.Matchers import pl.iterators.kebs.circe.KebsEnumFormats -import pl.iterators.kebs.enums.ValueEnum -class CirceValueEnumDecoderEncoderTests extends AnyFunSuite with Matchers { +import pl.iterators.kebs.enums.KebsValueEnum +import pl.iterators.kebs.core.enums.ValueEnumLikeEntry + +class CirceValueEnumDecoderEncoderTests extends AnyFunSuite with Matchers with KebsValueEnum { object KebsProtocol extends KebsEnumFormats - enum LongGreeting(val value: Long) extends ValueEnum[Long] { + enum LongGreeting(val value: Long) extends ValueEnumLikeEntry[Long] { case Hello extends LongGreeting(0L) case GoodBye extends LongGreeting(1L) case Hi extends LongGreeting(2L) diff --git a/circe/src/test/scala-3/instances/TimeInstancesMixinTests.scala b/circe/src/test/scala-3/pl/iterators/kebs/circe/instances/TimeInstancesMixinTests.scala similarity index 80% rename from circe/src/test/scala-3/instances/TimeInstancesMixinTests.scala rename to circe/src/test/scala-3/pl/iterators/kebs/circe/instances/TimeInstancesMixinTests.scala index d1f165b6..6b3bbf98 100644 --- a/circe/src/test/scala-3/instances/TimeInstancesMixinTests.scala +++ b/circe/src/test/scala-3/pl/iterators/kebs/circe/instances/TimeInstancesMixinTests.scala @@ -1,24 +1,26 @@ - +package pl.iterators.kebs.circe.instances import io.circe.{Decoder, Encoder, Json} import org.scalatest.funsuite.AnyFunSuite import org.scalatest.matchers.should.Matchers import pl.iterators.kebs.circe.KebsCirce -import pl.iterators.kebs.instances.time.LocalDateTimeString -import pl.iterators.kebs.instances.time.mixins.{DurationNanosLong, InstantEpochMilliLong} -import pl.iterators.kebs.instances.{InstanceConverter, TimeInstances} import java.time._ import java.time.format.DateTimeFormatter +import pl.iterators.kebs.core.instances.InstanceConverter +import pl.iterators.kebs.instances.TimeInstances +import pl.iterators.kebs.instances.time.LocalDateTimeString +import pl.iterators.kebs.instances.time.mixins.{InstantEpochMilliLong, DurationNanosLong} + class TimeInstancesMixinTests extends AnyFunSuite with Matchers { test("Instant epoch milli format") { object TimeInstancesProtocol extends KebsCirce with InstantEpochMilliLong import TimeInstancesProtocol.{given, _} - "implicitly[CaseClass1Rep[Instant, Long]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[Long, Instant]]" shouldNot typeCheck + "implicitly[ValueClassLike[Instant, Long]]" shouldNot typeCheck + "implicitly[ValueClassLike[Long, Instant]]" shouldNot typeCheck val decoder = implicitly[Decoder[Instant]] val encoder = implicitly[Encoder[Instant]] @@ -33,10 +35,10 @@ class TimeInstancesMixinTests extends AnyFunSuite with Matchers { object TimeInstancesProtocol extends KebsCirce with DurationNanosLong with InstantEpochMilliLong import TimeInstancesProtocol.{given, _} - "implicitly[CaseClass1Rep[Instant, Long]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[Long, Instant]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[Duration, Long]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[Long, Duration]]" shouldNot typeCheck + "implicitly[ValueClassLike[Instant, Long]]" shouldNot typeCheck + "implicitly[ValueClassLike[Long, Instant]]" shouldNot typeCheck + "implicitly[ValueClassLike[Duration, Long]]" shouldNot typeCheck + "implicitly[ValueClassLike[Long, Duration]]" shouldNot typeCheck val decoder_duration = implicitly[Decoder[Duration]] val encoder_duration = implicitly[Encoder[Duration]] @@ -64,8 +66,8 @@ class TimeInstancesMixinTests extends AnyFunSuite with Matchers { } import TimeInstancesProtocol.{given, _} - "implicitly[CaseClass1Rep[LocalDateTime, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, LocalDateTime]]" shouldNot typeCheck + "implicitly[ValueClassLike[LocalDateTime, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, LocalDateTime]]" shouldNot typeCheck val encoder = implicitly[Encoder[LocalDateTime]] val decoder = implicitly[Decoder[LocalDateTime]] @@ -98,8 +100,8 @@ class TimeInstancesMixinTests extends AnyFunSuite with Matchers { } import TimeInstancesProtocol.{given, _} - "implicitly[CaseClass1Rep[LocalDateTime, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, LocalDateTime]]" shouldNot typeCheck + "implicitly[ValueClassLike[LocalDateTime, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, LocalDateTime]]" shouldNot typeCheck val encoder = implicitly[Encoder[LocalDateTime]] val decoder = implicitly[Decoder[LocalDateTime]] diff --git a/circe/src/test/scala-3/model/model.scala b/circe/src/test/scala-3/pl/iterators/kebs/circe/model/model.scala similarity index 98% rename from circe/src/test/scala-3/model/model.scala rename to circe/src/test/scala-3/pl/iterators/kebs/circe/model/model.scala index f2d030b3..110a7cfb 100644 --- a/circe/src/test/scala-3/model/model.scala +++ b/circe/src/test/scala-3/pl/iterators/kebs/circe/model/model.scala @@ -1,3 +1,4 @@ +package pl.iterators.kebs.circe import io.circe.Decoder import io.circe.Encoder diff --git a/circe/src/test/scala/instances/NetInstancesTests.scala b/circe/src/test/scala/pl/iterators/kebs/circe/instances/NetInstancesTests.scala similarity index 78% rename from circe/src/test/scala/instances/NetInstancesTests.scala rename to circe/src/test/scala/pl/iterators/kebs/circe/instances/NetInstancesTests.scala index 8a62ed22..a5aa939f 100644 --- a/circe/src/test/scala/instances/NetInstancesTests.scala +++ b/circe/src/test/scala/pl/iterators/kebs/circe/instances/NetInstancesTests.scala @@ -1,4 +1,4 @@ -package instances +package pl.iterators.kebs.circe.instances import io.circe.{Decoder, Encoder, Json} import org.scalatest.funsuite.AnyFunSuite @@ -27,9 +27,9 @@ class NetInstancesTests extends AnyFunSuite with Matchers with KebsCirce with UR decoder(Json.fromString(value).hcursor) shouldBe a [Left[_, _]] } - test("No CaseClass1Rep implicits derived") { + test("No ValueClassLike implicits derived") { - "implicitly[CaseClass1Rep[URI, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, URI]]" shouldNot typeCheck + "implicitly[ValueClassLike[URI, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, URI]]" shouldNot typeCheck } } diff --git a/circe/src/test/scala/instances/TimeInstancesTests.scala b/circe/src/test/scala/pl/iterators/kebs/circe/instances/TimeInstancesTests.scala similarity index 79% rename from circe/src/test/scala/instances/TimeInstancesTests.scala rename to circe/src/test/scala/pl/iterators/kebs/circe/instances/TimeInstancesTests.scala index 53c114b2..2a7c7793 100644 --- a/circe/src/test/scala/instances/TimeInstancesTests.scala +++ b/circe/src/test/scala/pl/iterators/kebs/circe/instances/TimeInstancesTests.scala @@ -1,50 +1,50 @@ - package instances + package pl.iterators.kebs.circe.instances - import io.circe.{Decoder, Encoder, Json} +import io.circe.{Decoder, Encoder, Json} import org.scalatest.funsuite.AnyFunSuite import org.scalatest.matchers.should.Matchers import pl.iterators.kebs.circe.KebsCirce - import pl.iterators.kebs.instances.InstanceConverter.DecodeErrorException + import pl.iterators.kebs.core.instances.InstanceConverter.DecodeErrorException import pl.iterators.kebs.instances.TimeInstances import java.time._ class TimeInstancesTests extends AnyFunSuite with Matchers with KebsCirce with TimeInstances { - test("No CaseClass1Rep implicits derived") { - - "implicitly[CaseClass1Rep[DayOfWeek, Int]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[Int, DayOfWeek]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[Duration, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, Duration]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[Instant, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, Instant]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[LocalDate, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, LocalDate]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[LocalDateTime, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, LocalDateTime]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[LocalTime, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, LocalTime]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[Month, Int]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[Int, Month]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[MonthDay, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, MonthDay]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[OffsetDateTime, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, OffsetDateTime]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[OffsetTime, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, OffsetTime]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[Period, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, Period]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[Year, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, Year]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[YearMonth, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, YearMonth]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[ZoneId, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, ZoneId]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[ZoneOffset, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, ZoneOffset]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[ZonedDateTime, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, ZonedDateTime]]" shouldNot typeCheck + test("No ValueClassLike implicits derived") { + + "implicitly[ValueClassLike[DayOfWeek, Int]]" shouldNot typeCheck + "implicitly[ValueClassLike[Int, DayOfWeek]]" shouldNot typeCheck + "implicitly[ValueClassLike[Duration, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, Duration]]" shouldNot typeCheck + "implicitly[ValueClassLike[Instant, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, Instant]]" shouldNot typeCheck + "implicitly[ValueClassLike[LocalDate, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, LocalDate]]" shouldNot typeCheck + "implicitly[ValueClassLike[LocalDateTime, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, LocalDateTime]]" shouldNot typeCheck + "implicitly[ValueClassLike[LocalTime, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, LocalTime]]" shouldNot typeCheck + "implicitly[ValueClassLike[Month, Int]]" shouldNot typeCheck + "implicitly[ValueClassLike[Int, Month]]" shouldNot typeCheck + "implicitly[ValueClassLike[MonthDay, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, MonthDay]]" shouldNot typeCheck + "implicitly[ValueClassLike[OffsetDateTime, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, OffsetDateTime]]" shouldNot typeCheck + "implicitly[ValueClassLike[OffsetTime, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, OffsetTime]]" shouldNot typeCheck + "implicitly[ValueClassLike[Period, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, Period]]" shouldNot typeCheck + "implicitly[ValueClassLike[Year, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, Year]]" shouldNot typeCheck + "implicitly[ValueClassLike[YearMonth, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, YearMonth]]" shouldNot typeCheck + "implicitly[ValueClassLike[ZoneId, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, ZoneId]]" shouldNot typeCheck + "implicitly[ValueClassLike[ZoneOffset, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, ZoneOffset]]" shouldNot typeCheck + "implicitly[ValueClassLike[ZonedDateTime, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, ZonedDateTime]]" shouldNot typeCheck } test("DayOfWeek standard format") { diff --git a/circe/src/test/scala/instances/UtilInstancesTests.scala b/circe/src/test/scala/pl/iterators/kebs/circe/instances/UtilInstancesTests.scala similarity index 75% rename from circe/src/test/scala/instances/UtilInstancesTests.scala rename to circe/src/test/scala/pl/iterators/kebs/circe/instances/UtilInstancesTests.scala index 332c62dc..9c17b746 100644 --- a/circe/src/test/scala/instances/UtilInstancesTests.scala +++ b/circe/src/test/scala/pl/iterators/kebs/circe/instances/UtilInstancesTests.scala @@ -1,24 +1,24 @@ -package instances +package pl.iterators.kebs.circe.instances import io.circe.{Decoder, Encoder, Json} import org.scalatest.funsuite.AnyFunSuite import org.scalatest.matchers.should.Matchers import pl.iterators.kebs.circe.KebsCirce -import pl.iterators.kebs.instances.InstanceConverter.DecodeErrorException +import pl.iterators.kebs.core.instances.InstanceConverter.DecodeErrorException import pl.iterators.kebs.instances.UtilInstances import java.util.{Currency, Locale, UUID} class UtilInstancesTests extends AnyFunSuite with Matchers with KebsCirce with UtilInstances { - test("No CaseClass1Rep implicits derived") { + test("No ValueClassLike implicits derived") { - "implicitly[CaseClass1Rep[Currency, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, Currency]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[Locale, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, Locale]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[UUID, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, UUID]]" shouldNot typeCheck + "implicitly[ValueClassLike[Currency, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, Currency]]" shouldNot typeCheck + "implicitly[ValueClassLike[Locale, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, Locale]]" shouldNot typeCheck + "implicitly[ValueClassLike[UUID, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, UUID]]" shouldNot typeCheck } test("Currency standard format") { diff --git a/core/src/main/scala-2.12/pl/iterators/kebs/support/FractionalSupport.scala b/core/src/main/scala-2.12/pl/iterators/kebs/core/support/FractionalSupport.scala similarity index 78% rename from core/src/main/scala-2.12/pl/iterators/kebs/support/FractionalSupport.scala rename to core/src/main/scala-2.12/pl/iterators/kebs/core/support/FractionalSupport.scala index 57a73211..ba41c9d4 100644 --- a/core/src/main/scala-2.12/pl/iterators/kebs/support/FractionalSupport.scala +++ b/core/src/main/scala-2.12/pl/iterators/kebs/core/support/FractionalSupport.scala @@ -1,14 +1,12 @@ package pl.iterators.kebs.support -import pl.iterators.kebs.macros.CaseClass1Rep - trait FractionalSupport { - implicit def fractionalFromCaseClass1Rep[A, Rep](implicit cc1Rep: CaseClass1Rep[A, Rep], + implicit def fractionalFromValueClassLike[A, Rep](implicit vcLike: ValueClassLike[A, Rep], fractionalRep: Fractional[Rep], numeric: Numeric[A]): Fractional[A] = new Fractional[A] { - override def div(x: A, y: A): A = cc1Rep.apply(fractionalRep.div(cc1Rep.unapply(x), cc1Rep.unapply(y))) + override def div(x: A, y: A): A = vcLike.apply(fractionalRep.div(vcLike.unapply(x), vcLike.unapply(y))) override def plus(x: A, y: A): A = numeric.plus(x, y) override def minus(x: A, y: A): A = numeric.minus(x, y) override def times(x: A, y: A): A = numeric.times(x, y) diff --git a/core/src/main/scala-2.12/pl/iterators/kebs/support/IntegralSupport.scala b/core/src/main/scala-2.12/pl/iterators/kebs/core/support/IntegralSupport.scala similarity index 71% rename from core/src/main/scala-2.12/pl/iterators/kebs/support/IntegralSupport.scala rename to core/src/main/scala-2.12/pl/iterators/kebs/core/support/IntegralSupport.scala index 82f6683c..8b1a3417 100644 --- a/core/src/main/scala-2.12/pl/iterators/kebs/support/IntegralSupport.scala +++ b/core/src/main/scala-2.12/pl/iterators/kebs/core/support/IntegralSupport.scala @@ -1,15 +1,13 @@ package pl.iterators.kebs.support -import pl.iterators.kebs.macros.CaseClass1Rep - trait IntegralSupport { - implicit def integralFromCaseClass1Rep[A, Rep](implicit cc1Rep: CaseClass1Rep[A, Rep], + implicit def integralFromValueClassLike[A, Rep](implicit vcLike: ValueClassLike[A, Rep], integralRep: Integral[Rep], numeric: Numeric[A]): Integral[A] = new Integral[A] { - override def quot(x: A, y: A): A = cc1Rep.apply(integralRep.quot(cc1Rep.unapply(x), cc1Rep.unapply(y))) - override def rem(x: A, y: A): A = cc1Rep.apply(integralRep.rem(cc1Rep.unapply(x), cc1Rep.unapply(y))) + override def quot(x: A, y: A): A = vcLike.apply(integralRep.quot(vcLike.unapply(x), vcLike.unapply(y))) + override def rem(x: A, y: A): A = vcLike.apply(integralRep.rem(vcLike.unapply(x), vcLike.unapply(y))) override def plus(x: A, y: A): A = numeric.plus(x, y) override def minus(x: A, y: A): A = numeric.minus(x, y) override def times(x: A, y: A): A = numeric.times(x, y) diff --git a/core/src/main/scala-2.12/pl/iterators/kebs/core/support/NumericSupport.scala b/core/src/main/scala-2.12/pl/iterators/kebs/core/support/NumericSupport.scala new file mode 100644 index 00000000..eec0c85d --- /dev/null +++ b/core/src/main/scala-2.12/pl/iterators/kebs/core/support/NumericSupport.scala @@ -0,0 +1,20 @@ +package pl.iterators.kebs.support + +trait NumericSupport { + + implicit def numericFromValueClassLike[A, Rep](implicit vcLike: ValueClassLike[A, Rep], numericRep: Numeric[Rep]): Numeric[A] = { + new Numeric[A] { + override def plus(x: A, y: A): A = vcLike.apply(numericRep.plus(vcLike.unapply(x), vcLike.unapply(y))) + override def minus(x: A, y: A): A = vcLike.apply(numericRep.minus(vcLike.unapply(x), vcLike.unapply(y))) + override def times(x: A, y: A): A = vcLike.apply(numericRep.times(vcLike.unapply(x), vcLike.unapply(y))) + override def negate(x: A): A = vcLike.apply(numericRep.negate(vcLike.unapply(x))) + override def fromInt(x: Int): A = vcLike.apply(numericRep.fromInt(x)) + override def toInt(x: A): Int = numericRep.toInt(vcLike.unapply(x)) + override def toLong(x: A): Long = numericRep.toLong(vcLike.unapply(x)) + override def toFloat(x: A): Float = numericRep.toFloat(vcLike.unapply(x)) + override def toDouble(x: A): Double = numericRep.toDouble(vcLike.unapply(x)) + override def compare(x: A, y: A): Int = numericRep.compare(vcLike.unapply(x), vcLike.unapply(y)) + } + } + +} diff --git a/core/src/main/scala-2.12/pl/iterators/kebs/support/NumericSupport.scala b/core/src/main/scala-2.12/pl/iterators/kebs/support/NumericSupport.scala deleted file mode 100644 index 74e198d7..00000000 --- a/core/src/main/scala-2.12/pl/iterators/kebs/support/NumericSupport.scala +++ /dev/null @@ -1,22 +0,0 @@ -package pl.iterators.kebs.support - -import pl.iterators.kebs.macros.CaseClass1Rep - -trait NumericSupport { - - implicit def numericFromCaseClass1Rep[A, Rep](implicit cc1Rep: CaseClass1Rep[A, Rep], numericRep: Numeric[Rep]): Numeric[A] = { - new Numeric[A] { - override def plus(x: A, y: A): A = cc1Rep.apply(numericRep.plus(cc1Rep.unapply(x), cc1Rep.unapply(y))) - override def minus(x: A, y: A): A = cc1Rep.apply(numericRep.minus(cc1Rep.unapply(x), cc1Rep.unapply(y))) - override def times(x: A, y: A): A = cc1Rep.apply(numericRep.times(cc1Rep.unapply(x), cc1Rep.unapply(y))) - override def negate(x: A): A = cc1Rep.apply(numericRep.negate(cc1Rep.unapply(x))) - override def fromInt(x: Int): A = cc1Rep.apply(numericRep.fromInt(x)) - override def toInt(x: A): Int = numericRep.toInt(cc1Rep.unapply(x)) - override def toLong(x: A): Long = numericRep.toLong(cc1Rep.unapply(x)) - override def toFloat(x: A): Float = numericRep.toFloat(cc1Rep.unapply(x)) - override def toDouble(x: A): Double = numericRep.toDouble(cc1Rep.unapply(x)) - override def compare(x: A, y: A): Int = numericRep.compare(cc1Rep.unapply(x), cc1Rep.unapply(y)) - } - } - -} diff --git a/core/src/main/scala-3/pl/iterators/kebs/support/FractionalSupport.scala b/core/src/main/scala-2.13/pl/iterators/kebs/core/support/FractionalSupport.scala similarity index 65% rename from core/src/main/scala-3/pl/iterators/kebs/support/FractionalSupport.scala rename to core/src/main/scala-2.13/pl/iterators/kebs/core/support/FractionalSupport.scala index 45f64b50..dca58245 100644 --- a/core/src/main/scala-3/pl/iterators/kebs/support/FractionalSupport.scala +++ b/core/src/main/scala-2.13/pl/iterators/kebs/core/support/FractionalSupport.scala @@ -1,14 +1,14 @@ -package pl.iterators.kebs.support +package pl.iterators.kebs.core.support -import pl.iterators.kebs.macros.CaseClass1Rep +import pl.iterators.kebs.core.macros.ValueClassLike trait FractionalSupport { - implicit def fractionalFromCaseClass1Rep[A, Rep](implicit cc1Rep: CaseClass1Rep[A, Rep], - fractionalRep: Fractional[Rep], - numeric: Numeric[A]): Fractional[A] = + implicit def fractionalFromValueClassLike[A, Rep](implicit vcLike: ValueClassLike[A, Rep], + fractionalRep: Fractional[Rep], + numeric: Numeric[A]): Fractional[A] = new Fractional[A] { - override def div(x: A, y: A): A = cc1Rep.apply(fractionalRep.div(cc1Rep.unapply(x), cc1Rep.unapply(y))) + override def div(x: A, y: A): A = vcLike.apply(fractionalRep.div(vcLike.unapply(x), vcLike.unapply(y))) override def plus(x: A, y: A): A = numeric.plus(x, y) override def minus(x: A, y: A): A = numeric.minus(x, y) override def times(x: A, y: A): A = numeric.times(x, y) diff --git a/core/src/main/scala-2.13/pl/iterators/kebs/support/IntegralSupport.scala b/core/src/main/scala-2.13/pl/iterators/kebs/core/support/IntegralSupport.scala similarity index 71% rename from core/src/main/scala-2.13/pl/iterators/kebs/support/IntegralSupport.scala rename to core/src/main/scala-2.13/pl/iterators/kebs/core/support/IntegralSupport.scala index 3fc592bb..a301d026 100644 --- a/core/src/main/scala-2.13/pl/iterators/kebs/support/IntegralSupport.scala +++ b/core/src/main/scala-2.13/pl/iterators/kebs/core/support/IntegralSupport.scala @@ -1,15 +1,15 @@ -package pl.iterators.kebs.support +package pl.iterators.kebs.core.support -import pl.iterators.kebs.macros.CaseClass1Rep +import pl.iterators.kebs.core.macros.ValueClassLike trait IntegralSupport { - implicit def integralFromCaseClass1Rep[A, Rep](implicit cc1Rep: CaseClass1Rep[A, Rep], + implicit def integralFromValueClassLike[A, Rep](implicit vcLike: ValueClassLike[A, Rep], integralRep: Integral[Rep], numeric: Numeric[A]): Integral[A] = new Integral[A] { - override def quot(x: A, y: A): A = cc1Rep.apply(integralRep.quot(cc1Rep.unapply(x), cc1Rep.unapply(y))) - override def rem(x: A, y: A): A = cc1Rep.apply(integralRep.rem(cc1Rep.unapply(x), cc1Rep.unapply(y))) + override def quot(x: A, y: A): A = vcLike.apply(integralRep.quot(vcLike.unapply(x), vcLike.unapply(y))) + override def rem(x: A, y: A): A = vcLike.apply(integralRep.rem(vcLike.unapply(x), vcLike.unapply(y))) override def plus(x: A, y: A): A = numeric.plus(x, y) override def minus(x: A, y: A): A = numeric.minus(x, y) override def times(x: A, y: A): A = numeric.times(x, y) diff --git a/core/src/main/scala-2.13/pl/iterators/kebs/core/support/NumericSupport.scala b/core/src/main/scala-2.13/pl/iterators/kebs/core/support/NumericSupport.scala new file mode 100644 index 00000000..35ce1bab --- /dev/null +++ b/core/src/main/scala-2.13/pl/iterators/kebs/core/support/NumericSupport.scala @@ -0,0 +1,23 @@ +package pl.iterators.kebs.core.support + +import pl.iterators.kebs.core.macros.ValueClassLike + +trait NumericSupport { + + implicit def numericFromValueClassLike[A, Rep](implicit vcLike: ValueClassLike[A, Rep], numericRep: Numeric[Rep]): Numeric[A] = { + new Numeric[A] { + override def plus(x: A, y: A): A = vcLike.apply(numericRep.plus(vcLike.unapply(x), vcLike.unapply(y))) + override def minus(x: A, y: A): A = vcLike.apply(numericRep.minus(vcLike.unapply(x), vcLike.unapply(y))) + override def times(x: A, y: A): A = vcLike.apply(numericRep.times(vcLike.unapply(x), vcLike.unapply(y))) + override def negate(x: A): A = vcLike.apply(numericRep.negate(vcLike.unapply(x))) + override def fromInt(x: Int): A = vcLike.apply(numericRep.fromInt(x)) + override def toInt(x: A): Int = numericRep.toInt(vcLike.unapply(x)) + override def toLong(x: A): Long = numericRep.toLong(vcLike.unapply(x)) + override def toFloat(x: A): Float = numericRep.toFloat(vcLike.unapply(x)) + override def toDouble(x: A): Double = numericRep.toDouble(vcLike.unapply(x)) + override def compare(x: A, y: A): Int = numericRep.compare(vcLike.unapply(x), vcLike.unapply(y)) + override def parseString(str: String): Option[A] = numericRep.parseString(str).map(vcLike.apply) + } + } + +} diff --git a/core/src/main/scala-2.13/pl/iterators/kebs/support/NumericSupport.scala b/core/src/main/scala-2.13/pl/iterators/kebs/support/NumericSupport.scala deleted file mode 100644 index 27d4c234..00000000 --- a/core/src/main/scala-2.13/pl/iterators/kebs/support/NumericSupport.scala +++ /dev/null @@ -1,23 +0,0 @@ -package pl.iterators.kebs.support - -import pl.iterators.kebs.macros.CaseClass1Rep - -trait NumericSupport { - - implicit def numericFromCaseClass1Rep[A, Rep](implicit cc1Rep: CaseClass1Rep[A, Rep], numericRep: Numeric[Rep]): Numeric[A] = { - new Numeric[A] { - override def plus(x: A, y: A): A = cc1Rep.apply(numericRep.plus(cc1Rep.unapply(x), cc1Rep.unapply(y))) - override def minus(x: A, y: A): A = cc1Rep.apply(numericRep.minus(cc1Rep.unapply(x), cc1Rep.unapply(y))) - override def times(x: A, y: A): A = cc1Rep.apply(numericRep.times(cc1Rep.unapply(x), cc1Rep.unapply(y))) - override def negate(x: A): A = cc1Rep.apply(numericRep.negate(cc1Rep.unapply(x))) - override def fromInt(x: Int): A = cc1Rep.apply(numericRep.fromInt(x)) - override def toInt(x: A): Int = numericRep.toInt(cc1Rep.unapply(x)) - override def toLong(x: A): Long = numericRep.toLong(cc1Rep.unapply(x)) - override def toFloat(x: A): Float = numericRep.toFloat(cc1Rep.unapply(x)) - override def toDouble(x: A): Double = numericRep.toDouble(cc1Rep.unapply(x)) - override def compare(x: A, y: A): Int = numericRep.compare(cc1Rep.unapply(x), cc1Rep.unapply(y)) - override def parseString(str: String): Option[A] = numericRep.parseString(str).map(cc1Rep.apply) - } - } - -} diff --git a/core/src/main/scala-2/pl/iterators/kebs/macros/MacroUtils.scala b/core/src/main/scala-2/pl/iterators/kebs/core/macros/MacroUtils.scala similarity index 97% rename from core/src/main/scala-2/pl/iterators/kebs/macros/MacroUtils.scala rename to core/src/main/scala-2/pl/iterators/kebs/core/macros/MacroUtils.scala index 03014095..3189f67f 100644 --- a/core/src/main/scala-2/pl/iterators/kebs/macros/MacroUtils.scala +++ b/core/src/main/scala-2/pl/iterators/kebs/core/macros/MacroUtils.scala @@ -1,4 +1,4 @@ -package pl.iterators.kebs.macros +package pl.iterators.kebs.core.macros import scala.reflect.macros._ diff --git a/core/src/main/scala-2/pl/iterators/kebs/core/macros/ValueClassReps.scala b/core/src/main/scala-2/pl/iterators/kebs/core/macros/ValueClassReps.scala new file mode 100644 index 00000000..c6866edf --- /dev/null +++ b/core/src/main/scala-2/pl/iterators/kebs/core/macros/ValueClassReps.scala @@ -0,0 +1,35 @@ +package pl.iterators.kebs.core.macros + +import scala.language.experimental.macros +import scala.language.higherKinds +import scala.reflect.macros.whitebox + +final class ValueClassLike[VC, F1](val apply: F1 => VC, val unapply: VC => F1) + +trait CaseClass1ToValueClass { + implicit def repFromCaseClass[VC <: Product, F1]: ValueClassLike[VC, F1] = macro ValueClassRepMacros.materializeValueClassRep[VC, F1] +} +object CaseClass1ToValueClass extends CaseClass1ToValueClass + +class ValueClassRepMacros(override val c: whitebox.Context) extends MacroUtils { + import c.universe._ + + def materializeValueClassRep[VC <: Product: c.WeakTypeTag, F1: c.WeakTypeTag]: c.Expr[ValueClassLike[VC, F1]] = { + val ValueClass = weakTypeOf[VC] + assertCaseClass(ValueClass, s"To materialize value class representation, ${ValueClass.typeSymbol} must be a value class") + + ValueClass match { + case Product1(_1) => c.Expr[ValueClassLike[VC, F1]](materializeRep1(ValueClass, _1)) + case _ => c.abort(c.enclosingPosition, "To materialize ValueClassLike, case class must have arity == 1") + } + } + + private def materializeRep1(caseClassType: Type, caseAccessor: MethodSymbol) = { + val f1 = resultType(caseAccessor, caseClassType) + + val unapplyF = q"_.$caseAccessor" + val applyF = apply(caseClassType) + + q"new _root_.pl.iterators.kebs.core.macros.ValueClassLike[$caseClassType, $f1]($applyF, $unapplyF)" + } +} diff --git a/core/src/main/scala-2/pl/iterators/kebs/macros/namingconventions/SnakifyVariant.scala b/core/src/main/scala-2/pl/iterators/kebs/core/macros/namingconventions/SnakifyVariant.scala similarity index 89% rename from core/src/main/scala-2/pl/iterators/kebs/macros/namingconventions/SnakifyVariant.scala rename to core/src/main/scala-2/pl/iterators/kebs/core/macros/namingconventions/SnakifyVariant.scala index 9550b6c2..5c2d0a70 100644 --- a/core/src/main/scala-2/pl/iterators/kebs/macros/namingconventions/SnakifyVariant.scala +++ b/core/src/main/scala-2/pl/iterators/kebs/core/macros/namingconventions/SnakifyVariant.scala @@ -1,4 +1,4 @@ -package pl.iterators.kebs.macros.namingconventions +package pl.iterators.kebs.core.macros.namingconventions object SnakifyVariant { private val PASS_1 = """([A-Z\d]+)([A-Z][a-z])""".r diff --git a/core/src/main/scala-2/pl/iterators/kebs/core/support/EquivSupport.scala b/core/src/main/scala-2/pl/iterators/kebs/core/support/EquivSupport.scala new file mode 100644 index 00000000..aefd4527 --- /dev/null +++ b/core/src/main/scala-2/pl/iterators/kebs/core/support/EquivSupport.scala @@ -0,0 +1,10 @@ +package pl.iterators.kebs.core.support + +import pl.iterators.kebs.core.macros.ValueClassLike + +trait EquivSupport { + + implicit def equivFromValueClassLike[A, Rep](implicit vcLike: ValueClassLike[A, Rep], equivRep: Equiv[Rep]): Equiv[A] = + (x: A, y: A) => equivRep.equiv(vcLike.unapply(x), vcLike.unapply(y)) + +} diff --git a/core/src/main/scala-2/pl/iterators/kebs/core/support/PartialOrderingSupport.scala b/core/src/main/scala-2/pl/iterators/kebs/core/support/PartialOrderingSupport.scala new file mode 100644 index 00000000..51dde933 --- /dev/null +++ b/core/src/main/scala-2/pl/iterators/kebs/core/support/PartialOrderingSupport.scala @@ -0,0 +1,14 @@ +package pl.iterators.kebs.core.support + +import pl.iterators.kebs.core.macros.ValueClassLike + +trait PartialOrderingSupport { + + implicit def partialOrderingFromValueClassLike[A, Rep](implicit vcLike: ValueClassLike[A, Rep], + partialOrderingRep: PartialOrdering[Rep]): PartialOrdering[A] = + new PartialOrdering[A] { + override def tryCompare(x: A, y: A): Option[Int] = partialOrderingRep.tryCompare(vcLike.unapply(x), vcLike.unapply(y)) + override def lteq(x: A, y: A): Boolean = partialOrderingRep.lteq(vcLike.unapply(x), vcLike.unapply(y)) + } + +} diff --git a/core/src/main/scala-2/pl/iterators/kebs/support/package.scala b/core/src/main/scala-2/pl/iterators/kebs/core/support/package.scala similarity index 81% rename from core/src/main/scala-2/pl/iterators/kebs/support/package.scala rename to core/src/main/scala-2/pl/iterators/kebs/core/support/package.scala index 0c41bbdc..e32aaa6f 100644 --- a/core/src/main/scala-2/pl/iterators/kebs/support/package.scala +++ b/core/src/main/scala-2/pl/iterators/kebs/core/support/package.scala @@ -1,3 +1,3 @@ -package pl.iterators.kebs +package pl.iterators.kebs.core package object support extends FractionalSupport with IntegralSupport with NumericSupport with PartialOrderingSupport with EquivSupport diff --git a/core/src/main/scala-2/pl/iterators/kebs/macros/CaseClassReps.scala b/core/src/main/scala-2/pl/iterators/kebs/macros/CaseClassReps.scala deleted file mode 100644 index 1382279b..00000000 --- a/core/src/main/scala-2/pl/iterators/kebs/macros/CaseClassReps.scala +++ /dev/null @@ -1,34 +0,0 @@ -package pl.iterators.kebs.macros - -import scala.language.experimental.macros -import scala.language.higherKinds -import scala.reflect.macros.whitebox - -final class CaseClass1Rep[CC, F1](val apply: F1 => CC, val unapply: CC => F1) - -object CaseClass1Rep { - implicit def repFromCaseClass[CC <: Product, F1]: CaseClass1Rep[CC, F1] = macro CaseClassRepMacros.materializeCaseClass1Rep[CC, F1] -} - -class CaseClassRepMacros(override val c: whitebox.Context) extends MacroUtils { - import c.universe._ - - def materializeCaseClass1Rep[CC <: Product: c.WeakTypeTag, F1: c.WeakTypeTag]: c.Expr[CaseClass1Rep[CC, F1]] = { - val CaseClass = weakTypeOf[CC] - assertCaseClass(CaseClass, s"To materialize case class representation, ${CaseClass.typeSymbol} must be a case class") - - CaseClass match { - case Product1(_1) => c.Expr[CaseClass1Rep[CC, F1]](materializeRep1(CaseClass, _1)) - case _ => c.abort(c.enclosingPosition, "To materialize CaseClass1Rep, case class must have arity == 1") - } - } - - private def materializeRep1(caseClassType: Type, caseAccessor: MethodSymbol) = { - val f1 = resultType(caseAccessor, caseClassType) - - val unapplyF = q"_.$caseAccessor" - val applyF = apply(caseClassType) - - q"new _root_.pl.iterators.kebs.macros.CaseClass1Rep[$caseClassType, $f1]($applyF, $unapplyF)" - } -} diff --git a/core/src/main/scala-2/pl/iterators/kebs/macros/enums/EnumEntryMacros.scala b/core/src/main/scala-2/pl/iterators/kebs/macros/enums/EnumEntryMacros.scala deleted file mode 100644 index 9848362f..00000000 --- a/core/src/main/scala-2/pl/iterators/kebs/macros/enums/EnumEntryMacros.scala +++ /dev/null @@ -1,23 +0,0 @@ -package pl.iterators.kebs.macros.enums - -import enumeratum.{Enum, EnumEntry} - -import scala.language.experimental.macros -import scala.reflect.macros.blackbox - -class EnumOf[E <: EnumEntry](val `enum`: Enum[E]) - -object EnumOf { - implicit def enumOf[E <: EnumEntry]: EnumOf[E] = macro EnumEntryMacros.enumOfImpl[E] -} - -class EnumEntryMacros(override val c: blackbox.Context) extends EnumMacroUtils { - import c.universe._ - - def enumOfImpl[E <: EnumEntry: c.WeakTypeTag]: c.Expr[EnumOf[E]] = { - val EnumEntry = weakTypeOf[E] - assertEnumEntry(EnumEntry, s"${EnumEntry.typeSymbol} must subclass enumeratum.EnumEntry") - - c.Expr[EnumOf[E]](q"new _root_.pl.iterators.kebs.macros.enums.EnumOf(${companion(EnumEntry)})") - } -} diff --git a/core/src/main/scala-2/pl/iterators/kebs/macros/enums/EnumMacroUtils.scala b/core/src/main/scala-2/pl/iterators/kebs/macros/enums/EnumMacroUtils.scala deleted file mode 100644 index 70a2056e..00000000 --- a/core/src/main/scala-2/pl/iterators/kebs/macros/enums/EnumMacroUtils.scala +++ /dev/null @@ -1,17 +0,0 @@ -package pl.iterators.kebs.macros.enums - -import enumeratum.EnumEntry -import enumeratum.values.ValueEnumEntry -import pl.iterators.kebs.macros.MacroUtils - -abstract class EnumMacroUtils extends MacroUtils { - import c.universe._ - - private val EnumEntry = typeOf[EnumEntry] - private val ValueEnumEntry = typeOf[ValueEnumEntry[_]] - - protected def assertEnumEntry(t: Type, msg: => String) = if (!(t <:< EnumEntry)) c.abort(c.enclosingPosition, msg) - protected def assertValueEnumEntry(t: Type, msg: => String) = if (!(t <:< ValueEnumEntry)) c.abort(c.enclosingPosition, msg) - - protected def ValueType(valueEnumEntry: Type) = valueEnumEntry.typeArgs.head -} diff --git a/core/src/main/scala-2/pl/iterators/kebs/macros/enums/ValueEnumEntryMacros.scala b/core/src/main/scala-2/pl/iterators/kebs/macros/enums/ValueEnumEntryMacros.scala deleted file mode 100644 index 4031e75f..00000000 --- a/core/src/main/scala-2/pl/iterators/kebs/macros/enums/ValueEnumEntryMacros.scala +++ /dev/null @@ -1,37 +0,0 @@ -package pl.iterators.kebs.macros.enums - -import enumeratum.values._ - -import scala.language.experimental.macros -import scala.reflect.macros.blackbox - -class ValueEnumOf[ValueType, E <: ValueEnumEntry[ValueType]](val valueEnum: ValueEnum[ValueType, E]) - -object ValueEnumOf { - implicit def intValueEnumOf[E <: IntEnumEntry]: ValueEnumOf[Int, E] = - macro ValueEnumEntryMacros.valueEnumOfImpl[Int, E] - implicit def shortValueEnumOf[E <: ShortEnumEntry]: ValueEnumOf[Short, E] = - macro ValueEnumEntryMacros.valueEnumOfImpl[Short, E] - implicit def longValueEnumOf[E <: LongEnumEntry]: ValueEnumOf[Long, E] = - macro ValueEnumEntryMacros.valueEnumOfImpl[Long, E] - implicit def byteValueEnumOf[E <: ByteEnumEntry]: ValueEnumOf[Byte, E] = - macro ValueEnumEntryMacros.valueEnumOfImpl[Byte, E] - implicit def stringValueEnumOf[E <: StringEnumEntry]: ValueEnumOf[String, E] = - macro ValueEnumEntryMacros.valueEnumOfImpl[String, E] -} - -/** - * this needs to be whitebox because macro needs to deduce `ValueType` type param - */ -class ValueEnumEntryMacros(override val c: blackbox.Context) extends EnumMacroUtils { - import c.universe._ - - def valueEnumOfImpl[ValueType: c.WeakTypeTag, E <: ValueEnumEntry[ValueType]: c.WeakTypeTag]: c.Expr[ValueEnumOf[ValueType, E]] = { - val EnumEntry = weakTypeOf[E] - assertValueEnumEntry(EnumEntry, s"${EnumEntry.typeSymbol} must subclass enumeratum.values.ValueEnumEntry") - - val ValueType = weakTypeOf[ValueType] - c.Expr[ValueEnumOf[ValueType, E]]( - q"new _root_.pl.iterators.kebs.macros.enums.ValueEnumOf[$ValueType, $EnumEntry](${companion(EnumEntry)})") - } -} diff --git a/core/src/main/scala-2/pl/iterators/kebs/support/EquivSupport.scala b/core/src/main/scala-2/pl/iterators/kebs/support/EquivSupport.scala deleted file mode 100644 index ed316fbe..00000000 --- a/core/src/main/scala-2/pl/iterators/kebs/support/EquivSupport.scala +++ /dev/null @@ -1,10 +0,0 @@ -package pl.iterators.kebs.support - -import pl.iterators.kebs.macros.CaseClass1Rep - -trait EquivSupport { - - implicit def equivFromCaseClass1Rep[A, Rep](implicit cc1Rep: CaseClass1Rep[A, Rep], equivRep: Equiv[Rep]): Equiv[A] = - (x: A, y: A) => equivRep.equiv(cc1Rep.unapply(x), cc1Rep.unapply(y)) - -} diff --git a/core/src/main/scala-2/pl/iterators/kebs/support/PartialOrderingSupport.scala b/core/src/main/scala-2/pl/iterators/kebs/support/PartialOrderingSupport.scala deleted file mode 100644 index 20764fee..00000000 --- a/core/src/main/scala-2/pl/iterators/kebs/support/PartialOrderingSupport.scala +++ /dev/null @@ -1,14 +0,0 @@ -package pl.iterators.kebs.support - -import pl.iterators.kebs.macros.CaseClass1Rep - -trait PartialOrderingSupport { - - implicit def partialOrderingFromCaseClass1Rep[A, Rep](implicit cc1Rep: CaseClass1Rep[A, Rep], - partialOrderingRep: PartialOrdering[Rep]): PartialOrdering[A] = - new PartialOrdering[A] { - override def tryCompare(x: A, y: A): Option[Int] = partialOrderingRep.tryCompare(cc1Rep.unapply(x), cc1Rep.unapply(y)) - override def lteq(x: A, y: A): Boolean = partialOrderingRep.lteq(cc1Rep.unapply(x), cc1Rep.unapply(y)) - } - -} diff --git a/core/src/main/scala-3/pl/iterators/kebs/core/macros/ValueClassReps.scala b/core/src/main/scala-3/pl/iterators/kebs/core/macros/ValueClassReps.scala new file mode 100644 index 00000000..526bfd9d --- /dev/null +++ b/core/src/main/scala-3/pl/iterators/kebs/core/macros/ValueClassReps.scala @@ -0,0 +1,12 @@ +package pl.iterators.kebs.core.macros + +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] = { + new ValueClassLike[T, F1](f1 => m.fromProduct(Tuple1(f1)), _.productElement(0).asInstanceOf[F1]) + } +} +object CaseClass1ToValueClass extends CaseClass1ToValueClass \ No newline at end of file diff --git a/core/src/main/scala-3/pl/iterators/kebs/core/support/EquivSupport.scala b/core/src/main/scala-3/pl/iterators/kebs/core/support/EquivSupport.scala new file mode 100644 index 00000000..aefd4527 --- /dev/null +++ b/core/src/main/scala-3/pl/iterators/kebs/core/support/EquivSupport.scala @@ -0,0 +1,10 @@ +package pl.iterators.kebs.core.support + +import pl.iterators.kebs.core.macros.ValueClassLike + +trait EquivSupport { + + implicit def equivFromValueClassLike[A, Rep](implicit vcLike: ValueClassLike[A, Rep], equivRep: Equiv[Rep]): Equiv[A] = + (x: A, y: A) => equivRep.equiv(vcLike.unapply(x), vcLike.unapply(y)) + +} diff --git a/core/src/main/scala-2.13/pl/iterators/kebs/support/FractionalSupport.scala b/core/src/main/scala-3/pl/iterators/kebs/core/support/FractionalSupport.scala similarity index 77% rename from core/src/main/scala-2.13/pl/iterators/kebs/support/FractionalSupport.scala rename to core/src/main/scala-3/pl/iterators/kebs/core/support/FractionalSupport.scala index 45f64b50..3e04be80 100644 --- a/core/src/main/scala-2.13/pl/iterators/kebs/support/FractionalSupport.scala +++ b/core/src/main/scala-3/pl/iterators/kebs/core/support/FractionalSupport.scala @@ -1,14 +1,14 @@ -package pl.iterators.kebs.support +package pl.iterators.kebs.core.support -import pl.iterators.kebs.macros.CaseClass1Rep +import pl.iterators.kebs.core.macros.ValueClassLike trait FractionalSupport { - implicit def fractionalFromCaseClass1Rep[A, Rep](implicit cc1Rep: CaseClass1Rep[A, Rep], + implicit def fractionalFromValueClassLike[A, Rep](implicit vcLike: ValueClassLike[A, Rep], fractionalRep: Fractional[Rep], numeric: Numeric[A]): Fractional[A] = new Fractional[A] { - override def div(x: A, y: A): A = cc1Rep.apply(fractionalRep.div(cc1Rep.unapply(x), cc1Rep.unapply(y))) + override def div(x: A, y: A): A = vcLike.apply(fractionalRep.div(vcLike.unapply(x), vcLike.unapply(y))) override def plus(x: A, y: A): A = numeric.plus(x, y) override def minus(x: A, y: A): A = numeric.minus(x, y) override def times(x: A, y: A): A = numeric.times(x, y) diff --git a/core/src/main/scala-3/pl/iterators/kebs/support/IntegralSupport.scala b/core/src/main/scala-3/pl/iterators/kebs/core/support/IntegralSupport.scala similarity index 71% rename from core/src/main/scala-3/pl/iterators/kebs/support/IntegralSupport.scala rename to core/src/main/scala-3/pl/iterators/kebs/core/support/IntegralSupport.scala index 3fc592bb..a301d026 100644 --- a/core/src/main/scala-3/pl/iterators/kebs/support/IntegralSupport.scala +++ b/core/src/main/scala-3/pl/iterators/kebs/core/support/IntegralSupport.scala @@ -1,15 +1,15 @@ -package pl.iterators.kebs.support +package pl.iterators.kebs.core.support -import pl.iterators.kebs.macros.CaseClass1Rep +import pl.iterators.kebs.core.macros.ValueClassLike trait IntegralSupport { - implicit def integralFromCaseClass1Rep[A, Rep](implicit cc1Rep: CaseClass1Rep[A, Rep], + implicit def integralFromValueClassLike[A, Rep](implicit vcLike: ValueClassLike[A, Rep], integralRep: Integral[Rep], numeric: Numeric[A]): Integral[A] = new Integral[A] { - override def quot(x: A, y: A): A = cc1Rep.apply(integralRep.quot(cc1Rep.unapply(x), cc1Rep.unapply(y))) - override def rem(x: A, y: A): A = cc1Rep.apply(integralRep.rem(cc1Rep.unapply(x), cc1Rep.unapply(y))) + override def quot(x: A, y: A): A = vcLike.apply(integralRep.quot(vcLike.unapply(x), vcLike.unapply(y))) + override def rem(x: A, y: A): A = vcLike.apply(integralRep.rem(vcLike.unapply(x), vcLike.unapply(y))) override def plus(x: A, y: A): A = numeric.plus(x, y) override def minus(x: A, y: A): A = numeric.minus(x, y) override def times(x: A, y: A): A = numeric.times(x, y) diff --git a/core/src/main/scala-3/pl/iterators/kebs/core/support/NumericSupport.scala b/core/src/main/scala-3/pl/iterators/kebs/core/support/NumericSupport.scala new file mode 100644 index 00000000..35ce1bab --- /dev/null +++ b/core/src/main/scala-3/pl/iterators/kebs/core/support/NumericSupport.scala @@ -0,0 +1,23 @@ +package pl.iterators.kebs.core.support + +import pl.iterators.kebs.core.macros.ValueClassLike + +trait NumericSupport { + + implicit def numericFromValueClassLike[A, Rep](implicit vcLike: ValueClassLike[A, Rep], numericRep: Numeric[Rep]): Numeric[A] = { + new Numeric[A] { + override def plus(x: A, y: A): A = vcLike.apply(numericRep.plus(vcLike.unapply(x), vcLike.unapply(y))) + override def minus(x: A, y: A): A = vcLike.apply(numericRep.minus(vcLike.unapply(x), vcLike.unapply(y))) + override def times(x: A, y: A): A = vcLike.apply(numericRep.times(vcLike.unapply(x), vcLike.unapply(y))) + override def negate(x: A): A = vcLike.apply(numericRep.negate(vcLike.unapply(x))) + override def fromInt(x: Int): A = vcLike.apply(numericRep.fromInt(x)) + override def toInt(x: A): Int = numericRep.toInt(vcLike.unapply(x)) + override def toLong(x: A): Long = numericRep.toLong(vcLike.unapply(x)) + override def toFloat(x: A): Float = numericRep.toFloat(vcLike.unapply(x)) + override def toDouble(x: A): Double = numericRep.toDouble(vcLike.unapply(x)) + override def compare(x: A, y: A): Int = numericRep.compare(vcLike.unapply(x), vcLike.unapply(y)) + override def parseString(str: String): Option[A] = numericRep.parseString(str).map(vcLike.apply) + } + } + +} diff --git a/core/src/main/scala-3/pl/iterators/kebs/core/support/PartialOrderingSupport.scala b/core/src/main/scala-3/pl/iterators/kebs/core/support/PartialOrderingSupport.scala new file mode 100644 index 00000000..51dde933 --- /dev/null +++ b/core/src/main/scala-3/pl/iterators/kebs/core/support/PartialOrderingSupport.scala @@ -0,0 +1,14 @@ +package pl.iterators.kebs.core.support + +import pl.iterators.kebs.core.macros.ValueClassLike + +trait PartialOrderingSupport { + + implicit def partialOrderingFromValueClassLike[A, Rep](implicit vcLike: ValueClassLike[A, Rep], + partialOrderingRep: PartialOrdering[Rep]): PartialOrdering[A] = + new PartialOrdering[A] { + override def tryCompare(x: A, y: A): Option[Int] = partialOrderingRep.tryCompare(vcLike.unapply(x), vcLike.unapply(y)) + override def lteq(x: A, y: A): Boolean = partialOrderingRep.lteq(vcLike.unapply(x), vcLike.unapply(y)) + } + +} diff --git a/core/src/main/scala-3/pl/iterators/kebs/support/package.scala b/core/src/main/scala-3/pl/iterators/kebs/core/support/package.scala similarity index 81% rename from core/src/main/scala-3/pl/iterators/kebs/support/package.scala rename to core/src/main/scala-3/pl/iterators/kebs/core/support/package.scala index 0c41bbdc..e32aaa6f 100644 --- a/core/src/main/scala-3/pl/iterators/kebs/support/package.scala +++ b/core/src/main/scala-3/pl/iterators/kebs/core/support/package.scala @@ -1,3 +1,3 @@ -package pl.iterators.kebs +package pl.iterators.kebs.core package object support extends FractionalSupport with IntegralSupport with NumericSupport with PartialOrderingSupport with EquivSupport diff --git a/core/src/main/scala-3/pl/iterators/kebs/macros/CaseClassReps.scala b/core/src/main/scala-3/pl/iterators/kebs/macros/CaseClassReps.scala deleted file mode 100644 index acfcde40..00000000 --- a/core/src/main/scala-3/pl/iterators/kebs/macros/CaseClassReps.scala +++ /dev/null @@ -1,11 +0,0 @@ -package pl.iterators.kebs.macros - -import scala.deriving.Mirror - -final class CaseClass1Rep[CC, F1](val apply: F1 => CC, val unapply: CC => F1) - -object CaseClass1Rep { - inline given[T <: Product, F1](using m: Mirror.ProductOf[T], teq: m.MirroredElemTypes =:= F1 *: EmptyTuple.type): CaseClass1Rep[T, F1] = { - new CaseClass1Rep[T, F1](f1 => m.fromProduct(Tuple1(f1)), _.productElement(0).asInstanceOf[F1]) - } -} \ No newline at end of file diff --git a/core/src/main/scala-3/pl/iterators/kebs/macros/enums/EnumEntryMacros.scala b/core/src/main/scala-3/pl/iterators/kebs/macros/enums/EnumEntryMacros.scala deleted file mode 100644 index 536cc8df..00000000 --- a/core/src/main/scala-3/pl/iterators/kebs/macros/enums/EnumEntryMacros.scala +++ /dev/null @@ -1,70 +0,0 @@ -package pl.iterators.kebs.macros.enums - -import pl.iterators.kebs.enums.ValueEnum -import scala.quoted._ -import scala.compiletime.{constValue, erasedValue, error, summonInline} -import scala.deriving.Mirror -import scala.reflect.{ClassTag, Enum} - -trait EnumLike[T] { - def values: Array[T] - def valueOf(name: String): T = values.find(_.toString == name).getOrElse(throw new IllegalArgumentException(s"enum case not found: $name")) - def fromOrdinal(ordinal: Int): T = values.lift(ordinal).getOrElse(throw new NoSuchElementException(ordinal.toString)) -} - -class EnumOf[E](val `enum`: EnumLike[E]) - -inline private def widen[A, B] (a: A): A & B = - inline a match { - case b: B => b - } - -object EnumOf { - inline given [E <: Enum](using m: Mirror.SumOf[E], ct: ClassTag[E]): EnumOf[E] = { - val enumValues = summonCases[m.MirroredElemTypes, E] - EnumOf[E](new EnumLike[E] { - override def values: Array[E] = enumValues.toArray - }) - } - - inline private def summonCases[T <: Tuple, A]: List[A] = - inline erasedValue[T] match { - case _: (h *: t) => - (inline summonInline[Mirror.Of[h]] match { - case m: Mirror.Singleton => - widen[m.MirroredMonoType, A](m.fromProduct(EmptyTuple)) :: summonCases[t, A] - case x => error("Enums cannot include parameterized cases.") - }) - - case _: EmptyTuple => Nil - } -} - -trait ValueEnumLike[ValueType, T <: ValueEnum[ValueType]] { - def values: Array[T] - def valueOf(value: ValueType): T = values.find(_.value == value).getOrElse(throw new IllegalArgumentException(s"enum case not found: $value")) - def fromOrdinal(ordinal: Int): T = values.lift(ordinal).getOrElse(throw new NoSuchElementException(ordinal.toString)) -} - -class ValueEnumOf[V, E <: ValueEnum[V]](val `enum`: ValueEnumLike[V, E]) - -object ValueEnumOf { - inline given [V, E <: ValueEnum[V] with Enum](using m: Mirror.SumOf[E], ct: ClassTag[E]): ValueEnumOf[V, E] = { - val enumValues = summonValueCases[m.MirroredElemTypes, V, E] - ValueEnumOf[V, E](new ValueEnumLike[V, E] { - override def values: Array[E] = enumValues.toArray - }) - } - - inline private def summonValueCases[T <: Tuple, V, A <: ValueEnum[V]]: List[A] = - inline erasedValue[T] match { - case _: (h *: t) => - (inline summonInline[Mirror.Of[h]] match { - case m: Mirror.Singleton => - widen[m.MirroredMonoType, A](m.fromProduct(EmptyTuple)) :: summonValueCases[t, V, A] - case x => error("Enums cannot include parameterized cases.") - }) - - case _: EmptyTuple => Nil - } -} \ No newline at end of file diff --git a/core/src/main/scala-3/pl/iterators/kebs/macros/enums/ValueEnum.scala b/core/src/main/scala-3/pl/iterators/kebs/macros/enums/ValueEnum.scala deleted file mode 100644 index 802cd69d..00000000 --- a/core/src/main/scala-3/pl/iterators/kebs/macros/enums/ValueEnum.scala +++ /dev/null @@ -1,6 +0,0 @@ - -package pl.iterators.kebs.enums - -trait ValueEnum[ValueType] { - def value: ValueType -} \ No newline at end of file diff --git a/core/src/main/scala-3/pl/iterators/kebs/support/EquivSupport.scala b/core/src/main/scala-3/pl/iterators/kebs/support/EquivSupport.scala deleted file mode 100644 index ed316fbe..00000000 --- a/core/src/main/scala-3/pl/iterators/kebs/support/EquivSupport.scala +++ /dev/null @@ -1,10 +0,0 @@ -package pl.iterators.kebs.support - -import pl.iterators.kebs.macros.CaseClass1Rep - -trait EquivSupport { - - implicit def equivFromCaseClass1Rep[A, Rep](implicit cc1Rep: CaseClass1Rep[A, Rep], equivRep: Equiv[Rep]): Equiv[A] = - (x: A, y: A) => equivRep.equiv(cc1Rep.unapply(x), cc1Rep.unapply(y)) - -} diff --git a/core/src/main/scala-3/pl/iterators/kebs/support/NumericSupport.scala b/core/src/main/scala-3/pl/iterators/kebs/support/NumericSupport.scala deleted file mode 100644 index 27d4c234..00000000 --- a/core/src/main/scala-3/pl/iterators/kebs/support/NumericSupport.scala +++ /dev/null @@ -1,23 +0,0 @@ -package pl.iterators.kebs.support - -import pl.iterators.kebs.macros.CaseClass1Rep - -trait NumericSupport { - - implicit def numericFromCaseClass1Rep[A, Rep](implicit cc1Rep: CaseClass1Rep[A, Rep], numericRep: Numeric[Rep]): Numeric[A] = { - new Numeric[A] { - override def plus(x: A, y: A): A = cc1Rep.apply(numericRep.plus(cc1Rep.unapply(x), cc1Rep.unapply(y))) - override def minus(x: A, y: A): A = cc1Rep.apply(numericRep.minus(cc1Rep.unapply(x), cc1Rep.unapply(y))) - override def times(x: A, y: A): A = cc1Rep.apply(numericRep.times(cc1Rep.unapply(x), cc1Rep.unapply(y))) - override def negate(x: A): A = cc1Rep.apply(numericRep.negate(cc1Rep.unapply(x))) - override def fromInt(x: Int): A = cc1Rep.apply(numericRep.fromInt(x)) - override def toInt(x: A): Int = numericRep.toInt(cc1Rep.unapply(x)) - override def toLong(x: A): Long = numericRep.toLong(cc1Rep.unapply(x)) - override def toFloat(x: A): Float = numericRep.toFloat(cc1Rep.unapply(x)) - override def toDouble(x: A): Double = numericRep.toDouble(cc1Rep.unapply(x)) - override def compare(x: A, y: A): Int = numericRep.compare(cc1Rep.unapply(x), cc1Rep.unapply(y)) - override def parseString(str: String): Option[A] = numericRep.parseString(str).map(cc1Rep.apply) - } - } - -} diff --git a/core/src/main/scala-3/pl/iterators/kebs/support/PartialOrderingSupport.scala b/core/src/main/scala-3/pl/iterators/kebs/support/PartialOrderingSupport.scala deleted file mode 100644 index 20764fee..00000000 --- a/core/src/main/scala-3/pl/iterators/kebs/support/PartialOrderingSupport.scala +++ /dev/null @@ -1,14 +0,0 @@ -package pl.iterators.kebs.support - -import pl.iterators.kebs.macros.CaseClass1Rep - -trait PartialOrderingSupport { - - implicit def partialOrderingFromCaseClass1Rep[A, Rep](implicit cc1Rep: CaseClass1Rep[A, Rep], - partialOrderingRep: PartialOrdering[Rep]): PartialOrdering[A] = - new PartialOrdering[A] { - override def tryCompare(x: A, y: A): Option[Int] = partialOrderingRep.tryCompare(cc1Rep.unapply(x), cc1Rep.unapply(y)) - override def lteq(x: A, y: A): Boolean = partialOrderingRep.lteq(cc1Rep.unapply(x), cc1Rep.unapply(y)) - } - -} diff --git a/core/src/main/scala/pl/iterators/kebs/core/enums/EnumLike.scala b/core/src/main/scala/pl/iterators/kebs/core/enums/EnumLike.scala new file mode 100644 index 00000000..1fa08263 --- /dev/null +++ b/core/src/main/scala/pl/iterators/kebs/core/enums/EnumLike.scala @@ -0,0 +1,29 @@ +package pl.iterators.kebs.core.enums + +import scala.collection.immutable + +trait EnumLike[T] { + def values: immutable.Seq[T] + def getNamesToValuesMap: Map[String, T] = EnumLike.namesToValuesMap(this) + def withNameOption(name: String): Option[T] = EnumLike.namesToValuesMap(this).get(name) + def withNameUppercaseOnlyOption(name: String): Option[T] = EnumLike.upperCaseNameValuesToMap(this).get(name) + def withNameInsensitiveOption(name: String): Option[T] = EnumLike.lowerCaseNamesToValuesMap(this).get(name.toLowerCase) + def withNameLowercaseOnlyOption(name: String): Option[T] = EnumLike.lowerCaseNamesToValuesMap(this).get(name) + def withNameUppercaseOnly(name: String): T = withNameUppercaseOnlyOption(name).getOrElse(throw new NoSuchElementException(EnumLike.buildNotFoundMessage(name, this))) + def withNameLowercaseOnly(name: String): T = withNameLowercaseOnlyOption(name).getOrElse(throw new NoSuchElementException(EnumLike.buildNotFoundMessage(name, this))) + def withName(name: String): T = withNameOption(name).getOrElse(throw new NoSuchElementException(EnumLike.buildNotFoundMessage(name, this))) + def valueOf(name: String): T = values.find(_.toString == name).getOrElse(throw new IllegalArgumentException(s"enum case not found: $name")) + def valueOfIgnoreCase(name: String): T = values.find(_.toString.equalsIgnoreCase(name)).getOrElse(throw new IllegalArgumentException(s"enum case not found: $name")) + def withNameIgnoreCase(name: String): T = values.find(_.toString.equalsIgnoreCase((name))).get + def withNameIgnoreCaseOption(name: String): Option[T] = values.find(_.toString.equalsIgnoreCase((name))) + def fromOrdinal(ordinal: Int): T = values.lift(ordinal).getOrElse(throw new NoSuchElementException(ordinal.toString)) + def indexOf(member: T): Int = values.zipWithIndex.toMap.getOrElse(member, -1) +} + +private[core] object EnumLike { + private def namesToValuesMap[T](`enum`: EnumLike[T]): Map[String, T] = `enum`.values.map(v => v.toString -> v).toMap + private def upperCaseNameValuesToMap[T](`enum`: EnumLike[T]): Map[String, T] = namesToValuesMap(`enum`).map { case (k, v) => k.toUpperCase() -> v } + private def lowerCaseNamesToValuesMap[T](`enum`: EnumLike[T]): Map[String, T] = namesToValuesMap(`enum`).map { case (k, v) => k.toLowerCase() -> v } + private def existingEntriesString[T](`enum`: EnumLike[T]): String = `enum`.values.map(_.toString).mkString(", ") + private def buildNotFoundMessage[T](notFoundName: String, `enum`: EnumLike[T]): String = s"$notFoundName is not a member of Enum (${existingEntriesString(`enum`)})" +} diff --git a/core/src/main/scala/pl/iterators/kebs/core/enums/ValueEnumLike.scala b/core/src/main/scala/pl/iterators/kebs/core/enums/ValueEnumLike.scala new file mode 100644 index 00000000..dcabf606 --- /dev/null +++ b/core/src/main/scala/pl/iterators/kebs/core/enums/ValueEnumLike.scala @@ -0,0 +1,25 @@ +package pl.iterators.kebs.core.enums + +import scala.collection.immutable + +trait ValueEnumLikeEntry[ValueType] { + def value: ValueType +} + + +trait ValueEnumLike[ValueType, EntryType <: ValueEnumLikeEntry[ValueType]] { + def values: immutable.Seq[EntryType] + def getValuesToEntriesMap: Map[ValueType, EntryType] = ValueEnumLike.valuesToEntriesMap(this) + def withValue(i: ValueType): EntryType = withValueOption(i).getOrElse(throw new NoSuchElementException(ValueEnumLike.buildNotFoundMessage(this, i))) + def withValueOption(i: ValueType): Option[EntryType] = ValueEnumLike.valuesToEntriesMap(this).get(i) + def valueOf(value: ValueType): EntryType = values.find(entry => value == entry.value).getOrElse(throw new IllegalArgumentException(s"enum case not found: $value")) + def valueOfOption(value: ValueType): Option[EntryType] = values.find(entry => value == entry.value) + def fromOrdinal(ordinal: Int): EntryType = values.lift(ordinal).getOrElse(throw new NoSuchElementException(ordinal.toString)) + def indexOf(member: EntryType): Int = values.zipWithIndex.find { case (entry, _) => member == entry }.map { case (_, index) => index }.getOrElse(-1) +} + +private[core] object ValueEnumLike { + private def valuesToEntriesMap[ValueType, EntryType <: ValueEnumLikeEntry[ValueType]](`enum`: ValueEnumLike[ValueType, EntryType]): Map[ValueType, EntryType] = `enum`.values.map(v => v.value -> v).toMap + private def existingEntriesString[ValueType, EntryType <: ValueEnumLikeEntry[ValueType]](`enum`: ValueEnumLike[ValueType, EntryType]): String = `enum`.values.map(_.value).mkString(", ") + private def buildNotFoundMessage[ValueType, EntryType <: ValueEnumLikeEntry[ValueType]](`enum`: ValueEnumLike[ValueType, EntryType], i: ValueType): String = s"${i.toString} is not a member of ValueEnum (${existingEntriesString(`enum`)})" +} diff --git a/core/src/main/scala/pl/iterators/kebs/instances/InstanceConverter.scala b/core/src/main/scala/pl/iterators/kebs/core/instances/InstanceConverter.scala similarity index 96% rename from core/src/main/scala/pl/iterators/kebs/instances/InstanceConverter.scala rename to core/src/main/scala/pl/iterators/kebs/core/instances/InstanceConverter.scala index cd8e97d8..05816321 100644 --- a/core/src/main/scala/pl/iterators/kebs/instances/InstanceConverter.scala +++ b/core/src/main/scala/pl/iterators/kebs/core/instances/InstanceConverter.scala @@ -1,4 +1,4 @@ -package pl.iterators.kebs.instances +package pl.iterators.kebs.core.instances import scala.reflect.{ClassTag, classTag} import scala.util.control.NonFatal diff --git a/core/src/test/scala-3/DerivingSpecification.scala b/core/src/test/scala-3/DerivingSpecification.scala deleted file mode 100644 index fdfa3b7b..00000000 --- a/core/src/test/scala-3/DerivingSpecification.scala +++ /dev/null @@ -1,34 +0,0 @@ -import org.scalacheck.Prop.forAll -import org.scalacheck.{Gen, Properties} -import pl.iterators.kebs.macros.CaseClass1Rep -import pl.iterators.kebs.macros.enums.{EnumOf, ValueEnumOf} -import pl.iterators.kebs.enums.ValueEnum - -object DerivingSpecification extends Properties("Deriving") { - case class CC1Ex(whatever: String) - - property("CaseClass1Rep derives properly from 1-element case class") = forAll { (stringValue: String) => - val tc = implicitly[CaseClass1Rep[CC1Ex, String]] - tc.apply(stringValue) == CC1Ex(stringValue) && tc.unapply(CC1Ex(stringValue)) == stringValue - } - - enum Color { - case Red, Green, Blue - } - - property("EnumOf derives properly for an enum") = forAll(Gen.oneOf(Color.values.toList)) { (color: Color) => - val tc = implicitly[EnumOf[Color]] - tc.`enum`.values.contains(color) && tc.`enum`.valueOf(color.toString) == color && tc.`enum`.fromOrdinal(color.ordinal) == color - } - - enum ColorButRGB(val value: Int) extends ValueEnum[Int] { - case Red extends ColorButRGB(0xFF0000) - case Green extends ColorButRGB(0x00FF00) - case Blue extends ColorButRGB(0x0000FF) - } - - property("ValueEnumOf derives properly for an enum") = forAll(Gen.oneOf(ColorButRGB.values.toList)) { (color: ColorButRGB) => - val tc = implicitly[ValueEnumOf[Int, ColorButRGB]] - tc.`enum`.values.contains(color) && tc.`enum`.valueOf(color.value) == color && tc.`enum`.fromOrdinal(color.ordinal) == color - } -} diff --git a/core/src/test/scala/NumbersDomain.scala b/core/src/test/scala/NumbersDomain.scala deleted file mode 100644 index 1237c1d3..00000000 --- a/core/src/test/scala/NumbersDomain.scala +++ /dev/null @@ -1,36 +0,0 @@ -import pl.iterators.kebs.macros.CaseClass1Rep - -object NumbersDomain { - - trait Tag1 - type TaggedBigDecimal = BigDecimal with Tag1 - object TaggedBigDecimal { - def apply(value: BigDecimal): TaggedBigDecimal = value.asInstanceOf[TaggedBigDecimal] - } - object Tag1 { - implicit val TaggedBigDecimalCaseClass1Rep: CaseClass1Rep[TaggedBigDecimal, BigDecimal] = - new CaseClass1Rep[TaggedBigDecimal, BigDecimal](TaggedBigDecimal.apply, identity) - } - - case class BoxedBigDecimal(value: BigDecimal) - object BoxedBigDecimal { - implicit val BoxedBigDecimalCaseClass1Rep: CaseClass1Rep[BoxedBigDecimal, BigDecimal] = - new CaseClass1Rep[BoxedBigDecimal, BigDecimal](BoxedBigDecimal.apply, _.value) - } - - trait Tag2 - type TaggedInt = Int with Tag2 - object TaggedInt { - def apply(value: Int): TaggedInt = value.asInstanceOf[TaggedInt] - } - object Tag2 { - implicit val TaggedIntCaseClass1Rep: CaseClass1Rep[TaggedInt, Int] = - new CaseClass1Rep[TaggedInt, Int](TaggedInt.apply, identity) - } - - case class BoxedInt(value: Int) - object BoxedInt { - implicit val BoxedIntCaseClass1Rep: CaseClass1Rep[BoxedInt, Int] = - new CaseClass1Rep[BoxedInt, Int](BoxedInt.apply, _.value) - } -} diff --git a/core/src/test/scala/StringsDomain.scala b/core/src/test/scala/StringsDomain.scala deleted file mode 100644 index 4d761ee1..00000000 --- a/core/src/test/scala/StringsDomain.scala +++ /dev/null @@ -1,19 +0,0 @@ -import pl.iterators.kebs.macros.CaseClass1Rep - -object StringsDomain { - trait Tag1 - type TaggedString = String with Tag1 - object TaggedString { - def apply(value: String): TaggedString = value.asInstanceOf[TaggedString] - } - object Tag1 { - implicit val TaggedStringCaseClass1Rep: CaseClass1Rep[TaggedString, String] = - new CaseClass1Rep[TaggedString, String](TaggedString.apply, identity) - } - - case class BoxedString(value: String) - object BoxedString { - implicit val BoxedStringCaseClass1Rep: CaseClass1Rep[BoxedString, String] = - new CaseClass1Rep[BoxedString, String](BoxedString.apply, _.value) - } -} diff --git a/core/src/test/scala/pl/iterators/kebs/core/DerivingSpecification.scala b/core/src/test/scala/pl/iterators/kebs/core/DerivingSpecification.scala new file mode 100644 index 00000000..536304d5 --- /dev/null +++ b/core/src/test/scala/pl/iterators/kebs/core/DerivingSpecification.scala @@ -0,0 +1,14 @@ +package pl.iterators.kebs.core + +import org.scalacheck.Prop.forAll +import org.scalacheck.Properties +import pl.iterators.kebs.core.macros.{CaseClass1ToValueClass, ValueClassLike} + +object DerivingSpecification extends Properties("Deriving") with CaseClass1ToValueClass { + case class CC1Ex(whatever: String) + + property("ValueClassLike derives properly from 1-element case class") = forAll { (stringValue: String) => + val tc = implicitly[ValueClassLike[CC1Ex, String]] + tc.apply(stringValue) == CC1Ex(stringValue) && tc.unapply(CC1Ex(stringValue)) == stringValue + } +} diff --git a/core/src/test/scala/EquivSupportSpecification.scala b/core/src/test/scala/pl/iterators/kebs/core/EquivSupportSpecification.scala similarity index 97% rename from core/src/test/scala/EquivSupportSpecification.scala rename to core/src/test/scala/pl/iterators/kebs/core/EquivSupportSpecification.scala index c7cd36d2..f45ef123 100644 --- a/core/src/test/scala/EquivSupportSpecification.scala +++ b/core/src/test/scala/pl/iterators/kebs/core/EquivSupportSpecification.scala @@ -1,10 +1,12 @@ +package pl.iterators.kebs.core + import org.scalacheck.Prop.forAll import org.scalacheck.Properties object EquivSupportSpecification extends Properties("EquivSupport") { import StringsDomain._ - import pl.iterators.kebs.support._ + import support._ private def isScalaJS = System.getProperty("java.vm.name") == "Scala.js" diff --git a/core/src/test/scala/FractionalSupportSpecification.scala b/core/src/test/scala/pl/iterators/kebs/core/FractionalSupportSpecification.scala similarity index 96% rename from core/src/test/scala/FractionalSupportSpecification.scala rename to core/src/test/scala/pl/iterators/kebs/core/FractionalSupportSpecification.scala index 16548dec..4fe2aad8 100644 --- a/core/src/test/scala/FractionalSupportSpecification.scala +++ b/core/src/test/scala/pl/iterators/kebs/core/FractionalSupportSpecification.scala @@ -1,3 +1,5 @@ +package pl.iterators.kebs.core + import org.scalacheck.Prop.forAll import org.scalacheck.{Arbitrary, Properties} @@ -6,7 +8,7 @@ object FractionalSupportSpecification extends Properties("FractionalSupport") { private val nonZeroBigDecimal = Arbitrary.arbitrary[BigDecimal] suchThat (_ != 0) import NumbersDomain._ - import pl.iterators.kebs.support._ + import support._ private def divide[A: Fractional](f1: A, f2: A): Option[A] = { import Fractional.Implicits._ diff --git a/core/src/test/scala/IntegralSupportSpecification.scala b/core/src/test/scala/pl/iterators/kebs/core/IntegralSupportSpecification.scala similarity index 94% rename from core/src/test/scala/IntegralSupportSpecification.scala rename to core/src/test/scala/pl/iterators/kebs/core/IntegralSupportSpecification.scala index 2cd52ba1..b878c9d5 100644 --- a/core/src/test/scala/IntegralSupportSpecification.scala +++ b/core/src/test/scala/pl/iterators/kebs/core/IntegralSupportSpecification.scala @@ -1,3 +1,5 @@ +package pl.iterators.kebs.core + import org.scalacheck.Prop.forAll import org.scalacheck.{Arbitrary, Properties} @@ -6,7 +8,7 @@ object IntegralSupportSpecification extends Properties("IntegralSupport") { private val nonZeroInt = Arbitrary.arbitrary[Int] suchThat (_ != 0) import NumbersDomain._ - import pl.iterators.kebs.support._ + import support._ private def divide[A: Integral](f1: A, f2: A): (A, A) = { import Integral.Implicits._ diff --git a/core/src/test/scala/pl/iterators/kebs/core/NumbersDomain.scala b/core/src/test/scala/pl/iterators/kebs/core/NumbersDomain.scala new file mode 100644 index 00000000..850e5574 --- /dev/null +++ b/core/src/test/scala/pl/iterators/kebs/core/NumbersDomain.scala @@ -0,0 +1,38 @@ +package pl.iterators.kebs.core + +import pl.iterators.kebs.core.macros.ValueClassLike + +object NumbersDomain { + + trait Tag1 + type TaggedBigDecimal = BigDecimal with Tag1 + object TaggedBigDecimal { + def apply(value: BigDecimal): TaggedBigDecimal = value.asInstanceOf[TaggedBigDecimal] + } + object Tag1 { + implicit val taggedBigDecimalValueClassLike: ValueClassLike[TaggedBigDecimal, BigDecimal] = + new ValueClassLike[TaggedBigDecimal, BigDecimal](TaggedBigDecimal.apply, identity) + } + + case class BoxedBigDecimal(value: BigDecimal) + object BoxedBigDecimal { + implicit val boxedBigDecimalValueClassLike: ValueClassLike[BoxedBigDecimal, BigDecimal] = + new ValueClassLike[BoxedBigDecimal, BigDecimal](BoxedBigDecimal.apply, _.value) + } + + trait Tag2 + type TaggedInt = Int with Tag2 + object TaggedInt { + def apply(value: Int): TaggedInt = value.asInstanceOf[TaggedInt] + } + object Tag2 { + implicit val taggedIntValueClassLike: ValueClassLike[TaggedInt, Int] = + new ValueClassLike[TaggedInt, Int](TaggedInt.apply, identity) + } + + case class BoxedInt(value: Int) + object BoxedInt { + implicit val boxedIntValueClassLike: ValueClassLike[BoxedInt, Int] = + new ValueClassLike[BoxedInt, Int](BoxedInt.apply, _.value) + } +} diff --git a/core/src/test/scala/NumericSupportSpecification.scala b/core/src/test/scala/pl/iterators/kebs/core/NumericSupportSpecification.scala similarity index 91% rename from core/src/test/scala/NumericSupportSpecification.scala rename to core/src/test/scala/pl/iterators/kebs/core/NumericSupportSpecification.scala index f9f6c04c..41615bdd 100644 --- a/core/src/test/scala/NumericSupportSpecification.scala +++ b/core/src/test/scala/pl/iterators/kebs/core/NumericSupportSpecification.scala @@ -1,10 +1,12 @@ +package pl.iterators.kebs.core + import org.scalacheck.Prop.forAll import org.scalacheck.Properties object NumericSupportSpecification extends Properties("NumericSupport") { import NumbersDomain._ - import pl.iterators.kebs.support._ + import support._ property("sum of List[TaggedBigDecimal]") = forAll { (bigDecimalList: List[BigDecimal]) => bigDecimalList.map(TaggedBigDecimal(_)).sum == TaggedBigDecimal(bigDecimalList.sum) diff --git a/core/src/test/scala/OrderingSupportSpecification.scala b/core/src/test/scala/pl/iterators/kebs/core/OrderingSupportSpecification.scala similarity index 96% rename from core/src/test/scala/OrderingSupportSpecification.scala rename to core/src/test/scala/pl/iterators/kebs/core/OrderingSupportSpecification.scala index 9fc18f93..55b8667b 100644 --- a/core/src/test/scala/OrderingSupportSpecification.scala +++ b/core/src/test/scala/pl/iterators/kebs/core/OrderingSupportSpecification.scala @@ -1,9 +1,11 @@ +package pl.iterators.kebs.core + import org.scalacheck.Prop.forAll import org.scalacheck.Properties object OrderingSupportSpecification extends Properties("OrderingSupport") { - import pl.iterators.kebs.support._ + import support._ import NumbersDomain._ private def toTagged(list: List[BigDecimal]): List[TaggedBigDecimal] = diff --git a/core/src/test/scala/PartialOrderingSupportSpecification.scala b/core/src/test/scala/pl/iterators/kebs/core/PartialOrderingSupportSpecification.scala similarity index 98% rename from core/src/test/scala/PartialOrderingSupportSpecification.scala rename to core/src/test/scala/pl/iterators/kebs/core/PartialOrderingSupportSpecification.scala index de11172a..4be258cf 100644 --- a/core/src/test/scala/PartialOrderingSupportSpecification.scala +++ b/core/src/test/scala/pl/iterators/kebs/core/PartialOrderingSupportSpecification.scala @@ -1,10 +1,12 @@ +package pl.iterators.kebs.core + import org.scalacheck.Prop.forAll import org.scalacheck.{Gen, Properties} object PartialOrderingSupportSpecification extends Properties("PartialOrderingSupport") { import StringsDomain._ - import pl.iterators.kebs.support._ + import support._ private def maybeCompare[A](e1: A, e2: A)(implicit PO: PartialOrdering[A]): Option[Int] = PO.tryCompare(e1, e2) diff --git a/core/src/test/scala/pl/iterators/kebs/core/StringsDomain.scala b/core/src/test/scala/pl/iterators/kebs/core/StringsDomain.scala new file mode 100644 index 00000000..c1622ac9 --- /dev/null +++ b/core/src/test/scala/pl/iterators/kebs/core/StringsDomain.scala @@ -0,0 +1,21 @@ +package pl.iterators.kebs.core + +import pl.iterators.kebs.core.macros.ValueClassLike + +object StringsDomain { + trait Tag1 + type TaggedString = String with Tag1 + object TaggedString { + def apply(value: String): TaggedString = value.asInstanceOf[TaggedString] + } + object Tag1 { + implicit val taggedStringValueClassLike: ValueClassLike[TaggedString, String] = + new ValueClassLike[TaggedString, String](TaggedString.apply, identity) + } + + case class BoxedString(value: String) + object BoxedString { + implicit val boxedStringValueClassLike: ValueClassLike[BoxedString, String] = + new ValueClassLike[BoxedString, String](BoxedString.apply, _.value) + } +} diff --git a/doobie/src/main/scala-2/pl/iterators/kebs/Kebs.scala b/doobie/src/main/scala-2/pl/iterators/kebs/Kebs.scala deleted file mode 100644 index 5490058d..00000000 --- a/doobie/src/main/scala-2/pl/iterators/kebs/Kebs.scala +++ /dev/null @@ -1,21 +0,0 @@ -package pl.iterators.kebs - -import doobie.Meta -import pl.iterators.kebs.instances.InstanceConverter -import pl.iterators.kebs.macros.CaseClass1Rep - -import scala.reflect.ClassTag - -trait Kebs { - implicit def caseClass1RepMeta[A, M](implicit cc1Rep: CaseClass1Rep[A, M], m: Meta[M]): Meta[A] = m.imap(cc1Rep.apply)(cc1Rep.unapply) - - implicit def caseClass1RepArrayMeta[A, M](implicit cc1Rep: CaseClass1Rep[A, M], m: Meta[Array[M]], cta: ClassTag[A], ctm: ClassTag[M]): Meta[Array[A]] = m.imap(_.map(cc1Rep.apply))(_.map(cc1Rep.unapply)) - - implicit def caseClass1RepOptionArrayMeta[A, M](implicit cc1Rep: CaseClass1Rep[A, M], m: Meta[Array[Option[M]]], cta: ClassTag[A], ctm: ClassTag[M]): Meta[Array[Option[A]]] = m.imap(_.map(_.map(cc1Rep.apply)))(_.map(_.map(cc1Rep.unapply))) - - implicit def instanceConverterMeta[A, M](implicit instanceConverter: InstanceConverter[A, M], m: Meta[M]): Meta[A] = m.imap(instanceConverter.decode)(instanceConverter.encode) - - implicit def instanceConverterArrayMeta[A, M](implicit 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 def instanceConverterOptionArrayMeta[A, M](implicit instanceConverter: InstanceConverter[A, M], m: Meta[Array[Option[M]]], cta: ClassTag[A], ctm: ClassTag[M]): Meta[Array[Option[A]]] = m.imap(_.map(_.map(instanceConverter.decode)))(_.map(_.map(instanceConverter.encode))) -} \ No newline at end of file diff --git a/doobie/src/main/scala-2/pl/iterators/kebs/doobie/Kebs.scala b/doobie/src/main/scala-2/pl/iterators/kebs/doobie/Kebs.scala new file mode 100644 index 00000000..42cf7b3f --- /dev/null +++ b/doobie/src/main/scala-2/pl/iterators/kebs/doobie/Kebs.scala @@ -0,0 +1,21 @@ +package pl.iterators.kebs.doobie + +import doobie.Meta +import pl.iterators.kebs.core.instances.InstanceConverter +import pl.iterators.kebs.core.macros.{CaseClass1ToValueClass, ValueClassLike} + +import scala.reflect.ClassTag + +trait Kebs extends CaseClass1ToValueClass { + implicit def valueClassLikeMeta[A, M](implicit vcLike: ValueClassLike[A, M], m: Meta[M]): Meta[A] = m.imap(vcLike.apply)(vcLike.unapply) + + implicit def valueClassLikeArrayMeta[A, M](implicit 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 def valueClassLikeOptionArrayMeta[A, M](implicit vcLike: ValueClassLike[A, M], m: Meta[Array[Option[M]]], cta: ClassTag[A], ctm: ClassTag[M]): Meta[Array[Option[A]]] = m.imap(_.map(_.map(vcLike.apply)))(_.map(_.map(vcLike.unapply))) + + implicit def instanceConverterMeta[A, M](implicit instanceConverter: InstanceConverter[A, M], m: Meta[M]): Meta[A] = m.imap(instanceConverter.decode)(instanceConverter.encode) + + implicit def instanceConverterArrayMeta[A, M](implicit 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 def instanceConverterOptionArrayMeta[A, M](implicit instanceConverter: InstanceConverter[A, M], m: Meta[Array[Option[M]]], cta: ClassTag[A], ctm: ClassTag[M]): Meta[Array[Option[A]]] = m.imap(_.map(_.map(instanceConverter.decode)))(_.map(_.map(instanceConverter.encode))) +} diff --git a/doobie/src/main/scala-2/pl/iterators/kebs/doobie/enums/KebsEnums.scala b/doobie/src/main/scala-2/pl/iterators/kebs/doobie/enums/KebsEnums.scala new file mode 100644 index 00000000..9ff501e0 --- /dev/null +++ b/doobie/src/main/scala-2/pl/iterators/kebs/doobie/enums/KebsEnums.scala @@ -0,0 +1,27 @@ +package pl.iterators.kebs.doobie.enums + +import doobie.Meta +import enumeratum.EnumEntry +import pl.iterators.kebs.core.enums.EnumLike + +import scala.reflect.ClassTag + +trait KebsEnums { + implicit def enumMeta[E <: EnumEntry](implicit e: EnumLike[E], m: Meta[String]): Meta[E] = m.imap(e.withName)(_.toString) + implicit def enumArrayMeta[E <: EnumEntry](implicit e: EnumLike[E], m: Meta[Array[String]], cte: ClassTag[E]): Meta[Array[E]] = m.imap(_.map(e.withName))(_.map(_.toString)) + implicit def enumOptionArrayMeta[E <: EnumEntry](implicit e: EnumLike[E], m: Meta[Array[Option[String]]], cte: ClassTag[Option[E]]): Meta[Array[Option[E]]] = m.imap(_.map(_.map(e.withName)))(_.map(_.map(_.toString))) + + trait Uppercase { + implicit def enumUppercaseMeta[E <: EnumEntry](implicit e: EnumLike[E], m: Meta[String]): Meta[E] = m.imap(e.withNameUppercaseOnly)(_.toString.toUpperCase) + implicit def enumUppercaseArrayMeta[E <: EnumEntry](implicit e: EnumLike[E], m: Meta[Array[String]], cte: ClassTag[E]): Meta[Array[E]] = m.imap(_.map(e.withNameUppercaseOnly))(_.map(_.toString.toUpperCase)) + implicit def enumUppercaseOptionArrayMeta[E <: EnumEntry](implicit e: EnumLike[E], m: Meta[Array[Option[String]]], cte: ClassTag[E]): Meta[Array[Option[E]]] = m.imap(_.map(_.map(e.withNameUppercaseOnly)))(_.map(_.map(_.toString.toUpperCase))) + } + + trait Lowercase { + implicit def enumLowercaseMeta[E <: EnumEntry](implicit e: EnumLike[E], m: Meta[String]): Meta[E] = m.imap(e.withNameLowercaseOnly)(_.toString.toLowerCase) + implicit def enumLowercaseArrayMeta[E <: EnumEntry](implicit e: EnumLike[E], m: Meta[Array[String]], cte: ClassTag[E]): Meta[Array[E]] = m.imap(_.map(e.withNameLowercaseOnly))(_.map(_.toString.toLowerCase)) + implicit def enumLowercaseOptionArrayMeta[E <: EnumEntry](implicit e: EnumLike[E], m: Meta[Array[Option[String]]], cte: ClassTag[E]): Meta[Array[Option[E]]] = m.imap(_.map(_.map(e.withNameLowercaseOnly)))(_.map(_.map(_.toString.toLowerCase))) + } +} + +object KebsEnums extends KebsEnums \ No newline at end of file diff --git a/doobie/src/main/scala-3/pl/iterators/kebs/enums/package.scala b/doobie/src/main/scala-2/pl/iterators/kebs/doobie/enums/package.scala similarity index 78% rename from doobie/src/main/scala-3/pl/iterators/kebs/enums/package.scala rename to doobie/src/main/scala-2/pl/iterators/kebs/doobie/enums/package.scala index 153bf1f2..e42cde32 100644 --- a/doobie/src/main/scala-3/pl/iterators/kebs/enums/package.scala +++ b/doobie/src/main/scala-2/pl/iterators/kebs/doobie/enums/package.scala @@ -1,4 +1,4 @@ -package pl.iterators.kebs +package pl.iterators.kebs.doobie package object enums extends KebsEnums { object uppercase extends Uppercase diff --git a/doobie/src/main/scala-2/pl/iterators/kebs/doobie/package.scala b/doobie/src/main/scala-2/pl/iterators/kebs/doobie/package.scala new file mode 100644 index 00000000..2022afb7 --- /dev/null +++ b/doobie/src/main/scala-2/pl/iterators/kebs/doobie/package.scala @@ -0,0 +1,3 @@ +package pl.iterators.kebs + +package object doobie extends Kebs diff --git a/doobie/src/main/scala-2/pl/iterators/kebs/enums/KebsEnums.scala b/doobie/src/main/scala-2/pl/iterators/kebs/enums/KebsEnums.scala deleted file mode 100644 index 4f857117..00000000 --- a/doobie/src/main/scala-2/pl/iterators/kebs/enums/KebsEnums.scala +++ /dev/null @@ -1,27 +0,0 @@ -package pl.iterators.kebs.enums - -import doobie.Meta -import enumeratum.EnumEntry -import pl.iterators.kebs.macros.enums.EnumOf - -import scala.reflect.ClassTag - -trait KebsEnums { - implicit def enumMeta[E <: EnumEntry](implicit e: EnumOf[E], m: Meta[String]): Meta[E] = m.imap(e.`enum`.withName)(_.toString) - implicit def enumArrayMeta[E <: EnumEntry](implicit e: EnumOf[E], m: Meta[Array[String]], cte: ClassTag[E]): Meta[Array[E]] = m.imap(_.map(e.`enum`.withName))(_.map(_.toString)) - implicit def enumOptionArrayMeta[E <: EnumEntry](implicit e: EnumOf[E], m: Meta[Array[Option[String]]], cte: ClassTag[Option[E]]): Meta[Array[Option[E]]] = m.imap(_.map(_.map(e.`enum`.withName)))(_.map(_.map(_.toString))) - - trait Uppercase { - implicit def enumUppercaseMeta[E <: EnumEntry](implicit e: EnumOf[E], m: Meta[String]): Meta[E] = m.imap(e.`enum`.withNameUppercaseOnly)(_.toString.toUpperCase) - implicit def enumUppercaseArrayMeta[E <: EnumEntry](implicit e: EnumOf[E], m: Meta[Array[String]], cte: ClassTag[E]): Meta[Array[E]] = m.imap(_.map(e.`enum`.withNameUppercaseOnly))(_.map(_.toString.toUpperCase)) - implicit def enumUppercaseOptionArrayMeta[E <: EnumEntry](implicit e: EnumOf[E], m: Meta[Array[Option[String]]], cte: ClassTag[E]): Meta[Array[Option[E]]] = m.imap(_.map(_.map(e.`enum`.withNameUppercaseOnly)))(_.map(_.map(_.toString.toUpperCase))) - } - - trait Lowercase { - implicit def enumLowercaseMeta[E <: EnumEntry](implicit e: EnumOf[E], m: Meta[String]): Meta[E] = m.imap(e.`enum`.withNameLowercaseOnly)(_.toString.toLowerCase) - implicit def enumLowercaseArrayMeta[E <: EnumEntry](implicit e: EnumOf[E], m: Meta[Array[String]], cte: ClassTag[E]): Meta[Array[E]] = m.imap(_.map(e.`enum`.withNameLowercaseOnly))(_.map(_.toString.toLowerCase)) - implicit def enumLowercaseOptionArrayMeta[E <: EnumEntry](implicit e: EnumOf[E], m: Meta[Array[Option[String]]], cte: ClassTag[E]): Meta[Array[Option[E]]] = m.imap(_.map(_.map(e.`enum`.withNameLowercaseOnly)))(_.map(_.map(_.toString.toLowerCase))) - } -} - -object KebsEnums extends KebsEnums \ No newline at end of file diff --git a/doobie/src/main/scala-2/pl/iterators/kebs/package.scala b/doobie/src/main/scala-2/pl/iterators/kebs/package.scala deleted file mode 100644 index feea7054..00000000 --- a/doobie/src/main/scala-2/pl/iterators/kebs/package.scala +++ /dev/null @@ -1,3 +0,0 @@ -package pl.iterators - -package object kebs extends Kebs diff --git a/doobie/src/main/scala-3/pl/iterators/kebs/Kebs.scala b/doobie/src/main/scala-3/pl/iterators/kebs/Kebs.scala deleted file mode 100644 index ee4bee28..00000000 --- a/doobie/src/main/scala-3/pl/iterators/kebs/Kebs.scala +++ /dev/null @@ -1,24 +0,0 @@ -package pl.iterators.kebs - -import doobie.{Get, Put, Meta} -import pl.iterators.kebs.enums.KebsEnums -import pl.iterators.kebs.instances.InstanceConverter -import pl.iterators.kebs.macros.CaseClass1Rep - -import scala.reflect.ClassTag - -trait Kebs { - inline given[A, M](using cc1Rep: CaseClass1Rep[A, M], m: Meta[M]): Meta[A] = m.imap(cc1Rep.apply)(cc1Rep.unapply) - - inline given[A, M](using cc1Rep: CaseClass1Rep[A, M], m: Meta[Option[M]]): Meta[Option[A]] = m.imap(_.map(cc1Rep.apply))(_.map(cc1Rep.unapply)) - - inline given[A, M](using cc1Rep: CaseClass1Rep[A, M], m: Meta[Array[M]], cta: ClassTag[A], ctm: ClassTag[M]): Meta[Array[A]] = m.imap(_.map(cc1Rep.apply))(_.map(cc1Rep.unapply)) - - inline given[A, M](using cc1Rep: CaseClass1Rep[A, M], m: Meta[Array[Option[M]]], cta: ClassTag[Option[A]]): Meta[Array[Option[A]]] = m.imap(_.map(_.map(cc1Rep.apply)))(_.map(_.map(cc1Rep.unapply))) - - inline given[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)) - - 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))) -} \ No newline at end of file diff --git a/doobie/src/main/scala-3/pl/iterators/kebs/doobie/Kebs.scala b/doobie/src/main/scala-3/pl/iterators/kebs/doobie/Kebs.scala new file mode 100644 index 00000000..8daab1d1 --- /dev/null +++ b/doobie/src/main/scala-3/pl/iterators/kebs/doobie/Kebs.scala @@ -0,0 +1,24 @@ +package pl.iterators.kebs.doobie + +import doobie.{Get, Put, Meta} +import pl.iterators.kebs.doobie.enums.KebsEnums +import pl.iterators.kebs.core.instances.InstanceConverter +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) + + inline given[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)) + + 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))) + + inline given[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)) + + 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))) +} \ No newline at end of file diff --git a/doobie/src/main/scala-3/pl/iterators/kebs/doobie/enums/KebsEnums.scala b/doobie/src/main/scala-3/pl/iterators/kebs/doobie/enums/KebsEnums.scala new file mode 100644 index 00000000..92741d1b --- /dev/null +++ b/doobie/src/main/scala-3/pl/iterators/kebs/doobie/enums/KebsEnums.scala @@ -0,0 +1,25 @@ +package pl.iterators.kebs.doobie.enums + +import doobie.Meta +import scala.reflect.ClassTag +import scala.reflect.Enum + +import pl.iterators.kebs.core.enums.EnumLike + +trait KebsEnums { + inline given enumMeta[E <: Enum](using e: EnumLike[E]): Meta[E] = Meta.StringMeta.imap(e.valueOf)(_.toString) + inline given enumArrayMeta[E <: Enum](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 <: Enum](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 <: Enum](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 <: Enum](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 <: Enum](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 <: Enum](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 <: Enum](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 <: Enum](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))) + } +} \ No newline at end of file diff --git a/doobie/src/main/scala-2/pl/iterators/kebs/enums/package.scala b/doobie/src/main/scala-3/pl/iterators/kebs/doobie/enums/package.scala similarity index 78% rename from doobie/src/main/scala-2/pl/iterators/kebs/enums/package.scala rename to doobie/src/main/scala-3/pl/iterators/kebs/doobie/enums/package.scala index 153bf1f2..e42cde32 100644 --- a/doobie/src/main/scala-2/pl/iterators/kebs/enums/package.scala +++ b/doobie/src/main/scala-3/pl/iterators/kebs/doobie/enums/package.scala @@ -1,4 +1,4 @@ -package pl.iterators.kebs +package pl.iterators.kebs.doobie package object enums extends KebsEnums { object uppercase extends Uppercase diff --git a/doobie/src/main/scala-3/pl/iterators/kebs/doobie/package.scala b/doobie/src/main/scala-3/pl/iterators/kebs/doobie/package.scala new file mode 100644 index 00000000..829c2abd --- /dev/null +++ b/doobie/src/main/scala-3/pl/iterators/kebs/doobie/package.scala @@ -0,0 +1,3 @@ +package pl.iterators.kebs + +package object doobie extends Kebs \ No newline at end of file diff --git a/doobie/src/main/scala-3/pl/iterators/kebs/enums/KebsEnums.scala b/doobie/src/main/scala-3/pl/iterators/kebs/enums/KebsEnums.scala deleted file mode 100644 index 54717fb0..00000000 --- a/doobie/src/main/scala-3/pl/iterators/kebs/enums/KebsEnums.scala +++ /dev/null @@ -1,24 +0,0 @@ -package pl.iterators.kebs.enums - -import doobie.Meta -import pl.iterators.kebs.macros.enums.{EnumOf, EnumLike} -import scala.reflect.ClassTag -import scala.reflect.Enum - -trait KebsEnums { - inline given enumMeta[E <: Enum](using e: EnumOf[E]): Meta[E] = Meta.StringMeta.imap(e.`enum`.valueOf)(_.toString) - inline given enumArrayMeta[E <: Enum](using e: EnumOf[E], m: Meta[Array[String]], ct: ClassTag[E]): Meta[Array[E]] = m.imap(_.map(e.`enum`.valueOf))(_.map(_.toString)) - inline given enumOptionArrayMeta[E <: Enum](using e: EnumOf[E], m: Meta[Array[Option[String]]], ct: ClassTag[Option[E]]): Meta[Array[Option[E]]] = m.imap(_.map(_.map(e.`enum`.valueOf)))(_.map(_.map(_.toString))) - - trait Uppercase { - inline given enumUppercaseMeta[E <: Enum](using e: EnumOf[E]): Meta[E] = Meta.StringMeta.imap(s => e.`enum`.values.find(_.toString.toUpperCase == s).getOrElse(throw new IllegalArgumentException(s"enum case not found: $s")))(_.toString.toUpperCase) - inline given enumUppercaseArrayMeta[E <: Enum](using e: EnumOf[E], m: Meta[Array[String]], ct: ClassTag[E]): Meta[Array[E]] = m.imap(_.map(s => e.`enum`.values.find(_.toString.toUpperCase == s).getOrElse(throw new IllegalArgumentException(s"enum case not found: $s"))))(_.map(_.toString.toUpperCase)) - inline given enumUppercaseOptionArrayMeta[E <: Enum](using e: EnumOf[E], m: Meta[Array[Option[String]]], ct: ClassTag[Option[E]]): Meta[Array[Option[E]]] = m.imap(_.map(_.map(s => e.`enum`.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 <: Enum](using e: EnumOf[E]): Meta[E] = Meta.StringMeta.imap(s => e.`enum`.values.find(_.toString.toLowerCase == s).getOrElse(throw new IllegalArgumentException(s"enum case not found: $s")))(_.toString.toLowerCase) - inline given enumLowercaseMeta[E <: Enum](using e: EnumOf[E], m: Meta[Array[String]], ct: ClassTag[E]): Meta[Array[E]] = m.imap(_.map(s => e.`enum`.values.find(_.toString.toLowerCase == s).getOrElse(throw new IllegalArgumentException(s"enum case not found: $s"))))(_.map(_.toString.toLowerCase)) - inline given enumLowercaseOptionArrayMeta[E <: Enum](using e: EnumOf[E], m: Meta[Array[Option[String]]], ct: ClassTag[Option[E]]): Meta[Array[Option[E]]] = m.imap(_.map(_.map(s => e.`enum`.values.find(_.toString.toLowerCase == s).getOrElse(throw new IllegalArgumentException(s"enum case not found: $s")))))(_.map(_.map(_.toString.toLowerCase))) - } -} \ No newline at end of file diff --git a/doobie/src/main/scala-3/pl/iterators/kebs/package.scala b/doobie/src/main/scala-3/pl/iterators/kebs/package.scala deleted file mode 100644 index feea7054..00000000 --- a/doobie/src/main/scala-3/pl/iterators/kebs/package.scala +++ /dev/null @@ -1,3 +0,0 @@ -package pl.iterators - -package object kebs extends Kebs diff --git a/doobie/src/test/scala-2/ComplexTypesTests.scala b/doobie/src/test/scala-2/pl/iterators/kebs/doobie/ComplexTypesTests.scala similarity index 91% rename from doobie/src/test/scala-2/ComplexTypesTests.scala rename to doobie/src/test/scala-2/pl/iterators/kebs/doobie/ComplexTypesTests.scala index 58dc9e7c..641f652a 100644 --- a/doobie/src/test/scala-2/ComplexTypesTests.scala +++ b/doobie/src/test/scala-2/pl/iterators/kebs/doobie/ComplexTypesTests.scala @@ -1,26 +1,36 @@ -import enumeratum.{Enum, EnumEntry} +package pl.iterators.kebs.doobie + +import _root_.enumeratum.{Enum, EnumEntry} import org.scalatest.funsuite.AnyFunSuite import org.scalatest.matchers.should.Matchers +import pl.iterators.kebs.enumeratum.KebsEnumeratum import java.util.Currency import doobie._ import doobie.implicits._ import doobie.postgres._ import doobie.postgres.implicits._ -import pl.iterators.kebs.enums._ -import pl.iterators.kebs._ +import pl.iterators.kebs.doobie.enums._ +import pl.iterators.kebs.doobie._ import pl.iterators.kebs.instances.KebsInstances._ -class ComplexTypesTests extends AnyFunSuite with Matchers { +class ComplexTypesTests extends AnyFunSuite with Matchers with KebsEnumeratum { case class Name(name: String) + sealed trait EyeColor extends EnumEntry + object EyeColor extends Enum[EyeColor] { case object Blue extends EyeColor + case object Green extends EyeColor + case object Brown extends EyeColor + case object Other extends EyeColor + def values = findValues } + case class Person(name: Name, eyeColor: EyeColor, preferredCurrency: Currency, relatives: List[Name], eyeballsInTheJar: Array[EyeColor]) test("Put & Get exist") { diff --git a/doobie/src/test/scala-3/ComplexTypesTests.scala b/doobie/src/test/scala-3/pl/iterators/kebs/doobie/ComplexTypesTests.scala similarity index 91% rename from doobie/src/test/scala-3/ComplexTypesTests.scala rename to doobie/src/test/scala-3/pl/iterators/kebs/doobie/ComplexTypesTests.scala index 74bb74e3..f4d2c93c 100644 --- a/doobie/src/test/scala-3/ComplexTypesTests.scala +++ b/doobie/src/test/scala-3/pl/iterators/kebs/doobie/ComplexTypesTests.scala @@ -1,16 +1,20 @@ -import org.scalatest.funsuite.AnyFunSuite -import org.scalatest.matchers.should.Matchers +package pl.iterators.kebs.doobie -import java.util.Currency -import doobie.{*, given} import doobie.implicits.given import doobie.postgres.given import doobie.postgres.implicits.given -import pl.iterators.kebs.given -import pl.iterators.kebs.enums.given +import doobie.{*, given} +import org.scalatest.funsuite.AnyFunSuite +import org.scalatest.matchers.should.Matchers +import pl.iterators.kebs.doobie.EyeColor +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.opaque.Opaque +import java.util.Currency + opaque type Name = String object Name extends Opaque[Name, String] @@ -19,7 +23,7 @@ enum EyeColor { } case class Person(name: Name, eyeColor: EyeColor, preferredCurrency: Currency, relatives: List[Name], eyeballsInTheJar: Array[EyeColor]) -class ComplexTypesTests extends AnyFunSuite with Matchers { +class ComplexTypesTests extends AnyFunSuite with Matchers with KebsEnum { test("Put & Get exist") { "implicitly[Get[Name]]" should compile "implicitly[Put[Name]]" should compile diff --git a/enum/src/main/scala-2/pl/iterators/kebs/enums/KebsEnum.scala b/enum/src/main/scala-2/pl/iterators/kebs/enums/KebsEnum.scala new file mode 100644 index 00000000..dce84749 --- /dev/null +++ b/enum/src/main/scala-2/pl/iterators/kebs/enums/KebsEnum.scala @@ -0,0 +1,23 @@ +package pl.iterators.kebs.enums + +import pl.iterators.kebs.core.enums.EnumLike + +import scala.language.experimental.macros +import scala.language.implicitConversions +import scala.reflect.macros.blackbox + +trait KebsEnum { + implicit def enumScala[E <: Enumeration#Value]: EnumLike[E] = macro EnumerationEntryMacros.enumOfImpl[E] +} + +class EnumerationEntryMacros(val c: blackbox.Context) { + import c.universe._ + + def enumOfImpl[E <: Enumeration#Value : c.WeakTypeTag]: c.Expr[EnumLike[E]] = { + import c.universe._ + val valueType = implicitly[c.WeakTypeTag[E]].tpe.dealias + val objectStr = valueType.toString.replaceFirst(".Value$", "") + val objectName = c.typecheck(c.parse(s"$objectStr: $objectStr.type")) + c.Expr[EnumLike[E]](q"new _root_.pl.iterators.kebs.core.enums.EnumLike[$valueType] { override def values: immutable.Seq[${valueType}] = ($objectName).values.toSeq }") + } +} diff --git a/enum/src/main/scala-2/pl/iterators/kebs/enums/package.scala b/enum/src/main/scala-2/pl/iterators/kebs/enums/package.scala new file mode 100644 index 00000000..0b044bd4 --- /dev/null +++ b/enum/src/main/scala-2/pl/iterators/kebs/enums/package.scala @@ -0,0 +1,3 @@ +package pl.iterators.kebs + +package object enums extends KebsEnum diff --git a/enum/src/main/scala-3/pl/iterators/kebs/enums/KebsEnum.scala b/enum/src/main/scala-3/pl/iterators/kebs/enums/KebsEnum.scala new file mode 100644 index 00000000..44b31da8 --- /dev/null +++ b/enum/src/main/scala-3/pl/iterators/kebs/enums/KebsEnum.scala @@ -0,0 +1,35 @@ +package pl.iterators.kebs.enums + +import scala.collection.immutable +import scala.quoted._ +import scala.compiletime.{constValue, erasedValue, error, summonInline} +import scala.deriving.Mirror +import scala.reflect.{ClassTag, Enum} + +import pl.iterators.kebs.core.enums.EnumLike + +trait KebsEnum { + inline implicit def kebsEnumScala[E <: Enum](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 + } + } +} + +inline private def widen[A, B](a: A): A & B = + inline a match { + case b: B => b + } + +inline private def summonCases[T <: Tuple, A]: List[A] = + inline erasedValue[T] match { + case _: (h *: t) => + (inline summonInline[Mirror.Of[h]] match { + case m: Mirror.Singleton => + widen[m.MirroredMonoType, A](m.fromProduct(EmptyTuple)) :: summonCases[t, A] + case x => error("Enums cannot include parameterized cases.") + }) + + case _: EmptyTuple => Nil +} \ No newline at end of file diff --git a/enum/src/main/scala-3/pl/iterators/kebs/enums/KebsValueEnum.scala b/enum/src/main/scala-3/pl/iterators/kebs/enums/KebsValueEnum.scala new file mode 100644 index 00000000..8fda0487 --- /dev/null +++ b/enum/src/main/scala-3/pl/iterators/kebs/enums/KebsValueEnum.scala @@ -0,0 +1,30 @@ +package pl.iterators.kebs.enums + +import scala.collection.immutable +import scala.quoted.* +import scala.compiletime.{constValue, erasedValue, error, summonInline} +import scala.deriving.Mirror +import scala.reflect.{ClassTag, Enum} + +import pl.iterators.kebs.core.enums.{ValueEnumLike, ValueEnumLikeEntry} + +trait KebsValueEnum { + inline implicit def valueEnumScala[V, E <: ValueEnumLikeEntry[V]](using classTag: ClassTag[E], m: Mirror.SumOf[E]): ValueEnumLike[V, E] = { + val enumValues = summonValueCases[m.MirroredElemTypes, V, E] + new ValueEnumLike[V, E] { + override def values: immutable.Seq[E] = enumValues.toSeq + } + } +} + +inline private def summonValueCases[T <: Tuple, V, A <: ValueEnumLikeEntry[V]]: List[A] = + inline erasedValue[T] match { + case _: (h *: t) => + (inline summonInline[Mirror.Of[h]] match { + case m: Mirror.Singleton => + widen[m.MirroredMonoType, A](m.fromProduct(EmptyTuple)) :: summonValueCases[t, V, A] + case x => error("Enums cannot include parameterized cases.") + }) + + case _: EmptyTuple => Nil +} diff --git a/enum/src/main/scala-3/pl/iterators/kebs/enums/package.scala b/enum/src/main/scala-3/pl/iterators/kebs/enums/package.scala new file mode 100644 index 00000000..38514833 --- /dev/null +++ b/enum/src/main/scala-3/pl/iterators/kebs/enums/package.scala @@ -0,0 +1,3 @@ +package pl.iterators.kebs + +package object enums extends KebsEnum with KebsValueEnum diff --git a/enum/src/test/scala-2/pl/iterators/kebs/enums/domain/Color.scala b/enum/src/test/scala-2/pl/iterators/kebs/enums/domain/Color.scala new file mode 100644 index 00000000..cee9d48e --- /dev/null +++ b/enum/src/test/scala-2/pl/iterators/kebs/enums/domain/Color.scala @@ -0,0 +1,10 @@ +package pl.iterators.kebs.enums.domain + +object Color extends Enumeration { + type Color = Value + val Red, Green, Blue = Value +} +object ColorDomain { + val colorValues = Color.values.toList + type ColorType = Color.Color +} \ No newline at end of file diff --git a/enum/src/test/scala-2/pl/iterators/kebs/enums/enums.scala b/enum/src/test/scala-2/pl/iterators/kebs/enums/enums.scala new file mode 100644 index 00000000..0b044bd4 --- /dev/null +++ b/enum/src/test/scala-2/pl/iterators/kebs/enums/enums.scala @@ -0,0 +1,3 @@ +package pl.iterators.kebs + +package object enums extends KebsEnum diff --git a/enum/src/test/scala-3/pl/iterators/kebs/enums/ValueEnumTest.scala b/enum/src/test/scala-3/pl/iterators/kebs/enums/ValueEnumTest.scala new file mode 100644 index 00000000..ce0e7d37 --- /dev/null +++ b/enum/src/test/scala-3/pl/iterators/kebs/enums/ValueEnumTest.scala @@ -0,0 +1,22 @@ +package pl.iterators.kebs.enums + +import org.scalacheck.Prop.forAll +import org.scalacheck.{Gen, Properties} +import scala.deriving.Mirror +import scala.reflect.{ClassTag, Enum} + +import pl.iterators.kebs.core.enums.{ValueEnumLike, ValueEnumLikeEntry} + +object DerivingSpecification extends Properties("Deriving") with KebsValueEnum { + + enum ColorButRGB(val value: Int) extends ValueEnumLikeEntry[Int] { + case Red extends ColorButRGB(0xFF0000) + case Green extends ColorButRGB(0x00FF00) + case Blue extends ColorButRGB(0x0000FF) + } + + property("ValueEnumLike derives properly for a value enum") = forAll(Gen.oneOf(ColorButRGB.values.toList)) { (color: ColorButRGB) => + val tc = implicitly[ValueEnumLike[Int, ColorButRGB]] + tc.values.contains(color) && tc.valueOf(color.value) == color && tc.fromOrdinal(color.ordinal) == color + } +} diff --git a/enum/src/test/scala-3/pl/iterators/kebs/enums/domain/Color.scala b/enum/src/test/scala-3/pl/iterators/kebs/enums/domain/Color.scala new file mode 100644 index 00000000..587f38fc --- /dev/null +++ b/enum/src/test/scala-3/pl/iterators/kebs/enums/domain/Color.scala @@ -0,0 +1,9 @@ +package pl.iterators.kebs.enums.domain + +enum Color { + case Red, Green, Blue +} +object ColorDomain { + val colorValues = Color.values.toList + type ColorType = Color +} \ No newline at end of file diff --git a/enum/src/test/scala-3/pl/iterators/kebs/enums/package.scala b/enum/src/test/scala-3/pl/iterators/kebs/enums/package.scala new file mode 100644 index 00000000..3eaf7405 --- /dev/null +++ b/enum/src/test/scala-3/pl/iterators/kebs/enums/package.scala @@ -0,0 +1,3 @@ +package pl.iterators.kebs + +package object enums extends KebsEnum with KebsValueEnum \ No newline at end of file diff --git a/enum/src/test/scala/pl/iterators/kebs/enums/EnumTest.scala b/enum/src/test/scala/pl/iterators/kebs/enums/EnumTest.scala new file mode 100644 index 00000000..6afa92f2 --- /dev/null +++ b/enum/src/test/scala/pl/iterators/kebs/enums/EnumTest.scala @@ -0,0 +1,15 @@ +package pl.iterators.kebs.enums + +import scala.collection.immutable +import org.scalacheck.Prop.forAll +import org.scalacheck.{Gen, Properties} +import pl.iterators.kebs.core.enums.EnumLike +import pl.iterators.kebs.enums.domain.ColorDomain + +object EnumTest extends Properties("Deriving") with KebsEnum { + + property("EnumLike derives properly for an enum") = forAll(Gen.oneOf(ColorDomain.colorValues)) { (color: ColorDomain.ColorType) => + val tc = implicitly[EnumLike[ColorDomain.ColorType]] + tc.values.contains(color) && tc.valueOf(color.toString) == color + } +} diff --git a/enumeratum/src/main/scala-2/pl/iterators/kebs/enumeratum/KebsEnumeratum.scala b/enumeratum/src/main/scala-2/pl/iterators/kebs/enumeratum/KebsEnumeratum.scala new file mode 100644 index 00000000..ade79ee8 --- /dev/null +++ b/enumeratum/src/main/scala-2/pl/iterators/kebs/enumeratum/KebsEnumeratum.scala @@ -0,0 +1,27 @@ +package pl.iterators.kebs.enumeratum + +import scala.language.experimental.macros +import scala.language.implicitConversions +import scala.reflect.macros.blackbox +import enumeratum.EnumEntry +import pl.iterators.kebs.core.enums.EnumLike +import pl.iterators.kebs.core.macros.MacroUtils + +trait KebsEnumeratum { + implicit def enumeratumScala2[E <: EnumEntry]: EnumLike[E] = macro EnumeratumEntryMacros.enumeratumOfImpl[E] +} + +class EnumeratumEntryMacros(val c: blackbox.Context) extends MacroUtils { + import c.universe._ + + private def assertEnumEntry(t: Type, msg: => String) = if (!(t <:< typeOf[EnumEntry])) c.abort(c.enclosingPosition, msg) + + def enumeratumOfImpl[E <: EnumEntry: c.WeakTypeTag]: c.Expr[EnumLike[E]] = { + val EnumEntry = weakTypeOf[E] + assertEnumEntry(EnumEntry, s"${EnumEntry.typeSymbol} must subclass EnumEntry") + + c.Expr[EnumLike[E]](q"new _root_.pl.iterators.kebs.core.enums.EnumLike[${EnumEntry.typeSymbol}] { override def values: Seq[${EnumEntry.typeSymbol}] = ${companion(EnumEntry)}.values.toSeq }") + } +} + + diff --git a/enumeratum/src/main/scala-2/pl/iterators/kebs/enumeratum/KebsValueEnumeratum.scala b/enumeratum/src/main/scala-2/pl/iterators/kebs/enumeratum/KebsValueEnumeratum.scala new file mode 100644 index 00000000..c1edecd6 --- /dev/null +++ b/enumeratum/src/main/scala-2/pl/iterators/kebs/enumeratum/KebsValueEnumeratum.scala @@ -0,0 +1,34 @@ +package pl.iterators.kebs.enumeratum + +import enumeratum.values._ +import pl.iterators.kebs.core.enums.{ValueEnumLike, ValueEnumLikeEntry} + +import scala.language.experimental.macros +import scala.reflect.macros.blackbox + +trait KebsValueEnumeratum { + implicit def valueIntEnumeratumScala2[E <: IntEnumEntry with ValueEnumLikeEntry[Int]]: ValueEnumLike[Int, E] = macro ValueEnumEntryMacros.valueEnumOfImpl[Int, E] + implicit def valueShortEnumeratumScala2[E <: ShortEnumEntry with ValueEnumLikeEntry[Short]]: ValueEnumLike[Short, E] = macro ValueEnumEntryMacros.valueEnumOfImpl[Short, E] + implicit def valueLongEnumeratumScala2[E <: LongEnumEntry with ValueEnumLikeEntry[Long]]: ValueEnumLike[Long, E] = macro ValueEnumEntryMacros.valueEnumOfImpl[Long, E] + implicit def valueByteEnumeratumScala2[E <: ByteEnumEntry with ValueEnumLikeEntry[Byte]]: ValueEnumLike[Byte, E] = macro ValueEnumEntryMacros.valueEnumOfImpl[Byte, E] + implicit def valueStringEnumeratumScala2[E <: StringEnumEntry with ValueEnumLikeEntry[String]]: ValueEnumLike[String, E] = macro ValueEnumEntryMacros.valueEnumOfImpl[String, E] + implicit def valueEnumeratumScala2[ValueType, E <: ValueEnumEntry[ValueType] with ValueEnumLikeEntry[ValueType]]: ValueEnumLike[ValueType, E] = macro ValueEnumEntryMacros.valueEnumOfImpl[ValueType, E] +} + + +class ValueEnumEntryMacros(val c: blackbox.Context) { + import c.universe._ + + def valueEnumOfImpl[ValueType: c.WeakTypeTag, E <: ValueEnumEntry[ValueType] with ValueEnumLikeEntry[ValueType]: c.WeakTypeTag]: c.Expr[ValueEnumLike[ValueType, E]] = { + val ValueType = weakTypeOf[ValueType] + val EnumEntry = weakTypeOf[E] + + c.Expr[ValueEnumLike[ValueType, E]]( + q""" + new _root_.pl.iterators.kebs.core.enums.ValueEnumLike[${ValueType}, ${EnumEntry}] { + override def values: Seq[$EnumEntry] = ${EnumEntry.typeSymbol.companion}.values.toSeq + } + """ + ) + } +} diff --git a/enumeratum/src/main/scala-2/pl/iterators/kebs/enumeratum/package.scala b/enumeratum/src/main/scala-2/pl/iterators/kebs/enumeratum/package.scala new file mode 100644 index 00000000..5212edef --- /dev/null +++ b/enumeratum/src/main/scala-2/pl/iterators/kebs/enumeratum/package.scala @@ -0,0 +1,3 @@ +package pl.iterators.kebs + +package object enumeratum extends KebsEnumeratum with KebsValueEnumeratum diff --git a/enumeratum/src/main/scala-3/pl/iterators/kebs/enumeratum/KebsEnumeratum.scala b/enumeratum/src/main/scala-3/pl/iterators/kebs/enumeratum/KebsEnumeratum.scala new file mode 100644 index 00000000..06e5e863 --- /dev/null +++ b/enumeratum/src/main/scala-3/pl/iterators/kebs/enumeratum/KebsEnumeratum.scala @@ -0,0 +1,36 @@ +package pl.iterators.kebs.enumeratum + +import enumeratum._ +import scala.collection.immutable +import scala.quoted._ +import scala.compiletime.{constValue, erasedValue, error, summonInline} +import scala.deriving.Mirror +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] = { + val enumValues = summonCases[m.MirroredElemTypes, E] + new EnumLike[E] { + override def values: immutable.Seq[E] = enumValues.toSeq + } + } +} + +inline private def widen[A, B] (a: A): A & B = + inline a match { + case b: B => b + } + +inline private def summonCases[T <: Tuple, A]: List[A] = + inline erasedValue[T] match { + case _: (h *: t) => + (inline summonInline[Mirror.Of[h]] match { + case m: Mirror.Singleton => + widen[m.MirroredMonoType, A](m.fromProduct(EmptyTuple)) :: summonCases[t, A] + case x => error("Enums cannot include parameterized cases.") + }) + + case _: EmptyTuple => Nil +} diff --git a/enumeratum/src/main/scala-3/pl/iterators/kebs/enumeratum/KebsValueEnumeratum.scala b/enumeratum/src/main/scala-3/pl/iterators/kebs/enumeratum/KebsValueEnumeratum.scala new file mode 100644 index 00000000..b33d02ab --- /dev/null +++ b/enumeratum/src/main/scala-3/pl/iterators/kebs/enumeratum/KebsValueEnumeratum.scala @@ -0,0 +1,36 @@ +package pl.iterators.kebs.enumeratum + +import scala.collection.immutable +import enumeratum.values._ +import scala.quoted._ +import scala.compiletime.{constValue, erasedValue, error, summonInline} +import scala.deriving._ +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] = { + val enumValues = summonValueCases[m.MirroredElemTypes, V, E] + new ValueEnumLike[V, E] { + override def values: immutable.Seq[E] = enumValues + } + } +} + +inline private def widen[A, B] (a: A): A & B = + inline a match { + case b: B => b + } + +inline private def summonValueCases[T <: Tuple, V, A <: ValueEnumEntry[V]]: List[A] = + inline erasedValue[T] match { + case _: (h *: t) => + (inline summonInline[Mirror.Of[h]] match { + case m: Mirror.Singleton => + widen[m.MirroredMonoType, A](m.fromProduct(EmptyTuple)) :: summonValueCases[t, V, A] + case x => error("Enums cannot include parameterized cases.") + }) + + case _: EmptyTuple => Nil +} diff --git a/enumeratum/src/main/scala-3/pl/iterators/kebs/enumeratum/package.scala b/enumeratum/src/main/scala-3/pl/iterators/kebs/enumeratum/package.scala new file mode 100644 index 00000000..5212edef --- /dev/null +++ b/enumeratum/src/main/scala-3/pl/iterators/kebs/enumeratum/package.scala @@ -0,0 +1,3 @@ +package pl.iterators.kebs + +package object enumeratum extends KebsEnumeratum with KebsValueEnumeratum diff --git a/enumeratum/src/test/scala/pl/iterators/kebs/enumeratum/EnumeratumTest.scala b/enumeratum/src/test/scala/pl/iterators/kebs/enumeratum/EnumeratumTest.scala new file mode 100644 index 00000000..24b74b2f --- /dev/null +++ b/enumeratum/src/test/scala/pl/iterators/kebs/enumeratum/EnumeratumTest.scala @@ -0,0 +1,23 @@ +package pl.iterators.kebs.enumeratum + +import enumeratum._ +import org.scalacheck.Prop.forAll +import org.scalacheck.{Gen, Properties} +import pl.iterators.kebs.core.enums.EnumLike + +object EnumeratumTest extends Properties("Deriving") with KebsEnumeratum { + + sealed trait Greeting extends EnumEntry + object Greeting extends Enum[Greeting] { + val values = findValues + case object Hello extends Greeting + case object GoodBye extends Greeting + case object Hi extends Greeting + case object Bye extends Greeting + } + + property("EnumLike derives properly for an enumeratum enum") = forAll(Gen.oneOf(Greeting.values.toList)) { (greeting: Greeting) => + val tc = implicitly[EnumLike[Greeting]] + tc.values.contains(greeting) && tc.valueOf(greeting.toString) == greeting && tc.fromOrdinal(Greeting.values.indexOf(greeting)) == greeting + } +} diff --git a/enumeratum/src/test/scala/pl/iterators/kebs/enumeratum/ValueEnumeratumTest.scala b/enumeratum/src/test/scala/pl/iterators/kebs/enumeratum/ValueEnumeratumTest.scala new file mode 100644 index 00000000..1fb242ea --- /dev/null +++ b/enumeratum/src/test/scala/pl/iterators/kebs/enumeratum/ValueEnumeratumTest.scala @@ -0,0 +1,22 @@ +package pl.iterators.kebs.enumeratum + +import enumeratum.values._ +import org.scalacheck.Prop.forAll +import org.scalacheck.{Gen, Properties} +import pl.iterators.kebs.core.enums.{ValueEnumLike, ValueEnumLikeEntry} + +object ValueEnumTest extends Properties("Deriving") with KebsValueEnumeratum { + sealed abstract class LibraryItem(val value: Int) extends IntEnumEntry with ValueEnumLikeEntry[Int] + object LibraryItem extends IntEnum[LibraryItem] { + case object Book extends LibraryItem(value = 1) + case object Movie extends LibraryItem(value = 2) + case object Magazine extends LibraryItem(3) + case object CD extends LibraryItem(4) + val values = findValues + } + + property("ValueEnumLike derives properly for a value enum") = forAll(Gen.oneOf(LibraryItem.values.toList)) { (libraryItem: LibraryItem) => + val tc = implicitly[ValueEnumLike[Int, LibraryItem]] + tc.values.contains(libraryItem) && tc.valueOf(libraryItem.value) == libraryItem + } +} diff --git a/enumeratum/src/test/scala/pl/iterators/kebs/enumeratum/package.scala b/enumeratum/src/test/scala/pl/iterators/kebs/enumeratum/package.scala new file mode 100644 index 00000000..5212edef --- /dev/null +++ b/enumeratum/src/test/scala/pl/iterators/kebs/enumeratum/package.scala @@ -0,0 +1,3 @@ +package pl.iterators.kebs + +package object enumeratum extends KebsEnumeratum with KebsValueEnumeratum diff --git a/examples/src/main/scala/pl/iterators/kebs_examples/CirceExample.scala b/examples/src/main/scala/pl/iterators/kebs/examples/CirceExample.scala similarity index 99% rename from examples/src/main/scala/pl/iterators/kebs_examples/CirceExample.scala rename to examples/src/main/scala/pl/iterators/kebs/examples/CirceExample.scala index 9840a610..5c04e7a8 100644 --- a/examples/src/main/scala/pl/iterators/kebs_examples/CirceExample.scala +++ b/examples/src/main/scala/pl/iterators/kebs/examples/CirceExample.scala @@ -1,4 +1,4 @@ -package pl.iterators.kebs_examples +package pl.iterators.kebs.examples import java.net.URL import java.util.UUID diff --git a/examples/src/main/scala/pl/iterators/kebs_examples/EnumSprayJsonFormat.scala b/examples/src/main/scala/pl/iterators/kebs/examples/EnumSprayJsonFormat.scala similarity index 99% rename from examples/src/main/scala/pl/iterators/kebs_examples/EnumSprayJsonFormat.scala rename to examples/src/main/scala/pl/iterators/kebs/examples/EnumSprayJsonFormat.scala index ba6812af..8788bea4 100644 --- a/examples/src/main/scala/pl/iterators/kebs_examples/EnumSprayJsonFormat.scala +++ b/examples/src/main/scala/pl/iterators/kebs/examples/EnumSprayJsonFormat.scala @@ -1,4 +1,4 @@ -package pl.iterators.kebs_examples +package pl.iterators.kebs.examples import java.net.URL import java.util.UUID diff --git a/examples/src/main/scala/pl/iterators/kebs_examples/EnumValueColumnType.scala b/examples/src/main/scala/pl/iterators/kebs/examples/EnumValueColumnType.scala similarity index 98% rename from examples/src/main/scala/pl/iterators/kebs_examples/EnumValueColumnType.scala rename to examples/src/main/scala/pl/iterators/kebs/examples/EnumValueColumnType.scala index 96db161d..458a3930 100644 --- a/examples/src/main/scala/pl/iterators/kebs_examples/EnumValueColumnType.scala +++ b/examples/src/main/scala/pl/iterators/kebs/examples/EnumValueColumnType.scala @@ -1,4 +1,4 @@ -package pl.iterators.kebs_examples +package pl.iterators.kebs.examples import com.github.tminglei.slickpg.ExPostgresProfile import enumeratum.{Enum, EnumEntry} @@ -64,7 +64,6 @@ object EnumValueColumnType { object AfterKebs { import slick.jdbc.PostgresProfile.api._ import pl.iterators.kebs._ - import enums._ class People(tag: Tag) extends Table[Person](tag, "people") { def userId: Rep[UserId] = column[UserId]("user_id") @@ -98,8 +97,8 @@ object EnumValueColumnType { } object AfterKebsTraitStyle { - import pl.iterators.kebs.Kebs - import pl.iterators.kebs.enums.KebsEnums + + import pl.iterators.kebs.slick.Kebs object MyPostgresProfile extends ExPostgresProfile { override val api: APIWithKebsAndEnums = new APIWithKebsAndEnums {} diff --git a/examples/src/main/scala/pl/iterators/kebs_examples/HStoreColumnType.scala b/examples/src/main/scala/pl/iterators/kebs/examples/HStoreColumnType.scala similarity index 96% rename from examples/src/main/scala/pl/iterators/kebs_examples/HStoreColumnType.scala rename to examples/src/main/scala/pl/iterators/kebs/examples/HStoreColumnType.scala index 8f32cf15..96d6271c 100644 --- a/examples/src/main/scala/pl/iterators/kebs_examples/HStoreColumnType.scala +++ b/examples/src/main/scala/pl/iterators/kebs/examples/HStoreColumnType.scala @@ -1,4 +1,4 @@ -package pl.iterators.kebs_examples +package pl.iterators.kebs.examples import com.github.tminglei.slickpg.{ExPostgresProfile, PgHStoreSupport} import org.postgresql.util.HStoreConverter @@ -72,8 +72,8 @@ object HStoreColumnType { } object AfterKebs { - import pl.iterators.kebs.Kebs - import pl.iterators.kebs.instances.time.YearMonthString + import pl.iterators.kebs.circe.instances.time.YearMonthString + import pl.iterators.kebs.slick.Kebs object MyPostgresProfile extends ExPostgresProfile with PgHStoreSupport { override val api: APIWithHstore = new APIWithHstore {} diff --git a/examples/src/main/scala/pl/iterators/kebs_examples/HStoreExtensionMethods.scala b/examples/src/main/scala/pl/iterators/kebs/examples/HStoreExtensionMethods.scala similarity index 95% rename from examples/src/main/scala/pl/iterators/kebs_examples/HStoreExtensionMethods.scala rename to examples/src/main/scala/pl/iterators/kebs/examples/HStoreExtensionMethods.scala index de17d9c3..0af45f93 100644 --- a/examples/src/main/scala/pl/iterators/kebs_examples/HStoreExtensionMethods.scala +++ b/examples/src/main/scala/pl/iterators/kebs/examples/HStoreExtensionMethods.scala @@ -1,4 +1,4 @@ -package pl.iterators.kebs_examples +package pl.iterators.kebs.examples import com.github.tminglei.slickpg.{ExPostgresProfile, PgArraySupport, PgHStoreSupport} import slick.lifted.MappedProjection @@ -48,8 +48,8 @@ object HStoreExtensionMethods { } object AfterKebs { - import pl.iterators.kebs.Kebs - import pl.iterators.kebs.instances.time.YearMonthString + import pl.iterators.kebs.circe.instances.time.YearMonthString + import pl.iterators.kebs.slick.Kebs object MyPostgresProfile extends ExPostgresProfile with PgHStoreSupport with PgArraySupport { override val api: APIWithHstore = new APIWithHstore {} diff --git a/examples/src/main/scala/pl/iterators/kebs_examples/ListValueCommonType.scala b/examples/src/main/scala/pl/iterators/kebs/examples/ListValueCommonType.scala similarity index 97% rename from examples/src/main/scala/pl/iterators/kebs_examples/ListValueCommonType.scala rename to examples/src/main/scala/pl/iterators/kebs/examples/ListValueCommonType.scala index d13bd917..0edbb26f 100644 --- a/examples/src/main/scala/pl/iterators/kebs_examples/ListValueCommonType.scala +++ b/examples/src/main/scala/pl/iterators/kebs/examples/ListValueCommonType.scala @@ -1,4 +1,4 @@ -package pl.iterators.kebs_examples +package pl.iterators.kebs.examples import com.github.tminglei.slickpg._ @@ -46,7 +46,8 @@ object ListValueCommonType { } object AfterKebsTraitStyle { - import pl.iterators.kebs.Kebs + + import pl.iterators.kebs.slick.Kebs object MyPostgresProfile extends ExPostgresProfile with PgArraySupport { override val api: APIWithArraysAndKebs = new APIWithArraysAndKebs {} trait APIWithArraysAndKebs extends super.API with ArrayImplicits with Kebs diff --git a/examples/src/main/scala/pl/iterators/kebs_examples/NumericExample.scala b/examples/src/main/scala/pl/iterators/kebs/examples/NumericExample.scala similarity index 87% rename from examples/src/main/scala/pl/iterators/kebs_examples/NumericExample.scala rename to examples/src/main/scala/pl/iterators/kebs/examples/NumericExample.scala index 1f4b6542..31ab0594 100644 --- a/examples/src/main/scala/pl/iterators/kebs_examples/NumericExample.scala +++ b/examples/src/main/scala/pl/iterators/kebs/examples/NumericExample.scala @@ -1,8 +1,7 @@ -package pl.iterators.kebs_examples +package pl.iterators.kebs.examples import pl.iterators.kebs.tag.meta.tagged import pl.iterators.kebs.tagged._ -import pl.iterators.kebs.support._ @tagged trait NumericDomain { trait Tag1 diff --git a/examples/src/main/scala/pl/iterators/kebs_examples/PekkoHttpUnmarshallers.scala b/examples/src/main/scala/pl/iterators/kebs/examples/PekkoHttpUnmarshallers.scala similarity index 97% rename from examples/src/main/scala/pl/iterators/kebs_examples/PekkoHttpUnmarshallers.scala rename to examples/src/main/scala/pl/iterators/kebs/examples/PekkoHttpUnmarshallers.scala index 6090cfe9..77c91b12 100644 --- a/examples/src/main/scala/pl/iterators/kebs_examples/PekkoHttpUnmarshallers.scala +++ b/examples/src/main/scala/pl/iterators/kebs/examples/PekkoHttpUnmarshallers.scala @@ -1,4 +1,4 @@ -package pl.iterators.kebs_examples +package pl.iterators.kebs.examples import org.apache.pekko.http.scaladsl.model.StatusCodes import org.apache.pekko.http.scaladsl.server.Directives._ @@ -66,8 +66,6 @@ object PekkoHttpUnmarshallers { } object AfterKebs { - import pl.iterators.kebs.unmarshallers._ - import enums._ val route = get { parameters(Symbol("sortBy").as[Column], diff --git a/examples/src/main/scala/pl/iterators/kebs_examples/PlayJsonFormat.scala b/examples/src/main/scala/pl/iterators/kebs/examples/PlayJsonFormat.scala similarity index 99% rename from examples/src/main/scala/pl/iterators/kebs_examples/PlayJsonFormat.scala rename to examples/src/main/scala/pl/iterators/kebs/examples/PlayJsonFormat.scala index 05f7b107..112da84c 100644 --- a/examples/src/main/scala/pl/iterators/kebs_examples/PlayJsonFormat.scala +++ b/examples/src/main/scala/pl/iterators/kebs/examples/PlayJsonFormat.scala @@ -1,4 +1,4 @@ -package pl.iterators.kebs_examples +package pl.iterators.kebs.examples import java.net.URL import java.util.UUID diff --git a/examples/src/main/scala/pl/iterators/kebs_examples/SlickTaggedExample.scala b/examples/src/main/scala/pl/iterators/kebs/examples/SlickTaggedExample.scala similarity index 96% rename from examples/src/main/scala/pl/iterators/kebs_examples/SlickTaggedExample.scala rename to examples/src/main/scala/pl/iterators/kebs/examples/SlickTaggedExample.scala index b7fca3a6..a703d8d3 100644 --- a/examples/src/main/scala/pl/iterators/kebs_examples/SlickTaggedExample.scala +++ b/examples/src/main/scala/pl/iterators/kebs/examples/SlickTaggedExample.scala @@ -1,4 +1,4 @@ -package pl.iterators.kebs_examples +package pl.iterators.kebs.examples import slick.jdbc.PostgresProfile.api._ import slick.lifted.ProvenShape diff --git a/examples/src/main/scala/pl/iterators/kebs_examples/SprayJsonFormat.scala b/examples/src/main/scala/pl/iterators/kebs/examples/SprayJsonFormat.scala similarity index 96% rename from examples/src/main/scala/pl/iterators/kebs_examples/SprayJsonFormat.scala rename to examples/src/main/scala/pl/iterators/kebs/examples/SprayJsonFormat.scala index 68c29b08..bcb3a472 100644 --- a/examples/src/main/scala/pl/iterators/kebs_examples/SprayJsonFormat.scala +++ b/examples/src/main/scala/pl/iterators/kebs/examples/SprayJsonFormat.scala @@ -1,11 +1,11 @@ -package pl.iterators.kebs_examples +package pl.iterators.kebs.examples import org.apache.pekko.http.scaladsl.marshallers.sprayjson.SprayJsonSupport import org.apache.pekko.http.scaladsl.marshalling.ToResponseMarshallable import org.apache.pekko.http.scaladsl.model.StatusCodes._ import org.apache.pekko.http.scaladsl.server.Directives._ -import pl.iterators.kebs.instances.net.URIString -import pl.iterators.kebs.instances.util.UUIDString +import pl.iterators.kebs.circe.instances.net.URIString +import pl.iterators.kebs.circe.instances.util.UUIDString import pl.iterators.kebs.json.KebsSpray import spray.json._ diff --git a/examples/src/main/scala/pl/iterators/kebs_examples/SprayJsonWithPekkoHttpExample.scala b/examples/src/main/scala/pl/iterators/kebs/examples/SprayJsonWithPekkoHttpExample.scala similarity index 99% rename from examples/src/main/scala/pl/iterators/kebs_examples/SprayJsonWithPekkoHttpExample.scala rename to examples/src/main/scala/pl/iterators/kebs/examples/SprayJsonWithPekkoHttpExample.scala index b7332a3c..752fc959 100644 --- a/examples/src/main/scala/pl/iterators/kebs_examples/SprayJsonWithPekkoHttpExample.scala +++ b/examples/src/main/scala/pl/iterators/kebs/examples/SprayJsonWithPekkoHttpExample.scala @@ -1,4 +1,4 @@ -package pl.iterators.kebs_examples +package pl.iterators.kebs.examples import java.io.IOException import java.time.format.DateTimeFormatter diff --git a/examples/src/main/scala/pl/iterators/kebs_examples/TaggedMeta.scala b/examples/src/main/scala/pl/iterators/kebs/examples/TaggedMeta.scala similarity index 97% rename from examples/src/main/scala/pl/iterators/kebs_examples/TaggedMeta.scala rename to examples/src/main/scala/pl/iterators/kebs/examples/TaggedMeta.scala index e9cecfe3..7c93da12 100644 --- a/examples/src/main/scala/pl/iterators/kebs_examples/TaggedMeta.scala +++ b/examples/src/main/scala/pl/iterators/kebs/examples/TaggedMeta.scala @@ -1,4 +1,4 @@ -package pl.iterators.kebs_examples +package pl.iterators.kebs.examples import java.util.UUID import pl.iterators.kebs.tagged._ diff --git a/examples/src/main/scala/pl/iterators/kebs_examples/ValueColumnType.scala b/examples/src/main/scala/pl/iterators/kebs/examples/ValueColumnType.scala similarity index 99% rename from examples/src/main/scala/pl/iterators/kebs_examples/ValueColumnType.scala rename to examples/src/main/scala/pl/iterators/kebs/examples/ValueColumnType.scala index 88847ecd..f2b79208 100644 --- a/examples/src/main/scala/pl/iterators/kebs_examples/ValueColumnType.scala +++ b/examples/src/main/scala/pl/iterators/kebs/examples/ValueColumnType.scala @@ -1,4 +1,4 @@ -package pl.iterators.kebs_examples +package pl.iterators.kebs.examples import slick.jdbc.PostgresProfile.api._ import slick.lifted.ProvenShape diff --git a/http4s-stir/src/main/scala-2/matchers/KebsMatchers.scala b/http4s-stir/src/main/scala-2/pl/iterators/kebs/http4sstir/matchers/KebsMatchers.scala similarity index 67% rename from http4s-stir/src/main/scala-2/matchers/KebsMatchers.scala rename to http4s-stir/src/main/scala-2/pl/iterators/kebs/http4sstir/matchers/KebsMatchers.scala index f17b477c..fd9cf88a 100644 --- a/http4s-stir/src/main/scala-2/matchers/KebsMatchers.scala +++ b/http4s-stir/src/main/scala-2/pl/iterators/kebs/http4sstir/matchers/KebsMatchers.scala @@ -1,16 +1,16 @@ -package pl.iterators.kebs.matchers +package pl.iterators.kebs.http4sstir.matchers import pl.iterators.stir.server.PathMatcher1 import enumeratum.{Enum, EnumEntry} -import pl.iterators.kebs.instances.InstanceConverter -import pl.iterators.kebs.macros.CaseClass1Rep +import pl.iterators.kebs.core.instances.InstanceConverter +import pl.iterators.kebs.core.macros.{CaseClass1ToValueClass, ValueClassLike} import scala.language.implicitConversions -trait KebsMatchers extends pl.iterators.stir.server.PathMatchers { +trait KebsMatchers extends pl.iterators.stir.server.PathMatchers with CaseClass1ToValueClass { implicit class SegmentIsomorphism[U](segment: PathMatcher1[U]) { - def as[T](implicit rep: CaseClass1Rep[T, U]): PathMatcher1[T] = segment.map(rep.apply) + def as[T](implicit rep: ValueClassLike[T, U]): PathMatcher1[T] = segment.map(rep.apply) } implicit class SegmentConversion[Source](segment: PathMatcher1[Source]) { diff --git a/http4s-stir/src/main/scala-2/pl/iterators/kebs/http4sstir/unmarshallers/enums/KebsEnumUnmarshallers.scala b/http4s-stir/src/main/scala-2/pl/iterators/kebs/http4sstir/unmarshallers/enums/KebsEnumUnmarshallers.scala new file mode 100644 index 00000000..4ec1dcac --- /dev/null +++ b/http4s-stir/src/main/scala-2/pl/iterators/kebs/http4sstir/unmarshallers/enums/KebsEnumUnmarshallers.scala @@ -0,0 +1,46 @@ +package pl.iterators.kebs.http4sstir.enums + +import pl.iterators.stir.unmarshalling.PredefinedFromStringUnmarshallers._ +import pl.iterators.stir.unmarshalling.{FromStringUnmarshaller, Unmarshaller} +import cats.effect.IO +import pl.iterators.kebs.core.enums.{EnumLike, ValueEnumLike, ValueEnumLikeEntry} + +trait EnumUnmarshallers { + final def enumUnmarshaller[E](`enum`: EnumLike[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`.getNamesToValuesMap.keysIterator + .mkString(", ")}""")) + } + } + + implicit def kebsEnumUnmarshaller[E](implicit ev: EnumLike[E]): FromStringUnmarshaller[E] = + enumUnmarshaller(ev) +} + +trait ValueEnumUnmarshallers { + final def valueEnumUnmarshaller[V, E <: ValueEnumLikeEntry[V]](`enum`: ValueEnumLike[V, E]): Unmarshaller[V, E] = Unmarshaller { v => + `enum`.withValueOption(v) match { + case Some(enumEntry) => IO.pure(enumEntry) + case None => + IO.raiseError(new IllegalArgumentException(s"""Invalid value '$v'. Expected one of: ${`enum`.getValuesToEntriesMap.keysIterator + .mkString(", ")}""")) + } + } + + implicit def kebsValueEnumUnmarshaller[V, E <: ValueEnumLikeEntry[V]](implicit ev: ValueEnumLike[V, E]): Unmarshaller[V, E] = + valueEnumUnmarshaller(ev) + + implicit def kebsIntValueEnumFromStringUnmarshaller[E <: ValueEnumLikeEntry[Int]](implicit ev: ValueEnumLike[Int, E]): FromStringUnmarshaller[E] = + intFromStringUnmarshaller andThen valueEnumUnmarshaller(ev) + implicit def kebsLongValueEnumFromStringUnmarshaller[E <: ValueEnumLikeEntry[Long]](implicit ev: ValueEnumLike[Long, E]): FromStringUnmarshaller[E] = + longFromStringUnmarshaller andThen valueEnumUnmarshaller(ev) + implicit def kebsShortValueEnumFromStringUnmarshaller[E <: ValueEnumLikeEntry[Short]]( + implicit ev: ValueEnumLike[Short, E]): FromStringUnmarshaller[E] = + shortFromStringUnmarshaller andThen valueEnumUnmarshaller(ev) + implicit def kebsByteValueEnumFromStringUnmarshaller[E <: ValueEnumLikeEntry[Byte]](implicit ev: ValueEnumLike[Byte, E]): FromStringUnmarshaller[E] = + byteFromStringUnmarshaller andThen valueEnumUnmarshaller(ev) +} + +trait KebsEnumUnmarshallers extends EnumUnmarshallers with ValueEnumUnmarshallers {} diff --git a/akka-http/src/main/scala/pl/iterators/kebs/unmarshallers/enums/package.scala b/http4s-stir/src/main/scala-2/pl/iterators/kebs/http4sstir/unmarshallers/enums/package.scala similarity index 56% rename from akka-http/src/main/scala/pl/iterators/kebs/unmarshallers/enums/package.scala rename to http4s-stir/src/main/scala-2/pl/iterators/kebs/http4sstir/unmarshallers/enums/package.scala index a4fa82c6..515fbd46 100644 --- a/akka-http/src/main/scala/pl/iterators/kebs/unmarshallers/enums/package.scala +++ b/http4s-stir/src/main/scala-2/pl/iterators/kebs/http4sstir/unmarshallers/enums/package.scala @@ -1,3 +1,3 @@ -package pl.iterators.kebs.unmarshallers +package pl.iterators.kebs.http4sstir package object enums extends KebsEnumUnmarshallers diff --git a/http4s-stir/src/main/scala-2/unmarshallers/enums/KebsEnumUnmarshallers.scala b/http4s-stir/src/main/scala-2/unmarshallers/enums/KebsEnumUnmarshallers.scala deleted file mode 100644 index 7fcb0d91..00000000 --- a/http4s-stir/src/main/scala-2/unmarshallers/enums/KebsEnumUnmarshallers.scala +++ /dev/null @@ -1,48 +0,0 @@ -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 {} diff --git a/http4s-stir/src/main/scala-3/matchers/KebsMatchers.scala b/http4s-stir/src/main/scala-3/matchers/KebsMatchers.scala deleted file mode 100644 index 57b8d1c2..00000000 --- a/http4s-stir/src/main/scala-3/matchers/KebsMatchers.scala +++ /dev/null @@ -1,26 +0,0 @@ -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(", ")}"""))) - } - } -} diff --git a/http4s-stir/src/main/scala-3/pl/iterators/kebs/http4sstir/matchers/KebsMatchers.scala b/http4s-stir/src/main/scala-3/pl/iterators/kebs/http4sstir/matchers/KebsMatchers.scala new file mode 100644 index 00000000..643a5866 --- /dev/null +++ b/http4s-stir/src/main/scala-3/pl/iterators/kebs/http4sstir/matchers/KebsMatchers.scala @@ -0,0 +1,26 @@ +package pl.iterators.kebs.http4sstir.matchers + +import pl.iterators.stir.server.PathMatcher1 +import scala.reflect.Enum +import pl.iterators.kebs.core.enums.EnumLike +import pl.iterators.kebs.core.macros.ValueClassLike +import pl.iterators.kebs.core.instances.InstanceConverter + +import scala.language.implicitConversions + +trait KebsMatchers extends pl.iterators.stir.server.PathMatchers { + + implicit class SegmentIsomorphism[U](segment: PathMatcher1[U]) { + def as[T](implicit rep: ValueClassLike[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: EnumLike[T]): PathMatcher1[T] = { + Segment.map(s => e.values.find(_.toString().toLowerCase() == s.toLowerCase()).getOrElse(throw new IllegalArgumentException(s"""Invalid value '$s'. Expected one of: ${e.values.mkString(", ")}"""))) + } + } +} diff --git a/http4s-stir/src/main/scala-3/pl/iterators/kebs/http4sstir/unmarshallers/enums/KebsEnumUnmarshallers.scala b/http4s-stir/src/main/scala-3/pl/iterators/kebs/http4sstir/unmarshallers/enums/KebsEnumUnmarshallers.scala new file mode 100644 index 00000000..8ec85f67 --- /dev/null +++ b/http4s-stir/src/main/scala-3/pl/iterators/kebs/http4sstir/unmarshallers/enums/KebsEnumUnmarshallers.scala @@ -0,0 +1,58 @@ +package pl.iterators.kebs.http4sstir.unmarshallers.enums + +import cats.effect.IO +import pl.iterators.stir.unmarshalling.PredefinedFromStringUnmarshallers.* +import pl.iterators.stir.unmarshalling.{FromStringUnmarshaller, Unmarshaller} + +import scala.reflect.{ClassTag, Enum} +import scala.reflect.Selectable.reflectiveSelectable + +import pl.iterators.kebs.core.enums.{EnumLike, ValueEnumLike, ValueEnumLikeEntry} + +trait EnumUnmarshallers { + final def enumUnmarshaller[E <: Enum](using e: EnumLike[E]): FromStringUnmarshaller[E] = Unmarshaller { name => + e.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.values.mkString(", ")}""")) + } + } + + given kebsEnumUnmarshaller[E <: Enum](using e: EnumLike[E]): FromStringUnmarshaller[E] = + enumUnmarshaller +} + +trait ValueEnumUnmarshallers extends EnumUnmarshallers { + final def valueEnumUnmarshaller[V, E <: ValueEnumLikeEntry[V]](using `enum`: ValueEnumLike[V, E], cls: ClassTag[V]): Unmarshaller[V, E] = + Unmarshaller { + v => + `enum`.values.find(e => e.value == v && e.value.getClass == v.getClass) match { + case Some(enumEntry) => + IO.pure(enumEntry) + case _ => + `enum`.values.find(e => e.value == v) match { + case Some(enumEntry) => + IO.raiseError(new IllegalArgumentException(s"""Invalid value '$v'""")) + case None => + IO.raiseError(new IllegalArgumentException(s"""Invalid value '$v'. Expected one of: ${`enum`.values.map(_.value).mkString(", ")}""")) + } + } + } + + given 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] = + intFromStringUnmarshaller andThen valueEnumUnmarshaller + + given 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] = + shortFromStringUnmarshaller andThen valueEnumUnmarshaller + + given kebsByteValueEnumFromStringUnmarshaller[E <: ValueEnumLikeEntry[Byte]](using ev: ValueEnumLike[Byte, E]): FromStringUnmarshaller[E] = + byteFromStringUnmarshaller andThen valueEnumUnmarshaller +} + +trait KebsEnumUnmarshallers extends ValueEnumUnmarshallers {} diff --git a/http4s-stir/src/main/scala-3/unmarshallers/enums/package.scala b/http4s-stir/src/main/scala-3/pl/iterators/kebs/http4sstir/unmarshallers/enums/package.scala similarity index 50% rename from http4s-stir/src/main/scala-3/unmarshallers/enums/package.scala rename to http4s-stir/src/main/scala-3/pl/iterators/kebs/http4sstir/unmarshallers/enums/package.scala index a4fa82c6..7b6c5418 100644 --- a/http4s-stir/src/main/scala-3/unmarshallers/enums/package.scala +++ b/http4s-stir/src/main/scala-3/pl/iterators/kebs/http4sstir/unmarshallers/enums/package.scala @@ -1,3 +1,3 @@ -package pl.iterators.kebs.unmarshallers +package pl.iterators.kebs.http4sstir.unmarshallers package object enums extends KebsEnumUnmarshallers diff --git a/http4s-stir/src/main/scala-3/unmarshallers/enums/KebsEnumUnmarshallers.scala b/http4s-stir/src/main/scala-3/unmarshallers/enums/KebsEnumUnmarshallers.scala deleted file mode 100644 index 54270cd6..00000000 --- a/http4s-stir/src/main/scala-3/unmarshallers/enums/KebsEnumUnmarshallers.scala +++ /dev/null @@ -1,47 +0,0 @@ -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 {} diff --git a/http4s-stir/src/main/scala/pl/iterators/kebs/http4sstir/matchers/package.scala b/http4s-stir/src/main/scala/pl/iterators/kebs/http4sstir/matchers/package.scala new file mode 100644 index 00000000..02aa9490 --- /dev/null +++ b/http4s-stir/src/main/scala/pl/iterators/kebs/http4sstir/matchers/package.scala @@ -0,0 +1,5 @@ +package pl.iterators.kebs.http4sstir + +import pl.iterators.kebs.http4sstir.matchers.KebsMatchers + +package object matchers extends KebsMatchers diff --git a/http4s-stir/src/main/scala/pl/iterators/kebs/unmarshallers/KebsUnmarshallers.scala b/http4s-stir/src/main/scala/pl/iterators/kebs/http4sstir/unmarshallers/KebsUnmarshallers.scala similarity index 61% rename from http4s-stir/src/main/scala/pl/iterators/kebs/unmarshallers/KebsUnmarshallers.scala rename to http4s-stir/src/main/scala/pl/iterators/kebs/http4sstir/unmarshallers/KebsUnmarshallers.scala index df5f2607..045613f1 100644 --- a/http4s-stir/src/main/scala/pl/iterators/kebs/unmarshallers/KebsUnmarshallers.scala +++ b/http4s-stir/src/main/scala/pl/iterators/kebs/http4sstir/unmarshallers/KebsUnmarshallers.scala @@ -1,12 +1,12 @@ -package pl.iterators.kebs.unmarshallers +package pl.iterators.kebs.http4sstir.unmarshallers +import pl.iterators.kebs.core.instances.InstanceConverter +import pl.iterators.kebs.core.macros.{CaseClass1ToValueClass, ValueClassLike} import pl.iterators.stir.unmarshalling.{FromStringUnmarshaller, Unmarshaller} -import pl.iterators.kebs.instances.InstanceConverter -import pl.iterators.kebs.macros.CaseClass1Rep -trait KebsUnmarshallers extends LowPriorityKebsUnmarshallers { +trait KebsUnmarshallers extends LowPriorityKebsUnmarshallers with CaseClass1ToValueClass { @inline - implicit def kebsFromStringUnmarshaller[A, B](implicit rep: CaseClass1Rep[B, A], + implicit def kebsFromStringUnmarshaller[A, B](implicit rep: ValueClassLike[B, A], fsu: FromStringUnmarshaller[A]): FromStringUnmarshaller[B] = fsu andThen kebsUnmarshaller(rep) @@ -22,6 +22,6 @@ 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] = + implicit def kebsUnmarshaller[A, B](implicit rep: ValueClassLike[B, A]): Unmarshaller[A, B] = Unmarshaller.strict[A, B](rep.apply) } \ No newline at end of file diff --git a/akka-http/src/main/scala/pl/iterators/kebs/unmarshallers/package.scala b/http4s-stir/src/main/scala/pl/iterators/kebs/http4sstir/unmarshallers/package.scala similarity index 60% rename from akka-http/src/main/scala/pl/iterators/kebs/unmarshallers/package.scala rename to http4s-stir/src/main/scala/pl/iterators/kebs/http4sstir/unmarshallers/package.scala index 6fd93de3..1e711bc3 100644 --- a/akka-http/src/main/scala/pl/iterators/kebs/unmarshallers/package.scala +++ b/http4s-stir/src/main/scala/pl/iterators/kebs/http4sstir/unmarshallers/package.scala @@ -1,3 +1,3 @@ -package pl.iterators.kebs +package pl.iterators.kebs.http4sstir package object unmarshallers extends KebsUnmarshallers diff --git a/http4s-stir/src/test/scala-2/pl/iterators/kebs/Http4sStirTagsDomain.scala b/http4s-stir/src/test/scala-2/pl/iterators/kebs/http4sstir/domain/Http4sStirTagsDomain.scala similarity index 92% rename from http4s-stir/src/test/scala-2/pl/iterators/kebs/Http4sStirTagsDomain.scala rename to http4s-stir/src/test/scala-2/pl/iterators/kebs/http4sstir/domain/Http4sStirTagsDomain.scala index f0661a1e..554df6f0 100644 --- a/http4s-stir/src/test/scala-2/pl/iterators/kebs/Http4sStirTagsDomain.scala +++ b/http4s-stir/src/test/scala-2/pl/iterators/kebs/http4sstir/domain/Http4sStirTagsDomain.scala @@ -1,9 +1,10 @@ -package pl.iterators.kebs +package pl.iterators.kebs.http4sstir.domain import enumeratum.values.{IntEnum, IntEnumEntry, StringEnum, StringEnumEntry} import enumeratum.{Enum, EnumEntry} import pl.iterators.kebs.tag.meta.tagged import pl.iterators.kebs.tagged._ +import pl.iterators.kebs.core.enums.ValueEnumLikeEntry import java.net.URI import java.util.UUID @@ -47,7 +48,7 @@ object Domain extends Tags { val values = findValues } - sealed abstract class LibraryItem(val value: Int) extends IntEnumEntry + sealed abstract class LibraryItem(val value: Int) extends IntEnumEntry with ValueEnumLikeEntry[Int] object LibraryItem extends IntEnum[LibraryItem] { case object Book extends LibraryItem(1) @@ -63,7 +64,7 @@ object Domain extends Tags { case class Blue(value: Int) case class Color(red: Red, green: Green, blue: Blue) - sealed abstract class ShirtSize(val value: String) extends StringEnumEntry + sealed abstract class ShirtSize(val value: String) extends StringEnumEntry with ValueEnumLikeEntry[String] object ShirtSize extends StringEnum[ShirtSize] { case object Small extends ShirtSize("S") case object Medium extends ShirtSize("M") diff --git a/http4s-stir/src/test/scala-2/pl/iterators/kebs/matchers/Http4sStirMatchersTests.scala b/http4s-stir/src/test/scala-2/pl/iterators/kebs/http4sstir/matchers/Http4sStirMatchersTests.scala similarity index 83% rename from http4s-stir/src/test/scala-2/pl/iterators/kebs/matchers/Http4sStirMatchersTests.scala rename to http4s-stir/src/test/scala-2/pl/iterators/kebs/http4sstir/matchers/Http4sStirMatchersTests.scala index 70b85554..acb85bbf 100644 --- a/http4s-stir/src/test/scala-2/pl/iterators/kebs/matchers/Http4sStirMatchersTests.scala +++ b/http4s-stir/src/test/scala-2/pl/iterators/kebs/http4sstir/matchers/Http4sStirMatchersTests.scala @@ -1,14 +1,14 @@ -package pl.iterators.kebs.matchers +package pl.iterators.kebs.http4sstir.matchers import pl.iterators.stir.server.Directives import pl.iterators.stir.testkit.ScalatestRouteTest import org.scalatest.concurrent.ScalaFutures import org.scalatest.funsuite.AnyFunSuite import org.scalatest.matchers.should.Matchers -import pl.iterators.kebs.Domain._ import pl.iterators.kebs.instances.net.URIString -import pl.iterators.kebs.instances.time.mixins.InstantEpochMilliLong import pl.iterators.kebs.instances.time.{DayOfWeekInt, ZonedDateTimeString} +import pl.iterators.kebs.instances.time.mixins.InstantEpochMilliLong +import pl.iterators.kebs.http4sstir.domain.Domain._ import java.net.URI import java.time.{DayOfWeek, Instant, ZonedDateTime} @@ -25,15 +25,15 @@ class Http4sStirMatchersTests with URIString { implicit def runtime: cats.effect.unsafe.IORuntime = cats.effect.unsafe.IORuntime.global - test("No CaseClass1Rep implicits derived") { - import pl.iterators.kebs.macros.CaseClass1Rep + test("No ValueClassLike implicits derived") { + import pl.iterators.kebs.core.macros.ValueClassLike - "implicitly[CaseClass1Rep[DayOfWeek, Int]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[Int, DayOfWeek]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[Instant, Long]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[Long, Instant]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[URI, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, URI]]" shouldNot typeCheck + "implicitly[ValueClassLike[DayOfWeek, Int]]" shouldNot typeCheck + "implicitly[ValueClassLike[Int, DayOfWeek]]" shouldNot typeCheck + "implicitly[ValueClassLike[Instant, Long]]" shouldNot typeCheck + "implicitly[ValueClassLike[Long, Instant]]" shouldNot typeCheck + "implicitly[ValueClassLike[URI, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, URI]]" shouldNot typeCheck } test("Extract String to ZonedDateTime") { diff --git a/http4s-stir/src/test/scala-2/pl/iterators/kebs/unmarshallers/Http4sStirUnmarshallersTests.scala b/http4s-stir/src/test/scala-2/pl/iterators/kebs/http4sstir/unmarshallers/Http4sStirUnmarshallersTests.scala similarity index 86% rename from http4s-stir/src/test/scala-2/pl/iterators/kebs/unmarshallers/Http4sStirUnmarshallersTests.scala rename to http4s-stir/src/test/scala-2/pl/iterators/kebs/http4sstir/unmarshallers/Http4sStirUnmarshallersTests.scala index 3deb6c04..90d8e07f 100644 --- a/http4s-stir/src/test/scala-2/pl/iterators/kebs/unmarshallers/Http4sStirUnmarshallersTests.scala +++ b/http4s-stir/src/test/scala-2/pl/iterators/kebs/http4sstir/unmarshallers/Http4sStirUnmarshallersTests.scala @@ -1,4 +1,4 @@ -package pl.iterators.kebs.unmarshallers +package pl.iterators.kebs.http4sstir.unmarshallers import org.http4s.UrlForm import pl.iterators.stir.server.{Directives, MalformedQueryParamRejection} @@ -6,10 +6,12 @@ import pl.iterators.stir.testkit.ScalatestRouteTest import org.scalatest.concurrent.ScalaFutures import org.scalatest.funsuite.AnyFunSuite import org.scalatest.matchers.should.Matchers -import pl.iterators.kebs.Domain._ import pl.iterators.kebs.instances.net.URIString import pl.iterators.kebs.instances.time.{DayOfWeekInt, YearMonthString} -import pl.iterators.kebs.unmarshallers.enums.KebsEnumUnmarshallers +import pl.iterators.kebs.http4sstir.domain.Domain._ +import pl.iterators.kebs.enumeratum.{KebsEnumeratum, KebsValueEnumeratum} +import pl.iterators.kebs.http4sstir.enums.KebsEnumUnmarshallers +import pl.iterators.kebs.http4sstir.unmarshallers.KebsUnmarshallers import java.time.{DayOfWeek, YearMonth} @@ -23,18 +25,20 @@ class Http4sStirUnmarshallersTests with KebsEnumUnmarshallers with URIString with YearMonthString - with DayOfWeekInt { + with DayOfWeekInt + with KebsEnumeratum + with KebsValueEnumeratum { implicit def runtime: cats.effect.unsafe.IORuntime = cats.effect.unsafe.IORuntime.global - test("No CaseClass1Rep implicits derived") { - import pl.iterators.kebs.macros.CaseClass1Rep + test("No ValueClassLike implicits derived") { + import pl.iterators.kebs.core.macros.ValueClassLike - "implicitly[CaseClass1Rep[URI, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, URI]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[YearMonth, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, YearMonth]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[DayOfWeek, Int]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[Int, DayOfWeek]]" shouldNot typeCheck + "implicitly[ValueClassLike[URI, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, URI]]" shouldNot typeCheck + "implicitly[ValueClassLike[YearMonth, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, YearMonth]]" shouldNot typeCheck + "implicitly[ValueClassLike[DayOfWeek, Int]]" shouldNot typeCheck + "implicitly[ValueClassLike[Int, DayOfWeek]]" shouldNot typeCheck } test("Unmarshalling parameter") { diff --git a/http4s-stir/src/test/scala-3/pl/iterators/kebs/Http4sStirTagsDomain.scala b/http4s-stir/src/test/scala-3/pl/iterators/kebs/http4sstir/domain/Http4sStirTagsDomain.scala similarity index 80% rename from http4s-stir/src/test/scala-3/pl/iterators/kebs/Http4sStirTagsDomain.scala rename to http4s-stir/src/test/scala-3/pl/iterators/kebs/http4sstir/domain/Http4sStirTagsDomain.scala index 62cccb5b..32cf2900 100644 --- a/http4s-stir/src/test/scala-3/pl/iterators/kebs/Http4sStirTagsDomain.scala +++ b/http4s-stir/src/test/scala-3/pl/iterators/kebs/http4sstir/domain/Http4sStirTagsDomain.scala @@ -1,10 +1,11 @@ -package pl.iterators.kebs +package pl.iterators.kebs.http4sstir.domain import pl.iterators.kebs.opaque.Opaque import java.net.URI import java.util.UUID -import pl.iterators.kebs.enums.ValueEnum + +import pl.iterators.kebs.core.enums.ValueEnumLikeEntry object Domain { opaque type TestTaggedUri = URI @@ -24,7 +25,7 @@ object Domain { } - enum LibraryItem(val value: Int) extends ValueEnum[Int] { + enum LibraryItem(val value: Int) extends ValueEnumLikeEntry[Int] { case Book extends LibraryItem(1) case Movie extends LibraryItem(2) case Magazine extends LibraryItem(3) @@ -37,7 +38,7 @@ object Domain { case class Color(red: Red, green: Green, blue: Blue) - enum ShirtSize(val value: String) extends ValueEnum[String] { + enum ShirtSize(val value: String) extends ValueEnumLikeEntry[String] { case Small extends ShirtSize("S") case Medium extends ShirtSize("M") case Large extends ShirtSize("L") diff --git a/http4s-stir/src/test/scala-3/pl/iterators/kebs/matchers/Http4sStirMatchersTests.scala b/http4s-stir/src/test/scala-3/pl/iterators/kebs/http4sstir/matchers/Http4sStirMatchersTests.scala similarity index 74% rename from http4s-stir/src/test/scala-3/pl/iterators/kebs/matchers/Http4sStirMatchersTests.scala rename to http4s-stir/src/test/scala-3/pl/iterators/kebs/http4sstir/matchers/Http4sStirMatchersTests.scala index ad6e3b41..b3bf563c 100644 --- a/http4s-stir/src/test/scala-3/pl/iterators/kebs/matchers/Http4sStirMatchersTests.scala +++ b/http4s-stir/src/test/scala-3/pl/iterators/kebs/http4sstir/matchers/Http4sStirMatchersTests.scala @@ -1,14 +1,17 @@ -package pl.iterators.kebs.matchers +package pl.iterators.kebs.http4sstir.matchers import pl.iterators.stir.server.Directives import pl.iterators.stir.testkit.ScalatestRouteTest import org.scalatest.concurrent.ScalaFutures import org.scalatest.funsuite.AnyFunSuite import org.scalatest.matchers.should.Matchers -import pl.iterators.kebs.Domain._ import pl.iterators.kebs.instances.net.URIString -import pl.iterators.kebs.instances.time.mixins.InstantEpochMilliLong import pl.iterators.kebs.instances.time.{DayOfWeekInt, ZonedDateTimeString} +import pl.iterators.kebs.instances.time.mixins.InstantEpochMilliLong +import pl.iterators.kebs.http4sstir.domain.Domain._ + +import pl.iterators.kebs.enums.{KebsEnum, KebsValueEnum} +import pl.iterators.kebs.instances import java.net.URI import java.time.{DayOfWeek, Instant, ZonedDateTime} @@ -22,18 +25,20 @@ class Http4sStirMatchersTests with ZonedDateTimeString with DayOfWeekInt with InstantEpochMilliLong - with URIString { + with URIString + with KebsEnum + with KebsValueEnum{ implicit def runtime: cats.effect.unsafe.IORuntime = cats.effect.unsafe.IORuntime.global - test("No CaseClass1Rep implicits derived") { - import pl.iterators.kebs.macros.CaseClass1Rep + test("No ValueClassLike implicits derived") { + import pl.iterators.kebs.core.macros.ValueClassLike - "implicitly[CaseClass1Rep[DayOfWeek, Int]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[Int, DayOfWeek]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[Instant, Long]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[Long, Instant]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[URI, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, URI]]" shouldNot typeCheck + "implicitly[ValueClassLike[DayOfWeek, Int]]" shouldNot typeCheck + "implicitly[ValueClassLike[Int, DayOfWeek]]" shouldNot typeCheck + "implicitly[ValueClassLike[Instant, Long]]" shouldNot typeCheck + "implicitly[ValueClassLike[Long, Instant]]" shouldNot typeCheck + "implicitly[ValueClassLike[URI, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, URI]]" shouldNot typeCheck } test("Extract String to ZonedDateTime") { diff --git a/http4s-stir/src/test/scala-3/pl/iterators/kebs/unmarshallers/Http4sStirUnmarshallersTests.scala b/http4s-stir/src/test/scala-3/pl/iterators/kebs/http4sstir/unmarshallers/Http4sStirUnmarshallersTests.scala similarity index 83% rename from http4s-stir/src/test/scala-3/pl/iterators/kebs/unmarshallers/Http4sStirUnmarshallersTests.scala rename to http4s-stir/src/test/scala-3/pl/iterators/kebs/http4sstir/unmarshallers/Http4sStirUnmarshallersTests.scala index a0dabbed..61c5e58e 100644 --- a/http4s-stir/src/test/scala-3/pl/iterators/kebs/unmarshallers/Http4sStirUnmarshallersTests.scala +++ b/http4s-stir/src/test/scala-3/pl/iterators/kebs/http4sstir/unmarshallers/Http4sStirUnmarshallersTests.scala @@ -1,4 +1,4 @@ -package pl.iterators.kebs.unmarshallers +package pl.iterators.kebs.http4sstir.unmarshallers import org.http4s.UrlForm import pl.iterators.stir.server.{Directives, MalformedQueryParamRejection} @@ -6,10 +6,13 @@ import pl.iterators.stir.testkit.ScalatestRouteTest import org.scalatest.concurrent.ScalaFutures import org.scalatest.funsuite.AnyFunSuite import org.scalatest.matchers.should.Matchers -import pl.iterators.kebs.Domain._ +import pl.iterators.kebs.http4sstir.domain.Domain._ import pl.iterators.kebs.instances.net.URIString -import pl.iterators.kebs.instances.time.{DayOfWeekInt, YearMonthString} -import pl.iterators.kebs.unmarshallers.enums.KebsEnumUnmarshallers +import pl.iterators.kebs.instances.time.{DayOfWeekInt, ZonedDateTimeString, YearMonthString} +import pl.iterators.kebs.instances.time.mixins.InstantEpochMilliLong +import pl.iterators.kebs.core.macros.CaseClass1ToValueClass +import pl.iterators.kebs.enums.{KebsEnum, KebsValueEnum} +import pl.iterators.kebs.http4sstir.unmarshallers.enums.KebsEnumUnmarshallers import java.time.{DayOfWeek, YearMonth} @@ -23,18 +26,22 @@ class Http4sStirUnmarshallersTests with KebsEnumUnmarshallers with URIString with YearMonthString - with DayOfWeekInt { + with DayOfWeekInt + with KebsEnum + with KebsValueEnum + with CaseClass1ToValueClass + { implicit def runtime: cats.effect.unsafe.IORuntime = cats.effect.unsafe.IORuntime.global - test("No CaseClass1Rep implicits derived") { - import pl.iterators.kebs.macros.CaseClass1Rep + test("No ValueClassLike implicits derived") { + import pl.iterators.kebs.core.macros.ValueClassLike - "implicitly[CaseClass1Rep[URI, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, URI]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[YearMonth, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, YearMonth]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[DayOfWeek, Int]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[Int, DayOfWeek]]" shouldNot typeCheck + "implicitly[ValueClassLike[URI, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, URI]]" shouldNot typeCheck + "implicitly[ValueClassLike[YearMonth, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, YearMonth]]" shouldNot typeCheck + "implicitly[ValueClassLike[DayOfWeek, Int]]" shouldNot typeCheck + "implicitly[ValueClassLike[Int, DayOfWeek]]" shouldNot typeCheck } test("Unmarshalling parameter") { diff --git a/http4s/src/main/scala-2/pl/iterators/kebs/Http4s.scala b/http4s/src/main/scala-2/pl/iterators/kebs/Http4s.scala deleted file mode 100644 index eac47ae9..00000000 --- a/http4s/src/main/scala-2/pl/iterators/kebs/Http4s.scala +++ /dev/null @@ -1,61 +0,0 @@ -package pl.iterators.kebs - -import enumeratum.EnumEntry - -import scala.util.Try -import pl.iterators.kebs.macros.CaseClass1Rep -import pl.iterators.kebs.macros.enums.EnumOf -import org.http4s._ -import pl.iterators.kebs.instances.InstanceConverter - -import java.util.UUID - -trait Http4s { - protected class PathVar[A](cast: String => Try[A]) { - def unapply(str: String): Option[A] = - if (str.nonEmpty) - cast(str).toOption - else - None - } - - object WrappedString { - def apply[T](implicit rep: CaseClass1Rep[T, String]) = new PathVar[T](str => Try(rep.apply(str))) - } - - object InstanceString { - def apply[T](implicit rep: InstanceConverter[T, String]) = new PathVar[T](str => Try(rep.decode(str))) - } - - object EnumString { - def apply[T <: EnumEntry](implicit e: EnumOf[T]) = new PathVar[T](str => Try(e.`enum`.values.find(_.toString.toUpperCase == str.toUpperCase).getOrElse(throw new IllegalArgumentException(s"enum case not found: $str")))) - } - - object WrappedInt { - def apply[T](implicit rep: CaseClass1Rep[T, Int]) = new PathVar[T](str => Try(rep.apply(str.toInt))) - } - - object InstanceInt { - def apply[T](implicit rep: InstanceConverter[T, Int]) = new PathVar[T](str => Try(rep.decode(str.toInt))) - } - - object WrappedLong { - def apply[T](implicit rep: CaseClass1Rep[T, Long]) = new PathVar[T](str => Try(rep.apply(str.toLong))) - } - - object InstanceLong { - def apply[T](implicit rep: InstanceConverter[T, Long]) = new PathVar[T](str => Try(rep.decode(str.toLong))) - } - - object WrappedUUID { - def apply[T](implicit rep: CaseClass1Rep[T, UUID]) = new PathVar[T](str => Try(rep.apply(UUID.fromString(str)))) - } - - object InstanceUUID { - def apply[T](implicit rep: InstanceConverter[T, UUID]) = new PathVar[T](str => Try(rep.decode(UUID.fromString(str)))) - } - - implicit def cc1RepQueryParamDecoder[T, U](implicit rep: CaseClass1Rep[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](implicit 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 <: EnumEntry](implicit e: EnumOf[E]): QueryParamDecoder[E] = QueryParamDecoder[String].emap(str => Try(e.`enum`.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))) -} diff --git a/http4s/src/main/scala-2/pl/iterators/kebs/http4s/Http4s.scala b/http4s/src/main/scala-2/pl/iterators/kebs/http4s/Http4s.scala new file mode 100644 index 00000000..ad63a772 --- /dev/null +++ b/http4s/src/main/scala-2/pl/iterators/kebs/http4s/Http4s.scala @@ -0,0 +1,59 @@ +package pl.iterators.kebs.http4s + +import org.http4s._ +import pl.iterators.kebs.core.enums.EnumLike +import pl.iterators.kebs.core.instances.InstanceConverter +import pl.iterators.kebs.core.macros.{CaseClass1ToValueClass, ValueClassLike} + +import java.util.UUID +import scala.util.Try + +trait Http4s extends CaseClass1ToValueClass { + protected class PathVar[A](cast: String => Try[A]) { + def unapply(str: String): Option[A] = + if (str.nonEmpty) + cast(str).toOption + else + None + } + + object WrappedString { + def apply[T](implicit rep: ValueClassLike[T, String]) = new PathVar[T](str => Try(rep.apply(str))) + } + + object InstanceString { + def apply[T](implicit rep: InstanceConverter[T, String]) = new PathVar[T](str => Try(rep.decode(str))) + } + + object EnumString { + def apply[T](implicit e: EnumLike[T]) = new PathVar[T](str => Try(e.values.find(_.toString.toUpperCase == str.toUpperCase).getOrElse(throw new IllegalArgumentException(s"enum case not found: $str")))) + } + + object WrappedInt { + def apply[T](implicit rep: ValueClassLike[T, Int]) = new PathVar[T](str => Try(rep.apply(str.toInt))) + } + + object InstanceInt { + def apply[T](implicit rep: InstanceConverter[T, Int]) = new PathVar[T](str => Try(rep.decode(str.toInt))) + } + + object WrappedLong { + def apply[T](implicit rep: ValueClassLike[T, Long]) = new PathVar[T](str => Try(rep.apply(str.toLong))) + } + + object InstanceLong { + def apply[T](implicit rep: InstanceConverter[T, Long]) = new PathVar[T](str => Try(rep.decode(str.toLong))) + } + + object WrappedUUID { + def apply[T](implicit rep: ValueClassLike[T, UUID]) = new PathVar[T](str => Try(rep.apply(UUID.fromString(str)))) + } + + object InstanceUUID { + def apply[T](implicit rep: InstanceConverter[T, UUID]) = new PathVar[T](str => Try(rep.decode(UUID.fromString(str)))) + } + + implicit def vcLikeQueryParamDecoder[T, U](implicit 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](implicit 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](implicit 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))) +} diff --git a/http4s/src/main/scala-3/pl/iterators/kebs/http4s/package.scala b/http4s/src/main/scala-3/pl/iterators/kebs/http4s/package.scala index 886045b9..528671c0 100644 --- a/http4s/src/main/scala-3/pl/iterators/kebs/http4s/package.scala +++ b/http4s/src/main/scala-3/pl/iterators/kebs/http4s/package.scala @@ -2,10 +2,10 @@ package pl.iterators.kebs.http4s import scala.util.Try import scala.reflect.Enum -import pl.iterators.kebs.macros.CaseClass1Rep -import pl.iterators.kebs.macros.enums.EnumOf +import pl.iterators.kebs.core.enums.EnumLike +import pl.iterators.kebs.core.macros.ValueClassLike +import pl.iterators.kebs.core.instances.InstanceConverter import org.http4s._ -import pl.iterators.kebs.instances.InstanceConverter import java.util.UUID protected class PathVar[A](cast: String => Try[A]) { @@ -17,7 +17,7 @@ protected class PathVar[A](cast: String => Try[A]) { } object WrappedString { - def apply[T](using rep: CaseClass1Rep[T, String]) = new PathVar[T](str => Try(rep.apply(str))) + def apply[T](using rep: ValueClassLike[T, String]) = new PathVar[T](str => Try(rep.apply(str))) } object InstanceString { @@ -25,11 +25,11 @@ object InstanceString { } object EnumString { - def apply[T <: Enum](using e: EnumOf[T]) = new PathVar[T](str => Try(e.`enum`.values.find(_.toString.toUpperCase == str.toUpperCase).getOrElse(throw new IllegalArgumentException(s"enum case not found: $str")))) + def apply[T <: Enum](using e: EnumLike[T]) = new PathVar[T](str => Try(e.values.find(_.toString.toUpperCase == str.toUpperCase).getOrElse(throw new IllegalArgumentException(s"enum case not found: $str")))) } object WrappedInt { - def apply[T](using rep: CaseClass1Rep[T, Int]) = new PathVar[T](str => Try(rep.apply(str.toInt))) + def apply[T](using rep: ValueClassLike[T, Int]) = new PathVar[T](str => Try(rep.apply(str.toInt))) } object InstanceInt { @@ -37,7 +37,7 @@ object InstanceInt { } object WrappedLong { - def apply[T](using rep: CaseClass1Rep[T, Long]) = new PathVar[T](str => Try(rep.apply(str.toLong))) + def apply[T](using rep: ValueClassLike[T, Long]) = new PathVar[T](str => Try(rep.apply(str.toLong))) } object InstanceLong { @@ -45,13 +45,13 @@ object InstanceLong { } object WrappedUUID { - def apply[T](using rep: CaseClass1Rep[T, UUID]) = new PathVar[T](str => Try(rep.apply(UUID.fromString(str)))) + def apply[T](using rep: ValueClassLike[T, UUID]) = new PathVar[T](str => Try(rep.apply(UUID.fromString(str)))) } 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: CaseClass1Rep[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: 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: EnumOf[E]): QueryParamDecoder[E] = QueryParamDecoder[String].emap(str => Try(e.`enum`.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))) +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))) diff --git a/http4s/src/test/scala-2/pl/iterators/kebs/Http4sDslTests.scala b/http4s/src/test/scala-2/pl/iterators/kebs/http4s/Http4sDslTests.scala similarity index 91% rename from http4s/src/test/scala-2/pl/iterators/kebs/Http4sDslTests.scala rename to http4s/src/test/scala-2/pl/iterators/kebs/http4s/Http4sDslTests.scala index 18b7f51c..c6ab946e 100644 --- a/http4s/src/test/scala-2/pl/iterators/kebs/Http4sDslTests.scala +++ b/http4s/src/test/scala-2/pl/iterators/kebs/http4s/Http4sDslTests.scala @@ -1,4 +1,4 @@ -package pl.iterators.kebs +package pl.iterators.kebs.http4s import cats.effect.IO import cats.effect.unsafe.IORuntime @@ -7,14 +7,17 @@ import org.http4s.dsl.io._ import org.http4s.implicits._ import org.scalatest.funsuite.AnyFunSuite import org.scalatest.matchers.should.Matchers +import pl.iterators.kebs.instances.KebsInstances._ +import pl.iterators.kebs.enumeratum.KebsEnumeratum import java.time.Year import java.util.Currency import pl.iterators.kebs.instances.KebsInstances._ import pl.iterators.kebs.http4s._ +import pl.iterators.kebs.enumeratum.KebsEnumeratum -class Http4sDslTests extends AnyFunSuite with Matchers { - import Domain._ +class Http4sDslTests extends AnyFunSuite with Matchers with KebsEnumeratum { + import pl.iterators.kebs.http4s.domain.Domain._ implicit val runtime: IORuntime = cats.effect.unsafe.IORuntime.global diff --git a/http4s/src/test/scala-2/pl/iterators/kebs/Domain.scala b/http4s/src/test/scala-2/pl/iterators/kebs/http4s/domain/Domain.scala similarity index 94% rename from http4s/src/test/scala-2/pl/iterators/kebs/Domain.scala rename to http4s/src/test/scala-2/pl/iterators/kebs/http4s/domain/Domain.scala index 61952f89..eb3836b0 100644 --- a/http4s/src/test/scala-2/pl/iterators/kebs/Domain.scala +++ b/http4s/src/test/scala-2/pl/iterators/kebs/http4s/domain/Domain.scala @@ -1,4 +1,4 @@ -package pl.iterators.kebs +package pl.iterators.kebs.http4s.domain import enumeratum.{Enum, EnumEntry} import pl.iterators.kebs.tag.meta.tagged diff --git a/http4s/src/test/scala-3/pl/iterators/kebs/Domain.scala b/http4s/src/test/scala-3/pl/iterators/kebs/http4s/Domain.scala similarity index 91% rename from http4s/src/test/scala-3/pl/iterators/kebs/Domain.scala rename to http4s/src/test/scala-3/pl/iterators/kebs/http4s/Domain.scala index a0941dc6..1aadbfd9 100644 --- a/http4s/src/test/scala-3/pl/iterators/kebs/Domain.scala +++ b/http4s/src/test/scala-3/pl/iterators/kebs/http4s/Domain.scala @@ -1,4 +1,4 @@ -package pl.iterators.kebs +package pl.iterators.kebs.http4s import pl.iterators.kebs.opaque.Opaque diff --git a/http4s/src/test/scala-3/pl/iterators/kebs/Http4sDslTests.scala b/http4s/src/test/scala-3/pl/iterators/kebs/http4s/Http4sDslTests.scala similarity index 93% rename from http4s/src/test/scala-3/pl/iterators/kebs/Http4sDslTests.scala rename to http4s/src/test/scala-3/pl/iterators/kebs/http4s/Http4sDslTests.scala index 82bfa975..7ef85a75 100644 --- a/http4s/src/test/scala-3/pl/iterators/kebs/Http4sDslTests.scala +++ b/http4s/src/test/scala-3/pl/iterators/kebs/http4s/Http4sDslTests.scala @@ -1,4 +1,4 @@ -package pl.iterators.kebs +package pl.iterators.kebs.http4s import cats.effect.IO import cats.effect.unsafe.IORuntime @@ -12,8 +12,10 @@ import java.util.Currency import pl.iterators.kebs.instances.KebsInstances._ import pl.iterators.kebs.http4s.{given, _} +import pl.iterators.kebs.core.macros.CaseClass1ToValueClass +import pl.iterators.kebs.enums.KebsEnum -class Http4sDslTests extends AnyFunSuite with Matchers { +class Http4sDslTests extends AnyFunSuite with Matchers with KebsEnum with CaseClass1ToValueClass { import Domain._ given runtime: IORuntime = cats.effect.unsafe.IORuntime.global diff --git a/instances/src/main/scala/pl/iterators/kebs/instances/TimeInstances.scala b/instances/src/main/scala/pl/iterators/kebs/instances/TimeInstances.scala index f903b8c2..936d4089 100644 --- a/instances/src/main/scala/pl/iterators/kebs/instances/TimeInstances.scala +++ b/instances/src/main/scala/pl/iterators/kebs/instances/TimeInstances.scala @@ -1,6 +1,6 @@ package pl.iterators.kebs.instances -import pl.iterators.kebs.instances.time.{DurationString, PeriodString, _} +import pl.iterators.kebs.instances.time.{DayOfWeekInt, DurationString, InstantString, LocalDateString, LocalDateTimeString, LocalTimeString, MonthDayString, MonthInt, OffsetDateTimeString, OffsetTimeString, PeriodString, YearInt, YearMonthString, ZoneIdString, ZoneOffsetString, ZonedDateTimeString} trait TimeInstances extends InstantString diff --git a/instances/src/main/scala/pl/iterators/kebs/instances/net/URIString.scala b/instances/src/main/scala/pl/iterators/kebs/instances/net/URIString.scala index 57b2d46a..84a8e067 100644 --- a/instances/src/main/scala/pl/iterators/kebs/instances/net/URIString.scala +++ b/instances/src/main/scala/pl/iterators/kebs/instances/net/URIString.scala @@ -1,7 +1,7 @@ package pl.iterators.kebs.instances.net -import pl.iterators.kebs.instances.InstanceConverter -import pl.iterators.kebs.instances.net.URIString.URIFormat +import URIString.URIFormat +import pl.iterators.kebs.core.instances.InstanceConverter import java.net.URI diff --git a/instances/src/main/scala/pl/iterators/kebs/instances/time/DayOfWeekInt.scala b/instances/src/main/scala/pl/iterators/kebs/instances/time/DayOfWeekInt.scala index 3252eaed..927fced4 100644 --- a/instances/src/main/scala/pl/iterators/kebs/instances/time/DayOfWeekInt.scala +++ b/instances/src/main/scala/pl/iterators/kebs/instances/time/DayOfWeekInt.scala @@ -1,7 +1,7 @@ package pl.iterators.kebs.instances.time -import pl.iterators.kebs.instances.InstanceConverter -import pl.iterators.kebs.instances.time.DayOfWeekInt._ +import DayOfWeekInt._ +import pl.iterators.kebs.core.instances.InstanceConverter import java.time.DayOfWeek diff --git a/instances/src/main/scala/pl/iterators/kebs/instances/time/DurationString.scala b/instances/src/main/scala/pl/iterators/kebs/instances/time/DurationString.scala index 663cf19d..83a04913 100644 --- a/instances/src/main/scala/pl/iterators/kebs/instances/time/DurationString.scala +++ b/instances/src/main/scala/pl/iterators/kebs/instances/time/DurationString.scala @@ -1,7 +1,7 @@ package pl.iterators.kebs.instances.time -import pl.iterators.kebs.instances.InstanceConverter -import pl.iterators.kebs.instances.time.DurationString.DurationFormat +import DurationString.DurationFormat +import pl.iterators.kebs.core.instances.InstanceConverter import java.time.Duration diff --git a/instances/src/main/scala/pl/iterators/kebs/instances/time/InstantString.scala b/instances/src/main/scala/pl/iterators/kebs/instances/time/InstantString.scala index 24a2fda6..01eeb455 100644 --- a/instances/src/main/scala/pl/iterators/kebs/instances/time/InstantString.scala +++ b/instances/src/main/scala/pl/iterators/kebs/instances/time/InstantString.scala @@ -1,7 +1,7 @@ package pl.iterators.kebs.instances.time -import pl.iterators.kebs.instances.InstanceConverter -import pl.iterators.kebs.instances.time.InstantString.InstantFormat +import InstantString.InstantFormat +import pl.iterators.kebs.core.instances.InstanceConverter import java.time.Instant diff --git a/instances/src/main/scala/pl/iterators/kebs/instances/time/LocalDateString.scala b/instances/src/main/scala/pl/iterators/kebs/instances/time/LocalDateString.scala index 5ebbde0c..333a55d1 100644 --- a/instances/src/main/scala/pl/iterators/kebs/instances/time/LocalDateString.scala +++ b/instances/src/main/scala/pl/iterators/kebs/instances/time/LocalDateString.scala @@ -1,7 +1,7 @@ package pl.iterators.kebs.instances.time -import pl.iterators.kebs.instances.InstanceConverter -import pl.iterators.kebs.instances.time.LocalDateString.{LocalDateFormat, formatter} +import LocalDateString.{LocalDateFormat, formatter} +import pl.iterators.kebs.core.instances.InstanceConverter import java.time.LocalDate import java.time.format.DateTimeFormatter diff --git a/instances/src/main/scala/pl/iterators/kebs/instances/time/LocalDateTimeString.scala b/instances/src/main/scala/pl/iterators/kebs/instances/time/LocalDateTimeString.scala index 644dd6d9..3e977fdf 100644 --- a/instances/src/main/scala/pl/iterators/kebs/instances/time/LocalDateTimeString.scala +++ b/instances/src/main/scala/pl/iterators/kebs/instances/time/LocalDateTimeString.scala @@ -1,7 +1,7 @@ package pl.iterators.kebs.instances.time -import pl.iterators.kebs.instances.InstanceConverter -import pl.iterators.kebs.instances.time.LocalDateTimeString.{LocalDateTimeFormat, formatter} +import LocalDateTimeString.{LocalDateTimeFormat, formatter} +import pl.iterators.kebs.core.instances.InstanceConverter import java.time.LocalDateTime import java.time.format.DateTimeFormatter diff --git a/instances/src/main/scala/pl/iterators/kebs/instances/time/LocalTimeString.scala b/instances/src/main/scala/pl/iterators/kebs/instances/time/LocalTimeString.scala index 6a662292..dd5889dc 100644 --- a/instances/src/main/scala/pl/iterators/kebs/instances/time/LocalTimeString.scala +++ b/instances/src/main/scala/pl/iterators/kebs/instances/time/LocalTimeString.scala @@ -1,7 +1,7 @@ package pl.iterators.kebs.instances.time -import pl.iterators.kebs.instances.InstanceConverter -import pl.iterators.kebs.instances.time.LocalTimeString.{LocalTimeFormat, formatter} +import LocalTimeString.{LocalTimeFormat, formatter} +import pl.iterators.kebs.core.instances.InstanceConverter import java.time.LocalTime import java.time.format.DateTimeFormatter diff --git a/instances/src/main/scala/pl/iterators/kebs/instances/time/MonthDayString.scala b/instances/src/main/scala/pl/iterators/kebs/instances/time/MonthDayString.scala index 10983411..5e803679 100644 --- a/instances/src/main/scala/pl/iterators/kebs/instances/time/MonthDayString.scala +++ b/instances/src/main/scala/pl/iterators/kebs/instances/time/MonthDayString.scala @@ -1,7 +1,7 @@ package pl.iterators.kebs.instances.time -import pl.iterators.kebs.instances.InstanceConverter -import pl.iterators.kebs.instances.time.MonthDayString.{MonthDayFormat, formatter} +import MonthDayString.{MonthDayFormat, formatter} +import pl.iterators.kebs.core.instances.InstanceConverter import java.time.MonthDay import java.time.format.DateTimeFormatter diff --git a/instances/src/main/scala/pl/iterators/kebs/instances/time/MonthInt.scala b/instances/src/main/scala/pl/iterators/kebs/instances/time/MonthInt.scala index 76e987ca..20657a5a 100644 --- a/instances/src/main/scala/pl/iterators/kebs/instances/time/MonthInt.scala +++ b/instances/src/main/scala/pl/iterators/kebs/instances/time/MonthInt.scala @@ -1,7 +1,7 @@ package pl.iterators.kebs.instances.time -import pl.iterators.kebs.instances.InstanceConverter -import pl.iterators.kebs.instances.time.MonthInt.MonthFormat +import MonthInt.MonthFormat +import pl.iterators.kebs.core.instances.InstanceConverter import java.time.Month diff --git a/instances/src/main/scala/pl/iterators/kebs/instances/time/OffsetDateTimeString.scala b/instances/src/main/scala/pl/iterators/kebs/instances/time/OffsetDateTimeString.scala index b7ebd002..cbd68f09 100644 --- a/instances/src/main/scala/pl/iterators/kebs/instances/time/OffsetDateTimeString.scala +++ b/instances/src/main/scala/pl/iterators/kebs/instances/time/OffsetDateTimeString.scala @@ -1,7 +1,7 @@ package pl.iterators.kebs.instances.time -import pl.iterators.kebs.instances.InstanceConverter -import pl.iterators.kebs.instances.time.OffsetDateTimeString.{OffsetDateTimeFormat, formatter} +import OffsetDateTimeString.{OffsetDateTimeFormat, formatter} +import pl.iterators.kebs.core.instances.InstanceConverter import java.time.OffsetDateTime import java.time.format.DateTimeFormatter diff --git a/instances/src/main/scala/pl/iterators/kebs/instances/time/OffsetTimeString.scala b/instances/src/main/scala/pl/iterators/kebs/instances/time/OffsetTimeString.scala index 3bf7e637..81a74472 100644 --- a/instances/src/main/scala/pl/iterators/kebs/instances/time/OffsetTimeString.scala +++ b/instances/src/main/scala/pl/iterators/kebs/instances/time/OffsetTimeString.scala @@ -1,7 +1,7 @@ package pl.iterators.kebs.instances.time -import pl.iterators.kebs.instances.InstanceConverter -import pl.iterators.kebs.instances.time.OffsetTimeString.{OffsetTimeFormat, formatter} +import OffsetTimeString.{OffsetTimeFormat, formatter} +import pl.iterators.kebs.core.instances.InstanceConverter import java.time.OffsetTime import java.time.format.DateTimeFormatter diff --git a/instances/src/main/scala/pl/iterators/kebs/instances/time/PeriodString.scala b/instances/src/main/scala/pl/iterators/kebs/instances/time/PeriodString.scala index e6d7fde3..78f5e4bd 100644 --- a/instances/src/main/scala/pl/iterators/kebs/instances/time/PeriodString.scala +++ b/instances/src/main/scala/pl/iterators/kebs/instances/time/PeriodString.scala @@ -1,7 +1,7 @@ package pl.iterators.kebs.instances.time -import pl.iterators.kebs.instances.InstanceConverter -import pl.iterators.kebs.instances.time.PeriodString.PeriodFormat +import PeriodString.PeriodFormat +import pl.iterators.kebs.core.instances.InstanceConverter import java.time.Period diff --git a/instances/src/main/scala/pl/iterators/kebs/instances/time/YearInt.scala b/instances/src/main/scala/pl/iterators/kebs/instances/time/YearInt.scala index 244805e3..52dc6275 100644 --- a/instances/src/main/scala/pl/iterators/kebs/instances/time/YearInt.scala +++ b/instances/src/main/scala/pl/iterators/kebs/instances/time/YearInt.scala @@ -1,7 +1,7 @@ package pl.iterators.kebs.instances.time -import pl.iterators.kebs.instances.InstanceConverter -import pl.iterators.kebs.instances.time.YearInt.YearFormat +import YearInt.YearFormat +import pl.iterators.kebs.core.instances.InstanceConverter import java.time.Year diff --git a/instances/src/main/scala/pl/iterators/kebs/instances/time/YearMonthString.scala b/instances/src/main/scala/pl/iterators/kebs/instances/time/YearMonthString.scala index 7d579759..bb733ef5 100644 --- a/instances/src/main/scala/pl/iterators/kebs/instances/time/YearMonthString.scala +++ b/instances/src/main/scala/pl/iterators/kebs/instances/time/YearMonthString.scala @@ -1,7 +1,7 @@ package pl.iterators.kebs.instances.time -import pl.iterators.kebs.instances.InstanceConverter -import pl.iterators.kebs.instances.time.YearMonthString.{YearMonthFormat, formatter} +import YearMonthString.{YearMonthFormat, formatter} +import pl.iterators.kebs.core.instances.InstanceConverter import java.time.YearMonth import java.time.format.DateTimeFormatter diff --git a/instances/src/main/scala/pl/iterators/kebs/instances/time/ZoneIdString.scala b/instances/src/main/scala/pl/iterators/kebs/instances/time/ZoneIdString.scala index 33461a08..098bde54 100644 --- a/instances/src/main/scala/pl/iterators/kebs/instances/time/ZoneIdString.scala +++ b/instances/src/main/scala/pl/iterators/kebs/instances/time/ZoneIdString.scala @@ -1,7 +1,7 @@ package pl.iterators.kebs.instances.time -import pl.iterators.kebs.instances.InstanceConverter -import pl.iterators.kebs.instances.time.ZoneIdString.ZoneIdFormat +import ZoneIdString.ZoneIdFormat +import pl.iterators.kebs.core.instances.InstanceConverter import java.time.ZoneId diff --git a/instances/src/main/scala/pl/iterators/kebs/instances/time/ZoneOffsetString.scala b/instances/src/main/scala/pl/iterators/kebs/instances/time/ZoneOffsetString.scala index 1a74f1da..c91da8f2 100644 --- a/instances/src/main/scala/pl/iterators/kebs/instances/time/ZoneOffsetString.scala +++ b/instances/src/main/scala/pl/iterators/kebs/instances/time/ZoneOffsetString.scala @@ -1,7 +1,7 @@ package pl.iterators.kebs.instances.time -import pl.iterators.kebs.instances.InstanceConverter -import pl.iterators.kebs.instances.time.ZoneOffsetString.ZoneOffsetFormat +import ZoneOffsetString.ZoneOffsetFormat +import pl.iterators.kebs.core.instances.InstanceConverter import java.time.ZoneOffset diff --git a/instances/src/main/scala/pl/iterators/kebs/instances/time/ZonedDateTimeString.scala b/instances/src/main/scala/pl/iterators/kebs/instances/time/ZonedDateTimeString.scala index 29b944e7..f5fdef37 100644 --- a/instances/src/main/scala/pl/iterators/kebs/instances/time/ZonedDateTimeString.scala +++ b/instances/src/main/scala/pl/iterators/kebs/instances/time/ZonedDateTimeString.scala @@ -1,7 +1,7 @@ package pl.iterators.kebs.instances.time -import pl.iterators.kebs.instances.InstanceConverter -import pl.iterators.kebs.instances.time.ZonedDateTimeString.{ZonedDateTimeFormat, formatter} +import ZonedDateTimeString.{ZonedDateTimeFormat, formatter} +import pl.iterators.kebs.core.instances.InstanceConverter import java.time.ZonedDateTime import java.time.format.DateTimeFormatter diff --git a/instances/src/main/scala/pl/iterators/kebs/instances/time/mixins/DurationMillisLong.scala b/instances/src/main/scala/pl/iterators/kebs/instances/time/mixins/DurationMillisLong.scala index aad9a113..d7bc7bce 100644 --- a/instances/src/main/scala/pl/iterators/kebs/instances/time/mixins/DurationMillisLong.scala +++ b/instances/src/main/scala/pl/iterators/kebs/instances/time/mixins/DurationMillisLong.scala @@ -1,7 +1,6 @@ package pl.iterators.kebs.instances.time.mixins -import pl.iterators.kebs.instances.InstanceConverter - +import pl.iterators.kebs.core.instances.InstanceConverter import java.time.Duration trait DurationMillisLong { diff --git a/instances/src/main/scala/pl/iterators/kebs/instances/time/mixins/DurationMinutesLong.scala b/instances/src/main/scala/pl/iterators/kebs/instances/time/mixins/DurationMinutesLong.scala index 526e6be9..23bbee34 100644 --- a/instances/src/main/scala/pl/iterators/kebs/instances/time/mixins/DurationMinutesLong.scala +++ b/instances/src/main/scala/pl/iterators/kebs/instances/time/mixins/DurationMinutesLong.scala @@ -1,7 +1,6 @@ package pl.iterators.kebs.instances.time.mixins -import pl.iterators.kebs.instances.InstanceConverter - +import pl.iterators.kebs.core.instances.InstanceConverter import java.time.Duration trait DurationMinutesLong { diff --git a/instances/src/main/scala/pl/iterators/kebs/instances/time/mixins/DurationNanosLong.scala b/instances/src/main/scala/pl/iterators/kebs/instances/time/mixins/DurationNanosLong.scala index 4a1448f3..47258dc6 100644 --- a/instances/src/main/scala/pl/iterators/kebs/instances/time/mixins/DurationNanosLong.scala +++ b/instances/src/main/scala/pl/iterators/kebs/instances/time/mixins/DurationNanosLong.scala @@ -1,7 +1,6 @@ package pl.iterators.kebs.instances.time.mixins -import pl.iterators.kebs.instances.InstanceConverter - +import pl.iterators.kebs.core.instances.InstanceConverter import java.time.Duration trait DurationNanosLong { diff --git a/instances/src/main/scala/pl/iterators/kebs/instances/time/mixins/DurationSecondsLong.scala b/instances/src/main/scala/pl/iterators/kebs/instances/time/mixins/DurationSecondsLong.scala index 2d55f5df..633159e2 100644 --- a/instances/src/main/scala/pl/iterators/kebs/instances/time/mixins/DurationSecondsLong.scala +++ b/instances/src/main/scala/pl/iterators/kebs/instances/time/mixins/DurationSecondsLong.scala @@ -1,7 +1,6 @@ package pl.iterators.kebs.instances.time.mixins -import pl.iterators.kebs.instances.InstanceConverter - +import pl.iterators.kebs.core.instances.InstanceConverter import java.time.Duration trait DurationSecondsLong { diff --git a/instances/src/main/scala/pl/iterators/kebs/instances/time/mixins/InstantEpochMilliLong.scala b/instances/src/main/scala/pl/iterators/kebs/instances/time/mixins/InstantEpochMilliLong.scala index 77ade584..a4373b44 100644 --- a/instances/src/main/scala/pl/iterators/kebs/instances/time/mixins/InstantEpochMilliLong.scala +++ b/instances/src/main/scala/pl/iterators/kebs/instances/time/mixins/InstantEpochMilliLong.scala @@ -1,7 +1,6 @@ package pl.iterators.kebs.instances.time.mixins -import pl.iterators.kebs.instances.InstanceConverter - +import pl.iterators.kebs.core.instances.InstanceConverter import java.time.Instant trait InstantEpochMilliLong { diff --git a/instances/src/main/scala/pl/iterators/kebs/instances/time/mixins/InstantEpochSecondLong.scala b/instances/src/main/scala/pl/iterators/kebs/instances/time/mixins/InstantEpochSecondLong.scala index f23383a9..481062e1 100644 --- a/instances/src/main/scala/pl/iterators/kebs/instances/time/mixins/InstantEpochSecondLong.scala +++ b/instances/src/main/scala/pl/iterators/kebs/instances/time/mixins/InstantEpochSecondLong.scala @@ -1,7 +1,6 @@ package pl.iterators.kebs.instances.time.mixins -import pl.iterators.kebs.instances.InstanceConverter - +import pl.iterators.kebs.core.instances.InstanceConverter import java.time.Instant trait InstantEpochSecondLong { diff --git a/instances/src/main/scala/pl/iterators/kebs/instances/time/mixins/PeriodDays.scala b/instances/src/main/scala/pl/iterators/kebs/instances/time/mixins/PeriodDays.scala index 7395adf0..c9ee454e 100644 --- a/instances/src/main/scala/pl/iterators/kebs/instances/time/mixins/PeriodDays.scala +++ b/instances/src/main/scala/pl/iterators/kebs/instances/time/mixins/PeriodDays.scala @@ -1,7 +1,6 @@ package pl.iterators.kebs.instances.time.mixins -import pl.iterators.kebs.instances.InstanceConverter - +import pl.iterators.kebs.core.instances.InstanceConverter import java.time.Period trait PeriodDays { diff --git a/instances/src/main/scala/pl/iterators/kebs/instances/time/mixins/PeriodMonthsInt.scala b/instances/src/main/scala/pl/iterators/kebs/instances/time/mixins/PeriodMonthsInt.scala index 9d042b5a..e73eb913 100644 --- a/instances/src/main/scala/pl/iterators/kebs/instances/time/mixins/PeriodMonthsInt.scala +++ b/instances/src/main/scala/pl/iterators/kebs/instances/time/mixins/PeriodMonthsInt.scala @@ -1,7 +1,6 @@ package pl.iterators.kebs.instances.time.mixins -import pl.iterators.kebs.instances.InstanceConverter - +import pl.iterators.kebs.core.instances.InstanceConverter import java.time.Period trait PeriodMonthsInt { diff --git a/instances/src/main/scala/pl/iterators/kebs/instances/time/mixins/PeriodYearsInt.scala b/instances/src/main/scala/pl/iterators/kebs/instances/time/mixins/PeriodYearsInt.scala index 0d290eac..5de95e4b 100644 --- a/instances/src/main/scala/pl/iterators/kebs/instances/time/mixins/PeriodYearsInt.scala +++ b/instances/src/main/scala/pl/iterators/kebs/instances/time/mixins/PeriodYearsInt.scala @@ -1,7 +1,6 @@ package pl.iterators.kebs.instances.time.mixins -import pl.iterators.kebs.instances.InstanceConverter - +import pl.iterators.kebs.core.instances.InstanceConverter import java.time.Period trait PeriodYearsInt { diff --git a/instances/src/main/scala/pl/iterators/kebs/instances/util/CurrencyString.scala b/instances/src/main/scala/pl/iterators/kebs/instances/util/CurrencyString.scala index 0ab1c386..30d74581 100644 --- a/instances/src/main/scala/pl/iterators/kebs/instances/util/CurrencyString.scala +++ b/instances/src/main/scala/pl/iterators/kebs/instances/util/CurrencyString.scala @@ -1,7 +1,7 @@ package pl.iterators.kebs.instances.util -import pl.iterators.kebs.instances.InstanceConverter -import pl.iterators.kebs.instances.util.CurrencyString.CurrencyFormat +import CurrencyString.CurrencyFormat +import pl.iterators.kebs.core.instances.InstanceConverter import java.util.Currency diff --git a/instances/src/main/scala/pl/iterators/kebs/instances/util/LocaleString.scala b/instances/src/main/scala/pl/iterators/kebs/instances/util/LocaleString.scala index e8e44c06..fd8dac83 100644 --- a/instances/src/main/scala/pl/iterators/kebs/instances/util/LocaleString.scala +++ b/instances/src/main/scala/pl/iterators/kebs/instances/util/LocaleString.scala @@ -1,7 +1,7 @@ package pl.iterators.kebs.instances.util -import pl.iterators.kebs.instances.InstanceConverter -import pl.iterators.kebs.instances.util.LocaleString.LocaleFormat +import LocaleString.LocaleFormat +import pl.iterators.kebs.core.instances.InstanceConverter import java.util.Locale diff --git a/instances/src/main/scala/pl/iterators/kebs/instances/util/UUIDString.scala b/instances/src/main/scala/pl/iterators/kebs/instances/util/UUIDString.scala index 2eb45a4d..de2f6b8d 100644 --- a/instances/src/main/scala/pl/iterators/kebs/instances/util/UUIDString.scala +++ b/instances/src/main/scala/pl/iterators/kebs/instances/util/UUIDString.scala @@ -1,7 +1,7 @@ package pl.iterators.kebs.instances.util -import pl.iterators.kebs.instances.InstanceConverter -import pl.iterators.kebs.instances.util.UUIDString.UUIDFormat +import UUIDString.UUIDFormat +import pl.iterators.kebs.core.instances.InstanceConverter import java.util.UUID diff --git a/instances/src/test/scala/pl/iterators/kebs/instances/net/NetInstancesTests.scala b/instances/src/test/scala/pl/iterators/kebs/instances/net/NetInstancesTests.scala index 9237d610..db907ab3 100644 --- a/instances/src/test/scala/pl/iterators/kebs/instances/net/NetInstancesTests.scala +++ b/instances/src/test/scala/pl/iterators/kebs/instances/net/NetInstancesTests.scala @@ -2,8 +2,8 @@ package pl.iterators.kebs.instances.net import org.scalatest.funsuite.AnyFunSuite import org.scalatest.matchers.should.Matchers -import pl.iterators.kebs.instances.InstanceConverter -import InstanceConverter.DecodeErrorException +import pl.iterators.kebs.core.instances.InstanceConverter +import pl.iterators.kebs.core.instances.InstanceConverter.DecodeErrorException import java.net.URI diff --git a/instances/src/test/scala/pl/iterators/kebs/instances/time/TimeInstancesTests.scala b/instances/src/test/scala/pl/iterators/kebs/instances/time/TimeInstancesTests.scala index 20764d9e..e159e32b 100644 --- a/instances/src/test/scala/pl/iterators/kebs/instances/time/TimeInstancesTests.scala +++ b/instances/src/test/scala/pl/iterators/kebs/instances/time/TimeInstancesTests.scala @@ -2,9 +2,9 @@ package pl.iterators.kebs.instances.time import org.scalatest.funsuite.AnyFunSuite import org.scalatest.matchers.should.Matchers -import pl.iterators.kebs.instances.InstanceConverter -import pl.iterators.kebs.instances.InstanceConverter.DecodeErrorException import pl.iterators.kebs.instances.TimeInstances +import pl.iterators.kebs.core.instances.InstanceConverter +import InstanceConverter.DecodeErrorException import java.time._ diff --git a/instances/src/test/scala/pl/iterators/kebs/instances/util/UtilInstancesTests.scala b/instances/src/test/scala/pl/iterators/kebs/instances/util/UtilInstancesTests.scala index 6c8aa762..398ae505 100644 --- a/instances/src/test/scala/pl/iterators/kebs/instances/util/UtilInstancesTests.scala +++ b/instances/src/test/scala/pl/iterators/kebs/instances/util/UtilInstancesTests.scala @@ -2,9 +2,9 @@ package pl.iterators.kebs.instances.util import org.scalatest.funsuite.AnyFunSuite import org.scalatest.matchers.should.Matchers -import pl.iterators.kebs.instances.InstanceConverter -import pl.iterators.kebs.instances.InstanceConverter.DecodeErrorException import pl.iterators.kebs.instances.UtilInstances +import pl.iterators.kebs.core.instances.InstanceConverter +import InstanceConverter.DecodeErrorException import java.util.{Currency, Locale, UUID} diff --git a/jsonschema/src/main/scala/pl/iterators/kebs/jsonschema/KebsJsonSchema.scala b/jsonschema/src/main/scala/pl/iterators/kebs/jsonschema/KebsJsonSchema.scala index 48bbaefd..36f3cd1f 100644 --- a/jsonschema/src/main/scala/pl/iterators/kebs/jsonschema/KebsJsonSchema.scala +++ b/jsonschema/src/main/scala/pl/iterators/kebs/jsonschema/KebsJsonSchema.scala @@ -1,13 +1,13 @@ package pl.iterators.kebs.jsonschema -import pl.iterators.kebs.macros.CaseClass1Rep +import pl.iterators.kebs.core.macros.ValueClassLike trait KebsJsonSchema { import macros.KebsJsonSchemaMacros implicit val jswUnit: JsonSchemaWrapper[Unit] = JsonSchemaWrapper[Unit](null) - implicit def caseClass1RepJsonSchemaPredef[T, A](implicit rep: CaseClass1Rep[T, A], - schema: json.schema.Predef[A]): json.schema.Predef[T] = + implicit def valueClassLikeJsonSchemaPredef[T, A](implicit rep: ValueClassLike[T, A], + schema: json.schema.Predef[A]): json.schema.Predef[T] = schema.asInstanceOf[json.schema.Predef[T]] implicit def genericJsonSchemaWrapper[T]: JsonSchemaWrapper[T] = macro KebsJsonSchemaMacros.materializeSchema[T] } diff --git a/jsonschema/src/main/scala/pl/iterators/kebs/jsonschema/macros/KebsJsonSchemaMacros.scala b/jsonschema/src/main/scala/pl/iterators/kebs/jsonschema/macros/KebsJsonSchemaMacros.scala index 03bf72c3..8158be9e 100644 --- a/jsonschema/src/main/scala/pl/iterators/kebs/jsonschema/macros/KebsJsonSchemaMacros.scala +++ b/jsonschema/src/main/scala/pl/iterators/kebs/jsonschema/macros/KebsJsonSchemaMacros.scala @@ -1,9 +1,8 @@ package pl.iterators.kebs.jsonschema.macros -import pl.iterators.kebs.macros.MacroUtils - import scala.reflect.macros._ import json._ +import pl.iterators.kebs.core.macros.MacroUtils import pl.iterators.kebs.jsonschema.JsonSchemaWrapper class KebsJsonSchemaMacros(override val c: whitebox.Context) extends MacroUtils { diff --git a/jsonschema/src/test/scala/JsonSchemaTests.scala b/jsonschema/src/test/scala/pl/iterators/kebs/jsonschema/JsonSchemaTests.scala similarity index 63% rename from jsonschema/src/test/scala/JsonSchemaTests.scala rename to jsonschema/src/test/scala/pl/iterators/kebs/jsonschema/JsonSchemaTests.scala index cbe5391f..3b9d5408 100644 --- a/jsonschema/src/test/scala/JsonSchemaTests.scala +++ b/jsonschema/src/test/scala/pl/iterators/kebs/jsonschema/JsonSchemaTests.scala @@ -1,17 +1,10 @@ +package pl.iterators.kebs.jsonschema + import com.github.andyglow.json.JsonFormatter import com.github.andyglow.jsonschema.AsValue import json.schema.Version.Draft07 import org.scalatest.funsuite.AnyFunSuite import org.scalatest.matchers.should.Matchers -import pl.iterators.kebs.jsonschema.{KebsJsonSchema, JsonSchemaWrapper} - -case class WrappedInt(int: Int) -case class WrappedIntAnyVal(int: Int) extends AnyVal -case class Sample(someNumber: Int, - someText: String, - arrayOfNumbers: List[Int], - wrappedNumber: WrappedInt, - wrappedNumberAnyVal: WrappedIntAnyVal) class JsonSchemaTests extends AnyFunSuite with Matchers { object KebsProtocol extends KebsJsonSchema diff --git a/jsonschema/src/test/scala/pl/iterators/kebs/jsonschema/Sample.scala b/jsonschema/src/test/scala/pl/iterators/kebs/jsonschema/Sample.scala new file mode 100644 index 00000000..21abb27f --- /dev/null +++ b/jsonschema/src/test/scala/pl/iterators/kebs/jsonschema/Sample.scala @@ -0,0 +1,7 @@ +package pl.iterators.kebs.jsonschema + +case class Sample(someNumber: Int, + someText: String, + arrayOfNumbers: List[Int], + wrappedNumber: WrappedInt, + wrappedNumberAnyVal: WrappedIntAnyVal) diff --git a/jsonschema/src/test/scala/pl/iterators/kebs/jsonschema/WrappedInt.scala b/jsonschema/src/test/scala/pl/iterators/kebs/jsonschema/WrappedInt.scala new file mode 100644 index 00000000..ee23ab2a --- /dev/null +++ b/jsonschema/src/test/scala/pl/iterators/kebs/jsonschema/WrappedInt.scala @@ -0,0 +1,3 @@ +package pl.iterators.kebs.jsonschema + +case class WrappedInt(int: Int) diff --git a/jsonschema/src/test/scala/pl/iterators/kebs/jsonschema/WrappedIntAnyVal.scala b/jsonschema/src/test/scala/pl/iterators/kebs/jsonschema/WrappedIntAnyVal.scala new file mode 100644 index 00000000..9904d422 --- /dev/null +++ b/jsonschema/src/test/scala/pl/iterators/kebs/jsonschema/WrappedIntAnyVal.scala @@ -0,0 +1,3 @@ +package pl.iterators.kebs.jsonschema + +case class WrappedIntAnyVal(int: Int) extends AnyVal diff --git a/opaque/src/main/scala-3/pl/iterators/kebs/opaque/Opaque.scala b/opaque/src/main/scala-3/pl/iterators/kebs/opaque/Opaque.scala index 321f5c31..9aa33080 100644 --- a/opaque/src/main/scala-3/pl/iterators/kebs/opaque/Opaque.scala +++ b/opaque/src/main/scala-3/pl/iterators/kebs/opaque/Opaque.scala @@ -1,6 +1,6 @@ package pl.iterators.kebs.opaque -import pl.iterators.kebs.macros.CaseClass1Rep +import pl.iterators.kebs.core.macros.ValueClassLike trait Opaque[OpaqueType, Unwrapped](using ev: OpaqueType =:= Unwrapped) { /** @@ -40,5 +40,5 @@ trait Opaque[OpaqueType, Unwrapped](using ev: OpaqueType =:= Unwrapped) { def unwrap: Unwrapped = ev.apply(w) } - given cc1Rep: CaseClass1Rep[OpaqueType, Unwrapped] = CaseClass1Rep(apply, _.unwrap) + given vcLike: ValueClassLike[OpaqueType, Unwrapped] = ValueClassLike(apply, _.unwrap) } \ No newline at end of file diff --git a/opaque/src/test/scala-3/OpaqueTest.scala b/opaque/src/test/scala-3/pl/iterators/kebs/opaque/OpaqueTest.scala similarity index 76% rename from opaque/src/test/scala-3/OpaqueTest.scala rename to opaque/src/test/scala-3/pl/iterators/kebs/opaque/OpaqueTest.scala index aea40056..25c55ba4 100644 --- a/opaque/src/test/scala-3/OpaqueTest.scala +++ b/opaque/src/test/scala-3/pl/iterators/kebs/opaque/OpaqueTest.scala @@ -1,7 +1,7 @@ import org.scalatest.funsuite.AnyFunSuite import org.scalatest.matchers.should.Matchers import pl.iterators.kebs.opaque.Opaque -import pl.iterators.kebs.macros.CaseClass1Rep +import pl.iterators.kebs.core.macros.ValueClassLike object OpaqueTestDomain { opaque type TestWrappedInt = Int @@ -24,7 +24,7 @@ object OpaqueTestTypeclass { } given Showable[Int] = (a: Int) => a.toString - given[S, A](using showable: Showable[S], cc1Rep: CaseClass1Rep[A, S]): Showable[A] = (a: A) => showable.show(cc1Rep.unapply(a)) + given[S, A](using showable: Showable[S], vcLike: ValueClassLike[A, S]): Showable[A] = (a: A) => showable.show(vcLike.unapply(a)) } class OpaqueTest extends AnyFunSuite with Matchers { @@ -54,10 +54,10 @@ class OpaqueTest extends AnyFunSuite with Matchers { } test("Basic derivation") { - "implicitly[CaseClass1Rep[ValidatedTestWrappedString, String]]" should compile - implicitly[CaseClass1Rep[ValidatedTestWrappedString, String]].apply("foo") shouldEqual ValidatedTestWrappedString("foo") - implicitly[CaseClass1Rep[ValidatedTestWrappedString, String]].unapply(ValidatedTestWrappedString("foo")) shouldEqual "foo" - an[IllegalArgumentException] should be thrownBy implicitly[CaseClass1Rep[ValidatedTestWrappedString, String]].apply("") + "implicitly[ValueClassLike[ValidatedTestWrappedString, String]]" should compile + implicitly[ValueClassLike[ValidatedTestWrappedString, String]].apply("foo") shouldEqual ValidatedTestWrappedString("foo") + implicitly[ValueClassLike[ValidatedTestWrappedString, String]].unapply(ValidatedTestWrappedString("foo")) shouldEqual "foo" + an[IllegalArgumentException] should be thrownBy implicitly[ValueClassLike[ValidatedTestWrappedString, String]].apply("") } test("Typeclass derivation") { diff --git a/pekko-http/src/main/scala-2/matchers/KebsMatchers.scala b/pekko-http/src/main/scala-2/pl/iterators/kebs/pekkohttp/matchers/KebsMatchers.scala similarity index 72% rename from pekko-http/src/main/scala-2/matchers/KebsMatchers.scala rename to pekko-http/src/main/scala-2/pl/iterators/kebs/pekkohttp/matchers/KebsMatchers.scala index dfa33142..9217d128 100644 --- a/pekko-http/src/main/scala-2/matchers/KebsMatchers.scala +++ b/pekko-http/src/main/scala-2/pl/iterators/kebs/pekkohttp/matchers/KebsMatchers.scala @@ -1,16 +1,16 @@ -package pl.iterators.kebs.matchers +package pl.iterators.kebs.pekkohttp.matchers import org.apache.pekko.http.scaladsl.server.{PathMatcher1, PathMatchers} import enumeratum.{Enum, EnumEntry} -import pl.iterators.kebs.instances.InstanceConverter -import pl.iterators.kebs.macros.CaseClass1Rep +import pl.iterators.kebs.core.instances.InstanceConverter +import pl.iterators.kebs.core.macros.ValueClassLike import scala.language.implicitConversions trait KebsMatchers extends PathMatchers { implicit class SegmentIsomorphism[U](segment: PathMatcher1[U]) { - def as[T](implicit rep: CaseClass1Rep[T, U]): PathMatcher1[T] = segment.map(rep.apply) + def as[T](implicit rep: ValueClassLike[T, U]): PathMatcher1[T] = segment.map(rep.apply) } implicit class SegmentConversion[Source](segment: PathMatcher1[Source]) { diff --git a/pekko-http/src/main/scala-2/pl/iterators/kebs/pekkohttp/unmarshallers/enums/KebsEnumUnmarshallers.scala b/pekko-http/src/main/scala-2/pl/iterators/kebs/pekkohttp/unmarshallers/enums/KebsEnumUnmarshallers.scala new file mode 100644 index 00000000..dce95973 --- /dev/null +++ b/pekko-http/src/main/scala-2/pl/iterators/kebs/pekkohttp/unmarshallers/enums/KebsEnumUnmarshallers.scala @@ -0,0 +1,45 @@ +package pl.iterators.kebs.pekkohttp.unmarshallers.enums + +import org.apache.pekko.http.scaladsl.unmarshalling.PredefinedFromStringUnmarshallers._ +import org.apache.pekko.http.scaladsl.unmarshalling.{FromStringUnmarshaller, Unmarshaller} +import org.apache.pekko.http.scaladsl.util.FastFuture +import pl.iterators.kebs.core.enums.{EnumLike, ValueEnumLike, ValueEnumLikeEntry} + +trait EnumUnmarshallers { + final def enumUnmarshaller[E](`enum`: EnumLike[E]): FromStringUnmarshaller[E] = Unmarshaller { _ =>name => + `enum`.withNameInsensitiveOption(name) match { + case Some(enumEntry) => FastFuture.successful(enumEntry) + case None => + FastFuture.failed(new IllegalArgumentException(s"""Invalid value '$name'. Expected one of: ${`enum`.getNamesToValuesMap.keysIterator + .mkString(", ")}""")) + } + } + + implicit def kebsEnumUnmarshaller[E](implicit ev: EnumLike[E]): FromStringUnmarshaller[E] = + enumUnmarshaller(ev) +} + +trait ValueEnumUnmarshallers { + final def valueEnumUnmarshaller[V, E <: ValueEnumLikeEntry[V]](`enum`: ValueEnumLike[V, E]): Unmarshaller[V, E] = Unmarshaller { _ =>v => + `enum`.values.find(e => e.value == v && e.value.getClass == v.getClass) match { + case Some(enumEntry) => FastFuture.successful(enumEntry) + case None => + FastFuture.failed(new IllegalArgumentException(s"""Invalid value '$v'. Expected one of: ${`enum`.getValuesToEntriesMap.keysIterator + .mkString(", ")}""")) + } + } + + implicit def kebsValueEnumUnmarshaller[V, E <: ValueEnumLikeEntry[V]](implicit ev: ValueEnumLike[V, E]): Unmarshaller[V, E] = + valueEnumUnmarshaller(ev) + + implicit def kebsIntValueEnumFromStringUnmarshaller[E <: ValueEnumLikeEntry[Int]](implicit ev: ValueEnumLike[Int, E]): FromStringUnmarshaller[E] = + intFromStringUnmarshaller andThen valueEnumUnmarshaller(ev) + implicit def kebsLongValueEnumFromStringUnmarshaller[E <: ValueEnumLikeEntry[Long]](implicit ev: ValueEnumLike[Long, E]): FromStringUnmarshaller[E] = + longFromStringUnmarshaller andThen valueEnumUnmarshaller(ev) + implicit def kebsShortValueEnumFromStringUnmarshaller[E <: ValueEnumLikeEntry[Short]](implicit ev: ValueEnumLike[Short, E]): FromStringUnmarshaller[E] = + shortFromStringUnmarshaller andThen valueEnumUnmarshaller(ev) + implicit def kebsByteValueEnumFromStringUnmarshaller[E <: ValueEnumLikeEntry[Byte]](implicit ev: ValueEnumLike[Byte, E]): FromStringUnmarshaller[E] = + byteFromStringUnmarshaller andThen valueEnumUnmarshaller(ev) +} + +trait KebsEnumUnmarshallers extends EnumUnmarshallers with ValueEnumUnmarshallers {} diff --git a/pekko-http/src/main/scala-2/unmarshallers/enums/package.scala b/pekko-http/src/main/scala-2/pl/iterators/kebs/pekkohttp/unmarshallers/enums/package.scala similarity index 50% rename from pekko-http/src/main/scala-2/unmarshallers/enums/package.scala rename to pekko-http/src/main/scala-2/pl/iterators/kebs/pekkohttp/unmarshallers/enums/package.scala index 757c8e7e..3c2b9251 100644 --- a/pekko-http/src/main/scala-2/unmarshallers/enums/package.scala +++ b/pekko-http/src/main/scala-2/pl/iterators/kebs/pekkohttp/unmarshallers/enums/package.scala @@ -1,3 +1,3 @@ -package pl.iterators.kebs.unmarshallers +package pl.iterators.kebs.pekkohttp.unmarshallers package object enums extends KebsEnumUnmarshallers \ No newline at end of file diff --git a/pekko-http/src/main/scala-2/unmarshallers/enums/KebsEnumUnmarshallers.scala b/pekko-http/src/main/scala-2/unmarshallers/enums/KebsEnumUnmarshallers.scala deleted file mode 100644 index ca127d1b..00000000 --- a/pekko-http/src/main/scala-2/unmarshallers/enums/KebsEnumUnmarshallers.scala +++ /dev/null @@ -1,48 +0,0 @@ -package pl.iterators.kebs.unmarshallers.enums - -import org.apache.pekko.http.scaladsl.unmarshalling.PredefinedFromStringUnmarshallers._ -import org.apache.pekko.http.scaladsl.unmarshalling.{FromStringUnmarshaller, Unmarshaller} -import org.apache.pekko.http.scaladsl.util.FastFuture -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) => FastFuture.successful(enumEntry) - case None => - FastFuture.failed(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) => FastFuture.successful(enumEntry) - case None => - FastFuture.failed(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 {} diff --git a/pekko-http/src/main/scala-3/matchers/KebsMatchers.scala b/pekko-http/src/main/scala-3/matchers/KebsMatchers.scala deleted file mode 100644 index 9615081c..00000000 --- a/pekko-http/src/main/scala-3/matchers/KebsMatchers.scala +++ /dev/null @@ -1,27 +0,0 @@ -package pl.iterators.kebs.matchers - -import org.apache.pekko.http.scaladsl.server.PathMatcher1 -import pl.iterators.kebs.instances.InstanceConverter -import pl.iterators.kebs.macros.CaseClass1Rep -import pl.iterators.kebs.macros.enums.EnumOf -import org.apache.pekko.stream.Materializer -import scala.reflect.Enum - -import scala.language.implicitConversions - -trait KebsMatchers extends org.apache.pekko.http.scaladsl.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(", ")}"""))) - } - } -} diff --git a/pekko-http/src/main/scala-3/pl/iterators/kebs/pekkohttp/matchers/KebsMatchers.scala b/pekko-http/src/main/scala-3/pl/iterators/kebs/pekkohttp/matchers/KebsMatchers.scala new file mode 100644 index 00000000..7ab79280 --- /dev/null +++ b/pekko-http/src/main/scala-3/pl/iterators/kebs/pekkohttp/matchers/KebsMatchers.scala @@ -0,0 +1,28 @@ +package pl.iterators.kebs.pekkohttp.matchers + +import org.apache.pekko.http.scaladsl.server.PathMatcher1 +import pl.iterators.kebs.core.macros.ValueClassLike +import org.apache.pekko.stream.Materializer +import scala.reflect.Enum + +import pl.iterators.kebs.core.enums.EnumLike +import pl.iterators.kebs.core.instances.InstanceConverter + +import scala.language.implicitConversions + +trait KebsMatchers extends org.apache.pekko.http.scaladsl.server.PathMatchers { + + implicit class SegmentIsomorphism[U](segment: PathMatcher1[U]) { + def as[T](implicit rep: ValueClassLike[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: EnumLike[T]): PathMatcher1[T] = { + Segment.map(s => e.values.find(_.toString().toLowerCase() == s.toLowerCase()).getOrElse(throw new IllegalArgumentException(s"""Invalid value '$s'. Expected one of: ${e.values.mkString(", ")}"""))) + } + } +} diff --git a/pekko-http/src/main/scala-3/pl/iterators/kebs/pekkohttp/unmarshallers/enums/KebsEnumUnmarshallers.scala b/pekko-http/src/main/scala-3/pl/iterators/kebs/pekkohttp/unmarshallers/enums/KebsEnumUnmarshallers.scala new file mode 100644 index 00000000..c0607414 --- /dev/null +++ b/pekko-http/src/main/scala-3/pl/iterators/kebs/pekkohttp/unmarshallers/enums/KebsEnumUnmarshallers.scala @@ -0,0 +1,59 @@ +package pl.iterators.kebs.pekkohttp.unmarshallers.enums + +import org.apache.pekko.http.scaladsl.unmarshalling.PredefinedFromStringUnmarshallers.* +import org.apache.pekko.http.scaladsl.unmarshalling.{FromStringUnmarshaller, Unmarshaller} +import org.apache.pekko.http.scaladsl.util.FastFuture + +import scala.reflect.ClassTag +import scala.reflect.Selectable.reflectiveSelectable + +import pl.iterators.kebs.core.enums.{EnumLike, ValueEnumLike, ValueEnumLikeEntry} + +trait EnumUnmarshallers { + + final def enumUnmarshaller[E](using e: EnumLike[E]): FromStringUnmarshaller[E] = org.apache.pekko.http.scaladsl.unmarshalling.Unmarshaller { _ => name => + e.values.find(_.toString().toLowerCase() == name.toLowerCase()) match { + case Some(enumEntry) => FastFuture.successful(enumEntry) + case None => + FastFuture.failed(new IllegalArgumentException(s"""Invalid value '$name'. Expected one of: ${e.values.mkString(", ")}""")) + } + } + + given kebsEnumUnmarshaller[E](using e: EnumLike[E]): FromStringUnmarshaller[E] = + enumUnmarshaller +} + +trait ValueEnumUnmarshallers extends EnumUnmarshallers { + final def valueEnumUnmarshaller[V, E <: ValueEnumLikeEntry[V]](using `enum`: ValueEnumLike[V, E], cls: ClassTag[V]): Unmarshaller[V, E] = + Unmarshaller { _ => + v => + `enum`.values.find(e => e.value == v && e.value.getClass == v.getClass) match { + case Some(enumEntry) => + FastFuture.successful(enumEntry) + case _ => + `enum`.values.find(e => e.value == v) match { + case Some(enumEntry) => + FastFuture.failed(new IllegalArgumentException(s"""Invalid value '$v'""")) + case None => + FastFuture.failed(new IllegalArgumentException(s"""Invalid value '$v'. Expected one of: ${`enum`.values.map(_.value).mkString(", ")}""")) + } + } + } + + given 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] = + intFromStringUnmarshaller andThen valueEnumUnmarshaller + + given 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] = + shortFromStringUnmarshaller andThen valueEnumUnmarshaller + + given kebsByteValueEnumFromStringUnmarshaller[E <: ValueEnumLikeEntry[Byte]](using ev: ValueEnumLike[Byte, E]): FromStringUnmarshaller[E] = + byteFromStringUnmarshaller andThen valueEnumUnmarshaller +} + +trait KebsEnumUnmarshallers extends ValueEnumUnmarshallers {} diff --git a/pekko-http/src/main/scala-3/unmarshallers/enums/package.scala b/pekko-http/src/main/scala-3/pl/iterators/kebs/pekkohttp/unmarshallers/enums/package.scala similarity index 50% rename from pekko-http/src/main/scala-3/unmarshallers/enums/package.scala rename to pekko-http/src/main/scala-3/pl/iterators/kebs/pekkohttp/unmarshallers/enums/package.scala index 757c8e7e..3c2b9251 100644 --- a/pekko-http/src/main/scala-3/unmarshallers/enums/package.scala +++ b/pekko-http/src/main/scala-3/pl/iterators/kebs/pekkohttp/unmarshallers/enums/package.scala @@ -1,3 +1,3 @@ -package pl.iterators.kebs.unmarshallers +package pl.iterators.kebs.pekkohttp.unmarshallers package object enums extends KebsEnumUnmarshallers \ No newline at end of file diff --git a/pekko-http/src/main/scala-3/unmarshallers/enums/KebsEnumUnmarshallers.scala b/pekko-http/src/main/scala-3/unmarshallers/enums/KebsEnumUnmarshallers.scala deleted file mode 100644 index 914c15e1..00000000 --- a/pekko-http/src/main/scala-3/unmarshallers/enums/KebsEnumUnmarshallers.scala +++ /dev/null @@ -1,50 +0,0 @@ -package pl.iterators.kebs.unmarshallers.enums - -import org.apache.pekko.http.scaladsl.unmarshalling.PredefinedFromStringUnmarshallers._ -import org.apache.pekko.http.scaladsl.unmarshalling.{FromStringUnmarshaller, Unmarshaller} -import org.apache.pekko.http.scaladsl.util.FastFuture - -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] = org.apache.pekko.http.scaladsl.unmarshalling.Unmarshaller { _ => name => - e.`enum`.values.find(_.toString().toLowerCase() == name.toLowerCase()) match { - case Some(enumEntry) => FastFuture.successful(enumEntry) - case None => - FastFuture.failed(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) => FastFuture.successful(enumEntry) - case None => - FastFuture.failed(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 {} diff --git a/http4s-stir/src/main/scala/pl/iterators/kebs/matchers/package.scala b/pekko-http/src/main/scala/pl/iterators/kebs/pekkohttp/matchers/package.scala similarity index 56% rename from http4s-stir/src/main/scala/pl/iterators/kebs/matchers/package.scala rename to pekko-http/src/main/scala/pl/iterators/kebs/pekkohttp/matchers/package.scala index 610a2da7..3af3236b 100644 --- a/http4s-stir/src/main/scala/pl/iterators/kebs/matchers/package.scala +++ b/pekko-http/src/main/scala/pl/iterators/kebs/pekkohttp/matchers/package.scala @@ -1,3 +1,3 @@ -package pl.iterators.kebs +package pl.iterators.kebs.pekkohttp package object matchers extends KebsMatchers diff --git a/pekko-http/src/main/scala/pl/iterators/kebs/unmarshallers/KebsUnmarshallers.scala b/pekko-http/src/main/scala/pl/iterators/kebs/pekkohttp/unmarshallers/KebsUnmarshallers.scala similarity index 62% rename from pekko-http/src/main/scala/pl/iterators/kebs/unmarshallers/KebsUnmarshallers.scala rename to pekko-http/src/main/scala/pl/iterators/kebs/pekkohttp/unmarshallers/KebsUnmarshallers.scala index 696051a8..06270b6e 100644 --- a/pekko-http/src/main/scala/pl/iterators/kebs/unmarshallers/KebsUnmarshallers.scala +++ b/pekko-http/src/main/scala/pl/iterators/kebs/pekkohttp/unmarshallers/KebsUnmarshallers.scala @@ -1,12 +1,12 @@ -package pl.iterators.kebs.unmarshallers +package pl.iterators.kebs.pekkohttp.unmarshallers import org.apache.pekko.http.scaladsl.unmarshalling.{FromStringUnmarshaller, Unmarshaller} -import pl.iterators.kebs.instances.InstanceConverter -import pl.iterators.kebs.macros.CaseClass1Rep +import pl.iterators.kebs.core.instances.InstanceConverter +import pl.iterators.kebs.core.macros.{CaseClass1ToValueClass, ValueClassLike} -trait KebsUnmarshallers extends LowPriorityKebsUnmarshallers { +trait KebsUnmarshallers extends LowPriorityKebsUnmarshallers with CaseClass1ToValueClass { @inline - implicit def kebsFromStringUnmarshaller[A, B](implicit rep: CaseClass1Rep[B, A], + implicit def kebsFromStringUnmarshaller[A, B](implicit rep: ValueClassLike[B, A], fsu: FromStringUnmarshaller[A]): FromStringUnmarshaller[B] = fsu andThen kebsUnmarshaller(rep) @@ -22,6 +22,6 @@ 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] = + implicit def kebsUnmarshaller[A, B](implicit rep: ValueClassLike[B, A]): Unmarshaller[A, B] = Unmarshaller.strict[A, B](rep.apply) } \ No newline at end of file diff --git a/pekko-http/src/main/scala/pl/iterators/kebs/unmarshallers/package.scala b/pekko-http/src/main/scala/pl/iterators/kebs/pekkohttp/unmarshallers/package.scala similarity index 60% rename from pekko-http/src/main/scala/pl/iterators/kebs/unmarshallers/package.scala rename to pekko-http/src/main/scala/pl/iterators/kebs/pekkohttp/unmarshallers/package.scala index 6fd93de3..473504c9 100644 --- a/pekko-http/src/main/scala/pl/iterators/kebs/unmarshallers/package.scala +++ b/pekko-http/src/main/scala/pl/iterators/kebs/pekkohttp/unmarshallers/package.scala @@ -1,3 +1,3 @@ -package pl.iterators.kebs +package pl.iterators.kebs.pekkohttp package object unmarshallers extends KebsUnmarshallers diff --git a/pekko-http/src/test/scala-2/pl/iterators/kebs/PekkoHttpTagsDomain.scala b/pekko-http/src/test/scala-2/pl/iterators/kebs/pekkohttp/domain/PekkoHttpTagsDomain.scala similarity index 92% rename from pekko-http/src/test/scala-2/pl/iterators/kebs/PekkoHttpTagsDomain.scala rename to pekko-http/src/test/scala-2/pl/iterators/kebs/pekkohttp/domain/PekkoHttpTagsDomain.scala index f0661a1e..39e575f4 100644 --- a/pekko-http/src/test/scala-2/pl/iterators/kebs/PekkoHttpTagsDomain.scala +++ b/pekko-http/src/test/scala-2/pl/iterators/kebs/pekkohttp/domain/PekkoHttpTagsDomain.scala @@ -1,9 +1,10 @@ -package pl.iterators.kebs +package pl.iterators.kebs.pekkohttp.domain import enumeratum.values.{IntEnum, IntEnumEntry, StringEnum, StringEnumEntry} import enumeratum.{Enum, EnumEntry} import pl.iterators.kebs.tag.meta.tagged import pl.iterators.kebs.tagged._ +import pl.iterators.kebs.core.enums.ValueEnumLikeEntry import java.net.URI import java.util.UUID @@ -47,7 +48,7 @@ object Domain extends Tags { val values = findValues } - sealed abstract class LibraryItem(val value: Int) extends IntEnumEntry + sealed abstract class LibraryItem(val value: Int) extends IntEnumEntry with ValueEnumLikeEntry[Int] object LibraryItem extends IntEnum[LibraryItem] { case object Book extends LibraryItem(1) @@ -63,7 +64,7 @@ object Domain extends Tags { case class Blue(value: Int) case class Color(red: Red, green: Green, blue: Blue) - sealed abstract class ShirtSize(val value: String) extends StringEnumEntry + sealed abstract class ShirtSize(val value: String) extends StringEnumEntry with ValueEnumLikeEntry[String] object ShirtSize extends StringEnum[ShirtSize] { case object Small extends ShirtSize("S") case object Medium extends ShirtSize("M") diff --git a/pekko-http/src/test/scala-2/pl/iterators/kebs/matchers/PekkoHttpMatchersTests.scala b/pekko-http/src/test/scala-2/pl/iterators/kebs/pekkohttp/matchers/PekkoHttpMatchersTests.scala similarity index 83% rename from pekko-http/src/test/scala-2/pl/iterators/kebs/matchers/PekkoHttpMatchersTests.scala rename to pekko-http/src/test/scala-2/pl/iterators/kebs/pekkohttp/matchers/PekkoHttpMatchersTests.scala index 97ca9919..f5a7eda4 100644 --- a/pekko-http/src/test/scala-2/pl/iterators/kebs/matchers/PekkoHttpMatchersTests.scala +++ b/pekko-http/src/test/scala-2/pl/iterators/kebs/pekkohttp/matchers/PekkoHttpMatchersTests.scala @@ -1,14 +1,14 @@ -package pl.iterators.kebs.matchers +package pl.iterators.kebs.pekkohttp.matchers import org.apache.pekko.http.scaladsl.server.Directives import org.apache.pekko.http.scaladsl.testkit.ScalatestRouteTest import org.scalatest.concurrent.ScalaFutures import org.scalatest.funsuite.AnyFunSuite import org.scalatest.matchers.should.Matchers -import pl.iterators.kebs.Domain._ import pl.iterators.kebs.instances.net.URIString -import pl.iterators.kebs.instances.time.mixins.InstantEpochMilliLong import pl.iterators.kebs.instances.time.{DayOfWeekInt, ZonedDateTimeString} +import pl.iterators.kebs.instances.time.mixins.InstantEpochMilliLong +import pl.iterators.kebs.pekkohttp.domain.Domain._ import java.net.URI import java.time.{DayOfWeek, Instant, ZonedDateTime} @@ -24,15 +24,15 @@ class PekkoHttpMatchersTests with InstantEpochMilliLong with URIString { - test("No CaseClass1Rep implicits derived") { - import pl.iterators.kebs.macros.CaseClass1Rep + test("No ValueClassLike implicits derived") { + import pl.iterators.kebs.core.macros.ValueClassLike - "implicitly[CaseClass1Rep[DayOfWeek, Int]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[Int, DayOfWeek]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[Instant, Long]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[Long, Instant]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[URI, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, URI]]" shouldNot typeCheck + "implicitly[ValueClassLike[DayOfWeek, Int]]" shouldNot typeCheck + "implicitly[ValueClassLike[Int, DayOfWeek]]" shouldNot typeCheck + "implicitly[ValueClassLike[Instant, Long]]" shouldNot typeCheck + "implicitly[ValueClassLike[Long, Instant]]" shouldNot typeCheck + "implicitly[ValueClassLike[URI, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, URI]]" shouldNot typeCheck } test("Extract String to ZonedDateTime") { diff --git a/pekko-http/src/test/scala-3/pl/iterators/kebs/unmarshallers/PekkoHttpUnmarshallersTests.scala b/pekko-http/src/test/scala-2/pl/iterators/kebs/pekkohttp/unmarshallers/PekkoHttpUnmarshallersTests.scala similarity index 84% rename from pekko-http/src/test/scala-3/pl/iterators/kebs/unmarshallers/PekkoHttpUnmarshallersTests.scala rename to pekko-http/src/test/scala-2/pl/iterators/kebs/pekkohttp/unmarshallers/PekkoHttpUnmarshallersTests.scala index 3fcf4e49..1fbe93a9 100644 --- a/pekko-http/src/test/scala-3/pl/iterators/kebs/unmarshallers/PekkoHttpUnmarshallersTests.scala +++ b/pekko-http/src/test/scala-2/pl/iterators/kebs/pekkohttp/unmarshallers/PekkoHttpUnmarshallersTests.scala @@ -1,4 +1,4 @@ -package pl.iterators.kebs.unmarshallers +package pl.iterators.kebs.pekkohttp.unmarshallers import org.apache.pekko.http.scaladsl.model.FormData import org.apache.pekko.http.scaladsl.server.{Directives, MalformedQueryParamRejection} @@ -7,11 +7,13 @@ import org.apache.pekko.http.scaladsl.unmarshalling.Unmarshal import org.scalatest.concurrent.ScalaFutures import org.scalatest.funsuite.AnyFunSuite import org.scalatest.matchers.should.Matchers -import pl.iterators.kebs.Domain._ import pl.iterators.kebs.instances.net.URIString import pl.iterators.kebs.instances.time.{DayOfWeekInt, YearMonthString} -import pl.iterators.kebs.unmarshallers.enums.KebsEnumUnmarshallers - +import pl.iterators.kebs.pekkohttp.domain.Domain._ +import pl.iterators.kebs.enumeratum.{KebsEnumeratum, KebsValueEnumeratum} +import pl.iterators.kebs.instances.net.URIString +import pl.iterators.kebs.instances.time.{DayOfWeekInt, YearMonthString} +import pl.iterators.kebs.pekkohttp.unmarshallers.enums.KebsEnumUnmarshallers import java.time.{DayOfWeek, YearMonth} class PekkoHttpUnmarshallersTests @@ -24,17 +26,19 @@ class PekkoHttpUnmarshallersTests with KebsEnumUnmarshallers with URIString with YearMonthString - with DayOfWeekInt { + with DayOfWeekInt + with KebsEnumeratum + with KebsValueEnumeratum { - test("No CaseClass1Rep implicits derived") { - import pl.iterators.kebs.macros.CaseClass1Rep + test("No ValueClassLike implicits derived") { + import pl.iterators.kebs.core.macros.ValueClassLike - "implicitly[CaseClass1Rep[URI, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, URI]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[YearMonth, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, YearMonth]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[DayOfWeek, Int]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[Int, DayOfWeek]]" shouldNot typeCheck + "implicitly[ValueClassLike[URI, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, URI]]" shouldNot typeCheck + "implicitly[ValueClassLike[YearMonth, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, YearMonth]]" shouldNot typeCheck + "implicitly[ValueClassLike[DayOfWeek, Int]]" shouldNot typeCheck + "implicitly[ValueClassLike[Int, DayOfWeek]]" shouldNot typeCheck } test("Unmarshal") { @@ -119,11 +123,13 @@ class PekkoHttpUnmarshallersTests test("Case class extraction") { val route = path("color") { - parameters(Symbol("red").as[Red], Symbol("green").as[Green], Symbol("blue").as[Blue]).as(Color.apply) { color => + parameters(Symbol("red").as[Red], Symbol("green").as[Green], Symbol("blue").as[Blue]).as(Color) { color => complete(color.toString) } } - Get("/color?red=1&green=2&blue=3") ~> route ~> check { responseAs[String] shouldEqual "Color(Red(1),Green(2),Blue(3))" } + Get("/color?red=1&green=2&blue=3") ~> route ~> check { + responseAs[String] shouldEqual "Color(Red(1),Green(2),Blue(3))" + } } test("Unmarshalling instances parameter") { diff --git a/pekko-http/src/test/scala-3/pl/iterators/kebs/PekkoHttpTagsDomain.scala b/pekko-http/src/test/scala-3/pl/iterators/kebs/pekkohttp/domain/PekkoHttpTagsDomain.scala similarity index 80% rename from pekko-http/src/test/scala-3/pl/iterators/kebs/PekkoHttpTagsDomain.scala rename to pekko-http/src/test/scala-3/pl/iterators/kebs/pekkohttp/domain/PekkoHttpTagsDomain.scala index 39701de2..3c274c86 100644 --- a/pekko-http/src/test/scala-3/pl/iterators/kebs/PekkoHttpTagsDomain.scala +++ b/pekko-http/src/test/scala-3/pl/iterators/kebs/pekkohttp/domain/PekkoHttpTagsDomain.scala @@ -1,10 +1,11 @@ -package pl.iterators.kebs +package pl.iterators.kebs.pekkohttp.domain import pl.iterators.kebs.opaque.Opaque import java.net.URI import java.util.UUID -import pl.iterators.kebs.enums.ValueEnum + +import pl.iterators.kebs.core.enums.ValueEnumLikeEntry object Domain { opaque type TestTaggedUri = URI @@ -24,7 +25,7 @@ object Domain { } - enum LibraryItem(val value: Int) extends ValueEnum[Int] { + enum LibraryItem(val value: Int) extends ValueEnumLikeEntry[Int] { case Book extends LibraryItem(1) case Movie extends LibraryItem(2) case Magazine extends LibraryItem(3) @@ -36,7 +37,7 @@ object Domain { case class Blue(value: Int) case class Color(red: Red, green: Green, blue: Blue) - enum ShirtSize(val value: String) extends ValueEnum[String] { + enum ShirtSize(val value: String) extends ValueEnumLikeEntry[String] { case Small extends ShirtSize("S") case Medium extends ShirtSize("M") case Large extends ShirtSize("L") diff --git a/pekko-http/src/test/scala-3/pl/iterators/kebs/matchers/PekkoHttpMatchersTests.scala b/pekko-http/src/test/scala-3/pl/iterators/kebs/pekkohttp/matchers/PekkoHttpMatchersTests.scala similarity index 75% rename from pekko-http/src/test/scala-3/pl/iterators/kebs/matchers/PekkoHttpMatchersTests.scala rename to pekko-http/src/test/scala-3/pl/iterators/kebs/pekkohttp/matchers/PekkoHttpMatchersTests.scala index 3ceb6c95..f01cff2b 100644 --- a/pekko-http/src/test/scala-3/pl/iterators/kebs/matchers/PekkoHttpMatchersTests.scala +++ b/pekko-http/src/test/scala-3/pl/iterators/kebs/pekkohttp/matchers/PekkoHttpMatchersTests.scala @@ -1,18 +1,20 @@ -package pl.iterators.kebs.matchers +package pl.iterators.kebs.pekkohttp.matchers import org.apache.pekko.http.scaladsl.server.Directives import org.apache.pekko.http.scaladsl.testkit.ScalatestRouteTest import org.scalatest.concurrent.ScalaFutures import org.scalatest.funsuite.AnyFunSuite import org.scalatest.matchers.should.Matchers -import pl.iterators.kebs.Domain._ import pl.iterators.kebs.instances.net.URIString +import pl.iterators.kebs.instances.time.{DayOfWeekInt, ZonedDateTimeString, YearMonthString} import pl.iterators.kebs.instances.time.mixins.InstantEpochMilliLong -import pl.iterators.kebs.instances.time.{DayOfWeekInt, ZonedDateTimeString} +import pl.iterators.kebs.pekkohttp.domain.Domain._ import java.net.URI import java.time.{DayOfWeek, Instant, ZonedDateTime} +import pl.iterators.kebs.enums.KebsEnum + class PekkoHttpMatchersTests extends AnyFunSuite with Matchers @@ -22,17 +24,18 @@ class PekkoHttpMatchersTests with ZonedDateTimeString with DayOfWeekInt with InstantEpochMilliLong - with URIString { + with URIString + with KebsEnum { - test("No CaseClass1Rep implicits derived") { - import pl.iterators.kebs.macros.CaseClass1Rep + test("No ValueClassLike implicits derived") { + import pl.iterators.kebs.core.macros.ValueClassLike - "implicitly[CaseClass1Rep[DayOfWeek, Int]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[Int, DayOfWeek]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[Instant, Long]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[Long, Instant]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[URI, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, URI]]" shouldNot typeCheck + "implicitly[ValueClassLike[DayOfWeek, Int]]" shouldNot typeCheck + "implicitly[ValueClassLike[Int, DayOfWeek]]" shouldNot typeCheck + "implicitly[ValueClassLike[Instant, Long]]" shouldNot typeCheck + "implicitly[ValueClassLike[Long, Instant]]" shouldNot typeCheck + "implicitly[ValueClassLike[URI, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, URI]]" shouldNot typeCheck } test("Extract String to ZonedDateTime") { diff --git a/pekko-http/src/test/scala-2/pl/iterators/kebs/unmarshallers/PekkoHttpUnmarshallersTests.scala b/pekko-http/src/test/scala-3/pl/iterators/kebs/pekkohttp/unmarshallers/PekkoHttpUnmarshallersTests.scala similarity index 79% rename from pekko-http/src/test/scala-2/pl/iterators/kebs/unmarshallers/PekkoHttpUnmarshallersTests.scala rename to pekko-http/src/test/scala-3/pl/iterators/kebs/pekkohttp/unmarshallers/PekkoHttpUnmarshallersTests.scala index e65f8c52..6bc6dece 100644 --- a/pekko-http/src/test/scala-2/pl/iterators/kebs/unmarshallers/PekkoHttpUnmarshallersTests.scala +++ b/pekko-http/src/test/scala-3/pl/iterators/kebs/pekkohttp/unmarshallers/PekkoHttpUnmarshallersTests.scala @@ -1,21 +1,27 @@ -package pl.iterators.kebs.unmarshallers +package pl.iterators.kebs.pekkohttp.unmarshallers +import org.apache.pekko.http.scaladsl.common.ToNameReceptacleEnhancements import org.apache.pekko.http.scaladsl.model.FormData import org.apache.pekko.http.scaladsl.server.{Directives, MalformedQueryParamRejection} import org.apache.pekko.http.scaladsl.testkit.ScalatestRouteTest import org.apache.pekko.http.scaladsl.unmarshalling.Unmarshal +import org.apache.pekko.http.scaladsl.unmarshalling.{FromStringUnmarshaller, Unmarshaller} import org.scalatest.concurrent.ScalaFutures import org.scalatest.funsuite.AnyFunSuite import org.scalatest.matchers.should.Matchers -import pl.iterators.kebs.Domain._ -import pl.iterators.kebs.instances.net.URIString -import pl.iterators.kebs.instances.time.{DayOfWeekInt, YearMonthString} -import pl.iterators.kebs.unmarshallers.enums.KebsEnumUnmarshallers import java.time.{DayOfWeek, YearMonth} +import pl.iterators.kebs.pekkohttp.domain.Domain._ +import pl.iterators.kebs.instances.net.URIString +import pl.iterators.kebs.instances.time.{DayOfWeekInt, ZonedDateTimeString, YearMonthString} +import pl.iterators.kebs.instances.time.mixins.InstantEpochMilliLong +import pl.iterators.kebs.pekkohttp.unmarshallers.enums.KebsEnumUnmarshallers +import pl.iterators.kebs.core.macros.CaseClass1ToValueClass +import pl.iterators.kebs.enums.{KebsEnum, KebsValueEnum} + class PekkoHttpUnmarshallersTests - extends AnyFunSuite + extends AnyFunSuite with Matchers with ScalatestRouteTest with ScalaFutures @@ -24,17 +30,20 @@ class PekkoHttpUnmarshallersTests with KebsEnumUnmarshallers with URIString with YearMonthString - with DayOfWeekInt { + with DayOfWeekInt + with KebsEnum + with KebsValueEnum + with CaseClass1ToValueClass { - test("No CaseClass1Rep implicits derived") { - import pl.iterators.kebs.macros.CaseClass1Rep + test("No ValueClassLike implicits derived") { + import pl.iterators.kebs.core.macros.ValueClassLike - "implicitly[CaseClass1Rep[URI, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, URI]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[YearMonth, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, YearMonth]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[DayOfWeek, Int]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[Int, DayOfWeek]]" shouldNot typeCheck + "implicitly[ValueClassLike[URI, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, URI]]" shouldNot typeCheck + "implicitly[ValueClassLike[YearMonth, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, YearMonth]]" shouldNot typeCheck + "implicitly[ValueClassLike[DayOfWeek, Int]]" shouldNot typeCheck + "implicitly[ValueClassLike[Int, DayOfWeek]]" shouldNot typeCheck } test("Unmarshal") { @@ -56,6 +65,7 @@ class PekkoHttpUnmarshallersTests } test("Unmarshal value enum") { + val x = Unmarshal(1).to[LibraryItem] Unmarshal(3).to[LibraryItem].futureValue shouldBe LibraryItem.Magazine Unmarshal(5).to[LibraryItem].failed.futureValue shouldBe a[IllegalArgumentException] } @@ -99,13 +109,13 @@ class PekkoHttpUnmarshallersTests } Get("/?greeting=blah") ~> testRoute ~> check { rejection shouldEqual MalformedQueryParamRejection("greeting", - "Invalid value 'blah'. Expected one of: Hello, GoodBye, Hi, Bye", - None) + "Invalid value 'blah'. Expected one of: Hello, GoodBye, Hi, Bye", + None) } } test("Unmarshalling value enum parameter") { - val testRoute = parameters(Symbol("libraryItem").as[LibraryItem]) { item => + val testRoute = parameters(ToNameReceptacleEnhancements._symbol2NR(Symbol("libraryItem")).as[LibraryItem]) { item => complete(item.toString) } Get("/?libraryItem=1") ~> testRoute ~> check { @@ -119,7 +129,7 @@ class PekkoHttpUnmarshallersTests test("Case class extraction") { val route = path("color") { - parameters(Symbol("red").as[Red], Symbol("green").as[Green], Symbol("blue").as[Blue]).as(Color) { color => + parameters(Symbol("red").as[Red], Symbol("green").as[Green], Symbol("blue").as[Blue]).as(Color.apply) { color => complete(color.toString) } } diff --git a/play-json/src/main/scala/pl/iterators/kebs/json/KebsPlay.scala b/play-json/src/main/scala/pl/iterators/kebs/json/KebsPlay.scala index b2dcb4fc..5993d3ad 100644 --- a/play-json/src/main/scala/pl/iterators/kebs/json/KebsPlay.scala +++ b/play-json/src/main/scala/pl/iterators/kebs/json/KebsPlay.scala @@ -1,12 +1,12 @@ package pl.iterators.kebs.json -import pl.iterators.kebs.instances.InstanceConverter -import pl.iterators.kebs.macros.CaseClass1Rep +import pl.iterators.kebs.core.instances.InstanceConverter +import pl.iterators.kebs.core.macros.{CaseClass1ToValueClass, ValueClassLike} import play.api.libs.json._ -trait KebsPlay { - implicit def flatReads[T, A](implicit rep: CaseClass1Rep[T, A], reads: Reads[A]): Reads[T] = reads.map(rep.apply) - implicit def flatWrites[T, B](implicit rep: CaseClass1Rep[T, B], writes: Writes[B]): Writes[T] = +trait KebsPlay extends CaseClass1ToValueClass { + implicit def flatReads[T, A](implicit rep: ValueClassLike[T, A], reads: Reads[A]): Reads[T] = reads.map(rep.apply) + implicit def flatWrites[T, B](implicit rep: ValueClassLike[T, B], writes: Writes[B]): Writes[T] = Writes((obj: T) => writes.writes(rep.unapply(obj))) implicit def instanceConverterReads[T, A](implicit rep: InstanceConverter[T, A], reads: Reads[A]): Reads[T] = reads.map(rep.decode) diff --git a/play-json/src/test/scala/PlayJsonFormatTests.scala b/play-json/src/test/scala/pl/iterators/kebs/json/PlayJsonFormatTests.scala similarity index 97% rename from play-json/src/test/scala/PlayJsonFormatTests.scala rename to play-json/src/test/scala/pl/iterators/kebs/json/PlayJsonFormatTests.scala index ad16ef61..73828fb1 100644 --- a/play-json/src/test/scala/PlayJsonFormatTests.scala +++ b/play-json/src/test/scala/pl/iterators/kebs/json/PlayJsonFormatTests.scala @@ -1,8 +1,10 @@ -import java.util.UUID +package pl.iterators.kebs.json -import play.api.libs.json._ import org.scalatest.funsuite.AnyFunSuite import org.scalatest.matchers.should.Matchers +import play.api.libs.json._ + +import java.util.UUID class PlayJsonFormatTests extends AnyFunSuite with Matchers { import pl.iterators.kebs.json._ diff --git a/play-json/src/test/scala/instances/NetInstancesTests.scala b/play-json/src/test/scala/pl/iterators/kebs/json/instances/NetInstancesTests.scala similarity index 71% rename from play-json/src/test/scala/instances/NetInstancesTests.scala rename to play-json/src/test/scala/pl/iterators/kebs/json/instances/NetInstancesTests.scala index 85ae5e06..98bb324d 100644 --- a/play-json/src/test/scala/instances/NetInstancesTests.scala +++ b/play-json/src/test/scala/pl/iterators/kebs/json/instances/NetInstancesTests.scala @@ -1,8 +1,8 @@ -package instances +package pl.iterators.kebs.json.instances import org.scalatest.funsuite.AnyFunSuite import org.scalatest.matchers.should.Matchers -import pl.iterators.kebs.instances.InstanceConverter.DecodeErrorException +import pl.iterators.kebs.core.instances.InstanceConverter.DecodeErrorException import pl.iterators.kebs.instances.net.URIString import play.api.libs.json.{Format, JsString, JsSuccess} @@ -27,9 +27,9 @@ class NetInstancesTests extends AnyFunSuite with Matchers with URIString { assertThrows[DecodeErrorException](jf.reads(JsString(value))) } - test("No CaseClass1Rep implicits derived") { + test("No ValueClassLike implicits derived") { - "implicitly[CaseClass1Rep[URI, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, URI]]" shouldNot typeCheck + "implicitly[ValueClassLike[URI, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, URI]]" shouldNot typeCheck } } diff --git a/play-json/src/test/scala/instances/TimeInstancesMixinTests.scala b/play-json/src/test/scala/pl/iterators/kebs/json/instances/TimeInstancesMixinTests.scala similarity index 81% rename from play-json/src/test/scala/instances/TimeInstancesMixinTests.scala rename to play-json/src/test/scala/pl/iterators/kebs/json/instances/TimeInstancesMixinTests.scala index ab57e2c3..b30f0d84 100644 --- a/play-json/src/test/scala/instances/TimeInstancesMixinTests.scala +++ b/play-json/src/test/scala/pl/iterators/kebs/json/instances/TimeInstancesMixinTests.scala @@ -1,11 +1,11 @@ -package instances +package pl.iterators.kebs.json.instances import org.scalatest.funsuite.AnyFunSuite import org.scalatest.matchers.should.Matchers -import pl.iterators.kebs.instances.InstanceConverter +import pl.iterators.kebs.instances.TimeInstances import pl.iterators.kebs.instances.time.LocalDateTimeString import pl.iterators.kebs.instances.time.mixins.{DurationNanosLong, InstantEpochMilliLong} -import pl.iterators.kebs.instances.TimeInstances +import pl.iterators.kebs.core.instances.InstanceConverter import play.api.libs.json.{Format, JsNumber, JsString, JsSuccess} import java.time._ @@ -18,8 +18,8 @@ class TimeInstancesMixinTests extends AnyFunSuite with Matchers { object TimeInstancesProtocol extends InstantEpochMilliLong import TimeInstancesProtocol._ - "implicitly[CaseClass1Rep[Instant, Long]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[Long, Instant]]" shouldNot typeCheck + "implicitly[ValueClassLike[Instant, Long]]" shouldNot typeCheck + "implicitly[ValueClassLike[Long, Instant]]" shouldNot typeCheck val jf = implicitly[Format[Instant]] val value = 123456789 @@ -33,10 +33,10 @@ class TimeInstancesMixinTests extends AnyFunSuite with Matchers { object TimeInstancesProtocol extends DurationNanosLong with InstantEpochMilliLong import TimeInstancesProtocol._ - "implicitly[CaseClass1Rep[Instant, Long]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[Long, Instant]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[Duration, Long]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[Long, Duration]]" shouldNot typeCheck + "implicitly[ValueClassLike[Instant, Long]]" shouldNot typeCheck + "implicitly[ValueClassLike[Long, Instant]]" shouldNot typeCheck + "implicitly[ValueClassLike[Duration, Long]]" shouldNot typeCheck + "implicitly[ValueClassLike[Long, Duration]]" shouldNot typeCheck val jf_duration = implicitly[Format[Duration]] val value_duration = 123456789 @@ -62,8 +62,8 @@ class TimeInstancesMixinTests extends AnyFunSuite with Matchers { } import TimeInstancesProtocol._ - "implicitly[CaseClass1Rep[LocalDateTime, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, LocalDateTime]]" shouldNot typeCheck + "implicitly[ValueClassLike[LocalDateTime, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, LocalDateTime]]" shouldNot typeCheck val jf = implicitly[Format[LocalDateTime]] val value = "2007/12/03 10:30" @@ -95,8 +95,8 @@ class TimeInstancesMixinTests extends AnyFunSuite with Matchers { } import TimeInstancesProtocol._ - "implicitly[CaseClass1Rep[LocalDateTime, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, LocalDateTime]]" shouldNot typeCheck + "implicitly[ValueClassLike[LocalDateTime, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, LocalDateTime]]" shouldNot typeCheck val jf = implicitly[Format[LocalDateTime]] val value = "2007/12/03 10:30" diff --git a/play-json/src/test/scala/instances/TimeInstancesTests.scala b/play-json/src/test/scala/pl/iterators/kebs/json/instances/TimeInstancesTests.scala similarity index 76% rename from play-json/src/test/scala/instances/TimeInstancesTests.scala rename to play-json/src/test/scala/pl/iterators/kebs/json/instances/TimeInstancesTests.scala index 3f74aa00..56257847 100644 --- a/play-json/src/test/scala/instances/TimeInstancesTests.scala +++ b/play-json/src/test/scala/pl/iterators/kebs/json/instances/TimeInstancesTests.scala @@ -1,8 +1,8 @@ -package instances +package pl.iterators.kebs.json.instances import org.scalatest.funsuite.AnyFunSuite import org.scalatest.matchers.should.Matchers -import pl.iterators.kebs.instances.InstanceConverter.DecodeErrorException +import pl.iterators.kebs.core.instances.InstanceConverter.DecodeErrorException import pl.iterators.kebs.instances.TimeInstances import play.api.libs.json.{Format, JsNumber, JsString, JsSuccess} @@ -10,40 +10,40 @@ import java.time._ class TimeInstancesTests extends AnyFunSuite with Matchers with TimeInstances { import pl.iterators.kebs.json._ - test("No CaseClass1Rep implicits derived") { - - "implicitly[CaseClass1Rep[DayOfWeek, Int]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[Int, DayOfWeek]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[Duration, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, Duration]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[Instant, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, Instant]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[LocalDate, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, LocalDate]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[LocalDateTime, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, LocalDateTime]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[LocalTime, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, LocalTime]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[Month, Int]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[Int, Month]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[MonthDay, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, MonthDay]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[OffsetDateTime, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, OffsetDateTime]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[OffsetTime, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, OffsetTime]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[Period, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, Period]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[Year, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, Year]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[YearMonth, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, YearMonth]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[ZoneId, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, ZoneId]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[ZoneOffset, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, ZoneOffset]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[ZonedDateTime, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, ZonedDateTime]]" shouldNot typeCheck + test("No ValueClassLike implicits derived") { + + "implicitly[ValueClassLike[DayOfWeek, Int]]" shouldNot typeCheck + "implicitly[ValueClassLike[Int, DayOfWeek]]" shouldNot typeCheck + "implicitly[ValueClassLike[Duration, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, Duration]]" shouldNot typeCheck + "implicitly[ValueClassLike[Instant, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, Instant]]" shouldNot typeCheck + "implicitly[ValueClassLike[LocalDate, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, LocalDate]]" shouldNot typeCheck + "implicitly[ValueClassLike[LocalDateTime, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, LocalDateTime]]" shouldNot typeCheck + "implicitly[ValueClassLike[LocalTime, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, LocalTime]]" shouldNot typeCheck + "implicitly[ValueClassLike[Month, Int]]" shouldNot typeCheck + "implicitly[ValueClassLike[Int, Month]]" shouldNot typeCheck + "implicitly[ValueClassLike[MonthDay, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, MonthDay]]" shouldNot typeCheck + "implicitly[ValueClassLike[OffsetDateTime, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, OffsetDateTime]]" shouldNot typeCheck + "implicitly[ValueClassLike[OffsetTime, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, OffsetTime]]" shouldNot typeCheck + "implicitly[ValueClassLike[Period, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, Period]]" shouldNot typeCheck + "implicitly[ValueClassLike[Year, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, Year]]" shouldNot typeCheck + "implicitly[ValueClassLike[YearMonth, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, YearMonth]]" shouldNot typeCheck + "implicitly[ValueClassLike[ZoneId, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, ZoneId]]" shouldNot typeCheck + "implicitly[ValueClassLike[ZoneOffset, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, ZoneOffset]]" shouldNot typeCheck + "implicitly[ValueClassLike[ZonedDateTime, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, ZonedDateTime]]" shouldNot typeCheck } test("DayOfWeek standard format") { diff --git a/play-json/src/test/scala/instances/UtilInstancesTests.scala b/play-json/src/test/scala/pl/iterators/kebs/json/instances/UtilInstancesTests.scala similarity index 72% rename from play-json/src/test/scala/instances/UtilInstancesTests.scala rename to play-json/src/test/scala/pl/iterators/kebs/json/instances/UtilInstancesTests.scala index c59cfa7e..9f9902e3 100644 --- a/play-json/src/test/scala/instances/UtilInstancesTests.scala +++ b/play-json/src/test/scala/pl/iterators/kebs/json/instances/UtilInstancesTests.scala @@ -1,8 +1,8 @@ -package instances +package pl.iterators.kebs.json.instances import org.scalatest.funsuite.AnyFunSuite import org.scalatest.matchers.should.Matchers -import pl.iterators.kebs.instances.InstanceConverter.DecodeErrorException +import pl.iterators.kebs.core.instances.InstanceConverter.DecodeErrorException import pl.iterators.kebs.instances.UtilInstances import play.api.libs.json.{Format, JsString, JsSuccess} @@ -10,14 +10,14 @@ import java.util.{Currency, Locale, UUID} class UtilInstancesTests extends AnyFunSuite with Matchers with UtilInstances { import pl.iterators.kebs.json._ - test("No CaseClass1Rep implicits derived") { - - "implicitly[CaseClass1Rep[Currency, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, Currency]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[Locale, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, Locale]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[UUID, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, UUID]]" shouldNot typeCheck + test("No ValueClassLike implicits derived") { + + "implicitly[ValueClassLike[Currency, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, Currency]]" shouldNot typeCheck + "implicitly[ValueClassLike[Locale, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, Locale]]" shouldNot typeCheck + "implicitly[ValueClassLike[UUID, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, UUID]]" shouldNot typeCheck } test("Currency standard format") { diff --git a/scalacheck/src/main/scala-2/pl/iterators/kebs/scalacheck/CommonArbitrarySupport.scala b/scalacheck/src/main/scala-2/pl/iterators/kebs/scalacheck/CommonArbitrarySupport.scala index 6615a404..a00fb214 100644 --- a/scalacheck/src/main/scala-2/pl/iterators/kebs/scalacheck/CommonArbitrarySupport.scala +++ b/scalacheck/src/main/scala-2/pl/iterators/kebs/scalacheck/CommonArbitrarySupport.scala @@ -2,7 +2,7 @@ package pl.iterators.kebs.scalacheck import enumeratum.ScalacheckInstances import org.scalacheck.{Arbitrary, Gen, ScalacheckShapeless} -import pl.iterators.kebs.macros.CaseClass1Rep +import pl.iterators.kebs.core.macros.ValueClassLike import java.net.{URI, URL} import java.time.temporal.ChronoUnit @@ -12,9 +12,9 @@ import scala.reflect.ClassTag import scala.util.Random trait CommonArbitrarySupport extends ScalacheckShapeless with ScalacheckInstances { - implicit def caseClass1RepArbitraryPredef[T, A]( - implicit rep: CaseClass1Rep[T, A], - arbitrary: Arbitrary[A] + implicit def valueClassLikeArbitraryPredef[T, A]( + implicit rep: ValueClassLike[T, A], + arbitrary: Arbitrary[A] ): Arbitrary[T] = Arbitrary(arbitrary.arbitrary.map(rep.apply(_))) } \ No newline at end of file diff --git a/scalacheck/src/main/scala-2/pl/iterators/kebs/scalacheck/macros/KebsScalacheckGeneratorsMacro.scala b/scalacheck/src/main/scala-2/pl/iterators/kebs/scalacheck/macros/KebsScalacheckGeneratorsMacro.scala index 9b3b123d..a76c650b 100644 --- a/scalacheck/src/main/scala-2/pl/iterators/kebs/scalacheck/macros/KebsScalacheckGeneratorsMacro.scala +++ b/scalacheck/src/main/scala-2/pl/iterators/kebs/scalacheck/macros/KebsScalacheckGeneratorsMacro.scala @@ -1,6 +1,6 @@ package pl.iterators.kebs.scalacheck.macros -import pl.iterators.kebs.macros.MacroUtils +import pl.iterators.kebs.core.macros.MacroUtils import scala.language.experimental.macros import scala.reflect.macros._ import pl.iterators.kebs.scalacheck._ diff --git a/scalacheck/src/main/scala-3/pl/iterators/kebs/scalacheck/CommonArbitrarySupport.scala b/scalacheck/src/main/scala-3/pl/iterators/kebs/scalacheck/CommonArbitrarySupport.scala index db3b40bb..70859a94 100644 --- a/scalacheck/src/main/scala-3/pl/iterators/kebs/scalacheck/CommonArbitrarySupport.scala +++ b/scalacheck/src/main/scala-3/pl/iterators/kebs/scalacheck/CommonArbitrarySupport.scala @@ -1,7 +1,7 @@ package pl.iterators.kebs.scalacheck import org.scalacheck.{Arbitrary, Gen} -import pl.iterators.kebs.macros.CaseClass1Rep +import pl.iterators.kebs.core.macros.ValueClassLike import java.net.{URI, URL} import java.time.temporal.ChronoUnit @@ -12,9 +12,9 @@ import scala.util.Random import io.github.martinhh.derived.scalacheck.given import enumeratum.ScalacheckInstances trait CommonArbitrarySupport extends ScalacheckInstances { - implicit def caseClass1RepArbitraryPredef[T, A]( - implicit rep: CaseClass1Rep[T, A], - arbitrary: Arbitrary[A] + implicit def ValueClassLikeArbitraryPredef[T, A]( + implicit rep: ValueClassLike[T, A], + arbitrary: Arbitrary[A] ): Arbitrary[T] = Arbitrary(arbitrary.arbitrary.map(rep.apply(_))) } \ No newline at end of file diff --git a/scalacheck/src/main/scala/pl/iterators/kebs/scalacheck/ArbitrarySupport.scala b/scalacheck/src/main/scala/pl/iterators/kebs/scalacheck/ArbitrarySupport.scala index 4de5395c..6465f9ad 100644 --- a/scalacheck/src/main/scala/pl/iterators/kebs/scalacheck/ArbitrarySupport.scala +++ b/scalacheck/src/main/scala/pl/iterators/kebs/scalacheck/ArbitrarySupport.scala @@ -2,7 +2,7 @@ package pl.iterators.kebs.scalacheck import enumeratum.ScalacheckInstances import org.scalacheck.{Arbitrary, Gen, ScalacheckShapeless} -import pl.iterators.kebs.macros.CaseClass1Rep +import pl.iterators.kebs.core.macros.ValueClassLike import java.net.{URI, URL} import java.time.temporal.ChronoUnit diff --git a/scalacheck/src/test/scala-3/OpaqueGeneratorsTests.scala b/scalacheck/src/test/scala-3/pl/iterators/kebs/scalacheck/OpaqueGeneratorsTests.scala similarity index 100% rename from scalacheck/src/test/scala-3/OpaqueGeneratorsTests.scala rename to scalacheck/src/test/scala-3/pl/iterators/kebs/scalacheck/OpaqueGeneratorsTests.scala diff --git a/slick/src/main/scala/pl/iterators/kebs/enums/KebsEnums.scala b/slick/src/main/scala/pl/iterators/kebs/enums/KebsEnums.scala deleted file mode 100644 index 8ae7ebe2..00000000 --- a/slick/src/main/scala/pl/iterators/kebs/enums/KebsEnums.scala +++ /dev/null @@ -1,40 +0,0 @@ -package pl.iterators.kebs.enums - -import enumeratum.{Enum, EnumEntry} -import enumeratum.values.{ValueEnum, ValueEnumEntry} -import pl.iterators.kebs.macros.enums.{EnumOf, ValueEnumOf} -import slick.lifted.Isomorphism - -trait SlickEnum { - def enumIsomorphism[E <: EnumEntry](`enum`: Enum[E]): Isomorphism[E, String] = new Isomorphism[E, String](_.entryName, `enum`.withName) - def uppercaseEnumIsomorphism[E <: EnumEntry](`enum`: Enum[E]): Isomorphism[E, String] = - new Isomorphism[E, String](_.entryName.toUpperCase, `enum`.withNameUppercaseOnly) - def lowercaseEnumIsomorphism[E <: EnumEntry](`enum`: Enum[E]): Isomorphism[E, String] = - new Isomorphism[E, String](_.entryName.toLowerCase, `enum`.withNameLowercaseOnly) - - implicit def enumListColumnType[E <: EnumEntry](implicit iso: Isomorphism[E, String]): Isomorphism[List[E], List[String]] = - new Isomorphism[List[E], List[String]](_.map(iso.map), _.map(iso.comap)) - implicit def enumSeqColumnType[E <: EnumEntry](implicit iso: Isomorphism[E, String]): Isomorphism[Seq[E], List[String]] = - new Isomorphism[Seq[E], List[String]](_.map(iso.map).toList, _.map(iso.comap)) -} - -trait SlickValueEnum { - def valueEnumIsomorphism[V, E <: ValueEnumEntry[V]](`enum`: ValueEnum[V, E]): Isomorphism[E, V] = - new Isomorphism[E, V](_.value, `enum`.withValue) -} - -trait KebsEnums extends SlickEnum with SlickValueEnum { - implicit def enumValueColumn[E <: EnumEntry](implicit ev: EnumOf[E]): Isomorphism[E, String] = enumIsomorphism(ev.`enum`) - implicit def valueEnumColumn[V, E <: ValueEnumEntry[V]](implicit ev: ValueEnumOf[V, E]): Isomorphism[E, V] = - valueEnumIsomorphism(ev.valueEnum) - - trait Uppercase extends SlickEnum { - implicit def enumValueColumn[E <: EnumEntry](implicit ev: EnumOf[E]): Isomorphism[E, String] = uppercaseEnumIsomorphism(ev.`enum`) - } - - trait Lowercase extends SlickEnum { - implicit def enumValueColumn[E <: EnumEntry](implicit ev: EnumOf[E]): Isomorphism[E, String] = lowercaseEnumIsomorphism(ev.`enum`) - } -} - -object KebsEnums extends KebsEnums diff --git a/slick/src/main/scala/pl/iterators/kebs/package.scala b/slick/src/main/scala/pl/iterators/kebs/package.scala deleted file mode 100644 index feea7054..00000000 --- a/slick/src/main/scala/pl/iterators/kebs/package.scala +++ /dev/null @@ -1,3 +0,0 @@ -package pl.iterators - -package object kebs extends Kebs diff --git a/slick/src/main/scala/pl/iterators/kebs/Kebs.scala b/slick/src/main/scala/pl/iterators/kebs/slick/Kebs.scala similarity index 86% rename from slick/src/main/scala/pl/iterators/kebs/Kebs.scala rename to slick/src/main/scala/pl/iterators/kebs/slick/Kebs.scala index fdd135c2..a5b8dcb0 100644 --- a/slick/src/main/scala/pl/iterators/kebs/Kebs.scala +++ b/slick/src/main/scala/pl/iterators/kebs/slick/Kebs.scala @@ -1,30 +1,30 @@ -package pl.iterators.kebs +package pl.iterators.kebs.slick -import pl.iterators.kebs.hstore.KebsHStoreColumnExtensionMethods -import pl.iterators.kebs.instances.InstanceConverter -import pl.iterators.kebs.macros.CaseClass1Rep +import pl.iterators.kebs.core.instances.InstanceConverter +import pl.iterators.kebs.core.macros.{CaseClass1ToValueClass, ValueClassLike} +import pl.iterators.kebs.slick.hstore.KebsHStoreColumnExtensionMethods import slick.ast.{BaseTypedType, NumericTypedType} import slick.jdbc.JdbcType import slick.lifted._ import scala.language.implicitConversions -trait KebsColumnExtensionMethods { - implicit def stringValueColumnExt[CC](rep: Rep[CC])(implicit ev: CaseClass1Rep[CC, String]): StringColumnExtensionMethods[CC] = +trait KebsColumnExtensionMethods extends CaseClass1ToValueClass { + implicit def stringValueColumnExt[CC](rep: Rep[CC])(implicit ev: ValueClassLike[CC, String]): StringColumnExtensionMethods[CC] = new StringColumnExtensionMethods[CC](rep) implicit def stringValueOptionColumnExt[CC](rep: Rep[Option[CC]])( - implicit ev: CaseClass1Rep[CC, String]): StringColumnExtensionMethods[Option[CC]] = new StringColumnExtensionMethods[Option[CC]](rep) + implicit ev: ValueClassLike[CC, String]): StringColumnExtensionMethods[Option[CC]] = new StringColumnExtensionMethods[Option[CC]](rep) implicit def numericValueColumnExt[CC, B](rep: Rep[CC])( - implicit ev1: CaseClass1Rep[CC, B], - ev2: BaseTypedType[B] with NumericTypedType): BaseNumericColumnExtensionMethods[CC] = new BaseNumericColumnExtensionMethods[CC](rep) + implicit ev1: ValueClassLike[CC, B], + ev2: BaseTypedType[B] with NumericTypedType): BaseNumericColumnExtensionMethods[CC] = new BaseNumericColumnExtensionMethods[CC](rep) implicit def numericValueOptionColumnExt[CC, B](rep: Rep[Option[CC]])( - implicit ev1: CaseClass1Rep[CC, B], - ev2: BaseTypedType[B] with NumericTypedType): OptionNumericColumnExtensionMethods[CC] = + implicit ev1: ValueClassLike[CC, B], + ev2: BaseTypedType[B] with NumericTypedType): OptionNumericColumnExtensionMethods[CC] = new OptionNumericColumnExtensionMethods[CC](rep) - implicit def booleanValueColumnExt[CC](rep: Rep[CC])(implicit ev: CaseClass1Rep[CC, Boolean]): BooleanColumnExtensionMethods[CC] = + implicit def booleanValueColumnExt[CC](rep: Rep[CC])(implicit ev: ValueClassLike[CC, Boolean]): BooleanColumnExtensionMethods[CC] = new BooleanColumnExtensionMethods[CC](rep) implicit def booleanValueOptionColumnExt[CC](rep: Rep[Option[CC]])( - implicit ev: CaseClass1Rep[CC, Boolean]): BooleanColumnExtensionMethods[Option[CC]] = + implicit ev: ValueClassLike[CC, Boolean]): BooleanColumnExtensionMethods[Option[CC]] = new BooleanColumnExtensionMethods[Option[CC]](rep) implicit def hstoreColumnExt[KEY, VALUE](c: Rep[Map[KEY, VALUE]])( @@ -37,23 +37,23 @@ trait KebsColumnExtensionMethods { new KebsHStoreColumnExtensionMethods[KEY, VALUE, Map[KEY, VALUE]](c) @inline implicit def getCCOptionMapper2TT_1[B1, B2: BaseTypedType, BR, CC]( - implicit ev: CaseClass1Rep[CC, B1]): OptionMapper2[B1, B2, BR, CC, B2, BR] = + implicit ev: ValueClassLike[CC, B1]): OptionMapper2[B1, B2, BR, CC, B2, BR] = OptionMapper2.plain.asInstanceOf[OptionMapper2[B1, B2, BR, CC, B2, BR]] - @inline implicit def getCCOptionMapper2TT_2[B1, B2, BR, CC](implicit ev: CaseClass1Rep[CC, B2]): OptionMapper2[CC, CC, BR, CC, B2, BR] = + @inline implicit def getCCOptionMapper2TT_2[B1, B2, BR, CC](implicit ev: ValueClassLike[CC, B2]): OptionMapper2[CC, CC, BR, CC, B2, BR] = OptionMapper2.plain.asInstanceOf[OptionMapper2[CC, CC, BR, CC, B2, BR]] @inline implicit def getCCOptionMapper2TO[B1, B2: BaseTypedType, BR, CC]( - implicit ev: CaseClass1Rep[CC, B1]): OptionMapper2[B1, B2, BR, CC, Option[B2], Option[BR]] = + implicit ev: ValueClassLike[CC, B1]): OptionMapper2[B1, B2, BR, CC, Option[B2], Option[BR]] = OptionMapper2.option.asInstanceOf[OptionMapper2[B1, B2, BR, CC, Option[B2], Option[BR]]] @inline implicit def getCCOptionMapper2OT[B1, B2: BaseTypedType, BR, CC]( - implicit ev: CaseClass1Rep[CC, B1]): OptionMapper2[B1, B2, BR, Option[CC], B2, Option[BR]] = + implicit ev: ValueClassLike[CC, B1]): OptionMapper2[B1, B2, BR, Option[CC], B2, Option[BR]] = OptionMapper2.option.asInstanceOf[OptionMapper2[B1, B2, BR, Option[CC], B2, Option[BR]]] @inline implicit def getCCOptionMapper2OO[B1, B2: BaseTypedType, BR, CC]( - implicit ev: CaseClass1Rep[CC, B1]): OptionMapper2[B1, B2, BR, Option[CC], Option[B2], Option[BR]] = + implicit ev: ValueClassLike[CC, B1]): OptionMapper2[B1, B2, BR, Option[CC], Option[B2], Option[BR]] = OptionMapper2.option.asInstanceOf[OptionMapper2[B1, B2, BR, Option[CC], Option[B2], Option[BR]]] } trait Kebs extends KebsColumnExtensionMethods { - implicit def valueColumnType[CC, B](implicit rep1: CaseClass1Rep[CC, B]): Isomorphism[CC, B] = + implicit def valueColumnType[CC, B](implicit rep1: ValueClassLike[CC, B]): Isomorphism[CC, B] = new Isomorphism[CC, B](rep1.unapply, rep1.apply) implicit def valueTransitionColumnType[CC, B](implicit ico: InstanceConverter[CC, B]): Isomorphism[CC, B] = new Isomorphism[CC, B](ico.encode, ico.decode) diff --git a/slick/src/main/scala/pl/iterators/kebs/slick/enums/KebsEnums.scala b/slick/src/main/scala/pl/iterators/kebs/slick/enums/KebsEnums.scala new file mode 100644 index 00000000..d9e16975 --- /dev/null +++ b/slick/src/main/scala/pl/iterators/kebs/slick/enums/KebsEnums.scala @@ -0,0 +1,42 @@ +package pl.iterators.kebs.slick.enums + +import pl.iterators.kebs.core.enums.{EnumLike, ValueEnumLike, ValueEnumLikeEntry} +import slick.lifted.Isomorphism + +trait SlickEnum { + def enumIsomorphism[E](`enum`: EnumLike[E]): Isomorphism[E, String] = new Isomorphism[E, String](_.toString, `enum`.withName) + + def uppercaseEnumIsomorphism[E](`enum`: EnumLike[E]): Isomorphism[E, String] = + new Isomorphism[E, String](_.toString.toUpperCase, `enum`.withNameUppercaseOnly) + + def lowercaseEnumIsomorphism[E](`enum`: EnumLike[E]): Isomorphism[E, String] = + new Isomorphism[E, String](_.toString.toLowerCase, `enum`.withNameLowercaseOnly) + + implicit def enumListColumnType[E](implicit iso: Isomorphism[E, String]): Isomorphism[List[E], List[String]] = + new Isomorphism[List[E], List[String]](_.map(iso.map), _.map(iso.comap)) + + implicit def enumSeqColumnType[E](implicit iso: Isomorphism[E, String]): Isomorphism[Seq[E], List[String]] = + new Isomorphism[Seq[E], List[String]](_.map(iso.map).toList, _.map(iso.comap)) +} + +trait SlickValueEnum { + def valueEnumIsomorphism[V, E <: ValueEnumLikeEntry[V]](`enum`: ValueEnumLike[V, E]): Isomorphism[E, V] = + new Isomorphism[E, V](_.value, `enum`.withValue) +} + +trait KebsEnums extends SlickEnum with SlickValueEnum { + implicit def enumValueColumn[E](implicit ev: EnumLike[E]): Isomorphism[E, String] = enumIsomorphism(ev) + + implicit def valueEnumColumn[V, E <: ValueEnumLikeEntry[V]](implicit ev: ValueEnumLike[V, E]): Isomorphism[E, V] = + valueEnumIsomorphism(ev) + + trait Uppercase extends SlickEnum { + implicit def enumValueColumn[E](implicit ev: EnumLike[E]): Isomorphism[E, String] = uppercaseEnumIsomorphism(ev) + } + + trait Lowercase extends SlickEnum { + implicit def enumValueColumn[E](implicit ev: EnumLike[E]): Isomorphism[E, String] = lowercaseEnumIsomorphism(ev) + } +} + +object KebsEnums extends KebsEnums \ No newline at end of file diff --git a/slick/src/main/scala/pl/iterators/kebs/enums/package.scala b/slick/src/main/scala/pl/iterators/kebs/slick/enums/package.scala similarity index 79% rename from slick/src/main/scala/pl/iterators/kebs/enums/package.scala rename to slick/src/main/scala/pl/iterators/kebs/slick/enums/package.scala index 5252f17c..6a20e2d5 100644 --- a/slick/src/main/scala/pl/iterators/kebs/enums/package.scala +++ b/slick/src/main/scala/pl/iterators/kebs/slick/enums/package.scala @@ -1,4 +1,4 @@ -package pl.iterators.kebs +package pl.iterators.kebs.slick package object enums extends KebsEnums { diff --git a/slick/src/main/scala/pl/iterators/kebs/hstore/KebsHStoreColumnExtensionMethods.scala b/slick/src/main/scala/pl/iterators/kebs/slick/hstore/KebsHStoreColumnExtensionMethods.scala similarity index 98% rename from slick/src/main/scala/pl/iterators/kebs/hstore/KebsHStoreColumnExtensionMethods.scala rename to slick/src/main/scala/pl/iterators/kebs/slick/hstore/KebsHStoreColumnExtensionMethods.scala index cefc3dcc..5cdf80c7 100644 --- a/slick/src/main/scala/pl/iterators/kebs/hstore/KebsHStoreColumnExtensionMethods.scala +++ b/slick/src/main/scala/pl/iterators/kebs/slick/hstore/KebsHStoreColumnExtensionMethods.scala @@ -1,4 +1,4 @@ -package pl.iterators.kebs.hstore +package pl.iterators.kebs.slick.hstore import slick.ast.Library.{SqlFunction, SqlOperator} import slick.ast.ScalaBaseType._ diff --git a/slick/src/main/scala/pl/iterators/kebs/slick/package.scala b/slick/src/main/scala/pl/iterators/kebs/slick/package.scala new file mode 100644 index 00000000..c3fbccc3 --- /dev/null +++ b/slick/src/main/scala/pl/iterators/kebs/slick/package.scala @@ -0,0 +1,3 @@ +package pl.iterators.kebs + +package object slick extends Kebs diff --git a/slick/src/test/scala/arrays/ListIsomorphismTest.scala b/slick/src/test/scala/pl/iterators/kebs/slick/arrays/ListIsomorphismTest.scala similarity index 77% rename from slick/src/test/scala/arrays/ListIsomorphismTest.scala rename to slick/src/test/scala/pl/iterators/kebs/slick/arrays/ListIsomorphismTest.scala index e386d2a0..c71cf665 100644 --- a/slick/src/test/scala/arrays/ListIsomorphismTest.scala +++ b/slick/src/test/scala/pl/iterators/kebs/slick/arrays/ListIsomorphismTest.scala @@ -1,4 +1,4 @@ -package arrays +package pl.iterators.kebs.slick.arrays import org.scalatest.funsuite.AnyFunSuite import org.scalatest.matchers.should.Matchers @@ -6,15 +6,15 @@ import pl.iterators.kebs.instances.time.YearMonthString import slick.lifted.Isomorphism class ListIsomorphismTest extends AnyFunSuite with Matchers with YearMonthString { - import pl.iterators.kebs._ + import pl.iterators.kebs.slick._ case class C(a: String) - test("No CaseClass1Rep implicits derived") { - import pl.iterators.kebs.macros.CaseClass1Rep + test("No ValueClassLike implicits derived") { + import pl.iterators.kebs.core.macros.ValueClassLike - "implicitly[CaseClass1Rep[YearMonth, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, YearMonth]]" shouldNot typeCheck + "implicitly[ValueClassLike[YearMonth, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, YearMonth]]" shouldNot typeCheck } test("Case class isomorphism implies list isomorphism") { diff --git a/slick/src/test/scala/arrays/SlickPgArrayColumnTypeTests.scala b/slick/src/test/scala/pl/iterators/kebs/slick/arrays/SlickPgArrayColumnTypeTests.scala similarity index 93% rename from slick/src/test/scala/arrays/SlickPgArrayColumnTypeTests.scala rename to slick/src/test/scala/pl/iterators/kebs/slick/arrays/SlickPgArrayColumnTypeTests.scala index 25237b6f..64cf1cd4 100644 --- a/slick/src/test/scala/arrays/SlickPgArrayColumnTypeTests.scala +++ b/slick/src/test/scala/pl/iterators/kebs/slick/arrays/SlickPgArrayColumnTypeTests.scala @@ -1,16 +1,17 @@ -package arrays +package pl.iterators.kebs.slick.arrays import com.github.tminglei.slickpg._ import enumeratum.{Enum, EnumEntry} import org.scalatest.funsuite.AnyFunSuite import org.scalatest.matchers.should.Matchers +import pl.iterators.kebs.enumeratum.KebsEnumeratum +import pl.iterators.kebs.slick.enums.KebsEnums -class SlickPgArrayColumnTypeTests extends AnyFunSuite with Matchers { +class SlickPgArrayColumnTypeTests extends AnyFunSuite with Matchers with KebsEnumeratum { case class Institution(value: Long) case class MarketFinancialProduct(value: String) - import pl.iterators.kebs.Kebs - import pl.iterators.kebs.enums.KebsEnums + import pl.iterators.kebs.slick.Kebs object MyPostgresProfile extends ExPostgresProfile with PgArraySupport { override val api: APIWithArrays = new APIWithArrays {} diff --git a/slick/src/test/scala/arrays/SlickPgArrayTests.scala b/slick/src/test/scala/pl/iterators/kebs/slick/arrays/SlickPgArrayTests.scala similarity index 87% rename from slick/src/test/scala/arrays/SlickPgArrayTests.scala rename to slick/src/test/scala/pl/iterators/kebs/slick/arrays/SlickPgArrayTests.scala index 2218d9a2..cb884501 100644 --- a/slick/src/test/scala/arrays/SlickPgArrayTests.scala +++ b/slick/src/test/scala/pl/iterators/kebs/slick/arrays/SlickPgArrayTests.scala @@ -1,4 +1,4 @@ -package arrays +package pl.iterators.kebs.slick.arrays import com.github.tminglei.slickpg._ import org.scalatest.funsuite.AnyFunSuite @@ -9,8 +9,8 @@ import java.time.YearMonth import java.util.UUID class SlickPgArrayTests extends AnyFunSuite with Matchers { - import pl.iterators.kebs.Kebs import pl.iterators.kebs.instances.time.YearMonthString + import pl.iterators.kebs.slick.Kebs trait PostgresDriver extends ExPostgresProfile with PgArraySupport { override val api: ArrayAPI = new ArrayAPI {} @@ -40,11 +40,11 @@ class SlickPgArrayTests extends AnyFunSuite with Matchers { override def * : ProvenShape[Test] = (id, ccList) <> ((Test.apply _).tupled, Test.unapply) } - test("No CaseClass1Rep implicits derived") { - import pl.iterators.kebs.macros.CaseClass1Rep + test("No ValueClassLike implicits derived") { + import pl.iterators.kebs.core.macros.ValueClassLike - "implicitly[CaseClass1Rep[YearMonth, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, YearMonth]]" shouldNot typeCheck + "implicitly[ValueClassLike[YearMonth, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, YearMonth]]" shouldNot typeCheck } test("Case class list extension methods") { diff --git a/slick/src/test/scala/caseclasses/CaseClassIsomorphismTests.scala b/slick/src/test/scala/pl/iterators/kebs/slick/caseclasses/CaseClassIsomorphismTests.scala similarity index 97% rename from slick/src/test/scala/caseclasses/CaseClassIsomorphismTests.scala rename to slick/src/test/scala/pl/iterators/kebs/slick/caseclasses/CaseClassIsomorphismTests.scala index 3936891d..29a24d98 100644 --- a/slick/src/test/scala/caseclasses/CaseClassIsomorphismTests.scala +++ b/slick/src/test/scala/pl/iterators/kebs/slick/caseclasses/CaseClassIsomorphismTests.scala @@ -1,4 +1,4 @@ -package caseclasses +package pl.iterators.kebs.slick.caseclasses import org.scalatest.funsuite.AnyFunSuite import org.scalatest.matchers.should.Matchers diff --git a/slick/src/test/scala/caseclasses/SlickMappedColumnTypeTests.scala b/slick/src/test/scala/pl/iterators/kebs/slick/caseclasses/SlickMappedColumnTypeTests.scala similarity index 98% rename from slick/src/test/scala/caseclasses/SlickMappedColumnTypeTests.scala rename to slick/src/test/scala/pl/iterators/kebs/slick/caseclasses/SlickMappedColumnTypeTests.scala index ee1148b9..cbdaab8f 100644 --- a/slick/src/test/scala/caseclasses/SlickMappedColumnTypeTests.scala +++ b/slick/src/test/scala/pl/iterators/kebs/slick/caseclasses/SlickMappedColumnTypeTests.scala @@ -1,4 +1,4 @@ -package caseclasses +package pl.iterators.kebs.slick.caseclasses import org.scalatest.funsuite.AnyFunSuite import org.scalatest.matchers.should.Matchers diff --git a/slick/src/test/scala/caseclasses/SlickPgTests.scala b/slick/src/test/scala/pl/iterators/kebs/slick/caseclasses/SlickPgTests.scala similarity index 97% rename from slick/src/test/scala/caseclasses/SlickPgTests.scala rename to slick/src/test/scala/pl/iterators/kebs/slick/caseclasses/SlickPgTests.scala index ce07571a..8b91fcbb 100644 --- a/slick/src/test/scala/caseclasses/SlickPgTests.scala +++ b/slick/src/test/scala/pl/iterators/kebs/slick/caseclasses/SlickPgTests.scala @@ -1,4 +1,4 @@ -package caseclasses +package pl.iterators.kebs.slick.caseclasses import com.github.tminglei.slickpg._ import org.scalatest.funsuite.AnyFunSuite @@ -7,7 +7,8 @@ import org.scalatest.matchers.should.Matchers import java.util.UUID class SlickPgTests extends AnyFunSuite with Matchers { - import pl.iterators.kebs.Kebs + + import pl.iterators.kebs.slick.Kebs import slick.lifted.ProvenShape case class ServiceLineName(name: String) diff --git a/slick/src/test/scala/enums/EnumIsomorphismTests.scala b/slick/src/test/scala/pl/iterators/kebs/slick/enums/EnumIsomorphismTests.scala similarity index 71% rename from slick/src/test/scala/enums/EnumIsomorphismTests.scala rename to slick/src/test/scala/pl/iterators/kebs/slick/enums/EnumIsomorphismTests.scala index 83653a7f..cdd5fb47 100644 --- a/slick/src/test/scala/enums/EnumIsomorphismTests.scala +++ b/slick/src/test/scala/pl/iterators/kebs/slick/enums/EnumIsomorphismTests.scala @@ -3,9 +3,11 @@ package enums import enumeratum.{Enum, EnumEntry} import org.scalatest.funsuite.AnyFunSuite import org.scalatest.matchers.should.Matchers +import pl.iterators.kebs.core.enums.EnumLike import slick.lifted.Isomorphism +import pl.iterators.kebs.enumeratum.KebsEnumeratum -class EnumIsomorphismTests extends AnyFunSuite with Matchers { +class EnumIsomorphismTests extends AnyFunSuite with Matchers with KebsEnumeratum { sealed trait Greeting extends EnumEntry @@ -21,7 +23,7 @@ class EnumIsomorphismTests extends AnyFunSuite with Matchers { import Greeting._ test("Implicit isomorphism for EnumEntry") { - import pl.iterators.kebs.enums._ + import pl.iterators.kebs.slick.enums._ val iso = implicitly[Isomorphism[Greeting, String]] iso.map(Hello) shouldBe "Hello" @@ -29,15 +31,19 @@ class EnumIsomorphismTests extends AnyFunSuite with Matchers { } test("Implicit isomorphism for EnumEntry - lowercase") { - import pl.iterators.kebs.enums.lowercase._ + import pl.iterators.kebs.slick.enums.lowercase._ + + val enumm = new EnumLike[Greeting] { + override def values: Seq[Greeting] = Greeting.values} val iso = implicitly[Isomorphism[Greeting, String]] + iso.map(GoodBye) shouldBe "goodbye" iso.comap("goodbye") shouldBe GoodBye } test("Implicit isomorphism for EnumEntry - uppercase") { - import pl.iterators.kebs.enums.uppercase._ + import pl.iterators.kebs.slick.enums.uppercase._ val iso = implicitly[Isomorphism[Greeting, String]] iso.map(GoodBye) shouldBe "GOODBYE" diff --git a/slick/src/test/scala/enums/SlickMappedEnumColumnTypeTests.scala b/slick/src/test/scala/pl/iterators/kebs/slick/enums/SlickMappedEnumColumnTypeTests.scala similarity index 89% rename from slick/src/test/scala/enums/SlickMappedEnumColumnTypeTests.scala rename to slick/src/test/scala/pl/iterators/kebs/slick/enums/SlickMappedEnumColumnTypeTests.scala index 68e67755..0e6bed9d 100644 --- a/slick/src/test/scala/enums/SlickMappedEnumColumnTypeTests.scala +++ b/slick/src/test/scala/pl/iterators/kebs/slick/enums/SlickMappedEnumColumnTypeTests.scala @@ -1,12 +1,13 @@ -package enums +package pl.iterators.kebs.slick.enums import enumeratum.{Enum, EnumEntry} import org.scalatest.funsuite.AnyFunSuite import org.scalatest.matchers.should.Matchers +import pl.iterators.kebs.enumeratum.KebsEnumeratum -class SlickMappedEnumColumnTypeTests extends AnyFunSuite with Matchers { +class SlickMappedEnumColumnTypeTests extends AnyFunSuite with Matchers with KebsEnumeratum { import slick.jdbc.PostgresProfile.api._ - import pl.iterators.kebs.enums.lowercase._ + import pl.iterators.kebs.slick.enums._ sealed trait WorkerAccountStatus extends EnumEntry object WorkerAccountStatus extends Enum[WorkerAccountStatus] { diff --git a/slick/src/test/scala/enums/SlickMappedValueEnumColumnTypeTests.scala b/slick/src/test/scala/pl/iterators/kebs/slick/enums/SlickMappedValueEnumColumnTypeTests.scala similarity index 80% rename from slick/src/test/scala/enums/SlickMappedValueEnumColumnTypeTests.scala rename to slick/src/test/scala/pl/iterators/kebs/slick/enums/SlickMappedValueEnumColumnTypeTests.scala index 2e3ff351..6b1c6f6b 100644 --- a/slick/src/test/scala/enums/SlickMappedValueEnumColumnTypeTests.scala +++ b/slick/src/test/scala/pl/iterators/kebs/slick/enums/SlickMappedValueEnumColumnTypeTests.scala @@ -1,14 +1,16 @@ -package enums +package pl.iterators.kebs.slick.enums import enumeratum.values.{IntEnum, IntEnumEntry} import org.scalatest.funsuite.AnyFunSuite import org.scalatest.matchers.should.Matchers +import pl.iterators.kebs.core.enums.ValueEnumLikeEntry +import pl.iterators.kebs.enumeratum.KebsValueEnumeratum -class SlickMappedValueEnumColumnTypeTests extends AnyFunSuite with Matchers { +class SlickMappedValueEnumColumnTypeTests extends AnyFunSuite with Matchers with KebsValueEnumeratum { import slick.jdbc.PostgresProfile.api._ - import pl.iterators.kebs.enums._ + import pl.iterators.kebs.slick.enums._ - sealed abstract class WorkerAccountStatusInt(val value: Int) extends IntEnumEntry + sealed abstract class WorkerAccountStatusInt(val value: Int) extends IntEnumEntry with ValueEnumLikeEntry[Int] object WorkerAccountStatusInt extends IntEnum[WorkerAccountStatusInt] { case object Unapproved extends WorkerAccountStatusInt(0) case object Active extends WorkerAccountStatusInt(1) @@ -16,7 +18,7 @@ class SlickMappedValueEnumColumnTypeTests extends AnyFunSuite with Matchers { override val values = findValues } - + test("MappedColumnType for value enum entries") { "implicitly[BaseColumnType[WorkerAccountStatusInt]]" should compile } diff --git a/slick/src/test/scala/enums/ValueEnumIsomorphismTests.scala b/slick/src/test/scala/pl/iterators/kebs/slick/enums/ValueEnumIsomorphismTests.scala similarity index 75% rename from slick/src/test/scala/enums/ValueEnumIsomorphismTests.scala rename to slick/src/test/scala/pl/iterators/kebs/slick/enums/ValueEnumIsomorphismTests.scala index c84a9525..ff6622cc 100644 --- a/slick/src/test/scala/enums/ValueEnumIsomorphismTests.scala +++ b/slick/src/test/scala/pl/iterators/kebs/slick/enums/ValueEnumIsomorphismTests.scala @@ -1,13 +1,15 @@ -package enums +package pl.iterators.kebs.slick.enums import enumeratum.values.{IntEnum, IntEnumEntry} import org.scalatest.funsuite.AnyFunSuite import org.scalatest.matchers.should.Matchers +import pl.iterators.kebs.core.enums.ValueEnumLikeEntry import slick.lifted.Isomorphism +import pl.iterators.kebs.enumeratum.KebsEnumeratum -class ValueEnumIsomorphismTests extends AnyFunSuite with Matchers { +class ValueEnumIsomorphismTests extends AnyFunSuite with Matchers with KebsEnumeratum { - sealed abstract class IntGreeting(val value: Int) extends IntEnumEntry + sealed abstract class IntGreeting(val value: Int) extends IntEnumEntry with ValueEnumLikeEntry[Int] object IntGreeting extends IntEnum[IntGreeting] { case object Hello extends IntGreeting(0) @@ -21,7 +23,7 @@ class ValueEnumIsomorphismTests extends AnyFunSuite with Matchers { import IntGreeting._ test("Implicit isomorphism from ValueEnumEntry") { - import pl.iterators.kebs.enums._ + import pl.iterators.kebs.slick.enums._ val iso = implicitly[Isomorphism[IntGreeting, Int]] iso.map(Bye) shouldBe 3 diff --git a/slick/src/test/scala/hstore/MapIsomorphismTest.scala b/slick/src/test/scala/pl/iterators/kebs/slick/hstore/MapIsomorphismTest.scala similarity index 92% rename from slick/src/test/scala/hstore/MapIsomorphismTest.scala rename to slick/src/test/scala/pl/iterators/kebs/slick/hstore/MapIsomorphismTest.scala index 889cdbb2..657d8af2 100644 --- a/slick/src/test/scala/hstore/MapIsomorphismTest.scala +++ b/slick/src/test/scala/pl/iterators/kebs/slick/hstore/MapIsomorphismTest.scala @@ -1,26 +1,26 @@ -package hstore +package pl.iterators.kebs.slick.hstore import org.scalatest.funsuite.AnyFunSuite import org.scalatest.matchers.should.Matchers -import pl.iterators.kebs.instances.time.mixins.InstantEpochMilliLong import pl.iterators.kebs.instances.time.{DayOfWeekInt, YearMonthString} +import pl.iterators.kebs.instances.time.mixins.InstantEpochMilliLong import slick.lifted.Isomorphism class MapIsomorphismTest extends AnyFunSuite with Matchers with YearMonthString with DayOfWeekInt with InstantEpochMilliLong { - import pl.iterators.kebs._ + import pl.iterators.kebs.slick._ case class StringValue(value: String) case class IntValue(value: Int) - test("No CaseClass1Rep implicits derived") { - import pl.iterators.kebs.macros.CaseClass1Rep + test("No ValueClassLike implicits derived") { + import pl.iterators.kebs.core.macros.ValueClassLike - "implicitly[CaseClass1Rep[YearMonth, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, YearMonth]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[DayOfWeek, Int]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[Int, DayOfWeek]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[Instant, Long]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[Long, Instant]]" shouldNot typeCheck + "implicitly[ValueClassLike[YearMonth, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, YearMonth]]" shouldNot typeCheck + "implicitly[ValueClassLike[DayOfWeek, Int]]" shouldNot typeCheck + "implicitly[ValueClassLike[Int, DayOfWeek]]" shouldNot typeCheck + "implicitly[ValueClassLike[Instant, Long]]" shouldNot typeCheck + "implicitly[ValueClassLike[Long, Instant]]" shouldNot typeCheck } test("Case classes isomorphisms implies string to int map isomorphism") { diff --git a/slick/src/test/scala/hstore/SlickPgHstoreColumnTypeTests.scala b/slick/src/test/scala/pl/iterators/kebs/slick/hstore/SlickPgHstoreColumnTypeTests.scala similarity index 94% rename from slick/src/test/scala/hstore/SlickPgHstoreColumnTypeTests.scala rename to slick/src/test/scala/pl/iterators/kebs/slick/hstore/SlickPgHstoreColumnTypeTests.scala index 5f682c87..fe8ccaa2 100644 --- a/slick/src/test/scala/hstore/SlickPgHstoreColumnTypeTests.scala +++ b/slick/src/test/scala/pl/iterators/kebs/slick/hstore/SlickPgHstoreColumnTypeTests.scala @@ -1,13 +1,13 @@ -package hstore +package pl.iterators.kebs.slick.hstore import com.github.tminglei.slickpg._ import org.scalatest.funsuite.AnyFunSuite import org.scalatest.matchers.should.Matchers class SlickPgHstoreColumnTypeTests extends AnyFunSuite with Matchers { - import pl.iterators.kebs.Kebs import pl.iterators.kebs.instances.time.{DayOfWeekInt, YearMonthString} import pl.iterators.kebs.instances.time.mixins.InstantEpochMilliLong + import pl.iterators.kebs.slick.Kebs import java.time.{DayOfWeek, YearMonth, Instant} object MyPostgresProfile extends ExPostgresProfile with PgHStoreSupport { @@ -20,15 +20,15 @@ class SlickPgHstoreColumnTypeTests extends AnyFunSuite with Matchers { import MyPostgresProfile.api._ - test("No CaseClass1Rep implicits derived") { - import pl.iterators.kebs.macros.CaseClass1Rep + test("No ValueClassLike implicits derived") { + import pl.iterators.kebs.core.macros.ValueClassLike - "implicitly[CaseClass1Rep[YearMonth, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, YearMonth]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[DayOfWeek, Int]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[Int, DayOfWeek]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[Instant, Long]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[Long, Instant]]" shouldNot typeCheck + "implicitly[ValueClassLike[YearMonth, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, YearMonth]]" shouldNot typeCheck + "implicitly[ValueClassLike[DayOfWeek, Int]]" shouldNot typeCheck + "implicitly[ValueClassLike[Int, DayOfWeek]]" shouldNot typeCheck + "implicitly[ValueClassLike[Instant, Long]]" shouldNot typeCheck + "implicitly[ValueClassLike[Long, Instant]]" shouldNot typeCheck } test("Value classes to HStore mapping") { @@ -42,7 +42,7 @@ class SlickPgHstoreColumnTypeTests extends AnyFunSuite with Matchers { |""".stripMargin should compile } - /* CaseClass1Rep[Obj, String] */ + /* ValueClassLike[Obj, String] */ test("Map[Obj[String], String] column type") { """ |class HStoreTestTable(tag: Tag) extends Table[(Long, Map[YearMonth, String])](tag, "HStoreTestTable") { @@ -131,7 +131,7 @@ class SlickPgHstoreColumnTypeTests extends AnyFunSuite with Matchers { |""".stripMargin should compile } - /* CaseClass1Rep[Obj, Int] */ + /* ValueClassLike[Obj, Int] */ test("Map[Obj[Int], String] column type") { """ |class HStoreTestTable(tag: Tag) extends Table[(Long, Map[DayOfWeek, String])](tag, "HStoreTestTable") { @@ -220,7 +220,7 @@ class SlickPgHstoreColumnTypeTests extends AnyFunSuite with Matchers { |""".stripMargin should compile } - /* CaseClass1Rep[Obj, Long] */ + /* ValueClassLike[Obj, Long] */ test("Map[Obj[Long], String] column type") { """ |class HStoreTestTable(tag: Tag) extends Table[(Long, Map[Instant, String])](tag, "HStoreTestTable") { diff --git a/slick/src/test/scala/hstore/SlickPgHstoreTests.scala b/slick/src/test/scala/pl/iterators/kebs/slick/hstore/SlickPgHstoreTests.scala similarity index 93% rename from slick/src/test/scala/hstore/SlickPgHstoreTests.scala rename to slick/src/test/scala/pl/iterators/kebs/slick/hstore/SlickPgHstoreTests.scala index 25726f1a..da17c270 100644 --- a/slick/src/test/scala/hstore/SlickPgHstoreTests.scala +++ b/slick/src/test/scala/pl/iterators/kebs/slick/hstore/SlickPgHstoreTests.scala @@ -1,4 +1,4 @@ -package hstore +package pl.iterators.kebs.slick.hstore import com.github.tminglei.slickpg._ import org.scalatest.funsuite.AnyFunSuite @@ -9,8 +9,8 @@ import java.time.YearMonth import java.util.UUID class SlickPgHstoreTests extends AnyFunSuite with Matchers { - import pl.iterators.kebs.Kebs import pl.iterators.kebs.instances.time.YearMonthString + import pl.iterators.kebs.slick.Kebs trait PostgresDriver extends ExPostgresProfile with PgArraySupport with PgHStoreSupport { override val api: HstoreAPI = new HstoreAPI {} @@ -41,11 +41,11 @@ class SlickPgHstoreTests extends AnyFunSuite with Matchers { override def * : ProvenShape[Test] = (id, hstoreMap) <> ((Test.apply _).tupled, Test.unapply) } - test("No CaseClass1Rep implicits derived") { - import pl.iterators.kebs.macros.CaseClass1Rep + test("No ValueClassLike implicits derived") { + import pl.iterators.kebs.core.macros.ValueClassLike - "implicitly[CaseClass1Rep[YearMonth, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, YearMonth]]" shouldNot typeCheck + "implicitly[ValueClassLike[YearMonth, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, YearMonth]]" shouldNot typeCheck } test("Case class hstore extension methods") { diff --git a/spray-json-macros/src/main/scala/pl/iterators/kebs/json/macros/KebsSprayMacros.scala b/spray-json-macros/src/main/scala/pl/iterators/kebs/json/macros/KebsSprayMacros.scala index cd7f1d6c..56d666e6 100644 --- a/spray-json-macros/src/main/scala/pl/iterators/kebs/json/macros/KebsSprayMacros.scala +++ b/spray-json-macros/src/main/scala/pl/iterators/kebs/json/macros/KebsSprayMacros.scala @@ -1,7 +1,7 @@ package pl.iterators.kebs.json.macros +import pl.iterators.kebs.core.macros.MacroUtils import pl.iterators.kebs.json.noflat -import pl.iterators.kebs.macros.MacroUtils import spray.json.{JsonFormat, JsonReader, JsonWriter, NullOptions, RootJsonFormat} import scala.collection.immutable.Seq @@ -106,7 +106,7 @@ object KebsSprayMacros { override protected val preferFlat = false } class SnakifyVariant(context: whitebox.Context) extends KebsSprayMacros(context) { - import pl.iterators.kebs.macros.namingconventions.SnakifyVariant.snakify + import pl.iterators.kebs.core.macros.namingconventions.SnakifyVariant.snakify import c.universe._ override protected def extractJsonFieldNames(fields: List[MethodSymbol]) = super.extractJsonFieldNames(fields).map(snakify) diff --git a/spray-json/src/main/scala/pl/iterators/kebs/json/KebsEnumFormats.scala b/spray-json/src/main/scala/pl/iterators/kebs/json/KebsEnumFormats.scala index 05b7d4ba..0c1b7d7d 100644 --- a/spray-json/src/main/scala/pl/iterators/kebs/json/KebsEnumFormats.scala +++ b/spray-json/src/main/scala/pl/iterators/kebs/json/KebsEnumFormats.scala @@ -1,61 +1,59 @@ package pl.iterators.kebs.json -import enumeratum.values.{ValueEnum, ValueEnumEntry} -import enumeratum.{Enum, EnumEntry} -import pl.iterators.kebs.macros.enums.{EnumOf, ValueEnumOf} +import pl.iterators.kebs.core.enums.{EnumLike, ValueEnumLike, ValueEnumLikeEntry} import spray.json.{JsString, JsValue, JsonFormat} trait SprayJsonEnum { - @inline protected final def enumNameDeserializationError[E <: EnumEntry](`enum`: Enum[E], name: String) = { - val enumNames = `enum`.namesToValuesMap.values.mkString(", ") + @inline protected final def enumNameDeserializationError[E](`enum`: EnumLike[E], name: String) = { + val enumNames = `enum`.getNamesToValuesMap.values.mkString(", ") spray.json.deserializationError(s"$name should be one of $enumNames") } - @inline protected final def enumValueDeserializationError[E <: EnumEntry](`enum`: Enum[E], value: JsValue) = { - val enumNames = `enum`.namesToValuesMap.values.mkString(", ") + @inline protected final def enumValueDeserializationError[E](`enum`: EnumLike[E], value: JsValue) = { + val enumNames = `enum`.getNamesToValuesMap.values.mkString(", ") spray.json.deserializationError(s"$value should be a string of value $enumNames") } - protected final def enumJsonFormat[E <: EnumEntry](`enum`: Enum[E], map: E => String, comap: String => Option[E]) = new JsonFormat[E] { + protected final def enumJsonFormat[E](`enum`: EnumLike[E], map: E => String, comap: String => Option[E]) = new JsonFormat[E] { override def write(obj: E): JsValue = JsString(map(obj)) override def read(json: JsValue): E = json match { case JsString(name) => comap(name).getOrElse(enumNameDeserializationError(`enum`, name)) case _ => enumValueDeserializationError(`enum`, json) } } - def jsonFormat[E <: EnumEntry](`enum`: Enum[E]) = enumJsonFormat[E](`enum`, _.entryName, `enum`.withNameInsensitiveOption(_)) - def lowercaseJsonFormat[E <: EnumEntry](`enum`: Enum[E]) = - enumJsonFormat[E](`enum`, _.entryName.toLowerCase, `enum`.withNameLowercaseOnlyOption(_)) - def uppercaseJsonFormat[E <: EnumEntry](`enum`: Enum[E]) = - enumJsonFormat[E](`enum`, _.entryName.toUpperCase, `enum`.withNameUppercaseOnlyOption(_)) + def jsonFormat[E](`enum`: EnumLike[E]) = enumJsonFormat[E](`enum`, _.toString, `enum`.withNameInsensitiveOption(_)) + def lowercaseJsonFormat[E](`enum`: EnumLike[E]) = + enumJsonFormat[E](`enum`, _.toString.toLowerCase, `enum`.withNameLowercaseOnlyOption(_)) + def uppercaseJsonFormat[E](`enum`: EnumLike[E]) = + enumJsonFormat[E](`enum`, _.toString.toUpperCase, `enum`.withNameUppercaseOnlyOption(_)) } trait SprayJsonValueEnum { - @inline protected final def valueEnumDeserializationError[V, E <: ValueEnumEntry[V]](`enum`: ValueEnum[V, E], value: V) = { - val enumValues = `enum`.valuesToEntriesMap.keys.mkString(", ") + @inline protected final def valueEnumDeserializationError[V, E <: ValueEnumLikeEntry[V]](`enum`: ValueEnumLike[V, E], value: V) = { + val enumValues = `enum`.getValuesToEntriesMap.keys.mkString(", ") spray.json.deserializationError(s"$value is not a member of $enumValues") } - def jsonFormat[V, E <: ValueEnumEntry[V]](`enum`: ValueEnum[V, E])(implicit baseJsonFormat: JsonFormat[V]) = new JsonFormat[E] { + def jsonFormatValue[V, E <: ValueEnumLikeEntry[V]](`enum`: ValueEnumLike[V, E])(implicit baseJsonFormat: JsonFormat[V]) = new JsonFormat[E] { override def write(obj: E): JsValue = baseJsonFormat.write(obj.value) override def read(json: JsValue): E = { val value = baseJsonFormat.read(json) - `enum`.withValueOpt(value).getOrElse(valueEnumDeserializationError(`enum`, value)) + `enum`.withValueOption(value).getOrElse(valueEnumDeserializationError(`enum`, value)) } } } trait KebsEnumFormats extends SprayJsonEnum with SprayJsonValueEnum { - implicit def jsonEnumFormat[E <: EnumEntry](implicit ev: EnumOf[E]): JsonFormat[E] = jsonFormat(ev.`enum`) - implicit def jsonValueEnumFormat[V, E <: ValueEnumEntry[V]](implicit ev: ValueEnumOf[V, E], - baseJsonFormat: JsonFormat[V]): JsonFormat[E] = jsonFormat(ev.valueEnum) + implicit def jsonEnumFormat[E](implicit ev: EnumLike[E]): JsonFormat[E] = jsonFormat(ev) + implicit def jsonValueEnumFormat[V, E <: ValueEnumLikeEntry[V]](implicit ev: ValueEnumLike[V, E], + baseJsonFormat: JsonFormat[V]): JsonFormat[E] = jsonFormatValue(ev) trait Uppercase extends SprayJsonEnum { - implicit def jsonEnumFormat[E <: EnumEntry](implicit ev: EnumOf[E]): JsonFormat[E] = uppercaseJsonFormat(ev.`enum`) + implicit def jsonEnumFormat[E](implicit ev: EnumLike[E]): JsonFormat[E] = uppercaseJsonFormat(ev) } trait Lowercase extends SprayJsonEnum { - implicit def jsonEnumFormat[E <: EnumEntry](implicit ev: EnumOf[E]): JsonFormat[E] = lowercaseJsonFormat(ev.`enum`) + implicit def jsonEnumFormat[E](implicit ev: EnumLike[E]): JsonFormat[E] = lowercaseJsonFormat(ev) } } diff --git a/spray-json/src/main/scala/pl/iterators/kebs/json/KebsSpray.scala b/spray-json/src/main/scala/pl/iterators/kebs/json/KebsSpray.scala index 3917e00d..8044d929 100644 --- a/spray-json/src/main/scala/pl/iterators/kebs/json/KebsSpray.scala +++ b/spray-json/src/main/scala/pl/iterators/kebs/json/KebsSpray.scala @@ -1,13 +1,13 @@ package pl.iterators.kebs.json -import pl.iterators.kebs.macros.CaseClass1Rep +import pl.iterators.kebs.core.instances.InstanceConverter +import pl.iterators.kebs.core.macros.{CaseClass1ToValueClass, ValueClassLike} import spray.json.{DefaultJsonProtocol, JsValue, JsonFormat, JsonReader, RootJsonFormat} -import pl.iterators.kebs.instances.InstanceConverter -trait KebsSpray { self: DefaultJsonProtocol => +trait KebsSpray extends CaseClass1ToValueClass { self: DefaultJsonProtocol => import macros.KebsSprayMacros implicit def jsonFormatN[T <: Product]: RootJsonFormat[T] = macro KebsSprayMacros.materializeRootFormat[T] - implicit def jsonFlatFormat[T, A](implicit rep: CaseClass1Rep[T, A], baseJsonFormat: JsonFormat[A]): JsonFormat[T] = { + implicit def jsonFlatFormat[T, A](implicit rep: ValueClassLike[T, A], baseJsonFormat: JsonFormat[A]): JsonFormat[T] = { val reader: JsValue => T = json => rep.apply(baseJsonFormat.read(json)) val writer: T => JsValue = obj => baseJsonFormat.write(rep.unapply(obj)) jsonFormat[T](reader, writer) diff --git a/spray-json/src/test/scala/SprayEnumJsonFormatTests.scala b/spray-json/src/test/scala/pl/iterators/kebs/json/SprayEnumJsonFormatTests.scala similarity index 95% rename from spray-json/src/test/scala/SprayEnumJsonFormatTests.scala rename to spray-json/src/test/scala/pl/iterators/kebs/json/SprayEnumJsonFormatTests.scala index bc8c5aff..a69bede3 100644 --- a/spray-json/src/test/scala/SprayEnumJsonFormatTests.scala +++ b/spray-json/src/test/scala/pl/iterators/kebs/json/SprayEnumJsonFormatTests.scala @@ -1,10 +1,13 @@ +package pl.iterators.kebs.json + import enumeratum.{Enum, EnumEntry} import pl.iterators.kebs.json.{KebsEnumFormats, KebsSpray} import spray.json._ import org.scalatest.funsuite.AnyFunSuite import org.scalatest.matchers.should.Matchers +import pl.iterators.kebs.enumeratum.KebsEnumeratum -class SprayEnumJsonFormatTests extends AnyFunSuite with Matchers { +class SprayEnumJsonFormatTests extends AnyFunSuite with Matchers with KebsEnumeratum { sealed trait Greeting extends EnumEntry object Greeting extends Enum[Greeting] { diff --git a/spray-json/src/test/scala/SprayJsonFormatCapitalizedVariantTests.scala b/spray-json/src/test/scala/pl/iterators/kebs/json/SprayJsonFormatCapitalizedVariantTests.scala similarity index 92% rename from spray-json/src/test/scala/SprayJsonFormatCapitalizedVariantTests.scala rename to spray-json/src/test/scala/pl/iterators/kebs/json/SprayJsonFormatCapitalizedVariantTests.scala index 2ed9f5ae..982869b3 100644 --- a/spray-json/src/test/scala/SprayJsonFormatCapitalizedVariantTests.scala +++ b/spray-json/src/test/scala/pl/iterators/kebs/json/SprayJsonFormatCapitalizedVariantTests.scala @@ -1,7 +1,8 @@ -import pl.iterators.kebs.json.KebsSpray -import spray.json.{DefaultJsonProtocol, JsArray, JsBoolean, JsNull, JsNumber, JsObject, JsString, JsonFormat, RootJsonFormat} +package pl.iterators.kebs.json + import org.scalatest.funsuite.AnyFunSuite import org.scalatest.matchers.should.Matchers +import spray.json.{DefaultJsonProtocol, JsNumber, JsObject, JsString, JsonFormat, RootJsonFormat} class SprayJsonFormatCapitalizedVariantTests extends AnyFunSuite with Matchers { object KebsProtocol extends DefaultJsonProtocol with KebsSpray.Capitalized diff --git a/spray-json/src/test/scala/SprayJsonFormatNoFlatTests.scala b/spray-json/src/test/scala/pl/iterators/kebs/json/SprayJsonFormatNoFlatTests.scala similarity index 95% rename from spray-json/src/test/scala/SprayJsonFormatNoFlatTests.scala rename to spray-json/src/test/scala/pl/iterators/kebs/json/SprayJsonFormatNoFlatTests.scala index 75b18ed8..75825aac 100644 --- a/spray-json/src/test/scala/SprayJsonFormatNoFlatTests.scala +++ b/spray-json/src/test/scala/pl/iterators/kebs/json/SprayJsonFormatNoFlatTests.scala @@ -1,7 +1,8 @@ -import pl.iterators.kebs.json.KebsSpray -import spray.json._ +package pl.iterators.kebs.json + import org.scalatest.funsuite.AnyFunSuite import org.scalatest.matchers.should.Matchers +import spray.json._ class SprayJsonFormatNoFlatTests extends AnyFunSuite with Matchers { object KebsProtocol extends DefaultJsonProtocol with KebsSpray.NoFlat diff --git a/spray-json/src/test/scala/SprayJsonFormatSnakifyVariantTests.scala b/spray-json/src/test/scala/pl/iterators/kebs/json/SprayJsonFormatSnakifyVariantTests.scala similarity index 99% rename from spray-json/src/test/scala/SprayJsonFormatSnakifyVariantTests.scala rename to spray-json/src/test/scala/pl/iterators/kebs/json/SprayJsonFormatSnakifyVariantTests.scala index faacd8fb..a943606a 100644 --- a/spray-json/src/test/scala/SprayJsonFormatSnakifyVariantTests.scala +++ b/spray-json/src/test/scala/pl/iterators/kebs/json/SprayJsonFormatSnakifyVariantTests.scala @@ -1,7 +1,8 @@ -import pl.iterators.kebs.json.KebsSpray -import spray.json.{DefaultJsonProtocol, JsArray, JsBoolean, JsNull, JsNumber, JsObject, JsString, JsonFormat, NullOptions, RootJsonFormat} +package pl.iterators.kebs.json + import org.scalatest.funsuite.AnyFunSuite import org.scalatest.matchers.should.Matchers +import spray.json.{DefaultJsonProtocol, JsArray, JsBoolean, JsNull, JsNumber, JsObject, JsString, JsonFormat, NullOptions, RootJsonFormat} class SprayJsonFormatSnakifyVariantTests extends AnyFunSuite with Matchers { object KebsProtocol extends DefaultJsonProtocol with KebsSpray.Snakified @@ -92,8 +93,8 @@ class SprayJsonFormatSnakifyVariantTests extends AnyFunSuite with Matchers { test("Root format snakified with NullOptions - case class with > 22 fields (issue #73)") { object KebsProtocolNullOptions extends DefaultJsonProtocol with KebsSpray.Snakified with NullOptions - import model._ import KebsProtocolNullOptions._ + import model._ val jf = implicitly[JsonFormat[ClassWith23Fields]] val obj = ClassWith23Fields.Example diff --git a/spray-json/src/test/scala/SprayJsonFormatTests.scala b/spray-json/src/test/scala/pl/iterators/kebs/json/SprayJsonFormatTests.scala similarity index 99% rename from spray-json/src/test/scala/SprayJsonFormatTests.scala rename to spray-json/src/test/scala/pl/iterators/kebs/json/SprayJsonFormatTests.scala index 89577cd9..83b05b99 100644 --- a/spray-json/src/test/scala/SprayJsonFormatTests.scala +++ b/spray-json/src/test/scala/pl/iterators/kebs/json/SprayJsonFormatTests.scala @@ -1,9 +1,10 @@ -import java.util.UUID +package pl.iterators.kebs.json -import pl.iterators.kebs.json.{KebsSpray, noflat} -import spray.json._ import org.scalatest.funsuite.AnyFunSuite import org.scalatest.matchers.should.Matchers +import spray.json._ + +import java.util.UUID class SprayJsonFormatTests extends AnyFunSuite with Matchers { object KebsProtocol extends DefaultJsonProtocol with KebsSpray @@ -197,8 +198,8 @@ class SprayJsonFormatTests extends AnyFunSuite with Matchers { test("Root format with NullOptions - case class with > 22 fields (issue #73)") { object KebsProtocolNullOptions extends DefaultJsonProtocol with KebsSpray with NullOptions - import model._ import KebsProtocolNullOptions._ + import model._ val jf = implicitly[JsonFormat[ClassWith23Fields]] val obj = ClassWith23Fields.Example diff --git a/spray-json/src/test/scala/SprayValueEnumJsonFormatTests.scala b/spray-json/src/test/scala/pl/iterators/kebs/json/SprayValueEnumJsonFormatTests.scala similarity index 84% rename from spray-json/src/test/scala/SprayValueEnumJsonFormatTests.scala rename to spray-json/src/test/scala/pl/iterators/kebs/json/SprayValueEnumJsonFormatTests.scala index bfc3845c..b341bd4d 100644 --- a/spray-json/src/test/scala/SprayValueEnumJsonFormatTests.scala +++ b/spray-json/src/test/scala/pl/iterators/kebs/json/SprayValueEnumJsonFormatTests.scala @@ -1,11 +1,14 @@ +package pl.iterators.kebs.json + import enumeratum.values.{LongEnum, LongEnumEntry} -import pl.iterators.kebs.json.{KebsEnumFormats, KebsSpray} -import spray.json._ import org.scalatest.funsuite.AnyFunSuite import org.scalatest.matchers.should.Matchers +import pl.iterators.kebs.core.enums.ValueEnumLikeEntry +import pl.iterators.kebs.enumeratum.KebsValueEnumeratum +import spray.json._ -class SprayValueEnumJsonFormatTests extends AnyFunSuite with Matchers { - sealed abstract class LongGreeting(val value: Long) extends LongEnumEntry +class SprayValueEnumJsonFormatTests extends AnyFunSuite with Matchers with KebsValueEnumeratum { + sealed abstract class LongGreeting(val value: Long) extends LongEnumEntry with ValueEnumLikeEntry[Long] object LongGreeting extends LongEnum[LongGreeting] { val values = findValues diff --git a/spray-json/src/test/scala/instances/NetInstancesTests.scala b/spray-json/src/test/scala/pl/iterators/kebs/json/instances/NetInstancesTests.scala similarity index 68% rename from spray-json/src/test/scala/instances/NetInstancesTests.scala rename to spray-json/src/test/scala/pl/iterators/kebs/json/instances/NetInstancesTests.scala index 8e05c60d..5ea7bbaf 100644 --- a/spray-json/src/test/scala/instances/NetInstancesTests.scala +++ b/spray-json/src/test/scala/pl/iterators/kebs/json/instances/NetInstancesTests.scala @@ -1,9 +1,9 @@ -package instances +package pl.iterators.kebs.json.instances import org.scalatest.funsuite.AnyFunSuite import org.scalatest.matchers.should.Matchers -import pl.iterators.kebs.instances.InstanceConverter.DecodeErrorException import pl.iterators.kebs.instances.net.URIString +import pl.iterators.kebs.core.instances.InstanceConverter.DecodeErrorException import pl.iterators.kebs.json.KebsSpray import spray.json._ @@ -27,10 +27,10 @@ class NetInstancesTests extends AnyFunSuite with Matchers with DefaultJsonProtoc assertThrows[DecodeErrorException](jf.read(JsString(value))) } - test("No CaseClass1Rep implicits derived") { - import pl.iterators.kebs.macros.CaseClass1Rep + test("No ValueClassLike implicits derived") { + import pl.iterators.kebs.core.macros.ValueClassLike - "implicitly[CaseClass1Rep[URI, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, URI]]" shouldNot typeCheck + "implicitly[ValueClassLike[URI, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, URI]]" shouldNot typeCheck } } diff --git a/spray-json/src/test/scala/instances/TimeInstancesMixinTests.scala b/spray-json/src/test/scala/pl/iterators/kebs/json/instances/TimeInstancesMixinTests.scala similarity index 81% rename from spray-json/src/test/scala/instances/TimeInstancesMixinTests.scala rename to spray-json/src/test/scala/pl/iterators/kebs/json/instances/TimeInstancesMixinTests.scala index 00950f5b..1b612e3b 100644 --- a/spray-json/src/test/scala/instances/TimeInstancesMixinTests.scala +++ b/spray-json/src/test/scala/pl/iterators/kebs/json/instances/TimeInstancesMixinTests.scala @@ -1,13 +1,13 @@ -package instances +package pl.iterators.kebs.json.instances import org.scalatest.funsuite.AnyFunSuite import org.scalatest.matchers.should.Matchers -import pl.iterators.kebs.instances.InstanceConverter +import pl.iterators.kebs.instances.TimeInstances import pl.iterators.kebs.instances.time.LocalDateTimeString import pl.iterators.kebs.instances.time.mixins.{DurationNanosLong, InstantEpochMilliLong} -import pl.iterators.kebs.instances.TimeInstances +import pl.iterators.kebs.core.instances.InstanceConverter +import pl.iterators.kebs.core.macros.ValueClassLike import pl.iterators.kebs.json.KebsSpray -import pl.iterators.kebs.macros.CaseClass1Rep import spray.json._ import java.time._ @@ -19,8 +19,8 @@ class TimeInstancesMixinTests extends AnyFunSuite with Matchers { object TimeInstancesProtocol extends DefaultJsonProtocol with KebsSpray with InstantEpochMilliLong import TimeInstancesProtocol._ - "implicitly[CaseClass1Rep[Instant, Long]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[Long, Instant]]" shouldNot typeCheck + "implicitly[ValueClassLike[Instant, Long]]" shouldNot typeCheck + "implicitly[ValueClassLike[Long, Instant]]" shouldNot typeCheck val jf = implicitly[JsonFormat[Instant]] val value = 123456789 @@ -34,10 +34,10 @@ class TimeInstancesMixinTests extends AnyFunSuite with Matchers { object TimeInstancesProtocol extends DefaultJsonProtocol with KebsSpray with DurationNanosLong with InstantEpochMilliLong import TimeInstancesProtocol._ - "implicitly[CaseClass1Rep[Instant, Long]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[Long, Instant]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[Duration, Long]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[Long, Duration]]" shouldNot typeCheck + "implicitly[ValueClassLike[Instant, Long]]" shouldNot typeCheck + "implicitly[ValueClassLike[Long, Instant]]" shouldNot typeCheck + "implicitly[ValueClassLike[Duration, Long]]" shouldNot typeCheck + "implicitly[ValueClassLike[Long, Duration]]" shouldNot typeCheck val jf_duration = implicitly[JsonFormat[Duration]] val value_duration = 123456789 @@ -63,8 +63,8 @@ class TimeInstancesMixinTests extends AnyFunSuite with Matchers { } import TimeInstancesProtocol._ - "implicitly[CaseClass1Rep[LocalDateTime, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, LocalDateTime]]" shouldNot typeCheck + "implicitly[ValueClassLike[LocalDateTime, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, LocalDateTime]]" shouldNot typeCheck val jf = implicitly[JsonFormat[LocalDateTime]] val value = "2007/12/03 10:30" @@ -96,8 +96,8 @@ class TimeInstancesMixinTests extends AnyFunSuite with Matchers { } import TimeInstancesProtocol._ - "implicitly[CaseClass1Rep[LocalDateTime, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, LocalDateTime]]" shouldNot typeCheck + "implicitly[ValueClassLike[LocalDateTime, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, LocalDateTime]]" shouldNot typeCheck val jf = implicitly[JsonFormat[LocalDateTime]] val value = "2007/12/03 10:30" diff --git a/spray-json/src/test/scala/instances/TimeInstancesTests.scala b/spray-json/src/test/scala/pl/iterators/kebs/json/instances/TimeInstancesTests.scala similarity index 75% rename from spray-json/src/test/scala/instances/TimeInstancesTests.scala rename to spray-json/src/test/scala/pl/iterators/kebs/json/instances/TimeInstancesTests.scala index 8270c28f..e3df3b05 100644 --- a/spray-json/src/test/scala/instances/TimeInstancesTests.scala +++ b/spray-json/src/test/scala/pl/iterators/kebs/json/instances/TimeInstancesTests.scala @@ -1,8 +1,8 @@ -package instances +package pl.iterators.kebs.json.instances import org.scalatest.funsuite.AnyFunSuite import org.scalatest.matchers.should.Matchers -import pl.iterators.kebs.instances.InstanceConverter.DecodeErrorException +import pl.iterators.kebs.core.instances.InstanceConverter.DecodeErrorException import pl.iterators.kebs.instances.TimeInstances import pl.iterators.kebs.json.KebsSpray import spray.json._ @@ -11,41 +11,41 @@ import java.time._ class TimeInstancesTests extends AnyFunSuite with Matchers with DefaultJsonProtocol with KebsSpray with TimeInstances { - test("No CaseClass1Rep implicits derived") { - import pl.iterators.kebs.macros.CaseClass1Rep - - "implicitly[CaseClass1Rep[DayOfWeek, Int]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[Int, DayOfWeek]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[Duration, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, Duration]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[Instant, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, Instant]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[LocalDate, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, LocalDate]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[LocalDateTime, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, LocalDateTime]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[LocalTime, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, LocalTime]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[Month, Int]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[Int, Month]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[MonthDay, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, MonthDay]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[OffsetDateTime, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, OffsetDateTime]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[OffsetTime, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, OffsetTime]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[Period, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, Period]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[Year, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, Year]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[YearMonth, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, YearMonth]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[ZoneId, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, ZoneId]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[ZoneOffset, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, ZoneOffset]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[ZonedDateTime, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, ZonedDateTime]]" shouldNot typeCheck + test("No ValueClassLike implicits derived") { + import pl.iterators.kebs.core.macros.ValueClassLike + + "implicitly[ValueClassLike[DayOfWeek, Int]]" shouldNot typeCheck + "implicitly[ValueClassLike[Int, DayOfWeek]]" shouldNot typeCheck + "implicitly[ValueClassLike[Duration, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, Duration]]" shouldNot typeCheck + "implicitly[ValueClassLike[Instant, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, Instant]]" shouldNot typeCheck + "implicitly[ValueClassLike[LocalDate, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, LocalDate]]" shouldNot typeCheck + "implicitly[ValueClassLike[LocalDateTime, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, LocalDateTime]]" shouldNot typeCheck + "implicitly[ValueClassLike[LocalTime, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, LocalTime]]" shouldNot typeCheck + "implicitly[ValueClassLike[Month, Int]]" shouldNot typeCheck + "implicitly[ValueClassLike[Int, Month]]" shouldNot typeCheck + "implicitly[ValueClassLike[MonthDay, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, MonthDay]]" shouldNot typeCheck + "implicitly[ValueClassLike[OffsetDateTime, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, OffsetDateTime]]" shouldNot typeCheck + "implicitly[ValueClassLike[OffsetTime, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, OffsetTime]]" shouldNot typeCheck + "implicitly[ValueClassLike[Period, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, Period]]" shouldNot typeCheck + "implicitly[ValueClassLike[Year, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, Year]]" shouldNot typeCheck + "implicitly[ValueClassLike[YearMonth, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, YearMonth]]" shouldNot typeCheck + "implicitly[ValueClassLike[ZoneId, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, ZoneId]]" shouldNot typeCheck + "implicitly[ValueClassLike[ZoneOffset, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, ZoneOffset]]" shouldNot typeCheck + "implicitly[ValueClassLike[ZonedDateTime, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, ZonedDateTime]]" shouldNot typeCheck } test("DayOfWeek standard format") { diff --git a/spray-json/src/test/scala/instances/UtilInstancesTests.scala b/spray-json/src/test/scala/pl/iterators/kebs/json/instances/UtilInstancesTests.scala similarity index 70% rename from spray-json/src/test/scala/instances/UtilInstancesTests.scala rename to spray-json/src/test/scala/pl/iterators/kebs/json/instances/UtilInstancesTests.scala index 4409d8ee..4a525a44 100644 --- a/spray-json/src/test/scala/instances/UtilInstancesTests.scala +++ b/spray-json/src/test/scala/pl/iterators/kebs/json/instances/UtilInstancesTests.scala @@ -1,8 +1,8 @@ -package instances +package pl.iterators.kebs.json.instances import org.scalatest.funsuite.AnyFunSuite import org.scalatest.matchers.should.Matchers -import pl.iterators.kebs.instances.InstanceConverter.DecodeErrorException +import pl.iterators.kebs.core.instances.InstanceConverter.DecodeErrorException import pl.iterators.kebs.instances.UtilInstances import pl.iterators.kebs.json.KebsSpray import spray.json._ @@ -11,15 +11,15 @@ import java.util.{Currency, Locale, UUID} class UtilInstancesTests extends AnyFunSuite with Matchers with DefaultJsonProtocol with KebsSpray with UtilInstances { - test("No CaseClass1Rep implicits derived") { - import pl.iterators.kebs.macros.CaseClass1Rep + test("No ValueClassLike implicits derived") { + import pl.iterators.kebs.core.macros.ValueClassLike - "implicitly[CaseClass1Rep[Currency, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, Currency]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[Locale, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, Locale]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[UUID, String]]" shouldNot typeCheck - "implicitly[CaseClass1Rep[String, UUID]]" shouldNot typeCheck + "implicitly[ValueClassLike[Currency, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, Currency]]" shouldNot typeCheck + "implicitly[ValueClassLike[Locale, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, Locale]]" shouldNot typeCheck + "implicitly[ValueClassLike[UUID, String]]" shouldNot typeCheck + "implicitly[ValueClassLike[String, UUID]]" shouldNot typeCheck } test("Currency standard format") { diff --git a/circe/src/test/scala-2/model/model.scala b/spray-json/src/test/scala/pl/iterators/kebs/json/model/package.scala similarity index 98% rename from circe/src/test/scala-2/model/model.scala rename to spray-json/src/test/scala/pl/iterators/kebs/json/model/package.scala index 945565f5..ffa444df 100644 --- a/circe/src/test/scala-2/model/model.scala +++ b/spray-json/src/test/scala/pl/iterators/kebs/json/model/package.scala @@ -1,3 +1,5 @@ +package pl.iterators.kebs.json + package object model { case class F1(f1: String) extends AnyVal @@ -27,7 +29,6 @@ package object model { f22: String, f23: Boolean ) - object ClassWith23Fields { val Example = ClassWith23Fields( f1 = F1("f1 value"), @@ -81,7 +82,6 @@ package object model { f22: String, f23: Boolean ) - object ClassWith23FieldsNested { val Example: ClassWith23FieldsNested = ClassWith23FieldsNested( f1 = F1("f1 value"), diff --git a/tagged-meta/src/main/scala/pl/iterators/kebs/tag/meta/tagged.scala b/tagged-meta/src/main/scala/pl/iterators/kebs/tag/meta/tagged.scala index fa2a0b0e..ef6cb666 100644 --- a/tagged-meta/src/main/scala/pl/iterators/kebs/tag/meta/tagged.scala +++ b/tagged-meta/src/main/scala/pl/iterators/kebs/tag/meta/tagged.scala @@ -115,15 +115,15 @@ final class macroImpl(val c: whitebox.Context) { q"def apply[..$typeParams](arg: $baseTypeName[..$baseParams]) = $body" } - def generateCaseClass1RepImplicit: Tree = { - val caseClass1RepInstanceTree = - q"new _root_.pl.iterators.kebs.macros.CaseClass1Rep[$selfType, $baseTypeName[..$baseParams]](${name.toTermName}.apply(_), identity)" - val implicitName = TermName(name.decodedName.toString + "CaseClass1Rep") + def generateValueClassLikeImplicit: Tree = { + val valueClassLikeInstanceTree = + q"new _root_.pl.iterators.kebs.core.macros.ValueClassLike[$selfType, $baseTypeName[..$baseParams]](${name.toTermName}.apply(_), identity)" + val implicitName = TermName(name.decodedName.toString + "ValueClassLike") if (typeParams.isEmpty) - q"implicit val $implicitName = $caseClass1RepInstanceTree" + q"implicit val $implicitName = $valueClassLikeInstanceTree" else - q"implicit def $implicitName[..$typeParams] = $caseClass1RepInstanceTree" + q"implicit def $implicitName[..$typeParams] = $valueClassLikeInstanceTree" } private def containsApply(trees: List[Tree]): Boolean = { @@ -153,7 +153,7 @@ final class macroImpl(val c: whitebox.Context) { case class TagTypeRep(tagName: TypeName, maybeCompanion: Option[ModuleDef]) { def generateCompanion(taggedTypes: List[TaggedType]): Tree = { - val implicits = taggedTypes.map(_.generateCaseClass1RepImplicit) + val implicits = taggedTypes.map(_.generateValueClassLikeImplicit) maybeCompanion match { case Some(ModuleDef(mods, companionName, template)) => ModuleDef(mods, companionName, Template(template.parents, template.self, template.body ++ implicits)) diff --git a/tagged-meta/src/test/scala/CirceAnnotationTests.scala b/tagged-meta/src/test/scala/pl/iterators/kebs/tag/meta/CirceAnnotationTests.scala similarity index 98% rename from tagged-meta/src/test/scala/CirceAnnotationTests.scala rename to tagged-meta/src/test/scala/pl/iterators/kebs/tag/meta/CirceAnnotationTests.scala index d6b49283..27ab094f 100644 --- a/tagged-meta/src/test/scala/CirceAnnotationTests.scala +++ b/tagged-meta/src/test/scala/pl/iterators/kebs/tag/meta/CirceAnnotationTests.scala @@ -1,9 +1,10 @@ +package pl.iterators.kebs.tag.meta + import io.circe.{CursorOp, Decoder, DecodingFailure, Json} import org.scalatest.funsuite.AnyFunSuite -import pl.iterators.kebs.tagged._ -import pl.iterators.kebs.tag.meta._ -import pl.iterators.kebs.circe.KebsCirce import org.scalatest.matchers.should.Matchers +import pl.iterators.kebs.circe.KebsCirce +import pl.iterators.kebs.tagged._ @tagged object CirceTestTags { trait NameTag diff --git a/tagged-meta/src/test/scala/JsonSchemaAnnotationTests.scala b/tagged-meta/src/test/scala/pl/iterators/kebs/tag/meta/JsonSchemaAnnotationTests.scala similarity index 92% rename from tagged-meta/src/test/scala/JsonSchemaAnnotationTests.scala rename to tagged-meta/src/test/scala/pl/iterators/kebs/tag/meta/JsonSchemaAnnotationTests.scala index f7a4429b..7f67f9f5 100644 --- a/tagged-meta/src/test/scala/JsonSchemaAnnotationTests.scala +++ b/tagged-meta/src/test/scala/pl/iterators/kebs/tag/meta/JsonSchemaAnnotationTests.scala @@ -1,12 +1,10 @@ -import com.github.andyglow.json.JsonFormatter -import com.github.andyglow.jsonschema.AsValue +package pl.iterators.kebs.tag.meta + import json.Schema -import json.schema.Version.Draft07 -import pl.iterators.kebs.tagged._ -import pl.iterators.kebs.tag.meta._ import org.scalatest.funsuite.AnyFunSuite import org.scalatest.matchers.should.Matchers import pl.iterators.kebs.jsonschema.{JsonSchemaWrapper, KebsJsonSchema} +import pl.iterators.kebs.tagged._ @tagged object JsonSchemaTestTags { trait NameTag diff --git a/tagged-meta/src/test/scala/SprayAnnotationTests.scala b/tagged-meta/src/test/scala/pl/iterators/kebs/tag/meta/SprayAnnotationTests.scala similarity index 98% rename from tagged-meta/src/test/scala/SprayAnnotationTests.scala rename to tagged-meta/src/test/scala/pl/iterators/kebs/tag/meta/SprayAnnotationTests.scala index d4bff174..fceb89ab 100644 --- a/tagged-meta/src/test/scala/SprayAnnotationTests.scala +++ b/tagged-meta/src/test/scala/pl/iterators/kebs/tag/meta/SprayAnnotationTests.scala @@ -1,9 +1,10 @@ -import pl.iterators.kebs.tagged._ -import pl.iterators.kebs.tag.meta._ +package pl.iterators.kebs.tag.meta + import _root_.spray.json._ -import pl.iterators.kebs.json.KebsSpray import org.scalatest.funsuite.AnyFunSuite import org.scalatest.matchers.should.Matchers +import pl.iterators.kebs.json.KebsSpray +import pl.iterators.kebs.tagged._ @tagged object SprayTestTags { trait NameTag diff --git a/tagged-meta/src/test/scala/SprayKebsIssue47Test.scala b/tagged-meta/src/test/scala/pl/iterators/kebs/tag/meta/SprayKebsIssue47Test.scala similarity index 89% rename from tagged-meta/src/test/scala/SprayKebsIssue47Test.scala rename to tagged-meta/src/test/scala/pl/iterators/kebs/tag/meta/SprayKebsIssue47Test.scala index be019b22..848c7759 100644 --- a/tagged-meta/src/test/scala/SprayKebsIssue47Test.scala +++ b/tagged-meta/src/test/scala/pl/iterators/kebs/tag/meta/SprayKebsIssue47Test.scala @@ -1,6 +1,10 @@ +package pl.iterators.kebs.tag.meta + import org.scalatest.funsuite.AnyFunSuite import org.scalatest.matchers.should.Matchers import pl.iterators.kebs.json.KebsSpray +import pl.iterators.kebs.tag.meta._ +import pl.iterators.kebs.tag._ import pl.iterators.kebs.tag.meta.tagged import pl.iterators.kebs.tagged._ import util.Properties.versionNumberString diff --git a/tagged-meta/src/test/scala/TaggedAnnotationFromMethodTest.scala b/tagged-meta/src/test/scala/pl/iterators/kebs/tag/meta/TaggedAnnotationFromMethodTest.scala similarity index 94% rename from tagged-meta/src/test/scala/TaggedAnnotationFromMethodTest.scala rename to tagged-meta/src/test/scala/pl/iterators/kebs/tag/meta/TaggedAnnotationFromMethodTest.scala index 9b82ba02..b9367a0b 100644 --- a/tagged-meta/src/test/scala/TaggedAnnotationFromMethodTest.scala +++ b/tagged-meta/src/test/scala/pl/iterators/kebs/tag/meta/TaggedAnnotationFromMethodTest.scala @@ -1,8 +1,9 @@ +package pl.iterators.kebs.tag.meta + import org.scalatest._ -import pl.iterators.kebs.tagged._ -import pl.iterators.kebs.tag.meta.tagged import org.scalatest.funsuite.AnyFunSuite import org.scalatest.matchers.should.Matchers +import pl.iterators.kebs.tagged._ @tagged object DomainTrimmedString { trait NameTag diff --git a/tagged-meta/src/test/scala/TaggedAnnotationTests.scala b/tagged-meta/src/test/scala/pl/iterators/kebs/tag/meta/TaggedAnnotationTests.scala similarity index 98% rename from tagged-meta/src/test/scala/TaggedAnnotationTests.scala rename to tagged-meta/src/test/scala/pl/iterators/kebs/tag/meta/TaggedAnnotationTests.scala index 93034dd6..9b2cdb4c 100644 --- a/tagged-meta/src/test/scala/TaggedAnnotationTests.scala +++ b/tagged-meta/src/test/scala/pl/iterators/kebs/tag/meta/TaggedAnnotationTests.scala @@ -1,8 +1,9 @@ +package pl.iterators.kebs.tag.meta + import org.scalatest._ -import pl.iterators.kebs.tagged._ -import pl.iterators.kebs.tag.meta.tagged import org.scalatest.funsuite.AnyFunSuite import org.scalatest.matchers.should.Matchers +import pl.iterators.kebs.tagged._ @tagged object TestTags { trait NameTag