Question

Scala beginner, here. I'm pretty confused by this entire expression, to be honest. I vaguely understand what this is supposed to do, but what are the ~s doing?

val simple = {
   get[String]("user.email") ~
   get[String]("user.name") ~
   get[String]("user.password") map {
     case email~name~password => User(email, name, password)
   }
}

Here's the github source if you're curious or need more info.

Thanks in advance!

Was it helpful?

Solution

Yes the method RowParser.~ combines two separate RowParsers for separate columns, giving result RowParser[anorm.~[Col1Type, Col2Type]]. Here's the processing details:

  1. Singleton object anorm.SqlParser has all members imported.

  2. It has a method get[T]:

    def get[T](columnName: String)(implicit extractor: Column[T]): RowParser[T] 
    
    • when called, generic param T is instantiated as String
    • input param columnName is populated as "user.email", etc
    • input param extractor is implicit. It's not provided in calls. So, the compiler picks up an implicit value using the type signature matching within the Column singleton object. It finds method rowToString: Column[String].
    • output params RowParser[T] is instantiated RowParser[String]
  3. anorm.RowParser[String] has method "~" called. It's signature is:

    def ~[B](p: RowParser[B]): RowParser[~[String, B]]  
    
  4. But what is the input (parameter p) for "~"? It's on the next line: get[String]("user.name") ~.

  5. Because of this "chaining" of method calls, the method call order is actually bottom-up:

    • first

      get[String]("user.password") map {
        case email~name~password => User(email, name, password)
      

      which returns type RowParser[String]

    • which is passed into

      get[String]("user.name") ~
      

      which returns type RowParser[~[String, String]]. Here, this uses a different "~" - the type anorm.~[A,B] which is defined as a case class:

      case class ~[+A, +B](_1: A, _2: B) extends Product with Serializable 
      

      representing the result of conjoining two parsed columns in the row.

    • This RowParser is passed into:

      get[String]("user.email") ~
      

      which returns type RowParser[~[String, RowParser[~[String, String]]]]

OTHER TIPS

Figured it out. The '~' is a parser combinator that operates on a row. It validates the existence of user.emal, user.name, user.password, the result of which (if successful) is a ~[A, B, C] which can be mapped. In this case, if all 3 exist, a new User object is created and returned.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top