Created
January 23, 2015 22:23
-
-
Save divarvel/1196a00dd1644f6ba4be to your computer and use it in GitHub Desktop.
Enums
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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