I have a form where there is a number expected... I'm having a hard time verifying whether it has been submitted or not to return a message saying that it's required, I tried the following cases but none worked:
"orderBy" -> number.verifying("The order is required",_.isInstanceOf[Int])
"orderBy" -> number.verifying("The order is required",_>0)
Any ideas?
If orderBy isn't submitted with the Form at all, then it will return a FormError with the key error.required.
I assume you mean the case when an empty String is submitted instead of number. The problem with your attempts is that the verifying functions are never reached, because the empty String doesn't make it past the number validator.
The only thing I can think of is making a custom Mapping[Int] that first checks to see if the field is empty, then checks to see if it's a valid Int.
val requiredNumber: Mapping[Int] = Forms.nonEmptyText
.verifying("Must be numeric", i => Try(i.toInt).isSuccess || i.isEmpty)
.transform[Int](_.toInt, _.toString)
And testing:
scala> val form = Form(mapping("orderBy" -> requiredNumber)(identity)(Some(_)))
scala> form.bind(Map("orderBy" -> "1")).value
res24: Option[Int] = Some(1)
scala> form.bind(Map("orderBy" -> "")).errors
res26: Seq[play.api.data.FormError] = List(FormError(orderBy,List(error.required),WrappedArray()))
scala> form.bind(Map("orderBy" -> "aa")).errors
res27: Seq[play.api.data.FormError] = List(FormError(orderBy,List(Must be numeric),WrappedArray()))
scala> form.bind(Map("orderByzzz" -> "2")).errors
res28: Seq[play.api.data.FormError] = List(FormError(orderBy,List(error.required),List()))
Related
New to Scala, continue to struggle with Option related code. I have a HashMap built of Case Class instances that themselves contain hash maps with Case Class instance values. It is not clear to me how to access properties of the retrieved Class instances:
import collection.mutable.HashMap
case class InnerClass(name: String, age: Int)
case class OuterClass(name: String, nestedMap: HashMap[String, InnerClass])
// Load some data...hash maps are mutable
val innerMap = new HashMap[String, InnerClass]()
innerMap += ("aaa" -> InnerClass("xyz", 0))
val outerMap = new HashMap[String, OuterClass]()
outerMap += ("AAA" -> OuterClass("XYZ", innerMap))
// Try to retrieve data
val outerMapTest = outerMap.getOrElse("AAA", None)
val nestedMap = outerMapTest.nestedMap
This produces error: value nestedMap is not a member of Option[ScalaFiddle.OuterClass]
// Try to retrieve data a different way
val outerMapTest = outerMap.getOrElse("AAA", None)
val nestedMap = outerMapTest.nestedMap
This produces error: value nestedMap is not a member of Product with Serializable
Please advise on how I would go about getting access to outerMapTest.nestedMap. I'll eventually need to get values and properties out of the nestedMap HashMap as well.
Since you are using .getOrElse("someKey", None) which returns you a type Product (not the actual type as you expect to be OuterClass)
scala> val outerMapTest = outerMap.getOrElse("AAA", None)
outerMapTest: Product with Serializable = OuterClass(XYZ,Map(aaa -> InnerClass(xyz,0)))
so Product either needs to be pattern matched or casted to OuterClass
pattern match example
scala> outerMapTest match { case x : OuterClass => println(x.nestedMap); case _ => println("is not outerclass") }
Map(aaa -> InnerClass(xyz,0))
Casting example which is a terrible idea when outerMapTest is None, (pattern matching is favored over casting)
scala> outerMapTest.asInstanceOf[OuterClass].nestedMap
res30: scala.collection.mutable.HashMap[String,InnerClass] = Map(aaa -> InnerClass(xyz,0))
But better way of solving it would simply use .get which very smart and gives you Option[OuterClass],
scala> outerMap.get("AAA").map(outerClass => outerClass.nestedMap)
res27: Option[scala.collection.mutable.HashMap[String,InnerClass]] = Some(Map(aaa -> InnerClass(xyz,0)))
For key that does not exist, gives you None
scala> outerMap.get("I dont exist").map(outerClass => outerClass.nestedMap)
res28: Option[scala.collection.mutable.HashMap[String,InnerClass]] = None
Here are some steps you can take to get deep inside a nested structure like this.
outerMap.lift("AAA") // Option[OuterClass]
.map(_.nestedMap) // Option[HashMap[String,InnerClass]]
.flatMap(_.lift("aaa")) // Option[InnerClass]
.map(_.name) // Option[String]
.getOrElse("no name") // String
Notice that if either of the inner or outer maps doesn't have the specified key ("aaa" or "AAA" respectively) then the whole thing will safely result in the default string ("no name").
A HashMap will return None if a key is not found so it is unnecessary to do getOrElse to return None if the key is not found.
A simple solution to your problem would be to use get only as below
Change your first get as
val outerMapTest = outerMap.get("AAA").get
you can check the output as
println(outerMapTest.name)
println(outerMapTest.nestedMap)
And change the second get as
val nestedMap = outerMapTest.nestedMap.get("aaa").get
You can test the outputs as
println(nestedMap.name)
println(nestedMap.age)
Hope this is helpful
You want
val maybeInner = outerMap.get("AAA").flatMap(_.nestedMap.get("aaa"))
val maybeName = maybeInner.map(_.name)
Which if your feeling adventurous you can get with
val name: String = maybeName.get
But that will throw an error if its not there. If its a None
you can access the nestMap using below expression.
scala> outerMap.get("AAA").map(_.nestedMap).getOrElse(HashMap())
res5: scala.collection.mutable.HashMap[String,InnerClass] = Map(aaa -> InnerClass(xyz,0))
if "AAA" didnt exist in the outerMap Map object then the below expression would have returned an empty HashMap as indicated in the .getOrElse method argument (HashMap()).
Look at the following Map:
scala> val v = Map("id" -> ("_id", "$oid")).withDefault(identity)
v: scala.collection.immutable.Map[String,java.io.Serializable] = Map(id -> (_id,$oid))
The compiler generates a Map[String,java.io.Serializable] and the value of id can be retrieved like this:
scala> v("id")
res37: java.io.Serializable = (_id,$oid)
Now, if I try to access an element that does not exist like this...
scala> v("idx")
res45: java.io.Serializable = idx
... then as expected I get back the key itself... but how do I get back a tuple with the key itself and an empty string like this?
scala> v("idx")
resXX: java.io.Serializable = (idx,"")
I always need to get back a tuple, regardless of whether or not the element exists.
Thanks.
Instead of .withDefault(identity) you can use
val v = Map("id" -> ("_id", "$oid")).withDefault(x => (x, ""))
withDefault takes as a parameter a function that will create the default value when needed.
This will also change the return type from useless Serializable to more useful (String, String).
post("/api/v1/multi_preview/create"){
val html = getParam("html").get
val subject = getParam("subject").get
}
I want to know what exactly the .get method does in scala. getParam() is already returning the parameters to the post hit . I know that .get will make it easier as we dont have to "match" to check for null values as it will automotically thrown an exception in the former case.
Is there more to it than meets the eye?
It's usually a function on Options (i.e. Some or None). It gets you the contained element if it exists, otherwise it throws a NoSuchElementException.
https://www.scala-lang.org/api/current/scala/Option.html
scala> val x:Option[Int] = Some(42)
x: Option[Int] = Some(42)
scala> x.get
res2: Int = 42
scala> None.get
java.util.NoSuchElementException: None.get
at scala.None$.get(Option.scala:322)
... 32 elided
As a side note, you should try to avoid using get because it lands you back in the land of null-pointer exceptions. Instead, try to use getOrElse, or continue to use your Option value through higher-order functions like map, filter, fold, reduce etc.
Here is an example of how you can use it to your advantage:
scala> def foo(opt:Option[Int]) = opt map (_+2) filter (_%2 == 0) map (_+1)
foo: (opt: Option[Int])Option[Int]
scala> foo(Some(40))
res4: Option[Int] = Some(43)
scala> foo(Some(41))
res5: Option[Int] = None
scala> foo(None)
res6: Option[Int] = None
You can just pretend that the value is always specified if you don't "touch" it directly.
I suppose that's some Scalatra related code, if that's the case, getParam return an Option. Options are a wrapper around types that allow you to avoid having to check for nulls (and other kind of utilities too), in fact a value wrapped in an Option can be Some, in which case you can use get to access the value, e.g.
val someString = Option("some text")
println(someString.get) // prints "some text"
Or can be a None in which case when calling get you get an exception, wether a value is a Some or None can be determined via param match
someOption match {
case Some(value) => doSomething(value)
case None => doSomethingElse()
}
Or using isDefined which returns true if it's Some, false if it's None.
Note that your code could throw exceptions since you call get without knowing if it's a Some or None, you should use getOrElse which returns the value the Option holds if there's any, or a default specified parameter:
val someNone = Option(null)
println(someNone.getOrElse("some default")) // prints "some default"
I am currently working on a project with Scala and it seems I don't fully understand Scala's Typesystem :-/
I have the following situation:
def reviews(id: Int) = Action { implicit request =>
Ok(html.products.reviews(
reviewlist,
reviewlist
.find(review => review.id == id)
.getOrElse(reviewlist.headOption)
))
}
Unfortunately the compiler says, he cannot convert Product to Option[Review], so I changed the code
reviewlist
.find(review => review.id == id)
.getOrElse(reviewlist.headOption)
with
id match {
case 0 => reviewlist.headOption
case id => reviewlist.find(review => review.id == id)
}
which seems to work now, even though its not exactly the same thing as it does, for example, not show the first record anymore if an invalid review id is being submitted. it will then pretend, that there are no reviews available yet.
I then broke the problem down to a veeery simple sample:
val a: Option[Int] = Some(1).getOrElse(Some(1))
So, has anyone an idea, why the expression on the right side is not of the type Option[Int]?? Both, Some(1) and None inherit directly from Option and this expression is actually Some(1) in any or am I wrong?
Interestinly enough
val a: Option[Int] = None.getOrElse(None)
works, but all other combinations do not...
You wanted:
val a: Option[Int] = Some(1).orElse(Some(1))
Because
x.getOrElse(y)
will return 1 if x is Some(1) or y (which is Some(1)) if x is None, or speaking in code:
if (Some(1).isDefined) 1 else Some(1)
The type signature of Option.getOrElse is
getOrElse[B >: A](default: ⇒ B): B
That means that when you call getOrElse on an Option[A], it is going to try to return you something of type A. If the type of default (B) isn't the same as A, it is going to look for the closest shared ancestor of A and B. In your case, A and B are Option[Int] and Int. The best the compiler can do is Any.
An Option value has two representations, a good value (Some(...)) or a bad value (None).
With getOrElse you can reduce an Option to the type contained by it.
Imagine it as being a process of unpacking the value, removing it from the container.
In this process of unpacking, the Option is stripped and only the type contained by it is returned,
so in your example you really have this:
val a int = Some(1).getOrElse(2) // 1
And to do what you want is:
val b Option[Int] = Some(1).orElse(Some(2)) // Some(1)
My code is as follows
import scala.collection.mutable.HashMap
type CrossingInterval = (Date, Date)
val crossingMap = new HashMap[String, CrossingInterval]
val crossingData: String = ...
Firstly why does the following line compile?
val time = crossingMap.getOrElse(crossingData, -1)
I would have thought -1 would have been an invalid value
Secondly how do I do a basic check such as the following
if (value exists in map) {
}
else {
}
In Java I would just check for null values. I'm not sure about the proper way to do it in Scala
Typing your code in the interpreter shows why the first statement compiles:
type Date = String
scala> val time = crossingMap.getOrElse(crossingData, -1)
time: Any = -1
Basically, getOrElse on a Map[A, B] (here B = CrossingDate) accepts a parameter of any type B1 >: B: that means that B1 must be a supertype of B. Here B1 = Any, and -1 is of course a valid value of type Any. In this case you actually want to have a type declaration for time.
For testing whether a key belongs to the map, just call the contains method. An example is below - since Date was not available, I simply defined it as an alias to String.
scala> crossingMap.contains(crossingData)
res13: Boolean = false
scala> crossingMap += "" -> ("", "")
res14: crossingMap.type = Map("" -> ("",""))
//Now "" is a map of the key
scala> crossingMap.contains("")
res15: Boolean = true
If you want to check whether a value is part of the map, the simplest way is to write this code:
crossingMap.values.toSet.contains("")
However, this builds a Set containing all values. EDIT: You can find a better solution for this subproblem in Kipton Barros comment.