With Anorm 2.5.2
SQL(s"insert into user (name, registered_date) values ({name},{registered_date})").on(
'name -> user.name,
'registered_date -> user.registeredDate
).executeInsert()
Compilation error:
Error:(72, 24) type mismatch; found : (Symbol,
org.joda.time.LocalDateTime) required: anorm.NamedParameter
'registered_date -> user.registeredDate
Should I include some implicit Time->Row transformation or it should come out of the box with anorm?
where user:
case class User(id: Option[Long] = None,
name: String,
registeredDate: LocalDateTime // joda-time'
)
import anorm.JodaParameterMetaData._
from here: https://groups.google.com/forum/#!topic/play-framework/I6TnTzO5MUw
(it was nice talking to myself :) )
Related
I need to change from one List[String] to List[MyObject] in scala.
For example,JSON input is like below
employee: {
name: "test",
employeeBranch: ["CSE", "IT", "ECE"]
}
Output should be like this,
Employee: {
Name: "test",
EmployeeBranch:[{"branch": "CSE"}, {"branch": "IT"}, {"branch": "ECE"}]
}
Input case class:
Class Office(
name: Option[String],
employeeBranch: Option[List[String]])
Output case class:
Class Output(
Name: Option[String],
EmployeeBranch: Option[List[Branch]])
case class Branch(
branch: Option[String])
This is the requirement.
It is hard to answer without knowing details of the particular JSON library, but an Object is probably represented as a Map. So to convert a List[String] to a List[Map[String, String]] you can do this:
val list = List("CSE", "IT", "ECE")
val map = list.map(x => Map("branch" -> x))
This gives
List(Map(branch -> CSE), Map(branch -> IT), Map(branch -> ECE))
which should convert to the JSON you want.
I want to parse province to case class, it throws mismatch
scala.MatchError: Some(USA) (of class scala.Some)
val result = EntityUtils.toString(entity,"UTF-8")
val address = JsonParser.parse(result).extract[Address]
val value.province = Option(address.province)
val value.city = Option(address.city)
case class Access(
device: String,
deviceType: String,
os: String,
event: String,
net: String,
channel: String,
uid: String,
nu: Int,
ip: String,
time: Long,
version: String,
province: Option[String],
city: Option[String],
product: Option[Product]
)
This:
val value.province = Option(address.province)
val value.city = Option(address.city)
doesn't do what you think it does. It tries to treat value.province and value.city as extractors (which don't match the type, thus scala.MatchError exception). It doesn't mutate value as I believe you intended (because value apparently doesn't have such setters).
Since value is (apparently) Access case class, it is immutable and you can only obtain an updated copy:
val value2 = value.copy(
province = Option(address.province),
city = Option(address.city)
)
Assuming the starting point:
val province: Option[String] = ???
You can get the string with simple pattern matching:
province match {
case Some(stringValue) => JsonParser.parse(stringValue).extract[Province] //use parser to go from string to a case class
case None => .. //maybe provide a default value, depends on your context
}
Note: Without knowing what extract[T] returns it's hard to recommend a follow-up
simple case class:
case class country(name: String, townPopulation: Map[String,Int])
with simple example:
scala> val germany = country("Germany",Map("Berlin" -> 100000, "Saale" -> 4000))
germany: country = country(Germany,Map(Berlin -> 100000, Saale -> 4000))
scala> germany.townPopulation("Berlin")
res77: Int = 100000
scala> germany.townPopulation("blergh")
java.util.NoSuchElementException: key not found: blergh
at scala.collection.MapLike$class.default(MapLike.scala:228)
at scala.collection.AbstractMap.default(Map.scala:59)
at scala.collection.MapLike$class.apply(MapLike.scala:141)
at scala.collection.AbstractMap.apply(Map.scala:59)
... 42 elided
I would like to return 0 for towns that dont exist, this can be done when declaring a val:
scala> val germany = country("Germany",Map("Berlin" -> 100000, "Saale" -> 4000).withDefaultValue(0))
germany: country = country(Germany,Map(Berlin -> 100000, Saale -> 4000))
scala> germany.townPopulation("fdhjkjhkhjdfg")
res79: Int = 0
but I can not figure out how to do it in one place, at least not when it is a case class, I would like something simple as the following, but I am obviously doing it wrong:
scala> case class country(name: String, townPopulation: Map[String,Int].withDefaultValue(0))
<console>:1: error: ')' expected but '.' found.
case class country(name: String, townPopulation: Map[String,Int].withDefaultValue(0))
^
<console>:1: error: ';' expected but ')' found.
case class country(name: String, townPopulation: Map[String,Int].withDefaultValue(0))
Is there a short simple path to a solution that has 0 as defaultValue always?
I see few possible ways:
add auxiliary method which encapsulate logic of default value
def population(town : String) : Int = townPopulation.getOrElse(town, 0)
add method to companion object with same purpose
def withDefault(name: String, townPopulation: Map[String, Int]) : country =
country(name, townPopulation.withDefaultValue(0))
Use map.get(), which returns an Option:
println germany.townPopulation.get("blergh").getOrElse(0)
// or, more concisely:
println germany.townPopulation.getOrElse("blergh", 0)
Ah, on re-reading your question, you want to hard-code the default value in the case class. I guess you'll have to mess with the apply() method.
val germany = country("Germany",
Map("Berlin" -> 100000, "Saale" -> 4000)
.withDefaultValue(0))
Edit (after OP's answer):
My bad! Should have read more thoroughly your question.
As stated in this SO question: You do not have the option of changing the way the default constructor stores its parameters (e.g. by modifying the parameters before they are stored as vals) […].
An alternate solution would be to declare a regular class along with its companion object:
class Country(val name: String, val townPopulation: Map[String, Int])
case object Country {
def apply(name: String, townPopulation: Map[String, Int]) =
new Country(name, townPopulation.withDefaultValue(0))
}
This would allow you to declare countries using the nice syntax:
val germany = Country("Germany", Map("Berlin" -> 100000, "Saale" -> 4000))
assert(germany.townPopulation("Berlin") == 100000)
assert(germany.townPopulation("Blergh") == 0)
But note that, as it is not a case class you won't get the usual case class perks such as:
// Compiler will give you
// "object Country is not a case class,
// nor does it have an unapply/unapplySeq member"
//germany match {
// case Country(a, b) => println("It won't compile! Not a case class")
//}
Depending on your use case, you could go the long hard road and implement methods unapply and unapplySeq to retrieve such behavior if needed!
I have been having trouble understanding what the issue is here since the Scala Anorm Pk became deprecated.
I switched my model to the following:
case class Item(id: Option[Long] = NotAssigned,
title: String,
descr: String,
created: Option[Date],
private val imgs: List[Img],
private val tags: List[Tag])
From id: Pk[Long]
I changed my form to:
val itemForm = Form(
mapping(
"id" -> ignored(23L),
"title" -> nonEmptyText,
"descr" -> nonEmptyText,
"created" -> optional(ignored(new Date)),
"imgs" -> Forms.list(itemImgs),
"tags" -> Forms.list(itemTags)
)(Item.apply)(Item.unapply)
)
From "id" -> ignored(NotAssigned:Pk[Long])
But, I get this error.
type mismatch; found : (Option[Long], String, String, scala.math.BigDecimal, Option[java.util.Date], List[models.Img], List[models.Tag]) => models.Item required: (Long, String, String, Option[java.util.Date], List[models.Img], List[models.Tag]) => ?
)(Item.apply)(Item.unapply)
Why is an Option[Long] not required on the Item model?
I don't know what 23L is, but that's what was in the Play Documentation. The value of id in the database is coming from a sequence.
If I change it to:
"id" -> ignored(NotAssigned:Option[Long]),
Which makes the most sense to me... I get this error:
type mismatch; found : anorm.NotAssigned.type required: Option[Long]
"id" -> ignored(NotAssigned:Option[Long]),
Which makes less sense than before.
Just to clarify, it's not Anorm that's deprecated, but the Pk type within Anorm.
Your problem here is that you're trying to assign NotAssigned to an Option[Long], which is incompatible. You should change all of the NotAssigneds to None.
So your class would look like this:
case class Item(
id: Option[Long] = None,
title: String,
descr: String,
price: BigDecimal,
created: Option[Date],
private val imgs: List[Img],
private val tags: List[Tag]
)
And the Form mapping:
"id" -> ignored[Option[Long]](None)
I try to fill a form with the values of System
def edit(id: Long) = IsAuthenticated { username => implicit request =>
User.findByEmail(username).map { user =>
System.findById(id).map { system =>
Ok(html.systems.editForm(id, systemForm.fill(system), Person.options, user))
}.getOrElse(NotFound)
}.getOrElse(Forbidden)
}
but some of 'system' values are java.math.BigDecimal
val systemForm = Form(
mapping(
"id" -> ignored(NotAssigned:Pk[BigDecimal]),
"sys_name" -> nonEmptyText,
"sys_desc" -> nonEmptyText,
"sys_owner1_id" -> longNumber,
"sys_owner2_id" -> optional(longNumber)
)(System.apply)(System.unapply)
)
and it says :
type mismatch; found : (anorm.Pk[java.math.BigDecimal], String, String, String, Option[String], java.math.BigDecimal, Option[java.math.BigDecimal]) => models.System required: (anorm.Pk[java.math.BigDecimal], String, String, Long, Option[Long]) => ?
how can i handle this?
Looks like problem in anorm or somewhere near.
As you may see from error description sys_owner1_id and sys_owner2_id are BigIntegers in query result, but declared as long in form.
I am not familiar with anorm, but solution is to declare these ids as long in anorm, or declare them as BigInteger in form mapping or convert from BigInteger to long in your query.