Как Scala Slick переводит код Scala в JDBC?
Как Slick переводит код, такой как:
val q2 = for {
c <- Coffees if c.price < 9.0
s <- Suppliers if s.id === c.supID
} yield (c.name, s.name)
for(t <- q2) println(" " + t._1 + " supplied by " + t._2)
В JDBC?
Использует ли это Scala Virtualized? Использует ли он какой-то другой метод?
2 ответа
Стабильный API Slick достигает этого через то, что он называет встроенным встраиванием. Ваш пример явно использует стабильный API (как вы используете ===
для равенства, а не ==
).
Прелесть Slick (и, в свою очередь, Scala) заключается в том, что это достигается без использования макросов или Scala-Virtualized. (Примечание: экспериментальный API Slick использует макросы - и это позволит вам использовать ==
вместо ===
или же is
)
Перевод в SQL достигается с помощью:
в Scala
for
синтаксис понимания, который переводится в вызовы методов. Таблицы, определенные в Slick, являются Монадами - в них есть магияforeach
,map
,flatMap
, а такжеfilter
методы, которые позволяют им быть выраженными вfor
'loop', в то время как Scala переводит их в вызовы методов (как правильно показано в коде, представленном другим ответом @ emil-ivanov).Как и в обычных коллекциях Scala,
for
является синтаксическим сахаром для вложенных вызовов методовflatMap
/map
а такжеfilter
; в отличие от обычных коллекций, пятноTable
версии объектовmap
а такжеfilter
возвращать представления запроса, создавая его вместе с каждым условием фильтра (if
) или присоединиться (как вs <- Suppliers if s.id is c.supID
)Так что тип
q2
это не ваша обычная коллекция (как обычно используется для понимания в Scala), а скорее представление запроса. (Так же, как Monada Scala Option также работает сfor
понимание, несмотря на то, что не является "коллекцией" (таким образом, чтоList
или жеMap
является))Вы можете увидеть основной запрос с
q2.selectStatement
,Неявное снятие Скалы -
c.price
это неInt
а скорее представление значения столбца - так выражениеc.price < 9.0
становитсяc.price.<(Const(9.0))
(Int
поднимается до нужного типа), и<
это просто метод класса, который представляетc.price
,Column
,<
метод не делает то, что<
обычно делает (в случае простогоInt
s) - он просто возвращает представление SQL AST, соответствующееprice < 9
это становится частью SQL, который генерируется и отправляется в JDBC для выполнения.
С точки зрения деталей происходит еще много всего, но я думаю, что монада запросов и скрытое снятие являются главными составляющими.
В Скале for
"loop" на самом деле не специальная языковая конструкция, а скорее синтаксический сахар. Ваш первый пример
val q2 = for {
c <- Coffees if c.price < 9.0
s <- Suppliers if s.id === c.supID
} yield (c.name, s.name)
переводит что-то в строки:
val q2 = Coffees.withFilter(_.price < 9.0).flatMap(c =>
Suppliers.withFilter(_.id === c.supID).map(s =>
(c.name, s.name)
)
)
Теперь flatMap
, map
, withFilter
(а также foreach
) на самом деле не фильтруют коллекцию, а собирают то, что происходит, в AST (абстрактном синтаксическом дереве), который затем обрабатывается в Slick для перевода в SQL.
Также, c.price
, c.supID
на самом деле гладкий column
с которого <
, >
, ===
(и так далее) методы не возвращают bool, но также собирают сравнение, которое затем передается для преобразования в SQL.
Это выступление создателей, где большая часть этого описана (правильно).