What is the correct way, and where is the correct place, to trim a value from a fixed character database column when using the Play framework with Slick?
The reason I want to trim the string is that the database schema specifies a character(40)
column type rather than a character varying
type.
I have this case class:
case class Test(id: Long, trimMe: Option[String])
I have this Slick table relation:
class Tests(tag: Tag) extends Table[Test](tag, "test") {
def id = column[Long ]("test_id", O.PrimaryKey, O.AutoInc)
def trimMe = column[String]("trim_me" )
def * = (id, trimMe) <> (Test.tupled, Test.unapply _)
}
I have this test class with a JSON mapping:
object TrimTest {
implicit val testWrite = new Writes[Test] {
def writes(test: Test) = Json.obj(
"id" -> test.id ,
"trim" -> test.trimMe
)}
}
This all works but returns a space-padded string.
I tried a few variations of trimming in the JSON mapper:
object TrimTest {
implicit val testWrite = new Writes[Test] {
def writes(test: Test) = Json.obj(
"id" -> test.id ,
"trim1" -> test.trimMe.map(_.trim) ,
"trim2" -> test.trimMe.fold("") {_.trim} ,
"trim3" -> test.trimMe.map(_.trim).getOrElse("")
)}
}
trim1
above works, but returns null
when the optional value is not present.
trim2
does work for all cases, but I have seen it stated in various places that map
then getForElse
is "more idiomatic Scala" than using fold
.
trim3
is just past the limit of my current understanding of Scala and shows my intent but does not compile.
The compilation error in the case of trim3
is:
type mismatch; found : Object required: play.api.libs.json.Json.JsValueWrapper
I can certainly live with using fold
, but what is the usual way to do this?
What about getting the value and then trimming?
scala> val strOpt = Option("Some string not trimmed ")
strOpt: Option[String] = Some(Some string not trimmed )
scala> strOpt.getOrElse("").trim
res0: String = Some string not trimmed
scala> val strNone = Option(null)
strNone: Option[Null] = None
scala> strNone.getOrElse("").trim
res2: String = ""
Edit:
You have a Test
row which is a case class with two fields, id
and trimMe
, you want to map this class to a JSON but the problem is you also want to trim
it a the trimeMe
field.
If you have a Column[String]
, from the Slick
perspective it means a non optional field, but your case class has an optional field, either both (Test
and Tests
) have an optional trimMe
field (that means a nullable column) or they don't (that means that the column is mandatory).
In the end the case class you have is the representation of a row you have in your database and that's what Slick queries return(*), it should reflect your schema declaration.
For the trim
problem
if trimMe
is a Column[Option[String]]
your case class has trimMe: Option[String]
so you can getOrElse
and be sure to return a String
and then trim
,
val someString = Option("some String ")
someString.getOrElse("").trim
if trimMe
is a Column[String]
you case class has trimMe: String
, then just wrap it in an Option
, then getOrElse
and then trim
:
val str = "some other string "
Option(str).getOrElse("").trim
In this way wether it's a None
or Some
no exception is thrown.
(*) Not always, you can have queries which return columns instead of whole rows.