Question

Using findBy as seen below, I can search the Authentications table for a record by key and value

def findBy(key: String, value: String): Any = DB.withConnection { implicit connection =>
  SQL("select * from authentications where {key}={value} limit 1").on('key -> key, 'value -> value)
}

Example:

Authentication.findByMe("email", "toot@toot.com")

Returns:

res1: Any = SimpleSql(SqlQuery(select * from authentications where ?=? limit 1,List(key, value),None),List((key,ParameterValue(email,anorm.ToStatement$$anon$3@4ca9aed5)), (value,ParameterValue(toot@toot.com,anorm.ToStatement$$anon$3@18154945))),<function1>)

How can I turn it back into an Authentication object? An object with all the fields I got back from the query.

I've tried the following, but I can't get passed a nullable object error when there's there's something null in one of the columns. I can't figure out how to put to use the solutions offered here

val authentication_parser =
  get[String]("email") ~
  get[String]("encrypted_password") ~
  get[String]("user_id") ~
  get[String]("token") ~
  get[Date]("created_at") ~
  get[Date]("updated_at")

val authentication = {
  authentication_parser map {
    case email~encrypted_password~user_id~token~created_at~updated_at => Authentication(email, encrypted_password, user_id, token, created_at, updated_at)
  }
}

Using it like so:

def findBy(key: String, value: String): Any = DB.withConnection { implicit connection =>
  SQL("select * from authentications where {key}={value} limit 1").on('key -> key, 'value -> value).as(authentication *)
}

I'm also new to Scala, so I've been riddled with problems like this one.

Was it helpful?

Solution

Any column that is nullable in your table should be an Option in your Authentication object. For example, if your table is something like this:

`email` varchar(255) NOT NULL,
`encrypted_password` varchar(255) NULL,
`user_id` int(11) NOT NULL,
`token` varchar(255) NULL,
`created_at` datetime NOT NULL,
`updated_at` datetime NULL

Then you should have:

case class Authentication(email: String, password: Option[String], userId: Int, token: Option[String], createdAt: Date, updatedAt: Option[Date])

Your parser would look like:

val authentication_parser = {
   get[String]("email") ~
   get[Option[String]]("encrypted_password") ~
   get[String]("user_id") ~
   get[Option[String]]("token") ~
   get[Date]("created_at") ~
   get[Option[Date]]("updated_at") map {
       case email~encrypted_password~user_id~token~created_at~updated_at => 
           Authentication(email, encrypted_password, user_id, token, created_at, updated_at)
   }
}

If for some reason you don't want to use Option in your Authentication class, then use getOrElse in the map portion and fill it in with default values (much uglier):

case email~encrypted_password~user_id~token~created_at~updated_at => 
           Authentication(email, encrypted_password.getOrElse(""), user_id, token.getOrElse(""), created_at, updated_at.getOrElse(new Date())

For the paranoid, you may want to exclude the hashed password from the parser when retrieving from the database:

val authentication_parser = {
   get[String]("email") ~
   get[String]("user_id") ~
   get[Option[String]]("token") ~
   get[Date]("created_at") ~
   get[Option[Date]]("updated_at") map {
       case email~user_id~token~created_at~updated_at => 
           Authentication(email, None, user_id, token, created_at, updated_at)
   }
}

I would also suggest that you change your .as() parameter. SQL("....").on(...).as(authentication_parser *) will parse to List[Authentication]. Since you're using LIMIT 1 in your query, it would be better to use authentication_parser.single (parses to Authentication) or authentication_parser.singleOpt (parses to Option[Authentication]). singleOpt is really the way to go for single records, as single will raise an exception if nothing is found.

Lastly, you ought to make the return type of your function something other than Any. (whatever matches the parser) Sorry for the wall of text.

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