Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixing enum and some macro warnings. #185

Merged
merged 1 commit into from
Dec 22, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,25 @@ 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 {
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
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)
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 {
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
FastFuture.failed(new IllegalArgumentException(s"""Invalid value '$v'. Expected one of: ${`enum`.valuesToEntriesMap.keysIterator
.mkString(", ")}"""))
}
}
Expand Down
60 changes: 30 additions & 30 deletions circe/src/main/scala/pl/iterators/kebs/circe/KebsEnumFormats.scala
Original file line number Diff line number Diff line change
Expand Up @@ -7,57 +7,57 @@ 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(", ")
@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(", ")
@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] =
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)
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] =
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 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 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())
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(", ")
@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] =
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)
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] =
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 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 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)
Expand All @@ -67,18 +67,18 @@ trait KebsEnumFormats extends CirceEnum with CirceValueEnum {

trait Uppercase extends CirceEnum {
implicit def enumDecoder[E <: EnumEntry](implicit ev: EnumOf[E]): Decoder[E] =
uppercaseEnumDecoder(ev.enum)
uppercaseEnumDecoder(ev.`enum`)

implicit def enumEncoder[E <: EnumEntry](implicit ev: EnumOf[E]): Encoder[E] =
uppercaseEnumEncoder(ev.enum)
uppercaseEnumEncoder(ev.`enum`)
}

trait Lowercase extends CirceEnum {
implicit def enumDecoder[E <: EnumEntry](implicit ev: EnumOf[E]): Decoder[E] =
lowercaseEnumDecoder(ev.enum)
lowercaseEnumDecoder(ev.`enum`)

implicit def enumEncoder[E <: EnumEntry](implicit ev: EnumOf[E]): Encoder[E] =
lowercaseEnumEncoder(ev.enum)
lowercaseEnumEncoder(ev.`enum`)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,19 +31,19 @@ object AkkaHttpUnmarshallers {
case class PaginationQuery(sortBy: Column, sortOrder: SortOrder, offset: Offset, limit: Limit)

object BeforeKebs {
final def enumUnmarshaller[E <: EnumEntry](enum: Enum[E]): FromStringUnmarshaller[E] = Unmarshaller { _ => name =>
enum.withNameInsensitiveOption(name) match {
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
FastFuture.failed(new IllegalArgumentException(s"""Invalid value '$name'. Expected one of: ${`enum`.namesToValuesMap.keysIterator
.mkString(", ")}"""))
}
}
final def valueEnumUnmarshaller[V, E <: ValueEnumEntry[V]](enum: ValueEnum[V, E]): Unmarshaller[V, E] = Unmarshaller { _ => v =>
enum.withValueOpt(v) match {
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
FastFuture.failed(new IllegalArgumentException(s"""Invalid value '$v'. Expected one of: ${`enum`.valuesToEntriesMap.keysIterator
.mkString(", ")}"""))
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import enumeratum.{Enum, EnumEntry}
import scala.language.experimental.macros
import scala.reflect.macros.blackbox

class EnumOf[E <: EnumEntry](val enum: Enum[E])
class EnumOf[E <: EnumEntry](val `enum`: Enum[E])

object EnumOf {
implicit def enumOf[E <: EnumEntry]: EnumOf[E] = macro EnumEntryMacros.enumOfImpl[E]
Expand Down
20 changes: 10 additions & 10 deletions slick/src/main/scala/pl/iterators/kebs/enums/KebsEnums.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ 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)
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))
Expand All @@ -19,21 +19,21 @@ trait SlickEnum {
}

trait SlickValueEnum {
def valueEnumIsomorphism[V, E <: ValueEnumEntry[V]](enum: ValueEnum[V, E]): Isomorphism[E, V] =
new Isomorphism[E, V](_.value, enum.withValue)
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 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)
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)
implicit def enumValueColumn[E <: EnumEntry](implicit ev: EnumOf[E]): Isomorphism[E, String] = lowercaseEnumIsomorphism(ev.`enum`)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,56 +6,56 @@ import pl.iterators.kebs.macros.enums.{EnumOf, ValueEnumOf}
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 <: EnumEntry](`enum`: Enum[E], name: String) = {
val enumNames = `enum`.namesToValuesMap.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 <: EnumEntry](`enum`: Enum[E], value: JsValue) = {
val enumNames = `enum`.namesToValuesMap.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 <: EnumEntry](`enum`: Enum[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)
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 <: 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(_))
}

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 <: ValueEnumEntry[V]](`enum`: ValueEnum[V, E], value: V) = {
val enumValues = `enum`.valuesToEntriesMap.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 jsonFormat[V, E <: ValueEnumEntry[V]](`enum`: ValueEnum[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`.withValueOpt(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 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)

trait Uppercase extends SprayJsonEnum {
implicit def jsonEnumFormat[E <: EnumEntry](implicit ev: EnumOf[E]): JsonFormat[E] = uppercaseJsonFormat(ev.enum)
implicit def jsonEnumFormat[E <: EnumEntry](implicit ev: EnumOf[E]): JsonFormat[E] = uppercaseJsonFormat(ev.`enum`)
}

trait Lowercase extends SprayJsonEnum {
implicit def jsonEnumFormat[E <: EnumEntry](implicit ev: EnumOf[E]): JsonFormat[E] = lowercaseJsonFormat(ev.enum)
implicit def jsonEnumFormat[E <: EnumEntry](implicit ev: EnumOf[E]): JsonFormat[E] = lowercaseJsonFormat(ev.`enum`)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ final class macroImpl(val c: whitebox.Context) {
case Some(ModuleDef(mods, companionName, template)) =>
val generatedMethods = List(generateFromMethod, generateApplyMethod)
ModuleDef(mods, companionName, Template(template.parents, template.self, template.body ++ generatedMethods))
case Some(_) =>
c.abort(c.enclosingPosition, "Could not generate companion for tagged type, check proper context for @tagged")
case None =>
q"object ${name.toTermName} { ..${List(generateFromMethod, generateApplyMethod)} }"
}
Expand Down Expand Up @@ -155,6 +157,8 @@ final class macroImpl(val c: whitebox.Context) {
maybeCompanion match {
case Some(ModuleDef(mods, companionName, template)) =>
ModuleDef(mods, companionName, Template(template.parents, template.self, template.body ++ implicits))
case Some(_) =>
c.abort(c.enclosingPosition, "Could not generate companion for tagged type, check proper context for @tagged")
case None =>
q"object ${tagName.toTermName} { ..$implicits }"
}
Expand Down