All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.malliina.values.companions.scala Maven / Gradle / Ivy

The newest version!
package com.malliina.values

import io.circe.{Codec, Decoder, Encoder}

trait Identifier extends Any {
  def id: String
  override def toString: String = id
}

@deprecated("Use WrappedString instead.", "1.10.0")
abstract class Wrapped(val value: String) {
  override def toString: String = value
}

trait WrappedString extends Any {
  def value: String
  override def toString: String = value
}

trait WrappedId extends Any {
  def id: Long
  override def toString = s"$id"
}

trait WrappedLong extends Any {
  def num: Long
  override def toString = s"$num"
}

trait WrappedValue[T] {
  def value: T
}

abstract class IdentCompanion[T <: Identifier] extends JsonCompanion[String, T] {
  override def write(t: T): String = t.id
}

abstract class IdCompanion[T <: WrappedId] extends JsonCompanion[Long, T] {
  override def write(t: T): Long = t.id
}

abstract class StringCompanion[T <: WrappedString] extends JsonCompanion[String, T] {
  override def write(t: T): String = t.value
}

abstract class JsonCompanion[Raw, T](implicit
  d: Decoder[Raw],
  e: Encoder[Raw],
  o: Ordering[Raw],
  r: Readable[Raw]
) extends ValidatingCompanion[Raw, T] {
  def apply(raw: Raw): T

  override def build(input: Raw): Either[ErrorMessage, T] =
    Right(apply(input))
}

abstract class ValidatingCompanion[Raw, T](implicit
  d: Decoder[Raw],
  e: Encoder[Raw],
  o: Ordering[Raw],
  r: Readable[Raw]
) {
  implicit val json: Codec[T] = Codec.from(
    d.emap(raw => build(raw).left.map(err => err.message)),
    e.contramap[T](write)
  )
  implicit val ordering: Ordering[T] = o.on(write)
  implicit val readable: Readable[T] = r.emap(build)

  def build(input: Raw): Either[ErrorMessage, T]
  def write(t: T): Raw
  def defaultError(in: Raw): ErrorMessage = ErrorMessage(s"Invalid input: '$in'.")
}

abstract class WrappedEnum[T <: WrappedString] extends StringEnumCompanion[T] {
  override def write(t: T) = t.value
}

abstract class StringEnumCompanion[T] extends EnumCompanion[String, T] {
  override def build(input: String): Either[ErrorMessage, T] =
    all.find(i => write(i).toLowerCase == input.toLowerCase).toRight(defaultError(input))
}

abstract class EnumCompanion[Raw, T](implicit
  f: Decoder[Raw],
  e: Encoder[Raw],
  o: Ordering[Raw],
  r: Readable[Raw]
) extends ValidatingCompanion[Raw, T] {

  def all: Seq[T]
  def resolveName(item: T): Raw = write(item)
  private def allNames = all.map(write).mkString(", ")

  def build(input: Raw): Either[ErrorMessage, T] =
    all.find(i => write(i) == input).toRight(defaultError(input))

  override def defaultError(input: Raw) =
    ErrorMessage(s"Unknown input: '$input'. Must be one of: $allNames.")
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy