¿Cómo Scala Slick traduce el código de Scala en JDBC?
(2)
En Scala, el for
"loop" no es en realidad una construcción de lenguaje especial, sino azúcar sintáctica. Tu primer ejemplo
val q2 = for {
c <- Coffees if c.price < 9.0
s <- Suppliers if s.id === c.supID
} yield (c.name, s.name)
Se traduce en algo en las líneas de:
val q2 = Coffees.withFilter(_.price < 9.0).flatMap(c =>
Suppliers.withFilter(_.id === c.supID).map(s =>
(c.name, s.name)
)
)
Ahora, flatMap
, map
, withFilter
(y foreach
) en realidad no filtran la colección, sino que recopilan lo que está sucediendo en un AST (árbol de sintaxis abstracta), que luego es manejado por Slick para traducirlo a SQL.
Además, c.price
, c.supID
son en realidad column
Slick, cuyos métodos <
, >
, ===
(y así sucesivamente) no devuelven bool, sino que también recopilan la comparación, que luego se pasa a convertir a SQL.
Esta es una charla de los creadores, donde la mayor parte de esto se describe (correctamente).
¿Cómo traduce Slick código como:
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)
En JDBC?
¿Utiliza Scala virtualizado? ¿Utiliza algún otro método?
La API estable de Slick logra esto a través de lo que llama incrustación levantada . Su ejemplo es claramente el uso de la API estable (como usa ===
para la igualdad y no ==
).
La belleza de Slick (y, a su vez, Scala) es que: esto se logra sin usar macros o Scala-virtualizado. (Nota: la API experimental de Slick usa macros, y esto le permitirá usar ==
lugar de ===
o is
)
La traducción a SQL se realiza mediante:
La sintaxis de Scala
for
comprensión, que se traduce en llamadas de método. Las tablas definidas en Slick son Mónadas : tienen los métodos mágicos deforeach
,map
,flatMap
yfilter
que les permiten expresarse en "bucles", mientras que Scala los traduce en llamadas a métodos (como se ilustra correctamente en el código proporcionado por la otra respuesta). por @emil-ivanov ).Al igual que con las colecciones regulares de Scala, el
for
es azúcar sintáctico para llamadas de método anidadas aflatMap
/map
andfilter
; a diferencia de las colecciones regulares, las versiones delmap
y delfilter
objetos SlickTable
devuelven representaciones de una consulta, y las <- Suppliers if s.id is c.supID
junto con cada condición de filtro (if
) o unen (como ens <- Suppliers if s.id is c.supID
)Por lo tanto, el tipo de
q2
no es su colección habitual (como se suele utilizar para la comprensión en Scala), sino una representación de una consulta. (Del mismo modo que la Monada de opciones de Scala también funciona con comprensión a pesar de no ser una "colección" (en la forma en que es laList
o elMap
))Puede ver la consulta subyacente con
q2.selectStatement
.El levantamiento implícito de Scala -
c.price
no es unInt
sino una representación de un valor de columna - por lo que la expresiónc.price < 9.0
convierte enc.price.<(Const(9.0))
(unInt
se levanta al tipo deseado) y<
es solo un método de la clase que representac.price
, unaColumn
. El<
método no hace lo que<
normalmente hace (en el caso de losInt
.Int
): simplemente devuelve una representación del AST de SQL correspondiente alprice < 9
que se convierte en parte del SQL que se genera y envía a JDBC para que se ejecute .
Hay muchas otras cosas más, en términos de detalles, pero creo que la mónada de la consulta y el levantamiento implícito son los principales ingredientes.