scala-activerecord
dsl основан на squeryl
, поэтому при вычислении сложного запроса мы могли бы опуститься до низкого уровня и использовать его statement
для красивой печатиSQL-утверждение.Таким образом, мы могли бы итеративно настраивать dsl, пока не получим требуемый оператор SQL.Например, скажем, у нас есть следующая схема:
object Tables extends ActiveRecordTables {
val persons = table[Person]
val tickets = table[Ticket]
}
case class Person(name: String, email: String, age: Int) extends ActiveRecord
case class Ticket(price: Float, priority: Boolean) extends ActiveRecord {
lazy val person = belongsTo[Person]
}
object Person extends ActiveRecordCompanion[Person]
object Ticket extends ActiveRecordCompanion[Ticket]
, и мы переходим к squeryl dsl, чтобы определить следующий запрос
val query =
dsl.join(Person.toQuery, Ticket.toQuery)((person, ticket) =>
groupBy(person.name, person.age)
compute(count(ticket.id))
on(person.id === ticket.id)
)
, тогда мы можем довольно просто напечатать оператор, используя
println(Person.inTransaction(query.statement))
, который выводит реальный оператор SQL
Select
q1.people6_name as g0,
q1.people6_age as g1,
count(q7.tickets11_id) as c0
From
(Select
people6.name as people6_name,
people6.email as people6_email,
people6.age as people6_age,
people6.id as people6_id
From
people people6
) q1
inner join (Select
tickets11.priority as tickets11_priority,
tickets11.price as tickets11_price,
tickets11.id as tickets11_id
From
tickets tickets11
) as q7 on (q1.people6_id = q7.tickets11_id)
Group By
q1.people6_name,
q1.people6_age
Как только мы выясним правильный dsl в squeryl, мы по крайней мере узнаем, что это возможно, и затем мы могли бы попытаться написать его также в scala-activerecord.Потенциальным преимуществом этого подхода является то, что у Странно больше документации.Обратите внимание на то, что говорится в Групповых и агрегированных запросах , что должно косвенно также выполняться для scala-activerecord:
Squeryl немного отличается от SQL в том смысле, что агрегатные функции не разрешеныв пределах выбора .Вместо этого они объявляются в предложении 'compute', которое фактически является скрытым выбором, поскольку его аргументы заканчиваются в предложении select сгенерированного SQL.Мотивация для этого выбора дизайна состоит в том, чтобы немного усложнить написание недействительных операторов Select, поскольку DSL заставляет предложение 'compute' заменять выбор или следовать за groupBy.
Насколько я понимаю, это означает, что мы не должны писать PassTicket.where(_.passId === pass.id).count
в предложении select
.
Относительно groupBy
, возвращающего Map
, мы могли бы вызвать values.toList
, чтобы получитьобратно список, например, скажем, у нас есть
Person("Picard", "picard@starfleet.org", 34).save
Person("Data", "data@starfleet.org", 40).save
Person("Geordi", "geordi@starfleet.org", 40).save
тогда println(Person.groupBy(person => person.age).values.toList)
должно дать
List(
List(Person(Data,data@starfleet.org,40), Person(Geordi,geordi@starfleet.org,40)),
List(Person(Picard,picard@starfleet.org,34))
)