http://woss.name/2012/04/02/retrieving-bigdecimals-from-a-database-with-anorm-scala/
object Site {
val allFieldsParser = {
get[Pk[Long]]("sites.id") ~ // Help me parse this syntax
get[String]("sites.name") ~
get[BigDecimal]("sites.latitude") ~
get[BigDecimal]("sites.longitude") map {
case id ~ name ~ latitude ~ longitude =>
Site(id, name, latitude, longitude)
}
}
def findAll(): Seq[Site] = {
DB.withConnection { implicit connection =>
SQL("SELECT * FROM sites").as(Site.allFieldsParser *)
}
}
}
In your example, ~ is being used in two different ways to mean two different things. In the first part you have
get[Pk[Long]]("sites.id") ~ // Help me parse this syntax
get[String]("sites.name") ~
get[BigDecimal]("sites.latitude") ~
etc. As it has already been pointed out, this is just method invocation, it is the same as
get[Pk[Long]]("sites.id").~(get[String]("sites.name").~(...
You can look at the definition of this method in the anorm source. It is a method on a RowParser[A]
(a parser that parses an A
, which takes a RowParser[B]
(a parser that parses a B
) and returns a parser that parses a A ~ B
. This A ~ B
is a second meaning for ~
. This is now referring not to a method, but to a case class defined in the same file here.
case class ~[+A, +B](_1: A, _2: B)
This is just a idiosyncratic way of referring to a class ~[A,B]
. At the type level, when you have a two argument type constructor, you can use the name of the class in infix notation. This isn't anything special about ~
, it would work with any two argument type constructor. If you had trait Foo[A,B]
you could refer to that as A Foo B
. Analogously, in pattern matching, variables a
and b
can be bound using the syntax a Foo b
, which is referred to as an Infix Operation Pattern in section 8.1.10 of the language specification.
In the second part of your example you have:
case id ~ name ~ latitude ~ longitude =>
This is pattern matching on these ~
case clases which are the result of running the parse you constructed above. So this is really just a nicer way of writing:
case ~(~(~(id, name), latitude), longitude) =>
In Scala
a ~ b
means
a.~(b)
So it calls the method ~
on a
and gives b
as an argument. Also note that any operator not ending with :
is left-associative.
Your example revisited would be:
get[Pk[Long]]("sites.id").~( // Help me parse this syntax
get[String]("sites.name").~(
get[BigDecimal]("sites.latitude").~(
get[BigDecimal]("sites.longitude")))) map {
case id ~ name ~ latitude ~ longitude =>
Site(id, name, latitude, longitude)
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With