Как 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 достигается с помощью:

  1. в 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,

  2. Неявное снятие Скалы - 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.

Это выступление создателей, где большая часть этого описана (правильно).

Другие вопросы по тегам