Skip to content

Instantly share code, notes, and snippets.

@divarvel
Created January 23, 2015 22:23
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save divarvel/1196a00dd1644f6ba4be to your computer and use it in GitHub Desktop.
Save divarvel/1196a00dd1644f6ba4be to your computer and use it in GitHub Desktop.
Enums
package models
import scalaz._
import Scalaz._
import anorm._
import org.postgresql.util.PGobject
import org.postgresql.jdbc4.Jdbc4Array
import play.api.libs.json._
import play.api.data._
import play.api.data.format.Formatter
object enums {
trait EnumAdt[A] {
def values: List[A]
def valueAsString(x: A): String
def parseValue(x: String): Option[A] = values.find(valueAsString(_) == x)
}
def values[A](implicit ev: EnumAdt[A]): List[A] = ev.values
def toScalazEnum[A](implicit ev: EnumAdt[A]): Enum[A] = {
val vs = ev.values
val size = vs.size
new Enum[A] {
def pred(x: A) = {
val idx = vs.indexOf(x) + 1
vs(if(idx < size) idx else 0)
}
def succ(x: A) = {
val idx = vs.indexOf(x) - 1
vs(if(idx >= 0) idx else size - 1)
}
def order(x: A, y: A) = vs.indexOf(x) ?|? vs.indexOf(y)
override def min = vs.headOption
override def max = vs.lastOption
}
}
def jsonWrites[A](implicit ev: EnumAdt[A]): Writes[A] = new Writes[A] {
def writes(v: A) = {
JsString(ev.valueAsString(v))
}
}
def jsonReads[A](implicit ev: EnumAdt[A]): Reads[A] = new Reads[A] {
def reads(js: JsValue) = js match {
case JsString(s) => ev.parseValue(s).map(JsSuccess(_)).getOrElse(JsError("no parse"))
case _ => JsError("no parse")
}
}
def toStatement[A](implicit ev: EnumAdt[A]): ToStatement[A] = new ToStatement[A] {
def set(s: java.sql.PreparedStatement, index: Int, aValue: A): Unit = s.setObject(index, ev.valueAsString(aValue))
}
def fromColumn[A](implicit ev: EnumAdt[A]): Column[A] = Column.nonNull { (value, meta) =>
val MetaDataItem(qualified, nullable, clazz) = meta
val error = TypeDoesNotMatch("Cannot convert " + value + ":" + value.asInstanceOf[AnyRef].getClass + " for column " + qualified)
value match {
case s: PGobject => ev.parseValue(s.getValue).toRight(error)
case _ => Left(error)
}
}
def fromListColumn[A](implicit ev: EnumAdt[A]): Column[List[A]] = Column.nonNull { (value, meta) =>
val MetaDataItem(qualified, nullable, clazz) = meta
val err = TypeDoesNotMatch("Cannot convert " + value + ":" + value.asInstanceOf[AnyRef].getClass + " to list for column " + qualified)
value match {
case o: Jdbc4Array => {
Right(o.toString().drop(1).dropRight(1).split(',').toList.flatMap(x => ev.parseValue(x)))
}
case _ => Left(err)
}
}
def toListStatement[A](implicit ev: EnumAdt[A]): ToStatement[List[A]] = new ToStatement[List[A]] {
def set(s: java.sql.PreparedStatement, index: Int, aValue: List[A]): Unit = {
val string = aValue.map(x => "\"" + ev.valueAsString(x) + "\"").mkString("{", ",", "}")
s.setObject(index, string)
}
}
def enumFormat[A](implicit ev: EnumAdt[A]): Formatter[A] = new Formatter[A] {
def bind(key: String, data: Map[String, String]) =
data
.get(key)
.flatMap(x => ev.parseValue(x))
.toRight(Seq(FormError(key, "error.invalid", Nil)))
def unbind(key: String, value: A) = Map(key -> ev.valueAsString(value))
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment