How to map postgresql custom enum column with Slick2.0.1? - scala

I just can't figure it out. What I am using right now is:
abstract class DBEnumString extends Enumeration {
implicit val enumMapper = MappedJdbcType.base[Value, String](
_.toString(),
s => this.withName(s)
)
}
And then:
object SomeEnum extends DBEnumString {
type T = Value
val A1 = Value("A1")
val A2 = Value("A2")
}
The problem is, during insert/update JDBC driver for PostgreSQL complains about parameter type being "character varying" when column type is "some_enum", which is reasonable as I am converting SomeEnum to String.
How do I tell Slick to treat String as DB-defined "enum_type"? Or how to define some other Scala-type that will map to "enum_type"?

I had similar confusion when trying to get my postgreSQL enums to work with slick. Slick-pg allows you to use Scala enums with your databases enums, and the test suite shows how.
Below is an example.
Say we have this enumerated type in our database.
CREATE TYPE Dog AS ENUM ('Poodle', 'Labrador');
We want to be able to map these to Scala enums, so we can use them happily with Slick. We can do this with slick-pg, an extension for slick.
First off, we make a Scala version of the above enum.
object Dogs extends Enumeration {
type Dog = Value
val Poodle, Labrador = Value
}
To get the extra functionality from slick-pg we extend the normal PostgresDriver and say we want to map our Scala enum to the PostgreSQL one (remember to change the slick driver in application.conf to the one you've created).
object MyPostgresDriver extends PostgresDriver with PgEnumSupport {
override val api = new API with MyEnumImplicits {}
trait MyEnumImplicits {
implicit val dogTypeMapper = createEnumJdbcType("Dog", Dogs)
implicit val dogListTypeMapper = createEnumListJdbcType("Dog", Dogs)
implicit val dogColumnExtensionMethodsBuilder = createEnumColumnExtensionMethodsBuilder(Dogs)
implicit val dogOptionColumnExtensionMethodsBuilder = createEnumOptionColumnExtensionMethodsBuilder(Dogs)
}
}
Now when you want to make a new model case class, simply use the corresponding Scala enum.
case class User(favouriteDog: Dog)
And when you do the whole DAO table shenanigans, again you can just use it.
class Users(tag: Tag) extends Table[User](tag, "User") {
def favouriteDog = column[Dog]("favouriteDog")
def * = (favouriteDog) <> (Dog.tupled, Dog.unapply _)
}
Obviously you need the Scala Dog enum in scope wherever you use it.
Due to a bug in slick, currently you can't dynamically link to a custom slick driver in application.conf (it should work). This means you either need to run play framework with start and not get dynamic recompiling, or you can create a standalone sbt project with just the custom slick driver in it and depend on it locally.

Related

Shapeless. Modify tagged type

For instance I have two tagged types:
trait Created
type CreatedDttm = LocalDateTime ## Created
type CreatedTs = Timestamp ## Created
This types are used to deal with models. The first one is for common model, and the second one is for db entity.
final case class Entity(created: CreatedDttm) // Common model
final case class EntityRow(created: CreatedTs) // DB model
I have a converter somewhere in my sources:
def toModel(e: EntityRow) = Entity(e.created.toLocalDateTime) // Does not compile
This convertion does not compile, cause e.created.toLocalDateTime returns LocalDateTime, but Entity needs LocalDateTime tagged by Created.
So I have to change my conversion to tag[Created](e.created.toLocalDateTime) to make this code compile. It works, but, imho, it looks a kind of ugly.
Timestamp was tagged by Created, and a new LocalDateTime must be also tagged by the same Created.
Is there any way to modify tagged type without need to retag a new modified value?
Afraid not. The best I think you can do it minimize your pain. I would use an implicit class with a method like toCreatedDttm. Something like this:
implicit class LocalDateTimeOps(value: LocalDateTime) {
def toCreatedDttm: CreatedDttm = tag[Created][LocalDateTime](value)
}
Then you can change your line to:
def toModel(e: EntityRow) = Entity(e.created.toLocalDateTime.toCreatedDttm)
Or perhaps you can have the implicit class operate directly on the Timestamp like this:
implicit class TimestampOps(value: Timestamp) {
def toCreatedDttm: CreatedDttm = tag[Created][LocalDateTime](value.toLocalDateTime)
}
Then the line could be:
def toModel(e: EntityRow) = Entity(e.created.toCreatedDttm)

How to list annotations (custom java ones and others) on field members of Scala case class

So I'm trying to list fields with specific annotation in a Scala case class and I'm not able to get it working... Let's see come code right away
The case class (it's a simplified version of it, mine extends another class and is also nested in my test class where I use it for unit testing only):
case class Foo(#Unique var str: String) {}
The custom Java annotation:
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.FIELD, ElementType.PARAMETER})
public #interface Unique {}
And my class (simplified again) where I'm trying to do some stuffs with fields marked as unique
class SomeClass[T] (implicit typeTag: TypeTag[T]) {
val fields: Iterable[universe.TermSymbol] = typeOf(typeTag).members.collect { case s: TermSymbol => s }.
filter(s => s.isVal || s.isVar)
val list = fields.flatMap(f => f.annotations.find(_.tpe =:= TypeOf[Unique]).((f, _))).toList
}
But the val list in the last peace of code is always empty... fields has str listed in but without the annotation.
What am I missing?
The code listing the annotations is from the following answer:
How to list all fields with a custom annotation using Scala's reflection at runtime?
Seems the reference post is Scala 2.10 is old and is not compatible with the newest Scala version.
There is an example for how to get the specify annotation by type.
def listProperties[T: TypeTag]: List[universe.Annotation] = {
typeOf[T].typeSymbol.asClass
.asClass
.primaryConstructor
.typeSignature
.paramLists.flatten.flatMap(_.annotations)
}
val annotations = listProperties[Foo].filter(_.tree.tpe =:= typeOf[Unique])
println(annotations)
and there is way to get the annotation's field value:
case class Foo(#Unique(field = "bar") val str: String) {}
import scala.reflect.runtime.currentMirror
import scala.tools.reflect.ToolBox
val tb = currentMirror.mkToolBox()
val result = tb.eval(tb.untypecheck(head.tree)).asInstanceOf[Unique]
and need to call out your annotation class is implemented by using Java style, In Scala maybe you want to use StaticAnnotation for creating Annotation, like:
class Unique extends StaticAnnotation

How to define and use custom annotations in Scala

I am trying use a custom annotation in Scala. In this example, I create a string that I want to annotate with metadata (in this case, another string). Then, given an instance of the data, and I want to read the annotation.
scala> case class named(name: String) extends scala.annotation.StaticAnnotation
defined class named
scala> #named("Greeting") val v = "Hello"
v: String = Hello
scala> def valueToName(x: String): String = ???
valueToName: (x: String)String
scala> valueToName(v) // returns "Greeting"
Is this even possible?
With scala 2.11.6, this works to extract values of a annotation:
case class Named(name: String) extends scala.annotation.StaticAnnotation
val myAnnotatedClass: ClassSymbol = u.runtimeMirror(Thread.currentThread().getContextClassLoader).staticClass("MyAnnotatedClass")
val annotation: Option[Annotation] = myAnnotatedClass.annotations.find(_.tree.tpe =:= u.typeOf[Named])
val result = annotation.flatMap { a =>
a.tree.children.tail.collect({ case Literal(Constant(name: String)) => doSomething(name) }).headOption
}
There are different kinds of annotations in Scala:
Java Annotations that you can access using the Java Reflection API, annotations that are just in the source code, static annotations that are available to the type checker across different compilation units (so they should be somewhere in a class file but not where normal reflections go) and classfile annotations which are stored like java annotations, but cannot be read using the java reflection api.
I have described how to access static and classfile annotations here: What is the (current) state of scala reflection capabilities, especially wrt annotations, as of version 2.11?
If you just need a annotation containing a string using a Java annotation that is loaded by the JVM for you might be the simpler alternative.

How to update a mongo record using Rogue with MongoCaseClassField when case class contains a scala Enumeration

I am upgrading existing code from Rogue 1.1.8 to 2.0.0 and lift-mongodb-record from 2.4-M5 to 2.5.
I'm having difficulty writing MongoCaseClassField that contains a scala enum, that I really could use some help with.
For example,
object MyEnum extends Enumeration {
type MyEnum = Value
val A = Value(0)
val B = Value(1)
}
case class MyCaseClass(name: String, value: MyEnum.MyEnum)
class MyMongo extends MongoRecord[MyMongo] with StringPk[MyMongo] {
def meta = MyMongo
class MongoCaseClassFieldWithMyEnum[OwnerType <: net.liftweb.record.Record[OwnerType], CaseType](rec : OwnerType)(implicit mf : Manifest[CaseType]) extends MongoCaseClassField[OwnerType, CaseType](rec)(mf) {
override def formats = super.formats + new EnumSerializer(MyEnum)
}
object myCaseClass extends MongoCaseClassFieldWithMyEnum[MyMongo, MyCaseClass](this)
/// ...
}
When we try to write to this field, we get the following error:
could not find implicit value for evidence parameter of type
com.foursquare.rogue.BSONType[MyCaseClass]
.and(_.myCaseClass setTo myCaseClass)
We used to have this working in Rogue 1.1.8, by using our own version of the MongoCaseClassField, which made the #formats method overridable. But that feature was included into lift-mongodb-record in 2.5-RC6, so we thought this should just work now?
Answer coming from : http://grokbase.com/t/gg/rogue-users/1367nscf80/how-to-update-a-record-with-mongocaseclassfield-when-case-class-contains-a-scala-enumeration#20130612woc3x7utvaoacu7tv7lzn4sr2q
But more convenient directly here on StackOverFlow:
Sorry, I should have chimed in here sooner.
One of the long-standing problems with Rogue was that it was too easy to
accidentally make a field that was not serializable as BSON, and have it
fail at runtime (when you try to add that value to a DBObject) rather than
at compile time.
I introduced the BSONType type class to try to address this. The upside is
it catches BSON errors at compile time. The downside is you need to make a
choice when it comes to case classes.
If you want to do this the "correct" way, define your case class plus a
BSONType "witness" for that case class. To define a BSONType witness, you
need to provide serialization from that type to a BSON type. Example:
case class TestCC(v: Int)
implicit object TestCCIsBSONType extends BSONType[TestCC] {
override def asBSONObject(v: TestCC): AnyRef = {
// Create a BSON object
val ret = new BasicBSONObject
// Serialize all the fields of the case class
ret.put("v", v.v)
ret
}
}
That said, this can be quite burdensome if you're doing it for each case
class. Your second option is to define a generic witness that works for any
case class, if you have a generic serialization scheme:
implicit def CaseClassesAreBSONTypes[CC <: CaseClass]: BSONType[CC] =
new BSONType[CC] {
override def asBSONObject(v: CC): AnyRef = {
// your generic serialization code here, maybe involving formats
}
}
Hope this helps,

Is there anyway to create a new Scala object from a Java Class

I have a number of use cases for this, all around the idea of interop between existing Java libraries and new Scala Code. The use case I've selected is the easiest I think.
Use Case:
I working on providing a JUnit Runner for some scala tests (so that I can get my lovely red / green bar in Eclipse)
The runner needs to have a constructor with a java class as a parameter. So in Scala I can do the following:
class MyRunner(val clazz: Class[Any]) extends Runner {
def getDescription(): Description
def run(notifier: RunNotifier)
}
When I use either
#RunWith(MyRunner)
object MyTestObject
or
#RunWith(MyRunner)
class MyTestClass
then the runner is indeed instantiated correctly, and is passed a suitable class object
Unfortunately what i want to do now is to "get hold of" the object MyTestObject, or create a MyTestClass, which are both Scala entities. I would prefer to use Scala Reflection, but I also want to use the standard Junit jar.
What I have done
The following Stackover flow questions were educational, but not the same problem. There were the nearest questions I could find
How to create a TypeTag manually?
Any way to obtain a Java class from a Scala (2.10) type tag or symbol?
Using Scala reflection with Java reflection
The discussion on Environments, Universes and Mirrors in http://docs.scala-lang.org/overviews/reflection/environment-universes-mirrors.html was good, and the similar documents on other scala reflection also helped. Mostly through it is about the Scala reflection.
I browsed the Scaladocs, but my knowledge of Scala reflection wasn't enough (yet) to let me get what I wanted out of them.
Edit:
As asked here is the code of the class that is being created by reflection
#RunWith(classOf[MyRunner])
object Hello2 extends App {
println("starting")
val x= "xxx"
}
So the interesting thing is that the solution proposed below using the field called MODULE$ doesn't print anything and the value of x is null
This solution works fine if you want to use plan old java reflection. Not sure if you can use scala reflection given all you will have is a Class[_] to work with:
object ReflectTest {
import collection.JavaConversions._
def main(args: Array[String]) {
val fooObj = instantiate(MyTestObject.getClass())
println(fooObj.foo)
val fooClass = instantiate(classOf[MyTestClass])
println(fooClass.foo)
}
def instantiate(clazz:Class[_]):Foo = {
val rm = ru.runtimeMirror(clazz.getClassLoader())
val declaredFields = clazz.getDeclaredFields().toList
val obj = declaredFields.find(field => field.getName() == "MODULE$") match{
case Some(modField) => modField.get(clazz)
case None => clazz.newInstance()
}
obj.asInstanceOf[Foo]
}
}
trait Foo{
def foo:String
}
object MyTestObject extends Foo{
def foo = "bar"
}
class MyTestClass extends Foo{
def foo = "baz"
}