Suppose I have the following two classes:
case class User(id: Long, name: String)
case class Message(id: Long, body: String, to: User, from: User)
The RowParser
s might look something like this:
val parser: RowParser[User] = {
get[Long]("users.id") ~ get[String]("users.name") map {
case id~name => User(id, name)
}
}
val parser: RowParser[Message] = {
get[Long]("messages.id") ~
get[String]("messages.name") ~
User.parser ~
User.parser map {
case id~body~to~from => Message(id, body, to, from)
}
}
Except that this won't work, because when joining the users
table twice, Anorm will only parse the first joined columns (twice), so that to
and from
will be the same.
This can be overcome using column aliases in the User
parser:
def parser(alias: String): RowParser[User] = {
getAliased[Long](alias + "_id") ~ getAliased[String](alias + "_name") map {
case id~name => User(id, name)
}
}
Then using different aliases for each User
in the Message
parser:
val parser: RowParser[Message] = {
get[Long]("messages.id") ~
get[String]("messages.name") ~
User.parser("to") ~
User.parser("from") map {
case id~body~to~from => Message(id, body, to, from)
}
}
This is okay for simple scenarios, but what if User
is more complicated and has an Address
with a State
and Country
, etc? That would require aliasing multiple tables and parsers, which gets quite messy.
Is there a better way to accomplish this? That is, I'm looking to select all of the relevant data in one query, and parse it using parser combinators, without a massive column aliasing scheme.
getAliased[String]("to_name") ~
etc, directly in the parser? – Indentionto_name
and one withfrom_name
, etc. The example is also fairly simplified, theUser
parser would really have many more fields, and nested parsers. – Obeydef parser
basically just replacesval parser
for the user injecting the alias, so seems pretty good to me. – Indentionu1.*, u2.*
, I have to enumerate all of the aliases like:u1.id as to_id, u1.name as to_name, u2.id as from_name, u2.name as from_name
... which gets unwieldy when more columns are needed. And up until this point I've avoided nesting anything withinUser
to keep the query from exploding in size. – Obey.*
, I already use a variablesqlSelectorFields
, so I think I'm going to parameterise this tosqlSelectorFields(alias)
. – Indention