Slick 3.0.0 documentation - 15 Direct Embedding (Deprecated)

Permalink to Direct Embedding (Deprecated) — Slick 3.0.0 documentation

Direct Embedding(非推奨) 

バージョン3.0から非推奨となるAPI

DirectEmbeddingはSlick1.0の頃に加えられた、実験的なクエリAPIであったが、バージョン3.0より非推奨となった。この機能はバージョン3.1に削除される予定だ。プロダクション環境などでは、Slickの標準的なクエリAPIを利用して欲しい。

Unlike the standard API, the direct embedding uses macros instead of operator overloading and implicit conversions for its implementation. For a user the difference in the code is small, but queries using the direct embedding work with ordinary Scala types, which can make error messages easier to understand.

Dependencies 

direct embeddingは型検査のために実行時にScalaコンパイラにアクセスする必要がある。Slickは必要性に駆られない限り、アプリケーションに対し、依存性を避けるためにScalaコンパイラへの依存性を任意としている。そのため、direct embeddingを用いる際にはプロジェクトの build.sbt に対し明示的にその依存性を記述しなくてはならない。

libraryDependencies <+= (scalaVersion)("org.scala-lang" % "scala-compiler" % _)

Imports 

import slick.driver.H2Driver
import H2Driver.api.{Database, DBIO}
import slick.direct._
import slick.direct.AnnotationMapper._

Row class and schema 

スキーマは現在でえは行を保持しているケースクラスに対してアノテーションを付与する事で記述する事が出来る。今後、より柔軟にスキーマの情報を拡張出来るような機能を提供する予定だ。

// describe schema for direct embedding
@table(name="COFFEES")
case class Coffee(
  @column(name="NAME")
  name : String,
  @column(name="PRICE")
  price : Double
)

Query 

Queryableはテーブルデータに対しクエリの演算を行うためのものであり、注釈付けられた型引数を取る。

_.price はここではInt型である。潜在的な、マクロベースの実装においてはmapやfilterに与えられた引数はJVM上で実行されないが、その代わりにデータベースクエリへと変換される事を覚えておいて欲しい。

// query database using direct embedding
val q1 = Queryable[Coffee]
val q2 = q1.filter( _.price > 3.0 ).map( _ .name )

Execution 

クエリを実行するためには、選択したデータベースのドライバを用いるSlickBackendインスタンスを作成する必要がある。

val db = Database.forConfig("h2mem1")
try {
  // execute query using a chosen db backend
  val backend = new SlickBackend( H2Driver, AnnotationMapper )
  println( Await.result(db.run(backend.result(q2)), Duration.Inf) )
  println( Await.result(db.run(backend.result(q2.length)), Duration.Inf) )
} finally db.close

Alternative direct embedding bound to a driver and session 

ImplicitQueryableを用いると、queryableはバックエンドとセッションに束縛される。クエリはその上で以下のような方法で簡単に実行する事が出来る。

//
val iq1 = ImplicitQueryable( q1, backend, db )
val iq2 = iq1.filter( c => c.price > 3.0 )
println( iq2.toSeq ) //  <- triggers execution
println( iq2.length ) // <- triggers execution

Features 

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)) )
Fork me on GitHub