Этот код создает запрос для получения профиля пользователя на веб-сервере. Он создает запрос, который собирает необходимую информацию в DTO (который является просто классом case), который впоследствии отправляется обратно в виде JSON.
def getProfile(userId: Long)={
val q = for{
((((u,p),a),b), ba) <- filterById(userId) join
People on (_.personId === _.id) joinLeft
Addresses on (_._2.addressId === _.id) joinLeft
Businesses on (_._1._2.businessId === _.id) joinLeft
Addresses on (_._2.flatMap(_.addressId) === _.id)
}yield(p, a, b, ba)
db.run(q.result.headOption).map{ _.map{case(p,a,b,ba) =>
val business = b match {
case Some(b) => Some(dtos.Business(b.name, b.abn, b.adminFee, ba, b.id))
case _ => None
}
dtos.ProfileInfo(p, a, business)
}}
}
Я включил обработку результатов (db.run(...)
) только для контекста.
Я ищу более читаемый способ выразить конструкцию запроса.
Мой опыт чтения этого таков: «Подождите, что?? ... on (_._1._2.flatMap(_.addressId)
.... что это делает?? Почему плоская карта там, а не здесь: on (_._1._2.businessId
. На самом деле это прямые вещи, но не читайте прямо вперед. .
Я ищу способ выразить это, который не требует количества умозаключений, необходимых для прочтения этой версии. Мне нужно «вывести», что такое _._1._2 и почему его нужно сглаживать, что мне не нужно делать с эквивалентным SQL.
Примечания:
- Этот код исходит из существующего приложения (не написанного мной), которое я расширяю.
- Пользователи, Люди, Адреса, Компании (очевидно?) Таблицы.
- У людей и предприятий есть адреса.
- У пользователей есть человек(*), у людей есть бизнес
filterByUserId(userId)
в основном эквивалентноUsers.filter(_.id === userId
)Эквивалентный SQL:
select p.*, a1.*, b.*, a2.* from Users u innerJoin People p on (u.personId == p.id) leftJoin Addresses a1 on (p.addressId == a1.id) leftJoin Businesses b on (p.businessId == b.id) leftJoin Addresses a2 on ( b.addressId == a2.id)