Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to reuse an anorm parser in playframework 2.0 with scala

I've been having a look at the computer-database sample and I noticed that in order to reuse the Computer parser, the list method uses the Computer.withCompany parser, which returns a tuple of (Computer, Company)

In the case I have to handle, instead of a reference to the id of the computer I want to have a Computer object, like this

case class Computer(id: Pk[Long] = NotAssigned, name: String, introduced: Option[Date], discontinued: Option[Date], company: Company)

so I was thinking how can I achieve something like the following (it's seudocode, of course)

val simple = {
  get[Pk[Long]]("computer.id") ~
  get[String]("computer.name") ~
  get[Option[Date]]("computer.introduced") ~
  get[Option[Date]]("computer.discontinued") ~
  get[Company]("company.*") map {
    case id~name~introduced~discontinued~company => Computer(id, name, introduced, discontinued, company)
  }
}

Obviously, the tricky part would be how to solve getCompany

any idea???

like image 682
opensas Avatar asked Oct 02 '12 01:10

opensas


1 Answers

I have an Idea entity and an IdeaType entity (it's like Computer and Company, in the computer-database example)

case class IdeaTest(
  val id: Pk[Long]          = NotAssigned,
  val name: String          = "unknown idea",
  val description: String   = "no description",
  val kind: IdeaType        = IdeaType()
)

case class IdeaType (
  val id: Pk[Long] = NotAssigned,
  val name: String = "unknown idea type",
  val description: String = "no description"
)

I define a TypeParser

val typeParser: RowParser[IdeaType] = {
  get[Pk[Long]]("idea_type.id") ~
  get[String]("idea_type.name") ~
  get[String]("idea_type.description") map {
    case id~name~description => IdeaType(
      id, name, description
    )
  }
}

And the first thing I tried was:

val ideaParser: RowParser[IdeaTest] = {
  get[Pk[Long]]("idea.id") ~
  get[String]("idea.name") ~
  get[String]("idea.description") ~
  typeParser map {
    case id~name~description~ideaType => IdeaTest(
      id, name, description, ideaType
    )
  }
}

Even though it DOES compile ok, it always has trouble loading the ideaType.

In the end, I had to define an ideaParser with no ideaType and compose it with a typeParser:

val typeParser: RowParser[IdeaType] = {
  get[Pk[Long]]("idea_type.id") ~
  get[String]("idea_type.name") ~
  get[String]("idea_type.description") map {
    case id~name~description => IdeaType(
      id, name, description
    )
  }
}

val ideaWithTypeParser = ideaParser ~ typeParser map {
  case idea~kind => (idea.copy(kind=kind))
}

and this is the code using it:

def ideaById(id: Long): Option[IdeaTest] = {
  DB.withConnection { implicit connection =>
    SQL("""
      select * from
      idea inner join idea_type 
      on idea.idea_type_id = idea_type.id 
      where idea.id = {id}""").
      on('id -> id).
      as(ideaParser.singleOpt)
  }
}

The only trouble I see, is that I have to create the IdeaTest object in an inconsistent state (with no ideaType) and then copy it to another instance with the correct IdeaType.

like image 186
opensas Avatar answered Oct 13 '22 10:10

opensas