Slick 2.0.0 documentation - 11 Direct Embedding (Experimental Feature)
Permalink to Direct Embedding — Slick 2.0.0 documentation
direct embeddingは新しい、しかしまだ不完全で実験的なクエリAPIである。現在実験中。開発中の段階であるため、リリースに応じて非推奨な期間など無しに変更される事がある。安全に利用する事の出来る、安定したlifted embeddingクエリAPIに取って代わるような予定は無く、direct embeddingは共存させていく。lifted embeddingと違って、direct enbeddingは実装のための暗黙的な変換やオーバーロードするオペレータの代わりにマクロを用いて操作を行う。ユーザのために、コード内における違いは少なくしているが、direct enbeddingを用いるクエリは普遍的なScalaの型を用いて機能している。これは表示されるエラーメッセージの理解性を上げるためでもある。
以下の説明は*lifted embedding*の説明に類似した例である。
direct embeddingは型検査のために実行時にScalaコンパイラにアクセスする必要がある。Slickは必要性に駆られない限り、アプリケーションに対し、依存性を避けるためにScalaコンパイラへの依存性を任意としている。そのため、direct embeddingを用いる際にはプロジェクトの build.sbt
に対し明示的にその依存性を記述しなくてはならない。
libraryDependencies <+= (scalaVersion)("org.scala-lang" % "scala-compiler" % _)
import scala.slick.driver.H2Driver
import H2Driver.simple.Database
import Database.{threadLocalSession => session}
import scala.slick.direct._
import scala.slick.direct.AnnotationMapper._
スキーマは現在でえは行を保持しているケースクラスに対してアノテーションを付与する事で記述する事が出来る。今後、より柔軟にスキーマの情報を拡張出来るような機能を提供する予定だ。
// describe schema for direct embedding
@table(name="COFFEES")
case class Coffee(
@column(name="NAME")
name : String,
@column(name="PRICE")
price : Double
)
Queryableはテーブルデータに対しクエリの演算を行うためのものであり、注釈付けられた型引数を取る。
_.price
はここではInt型である。潜在的な、マクロベースの実装においてはmapやfilterに与えられた引数はJVM上で実行されないが、その代わりにデータベースクエリへと変換される事を覚えておいて欲しい。
// query database using direct embedding
val q1 = Queryable[Coffee]
val q2 = q1.filter( _.price > 3.0 ).map( _ .name )
クエリを実行するためには、選択したデータベースのドライバーを用いるSlickBackendインスタンスを作成する必要がある。
val db = Database.forURL("jdbc:h2:mem:test1", driver = "org.h2.Driver")
db withSession {
// execute query using a chosen db backend
val backend = new SlickBackend( H2Driver, AnnotationMapper )
println( backend.result( q2, session ) )
println( backend.result( q2.length, session ) )
}
ImplicitQueryableを用いると、queryableはバックエンドとセッションに束縛される。クエリはその上で以下のような方法で簡単に実行する事が出来る。
//
val iq1 = ImplicitQueryable( q1, backend, session )
val iq2 = iq1.filter( c => c.price > 3.0 )
println( iq2.toSeq ) // <- triggers execution
println( iq2.length ) // <- triggers execution
direct embeddingは現在、 String
, Int
, Double
といった値にたいしマッピングされるデータベースカラムのみサポートしている。
QueryableとImplicitQueryableは現在、次のようなメソッドを用意している。
map, flatMap, filter, length
これらのメソッドはimmutableな演算を行うが、関数呼び出しによる変化を包含した新しいQuaryableを返す。
上記の関数におけるシンタックスとして、以下の様なオペレータを利用する事が出来る。
Any: ==
Int, Double: + < >
String: +
Boolean: || &&
他に定義された独自のオペレータについても、型検査がマッチしていれば利用する事が出来る。しかし現時点では、それらのオペレータは実行時に失敗するクエリを生成するようなSQLへ変換する事が出来ない。(例: ( coffees.map( c => c.name.repr ) )
)将来的には、コンパイル中にそのようなものもキャッチするような方法を検討している。
クエリは行を補完するようなオブジェクトを保持する、任意にネストされたタプルのシーケンスを結果として返す。
q1.map( c => (c.name, (c, c.price)) )
direct embeddingは現在データの挿入といった機能を持っていない。その代わりに*lifted embedding*や*plain SQL queries*などを用いる事ができる。