Anorm parse float values - scala

In Play framework 2.0, I'm trying to load a real (i.e. single precision float) type column from PostgreSQL using a row parser like this:
case class Foo(bar: Float)
object Foo {
def all = DB.withConnection { implicit c =>
SQL("SELECT * FROM foo").as(fooParser *)
}
val fooParser = {
get[Float]("bar") map {
case bar => Foo(bar)
}
}
}
This generates an error: could not find implicit value for parameter extractor: anorm.Column[Float]
When using double precision types everything works fine. Is it somehow possible to use single precision floats with Anorm?

You can always create your own column parser base on the existing ones:
implicit def rowToFloat: Column[Float] = Column.nonNull { (value, meta) =>
val MetaDataItem(qualified, nullable, clazz) = meta
value match {
case d: Float => Right(d)
case _ => Left(TypeDoesNotMatch("Cannot convert " + value + ":" + value.asInstanceOf[AnyRef].getClass + " to Float for column " + qualified))
}
}
but it matches on the type of value returned by the JDBC driver which may not be correct (depends on the column definition).

Related

Decode an optional query parameter using QueryParamDecoder in Scala

I want to decode an optional query parameter in my Scala code. I'm using http4s. The parameter is of the form ?part=35/43. End goal is to store this fraction as a Type Part = (Int, Int) so that we can have (35, 43) as a tuple to use further in the code. I've created an Object like:
https://http4s.org/v0.18/dsl/#optional-query-parameters
object OptionalPartitionQueryParamMatcher
extends OptionalValidatingQueryParamDecoderMatcher[Part]("part")
Now OptionalValidatingQueryParamDecoderMatcher needs an implicit QueryParamDecoder[Part] in scope.
For this I created an implicit val, which needs to check if we actually have a valid fraction, which is to say, both the chars should be a digit (and not a/1 or b/c etc) and the fraction should be less than 1 (1/2, 5/8 etc):
implicit val ev: QueryParamDecoder[Part] =
new QueryParamDecoder[Part] {
def decode(
partition: QueryParameterValue
): ValidatedNel[ParseFailure, Part] = {
val partAndPartitions = partition.value.split("/")
Validated
.catchOnly[NumberFormatException] {
val part = partAndPartitions(0).toInt
val partitions = partAndPartitions(1).toInt
if (
partAndPartitions.length != 2 || part > partitions || part <= 0 || partitions <= 0
) {
throw new IllegalArgumentException
}
(part, partitions)
}
.leftMap(e => ParseFailure("Invalid query parameter part", e.getMessage))
.toValidatedNel
}
}
The problem with above code is, it only catches NumberFormatException (that too when it can't convert a string to Int using .toInt) but what if I input something like ?part=/1, it should then catch ArrayIndexOutOfBoundsException because I'm querying the first two values in the Array, or let's say IllegalArgumentException when the fraction is not valid at all. How can I achieve that, catching everything in a single pass? Thanks!
well, the simplest approach would be to use .catchOnly[Throwable] (or even QueryParamDecoder .fromUnsafeCast directly) and it will catch any error.
However, I personally would prefer to do something like this:
(I couldn't compile the code right now, so apologies if it has some typos)
implicit final val PartQueryParamDecoder: QueryParamDecoder[Part] =
QueryParamDecoder[String].emap { str =>
def failure(details: String): Either[ParseFailure, Part] =
Left(ParseFailure(
sanitized = "Invalid query parameter part",
details = s"'${str}' is not properly formttated: ${details}"
))
str.split('/').toList match {
case aRaw :: bRaw :: Nil =>
(aRaw.toIntOption, bRaw.toIntOption) match {
case (Some(a), Some(b)) =>
Right(Part(a, b))
case _ =>
failure(details = "Some of the fraction parts are not numbers")
}
case _ =>
failure(details = "It doesn't correspond to a fraction 'a/b'")
}
}

Simplify/DRY up a case statement in Scala for Twirl Templates

So I'm using play Twirl templates (not within play; independent project) and I have some templates that generate some database DDLs. The following works:
if(config.params.showDDL.isSupplied) {
print( BigSenseServer.config.options("dbms") match {
case "mysql" => txt.mysql(
BigSenseServer.config.options("dbDatabase"),
InetAddress.getLocalHost().getCanonicalHostName,
BigSenseServer.config.options("dboUser"),
BigSenseServer.config.options("dboPass"),
BigSenseServer.config.options("dbUser"),
BigSenseServer.config.options("dbPass")
)
case "pgsql" => txt.pgsql(
BigSenseServer.config.options("dbDatabase"),
InetAddress.getLocalHost().getCanonicalHostName,
BigSenseServer.config.options("dboUser"),
BigSenseServer.config.options("dboPass"),
BigSenseServer.config.options("dbUser"),
BigSenseServer.config.options("dbPass")
)
case "mssql" => txt.mssql$.MODULE$(
BigSenseServer.config.options("dbDatabase"),
InetAddress.getLocalHost().getCanonicalHostName,
BigSenseServer.config.options("dboUser"),
BigSenseServer.config.options("dboPass"),
BigSenseServer.config.options("dbUser"),
BigSenseServer.config.options("dbPass")
)
})
System.exit(0)
}
But I have a lot of repeated statements. If I try to assign the case to a variable and use the $.MODULE$ trick, I get an error saying my variable doesn't take parameters:
val b = BigSenseServer.config.options("dbms") match {
case "mysql" => txt.mysql$.MODULE$
case "pgsql" => txt.pgsql$.MODULE$
case "mssql" => txt.mssql$.MODULE$
}
b("string1","string2","string3","string4","string5","string6")
and the error:
BigSense/src/main/scala/io/bigsense/server/BigSenseServer.scala:32: play.twirl.api.BaseScalaTemplate[T,F] with play.twirl.api.Template6[A,B,C,D,E,F,Result] does not take parameters
What's the best way to simplify this Scala code?
EDIT: Final Solution using a combination of the answers below
The answers below suggest creating factory classes, but I really want to avoid that since I already have the Twirl generated template object. The partially applied functions gave me a better understanding of how to achieve this. Turns out all I needed to do was to pick the apply methods and to eta-expand these; if necessary in combination with partial function application. The following works great:
if(config.params.showDDL.isSupplied) {
print((config.options("dbms") match {
case "pgsql" =>
txt.pgsql.apply _
case "mssql" =>
txt.mssql.apply _
case "mysql" =>
txt.mysql.apply(InetAddress.getLocalHost().getCanonicalHostName,
_:String, _:String, _:String,_:String, _:String)
})(
config.options("dbDatabase"),
config.options("dboUser"),
config.options("dboPass"),
config.options("dbUser"),
config.options("dbPass")
))
System.exit(0)
}
You can try to use eta-expansion and partially applied functions.
Given a factory with some methods:
class Factory {
def mysql(i: Int, s: String) = s"x: $i/$s"
def pgsql(i: Int, s: String) = s"y: $i/$s"
def mssql(i: Int, j: Int, s: String) = s"z: $i/$j/$s"
}
You can abstract over the methods like this:
val factory = new Factory()
// Arguments required by all factory methods
val i = 5
val s = "Hello"
Seq("mysql", "pgsql", "mssql").foreach {
name =>
val f = name match {
case "mysql" =>
// Eta-expand: Convert method into function
factory.mysql _
case "pgsql" =>
factory.pgsql _
case "mssql" =>
// Argument for only one factory method
val j = 10
// Eta-expand, then apply function partially
factory.mssql(_ :Int, j, _: String)
}
// Fill in common arguments into the new function
val result = f(i, s)
println(name + " -> " + result)
}
As you can see in the "mssql" case, the arguments may even differ; yet the common arguments only need to be passed once. The foreach loop is just to test each case, the code in the body shows how to partially apply a function.
You can try to do this by using tupled() to create tupled version of the function.
object X {
def a(x : Int, y : Int, z : Int) = "A" + x + y + z
def b(x : Int, y : Int, z : Int) = "B" + x + y + z
def c(x : Int, y : Int, z : Int) = "C" + x + y + z
}
val selectedFunc = X.a _
selectedFunc.tupled((1, 2, 3)) //returns A123
More specifically, you would store your parameters in a tuple:
val params = (BigSenseServer.config.options("dbDatabase"),
InetAddress.getLocalHost().getCanonicalHostName) //etc.
and then in your match statement:
case "mysql" => (txt.mysql _).tupled(params)

How to create anorm's parser with array?

I am using postgresql which supports array column field. To parse a row, I use this parser. It has error at the Array object. I guess I did it wrongly.
case class ServiceRequest(
id: Pk[Long],
firstname: String,
lastname: String,
images: Array[String])
val parser: RowParser[ServiceRequest] = {
get[Pk[Long]]("id") ~
get[String]("firstname") ~
get[String]("lastname") ~
Error here >>> get[Array[String]]("images") map {
case id ~ firstname ~ lastname ~ images=>
ServiceRequest(id, firstname, lastname, images)
}
}
Thanks
The Array[T] type is now natively supported in play 2.4.x, your don't have to roll your own converters.
But, it's still not nice to work with insert or update statements like:
def updateTags(id: Long, values: Seq[String]):Int = {
DB.withConnection { implicit conn =>
SQL("UPDATE entries SET tags = {value} WHERE id = {id}")
.on('value -> values, 'id -> id).executeUpdate
}
will give you an error
play - Cannot invoke the action, eventually got an error:
org.postgresql.util.PSQLException: ERROR: syntax error at or near "$2"
Put it simply, you should create the PreparedStatement using java.sql.Array type:
on('value -> conn.createArrayOf("varchar", value.asInstanceOf[Array[AnyRef]]), ...
As of now (play 2.4-M1), java.sql.Array is not converted to ParameterValue by default, which means
SQL(...).on(`arr -> values:java.sql.Array ) still gives a compilation error, you need another implicit conversion to make it compiling:
implicit object sqlArrayToStatement extends ToStatement[java.sql.Array] {
def set(s: PreparedStatement, i: Int, n: java.sql.Array) = s.setArray(i, n)
}
I have solved my problem by adding this converter:
implicit def rowToStringArray: Column[Array[String]] = Column.nonNull { (value, meta) =>
val MetaDataItem(qualified, nullable, clazz) = meta
value match {
case o: java.sql.Array => Right(o.getArray().asInstanceOf[Array[String]])
case _ => Left(TypeDoesNotMatch("Cannot convert " + value + ":" + value.asInstanceOf[AnyRef].getClass))
}
}
The converter transforms data type from postgresql's jdbc to java's data type for the parser in SELECT function. When you insert, you need another converter to convert from java's data type to postgresql's jdbc.
There is currently a pullrequest to add support for java.sql.Array as column mapping: https://github.com/playframework/playframework/pull/3062 .
Best,

equivalent of pythons repr() in scala

Is it there an equivalent of Pythons repr function in scala?
Ie a function which you can give any scala object an it will produce a string representation of the object which is valid scala code.
eg:
val l = List(Map(1 -> "a"))
print(repr(l))
Would produce
List(Map(1 -> "a"))
There is mostly only the toString method on every object. (Inherited from Java.) This may or may not result in a parseable representation. In most generic cases it probably won’t; there is no real convention for this as there is in Python but some of the collection classes at least try to. (As long as they are not infinite.)
The point where it breaks down is of course already reached when Strings are involved
"some string".toString == "some string"
however, for a proper representation, one would need
repr("some string") == "\"some string\""
As far as I know there is no such thing in Scala. Some of the serialisation libraries might be of some help for this, though.
Based on the logic at Java equivalent of Python repr()?, I wrote this little function:
object Util {
def repr(s: String): String = {
if (s == null) "null"
else s.toList.map {
case '\0' => "\\0"
case '\t' => "\\t"
case '\n' => "\\n"
case '\r' => "\\r"
case '\"' => "\\\""
case '\\' => "\\\\"
case ch if (' ' <= ch && ch <= '\u007e') => ch.toString
case ch => {
val hex = Integer.toHexString(ch.toInt)
"\\u%s%s".format("0" * (4 - hex.length), hex)
}
}.mkString("\"", "", "\"")
}
}
I've tried it with a few values and it seems to work, though I'm pretty sure sticking in a Unicode character above U+FFFF would cause problems.
If you deal with case classes, you can mix in the following trait StringMaker, so that calling toString on such case classes will work even if their arguments are strings:
trait StringMaker {
override def toString = {
this.getClass.getName + "(" +
this.getClass.getDeclaredFields.map{
field =>
field.setAccessible(true)
val name = field.getName
val value = field.get(this)
value match {
case s: String => "\"" + value + "\"" //Or Util.repr(value) see the other answer
case _ => value.toString
}
}
.reduceLeft{_+", "+_} +
")"
}
}
trait Expression
case class EString(value: String, i: Int) extends Expression with StringMaker
case class EStringBad(value: String, i: Int) extends Expression //w/o StringMaker
val c_good = EString("641", 151)
val c_bad = EStringBad("641", 151)
will result in:
c_good: EString = EString("641", 151)
c_bad: EStringBad = EStringBad(641,151)
So you can parse back the firsst expression, but not the first one.
No, there is no such feature in Scala.

Pattern matching on Class[_] type?

I'm trying to use Scala pattern matching on Java Class[_] (in context of using Java reflection from Scala) but I'm getting some unexpected error. The following gives "unreachable code" on the line with case jLong
def foo[T](paramType: Class[_]): Unit = {
val jInteger = classOf[java.lang.Integer]
val jLong = classOf[java.lang.Long]
paramType match {
case jInteger => println("int")
case jLong => println("long")
}
}
Any ideas why this is happening ?
The code works as expected if you change the variable names to upper case (or surround them with backticks in the pattern):
scala> def foo[T](paramType: Class[_]): Unit = {
| val jInteger = classOf[java.lang.Integer]
| val jLong = classOf[java.lang.Long]
| paramType match {
| case `jInteger` => println("int")
| case `jLong` => println("long")
| }
| }
foo: [T](paramType: Class[_])Unit
scala> foo(classOf[java.lang.Integer])
int
In your code the jInteger in the first pattern is a new variable—it's not the jInteger from the surrounding scope. From the specification:
8.1.1 Variable Patterns
... A variable pattern x is a simple identifier which starts with a lower case letter. It
matches any value, and binds the variable name to that value.
...
8.1.5 Stable Identifier Patterns
... To resolve the syntactic overlap with a variable pattern, a stable
identifier pattern may not be a simple name starting with a lower-case
letter. However, it is possible to enclose a such a variable name in
backquotes; then it is treated as a stable identifier pattern.
See this question for more information.
On your pattern matching, each of these 2 cases try to create place holder names instead of matching the class type as expected.
If you use upper case in the starting character, you'll be fine
def foo[T](paramType: Class[_]): Unit = {
val JInteger = classOf[Int]
val JLong = classOf[Long]
paramType match {
case JInteger => println("int")
case JLong => println("long")
}
}
scala> foo(1.getClass)
int
JMPL is simple java library, which could emulate some of the features pattern matching, using Java 8 features.
matches(data).as(
Integer.class, i -> { System.out.println(i * i); },
Byte.class, b -> { System.out.println(b * b); },
Long.class, l -> { System.out.println(l * l); },
String.class, s -> { System.out.println(s * s); },
Null.class, () -> { System.out.println("Null value "); },
Else.class, () -> { System.out.println("Default value: " + data); }
);