解析 API 一开始可能看起来有点乏味,但当您开始组合和重用解析器时,它会非常强大,并且远比每个返回 SQL 的函数中的模式匹配更丑结果。
想象一下这样的事情:
case class User(id: Int, name: String, address: Address)
case class Address(id: Int, street: String, city: String, state: State, country: Country)
case class State(id: Int, abbrev: String, name: String)
case class Country(id: Int, code: String, name: String)
要构造User,您需要解析具有多个JOINs 的结果。我们没有一个大型解析器,而是为它的伴生对象中的每个类构造一个:
object User {
val parser: RowParser[User] = {
get[Int]("users.id") ~
get[String]("users.name") ~
Address.parser map {
case id~name~address => User(id, name, address)
}
}
}
object Address {
val parser: RowParser[Address] = {
get[Int]("address.id") ~
get[String]("address.street) ~
get[String]("address.city") ~
State.parser ~
Country.parser map {
case id~street~city~state~country => Address(id, street, city, state, country)
}
}
}
object State {
val parser: RowParser[State] = {
get[Int]("states.id") ~
get[String]("states.abbrev") ~
get[String]("states.name") map {
case id~abbrev~name => State(id, abbrev, name)
}
}
}
object Country {
val parser: RowParser[Country] = {
get[Int]("countries.id") ~
get[String]("countries.code") ~
get[String]("countries.name") map {
case id~code~name => Country(id, code, name)
}
}
}
请注意我如何在解析器中使用完整的表空间,以避免列名冲突。
总而言之,这看起来像很多代码,但对于每个源文件来说,它只是一个很小的占用空间。最大的好处是我们的User 解析器非常干净,尽管它的结构很复杂。假设在User 中address 实际上是Option[Address]。然后考虑该更改就像将 User 解析器中的 Address.parser 更改为 (Address.parser ?) 一样简单。
对于解析简单的查询,是的,它确实看起来像很多样板文件。但是在解析上述示例(以及更复杂的示例)时,我非常感谢解析 API。